|  | // Copyright (c) 2017 Google Inc. | 
|  | // | 
|  | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | // you may not use this file except in compliance with the License. | 
|  | // You may obtain a copy of the License at | 
|  | // | 
|  | //     http://www.apache.org/licenses/LICENSE-2.0 | 
|  | // | 
|  | // Unless required by applicable law or agreed to in writing, software | 
|  | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | // See the License for the specific language governing permissions and | 
|  | // limitations under the License. | 
|  |  | 
|  | #ifndef SOURCE_UTIL_ILIST_H_ | 
|  | #define SOURCE_UTIL_ILIST_H_ | 
|  |  | 
|  | #include <cassert> | 
|  | #include <memory> | 
|  | #include <type_traits> | 
|  | #include <vector> | 
|  |  | 
|  | #include "source/util/ilist_node.h" | 
|  |  | 
|  | namespace spvtools { | 
|  | namespace utils { | 
|  |  | 
|  | // An IntrusiveList is a generic implementation of a doubly-linked list.  The | 
|  | // intended convention for using this container is: | 
|  | // | 
|  | //      class Node : public IntrusiveNodeBase<Node> { | 
|  | //        // Note that "Node", the class being defined is the template. | 
|  | //        // Must have a default constructor accessible to List. | 
|  | //        // Add whatever data is needed in the node | 
|  | //      }; | 
|  | // | 
|  | //      using List = IntrusiveList<Node>; | 
|  | // | 
|  | // You can also inherit from IntrusiveList instead of a typedef if you want to | 
|  | // add more functionality. | 
|  | // | 
|  | // The condition on the template for IntrusiveNodeBase is there to add some type | 
|  | // checking to the container.  The compiler will still allow inserting elements | 
|  | // of type IntrusiveNodeBase<Node>, but that would be an error. This assumption | 
|  | // allows NextNode and PreviousNode to return pointers to Node, and casting will | 
|  | // not be required by the user. | 
|  |  | 
|  | template <class NodeType> | 
|  | class IntrusiveList { | 
|  | public: | 
|  | static_assert( | 
|  | std::is_base_of<IntrusiveNodeBase<NodeType>, NodeType>::value, | 
|  | "The type from the node must be derived from IntrusiveNodeBase, with " | 
|  | "itself in the template."); | 
|  |  | 
|  | // Creates an empty list. | 
|  | inline IntrusiveList(); | 
|  |  | 
|  | // Moves the contents of the given list to the list being constructed. | 
|  | IntrusiveList(IntrusiveList&&); | 
|  |  | 
|  | // Destorys the list.  Note that the elements of the list will not be deleted, | 
|  | // but they will be removed from the list. | 
|  | virtual ~IntrusiveList(); | 
|  |  | 
|  | // Moves all of the elements in the list on the RHS to the list on the LHS. | 
|  | IntrusiveList& operator=(IntrusiveList&&); | 
|  |  | 
|  | // Basetype for iterators so an IntrusiveList can be traversed like STL | 
|  | // containers. | 
|  | template <class T> | 
|  | class iterator_template { | 
|  | public: | 
|  | iterator_template(const iterator_template& i) : node_(i.node_) {} | 
|  |  | 
|  | iterator_template& operator++() { | 
|  | node_ = node_->next_node_; | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | iterator_template& operator--() { | 
|  | node_ = node_->previous_node_; | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | iterator_template& operator=(const iterator_template& i) { | 
|  | node_ = i.node_; | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | T& operator*() const { return *node_; } | 
|  | T* operator->() const { return node_; } | 
|  |  | 
|  | friend inline bool operator==(const iterator_template& lhs, | 
|  | const iterator_template& rhs) { | 
|  | return lhs.node_ == rhs.node_; | 
|  | } | 
|  | friend inline bool operator!=(const iterator_template& lhs, | 
|  | const iterator_template& rhs) { | 
|  | return !(lhs == rhs); | 
|  | } | 
|  |  | 
|  | // Moves the nodes in |list| to the list that |this| points to.  The | 
|  | // positions of the nodes will be immediately before the element pointed to | 
|  | // by the iterator.  The return value will be an iterator pointing to the | 
|  | // first of the newly inserted elements. | 
|  | iterator_template MoveBefore(IntrusiveList* list) { | 
|  | if (list->empty()) return *this; | 
|  |  | 
|  | NodeType* first_node = list->sentinel_.next_node_; | 
|  | NodeType* last_node = list->sentinel_.previous_node_; | 
|  |  | 
|  | this->node_->previous_node_->next_node_ = first_node; | 
|  | first_node->previous_node_ = this->node_->previous_node_; | 
|  |  | 
|  | last_node->next_node_ = this->node_; | 
|  | this->node_->previous_node_ = last_node; | 
|  |  | 
|  | list->sentinel_.next_node_ = &list->sentinel_; | 
|  | list->sentinel_.previous_node_ = &list->sentinel_; | 
|  |  | 
|  | return iterator(first_node); | 
|  | } | 
|  |  | 
|  | // Define standard iterator types needs so this class can be | 
|  | // used with <algorithms>. | 
|  | using iterator_category = std::bidirectional_iterator_tag; | 
|  | using difference_type = std::ptrdiff_t; | 
|  | using value_type = T; | 
|  | using pointer = T*; | 
|  | using const_pointer = const T*; | 
|  | using reference = T&; | 
|  | using const_reference = const T&; | 
|  | using size_type = size_t; | 
|  |  | 
|  | protected: | 
|  | iterator_template() = delete; | 
|  | inline iterator_template(T* node) { node_ = node; } | 
|  | T* node_; | 
|  |  | 
|  | friend IntrusiveList; | 
|  | }; | 
|  |  | 
|  | using iterator = iterator_template<NodeType>; | 
|  | using const_iterator = iterator_template<const NodeType>; | 
|  |  | 
|  | // Various types of iterators for the start (begin) and one past the end (end) | 
|  | // of the list. | 
|  | // | 
|  | // Decrementing |end()| iterator will give and iterator pointing to the last | 
|  | // element in the list, if one exists. | 
|  | // | 
|  | // Incrementing |end()| iterator will give |begin()|. | 
|  | // | 
|  | // Decrementing |begin()| will give |end()|. | 
|  | // | 
|  | // TODO: Not marking these functions as noexcept because Visual Studio 2013 | 
|  | // does not support it.  When we no longer care about that compiler, we should | 
|  | // mark these as noexcept. | 
|  | iterator begin(); | 
|  | iterator end(); | 
|  | const_iterator begin() const; | 
|  | const_iterator end() const; | 
|  | const_iterator cbegin() const; | 
|  | const_iterator cend() const; | 
|  |  | 
|  | // Appends |node| to the end of the list.  If |node| is already in a list, it | 
|  | // will be removed from that list first. | 
|  | void push_back(NodeType* node); | 
|  |  | 
|  | // Returns true if the list is empty. | 
|  | bool empty() const; | 
|  |  | 
|  | // Makes the current list empty. | 
|  | inline void clear(); | 
|  |  | 
|  | // Returns references to the first or last element in the list.  It is an | 
|  | // error to call these functions on an empty list. | 
|  | NodeType& front(); | 
|  | NodeType& back(); | 
|  | const NodeType& front() const; | 
|  | const NodeType& back() const; | 
|  |  | 
|  | // Transfers [|first|, |last|) from |other| into the list at |where|. | 
|  | // | 
|  | // If |other| is |this|, no change is made. | 
|  | void Splice(iterator where, IntrusiveList<NodeType>* other, iterator first, | 
|  | iterator last); | 
|  |  | 
|  | protected: | 
|  | // Doing a deep copy of the list does not make sense if the list does not own | 
|  | // the data.  It is not clear who will own the newly created data.  Making | 
|  | // copies illegal for that reason. | 
|  | IntrusiveList(const IntrusiveList&) = delete; | 
|  | IntrusiveList& operator=(const IntrusiveList&) = delete; | 
|  |  | 
|  | // This function will assert if it finds the list containing |node| is not in | 
|  | // a valid state. | 
|  | static void Check(NodeType* node); | 
|  |  | 
|  | // A special node used to represent both the start and end of the list, | 
|  | // without being part of the list. | 
|  | NodeType sentinel_; | 
|  | }; | 
|  |  | 
|  | // Implementation of IntrusiveList | 
|  |  | 
|  | template <class NodeType> | 
|  | inline IntrusiveList<NodeType>::IntrusiveList() : sentinel_() { | 
|  | sentinel_.next_node_ = &sentinel_; | 
|  | sentinel_.previous_node_ = &sentinel_; | 
|  | sentinel_.is_sentinel_ = true; | 
|  | } | 
|  |  | 
|  | template <class NodeType> | 
|  | IntrusiveList<NodeType>::IntrusiveList(IntrusiveList&& list) : sentinel_() { | 
|  | sentinel_.next_node_ = &sentinel_; | 
|  | sentinel_.previous_node_ = &sentinel_; | 
|  | sentinel_.is_sentinel_ = true; | 
|  | list.sentinel_.ReplaceWith(&sentinel_); | 
|  | } | 
|  |  | 
|  | template <class NodeType> | 
|  | IntrusiveList<NodeType>::~IntrusiveList() { | 
|  | clear(); | 
|  | } | 
|  |  | 
|  | template <class NodeType> | 
|  | IntrusiveList<NodeType>& IntrusiveList<NodeType>::operator=( | 
|  | IntrusiveList<NodeType>&& list) { | 
|  | list.sentinel_.ReplaceWith(&sentinel_); | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | template <class NodeType> | 
|  | inline typename IntrusiveList<NodeType>::iterator | 
|  | IntrusiveList<NodeType>::begin() { | 
|  | return iterator(sentinel_.next_node_); | 
|  | } | 
|  |  | 
|  | template <class NodeType> | 
|  | inline typename IntrusiveList<NodeType>::iterator | 
|  | IntrusiveList<NodeType>::end() { | 
|  | return iterator(&sentinel_); | 
|  | } | 
|  |  | 
|  | template <class NodeType> | 
|  | inline typename IntrusiveList<NodeType>::const_iterator | 
|  | IntrusiveList<NodeType>::begin() const { | 
|  | return const_iterator(sentinel_.next_node_); | 
|  | } | 
|  |  | 
|  | template <class NodeType> | 
|  | inline typename IntrusiveList<NodeType>::const_iterator | 
|  | IntrusiveList<NodeType>::end() const { | 
|  | return const_iterator(&sentinel_); | 
|  | } | 
|  |  | 
|  | template <class NodeType> | 
|  | inline typename IntrusiveList<NodeType>::const_iterator | 
|  | IntrusiveList<NodeType>::cbegin() const { | 
|  | return const_iterator(sentinel_.next_node_); | 
|  | } | 
|  |  | 
|  | template <class NodeType> | 
|  | inline typename IntrusiveList<NodeType>::const_iterator | 
|  | IntrusiveList<NodeType>::cend() const { | 
|  | return const_iterator(&sentinel_); | 
|  | } | 
|  |  | 
|  | template <class NodeType> | 
|  | void IntrusiveList<NodeType>::push_back(NodeType* node) { | 
|  | node->InsertBefore(&sentinel_); | 
|  | } | 
|  |  | 
|  | template <class NodeType> | 
|  | bool IntrusiveList<NodeType>::empty() const { | 
|  | return sentinel_.NextNode() == nullptr; | 
|  | } | 
|  |  | 
|  | template <class NodeType> | 
|  | void IntrusiveList<NodeType>::clear() { | 
|  | while (!empty()) { | 
|  | front().RemoveFromList(); | 
|  | } | 
|  | } | 
|  |  | 
|  | template <class NodeType> | 
|  | NodeType& IntrusiveList<NodeType>::front() { | 
|  | NodeType* node = sentinel_.NextNode(); | 
|  | assert(node != nullptr && "Can't get the front of an empty list."); | 
|  | return *node; | 
|  | } | 
|  |  | 
|  | template <class NodeType> | 
|  | NodeType& IntrusiveList<NodeType>::back() { | 
|  | NodeType* node = sentinel_.PreviousNode(); | 
|  | assert(node != nullptr && "Can't get the back of an empty list."); | 
|  | return *node; | 
|  | } | 
|  |  | 
|  | template <class NodeType> | 
|  | const NodeType& IntrusiveList<NodeType>::front() const { | 
|  | NodeType* node = sentinel_.NextNode(); | 
|  | assert(node != nullptr && "Can't get the front of an empty list."); | 
|  | return *node; | 
|  | } | 
|  |  | 
|  | template <class NodeType> | 
|  | const NodeType& IntrusiveList<NodeType>::back() const { | 
|  | NodeType* node = sentinel_.PreviousNode(); | 
|  | assert(node != nullptr && "Can't get the back of an empty list."); | 
|  | return *node; | 
|  | } | 
|  |  | 
|  | template <class NodeType> | 
|  | void IntrusiveList<NodeType>::Splice(iterator where, | 
|  | IntrusiveList<NodeType>* other, | 
|  | iterator first, iterator last) { | 
|  | if (first == last) return; | 
|  | if (other == this) return; | 
|  |  | 
|  | NodeType* first_prev = first.node_->previous_node_; | 
|  | NodeType* where_next = where.node_->next_node_; | 
|  |  | 
|  | // Attach first. | 
|  | where.node_->next_node_ = first.node_; | 
|  | first.node_->previous_node_ = where.node_; | 
|  |  | 
|  | // Attach last. | 
|  | where_next->previous_node_ = last.node_->previous_node_; | 
|  | last.node_->previous_node_->next_node_ = where_next; | 
|  |  | 
|  | // Fixup other. | 
|  | first_prev->next_node_ = last.node_; | 
|  | last.node_->previous_node_ = first_prev; | 
|  | } | 
|  |  | 
|  | template <class NodeType> | 
|  | void IntrusiveList<NodeType>::Check(NodeType* start) { | 
|  | int sentinel_count = 0; | 
|  | NodeType* p = start; | 
|  | do { | 
|  | assert(p != nullptr); | 
|  | assert(p->next_node_->previous_node_ == p); | 
|  | assert(p->previous_node_->next_node_ == p); | 
|  | if (p->is_sentinel_) sentinel_count++; | 
|  | p = p->next_node_; | 
|  | } while (p != start); | 
|  | assert(sentinel_count == 1 && "List should have exactly 1 sentinel node."); | 
|  |  | 
|  | p = start; | 
|  | do { | 
|  | assert(p != nullptr); | 
|  | assert(p->previous_node_->next_node_ == p); | 
|  | assert(p->next_node_->previous_node_ == p); | 
|  | if (p->is_sentinel_) sentinel_count++; | 
|  | p = p->previous_node_; | 
|  | } while (p != start); | 
|  | } | 
|  |  | 
|  | }  // namespace utils | 
|  | }  // namespace spvtools | 
|  |  | 
|  | #endif  // SOURCE_UTIL_ILIST_H_ |