Skip to content

Commit

Permalink
ObjectPool: add const version for ForEachActiveObject (project-chip#1…
Browse files Browse the repository at this point in the history
…3167)

#### Problem

Iterating a `const` pool can be useful.

#### Change overview

Add `const` overloads for `ForEachActiveObject` and associated internals.

#### Testing

Make the `TestPool` utility function `GetNumObjectsInUse()`
take a `const` pool.
  • Loading branch information
kpschoedel authored Dec 21, 2021
1 parent bf7feea commit 46d0321
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 9 deletions.
2 changes: 0 additions & 2 deletions src/lib/support/Pool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,6 @@ size_t StaticAllocatorBitmap::IndexOf(void * element)
return index;
}

using Lambda = Loop (*)(void *, void *);
Loop StaticAllocatorBitmap::ForEachActiveObjectInner(void * context, Lambda lambda)
{
for (size_t word = 0; word * kBitChunkSize < Capacity(); ++word)
Expand Down Expand Up @@ -117,7 +116,6 @@ HeapObjectListNode * HeapObjectList::FindNode(void * object) const
return nullptr;
}

using Lambda = Loop (*)(void *, void *);
Loop HeapObjectList::ForEachNode(void * context, Lambda lambda)
{
++mIterationDepth;
Expand Down
34 changes: 32 additions & 2 deletions src/lib/support/Pool.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,12 @@ class StaticAllocatorBitmap : public internal::StaticAllocatorBase
void * At(size_t index) { return static_cast<uint8_t *>(mElements) + mElementSize * index; }
size_t IndexOf(void * element);

Loop ForEachActiveObjectInner(void * context, Loop lambda(void * context, void * object));
using Lambda = Loop (*)(void * context, void * object);
Loop ForEachActiveObjectInner(void * context, Lambda lambda);
Loop ForEachActiveObjectInner(void * context, Loop lambda(void * context, const void * object)) const
{
return const_cast<StaticAllocatorBitmap *>(this)->ForEachActiveObjectInner(context, reinterpret_cast<Lambda>(lambda));
}

private:
void * mElements;
Expand Down Expand Up @@ -120,6 +125,10 @@ class LambdaProxy
{
return static_cast<LambdaProxy *>(context)->mFunction(static_cast<T *>(target));
}
static Loop ConstCall(void * context, const void * target)
{
return static_cast<LambdaProxy *>(context)->mFunction(static_cast<const T *>(target));
}

private:
Function mFunction;
Expand Down Expand Up @@ -154,7 +163,12 @@ struct HeapObjectList : HeapObjectListNode

HeapObjectListNode * FindNode(void * object) const;

Loop ForEachNode(void * context, Loop lambda(void * context, void * object));
using Lambda = Loop (*)(void *, void *);
Loop ForEachNode(void * context, Lambda lambda);
Loop ForEachNode(void * context, Loop lambda(void * context, const void * object)) const
{
return const_cast<HeapObjectList *>(this)->ForEachNode(context, reinterpret_cast<Lambda>(lambda));
}

size_t mIterationDepth;
};
Expand Down Expand Up @@ -242,6 +256,14 @@ class BitMapObjectPool : public internal::StaticAllocatorBitmap, public internal
internal::LambdaProxy<T, Function> proxy(std::forward<Function>(function));
return ForEachActiveObjectInner(&proxy, &internal::LambdaProxy<T, Function>::Call);
}
template <typename Function>
Loop ForEachActiveObject(Function && function) const
{
static_assert(std::is_same<Loop, decltype(function(std::declval<const T *>()))>::value,
"The function must take const T* and return Loop");
internal::LambdaProxy<T, Function> proxy(std::forward<Function>(function));
return ForEachActiveObjectInner(&proxy, &internal::LambdaProxy<T, Function>::ConstCall);
}

private:
static Loop ReleaseObject(void * context, void * object)
Expand Down Expand Up @@ -324,6 +346,14 @@ class HeapObjectPool : public internal::Statistics, public internal::PoolCommon<
internal::LambdaProxy<T, Function> proxy(std::forward<Function>(function));
return mObjects.ForEachNode(&proxy, &internal::LambdaProxy<T, Function>::Call);
}
template <typename Function>
Loop ForEachActiveObject(Function && function) const
{
static_assert(std::is_same<Loop, decltype(function(std::declval<const T *>()))>::value,
"The function must take const T* and return Loop");
internal::LambdaProxy<const T, Function> proxy(std::forward<Function>(function));
return mObjects.ForEachNode(&proxy, &internal::LambdaProxy<const T, Function>::ConstCall);
}

private:
static Loop ReleaseObject(void * context, void * object)
Expand Down
24 changes: 21 additions & 3 deletions src/lib/support/PoolWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,21 @@ class PoolInterface
return ForEachActiveObjectInner(
&proxy, [](void * context, U * target) -> Loop { return (*static_cast<decltype(proxy) *>(context))(target); });
}
template <typename Function>
Loop ForEachActiveObject(Function && function) const
{
static_assert(std::is_same<Loop, decltype(function(std::declval<U *>()))>::value,
"The function must take const T* and return Loop");
auto proxy = [&](const U * target) -> Loop { return function(target); };
return ForEachActiveObjectInner(
&proxy, [](void * context, const U * target) -> Loop { return (*static_cast<decltype(proxy) *>(context))(target); });
}

protected:
using Lambda = Loop (*)(void *, U *);
virtual Loop ForEachActiveObjectInner(void * context, Lambda lambda) = 0;
using Lambda = Loop (*)(void *, U *);
using LambdaConst = Loop (*)(void *, const U *);
virtual Loop ForEachActiveObjectInner(void * context, Lambda lambda) = 0;
virtual Loop ForEachActiveObjectInner(void * context, LambdaConst lambda) const = 0;
};

template <class T, size_t N, ObjectPoolMem M, typename Interface>
Expand Down Expand Up @@ -82,8 +93,14 @@ class PoolProxy<T, N, M, std::tuple<U, ConstructorArguments...>> : public PoolIn
{
return Impl().ForEachActiveObject([&](T * target) { return lambda(context, static_cast<U *>(target)); });
}
virtual Loop ForEachActiveObjectInner(void * context,
typename PoolInterface<U, ConstructorArguments...>::LambdaConst lambda) const override
{
return Impl().ForEachActiveObject([&](const T * target) { return lambda(context, static_cast<const U *>(target)); });
}

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

/*
Expand All @@ -107,6 +124,7 @@ class PoolImpl : public PoolProxy<T, N, M, Interfaces>...

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

private:
ObjectPool<T, N, M> mImpl;
Expand Down
4 changes: 2 additions & 2 deletions src/lib/support/tests/TestPool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@
namespace chip {

template <class POOL>
size_t GetNumObjectsInUse(POOL & pool)
size_t GetNumObjectsInUse(const POOL & pool)
{
size_t count = 0;
pool.ForEachActiveObject([&count](void *) {
pool.ForEachActiveObject([&count](const void *) {
++count;
return Loop::Continue;
});
Expand Down

0 comments on commit 46d0321

Please sign in to comment.