ilist.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. // Copyright (c) 2017 Google Inc.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #ifndef SOURCE_UTIL_ILIST_H_
  15. #define SOURCE_UTIL_ILIST_H_
  16. #include <cassert>
  17. #include <memory>
  18. #include <type_traits>
  19. #include <vector>
  20. #include "source/util/ilist_node.h"
  21. namespace spvtools {
  22. namespace utils {
  23. // An IntrusiveList is a generic implementation of a doubly-linked list. The
  24. // intended convention for using this container is:
  25. //
  26. // class Node : public IntrusiveNodeBase<Node> {
  27. // // Note that "Node", the class being defined is the template.
  28. // // Must have a default constructor accessible to List.
  29. // // Add whatever data is needed in the node
  30. // };
  31. //
  32. // using List = IntrusiveList<Node>;
  33. //
  34. // You can also inherit from IntrusiveList instead of a typedef if you want to
  35. // add more functionality.
  36. //
  37. // The condition on the template for IntrusiveNodeBase is there to add some type
  38. // checking to the container. The compiler will still allow inserting elements
  39. // of type IntrusiveNodeBase<Node>, but that would be an error. This assumption
  40. // allows NextNode and PreviousNode to return pointers to Node, and casting will
  41. // not be required by the user.
  42. template <class NodeType>
  43. class IntrusiveList {
  44. public:
  45. static_assert(
  46. std::is_base_of<IntrusiveNodeBase<NodeType>, NodeType>::value,
  47. "The type from the node must be derived from IntrusiveNodeBase, with "
  48. "itself in the template.");
  49. // Creates an empty list.
  50. inline IntrusiveList();
  51. // Moves the contents of the given list to the list being constructed.
  52. IntrusiveList(IntrusiveList&&);
  53. // Destorys the list. Note that the elements of the list will not be deleted,
  54. // but they will be removed from the list.
  55. virtual ~IntrusiveList();
  56. // Moves all of the elements in the list on the RHS to the list on the LHS.
  57. IntrusiveList& operator=(IntrusiveList&&);
  58. // Basetype for iterators so an IntrusiveList can be traversed like STL
  59. // containers.
  60. template <class T>
  61. class iterator_template {
  62. public:
  63. iterator_template(const iterator_template& i) : node_(i.node_) {}
  64. iterator_template& operator++() {
  65. node_ = node_->next_node_;
  66. return *this;
  67. }
  68. iterator_template& operator--() {
  69. node_ = node_->previous_node_;
  70. return *this;
  71. }
  72. iterator_template& operator=(const iterator_template& i) {
  73. node_ = i.node_;
  74. return *this;
  75. }
  76. T& operator*() const { return *node_; }
  77. T* operator->() const { return node_; }
  78. friend inline bool operator==(const iterator_template& lhs,
  79. const iterator_template& rhs) {
  80. return lhs.node_ == rhs.node_;
  81. }
  82. friend inline bool operator!=(const iterator_template& lhs,
  83. const iterator_template& rhs) {
  84. return !(lhs == rhs);
  85. }
  86. // Moves the nodes in |list| to the list that |this| points to. The
  87. // positions of the nodes will be immediately before the element pointed to
  88. // by the iterator. The return value will be an iterator pointing to the
  89. // first of the newly inserted elements.
  90. iterator_template MoveBefore(IntrusiveList* list) {
  91. if (list->empty()) return *this;
  92. NodeType* first_node = list->sentinel_.next_node_;
  93. NodeType* last_node = list->sentinel_.previous_node_;
  94. this->node_->previous_node_->next_node_ = first_node;
  95. first_node->previous_node_ = this->node_->previous_node_;
  96. last_node->next_node_ = this->node_;
  97. this->node_->previous_node_ = last_node;
  98. list->sentinel_.next_node_ = &list->sentinel_;
  99. list->sentinel_.previous_node_ = &list->sentinel_;
  100. return iterator(first_node);
  101. }
  102. // Define standard iterator types needs so this class can be
  103. // used with <algorithms>.
  104. using iterator_category = std::bidirectional_iterator_tag;
  105. using difference_type = std::ptrdiff_t;
  106. using value_type = T;
  107. using pointer = T*;
  108. using const_pointer = const T*;
  109. using reference = T&;
  110. using const_reference = const T&;
  111. using size_type = size_t;
  112. protected:
  113. iterator_template() = delete;
  114. inline iterator_template(T* node) { node_ = node; }
  115. T* node_;
  116. friend IntrusiveList;
  117. };
  118. using iterator = iterator_template<NodeType>;
  119. using const_iterator = iterator_template<const NodeType>;
  120. // Various types of iterators for the start (begin) and one past the end (end)
  121. // of the list.
  122. //
  123. // Decrementing |end()| iterator will give and iterator pointing to the last
  124. // element in the list, if one exists.
  125. //
  126. // Incrementing |end()| iterator will give |begin()|.
  127. //
  128. // Decrementing |begin()| will give |end()|.
  129. //
  130. // TODO: Not marking these functions as noexcept because Visual Studio 2013
  131. // does not support it. When we no longer care about that compiler, we should
  132. // mark these as noexcept.
  133. iterator begin();
  134. iterator end();
  135. const_iterator begin() const;
  136. const_iterator end() const;
  137. const_iterator cbegin() const;
  138. const_iterator cend() const;
  139. // Appends |node| to the end of the list. If |node| is already in a list, it
  140. // will be removed from that list first.
  141. void push_back(NodeType* node);
  142. // Returns true if the list is empty.
  143. bool empty() const;
  144. // Makes the current list empty.
  145. inline void clear();
  146. // Returns references to the first or last element in the list. It is an
  147. // error to call these functions on an empty list.
  148. NodeType& front();
  149. NodeType& back();
  150. const NodeType& front() const;
  151. const NodeType& back() const;
  152. // Transfers [|first|, |last|) from |other| into the list at |where|.
  153. //
  154. // If |other| is |this|, no change is made.
  155. void Splice(iterator where, IntrusiveList<NodeType>* other, iterator first,
  156. iterator last);
  157. protected:
  158. // Doing a deep copy of the list does not make sense if the list does not own
  159. // the data. It is not clear who will own the newly created data. Making
  160. // copies illegal for that reason.
  161. IntrusiveList(const IntrusiveList&) = delete;
  162. IntrusiveList& operator=(const IntrusiveList&) = delete;
  163. // This function will assert if it finds the list containing |node| is not in
  164. // a valid state.
  165. static void Check(NodeType* node);
  166. // A special node used to represent both the start and end of the list,
  167. // without being part of the list.
  168. NodeType sentinel_;
  169. };
  170. // Implementation of IntrusiveList
  171. template <class NodeType>
  172. inline IntrusiveList<NodeType>::IntrusiveList() : sentinel_() {
  173. sentinel_.next_node_ = &sentinel_;
  174. sentinel_.previous_node_ = &sentinel_;
  175. sentinel_.is_sentinel_ = true;
  176. }
  177. template <class NodeType>
  178. IntrusiveList<NodeType>::IntrusiveList(IntrusiveList&& list) : sentinel_() {
  179. sentinel_.next_node_ = &sentinel_;
  180. sentinel_.previous_node_ = &sentinel_;
  181. sentinel_.is_sentinel_ = true;
  182. list.sentinel_.ReplaceWith(&sentinel_);
  183. }
  184. template <class NodeType>
  185. IntrusiveList<NodeType>::~IntrusiveList() {
  186. clear();
  187. }
  188. template <class NodeType>
  189. IntrusiveList<NodeType>& IntrusiveList<NodeType>::operator=(
  190. IntrusiveList<NodeType>&& list) {
  191. list.sentinel_.ReplaceWith(&sentinel_);
  192. return *this;
  193. }
  194. template <class NodeType>
  195. inline typename IntrusiveList<NodeType>::iterator
  196. IntrusiveList<NodeType>::begin() {
  197. return iterator(sentinel_.next_node_);
  198. }
  199. template <class NodeType>
  200. inline typename IntrusiveList<NodeType>::iterator
  201. IntrusiveList<NodeType>::end() {
  202. return iterator(&sentinel_);
  203. }
  204. template <class NodeType>
  205. inline typename IntrusiveList<NodeType>::const_iterator
  206. IntrusiveList<NodeType>::begin() const {
  207. return const_iterator(sentinel_.next_node_);
  208. }
  209. template <class NodeType>
  210. inline typename IntrusiveList<NodeType>::const_iterator
  211. IntrusiveList<NodeType>::end() const {
  212. return const_iterator(&sentinel_);
  213. }
  214. template <class NodeType>
  215. inline typename IntrusiveList<NodeType>::const_iterator
  216. IntrusiveList<NodeType>::cbegin() const {
  217. return const_iterator(sentinel_.next_node_);
  218. }
  219. template <class NodeType>
  220. inline typename IntrusiveList<NodeType>::const_iterator
  221. IntrusiveList<NodeType>::cend() const {
  222. return const_iterator(&sentinel_);
  223. }
  224. template <class NodeType>
  225. void IntrusiveList<NodeType>::push_back(NodeType* node) {
  226. node->InsertBefore(&sentinel_);
  227. }
  228. template <class NodeType>
  229. bool IntrusiveList<NodeType>::empty() const {
  230. return sentinel_.NextNode() == nullptr;
  231. }
  232. template <class NodeType>
  233. void IntrusiveList<NodeType>::clear() {
  234. while (!empty()) {
  235. front().RemoveFromList();
  236. }
  237. }
  238. template <class NodeType>
  239. NodeType& IntrusiveList<NodeType>::front() {
  240. NodeType* node = sentinel_.NextNode();
  241. assert(node != nullptr && "Can't get the front of an empty list.");
  242. return *node;
  243. }
  244. template <class NodeType>
  245. NodeType& IntrusiveList<NodeType>::back() {
  246. NodeType* node = sentinel_.PreviousNode();
  247. assert(node != nullptr && "Can't get the back of an empty list.");
  248. return *node;
  249. }
  250. template <class NodeType>
  251. const NodeType& IntrusiveList<NodeType>::front() const {
  252. NodeType* node = sentinel_.NextNode();
  253. assert(node != nullptr && "Can't get the front of an empty list.");
  254. return *node;
  255. }
  256. template <class NodeType>
  257. const NodeType& IntrusiveList<NodeType>::back() const {
  258. NodeType* node = sentinel_.PreviousNode();
  259. assert(node != nullptr && "Can't get the back of an empty list.");
  260. return *node;
  261. }
  262. template <class NodeType>
  263. void IntrusiveList<NodeType>::Splice(iterator where,
  264. IntrusiveList<NodeType>* other,
  265. iterator first, iterator last) {
  266. if (first == last) return;
  267. if (other == this) return;
  268. NodeType* first_prev = first.node_->previous_node_;
  269. NodeType* where_next = where.node_->next_node_;
  270. // Attach first.
  271. where.node_->next_node_ = first.node_;
  272. first.node_->previous_node_ = where.node_;
  273. // Attach last.
  274. where_next->previous_node_ = last.node_->previous_node_;
  275. last.node_->previous_node_->next_node_ = where_next;
  276. // Fixup other.
  277. first_prev->next_node_ = last.node_;
  278. last.node_->previous_node_ = first_prev;
  279. }
  280. template <class NodeType>
  281. void IntrusiveList<NodeType>::Check(NodeType* start) {
  282. int sentinel_count = 0;
  283. NodeType* p = start;
  284. do {
  285. assert(p != nullptr);
  286. assert(p->next_node_->previous_node_ == p);
  287. assert(p->previous_node_->next_node_ == p);
  288. if (p->is_sentinel_) sentinel_count++;
  289. p = p->next_node_;
  290. } while (p != start);
  291. assert(sentinel_count == 1 && "List should have exactly 1 sentinel node.");
  292. p = start;
  293. do {
  294. assert(p != nullptr);
  295. assert(p->previous_node_->next_node_ == p);
  296. assert(p->next_node_->previous_node_ == p);
  297. if (p->is_sentinel_) sentinel_count++;
  298. p = p->previous_node_;
  299. } while (p != start);
  300. }
  301. } // namespace utils
  302. } // namespace spvtools
  303. #endif // SOURCE_UTIL_ILIST_H_