• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
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 
16 #ifndef PANDA_LIBPANDABASE_UTILS_LIST_H_
17 #define PANDA_LIBPANDABASE_UTILS_LIST_H_
18 
19 #include "macros.h"
20 
21 namespace panda {
22 
23 template <typename T>
24 class List;
25 template <typename T>
26 class ListIterator;
27 
28 /**
29  * Intrusive forward list node, which shall be inherited by list element class.
30  */
31 class ListNode {
32 public:
33     ListNode() = default;
34     ~ListNode() = default;
35 
ListNode(ListNode * next)36     explicit ListNode(ListNode *next) : next_(next) {}
ListNode(const ListNode &)37     ListNode(const ListNode & /* unused */) : next_(nullptr) {}
ListNode(ListNode &&)38     ListNode(ListNode && /* unused */) noexcept : next_(nullptr) {}
39 
40     ListNode &operator=(const ListNode & /* unused */)  // NOLINT(bugprone-unhandled-self-assignment, cert-oop54-cpp)
41     {
42         return *this;
43     }
44     ListNode &operator=(ListNode && /* unused */) noexcept
45     {
46         return *this;
47     }
48 
49 private:
50     mutable const ListNode *next_ {nullptr};
51 
52     template <typename T>
53     friend class List;
54     template <typename T>
55     friend class ListIterator;
56 };
57 
58 /**
59  * Intrusive forward list iterator
60  */
61 template <typename T>
62 class ListIterator : public std::iterator<std::forward_iterator_tag, T> {
63 public:
64     ListIterator() = default;
ListIterator(const ListNode * node)65     explicit ListIterator(const ListNode *node) : node_(node) {}
66 
67     template <typename OtherT, typename = typename std::enable_if<std::is_same<T, const OtherT>::value>::type>
ListIterator(const ListIterator<OtherT> & src)68     ListIterator(const ListIterator<OtherT> &src)  // NOLINT(google-explicit-constructor)
69         : node_(src.node_)
70     {
71     }
72 
73     ListIterator &operator++()
74     {
75         ASSERT(node_);
76         node_ = node_->next_;
77         return *this;
78     }
79 
80     const ListIterator operator++(int)  // NOLINT(readability-const-return-type)
81     {
82         ASSERT(node_);
83         ListIterator tmp(*this);
84         node_ = node_->next_;
85         return tmp;
86     }
87 
88     ListIterator operator+(int n)
89     {
90         ASSERT(node_);
91         ListIterator tmp(*this);
92         std::advance(tmp, n);
93         return tmp;
94     }
95 
96     T &operator*() const
97     {
98         return *(static_cast<T *>(const_cast<ListNode *>(node_)));
99     }
100 
101     T *operator->() const
102     {
103         return static_cast<T *>(const_cast<ListNode *>(node_));
104     }
105 
106     ~ListIterator() = default;
107 
108     DEFAULT_COPY_SEMANTIC(ListIterator);
109     DEFAULT_NOEXCEPT_MOVE_SEMANTIC(ListIterator);
110 
111 private:
112     const ListNode *node_ {nullptr};
113 
114     template <typename OtherT>
115     friend class ListIterator;
116 
117     template <typename OtherT>
118     friend class List;
119 
120     template <typename T1, typename T2>
121     // NOLINTNEXTLINE(readability-redundant-declaration)
122     friend typename std::enable_if<std::is_same<const T1, const T2>::value, bool>::type operator==(
123         const ListIterator<T1> &lhs, const ListIterator<T2> &rhs);
124 };
125 
126 /**
127  * Intrusive forward list
128  */
129 template <typename T>
130 class List {
131 public:
132     using ValueType = T;
133     using Reference = T &;
134     using ConstReference = const T &;
135     using Iterator = ListIterator<T>;
136     using ConstIterator = ListIterator<const T>;
137 
138     List() = default;
139     List(const List & /* unused */) = delete;
List(List && other)140     List(List &&other) noexcept
141     {
142         head_ = other.head_;
143         other.head_ = nullptr;
144     }
145     ~List() = default;
146 
147     List &operator=(const List & /* unused */) = delete;
148     List &operator=(List &&other) noexcept
149     {
150         head_ = other.head_;
151         other.head_ = nullptr;
152     }
153 
154     // NOLINTNEXTLINE(readability-identifier-naming)
before_begin()155     Iterator before_begin()
156     {
157         return Iterator(&head_);
158     }
159 
160     // NOLINTNEXTLINE(readability-identifier-naming)
before_begin()161     ConstIterator before_begin() const
162     {
163         return ConstIterator(&head_);
164     }
165 
166     // NOLINTNEXTLINE(readability-identifier-naming)
begin()167     Iterator begin()
168     {
169         return Iterator(head_.next_);
170     }
171 
172     // NOLINTNEXTLINE(readability-identifier-naming)
begin()173     ConstIterator begin() const
174     {
175         return ConstIterator(head_.next_);
176     }
177 
178     // NOLINTNEXTLINE(readability-identifier-naming)
end()179     Iterator end()
180     {
181         return Iterator(nullptr);
182     }
183 
184     // NOLINTNEXTLINE(readability-identifier-naming)
end()185     ConstIterator end() const
186     {
187         return ConstIterator(nullptr);
188     }
189 
190     // NOLINTNEXTLINE(readability-identifier-naming)
cbefore_begin()191     ConstIterator cbefore_begin() const
192     {
193         return ConstIterator(&head_);
194     }
195 
196     // NOLINTNEXTLINE(readability-identifier-naming)
cbegin()197     ConstIterator cbegin() const
198     {
199         return ConstIterator(head_.next_);
200     }
201 
202     // NOLINTNEXTLINE(readability-identifier-naming)
cend()203     ConstIterator cend() const
204     {
205         return ConstIterator(nullptr);
206     }
207 
Empty()208     bool Empty() const
209     {
210         return begin() == end();
211     }
212 
Front()213     Reference Front()
214     {
215         return *begin();
216     }
217 
Front()218     ConstReference Front() const
219     {
220         return *begin();
221     }
222 
PushFront(ValueType & value)223     void PushFront(ValueType &value)
224     {
225         InsertAfter(before_begin(), value);
226     }
227 
PushFront(ValueType && value)228     void PushFront(ValueType &&value)
229     {
230         InsertAfter(before_begin(), value);
231     }
232 
PopFront()233     void PopFront()
234     {
235         ASSERT(!Empty());
236         EraseAfter(before_begin());
237     }
238 
InsertAfter(ConstIterator position,ValueType & value)239     Iterator InsertAfter(ConstIterator position, ValueType &value)
240     {
241         auto new_node = static_cast<const ListNode *>(&value);
242         new_node->next_ = position.node_->next_;
243         position.node_->next_ = new_node;
244         return Iterator(new_node);
245     }
246 
247     template <typename InputIterator>
InsertAfter(ConstIterator position,InputIterator first,InputIterator last)248     Iterator InsertAfter(ConstIterator position, InputIterator first, InputIterator last)
249     {
250         while (first != last) {
251             position = InsertAfter(position, *first++);
252         }
253         return Iterator(position.node_);
254     }
255 
EraseAfter(ConstIterator position)256     Iterator EraseAfter(ConstIterator position)
257     {
258         ConstIterator last = position;
259         constexpr size_t SHIFT = 2;
260         std::advance(last, SHIFT);
261         return EraseAfter(position, last);
262     }
263 
264     /**
265      * Erase elements in range (position, last)
266      */
EraseAfter(ConstIterator position,ConstIterator last)267     Iterator EraseAfter(ConstIterator position, ConstIterator last)
268     {
269         ASSERT(position != last);
270         position.node_->next_ = last.node_;
271         return Iterator(last.node_);
272     }
273 
Remove(const ValueType & value)274     bool Remove(const ValueType &value)
275     {
276         return RemoveIf([&value](const ValueType &v) { return value == v; });
277     }
278 
279     template <typename Predicate>
RemoveIf(Predicate pred)280     bool RemoveIf(Predicate pred)
281     {
282         bool found = false;
283         Iterator prev = before_begin();
284         for (Iterator current = begin(); current != end(); ++current) {
285             if (pred(*current)) {
286                 found = true;
287                 EraseAfter(prev);
288                 current = prev;
289             } else {
290                 prev = current;
291             }
292         }
293         return found;
294     }
295 
Swap(List & other)296     void Swap(List &other) noexcept
297     {
298         std::swap(head_.next_, other.head_.next_);
299     }
300 
Clear()301     void Clear()
302     {
303         head_.next_ = nullptr;
304     }
305 
306     /**
307      * Transfer all elements from other list into place after position.
308      */
Splice(ConstIterator position,List & other)309     void Splice(ConstIterator position, List &other)
310     {
311         Splice(position, other, other.before_begin(), other.end());
312     }
313 
314     /**
315      * Transfer single element first+1 into place after position.
316      */
Splice(ConstIterator position,List & other,ConstIterator first)317     void Splice(ConstIterator position, List &other, ConstIterator first)
318     {
319         constexpr size_t SHIFT = 2;
320         Splice(position, other, first, first + SHIFT);
321     }
322 
323     /**
324      * Transfer the elements in the range (first,last) into place after position.
325      */
Splice(ConstIterator position,List & src_list,ConstIterator first,ConstIterator last)326     void Splice(ConstIterator position, List &src_list, ConstIterator first, ConstIterator last)
327     {
328         ASSERT(position != end());
329         ASSERT(first != last);
330 
331         if (++ConstIterator(first) == last) {
332             return;
333         }
334 
335         if (++ConstIterator(position) == end() && last == src_list.end()) {
336             position.node_->next_ = first.node_->next_;
337             first.node_->next_ = nullptr;
338             return;
339         }
340         ConstIterator before_last = first;
341         while (++ConstIterator(before_last) != last) {
342             ++before_last;
343         }
344 
345         const ListNode *first_taken = first.node_->next_;
346         first.node_->next_ = last.node_;
347         before_last.node_->next_ = position.node_->next_;
348         position.node_->next_ = first_taken;
349     }
350 
351 private:
352     ListNode head_;
353 };
354 
355 template <typename T, typename OtherT>
356 typename std::enable_if<std::is_same<const T, const OtherT>::value, bool>::type operator==(
357     const ListIterator<T> &lhs, const ListIterator<OtherT> &rhs)
358 {
359     return lhs.node_ == rhs.node_;
360 }
361 
362 template <typename T, typename OtherT>
363 typename std::enable_if<std::is_same<const T, const OtherT>::value, bool>::type operator!=(
364     const ListIterator<T> &lhs, const ListIterator<OtherT> &rhs)
365 {
366     return !(lhs == rhs);
367 }
368 
369 /**
370  * Intrusive doubly list node
371  */
372 struct DListNode {
373     DListNode *prev = nullptr;
374     DListNode *next = nullptr;
375 };
376 
377 /**
378  * Intrusive doubly list iterator
379  */
380 template <typename T>
381 class DListIterator {
382 public:
383     DListIterator() = default;
384     ~DListIterator() = default;
385 
DListIterator(T * node)386     explicit DListIterator(T *node) : node_(node) {}
387     DEFAULT_COPY_SEMANTIC(DListIterator);
388     DEFAULT_NOEXCEPT_MOVE_SEMANTIC(DListIterator);
389 
390     DListIterator &operator++()
391     {
392         ASSERT(node_);
393         node_ = node_->next;
394         return *this;
395     }
396 
397     // NOLINTNEXTLINE(cert-dcl21-cpp)
398     DListIterator operator++(int)
399     {
400         ASSERT(node_);
401         auto ret = *this;
402         ++(*this);
403         return ret;
404     }
405 
406     T &operator*() const
407     {
408         ASSERT(node_);
409         return *node_;
410     }
411 
412     T *operator->() const
413     {
414         ASSERT(node_);
415         return node_;
416     }
417 
418     bool operator==(DListIterator other) const
419     {
420         return node_ == other.node_;
421     }
422 
423     bool operator!=(DListIterator other) const
424     {
425         return !(*this == other);
426     }
427 
428 private:
429     T *node_ = nullptr;
430     friend class DList;
431 };
432 
433 /**
434  * Intrusive doubly list reverse iterator
435  */
436 template <typename T>
437 class DListReverseIterator {
438 public:
439     DListReverseIterator() = default;
440     ~DListReverseIterator() = default;
441 
DListReverseIterator(T * node)442     explicit DListReverseIterator(T *node) : node_(node) {}
443     DEFAULT_COPY_SEMANTIC(DListReverseIterator);
444     DEFAULT_NOEXCEPT_MOVE_SEMANTIC(DListReverseIterator);
445 
base()446     DListIterator<T> base()
447     {
448         DListIterator<T> it(node_);
449         return it;
450     }
451 
452     DListReverseIterator &operator++()
453     {
454         ASSERT(node_);
455         node_ = node_->prev;
456         return *this;
457     }
458 
459     // NOLINTNEXTLINE(cert-dcl21-cpp)
460     DListReverseIterator operator++(int)
461     {
462         ASSERT(node_);
463         auto ret = *this;
464         ++(*this);
465         return ret;
466     }
467 
468     T &operator*() const
469     {
470         ASSERT(node_);
471         return *node_;
472     }
473 
474     T *operator->() const
475     {
476         ASSERT(node_);
477         return node_;
478     }
479 
480     bool operator==(DListReverseIterator other) const
481     {
482         return node_ == other.node_;
483     }
484 
485     bool operator!=(DListReverseIterator other) const
486     {
487         return !(*this == other);
488     }
489 
490 private:
491     T *node_ = nullptr;
492     friend class DList;
493 };
494 
495 /**
496  * Intrusive doubly list
497  */
498 class DList {
499 public:
500     using Iterator = DListIterator<DListNode>;
501     using ConstIterator = DListIterator<const DListNode>;
502     using ReverseIterator = DListReverseIterator<DListNode>;
503     using ConstReverseIterator = DListReverseIterator<const DListNode>;
504 
DList()505     DList()
506     {
507         clear();
508     }
509 
510     ~DList() = default;
511 
512     NO_COPY_SEMANTIC(DList);
513     NO_MOVE_SEMANTIC(DList);
514 
size()515     size_t size() const
516     {
517         return size_;
518     }
519 
empty()520     bool empty() const
521     {
522         return size_ == 0;
523     }
524 
525     // NOLINTNEXTLINE(readability-identifier-naming)
begin()526     Iterator begin()
527     {
528         return Iterator(head_.next);
529     }
530 
531     // NOLINTNEXTLINE(readability-identifier-naming)
begin()532     ConstIterator begin() const
533     {
534         return ConstIterator(head_.next);
535     }
536 
537     // NOLINTNEXTLINE(readability-identifier-naming)
rbegin()538     ReverseIterator rbegin()
539     {
540         return ReverseIterator(head_.prev);
541     }
542 
543     // NOLINTNEXTLINE(readability-identifier-naming)
rbegin()544     ConstReverseIterator rbegin() const
545     {
546         return ConstReverseIterator(head_.prev);
547     }
548 
549     // NOLINTNEXTLINE(readability-identifier-naming)
end()550     Iterator end()
551     {
552         return Iterator(&head_);
553     }
554 
555     // NOLINTNEXTLINE(readability-identifier-naming)
end()556     ConstIterator end() const
557     {
558         return ConstIterator(&head_);
559     }
560 
561     // NOLINTNEXTLINE(readability-identifier-naming)
rend()562     ReverseIterator rend()
563     {
564         return ReverseIterator(&head_);
565     }
566 
567     // NOLINTNEXTLINE(readability-identifier-naming)
rend()568     ConstReverseIterator rend() const
569     {
570         return ConstReverseIterator(&head_);
571     }
572 
insert(Iterator position,DListNode * new_node)573     Iterator insert(Iterator position, DListNode *new_node)
574     {
575         ++size_;
576         new_node->next = position.node_;
577         new_node->prev = position.node_->prev;
578         position.node_->prev->next = new_node;
579         position.node_->prev = new_node;
580         return Iterator(new_node);
581     }
582 
push_back(DListNode * new_node)583     Iterator push_back(DListNode *new_node)
584     {
585         return insert(end(), new_node);
586     }
587 
erase(DListNode * node)588     Iterator erase(DListNode *node)
589     {
590         ASSERT(size_ > 0);
591         --size_;
592         node->next->prev = node->prev;
593         node->prev->next = node->next;
594         return Iterator(node->next);
595     }
596 
erase(Iterator position)597     Iterator erase(Iterator position)
598     {
599         return erase(position.node_);
600     }
601 
clear()602     void clear()
603     {
604         head_.prev = &head_;
605         head_.next = &head_;
606         size_ = 0;
607     }
608 
609     template <typename Predicate>
610     // NOLINTNEXTLINE(readability-identifier-naming)
remove_if(Predicate pred)611     void remove_if(Predicate pred)
612     {
613         Iterator it = begin();
614         while (it != end()) {
615             if (pred(&(*it))) {
616                 it = erase(it);
617             } else {
618                 ++it;
619             }
620         }
621     }
622 
623 private:
624     DListNode head_;
625     size_t size_ = 0;
626 };
627 
628 }  // namespace panda
629 
630 #endif  // PANDA_LIBPANDABASE_UTILS_LIST_H_
631