Fast RTPS  Version 2.14.1
Fast RTPS
Loading...
Searching...
No Matches
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 // notify the resource is free
159 cv_.notify_one();
160 }
161
162public:
163
164 using smart_ptr = std::unique_ptr<Proxy, D&>;
165
166 /*
167 * Constructor of the pool object.
168 * @param init Initialization value for all the proxies.
169 */
171 Proxy&& init)
172 : heap_(make_array<N>(std::move(init)))
173 , deleter_(this)
174 {
175 // make all resources available
176 mask_.set();
177 }
178
179 /*
180 * Destructor for the pool object.
181 * It waits till all the proxies are back in the pool to prevent data races.
182 */
184 {
185 std::unique_lock<std::mutex> lock(mtx_);
186 cv_.wait(lock, [&]()
187 {
188 return mask_.all();
189 });
190 }
191
192 /*
193 * Returns the number of proxies in the pool.
194 * @return pool size
195 */
196 static constexpr std::size_t size()
197 {
198 return N;
199 }
200
201 /*
202 * Returns the number of proxies available in the pool.
203 * @return available proxies
204 */
205 std::size_t available() const noexcept
206 {
207 std::lock_guard<std::mutex> _(mtx_);
208 return mask_.count();
209 }
210
211 /*
212 * Retrieve an available proxy from the pool.
213 * If not available a wait ensues.
214 * Note deleter is referenced not copied to avoid heap allocations on smart pointer construction
215 * @return unique_ptr referencing the proxy. On destruction the resource is returned.
216 */
217 std::unique_ptr<Proxy, D&> get()
218 {
219 std::unique_lock<std::mutex> lock(mtx_);
220
221 // wait for available resources
222 cv_.wait(lock, [&]()
223 {
224 return mask_.any();
225 });
226
227 // find the first available
228 std::size_t idx = 0;
229 while (idx < mask_.size() && !mask_.test(idx))
230 {
231 ++idx;
232 }
233
234 // retrieve it
235 mask_.reset(idx);
236 return std::unique_ptr<Proxy, D&>(&heap_[idx], deleter_);
237 }
238
239};
240
241} // eprosima namespace
242
243#endif /* FASTRTPS_UTILS_PROXY_POOL_HPP_ */
Definition ProxyPool.hpp:107
std::unique_ptr< Proxy, D & > smart_ptr
Definition ProxyPool.hpp:164
static constexpr std::size_t size()
Definition ProxyPool.hpp:196
friend class D
Definition ProxyPool.hpp:139
std::unique_ptr< Proxy, D & > get()
Definition ProxyPool.hpp:217
std::size_t available() const noexcept
Definition ProxyPool.hpp:205
~ProxyPool()
Definition ProxyPool.hpp:183
ProxyPool(Proxy &&init)
Definition ProxyPool.hpp:170
eProsima namespace.
Definition LibrarySettingsAttributes.h:23