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