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