1 /*
2  *  Copyright (c) 2020, 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 object pool.
32  */
33 
34 #ifndef POOL_HPP_
35 #define POOL_HPP_
36 
37 #include "openthread-core-config.h"
38 
39 #include "common/array.hpp"
40 #include "common/linked_list.hpp"
41 #include "common/non_copyable.hpp"
42 
43 namespace ot {
44 
45 class Instance;
46 
47 /**
48  * @addtogroup core-pool
49  *
50  * @brief
51  *   This module includes definitions for OpenThread object pool.
52  *
53  * @{
54  *
55  */
56 
57 /**
58  * This template class represents an object pool.
59  *
60  * @tparam Type         The object type. Type should provide `GetNext() and `SetNext()` so that it can be added to a
61  *                      linked list.
62  * @tparam kPoolSize    Specifies the pool size (maximum number of objects in the pool).
63  *
64  */
65 template <class Type, uint16_t kPoolSize> class Pool : private NonCopyable
66 {
67 public:
68     /**
69      * This constructor initializes the pool.
70      *
71      */
Pool(void)72     Pool(void)
73         : mFreeList()
74     {
75         for (Type &entry : mPool)
76         {
77             mFreeList.Push(entry);
78         }
79     }
80 
81     /**
82      * This constructor initializes the pool.
83      *
84      * This constructor version requires the `Type` class to provide method `void Init(Instance &)` to initialize
85      * each `Type` entry object. This can be realized by the `Type` class inheriting from `InstanceLocatorInit()`.
86      *
87      * @param[in] aInstance   A reference to the OpenThread instance.
88      *
89      */
Pool(Instance & aInstance)90     explicit Pool(Instance &aInstance)
91         : mFreeList()
92     {
93         for (Type &entry : mPool)
94         {
95             entry.Init(aInstance);
96             mFreeList.Push(entry);
97         }
98     }
99 
100     /**
101      * This method allocates a new object from the pool.
102      *
103      * @returns A pointer to the newly allocated object, or `nullptr` if all entries from the pool are already
104      *          allocated.
105      *
106      */
Allocate(void)107     Type *Allocate(void) { return mFreeList.Pop(); }
108 
109     /**
110      * This method frees a previously allocated object.
111      *
112      * The @p aEntry MUST be an entry from the pool previously allocated using `Allocate()` method and not yet freed.
113      * An already freed entry MUST not be freed again.
114      *
115      * @param[in]  aEntry   The pool object entry to free.
116      *
117      */
Free(Type & aEntry)118     void Free(Type &aEntry) { mFreeList.Push(aEntry); }
119 
120     /**
121      * This method frees all previously allocated objects.
122      *
123      */
FreeAll(void)124     void FreeAll(void)
125     {
126         mFreeList.Clear();
127 
128         for (Type &entry : mPool)
129         {
130             mFreeList.Push(entry);
131         }
132     }
133 
134     /**
135      * This method returns the pool size.
136      *
137      * @returns The pool size (maximum number of objects in the pool).
138      *
139      */
GetSize(void) const140     uint16_t GetSize(void) const { return kPoolSize; }
141 
142     /**
143      * This method indicates whether or not a given `Type` object is from the pool.
144      *
145      * @param[in]  aObject   A reference to a `Type` object.
146      *
147      * @retval TRUE if @p aObject is from the pool.
148      * @retval FALSE if @p aObject is not from the pool.
149      *
150      */
IsPoolEntry(const Type & aObject) const151     bool IsPoolEntry(const Type &aObject) const { return (&mPool[0] <= &aObject) && (&aObject < GetArrayEnd(mPool)); }
152 
153     /**
154      * This method returns the associated index of a given entry from the pool.
155      *
156      * The @p aEntry MUST be from the pool, otherwise the behavior of this method is undefined.
157      *
158      * @param[in] aEntry  A reference to an entry from the pool.
159      *
160      * @returns The associated index of @p aEntry.
161      *
162      */
GetIndexOf(const Type & aEntry) const163     uint16_t GetIndexOf(const Type &aEntry) const { return static_cast<uint16_t>(&aEntry - mPool); }
164 
165     /**
166      * This method retrieves a pool entry at a given index.
167      *
168      * The @p aIndex MUST be from an earlier call to `GetIndexOf()`.
169      *
170      * @param[in] aIndex  An index.
171      *
172      * @returns A reference to entry at index @p aIndex.
173      *
174      */
GetEntryAt(uint16_t aIndex)175     Type &GetEntryAt(uint16_t aIndex) { return mPool[aIndex]; }
176 
177     /**
178      * This method retrieves a pool entry at a given index.
179      *
180      * The @p aIndex MUST be from an earlier call to `GetIndexOf()`.
181      *
182      * @param[in] aIndex  An index.
183      *
184      * @returns A reference to entry at index @p aIndex.
185      *
186      */
GetEntryAt(uint16_t aIndex) const187     const Type &GetEntryAt(uint16_t aIndex) const { return mPool[aIndex]; }
188 
189 private:
190     LinkedList<Type> mFreeList;
191     Type             mPool[kPoolSize];
192 };
193 
194 /**
195  * @}
196  *
197  */
198 
199 } // namespace ot
200 
201 #endif // POOL_HPP_
202