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/const_cast.hpp" 42 #include "common/error.hpp" 43 #include "common/iterator_utils.hpp" 44 45 namespace ot { 46 47 /** 48 * @addtogroup core-linked-list 49 * 50 * @brief 51 * This module includes definitions for OpenThread Singly Linked List. 52 * 53 * @{ 54 */ 55 56 /** 57 * Represents a linked list entry. 58 * 59 * 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 template <class Type> class LinkedListEntry 68 { 69 public: 70 /** 71 * Gets the next entry in the linked list. 72 * 73 * @returns A pointer to the next entry in the linked list or `nullptr` if at the end of the list. 74 */ GetNext(void) const75 const Type *GetNext(void) const { return static_cast<const Type *>(static_cast<const Type *>(this)->mNext); } 76 77 /** 78 * Gets the next entry in the linked list. 79 * 80 * @returns A pointer to the next entry in the linked list or `nullptr` if at the end of the list. 81 */ GetNext(void)82 Type *GetNext(void) { return static_cast<Type *>(static_cast<Type *>(this)->mNext); } 83 84 /** 85 * Sets the next pointer on the entry. 86 * 87 * @param[in] aNext A pointer to the next entry. 88 */ SetNext(Type * aNext)89 void SetNext(Type *aNext) { static_cast<Type *>(this)->mNext = aNext; } 90 }; 91 92 /** 93 * Represents a singly linked list. 94 * 95 * The template type `Type` should provide `GetNext()` and `SetNext()` methods (which can be realized by `Type` 96 * inheriting from `LinkedListEntry<Type>` class). 97 */ 98 template <typename Type> class LinkedList 99 { 100 class Iterator; 101 class ConstIterator; 102 103 public: 104 /** 105 * Initializes the linked list. 106 */ LinkedList(void)107 LinkedList(void) 108 : mHead(nullptr) 109 { 110 } 111 112 /** 113 * Returns the entry at the head of the linked list 114 * 115 * @returns Pointer to the entry at the head of the linked list, or `nullptr` if the list is empty. 116 */ GetHead(void)117 Type *GetHead(void) { return mHead; } 118 119 /** 120 * Returns the entry at the head of the linked list. 121 * 122 * @returns Pointer to the entry at the head of the linked list, or `nullptr` if the list is empty. 123 */ GetHead(void) const124 const Type *GetHead(void) const { return mHead; } 125 126 /** 127 * Sets the head of the linked list to a given entry. 128 * 129 * @param[in] aHead A pointer to an entry to set as the head of the linked list. 130 */ SetHead(Type * aHead)131 void SetHead(Type *aHead) { mHead = aHead; } 132 133 /** 134 * Clears the linked list. 135 */ Clear(void)136 void Clear(void) { mHead = nullptr; } 137 138 /** 139 * Indicates whether the linked list is empty or not. 140 * 141 * @retval TRUE If the linked list is empty. 142 * @retval FALSE If the linked list is not empty. 143 */ IsEmpty(void) const144 bool IsEmpty(void) const { return (mHead == nullptr); } 145 146 /** 147 * Pushes an entry at the head of the linked list. 148 * 149 * @param[in] aEntry A reference to an entry to push at the head of linked list. 150 */ Push(Type & aEntry)151 void Push(Type &aEntry) 152 { 153 aEntry.SetNext(mHead); 154 mHead = &aEntry; 155 } 156 157 /** 158 * Pushes an entry after a given previous existing entry in the linked list. 159 * 160 * @param[in] aEntry A reference to an entry to push into the list. 161 * @param[in] aPrevEntry A reference to a previous entry (new entry @p aEntry will be pushed after this). 162 */ PushAfter(Type & aEntry,Type & aPrevEntry)163 void PushAfter(Type &aEntry, Type &aPrevEntry) 164 { 165 aEntry.SetNext(aPrevEntry.GetNext()); 166 aPrevEntry.SetNext(&aEntry); 167 } 168 169 /** 170 * Pushes an entry after the tail in the linked list. 171 * 172 * @param[in] aEntry A reference to an entry to push into the list. 173 */ PushAfterTail(Type & aEntry)174 void PushAfterTail(Type &aEntry) 175 { 176 Type *tail = GetTail(); 177 178 if (tail == nullptr) 179 { 180 Push(aEntry); 181 } 182 else 183 { 184 PushAfter(aEntry, *tail); 185 } 186 } 187 188 /** 189 * Pops an entry from head of the linked list. 190 * 191 * @note This method does not change the popped entry itself, i.e., the popped entry next pointer stays as before. 192 * 193 * @returns The entry that was popped if the list is not empty, or `nullptr` if the list is empty. 194 */ Pop(void)195 Type *Pop(void) 196 { 197 Type *entry = mHead; 198 199 if (mHead != nullptr) 200 { 201 mHead = mHead->GetNext(); 202 } 203 204 return entry; 205 } 206 207 /** 208 * Pops an entry after a given previous entry. 209 * 210 * @note This method does not change the popped entry itself, i.e., the popped entry next pointer stays as before. 211 * 212 * @param[in] aPrevEntry A pointer to a previous entry. If it is not `nullptr` the entry after this will be popped, 213 * otherwise (if it is `nullptr`) the entry at the head of the list is popped. 214 * 215 * @returns Pointer to the entry that was popped, or `nullptr` if there is no entry to pop. 216 */ PopAfter(Type * aPrevEntry)217 Type *PopAfter(Type *aPrevEntry) 218 { 219 Type *entry; 220 221 if (aPrevEntry == nullptr) 222 { 223 entry = Pop(); 224 } 225 else 226 { 227 entry = aPrevEntry->GetNext(); 228 229 if (entry != nullptr) 230 { 231 aPrevEntry->SetNext(entry->GetNext()); 232 } 233 } 234 235 return entry; 236 } 237 238 /** 239 * Indicates whether the linked list contains a given entry. 240 * 241 * @param[in] aEntry A reference to an entry. 242 * 243 * @retval TRUE The linked list contains @p aEntry. 244 * @retval FALSE The linked list does not contain @p aEntry. 245 */ Contains(const Type & aEntry) const246 bool Contains(const Type &aEntry) const 247 { 248 const Type *prev; 249 250 return Find(aEntry, prev) == kErrorNone; 251 } 252 253 /** 254 * Indicates whether the linked list contains an entry matching a set of conditions. 255 * 256 * To check that an entry matches, the `Matches()` method is invoked on each `Type` entry in the list. The 257 * `Matches()` method with the same set of `Args` input types should be provided by the `Type` class accordingly: 258 * 259 * bool Type::Matches(const Args &...) const 260 * 261 * @param[in] aArgs The args to pass to `Matches()`. 262 * 263 * @retval TRUE The linked list contains a matching entry. 264 * @retval FALSE The linked list does not contain a matching entry. 265 */ ContainsMatching(const Args &...aArgs) const266 template <typename... Args> bool ContainsMatching(const Args &...aArgs) const 267 { 268 return FindMatching(aArgs...) != nullptr; 269 } 270 271 /** 272 * Adds an entry (at the head of the linked list) if it is not already in the list. 273 * 274 * @param[in] aEntry A reference to an entry to add. 275 * 276 * @retval kErrorNone The entry was successfully added at the head of the list. 277 * @retval kErrorAlready The entry is already in the list. 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 * 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 */ Remove(const Type & aEntry)306 Error Remove(const Type &aEntry) 307 { 308 Type *prev; 309 Error error = Find(aEntry, prev); 310 311 if (error == kErrorNone) 312 { 313 PopAfter(prev); 314 } 315 316 return error; 317 } 318 319 /** 320 * Removes an entry matching a given set of conditions from the linked list. 321 * 322 * To check that an entry matches, the `Matches()` method is invoked on each `Type` entry in the list. The 323 * `Matches()` method with the same set of `Args` input types should be provided by the `Type` class accordingly: 324 * 325 * bool Type::Matches(const Args &...) const 326 * 327 * @note This method does not change the removed entry itself (which is returned in case of success), i.e., the 328 * entry next pointer stays as before. 329 * 330 * @param[in] aArgs The args to pass to `Matches()`. 331 * 332 * @returns A pointer to the removed matching entry if one could be found, or `nullptr` if no matching entry is 333 * found. 334 */ RemoveMatching(const Args &...aArgs)335 template <typename... Args> Type *RemoveMatching(const Args &...aArgs) 336 { 337 Type *prev; 338 Type *entry = FindMatchingWithPrev(prev, aArgs...); 339 340 if (entry != nullptr) 341 { 342 PopAfter(prev); 343 } 344 345 return entry; 346 } 347 348 /** 349 * Removes all entries in the list matching a given entry indicator from the list and adds 350 * them to a new list. 351 * 352 * To check that an entry matches, the `Matches()` method is invoked on each `Type` entry in the list. The 353 * `Matches()` method with the same set of `Args` input types should be provided by the `Type` class accordingly: 354 * 355 * bool Type::Matches(const Args &...) const 356 * 357 * @param[in] aRemovedList The list to add the removed entries to. 358 * @param[in] aArgs The args to pass to `Matches()`. 359 */ RemoveAllMatching(LinkedList & aRemovedList,const Args &...aArgs)360 template <typename... Args> void RemoveAllMatching(LinkedList &aRemovedList, const Args &...aArgs) 361 { 362 Type *entry; 363 Type *prev; 364 Type *next; 365 366 for (prev = nullptr, entry = GetHead(); entry != nullptr; entry = next) 367 { 368 next = entry->GetNext(); 369 370 if (entry->Matches(aArgs...)) 371 { 372 PopAfter(prev); 373 aRemovedList.Push(*entry); 374 375 // When the entry is removed from the list 376 // we keep the `prev` pointer same as before. 377 } 378 else 379 { 380 prev = entry; 381 } 382 } 383 } 384 385 /** 386 * Searches within the linked list to find an entry and if found returns a pointer to previous entry. 387 * 388 * @param[in] aEntry A reference to an entry to find. 389 * @param[out] aPrevEntry A pointer to output the previous entry on success (when @p aEntry is found in the list). 390 * @p aPrevEntry is set to `nullptr` if @p aEntry is the head of the list. Otherwise it is 391 * updated to point to the previous entry before @p aEntry in the list. 392 * 393 * @retval kErrorNone The entry was found in the list and @p aPrevEntry was updated successfully. 394 * @retval kErrorNotFound The entry was not found in the list. 395 */ Find(const Type & aEntry,const Type * & aPrevEntry) const396 Error Find(const Type &aEntry, const Type *&aPrevEntry) const 397 { 398 Error error = kErrorNotFound; 399 400 aPrevEntry = nullptr; 401 402 for (const Type *entry = mHead; entry != nullptr; aPrevEntry = entry, entry = entry->GetNext()) 403 { 404 if (entry == &aEntry) 405 { 406 error = kErrorNone; 407 break; 408 } 409 } 410 411 return error; 412 } 413 414 /** 415 * Searches within the linked list to find an entry and if found returns a pointer to previous entry. 416 * 417 * @param[in] aEntry A reference to an entry to find. 418 * @param[out] aPrevEntry A pointer to output the previous entry on success (when @p aEntry is found in the list). 419 * @p aPrevEntry is set to `nullptr` if @p aEntry is the head of the list. Otherwise it is 420 * updated to point to the previous entry before @p aEntry in the list. 421 * 422 * @retval kErrorNone The entry was found in the list and @p aPrevEntry was updated successfully. 423 * @retval kErrorNotFound The entry was not found in the list. 424 */ Find(const Type & aEntry,Type * & aPrevEntry)425 Error Find(const Type &aEntry, Type *&aPrevEntry) 426 { 427 return AsConst(this)->Find(aEntry, const_cast<const Type *&>(aPrevEntry)); 428 } 429 430 /** 431 * Searches within the linked list to find an entry matching a set of conditions, and if found also returns a 432 * pointer to its previous entry in the list. 433 * 434 * To check that an entry matches, the `Matches()` method is invoked on each `Type` entry in the list. The 435 * `Matches()` method with the same set of `Args` input types should be provided by the `Type` class accordingly: 436 * 437 * bool Type::Matches(const Args &...) const 438 * 439 * @param[out] aPrevEntry A pointer to output the previous entry on success (when a match is found in the list). 440 * @p aPrevEntry is set to `nullptr` if the matching entry is the head of the list. 441 * Otherwise it is updated to point to the previous entry before the matching entry in the 442 * list. 443 * @param[in] aArgs The args to pass to `Matches()`. 444 * 445 * @returns A pointer to the matching entry if one is found, or `nullptr` if no matching entry was found. 446 */ FindMatchingWithPrev(const Type * & aPrevEntry,Args &&...aArgs) const447 template <typename... Args> const Type *FindMatchingWithPrev(const Type *&aPrevEntry, Args &&...aArgs) const 448 { 449 const Type *entry; 450 451 aPrevEntry = nullptr; 452 453 for (entry = mHead; entry != nullptr; aPrevEntry = entry, entry = entry->GetNext()) 454 { 455 if (entry->Matches(aArgs...)) 456 { 457 break; 458 } 459 } 460 461 return entry; 462 } 463 464 /** 465 * Searches within the linked list to find an entry matching a set of conditions, and if found also returns a 466 * pointer to its previous entry in the list. 467 * 468 * To check that an entry matches, the `Matches()` method is invoked on each `Type` entry in the list. The 469 * `Matches()` method with the same set of `Args` input types should be provided by the `Type` class accordingly: 470 * 471 * bool Type::Matches(const Args &...) const 472 * 473 * @param[out] aPrevEntry A pointer to output the previous entry on success (when a match is found in the list). 474 * @p aPrevEntry is set to `nullptr` if the matching entry is the head of the list. 475 * Otherwise it is updated to point to the previous entry before the matching entry in the 476 * list. 477 * @param[in] aArgs The args to pass to `Matches()`. 478 * 479 * @returns A pointer to the matching entry if one is found, or `nullptr` if no matching entry was found. 480 */ FindMatchingWithPrev(Type * & aPrevEntry,Args &&...aArgs)481 template <typename... Args> Type *FindMatchingWithPrev(Type *&aPrevEntry, Args &&...aArgs) 482 { 483 return AsNonConst(AsConst(this)->FindMatchingWithPrev(const_cast<const Type *&>(aPrevEntry), aArgs...)); 484 } 485 486 /** 487 * Searches within the linked list to find an entry matching a set of conditions. 488 * 489 * To check that an entry matches, the `Matches()` method is invoked on each `Type` entry in the list. The 490 * `Matches()` method with the same set of `Args` input types should be provided by the `Type` class accordingly: 491 * 492 * bool Type::Matches(const Args &...) const 493 * 494 * @param[in] aArgs The args to pass to `Matches()`. 495 * 496 * @returns A pointer to the matching entry if one is found, or `nullptr` if no matching entry was found. 497 */ FindMatching(const Args &...aArgs) const498 template <typename... Args> const Type *FindMatching(const Args &...aArgs) const 499 { 500 const Type *prev; 501 502 return FindMatchingWithPrev(prev, aArgs...); 503 } 504 505 /** 506 * Searches within the linked list to find an entry matching a set of conditions. 507 * 508 * To check that an entry matches, the `Matches()` method is invoked on each `Type` entry in the list. The 509 * `Matches()` method with the same set of `Args` input types should be provided by the `Type` class accordingly: 510 * 511 * bool Type::Matches(const Args &...) const 512 * 513 * @param[in] aArgs The args to pass to `Matches()`. 514 * 515 * @returns A pointer to the matching entry if one is found, or `nullptr` if no matching entry was found. 516 */ FindMatching(const Args &...aArgs)517 template <typename... Args> Type *FindMatching(const Args &...aArgs) 518 { 519 return AsNonConst(AsConst(this)->FindMatching(aArgs...)); 520 } 521 522 /** 523 * Returns the tail of the linked list (i.e., the last entry in the list). 524 * 525 * @returns A pointer to the tail entry in the linked list or `nullptr` if the list is empty. 526 */ GetTail(void) const527 const Type *GetTail(void) const 528 { 529 const Type *tail = mHead; 530 531 if (tail != nullptr) 532 { 533 while (tail->GetNext() != nullptr) 534 { 535 tail = tail->GetNext(); 536 } 537 } 538 539 return tail; 540 } 541 542 /** 543 * Returns the tail of the linked list (i.e., the last entry in the list). 544 * 545 * @returns A pointer to the tail entry in the linked list or `nullptr` if the list is empty. 546 */ GetTail(void)547 Type *GetTail(void) { return AsNonConst(AsConst(this)->GetTail()); } 548 549 // The following methods are intended to support range-based `for` 550 // loop iteration over the linked-list entries and should not be 551 // used directly. 552 begin(void)553 Iterator begin(void) { return Iterator(GetHead()); } end(void)554 Iterator end(void) { return Iterator(nullptr); } 555 begin(void) const556 ConstIterator begin(void) const { return ConstIterator(GetHead()); } end(void) const557 ConstIterator end(void) const { return ConstIterator(nullptr); } 558 559 private: 560 class Iterator : public ItemPtrIterator<Type, Iterator> 561 { 562 friend class LinkedList; 563 friend class ItemPtrIterator<Type, Iterator>; 564 565 using ItemPtrIterator<Type, Iterator>::mItem; 566 Iterator(Type * aItem)567 explicit Iterator(Type *aItem) 568 : ItemPtrIterator<Type, Iterator>(aItem) 569 { 570 } 571 Advance(void)572 void Advance(void) { mItem = mItem->GetNext(); } 573 }; 574 575 class ConstIterator : public ItemPtrIterator<const Type, ConstIterator> 576 { 577 friend class LinkedList; 578 friend class ItemPtrIterator<const Type, ConstIterator>; 579 580 using ItemPtrIterator<const Type, ConstIterator>::mItem; 581 ConstIterator(const Type * aItem)582 explicit ConstIterator(const Type *aItem) 583 : ItemPtrIterator<const Type, ConstIterator>(aItem) 584 { 585 } 586 Advance(void)587 void Advance(void) { mItem = mItem->GetNext(); } 588 }; 589 590 Type *mHead; 591 }; 592 593 /** 594 * @} 595 */ 596 597 } // namespace ot 598 599 #endif // LINKED_LIST_HPP_ 600