Fast RTPS  Version 2.9.0
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  // notify the resource is free
159  cv_.notify_one();
160  }
161 
162 public:
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 & > get()
Definition: ProxyPool.hpp:217
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::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