Fast RTPS  Version 2.7.1
Fast RTPS
ProxyPool.hpp
1// Copyright 2022 Proyectos y Sistemas de Mantenimiento SL (eProsima).
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
19#ifndef FASTRTPS_UTILS_PROXY_POOL_HPP_
20#define FASTRTPS_UTILS_PROXY_POOL_HPP_
21
22#include <array>
23#include <bitset>
24#include <cassert>
25#include <condition_variable>
26#include <memory>
27#include <mutex>
28
29#if defined(__has_include) && __has_include(<version>)
30# include <version>
31#endif // if defined(__has_include) && __has_include(<version>)
32
33namespace eprosima {
34
35// unnamed namespace for isolation
36namespace {
37
38// Detect if integer_sequence is availalbe
39#if defined(__cpp_lib_integer_sequence) \
40 && ((__cpp_lib_integer_sequence <= _MSVC_LANG) \
41 || (__cpp_lib_integer_sequence <= __cplusplus))
42
43// Array initialization usin C++14
44template<class P, size_t... Ints>
45std::array<P, sizeof...(Ints)> make_array(
46 P&& i,
47 std::index_sequence<Ints...> is)
48{
49 return { (Ints == is.size() - 1 ? std::move(i) : i)...};
50}
51
52template<size_t N, class P>
53std::array<P, N> make_array(
54 P&& i)
55{
56 return make_array<P>(std::move(i), std::make_index_sequence<N>{});
57}
58
59#else // C++11 fallback
60
61template<size_t N, class P, class ... Ts>
62std::array<P, N> make_array(
63 P&& i,
64 Ts&&... args);
65
66template<bool, size_t N, class ... Ts>
67struct make_array_choice
68{
69 template<class P>
70 static std::array<P, N> res(
71 P&& i,
72 Ts&&... args)
73 {
74 P tmp(i);
75 return make_array<N>(std::move(i), std::move(tmp), std::move(args)...);
76 }
77
78};
79
80template<size_t N, class ... Ts>
81struct make_array_choice<true, N, Ts...>
82{
83 template<class P>
84 static std::array<P, N> res(
85 P&& i,
86 Ts&&... args)
87 {
88 return {std::move(i), std::move(args)...};
89 }
90
91};
92
93template<size_t N, class P, class ... Ts>
94std::array<P, N> make_array(
95 P&& i,
96 Ts&&... args)
97{
98 return make_array_choice < N == (sizeof...(Ts) + 1), N, Ts ... > ::res(std::move(i), std::move(args)...);
99}
100
101#endif // defined(__cpp_lib_integer_sequence)
102
103} // namespace
104
105template< class Proxy, std::size_t N = 4>
107{
108 mutable std::mutex mtx_;
109 std::condition_variable cv_;
110 std::array<Proxy, N> heap_;
111 std::bitset<N> mask_;
112
113 // unique_ptr<Proxy> deleters
114 class D
115 {
116 // Because ProxyPool will be destroy after all the proxies are returned
117 // this reference is always valid
118 ProxyPool& pool_;
119
120 friend class ProxyPool;
121
122 D(
123 ProxyPool* pool)
124 : pool_(*pool)
125 {
126 }
127
128 public:
129
130 void operator ()(
131 Proxy* p) const
132 {
133 pool_.set_back(p);
134 }
135
136 }
137 deleter_;
138
139 friend class D;
140
141 /*
142 * Return an available proxy to the pool.
143 * @param p pointer to the proxy.
144 */
145 void set_back(
146 Proxy* p) noexcept
147 {
148 std::size_t idx = p - heap_.data();
149
150 std::lock_guard<std::mutex> _(mtx_);
151
152 // check is not there
153 assert(!mask_.test(idx));
154
155 // return the resource
156 mask_.set(idx);
157 }
158
159public:
160
161 using smart_ptr = std::unique_ptr<Proxy, D&>;
162
163 /*
164 * Constructor of the pool object.
165 * @param init Initialization value for all the proxies.
166 */
168 Proxy&& init)
169 : heap_(make_array<N>(std::move(init)))
170 , deleter_(this)
171 {
172 // make all resources available
173 mask_.set();
174 }
175
176 /*
177 * Destructor for the pool object.
178 * It waits till all the proxies are back in the pool to prevent data races.
179 */
181 {
182 std::unique_lock<std::mutex> lock(mtx_);
183 cv_.wait(lock, [&]()
184 {
185 return mask_.all();
186 });
187 }
188
189 /*
190 * Returns the number of proxies in the pool.
191 * @return pool size
192 */
193 static constexpr std::size_t size()
194 {
195 return N;
196 }
197
198 /*
199 * Returns the number of proxies available in the pool.
200 * @return available proxies
201 */
202 std::size_t available() const noexcept
203 {
204 std::lock_guard<std::mutex> _(mtx_);
205 return mask_.count();
206 }
207
208 /*
209 * Retrieve an available proxy from the pool.
210 * If not available a wait ensues.
211 * Note deleter is referenced not copied to avoid heap allocations on smart pointer construction
212 * @return unique_ptr referencing the proxy. On destruction the resource is returned.
213 */
214 std::unique_ptr<Proxy, D&> get()
215 {
216 std::unique_lock<std::mutex> lock(mtx_);
217
218 // wait for available resources
219 cv_.wait(lock, [&]()
220 {
221 return mask_.any();
222 });
223
224 // find the first available
225 std::size_t idx = 0;
226 while (idx < mask_.size() && !mask_.test(idx))
227 {
228 ++idx;
229 }
230
231 // retrieve it
232 mask_.reset(idx);
233 return std::unique_ptr<Proxy, D&>(&heap_[idx], deleter_);
234 }
235
236};
237
238} // eprosima namespace
239
240#endif /* FASTRTPS_UTILS_PROXY_POOL_HPP_ */
Definition: ProxyPool.hpp:107
std::unique_ptr< Proxy, D & > smart_ptr
Definition: ProxyPool.hpp:161
static constexpr std::size_t size()
Definition: ProxyPool.hpp:193
friend class D
Definition: ProxyPool.hpp:139
std::unique_ptr< Proxy, D & > get()
Definition: ProxyPool.hpp:214
std::size_t available() const noexcept
Definition: ProxyPool.hpp:202
~ProxyPool()
Definition: ProxyPool.hpp:180
ProxyPool(Proxy &&init)
Definition: ProxyPool.hpp:167
eProsima namespace.
Definition: LibrarySettingsAttributes.h:23