| /* |
| * Copyright (c) 2021 Project CHIP Authors |
| * All rights reserved. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #pragma once |
| |
| #include <tuple> |
| |
| #include <lib/support/Pool.h> |
| |
| namespace chip { |
| |
| /// Provides an interface over a pool implementation which doesn't expose the size and the actual type of the pool. |
| template <typename U, typename... ConstructorArguments> |
| class PoolInterface |
| { |
| public: |
| // For convenient use in PoolImpl |
| using Interface = std::tuple<U, ConstructorArguments...>; |
| |
| virtual ~PoolInterface() {} |
| |
| virtual U * CreateObject(ConstructorArguments... args) = 0; |
| virtual void ReleaseObject(U * element) = 0; |
| virtual void ReleaseAll() = 0; |
| virtual void ResetObject(U * element, ConstructorArguments... args) = 0; |
| |
| template <typename Function> |
| Loop ForEachActiveObject(Function && function) |
| { |
| static_assert(std::is_same<Loop, decltype(function(std::declval<U *>()))>::value, |
| "The function must take T* and return Loop"); |
| auto proxy = [&](U * target) -> Loop { return function(target); }; |
| 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 *); |
| 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> |
| class PoolProxy; |
| |
| 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"); |
| |
| PoolProxy() {} |
| ~PoolProxy() override {} |
| |
| U * CreateObject(ConstructorArguments... args) override { return Impl().CreateObject(std::move(args)...); } |
| |
| void ReleaseObject(U * element) override { Impl().ReleaseObject(static_cast<T *>(element)); } |
| |
| void ReleaseAll() override { Impl().ReleaseAll(); } |
| |
| void ResetObject(U * element, ConstructorArguments... args) override |
| { |
| return Impl().ResetObject(static_cast<T *>(element), std::move(args)...); |
| } |
| |
| protected: |
| Loop ForEachActiveObjectInner(void * context, typename PoolInterface<U, ConstructorArguments...>::Lambda lambda) override |
| { |
| return Impl().ForEachActiveObject([&](T * target) { return lambda(context, static_cast<U *>(target)); }); |
| } |
| 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 const ObjectPool<T, N, M> & Impl() const = 0; |
| }; |
| |
| /* |
| * @brief |
| * Define a implementation of a pool which derive and expose PoolInterface's. |
| * |
| * @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, ObjectPoolMem M, typename... Interfaces> |
| class PoolImpl : public PoolProxy<T, N, M, Interfaces>... |
| { |
| public: |
| PoolImpl() {} |
| ~PoolImpl() override {} |
| |
| protected: |
| ObjectPool<T, N, M> & Impl() override { return mImpl; } |
| const ObjectPool<T, N, M> & Impl() const override { return mImpl; } |
| |
| private: |
| ObjectPool<T, N, M> mImpl; |
| }; |
| |
| } // namespace chip |