Line data Source code
1 : /**
2 : Copyright (c) 2017-2022 Roman Katuntsev <sbkarr@stappler.org>
3 : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
4 :
5 : Permission is hereby granted, free of charge, to any person obtaining a copy
6 : of this software and associated documentation files (the "Software"), to deal
7 : in the Software without restriction, including without limitation the rights
8 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 : copies of the Software, and to permit persons to whom the Software is
10 : furnished to do so, subject to the following conditions:
11 :
12 : The above copyright notice and this permission notice shall be included in
13 : all copies or substantial portions of the Software.
14 :
15 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 : THE SOFTWARE.
22 : **/
23 :
24 : #ifndef STAPPLER_CORE_MEMORY_SPMEMRBTREE_H_
25 : #define STAPPLER_CORE_MEMORY_SPMEMRBTREE_H_
26 :
27 : #include "SPMemAlloc.h"
28 :
29 : #define SP_MEM_RBTREE_DEBUG 0
30 :
31 : namespace STAPPLER_VERSIONIZED stappler::memory::rbtree {
32 :
33 : enum NodeColor : uintptr_t {
34 : Red = 0,
35 : Black = 1
36 : };
37 :
38 : template <typename Value>
39 : using Storage = memory::Storage<Value>;
40 :
41 : struct NodeBase : public AllocPool {
42 : struct Flag {
43 : uintptr_t color : 1;
44 : uintptr_t prealloc : 1;
45 : uintptr_t index : (sizeof(uintptr_t) / 2) * 8 - 2;
46 : uintptr_t size : (sizeof(uintptr_t) / 2) * 8;
47 : };
48 :
49 : NodeBase *parent = nullptr;
50 : NodeBase *left = nullptr;
51 : NodeBase *right = nullptr;
52 : Flag flag;
53 :
54 : NodeBase() noexcept : flag(Flag{0, 0, 0, 0}) { }
55 2251485 : NodeBase(NodeColor c) noexcept : flag(Flag{uintptr_t(c ? 1 : 0), 0, 0, 0}) { }
56 :
57 73832798 : inline void setColor(NodeColor c) { flag.color = c ? 1 : 0; }
58 57293111 : inline NodeColor getColor() const { return NodeColor(flag.color); }
59 :
60 12487308 : inline void setPrealloc(bool v) { flag.prealloc = v ? 1 : 0; }
61 9812949 : inline bool isPrealloc() const { return flag.prealloc != 0; }
62 :
63 12488151 : inline void setSize(uintptr_t s) { flag.size = s; }
64 2341021 : inline uintptr_t getSize() const { return flag.size; }
65 :
66 8608890 : inline void setIndex(uintptr_t s) { flag.index = s; }
67 0 : inline uintptr_t getIndex() const { return flag.index; }
68 :
69 : static inline NodeBase * min (NodeBase * x) {
70 : while (x->left != 0) x = x->left;
71 : return x;
72 : }
73 :
74 : static inline const NodeBase * min(const NodeBase * x) {
75 : while (x->left != 0) x = x->left;
76 : return x;
77 : }
78 :
79 : static inline NodeBase * max(NodeBase * x) {
80 : while (x->right != 0) x = x->right;
81 : return x;
82 : }
83 :
84 : static inline const NodeBase * max(const NodeBase * x) {
85 : while (x->right != 0) x = x->right;
86 : return x;
87 : }
88 :
89 : static NodeBase * increment(NodeBase *c);
90 : static const NodeBase * increment(const NodeBase *c);
91 :
92 : static NodeBase * decrement(NodeBase *c);
93 : static const NodeBase * decrement(const NodeBase *c);
94 :
95 : // replace node in it's place in tree with new one
96 : static NodeBase *replace(NodeBase *old, NodeBase *n);
97 :
98 : static void insert(NodeBase *head, NodeBase * n);
99 : static void remove(NodeBase *head, NodeBase * n);
100 : };
101 :
102 : template <typename Value>
103 : struct Node : public NodeBase {
104 : Storage<Value> value;
105 :
106 15180930 : static inline Value *cast(NodeBase *n) { return static_cast<Node<Value> *>(n)->value.ptr(); }
107 329684746 : static inline const Value *cast(const NodeBase *n) { return static_cast<const Node<Value> *>(n)->value.ptr(); }
108 : };
109 :
110 : template<typename Value>
111 : struct TreeIterator {
112 : using iterator_category = std::bidirectional_iterator_tag;
113 :
114 : using node_type = Node<Value>;
115 : using value_type = Value;
116 : using reference = Value &;
117 : using pointer = Value *;
118 :
119 : using difference_type = ptrdiff_t;
120 :
121 : using self = TreeIterator<Value>;
122 : using node_ptr = NodeBase *;
123 : using link_ptr = Node<Value> *;
124 :
125 : TreeIterator() noexcept : _node() {}
126 :
127 140487723 : explicit TreeIterator(node_ptr x) noexcept : _node(x) {}
128 :
129 8629793 : reference operator*() const noexcept {return *node_type::cast(_node);}
130 6551138 : pointer operator->() const noexcept {return node_type::cast(_node);}
131 :
132 8639796 : self & operator++() noexcept {_node = node_type::increment(_node); return *this;}
133 170250 : self operator++(int) noexcept {self ret = *this; _node = node_type::increment(_node); return ret;}
134 :
135 : self & operator--() noexcept {_node = node_type::decrement(_node); return *this;}
136 : self operator--(int) noexcept {self ret = *this; _node = node_type::decrement(_node); return ret;}
137 :
138 173971 : bool operator==(const self & other) const noexcept {return _node == other._node;}
139 10898564 : bool operator!=(const self & other) const noexcept {return _node != other._node;}
140 :
141 : node_ptr _node;
142 : };
143 :
144 : template<typename Value>
145 : struct TreeConstIterator {
146 : using iterator_category = std::bidirectional_iterator_tag;
147 :
148 : using node_type = Node<Value>;
149 : using value_type = Value;
150 : using reference = const Value &;
151 : using pointer = const Value *;
152 :
153 : using iterator = TreeIterator<Value>;
154 :
155 : using difference_type = ptrdiff_t;
156 :
157 : using self = TreeConstIterator<Value>;
158 : using node_ptr = const NodeBase *;
159 : using link_ptr = const Node<Value> *;
160 :
161 : TreeConstIterator() noexcept : _node() {}
162 :
163 52362946 : explicit TreeConstIterator(node_ptr x) noexcept : _node(x) {}
164 :
165 121548533 : TreeConstIterator(const iterator& it) noexcept : _node(it._node) {}
166 :
167 9228274 : iterator constcast() const noexcept {return iterator(const_cast<typename iterator::node_ptr>(_node));}
168 :
169 249980359 : reference operator*() const noexcept {return *node_type::cast(_node); }
170 84033728 : pointer operator->() const noexcept {return node_type::cast(_node); }
171 :
172 210266726 : self & operator++() noexcept {_node = node_type::increment(_node); return *this;}
173 : self operator++(int) noexcept {self tmp = *this; _node = node_type::increment(_node); return tmp;}
174 :
175 5211138 : self & operator--() noexcept {_node = node_type::decrement(_node); return *this;}
176 : self operator--(int) noexcept {self tmp = *this; _node = node_type::decrement(_node); return tmp;}
177 :
178 5424306 : bool operator==(const self & x) const noexcept {return _node == x._node;}
179 257212916 : bool operator!=(const self & x) const noexcept {return _node != x._node;}
180 :
181 : node_ptr _node;
182 : };
183 :
184 :
185 : template<typename Value> inline bool
186 : operator==(const TreeIterator<Value> & l, const TreeConstIterator<Value> & r) noexcept { return l._node == r._node; }
187 :
188 : template<typename Value> inline bool
189 : operator!=(const TreeIterator<Value> & l, const TreeConstIterator<Value> & r) noexcept { return l._node != r._node; }
190 :
191 :
192 : template <typename Key, typename Value>
193 : struct TreeKeyExtractor;
194 :
195 : template <typename Key>
196 : struct TreeKeyExtractor<Key, Key> {
197 114924663 : static inline const Key & extract(const Key &k) noexcept { return k; }
198 :
199 : template <typename A, typename ... Args>
200 : static inline void construct(A &alloc, Node<Key> *node, const Key &key, Args && ... args) noexcept {
201 : alloc.construct(node->value.ptr(), key);
202 : }
203 :
204 : template <typename A, typename ... Args>
205 : static inline void construct(A &alloc, Node<Key> *node, Key &&key, Args && ... args) noexcept {
206 : alloc.construct(node->value.ptr(), std::move(key));
207 : }
208 : };
209 :
210 : template <typename Key, typename Value>
211 : struct TreeKeyExtractor<Key, Pair<Key, Value>> {
212 : static inline const Key & extract(const Pair<Key, Value> &k) noexcept { return k.first; }
213 :
214 : template <typename A, typename ... Args>
215 : static inline void construct(A &alloc, Node<Pair<Key, Value>> *node, const Key &k, Args && ... args) noexcept {
216 : alloc.construct(node->value.ptr(),
217 : std::piecewise_construct,
218 : std::forward_as_tuple(k),
219 : std::forward_as_tuple(std::forward<Args>(args)...));
220 : }
221 :
222 : template <typename A, typename ... Args>
223 : static inline void construct(A &alloc, Node<Pair<Key, Value>> *node, Key &&k, Args && ... args) noexcept {
224 : alloc.construct(node->value.ptr(),
225 : std::piecewise_construct,
226 : std::forward_as_tuple(std::move(k)),
227 : std::forward_as_tuple(std::forward<Args>(args)...));
228 : }
229 : };
230 :
231 : template <typename Key, typename Value>
232 : struct TreeKeyExtractor<Key, Pair<const Key, Value>> {
233 18106908 : static inline const Key & extract(const Pair<const Key, Value> &k) noexcept { return k.first; }
234 :
235 : template <typename A, typename ... Args>
236 35292 : static inline void construct(A &alloc, Node<Pair<const Key, Value>> *node, const Key &k, Args && ... args) noexcept {
237 35292 : alloc.construct(node->value.ptr(),
238 : std::piecewise_construct,
239 : std::forward_as_tuple(k),
240 600 : std::forward_as_tuple(std::forward<Args>(args)...));
241 35292 : }
242 :
243 : template <typename A, typename ... Args>
244 5675380 : static inline void construct(A &alloc, Node<Pair<const Key, Value>> *node, Key &&k, Args && ... args) noexcept {
245 11331687 : alloc.construct(node->value.ptr(),
246 : std::piecewise_construct,
247 5675384 : std::forward_as_tuple(std::move(k)),
248 19076 : std::forward_as_tuple(std::forward<Args>(args)...));
249 5675383 : }
250 : };
251 :
252 : template <typename Key, typename Comp, typename Transparent = void>
253 : struct TreeComparator {
254 32261496 : static inline bool compare(const Key &l, const Key &r, const Comp &comp) noexcept {
255 32261496 : return comp(l, r);
256 : }
257 :
258 : template <typename A, typename B>
259 18330269 : static inline bool compare(const A &l, const B &r, const Comp &comp, typename Comp::is_transparent * = nullptr) noexcept {
260 18330269 : return comp(l, r);
261 : }
262 : };
263 :
264 : template <typename Key, typename Comp>
265 : struct TreeComparator<Key, Comp, typename Comp::is_transparent> {
266 : template <typename A, typename B>
267 : static inline bool compare(const A &l, const B &r, const Comp &comp) noexcept {
268 : return comp(l, r);
269 : }
270 : };
271 :
272 : template <typename Key, typename Value, typename Comp = std::less<>>
273 : class Tree : public AllocPool {
274 : public:
275 : using value_type = Value;
276 : using node_type = Node<Value>;
277 : using node_ptr = Node<Value> *;
278 : using base_type = NodeBase *;
279 : using const_node_ptr = const node_type *;
280 :
281 : using node_allocator_type = Allocator<node_type>;
282 : using value_allocator_type = Allocator<value_type>;
283 : using comparator_type = Comp;
284 :
285 : using iterator = TreeIterator<Value>;
286 : using const_iterator = TreeConstIterator<Value>;
287 :
288 : using reverse_iterator = std::reverse_iterator<iterator>;
289 : using const_reverse_iterator = std::reverse_iterator<const_iterator>;
290 :
291 : public:
292 1276067 : Tree(const Comp &comp = Comp(), const value_allocator_type &alloc = value_allocator_type()) noexcept
293 1276067 : : _header(NodeColor::Black), _comp(comp), _allocator(alloc), _size(0) { }
294 :
295 876675 : Tree(const Tree &other, const value_allocator_type &alloc = value_allocator_type()) noexcept
296 876675 : : _header(NodeColor::Black), _comp(other._comp), _allocator(alloc), _size(0) {
297 876675 : clone(other);
298 876675 : }
299 :
300 46288 : Tree(Tree &&other, const value_allocator_type &alloc = value_allocator_type()) noexcept
301 46288 : : _header(NodeColor::Black), _comp(other._comp), _allocator(alloc), _size(0) {
302 46298 : if (other.get_allocator() == _allocator) {
303 46267 : _header = other._header;
304 46267 : _size = other._size;
305 46267 : _comp = std::move(other._comp);
306 46265 : if (_header.left != nullptr) {
307 10375 : _header.left->parent = &_header;
308 : }
309 46265 : other._header = NodeBase(NodeColor::Black);
310 46270 : other._size = 0;
311 : } else {
312 25 : clone(other);
313 : }
314 46295 : }
315 :
316 : Tree & operator = (const Tree &other) noexcept {
317 : clone(other);
318 : return *this;
319 : }
320 :
321 2625 : Tree & operator = (Tree &&other) noexcept {
322 2625 : if (other.get_allocator() == _allocator) {
323 2325 : clear();
324 2325 : _header = other._header;
325 2325 : _size = other._size;
326 2325 : _comp = std::move(other._comp);
327 2325 : if (_header.left != nullptr) {
328 1550 : _header.left->parent = &_header;
329 : }
330 2325 : other._header = NodeBase(NodeColor::Black);
331 2325 : other._size = 0;
332 : } else {
333 300 : clone(other);
334 : }
335 2625 : return *this;
336 : }
337 :
338 472390 : ~Tree() noexcept {
339 472390 : if (_size > 0) {
340 215076 : clear();
341 : }
342 472392 : releaseTmp();
343 472331 : }
344 :
345 71068 : const value_allocator_type & get_allocator() const noexcept { return _allocator; }
346 :
347 : template <typename ... Args>
348 9291103 : Pair<iterator,bool> emplace(Args && ... args) {
349 9291103 : auto ret = insertNodeUnique(std::forward<Args>(args)...);
350 9334434 : return pair(iterator(ret.first), ret.second);
351 : }
352 :
353 : template <typename ... Args>
354 : iterator emplace_hint(const_iterator hint, Args && ... args) {
355 : return iterator(insertNodeUniqueHint(hint, std::forward<Args>(args)...));
356 : }
357 :
358 : template <typename K, typename ... Args>
359 5711593 : Pair<iterator,bool> try_emplace(K &&k, Args && ... args) {
360 5711593 : auto ret = tryInsertNodeUnique(std::forward<K>(k), std::forward<Args>(args)...);
361 5711594 : return pair(iterator(ret.first), ret.second);
362 : }
363 :
364 : template <typename K, typename ... Args>
365 : iterator try_emplace(const_iterator hint, K &&k, Args && ... args) {
366 : return iterator(tryInsertNodeUniqueHint(hint, std::forward<K>(k), std::forward<Args>(args)...));
367 : }
368 :
369 : template <typename K, class M>
370 : Pair<iterator, bool> insert_or_assign(K&& k, M&& m) {
371 : auto ret = tryAssignNodeUnique(std::forward<K>(k), std::forward<M>(m));
372 : return pair(iterator(ret.first), ret.second);
373 : }
374 :
375 : template <typename K, class M>
376 : iterator insert_or_assign(const_iterator hint, K&& k, M&& m) {
377 : return iterator(tryAssignNodeUniqueHint(hint, std::forward<K>(k), std::forward<M>(m)));
378 : }
379 :
380 9227896 : iterator erase( const_iterator pos ) {
381 9227896 : if (pos._node != &_header) {
382 9229683 : auto next = NodeBase::increment(pos.constcast()._node);
383 9223681 : deleteNode(const_cast<NodeBase *>(pos._node));
384 9217807 : return iterator(next);
385 : }
386 0 : return pos.constcast();
387 : }
388 :
389 : iterator erase( const_iterator first, const_iterator last ) {
390 : for (auto it = first; it != last; it ++) {
391 : deleteNode(const_cast<NodeBase *>(it._node));
392 : }
393 : return last;
394 : }
395 :
396 300 : size_t erase_unique(const Key &key) {
397 300 : auto node = find_impl(key);
398 300 : if (node) {
399 225 : deleteNode(node);
400 225 : return 1;
401 : }
402 75 : return 0;
403 : }
404 :
405 10321285 : iterator begin() noexcept { return iterator(_header.left?left():&_header); }
406 89385897 : iterator end() noexcept { return iterator(&_header); }
407 :
408 28266824 : const_iterator begin() const noexcept { return const_iterator(_header.left?left():&_header); }
409 18722369 : const_iterator end() const noexcept { return const_iterator(&_header); }
410 :
411 : reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
412 : reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
413 :
414 : const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); }
415 : const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); }
416 :
417 : const_iterator cbegin() const noexcept { return const_iterator(_header.left?left():&_header); }
418 : const_iterator cend() const noexcept { return const_iterator(&_header); }
419 :
420 : const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(cend()); }
421 : const_reverse_iterator crend() const noexcept { return const_reverse_iterator(cbegin()); }
422 :
423 1100745 : void clear() noexcept {
424 1100745 : if (_header.left) {
425 218400 : clear_visit(static_cast<Node<Value> *>(_header.left));
426 : }
427 1100748 : _header.left = nullptr;
428 1100748 : _header.right = nullptr;
429 1100748 : _header.parent = nullptr;
430 1100748 : _size = 0;
431 1100748 : }
432 :
433 75 : void shrink_to_fit() noexcept {
434 75 : releaseTmp();
435 75 : }
436 :
437 375 : size_t capacity() const noexcept {
438 375 : return _size + _header.flag.size;
439 : }
440 :
441 666663 : size_t size() const noexcept {
442 666663 : return _size;
443 : }
444 :
445 23601012 : bool empty() const noexcept {
446 23601012 : return _header.left == nullptr;
447 : }
448 :
449 128880 : void set_memory_persistent(bool value) noexcept {
450 128880 : _header.flag.prealloc = value ? 1 : 0;
451 128880 : }
452 :
453 : bool memory_persistent() const noexcept {
454 : return _header.flag.prealloc;
455 : }
456 :
457 : void swap(Tree &other) noexcept {
458 : std::swap(_header, other._header);
459 : std::swap(_allocator, other._allocator);
460 : std::swap(_size, other._size);
461 : std::swap(_comp, other._comp);
462 : std::swap(_tmp, other._tmp);
463 : }
464 :
465 770229 : template< class K > iterator find( const K& x ) {
466 770229 : auto ptr = find_impl(x);
467 770228 : return (ptr) ? iterator(ptr) : end();
468 : }
469 :
470 581597 : template< class K > const_iterator find( const K& x ) const {
471 581597 : auto ptr = find_impl(x);
472 581597 : return (ptr) ? const_iterator(ptr) : end();
473 : }
474 :
475 : template< class K >
476 9203863 : iterator lower_bound(const K& x) {
477 9203863 : auto ptr = lower_bound_ptr(x);
478 9188425 : return (ptr) ? iterator(ptr) : end();
479 : }
480 :
481 : template< class K >
482 5293969 : const_iterator lower_bound(const K& x) const {
483 5293969 : auto ptr = lower_bound_ptr(x);
484 5288574 : return (ptr) ? const_iterator(ptr) : end();
485 : }
486 :
487 : template< class K >
488 : iterator upper_bound( const K& x ) {
489 : auto ptr = upper_bound_ptr(x);
490 : return (ptr) ? iterator(ptr) : end();
491 : }
492 :
493 : template< class K >
494 : const_iterator upper_bound( const K& x ) const {
495 : auto ptr = upper_bound_ptr(x);
496 : return (ptr) ? const_iterator(ptr) : end();
497 : }
498 : template< class K >
499 : Pair<iterator,iterator> equal_range( const K& x ) {
500 : return pair(lower_bound(x), upper_bound(x));
501 : }
502 :
503 : template< class K >
504 : Pair<const_iterator,const_iterator> equal_range( const K& x ) const {
505 : return pair(lower_bound(x), upper_bound(x));
506 : }
507 :
508 : template< class K >
509 : size_t count( const K& x ) const {
510 : return count_impl(x);
511 : }
512 :
513 : template< class K >
514 : size_t count_unique( const K& x ) const {
515 : return findNode(x)?1:0;
516 : }
517 :
518 525487 : void reserve(size_t c) {
519 : // requested count is greater then size + pending preallocated nodes
520 525487 : if (c > _size + _header.flag.size) {
521 525451 : allocateTmp(c - _size);
522 : }
523 525544 : }
524 :
525 : protected:
526 : friend class TreeDebug;
527 :
528 : // header values has a special meanings:
529 : // _header.parent - left node from root (first node of iteration)
530 : // _header.right - right node from root
531 : // _header.left - root node (actual root of the tree), nullptr if tree is not defined
532 : // &_header (pointer to the header) - last node in iteration
533 : // _header.size - extra capacity, available via _tmp
534 : // _header.index - count of preallocated blocks in use
535 : // _header.prealloc - flag of persistent mode (enabled if 1, disabled by default)
536 :
537 : NodeBase _header; // root is _header.left
538 : comparator_type _comp;
539 : value_allocator_type _allocator;
540 : size_t _size = 0;
541 : Node<Value> *_tmp = nullptr;
542 :
543 6536205 : inline node_ptr root() { return static_cast<node_ptr>(_header.left); }
544 15705649 : inline const_node_ptr root() const { return static_cast<const_node_ptr>(_header.left); }
545 1161415 : inline void setroot(base_type n) { _header.left = n; n->parent = &_header; }
546 :
547 36472274 : inline node_ptr left() { return static_cast<node_ptr>(_header.parent); }
548 28262724 : inline const_node_ptr left() const { return static_cast<const_node_ptr>(_header.parent); }
549 4140238 : inline void setleft(base_type n) { _header.parent = (n == &_header)?nullptr:n; }
550 :
551 26492935 : inline node_ptr right() { return static_cast<node_ptr>(_header.right); }
552 : inline const_node_ptr right() const { return static_cast<const_node_ptr>(_header.right); }
553 8459604 : inline void setright(base_type n) { _header.right = (n == &_header)?nullptr:n; }
554 :
555 :
556 133086257 : inline const Key & extract(const Value &val) const { return TreeKeyExtractor<Key, Value>::extract(val); }
557 53715990 : inline const Key & extract(const Storage<Value> &s) const { return extract(s.ref()); }
558 80660913 : inline const Key & extract(const NodeBase *s) const { return extract(static_cast<const Node<Value> *>(s)->value.ref()); }
559 :
560 : template <typename A, typename B>
561 49926277 : inline bool compareLtTransparent(const A &l, const B &r) const { return TreeComparator<Key, Comp>::compare(l, r, _comp); }
562 :
563 75748532 : inline bool compareLtKey(const Key &l, const Key &r) const { return _comp(l, r); }
564 : inline bool compareEqKey(const Key &l, const Key &r) const { return !compareLtKey(l, r) && !compareLtKey(r, l); }
565 :
566 : inline bool compareEqValue(const Value &l, const Value &r) const { return compareEqKey(extract(l), extract(r)); }
567 : inline bool compareLtValue(const Value &l, const Value &r) const { return compareLtKey(extract(l), extract(r)); }
568 :
569 : struct InsertData {
570 : const Key *key;
571 : Node<Value> *val;
572 : NodeBase * current;
573 : NodeBase * parent;
574 : bool isLeft;
575 : };
576 :
577 : template <typename ... Args> InsertData
578 9282294 : constructNode(Args && ... args) {
579 9282294 : Node<Value> * ret = allocateNode();
580 9280387 : ret->parent = nullptr;
581 9280387 : ret->left = nullptr;
582 9280387 : ret->right = nullptr;
583 9280387 : ret->setColor(NodeColor::Red);
584 9279488 : _allocator.construct(ret->value.ptr(), std::forward<Args>(args)...);
585 :
586 9266943 : return InsertData{&extract(ret->value), ret, nullptr, nullptr, false};
587 : }
588 :
589 35292 : InsertData constructKey(const Key &k) {
590 35292 : return InsertData{&k, nullptr, nullptr, nullptr, false};
591 : }
592 :
593 5676348 : InsertData constructKey(Key &&k) {
594 5676348 : return InsertData{&k, nullptr, nullptr, nullptr, false};
595 : }
596 :
597 : template <typename K, typename ... Args>
598 5710675 : Node<Value> *constructEmplace(K &&k, Args && ... args) {
599 5710675 : Node<Value> * ret = allocateNode();
600 5710673 : ret->parent = nullptr;
601 5710673 : ret->left = nullptr;
602 5710673 : ret->right = nullptr;
603 5710673 : ret->setColor(NodeColor::Red);
604 :
605 5710673 : TreeKeyExtractor<Key, Value>::construct(_allocator, ret, std::forward<K>(k), std::forward<Args>(args)...);
606 5710673 : return ret;
607 : }
608 :
609 : template <typename M>
610 : void constructAssign(Node<Value> *n, const M &m) {
611 : n->value.ref() = m;
612 : }
613 :
614 : template <typename M>
615 : void constructAssign(Node<Value> *n, M &&m) {
616 : n->value.ref() = std::move(m);
617 : }
618 :
619 6539403 : bool getInsertPositionUnique_search(InsertData &d) {
620 28026567 : while (d.current != nullptr) {
621 21434657 : d.parent = d.current;
622 21434657 : if (compareLtKey(*(d.key), extract(d.current))) {
623 11315990 : d.isLeft = true;
624 11315990 : d.current = static_cast<Node<Value> *> (d.current->left);
625 : } else {
626 10173092 : if (!compareLtKey(extract(d.current), *(d.key))) { // equality check
627 1965 : return false;
628 : }
629 10171174 : d.isLeft = false;
630 10171174 : d.current = static_cast<Node<Value> *> (d.current->right);
631 : }
632 : }
633 6591910 : return true;
634 : }
635 :
636 14960883 : bool getInsertPosition_tryRoot(InsertData &d) {
637 14960883 : if (_size == 0) {
638 1161460 : d.parent = nullptr;
639 1161460 : d.isLeft = true;
640 1161460 : d.current = nullptr;
641 1161460 : return true;
642 : }
643 13799423 : return false;
644 : }
645 :
646 13805782 : bool getInsertPositionUnique_tryHint(InsertData &d) {
647 13805782 : if (d.current == nullptr) {
648 13808583 : return false; // no hint provided
649 : }
650 :
651 : // check if hint is special value (begin or end)
652 0 : if (d.current == left() || static_cast<NodeBase *>(d.current) == &_header) {
653 0 : d.current = nullptr;
654 0 : return false; // this cases served by next two functions
655 : }
656 :
657 : // check if we can insert just before hint
658 0 : auto h = static_cast<Node<Value> *>(d.current);
659 0 : if (compareLtKey(*(d.key), extract(h->value))) {
660 : // check for bound
661 0 : auto p = static_cast<node_ptr>(NodeBase::decrement(d.current));
662 0 : if (compareLtKey(extract(p->value), *(d.key))) {
663 0 : d.parent = d.current;
664 0 : d.current = d.current->left;
665 0 : d.isLeft = true;
666 0 : if (!getInsertPositionUnique_search(d)) {
667 0 : return true; // stop searching, non-unique position, current is not null
668 : }
669 0 : return true;
670 : }
671 0 : } else if (compareLtKey(extract(h->value), *(d.key))) {
672 0 : auto p = static_cast<node_ptr>(NodeBase::increment(d.current));
673 0 : if (static_cast<NodeBase *>(p) == &_header) { // insert back case
674 0 : d.parent = d.current;
675 0 : d.current = d.current->right;
676 0 : d.isLeft = false;
677 0 : return true;
678 0 : } else if (compareLtKey(*(d.key), extract(p->value))) {
679 0 : d.parent = d.current;
680 0 : d.current = d.current->right;
681 0 : d.isLeft = false;
682 0 : if (!getInsertPositionUnique_search(d)) {
683 0 : return true; // stop searching, non-unique position, current is not null
684 : }
685 0 : return true;
686 : }
687 : } else { // hint and new one is equal
688 0 : return true; // current is hint, non-unique cancel
689 : }
690 :
691 0 : d.current = nullptr;
692 0 : return false;
693 : }
694 :
695 13802914 : bool getInsertPositionUnique_tryLeft(InsertData &d) {
696 13802914 : if (auto l = left()) {
697 13802734 : if (compareLtKey(*(d.key), extract(l->value))) {
698 1556787 : d.current = nullptr; d.parent = l; d.isLeft = true;
699 1556787 : return true;
700 12286217 : } else if (!compareLtKey(extract(l->value), *(d.key))) {
701 756 : d.current = l;
702 756 : return true;
703 : }
704 : }
705 12292218 : return false;
706 : }
707 :
708 12291307 : bool getInsertPositionUnique_tryRight(InsertData &d) {
709 12291307 : if (auto r = right()) {
710 12299030 : if (compareLtKey(extract(r->value), *(d.key))) {
711 5785799 : d.current = nullptr; d.parent = r; d.isLeft = false;
712 5785799 : return true;
713 6535648 : } else if (!compareLtKey(*(d.key), extract(r->value))) {
714 345 : d.current = r;
715 345 : return true;
716 : }
717 : }
718 6536280 : return false;
719 : }
720 :
721 14961788 : bool getInsertPositionUnique(InsertData &d) {
722 : // *_try* functions should return true with non-nullptr d.current
723 : // if new node is not unique to stop search process
724 14961788 : if (getInsertPosition_tryRoot(d)
725 13805314 : || getInsertPositionUnique_tryHint(d)
726 13807727 : || getInsertPositionUnique_tryLeft(d)
727 28788088 : || getInsertPositionUnique_tryRight(d)) {
728 8499177 : return d.current == nullptr;
729 : }
730 :
731 : // full-scan
732 6536172 : if (!d.current) { d.current = root(); }
733 : /* find where node belongs */
734 6539914 : return getInsertPositionUnique_search(d);
735 : }
736 :
737 : template <typename ... Args> Pair<Node<Value> *,bool>
738 9286656 : insertNodeUnique(Args && ... args) {
739 9286656 : InsertData d = constructNode(std::forward<Args>(args)...);
740 9250020 : if (!getInsertPositionUnique(d)) {
741 2150 : destroyNode(d.val);
742 2150 : return pair(static_cast<Node<Value> *>(d.current), false);
743 : }
744 :
745 9319074 : return pair(makeInsert(d.val, d.parent, d.isLeft), true);
746 : }
747 :
748 : template <typename ... Args> Node<Value> *
749 : insertNodeUniqueHint(const_iterator hint, Args && ... args) {
750 : InsertData d = constructNode(std::forward<Args>(args)...);
751 : d.current = hint.constcast()._node;
752 : if (!getInsertPositionUnique(d)) {
753 : destroyNode(d.val);
754 : return static_cast<Node<Value> *>(d.current);
755 : }
756 :
757 : return makeInsert(d.val, d.parent, d.isLeft);
758 : }
759 :
760 : template <typename K, typename ... Args> Pair<Node<Value> *,bool>
761 5711594 : tryInsertNodeUnique(K &&k, Args && ... args) {
762 5711594 : InsertData d = constructKey(std::forward<K>(k));
763 5711595 : if (!getInsertPositionUnique(d)) {
764 916 : return pair(static_cast<Node<Value> *>(d.current), false);
765 : }
766 :
767 5710675 : return pair(makeInsert(
768 : constructEmplace(std::forward<K>(k), std::forward<Args>(args)...),
769 11421354 : d.parent, d.isLeft), true);
770 : }
771 :
772 : template <typename K, typename ... Args> Node<Value> *
773 : tryInsertNodeUniqueHint(const_iterator hint, K &&k, Args && ... args) {
774 : InsertData d = constructKey(std::forward<K>(k));
775 : d.current = hint.constcast()._node;
776 : if (!getInsertPositionUnique(d)) {
777 : return static_cast<Node<Value> *>(d.current);
778 : }
779 :
780 : return makeInsert(constructEmplace(std::forward<K>(k), std::forward<Args>(args)...),
781 : d.parent, d.isLeft);
782 : }
783 :
784 : template <typename K, typename M> Pair<Node<Value> *,bool>
785 : tryAssignNodeUnique(K &&k, M &&m) {
786 : InsertData d = constructKey(std::forward<K>(k));
787 : if (!getInsertPositionUnique(d)) {
788 : constructAssign(d.current, std::forward<M>(m));
789 : return pair(static_cast<Node<Value> *>(d.current), false);
790 : }
791 :
792 : return pair(makeInsert(constructEmplace(std::forward<K>(k), std::forward<M>(m)),
793 : d.parent, d.isLeft), true);
794 : }
795 :
796 : template <typename K, typename M> Node<Value> *
797 : tryAssignNodeUniqueHint(const_iterator hint, K &&k, M &&m) {
798 : InsertData d = constructKey(std::forward<K>(k));
799 : d.current = hint.constcast()._node;
800 : if (!getInsertPositionUnique(d)) {
801 : constructAssign(d.current, std::forward<M>(m));
802 : return static_cast<Node<Value> *>(d.current);
803 : }
804 :
805 : return makeInsert(constructEmplace(std::forward<K>(k), std::forward<M>(m)),
806 : d.parent, d.isLeft);
807 : }
808 :
809 15029131 : Node<Value> * makeInsert(Node<Value> *n, NodeBase *parent, bool isLeft) {
810 15029131 : n->parent = parent;
811 15029131 : if (parent) {
812 13872738 : if (isLeft) {
813 5461017 : if (parent == left())
814 1557040 : setleft(n);
815 5460747 : parent->left = n;
816 : } else {
817 8411721 : if (parent == right())
818 5786189 : setright(n);
819 8433733 : parent->right = n;
820 : }
821 : } else {
822 1156393 : setleft(n);
823 1161421 : setright(n);
824 1161429 : setroot(n);
825 : }
826 :
827 15055922 : NodeBase::insert(&_header, n);
828 15029717 : ++ _size;
829 15029717 : return n;
830 : }
831 :
832 9218768 : void deleteNode(NodeBase * z) {
833 9218768 : NodeBase * x = nullptr;
834 9218768 : NodeBase * y = nullptr;
835 :
836 9218768 : if (!z) return;
837 :
838 9218768 : if (!z->left || !z->right) {
839 : /* y has a leaf node as a child */
840 5846704 : y = z;
841 :
842 5846704 : if (z == right()) {
843 1517207 : setright((z == left())?nullptr:NodeBase::decrement(z));
844 : }
845 5885452 : if (z == left()) {
846 1430080 : setleft(NodeBase::increment(z));
847 : }
848 : } else {
849 3372064 : y = z->left;
850 5222161 : while (y->right) y = y->right;
851 : }
852 :
853 : /* x is y's only child */
854 9253667 : if (y->left) {
855 2113065 : x = y->left;
856 : } else {
857 7140602 : x = y->right;
858 : }
859 :
860 9253667 : if (!x) {
861 : // if there is no replacement (we use empty leaf node as new Z),
862 : // we run rebalance with phantom Y node, then swap data and remove links
863 : // to phantom
864 6178786 : if (y->getColor() == NodeColor::Black) {
865 2748791 : NodeBase::remove(&_header, y);
866 : }
867 :
868 6202257 : if (y == y->parent->left)
869 3175765 : y->parent->left = nullptr;
870 : else
871 3026492 : y->parent->right = nullptr;
872 :
873 :
874 6202257 : if (y != z) {
875 : // copy node's data may be expensive, so, we keep data and replace node
876 2885169 : NodeBase::replace(z, y);
877 : }
878 :
879 : } else {
880 : // if we have replacement, we insert it at proper place then call rebalance
881 3074881 : x->parent = y->parent;
882 :
883 3074881 : if (y == y->parent->left)
884 2222144 : y->parent->left = x;
885 : else
886 852737 : y->parent->right = x;
887 :
888 3074881 : if (y != z) {
889 489531 : NodeBase::replace(z, y);
890 : } else {
891 2585350 : y->setColor(NodeColor::Red);
892 : }
893 :
894 3084383 : if (y->getColor() == NodeColor::Black) {
895 363100 : NodeBase::remove(&_header, x);
896 : } else {
897 2719401 : x->setColor(NodeColor::Black);
898 : }
899 : }
900 :
901 9287956 : destroyNode(static_cast<Node<Value> *>(z));
902 9220815 : -- _size;
903 : }
904 :
905 857804 : void clear_visit(Node<Value> *target) {
906 857804 : if (target->left) {
907 272461 : clear_visit(static_cast<Node<Value> *>(target->left));
908 : }
909 857802 : if (target->right) {
910 366945 : clear_visit(static_cast<Node<Value> *>(target->right));
911 : }
912 857799 : destroyNode(target);
913 857795 : }
914 :
915 5196650 : void clone_visit(const Node<Value> *source, Node<Value> *target) {
916 5196650 : _allocator.construct(target->value.ptr(), source->value.ref());
917 5196650 : target->setColor(source->getColor());
918 5196650 : if (source->left) {
919 2016075 : target->left = allocateNode();
920 2016075 : target->left->parent = target;
921 2016075 : clone_visit(static_cast<Node<Value> *>(source->left), static_cast<Node<Value> *>(target->left));
922 2016075 : if (_header.parent == source->left) { // check for leftmost node
923 675625 : _header.parent = target->left;
924 : }
925 : } else {
926 3180575 : target->left = nullptr;
927 : }
928 :
929 5196650 : if (source->right) {
930 2303900 : target->right = allocateNode();
931 2303900 : target->right->parent = target;
932 2303900 : clone_visit(static_cast<Node<Value> *>(source->right), static_cast<Node<Value> *>(target->right));
933 2303900 : if (_header.right == source->right) { // check for rightmost node
934 794300 : _header.right = target->right;
935 : }
936 : } else {
937 2892750 : target->right = nullptr;
938 : }
939 5196650 : }
940 :
941 877000 : void clone(const Tree &other) {
942 877000 : clear();
943 :
944 877000 : _size = other._size;
945 877000 : if (_size) {
946 876675 : allocateTmp(_size);
947 : }
948 :
949 : _comp = other._comp;
950 877000 : _header = other._header;
951 877000 : if (other._header.left) {
952 876675 : _header.left = allocateNode();
953 876675 : _header.left->parent = &_header;
954 876675 : if (other._header.left == other._header.parent) {
955 201050 : _header.parent = _header.left;
956 : }
957 876675 : if (other._header.left == other._header.right) {
958 82375 : _header.right = _header.left;
959 : }
960 876675 : clone_visit(static_cast<Node<Value> *>(other._header.left), static_cast<Node<Value> *>(_header.left));
961 : }
962 877000 : }
963 :
964 : template< class K >
965 1294141 : node_ptr find_impl(const K & x) const {
966 1294141 : const_node_ptr current = root();
967 3002736 : while(current) {
968 2335574 : if (compareLtTransparent(x, extract(current))) {
969 658964 : current = static_cast<const_node_ptr> (current->left);
970 : } else {
971 1676608 : if (!compareLtTransparent(extract(current), x)) { // equality check
972 626978 : return const_cast<node_ptr>(current);
973 : }
974 1049631 : current = static_cast<const_node_ptr> (current->right);
975 : }
976 : }
977 667162 : return nullptr;
978 : }
979 :
980 : template< class K >
981 14489632 : node_ptr lower_bound_ptr(const K& x) const {
982 14489632 : const_node_ptr current = root();
983 14481178 : const_node_ptr saved = nullptr;
984 60613475 : while (current) {
985 45987479 : if (!compareLtTransparent(extract(current), x)) {
986 24930097 : saved = current;
987 24930097 : current = static_cast<const_node_ptr> (current->left);
988 : } else {
989 21202200 : current = static_cast<const_node_ptr> (current->right);
990 : }
991 : }
992 14625996 : return const_cast<node_ptr>(saved);
993 : }
994 :
995 : template< class K >
996 : node_ptr upper_bound_ptr(const K& x) const {
997 : const_node_ptr current = root();
998 : const_node_ptr saved = current;
999 : while (current) {
1000 : if (compareLtTransparent(x, extract(current))) {
1001 : saved = current;
1002 : current = static_cast<const_node_ptr> (current->left);
1003 : } else {
1004 : current = static_cast<const_node_ptr> (current->right);
1005 : }
1006 : }
1007 : return const_cast<node_ptr>(saved);
1008 : }
1009 :
1010 : template< class K >
1011 : size_t count_impl(const K& x) const {
1012 : auto c = find_impl(x);
1013 : if (!c) {
1014 : return 0;
1015 : } else {
1016 : size_t ret = 1;
1017 : const_node_ptr next, current;
1018 :
1019 : current = c;
1020 : next = static_cast<const_node_ptr> (NodeBase::decrement(current));
1021 : while (next && !compareLtTransparent(extract(next), extract(current))) {
1022 : current = next;
1023 : next = static_cast<const_node_ptr> (NodeBase::decrement(current));
1024 : ret ++;
1025 : }
1026 :
1027 : current = c;
1028 : next = static_cast<const_node_ptr> (NodeBase::increment(current));
1029 : while (next && next != &_header && !compareLtTransparent(extract(current), extract(next))) {
1030 : current = next;
1031 : next = static_cast<const_node_ptr> (NodeBase::increment(current));
1032 : ret ++;
1033 : }
1034 : return ret;
1035 : }
1036 : }
1037 :
1038 10080322 : void destroyNode(Node<Value> *n) {
1039 10080322 : _allocator.destroy(n->value.ptr());
1040 10099465 : if (!_tmp) {
1041 : // no saved node - hold one
1042 1949607 : n->parent = nullptr;
1043 1949607 : _tmp = n;
1044 1949607 : ++ _header.flag.size; // increment capacity counter
1045 8149858 : } else if (n->isPrealloc() || _header.flag.prealloc) {
1046 : // node was preallocated - hold it in chain
1047 7735105 : n->parent = _tmp;
1048 7735105 : _tmp = n;
1049 7735105 : ++ _header.flag.size; // increment capacity counter
1050 : } else {
1051 : // deallocate node
1052 415281 : node_allocator_type(_allocator).__deallocate(n, 1, n->getSize());
1053 : }
1054 10099993 : }
1055 :
1056 20185359 : Node<Value> * allocateNode() {
1057 20185359 : if (_tmp) {
1058 16341982 : auto ret = _tmp;
1059 16341982 : _tmp = (Node<Value> *)ret->parent;
1060 16341982 : -- _header.flag.size; // decrement capacity counter
1061 16341982 : return ret;
1062 : } else {
1063 : size_t s;
1064 3843377 : auto ret = node_allocator_type(_allocator).__allocate(1, s);
1065 3847394 : ret->setSize(s);
1066 3847398 : ret->setPrealloc(false);
1067 3847399 : return ret;
1068 : }
1069 : }
1070 :
1071 1402103 : void allocateTmp(size_t count) {
1072 : // preallocate new n nodes
1073 :
1074 1402103 : uintptr_t preallocIdx = ++ _header.flag.index;
1075 1402103 : _header.flag.size += count; // increment capacity counter
1076 :
1077 : size_t s;
1078 1402103 : auto ret = node_allocator_type(_allocator).__allocate(count, s);
1079 1402003 : auto n = ret;
1080 :
1081 10011901 : for (size_t i = 0; i < count; ++ i) {
1082 8609646 : NodeBase *tmpN = n;
1083 8609646 : tmpN->parent = n + 1;
1084 8609646 : tmpN->setPrealloc(true);
1085 8608931 : tmpN->setIndex(preallocIdx);
1086 8610695 : if (i < count - 1) {
1087 7208464 : tmpN->parent = n + 1;
1088 7208464 : tmpN->setSize(sizeof(Node<Value>));
1089 7207877 : s -= sizeof(Node<Value>);
1090 : } else {
1091 1402231 : tmpN->parent = _tmp;
1092 1402231 : n->setSize(s);
1093 : }
1094 8609898 : ++ n;
1095 : }
1096 1402255 : _tmp = ret;
1097 1402255 : }
1098 :
1099 472453 : void releaseTmp() {
1100 : // release any tmp nodes if possible
1101 : // preallocated nodes released in batch as acquired, only if tree is empty
1102 :
1103 : struct PreallocatedData {
1104 : Node<Value> *head = (Node<Value> *)maxOf<uintptr_t>();
1105 : size_t count = 0;
1106 : size_t size = 0;
1107 : };
1108 :
1109 472453 : if (_size != 0) {
1110 : // release only free tmps;
1111 25 : auto ptr = &_tmp;
1112 150 : while (*ptr) {
1113 125 : if (!(*ptr)->isPrealloc()) {
1114 75 : node_allocator_type(_allocator).__deallocate(*ptr, 1, (*ptr)->getSize());
1115 75 : *ptr = (Node<Value> *)(*ptr)->parent;
1116 75 : -- _header.flag.size;
1117 : } else {
1118 50 : ptr = (Node<Value> **)&((*ptr)->parent);
1119 : }
1120 : }
1121 25 : return;
1122 : }
1123 :
1124 472428 : if (_header.flag.index == 0) {
1125 : // no preallocated blocks
1126 558378 : while (_tmp) {
1127 250917 : auto ptr = _tmp;
1128 250917 : _tmp = (Node<Value> *)_tmp->parent;
1129 250917 : node_allocator_type(_allocator).__deallocate(ptr, 1, ptr->getSize());
1130 250919 : -- _header.flag.size;
1131 : }
1132 307461 : _tmp = nullptr;
1133 164970 : } else if (_header.flag.index == 1) {
1134 : // all preallocated nodes should be in tmp chain, only one preallocated block
1135 164959 : PreallocatedData data;
1136 :
1137 1828991 : while (_tmp) {
1138 1663803 : auto ptr = _tmp;
1139 1663803 : _tmp = (Node<Value> *)_tmp->parent;
1140 :
1141 1663803 : if (ptr->isPrealloc()) {
1142 1217849 : if (ptr < data.head) {
1143 353294 : data.head = ptr;
1144 : }
1145 1217849 : ++ data.count;
1146 1217849 : data.size += ptr->getSize();
1147 : } else {
1148 445972 : node_allocator_type(_allocator).__deallocate(ptr, 1, ptr->getSize());
1149 446087 : -- _header.flag.size;
1150 : }
1151 : }
1152 165188 : if (data.head != (Node<Value> *)maxOf<uintptr_t>()) {
1153 164929 : _header.flag.size -= data.count;
1154 164929 : node_allocator_type(_allocator).__deallocate(data.head, data.count, data.size);
1155 : }
1156 : } else {
1157 : // multiple preallocated blocks make things complicated
1158 : // VLA, compilers should support C99,
1159 : // MSVC - fuck off, use new[] or std::vector=)
1160 11 : PreallocatedData data[_header.flag.index];
1161 :
1162 0 : while (_tmp) {
1163 0 : auto ptr = _tmp;
1164 0 : _tmp = (Node<Value> *)_tmp->parent;
1165 :
1166 0 : if (ptr->isPrealloc()) {
1167 0 : if (ptr < data[ptr->getIndex() - 1].head) {
1168 0 : data[ptr->getIndex() - 1].head = ptr;
1169 : }
1170 0 : ++ data[ptr->getIndex() - 1].count;
1171 0 : data[ptr->getIndex() - 1].size += ptr->getSize();
1172 : } else {
1173 0 : node_allocator_type(_allocator).__deallocate(ptr, 1, ptr->getSize());
1174 0 : -- _header.flag.size;
1175 : }
1176 : }
1177 0 : for (size_t i = 0; i < _header.flag.index; ++ i) {
1178 0 : if (data[i].head != (Node<Value> *)maxOf<uintptr_t>()) {
1179 0 : _header.flag.size -= data[i].count;
1180 0 : node_allocator_type(_allocator).__deallocate(data[i].head, data[i].count, data[i].size);
1181 : }
1182 : }
1183 11 : }
1184 472379 : _tmp = nullptr;
1185 : }
1186 : };
1187 :
1188 : }
1189 :
1190 : #if SP_MEM_RBTREE_DEBUG
1191 :
1192 : namespace STAPPLER_VERSIONIZED stappler::memory::rbtree {
1193 :
1194 : class TreeDebug {
1195 : public:
1196 : enum class Validation {
1197 : Valid,
1198 : RootIsNotBlack,
1199 : RedChildIntoRedNode,
1200 : DifferentBlackNodeCount,
1201 : };
1202 :
1203 : template <class T>
1204 : static void visit(const T & tree, std::ostream &stream) {
1205 : typename T::const_node_ptr r = tree.root();
1206 : stream << "visit " << (void *)r << " header: " << tree._header.left << " | " << tree._header.right << " | " << tree._header.parent;
1207 : stream << "\n";
1208 : if (r) {
1209 : visit(tree, stream, static_cast<typename T::const_node_ptr>(r), 0);
1210 : }
1211 : }
1212 :
1213 : template <class T>
1214 : static Validation validate(const T & tree) {
1215 : if (tree._header.left && tree._header.left->flag.color == NodeColor::Red) {
1216 : return Validation::RootIsNotBlack;
1217 : } else {
1218 : auto counter = 0;
1219 : auto root = tree._header.left;
1220 : while (root) {
1221 : if (root->flag.color == NodeColor::Black) ++counter;
1222 : root = root->left;
1223 : }
1224 : return validate(counter, tree._header.left, 0);
1225 : }
1226 : }
1227 :
1228 : //static bool make_test(std::ostream &stream, int size = 128);
1229 : //static bool make_test(std::ostream &stream, const apr::array<int> &insert, const apr::array<int> &erase);
1230 :
1231 : static bool make_hint_test(std::ostream &stream, int size = 128);
1232 : protected:
1233 : template <class T>
1234 : static void visit(const T & tree, std::ostream &stream, typename T::const_node_ptr node, int depth) {
1235 : if (node->left) {
1236 : visit(tree, stream, static_cast<typename T::const_node_ptr>(node->left), depth + 1);
1237 : }
1238 : for (int i = 0; i < depth; i++) {
1239 : stream << "--";
1240 : }
1241 : stream << (void *)node << " l:" << (void *)node->left << " r:" << (void *)node->right << " p:"
1242 : << (void *)node->parent << " v:" << *(node->value.ptr()) << (node->flag.color?" black":" red") << "\n";
1243 : if (node->right) {
1244 : visit(tree, stream, static_cast<typename T::const_node_ptr>(node->right), depth + 1);
1245 : }
1246 : }
1247 :
1248 : static Validation validate(int counter, NodeBase *node, int path) {
1249 : if (node == nullptr) {
1250 : if (counter != path) {
1251 : return Validation::DifferentBlackNodeCount;
1252 : }
1253 : return Validation::Valid;
1254 : } else {
1255 : if (node->flag.color == NodeColor::Black) {
1256 : auto res = validate(counter, node->left, path + 1);
1257 : if (res == Validation::Valid) {
1258 : res = validate(counter, node->right, path + 1);
1259 : }
1260 : return res;
1261 : } else {
1262 : if ((node->left && node->left->flag.color == NodeColor::Red)
1263 : || (node->right && node->right->flag.color == NodeColor::Red)) {
1264 : return Validation::RedChildIntoRedNode;
1265 : } else {
1266 : auto res = validate(counter, node->left, path);
1267 : if (res == Validation::Valid) {
1268 : res = validate(counter, node->right, path);
1269 : }
1270 : return res;
1271 : }
1272 : }
1273 : }
1274 : }
1275 : };
1276 :
1277 : template<typename CharType> inline std::basic_ostream<CharType> &
1278 : operator << (std::basic_ostream<CharType> & os, const TreeDebug::Validation & v) {
1279 : switch(v) {
1280 : case TreeDebug::Validation::Valid: os << "Valid"; break;
1281 : case TreeDebug::Validation::DifferentBlackNodeCount: os << "DifferentBlackNodeCount"; break;
1282 : case TreeDebug::Validation::RedChildIntoRedNode: os << "RedChildIntoRedNode"; break;
1283 : case TreeDebug::Validation::RootIsNotBlack: os << "RootIsNotBlack"; break;
1284 : }
1285 : return os;
1286 : }
1287 :
1288 : }
1289 :
1290 : #endif // SP_MEM_RBTREE_DEBUG
1291 :
1292 : #endif /* STAPPLER_CORE_MEMORY_SPMEMRBTREE_H_ */
|