Skip to content

Commit

Permalink
Extend PoolInterface to heap pools (#12997)
Browse files Browse the repository at this point in the history
#### Problem

PR #11834 added `PoolInterface`, a useful helper for passing object
pools, but it only supports `BitMapObjectPool`.

#### Change overview

Generalize `PoolInterface` to handle both static and heap pools.

#### Testing

Added a unit test.
  • Loading branch information
kpschoedel authored and pull[bot] committed Nov 18, 2023
1 parent 8f0c198 commit 1642604
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 29 deletions.
3 changes: 2 additions & 1 deletion src/lib/dnssd/minimal_mdns/Server.h
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,8 @@ class ServerBase

// The PoolImpl impl is used as a base class because its destructor must be called after ServerBase's destructor.
template <size_t kCount>
class Server : private chip::PoolImpl<ServerBase::EndpointInfo, kCount, ServerBase::EndpointInfoPoolType::Interface>,
class Server : private chip::PoolImpl<ServerBase::EndpointInfo, kCount, chip::ObjectPoolMem::kStatic,
ServerBase::EndpointInfoPoolType::Interface>,
public ServerBase
{
public:
Expand Down
3 changes: 2 additions & 1 deletion src/lib/dnssd/minimal_mdns/tests/CheckOnlyServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,8 @@ void MakePrintableName(char (&location)[N], FullQName name)

} // namespace

class CheckOnlyServer : private chip::PoolImpl<ServerBase::EndpointInfo, 0, ServerBase::EndpointInfoPoolType::Interface>,
class CheckOnlyServer : private chip::PoolImpl<ServerBase::EndpointInfo, 0, chip::ObjectPoolMem::kStatic,
ServerBase::EndpointInfoPoolType::Interface>,
public ServerBase,
public ParserDelegate,
public TxtRecordDelegate
Expand Down
21 changes: 8 additions & 13 deletions src/lib/support/Pool.h
Original file line number Diff line number Diff line change
Expand Up @@ -336,33 +336,28 @@ class HeapObjectPool : public internal::Statistics, public internal::PoolCommon<

#endif // CHIP_SYSTEM_CONFIG_POOL_USE_HEAP

#if CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
template <typename T, unsigned int N>
using ObjectPool = HeapObjectPool<T>;
#else // CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
template <typename T, unsigned int N>
using ObjectPool = BitMapObjectPool<T, N>;
#endif // CHIP_SYSTEM_CONFIG_POOL_USE_HEAP

enum class ObjectPoolMem
{
kStatic,
#if CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
kDynamic
kDynamic,
kDefault = kDynamic
#else // CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
kDefault = kStatic
#endif // CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
};

template <typename T, size_t N, ObjectPoolMem P>
class MemTypeObjectPool;
template <typename T, size_t N, ObjectPoolMem P = ObjectPoolMem::kDefault>
class ObjectPool;

template <typename T, size_t N>
class MemTypeObjectPool<T, N, ObjectPoolMem::kStatic> : public BitMapObjectPool<T, N>
class ObjectPool<T, N, ObjectPoolMem::kStatic> : public BitMapObjectPool<T, N>
{
};

#if CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
template <typename T, size_t N>
class MemTypeObjectPool<T, N, ObjectPoolMem::kDynamic> : public HeapObjectPool<T>
class ObjectPool<T, N, ObjectPoolMem::kDynamic> : public HeapObjectPool<T>
{
};
#endif // CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
Expand Down
17 changes: 9 additions & 8 deletions src/lib/support/PoolWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,11 @@ class PoolInterface
virtual Loop ForEachActiveObjectInner(void * context, Lambda lambda) = 0;
};

template <class T, size_t N, typename Interface>
template <class T, size_t N, ObjectPoolMem M, typename Interface>
class PoolProxy;

template <class T, size_t N, typename U, typename... ConstructorArguments>
class PoolProxy<T, N, std::tuple<U, ConstructorArguments...>> : public PoolInterface<U, ConstructorArguments...>
template <class T, size_t N, ObjectPoolMem M, typename U, typename... ConstructorArguments>
class PoolProxy<T, N, M, std::tuple<U, ConstructorArguments...>> : public PoolInterface<U, ConstructorArguments...>
{
public:
static_assert(std::is_base_of<U, T>::value, "Interface type is not derived from Pool type");
Expand All @@ -83,7 +83,7 @@ class PoolProxy<T, N, std::tuple<U, ConstructorArguments...>> : public PoolInter
return Impl().ForEachActiveObject([&](T * target) { return lambda(context, static_cast<U *>(target)); });
}

virtual BitMapObjectPool<T, N> & Impl() = 0;
virtual ObjectPool<T, N, M> & Impl() = 0;
};

/*
Expand All @@ -92,23 +92,24 @@ class PoolProxy<T, N, std::tuple<U, ConstructorArguments...>> : public PoolInter
*
* @tparam T a subclass of element to be allocated.
* @tparam N a positive integer max number of elements the pool provides.
* @tparam M an ObjectPoolMem constant selecting static vs heap allocation.
* @tparam Interfaces a list of parameters which defines PoolInterface's. each interface is defined by a
* std::tuple<U, ConstructorArguments...>. The PoolImpl is derived from every
* PoolInterface<U, ConstructorArguments...>, the PoolImpl can be converted to the interface type
* and passed around
*/
template <class T, size_t N, typename... Interfaces>
class PoolImpl : public PoolProxy<T, N, Interfaces>...
template <class T, size_t N, ObjectPoolMem M, typename... Interfaces>
class PoolImpl : public PoolProxy<T, N, M, Interfaces>...
{
public:
PoolImpl() {}
virtual ~PoolImpl() override {}

protected:
virtual BitMapObjectPool<T, N> & Impl() override { return mImpl; }
virtual ObjectPool<T, N, M> & Impl() override { return mImpl; }

private:
BitMapObjectPool<T, N> mImpl;
ObjectPool<T, N, M> mImpl;
};

} // namespace chip
76 changes: 71 additions & 5 deletions src/lib/support/tests/TestPool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include <set>

#include <lib/support/Pool.h>
#include <lib/support/PoolWrapper.h>
#include <lib/support/UnitTestRegistration.h>
#include <system/SystemConfig.h>

Expand Down Expand Up @@ -53,7 +54,7 @@ using namespace chip;
template <typename T, size_t N, ObjectPoolMem P>
void TestReleaseNull(nlTestSuite * inSuite, void * inContext)
{
MemTypeObjectPool<T, N, P> pool;
ObjectPool<T, N, P> pool;
pool.ReleaseObject(nullptr);
NL_TEST_ASSERT(inSuite, GetNumObjectsInUse(pool) == 0);
NL_TEST_ASSERT(inSuite, pool.Allocated() == 0);
Expand All @@ -74,7 +75,7 @@ void TestReleaseNullDynamic(nlTestSuite * inSuite, void * inContext)
template <typename T, size_t N, ObjectPoolMem P>
void TestCreateReleaseObject(nlTestSuite * inSuite, void * inContext)
{
MemTypeObjectPool<uint32_t, N, ObjectPoolMem::kStatic> pool;
ObjectPool<uint32_t, N, ObjectPoolMem::kStatic> pool;
uint32_t * obj[N];

NL_TEST_ASSERT(inSuite, pool.Allocated() == 0);
Expand Down Expand Up @@ -105,7 +106,7 @@ void TestCreateReleaseObjectStatic(nlTestSuite * inSuite, void * inContext)
constexpr const size_t kSize = 100;
TestCreateReleaseObject<uint32_t, kSize, ObjectPoolMem::kStatic>(inSuite, inContext);

MemTypeObjectPool<uint32_t, kSize, ObjectPoolMem::kStatic> pool;
ObjectPool<uint32_t, kSize, ObjectPoolMem::kStatic> pool;
uint32_t * obj[kSize];

for (size_t i = 0; i < kSize; ++i)
Expand Down Expand Up @@ -159,7 +160,7 @@ void TestCreateReleaseStruct(nlTestSuite * inSuite, void * inContext)
std::set<S *> objs1;

constexpr const size_t kSize = 100;
MemTypeObjectPool<S, kSize, P> pool;
ObjectPool<S, kSize, P> pool;

S * objs2[kSize];
for (size_t i = 0; i < kSize; ++i)
Expand Down Expand Up @@ -223,7 +224,7 @@ void TestForEachActiveObject(nlTestSuite * inSuite, void * inContext)
S * objArray[kSize];
std::set<size_t> objIds;

MemTypeObjectPool<S, kSize, P> pool;
ObjectPool<S, kSize, P> pool;

for (size_t i = 0; i < kSize; ++i)
{
Expand Down Expand Up @@ -343,6 +344,69 @@ void TestForEachActiveObjectDynamic(nlTestSuite * inSuite, void * inContext)
}
#endif // CHIP_SYSTEM_CONFIG_POOL_USE_HEAP

template <ObjectPoolMem P>
void TestPoolInterface(nlTestSuite * inSuite, void * inContext)
{
struct TestObject
{
TestObject(uint32_t * set, size_t id) : mSet(set), mId(id) { *mSet |= (1 << mId); }
~TestObject() { *mSet &= ~(1 << mId); }
uint32_t * mSet;
size_t mId;
};
using TestObjectPoolType = PoolInterface<TestObject, uint32_t *, size_t>;

struct PoolHolder
{
PoolHolder(TestObjectPoolType & testObjectPool) : mTestObjectPoolInterface(testObjectPool) {}
TestObjectPoolType & mTestObjectPoolInterface;
};

constexpr size_t kSize = 10;
PoolImpl<TestObject, kSize, P, typename TestObjectPoolType::Interface> testObjectPool;
PoolHolder poolHolder(testObjectPool);
uint32_t bits = 0;

TestObject * objs2[kSize];
for (size_t i = 0; i < kSize; ++i)
{
objs2[i] = poolHolder.mTestObjectPoolInterface.CreateObject(&bits, i);
NL_TEST_ASSERT(inSuite, objs2[i] != nullptr);
NL_TEST_ASSERT(inSuite, GetNumObjectsInUse(poolHolder.mTestObjectPoolInterface) == i + 1);
NL_TEST_ASSERT(inSuite, bits == (1ul << (i + 1)) - 1);
}
for (size_t i = 0; i < kSize; ++i)
{
poolHolder.mTestObjectPoolInterface.ReleaseObject(objs2[i]);
NL_TEST_ASSERT(inSuite, GetNumObjectsInUse(poolHolder.mTestObjectPoolInterface) == kSize - i - 1);
}
NL_TEST_ASSERT(inSuite, bits == 0);

// Verify that ReleaseAll() calls the destructors.
for (size_t i = 0; i < kSize; ++i)
{
objs2[i] = poolHolder.mTestObjectPoolInterface.CreateObject(&bits, i);
}
NL_TEST_ASSERT(inSuite, bits == (1ul << kSize) - 1);
NL_TEST_ASSERT(inSuite, GetNumObjectsInUse(poolHolder.mTestObjectPoolInterface) == kSize);

poolHolder.mTestObjectPoolInterface.ReleaseAll();
NL_TEST_ASSERT(inSuite, bits == 0);
NL_TEST_ASSERT(inSuite, GetNumObjectsInUse(poolHolder.mTestObjectPoolInterface) == 0);
}

void TestPoolInterfaceStatic(nlTestSuite * inSuite, void * inContext)
{
TestPoolInterface<ObjectPoolMem::kStatic>(inSuite, inContext);
}

#if CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
void TestPoolInterfaceDynamic(nlTestSuite * inSuite, void * inContext)
{
TestPoolInterface<ObjectPoolMem::kDynamic>(inSuite, inContext);
}
#endif // CHIP_SYSTEM_CONFIG_POOL_USE_HEAP

int Setup(void * inContext)
{
return SUCCESS;
Expand All @@ -365,11 +429,13 @@ static const nlTest sTests[] = {
NL_TEST_DEF_FN(TestCreateReleaseObjectStatic),
NL_TEST_DEF_FN(TestCreateReleaseStructStatic),
NL_TEST_DEF_FN(TestForEachActiveObjectStatic),
NL_TEST_DEF_FN(TestPoolInterfaceStatic),
#if CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
NL_TEST_DEF_FN(TestReleaseNullDynamic),
NL_TEST_DEF_FN(TestCreateReleaseObjectDynamic),
NL_TEST_DEF_FN(TestCreateReleaseStructDynamic),
NL_TEST_DEF_FN(TestForEachActiveObjectDynamic),
NL_TEST_DEF_FN(TestPoolInterfaceDynamic),
#endif // CHIP_SYSTEM_CONFIG_POOL_USE_HEAP
NL_TEST_SENTINEL()
// clang-format on
Expand Down
2 changes: 1 addition & 1 deletion src/transport/raw/TCP.h
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ class TCP : public TCPBase
private:
friend class TCPTest;
TCPBase::ActiveConnectionState mConnectionsBuffer[kActiveConnectionsSize];
PoolImpl<PendingPacket, kPendingPacketSize, PendingPacketPoolType::Interface> mPendingPackets;
PoolImpl<PendingPacket, kPendingPacketSize, ObjectPoolMem::kStatic, PendingPacketPoolType::Interface> mPendingPackets;
};

} // namespace Transport
Expand Down

0 comments on commit 1642604

Please sign in to comment.