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 
33 namespace eprosima {
34 
35 // unnamed namespace for isolation
36 namespace {
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
44 template<class P, size_t... Ints>
45 std::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 
52 template<size_t N, class P>
53 std::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 
61 template<size_t N, class P, class ... Ts>
62 std::array<P, N> make_array(
63  P&& i,
64  Ts&&... args);
65 
66 template<bool, size_t N, class ... Ts>
67 struct 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 
80 template<size_t N, class ... Ts>
81 struct 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 
93 template<size_t N, class P, class ... Ts>
94 std::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 
105 template< 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 
159 public:
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 & > get()
Definition: ProxyPool.hpp:214
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::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