diff --git a/src/core/common/pool.hpp b/src/core/common/pool.hpp index 7b479d0ee..964248c8e 100644 --- a/src/core/common/pool.hpp +++ b/src/core/common/pool.hpp @@ -54,45 +54,14 @@ class Instance; */ /** - * Represents an object pool. + * Represents a base class for an object pool. * - * @tparam Type The object type. Type should provide `GetNext() and `SetNext()` so that it can be added to a + * @tparam Type The object type. Type should provide `GetNext()` and `SetNext()` so that it can be added to a * linked list. - * @tparam kPoolSize Specifies the pool size (maximum number of objects in the pool). */ -template class Pool : private NonCopyable +template class PoolBase : private NonCopyable { public: - /** - * Initializes the pool. - */ - Pool(void) - : mFreeList() - { - for (Type &entry : mPool) - { - mFreeList.Push(entry); - } - } - - /** - * Initializes the pool. - * - * Version requires the `Type` class to provide method `void Init(Instance &)` to initialize - * each `Type` entry object. This can be realized by the `Type` class inheriting from `InstanceLocatorInit()`. - * - * @param[in] aInstance A reference to the OpenThread instance. - */ - explicit Pool(Instance &aInstance) - : mFreeList() - { - for (Type &entry : mPool) - { - entry.Init(aInstance); - mFreeList.Push(entry); - } - } - /** * Allocates a new object from the pool. * @@ -111,16 +80,60 @@ public: */ void Free(Type &aEntry) { mFreeList.Push(aEntry); } +protected: + PoolBase(void) = default; + + LinkedList mFreeList; +}; + +/** + * Represents an object pool. + * + * @tparam Type The object type. Type should provide `GetNext() and `SetNext()` so that it can be added to a + * linked list. + * @tparam kPoolSize Specifies the pool size (maximum number of objects in the pool). + */ +template class Pool : public PoolBase +{ +public: + /** + * Initializes the pool. + */ + Pool(void) + { + for (Type &entry : mPool) + { + PoolBase::Free(entry); + } + } + + /** + * Initializes the pool. + * + * Version requires the `Type` class to provide method `void Init(Instance &)` to initialize + * each `Type` entry object. This can be realized by the `Type` class inheriting from `InstanceLocatorInit()`. + * + * @param[in] aInstance A reference to the OpenThread instance. + */ + explicit Pool(Instance &aInstance) + { + for (Type &entry : mPool) + { + entry.Init(aInstance); + PoolBase::Free(entry); + } + } + /** * Frees all previously allocated objects. */ void FreeAll(void) { - mFreeList.Clear(); + PoolBase::mFreeList.Clear(); for (Type &entry : mPool) { - mFreeList.Push(entry); + PoolBase::Free(entry); } } @@ -136,8 +149,8 @@ public: * * @param[in] aObject A reference to a `Type` object. * - * @retval TRUE if @p aObject is from the pool. - * @retval FALSE if @p aObject is not from the pool. + * @retval TRUE If @p aObject is from the pool. + * @retval FALSE If @p aObject is not from the pool. */ bool IsPoolEntry(const Type &aObject) const { return (&mPool[0] <= &aObject) && (&aObject < GetArrayEnd(mPool)); } @@ -175,8 +188,77 @@ public: const Type &GetEntryAt(uint16_t aIndex) const { return mPool[aIndex]; } private: - LinkedList mFreeList; - Type mPool[kPoolSize]; + Type mPool[kPoolSize]; +}; + +/** + * Represents an object pool with run-time configurable storage. + * + * @tparam Type The object type. Type should provide `GetNext()` and `SetNext()` so that it can be added to a + * linked list. + */ +template class ConfigPool : public PoolBase +{ +public: + /** + * Initializes the pool as empty and unlinked to any buffer. + */ + ConfigPool(void) + : mEntryArray(nullptr) + , mNumEntries(0) + { + } + + /** + * Initializes the pool with a given array of entries. + * + * @param[in] aEntryArray A pointer to an array of entries. + * @param[in] aNumEntries The number of entries in the array. + * + * @retval kErrorNone Successfully initialized the pool. + * @retval kErrorAlready The pool is already initialized. + */ + Error Init(Type *aEntryArray, uint16_t aNumEntries) + { + Error error = kErrorNone; + + VerifyOrExit(mEntryArray == nullptr, error = kErrorAlready); + + mEntryArray = aEntryArray; + mNumEntries = aNumEntries; + + for (uint16_t i = 0; i < aNumEntries; i++) + { + PoolBase::Free(mEntryArray[i]); + } + + exit: + return error; + } + + /** + * Returns the pool size. + * + * @returns The pool size (maximum number of objects in the pool). + */ + uint16_t GetSize(void) const { return mNumEntries; } + + /** + * Indicates whether or not a given `Type` object is from the pool. + * + * @param[in] aObject A reference to a `Type` object. + * + * @retval TRUE If @p aObject is from the pool. + * @retval FALSE If @p aObject is not from the pool. + */ + bool IsPoolEntry(const Type &aObject) const + { + return (mNumEntries > 0) && (mEntryArray <= &aObject) && (&aObject < &mEntryArray[mNumEntries]); + } + +private: + Type *mEntryArray; + uint16_t mNumEntries; }; /** diff --git a/tests/unit/test_pool.cpp b/tests/unit/test_pool.cpp index fc4f6cb2d..b0cb57007 100644 --- a/tests/unit/test_pool.cpp +++ b/tests/unit/test_pool.cpp @@ -61,6 +61,7 @@ private: constexpr uint16_t kPoolSize = 11; typedef Pool EntryPool; +typedef ConfigPool ConfigEntryPool; static Entry sNonPoolEntry; @@ -79,7 +80,15 @@ void VerifyEntry(EntryPool &aPool, const Entry &aEntry, bool aInitWithInstance) VerifyOrQuit(aEntry.IsInitializedWithInstance() == aInitWithInstance, "Pool did not correctly Init() entry"); } -void TestPool(EntryPool &aPool, bool aInitWithInstance) +void VerifyEntry(ConfigEntryPool &aPool, const Entry &aEntry, bool aInitWithInstance) +{ + OT_UNUSED_VARIABLE(aInitWithInstance); + + VerifyOrQuit(aPool.IsPoolEntry(aEntry)); + VerifyOrQuit(!aPool.IsPoolEntry(sNonPoolEntry), "Pool::IsPoolEntry() succeeded for non-pool entry"); +} + +template void TestPool(PoolType &aPool, bool aInitWithInstance = false) { Entry *entries[kPoolSize]; @@ -121,17 +130,33 @@ void TestPool(void) EntryPool pool1; EntryPool pool2(*instance); + printf("TestPool(/* aInitWithInstance */ false)\n"); TestPool(pool1, /* aInitWithInstance */ false); + + printf("TestPool(/* aInitWithInstance */ true)\n"); TestPool(pool2, /* aInitWithInstance */ true); testFreeInstance(instance); } +void TestConfigPool(void) +{ + ConfigEntryPool pool; + Entry entries[kPoolSize]; + + printf("TestConfigPool()\n"); + SuccessOrQuit(pool.Init(entries, kPoolSize)); + TestPool(pool); + + VerifyOrQuit(pool.Init(entries, kPoolSize) != kErrorNone); +} + } // namespace ot int main(void) { ot::TestPool(); + ot::TestConfigPool(); printf("All tests passed\n"); return 0; }