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