• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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