1 /* 2 * Copyright (c) 2019, The OpenThread Authors. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 3. Neither the name of the copyright holder nor the 13 * names of its contributors may be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /** 30 * @file 31 * This file includes definitions for a generic singly linked list. 32 */ 33 34 #ifndef LINKED_LIST_HPP_ 35 #define LINKED_LIST_HPP_ 36 37 #include "openthread-core-config.h" 38 39 #include <stdio.h> 40 41 #include "common/error.hpp" 42 #include "common/iterator_utils.hpp" 43 44 namespace ot { 45 46 /** 47 * @addtogroup core-linked-list 48 * 49 * @brief 50 * This module includes definitions for OpenThread Singly Linked List. 51 * 52 * @{ 53 * 54 */ 55 56 /** 57 * This template class represents a linked list entry. 58 * 59 * This class provides methods to `GetNext()` and `SetNext()` in the linked list entry. 60 * 61 * Users of this class should follow CRTP-style inheritance, i.e., the `Type` class itself should publicly inherit 62 * from `LinkedListEntry<Type>`. 63 * 64 * The template type `Type` should contain a `mNext` member variable. The `mNext` should be of a type that can be 65 * down-casted to `Type` itself. 66 * 67 */ 68 template <class Type> class LinkedListEntry 69 { 70 public: 71 /** 72 * This method gets the next entry in the linked list. 73 * 74 * @returns A pointer to the next entry in the linked list or nullptr if at the end of the list. 75 * 76 */ GetNext(void) const77 const Type *GetNext(void) const { return static_cast<const Type *>(static_cast<const Type *>(this)->mNext); } 78 79 /** 80 * This method gets the next entry in the linked list. 81 * 82 * @returns A pointer to the next entry in the linked list or nullptr if at the end of the list. 83 * 84 */ GetNext(void)85 Type *GetNext(void) { return static_cast<Type *>(static_cast<Type *>(this)->mNext); } 86 87 /** 88 * This method sets the next pointer on the entry. 89 * 90 * @param[in] aNext A pointer to the next entry. 91 * 92 */ SetNext(Type * aNext)93 void SetNext(Type *aNext) { static_cast<Type *>(this)->mNext = aNext; } 94 }; 95 96 /** 97 * This template class represents a singly linked list. 98 * 99 * The template type `Type` should provide `GetNext()` and `SetNext()` methods (which can be realized by `Type` 100 * inheriting from `LinkedListEntry<Type>` class). 101 * 102 */ 103 template <typename Type> class LinkedList 104 { 105 class Iterator; 106 class ConstIterator; 107 108 public: 109 /** 110 * This constructor initializes the linked list. 111 * 112 */ LinkedList(void)113 LinkedList(void) 114 : mHead(nullptr) 115 { 116 } 117 118 /** 119 * This method returns the entry at the head of the linked list 120 * 121 * @returns Pointer to the entry at the head of the linked list, or nullptr if the list is empty. 122 * 123 */ GetHead(void)124 Type *GetHead(void) { return mHead; } 125 126 /** 127 * This method returns the entry at the head of the linked list. 128 * 129 * @returns Pointer to the entry at the head of the linked list, or nullptr if the list is empty. 130 * 131 */ GetHead(void) const132 const Type *GetHead(void) const { return mHead; } 133 134 /** 135 * This method sets the head of the linked list to a given entry. 136 * 137 * @param[in] aHead A pointer to an entry to set as the head of the linked list. 138 * 139 */ SetHead(Type * aHead)140 void SetHead(Type *aHead) { mHead = aHead; } 141 142 /** 143 * This method clears the linked list. 144 * 145 */ Clear(void)146 void Clear(void) { mHead = nullptr; } 147 148 /** 149 * This method indicates whether the linked list is empty or not. 150 * 151 * @retval TRUE If the linked list is empty. 152 * @retval FALSE If the linked list is not empty. 153 * 154 */ IsEmpty(void) const155 bool IsEmpty(void) const { return (mHead == nullptr); } 156 157 /** 158 * This method pushes an entry at the head of the linked list. 159 * 160 * @param[in] aEntry A reference to an entry to push at the head of linked list. 161 * 162 */ Push(Type & aEntry)163 void Push(Type &aEntry) 164 { 165 aEntry.SetNext(mHead); 166 mHead = &aEntry; 167 } 168 169 /** 170 * This method pushes an entry after a given previous existing entry in the linked list. 171 * 172 * @param[in] aEntry A reference to an entry to push into the list. 173 * @param[in] aPrevEntry A reference to a previous entry (new entry @p aEntry will be pushed after this). 174 * 175 */ PushAfter(Type & aEntry,Type & aPrevEntry)176 void PushAfter(Type &aEntry, Type &aPrevEntry) 177 { 178 aEntry.SetNext(aPrevEntry.GetNext()); 179 aPrevEntry.SetNext(&aEntry); 180 } 181 182 /** 183 * This method pops an entry from head of the linked list. 184 * 185 * @note This method does not change the popped entry itself, i.e., the popped entry next pointer stays as before. 186 * 187 * @returns The entry that was popped if the list is not empty, or nullptr if the list is empty. 188 * 189 */ Pop(void)190 Type *Pop(void) 191 { 192 Type *entry = mHead; 193 194 if (mHead != nullptr) 195 { 196 mHead = mHead->GetNext(); 197 } 198 199 return entry; 200 } 201 202 /** 203 * This method pops an entry after a given previous entry. 204 * 205 * @note This method does not change the popped entry itself, i.e., the popped entry next pointer stays as before. 206 * 207 * @param[in] aPrevEntry A pointer to a previous entry. If it is not nullptr the entry after this will be popped, 208 * otherwise (if it is nullptr) the entry at the head of the list is popped. 209 * 210 * @returns Pointer to the entry that was popped, or nullptr if there is no entry to pop. 211 * 212 */ PopAfter(Type * aPrevEntry)213 Type *PopAfter(Type *aPrevEntry) 214 { 215 Type *entry; 216 217 if (aPrevEntry == nullptr) 218 { 219 entry = Pop(); 220 } 221 else 222 { 223 entry = aPrevEntry->GetNext(); 224 225 if (entry != nullptr) 226 { 227 aPrevEntry->SetNext(entry->GetNext()); 228 } 229 } 230 231 return entry; 232 } 233 234 /** 235 * This method indicates whether the linked list contains a given entry. 236 * 237 * @param[in] aEntry A reference to an entry. 238 * 239 * @retval TRUE The linked list contains @p aEntry. 240 * @retval FALSE The linked list does not contain @p aEntry. 241 * 242 */ Contains(const Type & aEntry) const243 bool Contains(const Type &aEntry) const 244 { 245 const Type *prev; 246 247 return Find(aEntry, prev) == kErrorNone; 248 } 249 250 /** 251 * This template method indicates whether the linked list contains an entry matching a given entry indicator. 252 * 253 * The template type `Indicator` specifies the type of @p aIndicator object which is used to match against entries 254 * in the list. To check that an entry matches the given indicator, the `Matches()` method is invoked on each 255 * `Type` entry in the list. The `Matches()` method should be provided by `Type` class accordingly: 256 * 257 * bool Type::Matches(const Indicator &aIndicator) const 258 * 259 * @param[in] aIndicator An entry indicator to match against entries in the list. 260 * 261 * @retval TRUE The linked list contains an entry matching @p aIndicator. 262 * @retval FALSE The linked list contains no entry matching @p aIndicator. 263 * 264 */ ContainsMatching(const Indicator & aIndicator) const265 template <typename Indicator> bool ContainsMatching(const Indicator &aIndicator) const 266 { 267 return FindMatching(aIndicator) != nullptr; 268 } 269 270 /** 271 * This method adds an entry (at the head of the linked list) if it is not already in the list. 272 * 273 * @param[in] aEntry A reference to an entry to add. 274 * 275 * @retval kErrorNone The entry was successfully added at the head of the list. 276 * @retval kErrorAlready The entry is already in the list. 277 * 278 */ Add(Type & aEntry)279 Error Add(Type &aEntry) 280 { 281 Error error = kErrorNone; 282 283 if (Contains(aEntry)) 284 { 285 error = kErrorAlready; 286 } 287 else 288 { 289 Push(aEntry); 290 } 291 292 return error; 293 } 294 295 /** 296 * This method removes an entry from the linked list. 297 * 298 * @note This method does not change the removed entry @p aEntry itself (it is `const`), i.e., the entry next 299 * pointer of @p aEntry stays as before. 300 * 301 * @param[in] aEntry A reference to an entry to remove. 302 * 303 * @retval kErrorNone The entry was successfully removed from the list. 304 * @retval kErrorNotFound Could not find the entry in the list. 305 * 306 */ Remove(const Type & aEntry)307 Error Remove(const Type &aEntry) 308 { 309 Type *prev; 310 Error error = Find(aEntry, prev); 311 312 if (error == kErrorNone) 313 { 314 PopAfter(prev); 315 } 316 317 return error; 318 } 319 320 /** 321 * This template method removes an entry matching a given entry indicator from the linked list. 322 * 323 * The template type `Indicator` specifies the type of @p aIndicator object which is used to match against entries 324 * in the list. To check that an entry matches the given indicator, the `Matches()` method is invoked on each 325 * `Type` entry in the list. The `Matches()` method should be provided by `Type` class accordingly: 326 * 327 * bool Type::Matches(const Indicator &aIndicator) const 328 * 329 * @note This method does not change the removed entry itself (which is returned in case of success), i.e., the 330 * entry next pointer stays as before. 331 * 332 * 333 * @param[in] aIndicator An entry indicator to match against entries in the list. 334 * 335 * @returns A pointer to the removed matching entry if one could be found, or nullptr if no matching entry is found. 336 * 337 */ RemoveMatching(const Indicator & aIndicator)338 template <typename Indicator> Type *RemoveMatching(const Indicator &aIndicator) 339 { 340 Type *prev; 341 Type *entry = FindMatching(aIndicator, prev); 342 343 if (entry != nullptr) 344 { 345 PopAfter(prev); 346 } 347 348 return entry; 349 } 350 351 /** 352 * This method searches within the linked list to find an entry and if found returns a pointer to previous entry. 353 * 354 * @param[in] aEntry A reference to an entry to find. 355 * @param[out] aPrevEntry A pointer to output the previous entry on success (when @p aEntry is found in the list). 356 * @p aPrevEntry is set to nullptr if @p aEntry is the head of the list. Otherwise it is 357 * updated to point to the previous entry before @p aEntry in the list. 358 * 359 * @retval kErrorNone The entry was found in the list and @p aPrevEntry was updated successfully. 360 * @retval kErrorNotFound The entry was not found in the list. 361 * 362 */ Find(const Type & aEntry,const Type * & aPrevEntry) const363 Error Find(const Type &aEntry, const Type *&aPrevEntry) const 364 { 365 Error error = kErrorNotFound; 366 367 aPrevEntry = nullptr; 368 369 for (const Type *entry = mHead; entry != nullptr; aPrevEntry = entry, entry = entry->GetNext()) 370 { 371 if (entry == &aEntry) 372 { 373 error = kErrorNone; 374 break; 375 } 376 } 377 378 return error; 379 } 380 381 /** 382 * This method searches within the linked list to find an entry and if found returns a pointer to previous entry. 383 * 384 * @param[in] aEntry A reference to an entry to find. 385 * @param[out] aPrevEntry A pointer to output the previous entry on success (when @p aEntry is found in the list). 386 * @p aPrevEntry is set to nullptr if @p aEntry is the head of the list. Otherwise it is 387 * updated to point to the previous entry before @p aEntry in the list. 388 * 389 * @retval kErrorNone The entry was found in the list and @p aPrevEntry was updated successfully. 390 * @retval kErrorNotFound The entry was not found in the list. 391 * 392 */ Find(const Type & aEntry,Type * & aPrevEntry)393 Error Find(const Type &aEntry, Type *&aPrevEntry) 394 { 395 return const_cast<const LinkedList *>(this)->Find(aEntry, const_cast<const Type *&>(aPrevEntry)); 396 } 397 398 /** 399 * This template method searches within a given range of the linked list to find an entry matching a given 400 * indicator. 401 * 402 * The template type `Indicator` specifies the type of @p aIndicator object which is used to match against entries 403 * in the list. To check that an entry matches the given indicator, the `Matches()` method is invoked on each 404 * `Type` entry in the list. The `Matches()` method should be provided by `Type` class accordingly: 405 * 406 * bool Type::Matches(const Indicator &aIndicator) const 407 * 408 * @param[in] aBegin A pointer to the begin of the range. 409 * @param[in] aEnd A pointer to the end of the range, or nullptr to search all entries after @p aBegin. 410 * @param[in] aIndicator An indicator to match with entries in the list. 411 * @param[out] aPrevEntry A pointer to output the previous entry on success (when a match is found in the list). 412 * @p aPrevEntry is set to nullptr if the matching entry is the head of the list. Otherwise 413 * it is updated to point to the previous entry before the matching entry in the list. 414 * 415 * @returns A pointer to the matching entry if one is found, or nullptr if no matching entry was found. 416 * 417 */ 418 template <typename Indicator> FindMatching(const Type * aBegin,const Type * aEnd,const Indicator & aIndicator,const Type * & aPrevEntry) const419 const Type *FindMatching(const Type * aBegin, 420 const Type * aEnd, 421 const Indicator &aIndicator, 422 const Type *& aPrevEntry) const 423 { 424 const Type *entry; 425 426 aPrevEntry = nullptr; 427 428 for (entry = aBegin; entry != aEnd; aPrevEntry = entry, entry = entry->GetNext()) 429 { 430 if (entry->Matches(aIndicator)) 431 { 432 break; 433 } 434 } 435 436 return entry; 437 } 438 439 /** 440 * This template method searches within a given range of the linked list to find an entry matching a given 441 * indicator. 442 * 443 * The template type `Indicator` specifies the type of @p aIndicator object which is used to match against entries 444 * in the list. To check that an entry matches the given indicator, the `Matches()` method is invoked on each 445 * `Type` entry in the list. The `Matches()` method should be provided by `Type` class accordingly: 446 * 447 * bool Type::Matches(const Indicator &aIndicator) const 448 * 449 * @param[in] aBegin A pointer to the begin of the range. 450 * @param[in] aEnd A pointer to the end of the range, or nullptr to search all entries after @p aBegin. 451 * @param[in] aIndicator An indicator to match with entries in the list. 452 * @param[out] aPrevEntry A pointer to output the previous entry on success (when a match is found in the list). 453 * @p aPrevEntry is set to nullptr if the matching entry is the head of the list. Otherwise 454 * it is updated to point to the previous entry before the matching entry in the list. 455 * 456 * @returns A pointer to the matching entry if one is found, or nullptr if no matching entry was found. 457 * 458 */ 459 template <typename Indicator> FindMatching(const Type * aBegin,const Type * aEnd,const Indicator & aIndicator,Type * & aPrevEntry)460 Type *FindMatching(const Type *aBegin, const Type *aEnd, const Indicator &aIndicator, Type *&aPrevEntry) 461 { 462 return const_cast<Type *>(FindMatching(aBegin, aEnd, aIndicator, const_cast<const Type *&>(aPrevEntry))); 463 } 464 465 /** 466 * This template method searches within the linked list to find an entry matching a given indicator. 467 * 468 * The template type `Indicator` specifies the type of @p aIndicator object which is used to match against entries 469 * in the list. To check that an entry matches the given indicator, the `Matches()` method is invoked on each 470 * `Type` entry in the list. The `Matches()` method should be provided by `Type` class accordingly: 471 * 472 * bool Type::Matches(const Indicator &aIndicator) const 473 * 474 * @param[in] aIndicator An indicator to match with entries in the list. 475 * @param[out] aPrevEntry A pointer to output the previous entry on success (when a match is found in the list). 476 * @p aPrevEntry is set to nullptr if the matching entry is the head of the list. Otherwise 477 * it is updated to point to the previous entry before the matching entry in the list. 478 * 479 * @returns A pointer to the matching entry if one is found, or nullptr if no matching entry was found. 480 * 481 */ FindMatching(const Indicator & aIndicator,const Type * & aPrevEntry) const482 template <typename Indicator> const Type *FindMatching(const Indicator &aIndicator, const Type *&aPrevEntry) const 483 { 484 return FindMatching(mHead, nullptr, aIndicator, aPrevEntry); 485 } 486 487 /** 488 * This template method searches within the linked list to find an entry matching a given indicator, and if found 489 * returns a pointer to its previous entry in the list. 490 * 491 * The template type `Indicator` specifies the type of @p aIndicator object which is used to match against entries 492 * in the list. To check that an entry matches the given indicator, the `Matches()` method is invoked on each 493 * `Type` entry in the list. The `Matches()` method should be provided by `Type` class accordingly: 494 * 495 * bool Type::Matches(const Indicator &aIndicator) const 496 * 497 * @param[in] aIndicator An indicator to match with entries in the list. 498 * @param[out] aPrevEntry A pointer to output the previous entry on success (when a match is found in the list). 499 * @p aPrevEntry is set to nullptr if the matching entry is the head of the list. Otherwise 500 * it is updated to point to the previous entry before the matching entry in the list. 501 * 502 * @returns A pointer to the matching entry if one is found, or nullptr if no matching entry was found. 503 * 504 */ FindMatching(const Indicator & aIndicator,Type * & aPrevEntry)505 template <typename Indicator> Type *FindMatching(const Indicator &aIndicator, Type *&aPrevEntry) 506 { 507 return const_cast<Type *>( 508 const_cast<const LinkedList *>(this)->FindMatching(aIndicator, const_cast<const Type *&>(aPrevEntry))); 509 } 510 511 /** 512 * This template method searches within the linked list to find an entry matching a given indicator. 513 * 514 * The template type `Indicator` specifies the type of @p aIndicator object which is used to match against entries 515 * in the list. To check that an entry matches the given indicator, the `Matches()` method is invoked on each 516 * `Type` entry in the list. The `Matches()` method should be provided by `Type` class accordingly: 517 * 518 * bool Type::Matches(const Indicator &aIndicator) const 519 * 520 * @param[in] aIndicator An indicator to match with entries in the list. 521 * 522 * @returns A pointer to the matching entry if one is found, or nullptr if no matching entry was found. 523 * 524 */ FindMatching(const Indicator & aIndicator) const525 template <typename Indicator> const Type *FindMatching(const Indicator &aIndicator) const 526 { 527 const Type *prev; 528 529 return FindMatching(aIndicator, prev); 530 } 531 532 /** 533 * This template method searches within the linked list to find an entry matching a given indicator. 534 * 535 * The template type `Indicator` specifies the type of @p aIndicator object which is used to match against entries 536 * in the list. To check that an entry matches the given indicator, the `Matches()` method is invoked on each 537 * `Type` entry in the list. The `Matches()` method should be provided by `Type` class accordingly: 538 * 539 * bool Type::Matches(const Indicator &aIndicator) const 540 * 541 * @param[in] aIndicator An indicator to match with entries in the list. 542 * 543 * @returns A pointer to the matching entry if one is found, or nullptr if no matching entry was found. 544 * 545 */ FindMatching(const Indicator & aIndicator)546 template <typename Indicator> Type *FindMatching(const Indicator &aIndicator) 547 { 548 return const_cast<Type *>(const_cast<const LinkedList *>(this)->FindMatching(aIndicator)); 549 } 550 551 /** 552 * This method returns the tail of the linked list (i.e., the last entry in the list). 553 * 554 * @returns A pointer to the tail entry in the linked list or nullptr if the list is empty. 555 * 556 */ GetTail(void) const557 const Type *GetTail(void) const 558 { 559 const Type *tail = mHead; 560 561 if (tail != nullptr) 562 { 563 while (tail->GetNext() != nullptr) 564 { 565 tail = tail->GetNext(); 566 } 567 } 568 569 return tail; 570 } 571 572 /** 573 * This method returns the tail of the linked list (i.e., the last entry in the list). 574 * 575 * @returns A pointer to the tail entry in the linked list or nullptr if the list is empty. 576 * 577 */ GetTail(void)578 Type *GetTail(void) { return const_cast<Type *>(const_cast<const LinkedList *>(this)->GetTail()); } 579 580 // The following methods are intended to support range-based `for` 581 // loop iteration over the linked-list entries and should not be 582 // used directly. 583 begin(void)584 Iterator begin(void) { return Iterator(GetHead()); } end(void)585 Iterator end(void) { return Iterator(nullptr); } 586 begin(void) const587 ConstIterator begin(void) const { return ConstIterator(GetHead()); } end(void) const588 ConstIterator end(void) const { return ConstIterator(nullptr); } 589 590 private: 591 class Iterator : public ItemPtrIterator<Type, Iterator> 592 { 593 friend class LinkedList; 594 friend class ItemPtrIterator<Type, Iterator>; 595 596 using ItemPtrIterator<Type, Iterator>::mItem; 597 Iterator(Type * aItem)598 explicit Iterator(Type *aItem) 599 : ItemPtrIterator<Type, Iterator>(aItem) 600 { 601 } 602 Advance(void)603 void Advance(void) { mItem = mItem->GetNext(); } 604 }; 605 606 class ConstIterator : public ItemPtrIterator<const Type, ConstIterator> 607 { 608 friend class LinkedList; 609 friend class ItemPtrIterator<const Type, ConstIterator>; 610 611 using ItemPtrIterator<const Type, ConstIterator>::mItem; 612 ConstIterator(const Type * aItem)613 explicit ConstIterator(const Type *aItem) 614 : ItemPtrIterator<const Type, ConstIterator>(aItem) 615 { 616 } 617 Advance(void)618 void Advance(void) { mItem = mItem->GetNext(); } 619 }; 620 621 Type *mHead; 622 }; 623 624 /** 625 * @} 626 * 627 */ 628 629 } // namespace ot 630 631 #endif // LINKED_LIST_HPP_ 632