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