Line data Source code
1 : /*
2 : * Copyright (c) 2021 Project CHIP Authors
3 : * All rights reserved.
4 : *
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 :
18 : #pragma once
19 :
20 : #include <tuple>
21 :
22 : #include <lib/support/Pool.h>
23 :
24 : namespace chip {
25 :
26 : /// Provides an interface over a pool implementation which doesn't expose the size and the actual type of the pool.
27 : template <typename U, typename... ConstructorArguments>
28 : class PoolInterface
29 : {
30 : public:
31 : // For convenient use in PoolImpl
32 : using Interface = std::tuple<U, ConstructorArguments...>;
33 :
34 29 : virtual ~PoolInterface() {}
35 :
36 : virtual U * CreateObject(ConstructorArguments... args) = 0;
37 : virtual void ReleaseObject(U * element) = 0;
38 : virtual void ReleaseAll() = 0;
39 :
40 : template <typename Function>
41 86 : Loop ForEachActiveObject(Function && function)
42 : {
43 : static_assert(std::is_same<Loop, decltype(function(std::declval<U *>()))>::value,
44 : "The function must take T* and return Loop");
45 186 : auto proxy = [&](U * target) -> Loop { return function(target); };
46 172 : return ForEachActiveObjectInner(
47 186 : &proxy, [](void * context, U * target) -> Loop { return (*static_cast<decltype(proxy) *>(context))(target); });
48 : }
49 : template <typename Function>
50 : Loop ForEachActiveObject(Function && function) const
51 : {
52 : static_assert(std::is_same<Loop, decltype(function(std::declval<U *>()))>::value,
53 : "The function must take const T* and return Loop");
54 : auto proxy = [&](const U * target) -> Loop { return function(target); };
55 : return ForEachActiveObjectInner(
56 : &proxy, [](void * context, const U * target) -> Loop { return (*static_cast<decltype(proxy) *>(context))(target); });
57 : }
58 :
59 : protected:
60 : using Lambda = Loop (*)(void *, U *);
61 : using LambdaConst = Loop (*)(void *, const U *);
62 : virtual Loop ForEachActiveObjectInner(void * context, Lambda lambda) = 0;
63 : virtual Loop ForEachActiveObjectInner(void * context, LambdaConst lambda) const = 0;
64 : };
65 :
66 : template <class T, size_t N, ObjectPoolMem M, typename Interface>
67 : class PoolProxy;
68 :
69 : template <class T, size_t N, ObjectPoolMem M, typename U, typename... ConstructorArguments>
70 : class PoolProxy<T, N, M, std::tuple<U, ConstructorArguments...>> : public PoolInterface<U, ConstructorArguments...>
71 : {
72 : public:
73 : static_assert(std::is_base_of<U, T>::value, "Interface type is not derived from Pool type");
74 :
75 30 : PoolProxy() {}
76 30 : ~PoolProxy() override {}
77 :
78 32 : U * CreateObject(ConstructorArguments... args) override { return Impl().CreateObject(std::move(args)...); }
79 :
80 0 : void ReleaseObject(U * element) override { Impl().ReleaseObject(static_cast<T *>(element)); }
81 :
82 80 : void ReleaseAll() override { Impl().ReleaseAll(); }
83 :
84 : protected:
85 50 : Loop ForEachActiveObjectInner(void * context, typename PoolInterface<U, ConstructorArguments...>::Lambda lambda) override
86 : {
87 147 : return Impl().ForEachActiveObject([&](T * target) { return lambda(context, static_cast<U *>(target)); });
88 : }
89 0 : Loop ForEachActiveObjectInner(void * context,
90 : typename PoolInterface<U, ConstructorArguments...>::LambdaConst lambda) const override
91 : {
92 0 : return Impl().ForEachActiveObject([&](const T * target) { return lambda(context, static_cast<const U *>(target)); });
93 : }
94 :
95 : virtual ObjectPool<T, N, M> & Impl() = 0;
96 : virtual const ObjectPool<T, N, M> & Impl() const = 0;
97 : };
98 :
99 : /*
100 : * @brief
101 : * Define a implementation of a pool which derive and expose PoolInterface's.
102 : *
103 : * @tparam T a subclass of element to be allocated.
104 : * @tparam N a positive integer max number of elements the pool provides.
105 : * @tparam M an ObjectPoolMem constant selecting static vs heap allocation.
106 : * @tparam Interfaces a list of parameters which defines PoolInterface's. each interface is defined by a
107 : * std::tuple<U, ConstructorArguments...>. The PoolImpl is derived from every
108 : * PoolInterface<U, ConstructorArguments...>, the PoolImpl can be converted to the interface type
109 : * and passed around
110 : */
111 : template <class T, size_t N, ObjectPoolMem M, typename... Interfaces>
112 : class PoolImpl : public PoolProxy<T, N, M, Interfaces>...
113 : {
114 : public:
115 30 : PoolImpl() {}
116 30 : ~PoolImpl() override {}
117 :
118 : protected:
119 162 : ObjectPool<T, N, M> & Impl() override { return mImpl; }
120 0 : const ObjectPool<T, N, M> & Impl() const override { return mImpl; }
121 :
122 : private:
123 : ObjectPool<T, N, M> mImpl;
124 : };
125 :
126 : } // namespace chip
|