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) {}
next_(nullptr)44 ListNode(ListNode && /* unused */) noexcept : next_(nullptr) {}
45
operator =(const ListNode & )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
operator ++()79 ListIterator &operator++()
80 {
81 ASSERT(node_);
82 node_ = node_->next_;
83 return *this;
84 }
85
operator ++(int)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
operator +(int n)94 ListIterator operator+(int n)
95 {
96 ASSERT(node_);
97 ListIterator tmp(*this);
98 std::advance(tmp, n);
99 return tmp;
100 }
101
operator *() const102 T &operator*() const
103 {
104 return *(static_cast<T *>(const_cast<ListNode *>(node_)));
105 }
106
operator ->() const107 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;
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() const166 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() const176 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() const186 ConstIterator end() const
187 {
188 return ConstIterator(nullptr);
189 }
190 // NOLINTNEXTLINE(readability-identifier-naming)
cbefore_begin() const191 ConstIterator cbefore_begin() const
192 {
193 return ConstIterator(&head_);
194 }
195 // NOLINTNEXTLINE(readability-identifier-naming)
cbegin() const196 ConstIterator cbegin() const
197 {
198 return ConstIterator(head_.next_);
199 }
200 // NOLINTNEXTLINE(readability-identifier-naming)
cend() const201 ConstIterator cend() const
202 {
203 return ConstIterator(nullptr);
204 }
205
Empty() const206 bool Empty() const
207 {
208 return begin() == end();
209 }
210
Front()211 Reference Front()
212 {
213 return *begin();
214 }
Front() const215 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
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>
operator ==( const ListIterator<T> &lhs, const ListIterator<OtherT> &rhs)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>
operator !=( const ListIterator<T> &lhs, const ListIterator<OtherT> &rhs)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
operator ++()382 DListIterator &operator++()
383 {
384 ASSERT(node_);
385 node_ = node_->next;
386 return *this;
387 }
388
389 // NOLINTNEXTLINE(cert-dcl21-cpp)
operator ++(int)390 DListIterator operator++(int)
391 {
392 ASSERT(node_);
393 auto ret = *this;
394 ++(*this);
395 return ret;
396 }
397
operator *() const398 T &operator*() const
399 {
400 ASSERT(node_);
401 return *node_;
402 }
403
operator ->() const404 T *operator->() const
405 {
406 ASSERT(node_);
407 return node_;
408 }
409
operator ==(DListIterator other) const410 bool operator==(DListIterator other) const
411 {
412 return node_ == other.node_;
413 }
414
operator !=(DListIterator other) const415 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
operator ++()444 DListReverseIterator &operator++()
445 {
446 ASSERT(node_);
447 node_ = node_->prev;
448 return *this;
449 }
450
451 // NOLINTNEXTLINE(cert-dcl21-cpp)
operator ++(int)452 DListReverseIterator operator++(int)
453 {
454 ASSERT(node_);
455 auto ret = *this;
456 ++(*this);
457 return ret;
458 }
459
operator *() const460 T &operator*() const
461 {
462 ASSERT(node_);
463 return *node_;
464 }
465
operator ->() const466 T *operator->() const
467 {
468 ASSERT(node_);
469 return node_;
470 }
471
operator ==(DListReverseIterator other) const472 bool operator==(DListReverseIterator other) const
473 {
474 return node_ == other.node_;
475 }
476
operator !=(DListReverseIterator other) const477 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() const507 size_t size() const
508 {
509 return size_;
510 }
511
empty() const512 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() const524 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() const536 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() const548 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() const560 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