RavEngine
Loading...
Searching...
No Matches
intrusive_list.h
1//----------------------------------------------------------------------------//
2// //
3// ozz-animation is hosted at http://github.com/guillaumeblanc/ozz-animation //
4// and distributed under the MIT License (MIT). //
5// //
6// Copyright (c) Guillaume Blanc //
7// //
8// Permission is hereby granted, free of charge, to any person obtaining a //
9// copy of this software and associated documentation files (the "Software"), //
10// to deal in the Software without restriction, including without limitation //
11// the rights to use, copy, modify, merge, publish, distribute, sublicense, //
12// and/or sell copies of the Software, and to permit persons to whom the //
13// Software is furnished to do so, subject to the following conditions: //
14// //
15// The above copyright notice and this permission notice shall be included in //
16// all copies or substantial portions of the Software. //
17// //
18// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
19// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
20// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL //
21// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
22// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING //
23// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER //
24// DEALINGS IN THE SOFTWARE. //
25// //
26//----------------------------------------------------------------------------//
27
28#ifndef OZZ_OZZ_BASE_CONTAINERS_INTRUSIVE_LIST_H_
29#define OZZ_OZZ_BASE_CONTAINERS_INTRUSIVE_LIST_H_
30
31#include <cassert>
32#include <cstddef>
33#include <iterator>
34
35namespace ozz {
36namespace containers {
37
38// Enumerate all the link modes that can be used.
39struct LinkMode {
40 enum Value {
41 kSafe, // RECOMMENDED default mode.
42 // Hooks and lists can not be deleted while they are linked.
43 // Programming errors that can corrupt the list are detected:
44 // - pushing a hook twice in a list.
45 // - popping an unlinked hook.
46 // - deleting a linked hook.
47 // - deleting a list that still contains hooks.
48 // This is the default and preferred mode as the rules above
49 // give a lot of guarantees to the user, often even about its own
50 // algorithm consistency.
51 kAuto, // Does the same checks as kSafe, but automatically unlink all hooks
52 // when the list is destroyed. It automatically unlinks a hook when
53 // it is destroyed also. BE CAREFUL that the containers can silently
54 // be modified (without any container's function call), which can
55 // easily lead to thread-unsafe code.
56 kUnsafe, // NOT RECOMMENDED.
57 // Behaves exactly as kSafe mode, but does not assert for
58 // deletion of a linked hook or a non empty list.
59 // This mode is unsafe as deleting a linked hook or a non empty
60 // list leads to corrupt data (dangling pointers). This is useful
61 // when the user knows that all the data (hooks + list) are going
62 // to be erased and that neither the list or any hook of the list
63 // will be accessed. This mode is NOT RECOMMENDED, but still
64 // allows to remove a O(n) algorithm (release all hooks) in some
65 // rare cases where a list is not by nature empty (or relatively
66 // small) at destruction time: .
67 };
68};
69
70// Holds the options for the IntrusiveList containers.
71// _Unique is never used in the code, but differentiates the type of multiple
72// IntrusiveList at compile time. This is useful in order to store the same
73// hook in more than one list (differentiated by their _Unique identifier thus)
74// at the same time.
75// _LinkMode is a value of LinkMode enumeration.
76template <LinkMode::Value _LinkMode = LinkMode::kSafe, int _Unique = 0>
77struct Option {
78 static const LinkMode::Value kLinkMode = _LinkMode;
79};
80
81// Defines the intrusive list container class.
82// In order to use a type _Ty within the IntrusiveList, _Ty elements must
83// inherit from IntrusiveList<...>::Hook objects. This Hook type is the
84// "intrusive" part of the intrusive list implementation, defining pointers of
85// the linked list.
86// The IntrusiveList implements all std::list functions, taking advantage of the
87// O(1) capabilities of the intrusive list. The size() function is NOT constant
88// time though, but linear O(n). If you wish to test whether a list is empty,
89// you should use empty() rather than size() == 0.
90template <typename _Ty, typename _Option = Option<>>
91class IntrusiveList;
92
93// Enters the internal namespace that encloses private implementation details.
94namespace internal {
95
96// Forward declares IntrusiveNodeList.
97class IntrusiveNodeList;
98
99// Defines the node class that's linked by the IntrusiveListImpl.
100// This is an internal class as the user's node class must inherit from
101// IntrusiveList<>::Hook (which inherit from Node).
102class Node {
103 public:
104 // Unlinks *this node from its current list.
105 // This function must be called on a linked node.
106 void unlink();
107
108 // Test if *this node is linked in a list.
109 // This function is not able to test for a particular list.
110 bool is_linked() const { return prev_ != this; }
111
112#ifndef NDEBUG
113 // Test if *this node is linked in _list.
114 // This function is only available for debug purpose.
115 // It tests the same thing is_linked does, but allows to test
116 // which particular list links *this node. Will return false if the node is
117 // linked in another list.
118 bool debug_is_linked_in(const IntrusiveNodeList& _list) const {
119 return &_list == list_;
120 }
121#endif // NDEBUG
122
123 protected:
124 // Constructs an unlinked node.
125 Node()
126#ifndef NDEBUG
127 : list_(nullptr)
128#endif // NDEBUG
129 {
130 prev_ = this;
131 next_ = this;
132 }
133
134 // Destructs the node, no check is done as they depend on the LinkMode.
135 ~Node() {}
136
137 private:
138 // The node class can be publicly used by the internal layers.
139 friend class IntrusiveNodeList;
140 template <typename, typename>
141 friend class IntrusiveListIterator;
142
143 // Pushes (inserts) *this node before _node.
144 // *this node must be unlinked and _node must be linked.
145 void insert(Node* _where);
146
147#ifndef NDEBUG
148 // Tests if *this node is the end node of a list.
149 // This function is only available for debug purpose.
150 // end_ is the first member of the list, which allows to compare *this
151 // address with list_.
152 bool debug_is_end_node() const {
153 return list_ == reinterpret_cast<IntrusiveNodeList const*>(this);
154 }
155#endif // NDEBUG
156
157 // Disallow Node copy and assignation
158 Node(const Node&);
159 void operator=(const Node&);
160
161 // prev_ and next_ points to *this node if *this is NOT linked.
162 Node* prev_; // Pointer to the previous node in the list.
163 Node* next_; // Pointer to the next node in the list.
164
165#ifndef NDEBUG
166 // Pointer to the list_ that references this node, used for debugging only.
167 IntrusiveNodeList* list_;
168#endif // NDEBUG
169};
170
171// Implements non template algorithms of the IntrusiveList class.
172// This class is based on Node type only, but still implement IntrusiveList
173// public algorithms.
175 public:
176 // Constructs an empty list.
178#ifndef NDEBUG
179 end_.list_ = this;
180#endif // NDEBUG
181 }
182
183 // Destructs a list. Assertions are done in the templates class as they
184 // depend on the LinkMode argument.
186
187 // Removes all the elements from the list iteratively.
188 // This function has an O(n) complexity.
189 void clear();
190
191 // Returns true if the list contains no element.
192 bool empty() const { return end_.next_ == &end_; }
193
194 // Reverses the order of elements in the list.
195 // All iterators remain valid and continue to point to the same elements.
196 // This function is linear time O(n).
197 void reverse();
198
199 // Swaps the contents of two lists.
200 // This function as O(1) complexity (except in debug builds) as opposed to
201 // the std::list implementation.
202 void swap(IntrusiveNodeList& _list);
203
204 // Returns the size of the list.
205 // This function is NOT constant time but linear O(n). If you wish to test
206 // whether a list is empty, you should write l.empty() rather than
207 // l.size() == 0.
208 size_t size() const;
209
210 protected:
211 // The type used to counts the number of elements in a list.
212 typedef size_t size_type;
213
214 // Returns the first node of the list if it is not empty, end node otherwise.
215 Node& begin_node() { return *end_.next_; }
216 const Node& begin_node() const { return *end_.next_; }
217
218 // Returns the last node of the list if it is not empty, end node otherwise.
219 Node& last_node() { return *end_.prev_; }
220 const Node& last_node() const { return *end_.prev_; }
221
222 // Returns the end node of the list.
223 Node& end_node() { return end_; }
224 const Node& end_node() const { return end_; }
225
226 // Links _node at the front of the list, ie: just after end node.
227 void link_front(Node* _node) { _node->insert(end_.next_); }
228
229 // Links _node at the back of the list, ie: just before end node.
230 void link_back(Node* _node) { _node->insert(&end_); }
231
232 // Inserts _node before _where.
233 void _insert(Node* _node, Node* _where) { _node->insert(_where); }
234
235#ifndef NDEBUG
236 // Tests if the range [_begin, end_[ is valid, ie: _begin <= _end.
237 // The range invalidity is triggered if _begin and _end are not in the same
238 // list, are not linked, or if the end node of the list is traversed while
239 // iterating from _begin to _end. Unfortunately it makes the algorithm O(n).
240 bool debug_is_range_valid(const Node& _begin, const Node& _end) {
241 if (!_begin.debug_is_linked_in(*this) || !_end.debug_is_linked_in(*this)) {
242 return false;
243 }
244 const Node* node = &_begin;
245 while (node != &_end) {
246 if (node == &_begin.list_->end_) {
247 return false;
248 }
249 node = node->next_;
250 }
251 return true;
252 }
253#endif // NDEBUG
254
255 // Implements splice algorithm.
256 void _splice(Node* _where, Node* _first, Node* _end);
257
258 // Implements erase algorithm.
259 void _erase(Node* _begin, Node* _end);
260
261 // Implements equality test using _pred functor.
262 template <typename _Pred>
263 bool _is_equal(IntrusiveNodeList const& _list, _Pred _pred) const;
264
265 // Implements "less than" test using _pred functor.
266 template <typename _Pred>
267 bool _is_less(IntrusiveNodeList const& _list, _Pred _pred) const;
268
269 // Implements merge algorithm using _pred functor.
270 template <typename _Pred>
271 void _merge(IntrusiveNodeList* _list, _Pred _pred);
272
273 // Implements sort algorithm using _pred functor.
274 template <typename _Pred>
275 void _sort(_Pred _pred);
276
277 // Implements merge algorithm using _pred functor.
278 template <typename _Pred>
279 bool _is_ordered(_Pred _pred) const;
280
281 // Implements remove_if algorithm using _pred functor.
282 template <typename _Pred>
283 void _remove_if(_Pred _pred);
284
285 private:
286 // Base iterator can access end_ for debug purpose
287 template <typename, typename>
288 friend class IntrusiveListIterator;
289
290 // The node that is used to link the first and last elements of the list,
291 // in order to create a circular list.
292 // This node is the one returned by the end() function.
293 Node end_;
294};
295
296// Declares the trait configuration of mutable iterators.
297template <typename _List>
299 typedef typename _List::pointer pointer;
300 typedef typename _List::reference reference;
301 typedef Node ListNode;
302 typedef typename _List::Hook Hook;
303 enum { kReverse = 0 };
304};
305
306// Declares the trait configuration of const iterators.
307template <typename _List>
308struct ConstCfg {
309 typedef typename _List::const_pointer pointer;
310 typedef typename _List::const_reference reference;
311 typedef const Node ListNode;
312 typedef const typename _List::Hook Hook;
313 enum { kReverse = 0 };
314};
315
316// Declares the trait configuration of mutable reverse iterators.
317template <typename _List>
319 typedef typename _List::pointer pointer;
320 typedef typename _List::reference reference;
321 typedef Node ListNode;
322 typedef typename _List::Hook Hook;
323 enum { kReverse = 1 };
324};
325
326// Declares the trait configuration of const reverse iterators.
327template <typename _List>
329 typedef typename _List::const_pointer pointer;
330 typedef typename _List::const_reference reference;
331 typedef const Node ListNode;
332 typedef const typename _List::Hook Hook;
333 enum { kReverse = 1 };
334};
335
336// Implements the IntrusiveList bidirectional iterator.
337// The _Config template argument is a trait that configures the iterator for
338// const/mutable and forward/reverse iteration orders.
339template <typename _List, typename _Config>
341 public:
342 // Defines iterator types as required by std::
343 typedef std::bidirectional_iterator_tag iterator_category;
344 typedef typename _List::value_type value_type;
345 typedef typename _List::difference_type difference_type;
346 typedef typename _Config::pointer pointer;
347 typedef typename _Config::reference reference;
348 typedef typename _Config::ListNode ListNode;
349
350 // Constructs an iterator pointing _node.
351 // _node can be nullptr which creates a default un-dereferencable iterator.
352 explicit IntrusiveListIterator(ListNode* _node = nullptr) : node_(_node) {
353 assert((!_node || _node->list_) &&
354 "Cannot build an iterator from a node that's unlinked");
355 }
356
358
360 : node_(_it.node_) {}
361
362 // Constructs an iterator from an iterator with a different config, like
363 // forward/reverse, const/mutable variations.
364 // Disallowed conversions, like const to mutable, do not compile.
365 template <typename _OConfig>
367 : node_(_it.node_) {}
368
369 // Compares two iterators with different configurations.
370 template <typename _OConfig>
371 bool operator==(IntrusiveListIterator<_List, _OConfig> const& _it) const {
372 assert(node_ && _it.node_ && node_->list_ == _it.node_->list_ &&
373 "List iterators incompatible");
374 return node_ == _it.node_;
375 }
376
377 // Compares two iterators with different configurations.
378 template <typename _OConfig>
379 bool operator!=(IntrusiveListIterator<_List, _OConfig> const& _it) const {
380 assert(node_ && _it.node_ && node_->list_ == _it.node_->list_ &&
381 "List iterators incompatible");
382 return node_ != _it.node_;
383 }
384
385 // Dereferences the object pointed by *this iterator.
386 // *this must be a valid iterator: initialized and not end().
387 reference operator*() const {
388 assert(node_ && !node_->debug_is_end_node() &&
389 "List iterator not dereferencable");
390 return static_cast<reference>(static_cast<typename _Config::Hook&>(*node_));
391 }
392
393 // Pre-increments iterator to the next object. The direction depends on
394 // iterator configuration (forward or reverse).
395 // *this must be a valid iterator: initialized and not end().
396 inline IntrusiveListIterator operator++() {
397 assert(node_ && !node_->debug_is_end_node() &&
398 "List iterator is already on list boundaries");
399 node_ = _Config::kReverse ? node_->prev_ : node_->next_;
400 return *this;
401 }
402
403 // Pre-decrements iterator to the next object. The direction depends on
404 // iterator configuration (forward or reverse).
405 // *this must be a valid iterator: initialized and not end().
406 inline IntrusiveListIterator operator--() {
407 assert(node_ &&
408 node_ != (_Config::kReverse ? node_->list_->end_.prev_
409 : node_->list_->end_.next_) &&
410 "List iterator is already on list boundaries");
411 node_ = _Config::kReverse ? node_->next_ : node_->prev_;
412 return *this;
413 }
414
415 // Post-increments iterator to the next object. The direction depends on
416 // iterator configuration (forward or reverse).
417 // *this must be a valid iterator: initialized and not end().
418 // DO NOT use the post-increment function if the returned value is ignored.
419 IntrusiveListIterator operator++(int) { // NOLINT unnamed argument
420 const IntrusiveListIterator old(*this);
421 ++(*this);
422 return old;
423 }
424
425 // Post-decrements iterator to the next object. The direction depends on
426 // iterator configuration (forward or reverse).
427 // *this must be a valid iterator: initialized and not end().
428 // DO NOT use the post-decrement function if the returned value is ignored.
429 IntrusiveListIterator operator--(int) { // NOLINT unnamed argument
430 const IntrusiveListIterator old(*this);
431 --(*this);
432 return old;
433 }
434
435 private:
436 // Grants the right to IntrusiveList to access node() function.
437 template <typename, typename>
439
440 // Get the node currently pointed by the iterator.
441 // *this iterator must be initialized, but can point a list end node.
442 Node& node() const {
443 assert(node_ && "Iterator isn't initialized");
444 return *node_;
445 }
446
447 // Other iterator specialization can access each other
448 template <typename, typename>
449 friend class IntrusiveListIterator;
450
451 // The list Node designated by *this iterator, which can be the end Node of a
452 // list. A default iterator has a nullptr designated Node.
453 ListNode* node_;
454};
455} // namespace internal
456
457// IntrusiveList implementation.
458template <typename _Ty, typename _Option>
460 public:
461 class Hook : public internal::Node {
462 protected:
463 Hook() {}
464 ~Hook() {
465 if (void(0), _Option::kLinkMode == LinkMode::kAuto && is_linked()) {
466 unlink();
467 }
468 assert((_Option::kLinkMode == LinkMode::kUnsafe || !is_linked()) &&
469 "Node is still linked");
470 }
471
472 private:
473 Hook(const Hook&);
474 void operator=(const Hook&);
475 };
476
477 // The type of te object T (aka the walue) stored in the list.
478 typedef _Ty value_type;
479
480 // Pointer to T.
481 typedef _Ty* pointer;
482
483 // Const pointer to T.
484 typedef _Ty const* const_pointer;
485
486 // Reference to T.
487 typedef _Ty& reference;
488
489 // Const reference to T.
490 typedef _Ty const& const_reference;
491
492 // A type that counts the number of elements in a list.
493 typedef internal::IntrusiveNodeList::size_type size_type;
494
495 // A type that provides the difference between two iterators.
496 typedef ptrdiff_t difference_type;
497
498 // Iterator used to iterate through a list;
501 iterator;
502
503 // Const iterator used to iterate through a list.
507
508 // Iterator used to iterate backwards through a list.
512
513 // Const iterator used to iterate backwards through a list.
517
518 // Constructs an empty list.
519 IntrusiveList() {}
520
521 // Destructs a list that must be empty if link mode is not kUnsafe, otherwise
522 // an assertion is thrown.
524 if (void(0), _Option::kLinkMode == LinkMode::kAuto) {
525 clear();
526 }
527 assert(_Option::kLinkMode == LinkMode::kUnsafe || empty());
528 }
529
530 // Inserts an unlinked element at the beginning of the list.
531 void push_front(reference _val) { link_front(static_cast<Hook*>(&_val)); }
532
533 // Inserts an unlinked element at the end of the list.
534 void push_back(reference _val) { link_back(static_cast<Hook*>(&_val)); }
535
536 // Removes the first element of the list and returns its reference.
537 // Compared to the std::list, this function can return the reference as
538 // pop_front does not delete the element.
539 // This function asserts if list is empty.
540 reference pop_front() {
541 assert(!empty() && "Invalid function on an empty list");
542 internal::Node& node = begin_node();
543 node.unlink();
544 return static_cast<reference>(static_cast<Hook&>(node));
545 }
546
547 // Removes the last element of the list and returns its reference.
548 // Compared to the std::list, this function can return the reference as
549 // pop_back does not delete the element.
550 // This function asserts if list is empty.
551 reference pop_back() {
552 assert(!empty() && "Invalid function on an empty list");
553 internal::Node& node = last_node();
554 node.unlink();
555 return static_cast<reference>(static_cast<Hook&>(node));
556 }
557
558 // Returns the a reference to the first element.
559 // This function asserts if list is empty.
560 reference front() {
561 assert(!empty() && "Invalid function on an empty list");
562 return static_cast<reference>(static_cast<Hook&>(begin_node()));
563 }
564
565 // Returns the a const reference to the first element.
566 // This function asserts if list is empty.
567 const_reference front() const {
568 assert(!empty() && "Invalid function on an empty list");
569 return static_cast<const_reference>(static_cast<const Hook&>(begin_node()));
570 }
571
572 // Returns the a reference to the last element.
573 // This function asserts if list is empty.
574 reference back() {
575 assert(!empty() && "Invalid function on an empty list");
576 return static_cast<reference>(static_cast<Hook&>(last_node()));
577 }
578
579 // Returns the a const reference to the last element.
580 // This function asserts if list is empty.
581 const_reference back() const {
582 assert(!empty() && "Invalid function on an empty list");
583 return static_cast<const_reference>(static_cast<const Hook&>(last_node()));
584 }
585
586 // Returns an iterator pointing to the beginning of the list.
587 iterator begin() { return iterator(&begin_node()); }
588
589 // Returns a const_iterator pointing to the beginning of the list.
590 const_iterator begin() const { return const_iterator(&begin_node()); }
591
592 // Returns an iterator pointing to the end of the list.
593 // The returned iterator can not be dereferenced.
594 iterator end() { return iterator(&end_node()); }
595
596 // Returns a const_iterator pointing to the end of the list.
597 // The returned iterator can not be dereferenced.
598 const_iterator end() const { return const_iterator(&end_node()); }
599
600 // Returns a reverse_iterator pointing to the beginning of the reversed list.
601 // The returned iterator can not be dereferenced.
602 reverse_iterator rbegin() { return reverse_iterator(&last_node()); }
603
604 // Returns a const_reverse_iterator pointing to the beginning of the reversed
605 // list. The returned iterator can not be dereferenced.
606 const_reverse_iterator rbegin() const {
607 return const_reverse_iterator(&last_node());
608 }
609
610 // Returns a reverse_iterator pointing to the end of the reversed list.
611 reverse_iterator rend() { return reverse_iterator(&end_node()); }
612
613 // Returns a const_reverse_iterator pointing to the end of the reversed list.
614 const_reverse_iterator rend() const {
615 return const_reverse_iterator(&end_node());
616 }
617
618 // Removes _val element from the list with a O(1) complexity.
619 // The relative order of elements is unchanged, and iterators to elements
620 // that are not removed remain valid.
621 // This functions asserts if _val is not element of the list.
622 void remove(reference _val) {
623 Hook& hook = static_cast<Hook&>(_val);
624 assert(hook.debug_is_linked_in(*this) && "The node is linked by this list");
625 hook.unlink();
626 }
627
628 // Removes all elements such that _pred() is true, with an O(n) complexity.
629 // The relative order of elements that are not removed is unchanged.
630 // Iterators to elements that are not removed remain valid.
631 template <typename _Pred>
632 void remove_if(_Pred _pred) {
633 _remove_if(UnnaryPredFw<_Pred>(_pred));
634 }
635
636 // Erases element at _where and returns an iterator that designates the first
637 // element remaining beyond the element removed.
638 // _where must be a valid iterator.
639 // ::remove should be preferred as it avoid creating and returning an
640 // iterator.
641 iterator erase(iterator _where) {
642 internal::Node& where_node = _where.node();
643 assert(where_node.debug_is_linked_in(*this) &&
644 "The node is linked by this list");
645 ++_where; // Offset the iterator to return before modifying the list
646 where_node.unlink();
647 return _where;
648 }
649
650 // Erases elements in range [_begin, _end[, and returns an iterator that
651 // designates the first element remaining beyond the element removed.
652 // _first and _end iterators must be a valid.
653 iterator erase(iterator const& _begin, iterator const& _end) {
654 internal::Node& begin_node = _begin.node();
655 internal::Node& end_node = _end.node();
656 _erase(&begin_node, &end_node);
657 return _end; // _end is still a valid iterator
658 }
659
660 // Insert _val before _where.
661 // Compared to std::list, this function does not return an iterator as
662 // IntrusiveLisrt iterators can be constructed in O(1) directly from _val.
663 void insert(iterator const& _where, reference _val) {
664 // Dereference iterator to ensure its validity
665 _insert(static_cast<Hook*>(&_val), &_where.node());
666 }
667
668 // All of the elements of _list are inserted before _where and removed from
669 // _list.
670 // This function is constant time.
671 void splice(iterator _where,
672 IntrusiveList& _list) { // NOLINT conforms with std::list API
673 if (this != &_list && !_list.empty()) {
674 _splice(&_where.node(), &_list.begin_node(), &_list.end_node());
675 }
676 }
677
678 // The elements _what from _list is inserted before _where and removed from
679 // _list.
680 // This function is constant time.
681 void splice(iterator _where,
682 IntrusiveList& _list, // NOLINT conforms with std::list API
683 iterator _what) {
684 reference val = static_cast<reference>(static_cast<Hook&>(_what.node()));
685 _list.remove(val);
686 insert(_where, val);
687 }
688
689 // All of the elements in the range [_begin, _end[ are inserted before
690 // _where and removed from _list.
691 // This function is constant time.
692 void splice(iterator _where,
693 IntrusiveList& _list, // NOLINT conforms with std::list API
694 iterator _begin, iterator _end) {
695 internal::Node* where_node = &_where.node();
696 internal::Node* begin_node = &_begin.node();
697 internal::Node* end_node = &_end.node();
698 if (begin_node != end_node && (this != &_list || where_node != end_node)) {
699 _splice(where_node, begin_node, end_node);
700 }
701 }
702
703 // Removes all of _list's elements and inserts them in order into *this.
704 // _Pred must be a comparison function that induces a strict weak ordering
705 // (as defined in the LessThan Comparable requirements) on objects of type
706 // _Ty, and both *this and _list must be sorted according to that ordering.
707 // The merge is stable; that is, if an element from *this is equivalent to
708 // one from x, then the element from *this will precede the one from x.
709 // This function is linear time and performs at most:
710 // size() + _list.size() - 1 applications of _Pred.
711 template <typename _Pred>
712 void merge(IntrusiveList& _list,
713 _Pred _pred) { // NOLINT conforms with std::list API
714 _merge(&_list, BinaryPredFw<_Pred>(_pred));
715 }
716
717 // Removes all of _list's elements and inserts them in order into *this.
718 // Both *this and x must be sorted according to operator<.
719 // The merge is stable; that is, if an element from *this is equivalent to
720 // one from x, then the element from *this will precede the one from x.
721 // All iterators to elements in *this and x remain valid.
722 // This function is linear time and performs at most
723 // size() + _list.size() - 1 comparisons.
724 void merge(IntrusiveList& _list) { // NOLINT conforms with std::list API
725 _merge(&_list, LessTester());
726 }
727
728 // Sorts the list *this according to Comp.
729 // Comp must be a comparison function that induces a strict weak ordering
730 // (as defined in the LessThan Comparable requirements on objects of type T.
731 // The sort is stable, that is, the relative order of equivalent elements is
732 // preserved.
733 // The number of comparisons is approximately n.log(n).
734 template <class _Pred>
735 void sort(_Pred _pred) {
736 _sort(BinaryPredFw<_Pred>(_pred));
737 }
738
739 // Sorts *this according to operator<.
740 // The sort is stable, that is, the relative order of equivalent elements is
741 // preserved.
742 // The number of comparisons is approximately n.log(n).
743 void sort() { _sort(LessTester()); }
744
745 // Tests two lists for equality according to operator==.
746 bool operator==(IntrusiveList const& _list) const {
747 return _is_equal(_list, EqualTester());
748 }
749
750 // Tests two lists for inequality according to operator==.
751 bool operator!=(IntrusiveList const& _list) const {
752 return !(*this == _list);
753 }
754
755 // Lexicographical "less" comparison according to operator<.
756 bool operator<(IntrusiveList const& _list) const {
757 return _is_less(_list, LessTester());
758 }
759
760 // Lexicographical "less or equal" comparison according to operator<.
761 bool operator<=(IntrusiveList const& _list) const { return !(_list < *this); }
762
763 // Lexicographical "greater" comparison according to operator<.
764 bool operator>(IntrusiveList const& _list) const { return _list < *this; }
765
766 // Lexicographical "greater or equal" comparison according to operator<.
767 bool operator>=(IntrusiveList const& _list) const { return !(*this < _list); }
768
769 private:
770 // Internal function that tests the order of the list according to _Pred.
771 template <typename _Pred>
772 bool is_ordered(_Pred _pred) const {
773 return _is_ordered(BinaryPredFw<_Pred>(_pred));
774 }
775
776 // Helper binary functor that converts the nodes in argument to
777 // a value_type that are given as arguments to _pred.
778 template <typename _Pred>
779 struct BinaryPredFw {
780 explicit BinaryPredFw(_Pred _pred) : pred_(_pred) {}
781 bool operator()(const internal::Node& _left, const internal::Node& _right) {
782 const_reference left =
783 static_cast<const_reference>(static_cast<const Hook&>(_left));
784 const_reference right =
785 static_cast<const_reference>(static_cast<const Hook&>(_right));
786 return pred_(left, right);
787 }
788 _Pred pred_;
789 };
790
791 // Helper unary functor that converts the node in argument to
792 // a value_type that is given as an argument to _pred.
793 template <typename _Pred>
794 struct UnnaryPredFw {
795 explicit UnnaryPredFw(_Pred _pred) : pred_(_pred) {}
796 bool operator()(const internal::Node& _node) {
797 const_reference val =
798 static_cast<const_reference>(static_cast<const Hook&>(_node));
799 return pred_(val);
800 }
801 _Pred pred_;
802 };
803
804 // Compares 2 nodes according to the value_type operator ==.
805 struct EqualTester {
806 bool operator()(const internal::Node& _left, const internal::Node& _right) {
807 const_reference left =
808 static_cast<const_reference>(static_cast<const Hook&>(_left));
809 const_reference right =
810 static_cast<const_reference>(static_cast<const Hook&>(_right));
811 return left == right;
812 }
813 };
814
815 // Compares 2 nodes according to the value_type operator <.
816 struct LessTester {
817 bool operator()(const internal::Node& _left, const internal::Node& _right) {
818 const_reference left =
819 static_cast<const_reference>(static_cast<const Hook&>(_left));
820 const_reference right =
821 static_cast<const_reference>(static_cast<const Hook&>(_right));
822 return left < right;
823 }
824 };
825
826 // Disallow copy and assignment
827 IntrusiveList(const IntrusiveList&);
828 void operator=(const IntrusiveList&);
829};
830
831// Enters the internal namespace that encloses private implementation details.
832namespace internal {
833
834// Connect the next and previous nodes together, resets internal linked state.
835inline void Node::unlink() {
836 assert(is_linked() && "This node is not linked");
837 assert(!debug_is_end_node() && "The end_ node cannot be unlinked");
838
839 next_->prev_ = prev_; // Reconnect prev and next nodes
840 prev_->next_ = next_;
841
842 // Reset this node to the NOT linked state
843 prev_ = this;
844 next_ = this;
845
846#ifndef NDEBUG
847 list_ = nullptr;
848#endif // NDEBUG
849}
850
851inline void Node::insert(Node* _where) {
852 assert(!is_linked() && _where->list_ && // Cannot test _where->is_linked
853 // as end_ would return false.
854 "*this node must be unlinked and _node must be linked");
855 assert(!debug_is_end_node() && "The end_ node cannot be linked");
856
857 prev_ = _where->prev_; // Connect the previous of *this node
858 _where->prev_->next_ = this;
859
860 next_ = _where; // Connect the next of *this node
861 _where->prev_ = this;
862
863#ifndef NDEBUG
864 list_ = _where->list_;
865#endif // NDEBUG
866}
867
868// Iterates through all elements to unlink them from the list.
869inline void IntrusiveNodeList::clear() {
870 while (end_.next_ != &end_) {
871 end_.next_->unlink();
872 }
873}
874
875// Iterates through all elements in range [_begin, _end[ to unlink them from
876// the list.
877inline void IntrusiveNodeList::_erase(Node* _begin, Node* _end) {
878 assert(debug_is_range_valid(*_begin, *_end) && "Invalid iterator range");
879 while (_begin != _end) {
880 internal::Node* next_node = _begin->next_;
881 _begin->unlink();
882 _begin = next_node;
883 }
884}
885
886// Loops and inserts the first element in front of the original last one,
887// until the last one is reached.
888inline void IntrusiveNodeList::reverse() {
889 Node* const last = end_.prev_;
890 while (end_.next_ != last) {
891 Node* node = end_.next_;
892 node->unlink();
893 node->insert(last->next_);
894 }
895}
896
897// Loops and counts the number of elements, excluding the end_ node.
898inline size_t IntrusiveNodeList::size() const {
899 size_t size = 0;
900 for (const Node *node = end_.next_; node != &end_;
901 node = node->next_, ++size) {
902 }
903 return size;
904}
905
906// Takes advantage of the intrusive property to swap end_ nodes without
907// iterating through all nodes.
908// This makes this implementation O(1) rather than O(n).
909// In debug build though, every node between of the two lists must be traversed
910// to reset their list_ member.
911inline void IntrusiveNodeList::swap(IntrusiveNodeList& _list) {
912// Don't use std::swap to avoid including <algorithm> in a h file.
913// Also std::swap does a branch for nothing when dealing with pointers.
914#define _SWAP_PTR(_a, _b) \
915 { \
916 Node* temp = _a; \
917 _a = _b; \
918 _b = temp; \
919 }
920
921 _SWAP_PTR(_list.end_.prev_->next_, end_.prev_->next_);
922 _SWAP_PTR(_list.end_.prev_, end_.prev_);
923 _SWAP_PTR(_list.end_.next_->prev_, end_.next_->prev_);
924 _SWAP_PTR(_list.end_.next_, end_.next_);
925#undef _SWAP_PTR
926
927#ifndef NDEBUG
928 // Reset node internal list_ pointer
929 Node* node = end_.next_;
930 while (node != &end_) {
931 node->list_ = this;
932 node = node->next_;
933 }
934 node = _list.end_.next_;
935 while (node != &_list.end_) {
936 node->list_ = &_list;
937 node = node->next_;
938 }
939#endif // NDEBUG
940}
941
942// Takes advantage of the intrusive property to splice nodes without iterating.
943// This makes this implementation O(1) rather than O(n).
944// In debug build though, every node between _first and _end must be traversed
945// to reset their list_ member.
946inline void IntrusiveNodeList::_splice(Node* _where, Node* _first, Node* _end) {
947 assert(_where->list_ == this && "_where is not a member of *this list");
948 assert(_first->list_ && _first->list_->debug_is_range_valid(*_first, *_end) &&
949 "Invalid iterator range");
950 assert(_first != _end);
951
952 // Keep a pointer to the last node as _end->prev_ is modified early
953 Node* last = _end->prev_;
954
955 // De-link _first and last from its original list
956 _first->prev_->next_ = _end;
957 _end->prev_ = _first->prev_;
958
959 // Re-link _first
960 _first->prev_ = _where->prev_;
961 _where->prev_->next_ = _first;
962
963 // Re-link _end
964 _where->prev_ = last;
965 last->next_ = _where;
966
967#ifndef NDEBUG
968 // Reset node internal list_ pointer, for all the inserted nodes
969 Node* node = _first;
970 while (node != _where) {
971 node->list_ = this;
972 node = node->next_;
973 }
974#endif // NDEBUG
975}
976
977template <typename _Pred>
978inline bool IntrusiveNodeList::_is_equal(IntrusiveNodeList const& _list,
979 _Pred _pred) const {
980 const internal::Node* left_node = end_.next_;
981 const internal::Node* right_node = _list.end_.next_;
982 while (left_node != &end_ && right_node != &_list.end_) {
983 if (!_pred(*left_node, *right_node)) {
984 return false;
985 }
986 left_node = left_node->next_;
987 right_node = right_node->next_;
988 }
989 // Finally returns true if the two lists have the same sizes
990 return left_node == &end_ && right_node == &_list.end_;
991}
992
993template <typename _Pred>
994inline bool IntrusiveNodeList::_is_less(IntrusiveNodeList const& _list,
995 _Pred _pred) const {
996 const internal::Node* left_node = end_.next_;
997 const internal::Node* right_node = _list.end_.next_;
998 while (left_node != &end_ && right_node != &_list.end_) {
999 if (_pred(*left_node, *right_node)) {
1000 return true;
1001 } else if (_pred(*right_node, *left_node)) {
1002 return false;
1003 }
1004 left_node = left_node->next_;
1005 right_node = right_node->next_;
1006 }
1007 // Finally returns true if "this" list has less elements
1008 return left_node == &end_ && right_node != &_list.end_;
1009}
1010
1011// Tries to splice more than one element at a time, as the intrusive policy
1012// allow splicing of n consecutive nodes in O(1) complexity.
1013template <typename _Pred>
1014inline void IntrusiveNodeList::_merge(IntrusiveNodeList* _list, _Pred _pred) {
1015 assert(_is_ordered(_pred) && "This list must be ordered");
1016 if (this == _list) {
1017 return;
1018 }
1019 assert(_list->_is_ordered(_pred) && "The list in argument must be ordered");
1020
1021 internal::Node* node = end_.next_;
1022 internal::Node* to__insertbegin = _list->end_.next_;
1023
1024 while (node != &end_ && to__insertbegin != &_list->end_) {
1025 if (_pred(*node, *to__insertbegin)) {
1026 node = node->next_;
1027 } else { // Try to find consecutive nodes satisfying _pred
1028 internal::Node* to__insertend = to__insertbegin->next_;
1029 while (to__insertend != &_list->end_) {
1030 if (_pred(*node, *to__insertend)) {
1031 break;
1032 }
1033 to__insertend = to__insertend->next_;
1034 }
1035 _splice(node, to__insertbegin, to__insertend);
1036 to__insertbegin = to__insertend;
1037 }
1038 }
1039
1040 if (to__insertbegin != &_list->end_) { // Appends the rest of _list
1041 _splice(&end_, to__insertbegin, &_list->end_);
1042 }
1043}
1044
1045// Iterate and test predicate _pred for every node.
1046template <typename _Pred>
1047inline void IntrusiveNodeList::_remove_if(_Pred _pred) {
1048 internal::Node* node = end_.next_;
1049 while (node != &end_) {
1050 internal::Node* next_node = node->next_;
1051 if (_pred(*node)) {
1052 node->unlink();
1053 }
1054 node = next_node;
1055 }
1056}
1057
1058// Bin sort algorithm, takes advantage of O(1) complexity of swap and splice.
1059template <typename _Pred>
1060inline void IntrusiveNodeList::_sort(_Pred _pred) {
1061 // It's worth sorting if there is more than one element
1062 if (end_.next_->next_ == &end_) {
1063 return;
1064 }
1065 const int kMaxBins = 25;
1066 IntrusiveNodeList bin_lists[kMaxBins + 1];
1067 IntrusiveNodeList temp_list;
1068 int used_bins = 0;
1069 while (!empty()) {
1070 // Inserts the front node at the front of temp_list
1071 internal::Node* node = end_.next_;
1072 node->unlink();
1073 temp_list.link_front(node);
1074
1075 int bin = 0;
1076 for (; bin < used_bins && !bin_lists[bin].empty(); ++bin) {
1077 // Merges into ever larger bins
1078 bin_lists[bin]._merge(&temp_list, _pred);
1079 bin_lists[bin].swap(temp_list);
1080 }
1081
1082 if (bin == kMaxBins) { // No more bin, merge in the last one
1083 bin_lists[kMaxBins - 1]._merge(&temp_list, _pred);
1084 } else { // Spills to new bin, while they last
1085 bin_lists[bin].swap(temp_list);
1086 if (bin == used_bins) {
1087 used_bins++;
1088 }
1089 }
1090 }
1091
1092 for (int bin = 1; bin < used_bins; ++bin) { // Merge up every bin
1093 bin_lists[bin]._merge(&bin_lists[bin - 1], _pred);
1094 }
1095
1096 if (used_bins != 0) { // Result is in last bin
1097 IntrusiveNodeList& last_bin = bin_lists[used_bins - 1];
1098 _splice(end_.next_, last_bin.end_.next_, &last_bin.end_);
1099 }
1100}
1101
1102// Loops and tests if _Pred is true for all nodes
1103template <typename _Pred>
1104inline bool IntrusiveNodeList::_is_ordered(_Pred _pred) const {
1105 const internal::Node* next_node = end_.next_->next_;
1106 while (next_node != &end_) {
1107 if (!_pred(*next_node->prev_, *next_node)) {
1108 return false;
1109 }
1110 next_node = next_node->next_;
1111 }
1112 return true;
1113}
1114} // namespace internal
1115} // namespace containers
1116} // namespace ozz
1117
1118// Specialization of the std::swap algorithm for the IntusiveList class.
1119// Does not need to be implemented in std namespace thanks to ADL.
1120template <typename _Ty, typename _Option>
1122 _left, // NOLINT Don't want to #include <algorithm>
1124 _left.swap(_right);
1125}
1126
1127// Undefines local macros
1128#endif // OZZ_OZZ_BASE_CONTAINERS_INTRUSIVE_LIST_H_
Definition intrusive_list.h:461
Definition intrusive_list.h:459
Definition intrusive_list.h:174
Definition intrusive_list.h:102
Definition intrusive_list.h:39
Definition intrusive_list.h:77
Definition intrusive_list.h:308
Definition intrusive_list.h:328
Definition intrusive_list.h:298
Definition intrusive_list.h:318