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