]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/beast/example/common/session_alloc.hpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / libs / beast / example / common / session_alloc.hpp
1 //
2 // Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // Official repository: https://github.com/boostorg/beast
8 //
9
10 #ifndef BOOST_BEAST_EXAMPLE_COMMON_SESSION_ALLOC_HPP
11 #define BOOST_BEAST_EXAMPLE_COMMON_SESSION_ALLOC_HPP
12
13 #include <boost/asio/associated_allocator.hpp>
14 #include <boost/asio/associated_executor.hpp>
15 #include <boost/asio/handler_continuation_hook.hpp>
16 #include <boost/assert.hpp>
17 #include <boost/core/ignore_unused.hpp>
18 #include <boost/intrusive/list.hpp>
19 #include <algorithm>
20 #include <cstddef>
21 #include <utility>
22
23 namespace detail {
24
25 template<class Context>
26 class session_alloc_base
27 {
28 protected:
29 class pool_t
30 {
31 using hook_type =
32 boost::intrusive::list_base_hook<
33 boost::intrusive::link_mode<
34 boost::intrusive::normal_link>>;
35
36 class element : public hook_type
37 {
38 std::size_t size_;
39 std::size_t used_;
40 // add padding here
41
42 public:
43 explicit
44 element(std::size_t size, std::size_t used)
45 : size_(size)
46 , used_(used)
47 {
48 }
49
50 std::size_t
51 size() const
52 {
53 return size_;
54 }
55
56 std::size_t
57 used() const
58 {
59 return used_;
60 }
61
62 char*
63 end() const
64 {
65 return data() + size_;
66 }
67
68 char*
69 data() const
70 {
71 return const_cast<char*>(
72 reinterpret_cast<
73 char const *>(this + 1));
74 }
75 };
76
77 using list_type = typename
78 boost::intrusive::make_list<element,
79 boost::intrusive::constant_time_size<
80 true>>::type;
81
82 std::size_t refs_ = 1; // shared count
83 std::size_t high_ = 0; // highest used
84 std::size_t size_ = 0; // size of buf_
85 char* buf_ = nullptr; // a large block
86 list_type list_; // list of allocations
87
88 pool_t() = default;
89
90 public:
91 static
92 pool_t&
93 construct();
94
95 ~pool_t();
96
97 pool_t&
98 addref();
99
100 void
101 release();
102
103 void*
104 alloc(std::size_t n);
105
106 void
107 dealloc(void* pv, std::size_t n);
108 };
109 };
110
111 template<class Context>
112 auto
113 session_alloc_base<Context>::
114 pool_t::
115 construct() ->
116 pool_t&
117 {
118 return *(new pool_t);
119 }
120
121 template<class Context>
122 session_alloc_base<Context>::
123 pool_t::
124 ~pool_t()
125 {
126 BOOST_ASSERT(list_.size() == 0);
127 if(buf_)
128 delete[] buf_;
129 }
130
131 template<class Context>
132 auto
133 session_alloc_base<Context>::
134 pool_t::
135 addref() ->
136 pool_t&
137 {
138 ++refs_;
139 return *this;
140 }
141
142 template<class Context>
143 void
144 session_alloc_base<Context>::
145 pool_t::
146 release()
147 {
148 if(--refs_)
149 return;
150 delete this;
151 }
152
153 template<class Context>
154 void*
155 session_alloc_base<Context>::
156 pool_t::
157 alloc(std::size_t n)
158 {
159 if(list_.empty() && size_ < high_)
160 {
161 if(buf_)
162 delete[] buf_;
163 buf_ = new char[high_];
164 size_ = high_;
165 }
166 if(buf_)
167 {
168 char* end;
169 std::size_t used;
170 if(list_.empty())
171 {
172 end = buf_;
173 used = sizeof(element) + n;
174 }
175 else
176 {
177 end = list_.back().end();
178 used = list_.back().used() +
179 sizeof(element) + n;
180 }
181 if(end >= buf_ && end +
182 sizeof(element) + n <= buf_ + size_)
183 {
184 auto& e = *new(end) element{n, used};
185 list_.push_back(e);
186 high_ = (std::max)(high_, used);
187 return e.data();
188 }
189 }
190 std::size_t const used =
191 sizeof(element) + n + (
192 buf_ && ! list_.empty() ?
193 list_.back().used() : 0);
194 auto& e = *new(new char[sizeof(element) + n]) element{n, used};
195 list_.push_back(e);
196 high_ = (std::max)(high_, used);
197 return e.data();
198 }
199
200 template<class Context>
201 void
202 session_alloc_base<Context>::
203 pool_t::
204 dealloc(void* pv, std::size_t n)
205 {
206 boost::ignore_unused(n);
207 auto& e = *(reinterpret_cast<element*>(pv) - 1);
208 BOOST_ASSERT(e.size() == n);
209 if( (e.end() > buf_ + size_) ||
210 reinterpret_cast<char*>(&e) < buf_)
211 {
212 list_.erase(list_.iterator_to(e));
213 e.~element();
214 delete[] reinterpret_cast<char*>(&e);
215 return;
216 }
217 list_.erase(list_.iterator_to(e));
218 e.~element();
219 }
220
221 } // detail
222
223 //------------------------------------------------------------------------------
224
225 namespace detail {
226 template<class Handler>
227 class session_alloc_wrapper;
228 } // detail
229
230 template<class T>
231 class session_alloc
232 : private detail::session_alloc_base<void>
233 {
234 template<class U>
235 friend class session_alloc;
236
237 using pool_t = typename
238 detail::session_alloc_base<void>::pool_t;
239
240 pool_t& pool_;
241
242 public:
243 using value_type = T;
244 using is_always_equal = std::false_type;
245 using pointer = T*;
246 using reference = T&;
247 using const_pointer = T const*;
248 using const_reference = T const&;
249 using size_type = std::size_t;
250 using difference_type = std::ptrdiff_t;
251
252 template<class U>
253 struct rebind
254 {
255 using other = session_alloc<U>;
256 };
257
258 session_alloc& operator=(session_alloc const&) = delete;
259
260 ~session_alloc()
261 {
262 pool_.release();
263 }
264
265 session_alloc()
266 : pool_(pool_t::construct())
267 {
268 }
269
270 session_alloc(session_alloc const& other) noexcept
271 : pool_(other.pool_.addref())
272 {
273 }
274
275 template<class U>
276 session_alloc(session_alloc<U> const& other) noexcept
277 : pool_(other.pool_)
278 {
279 }
280
281 template<class Handler>
282 detail::session_alloc_wrapper<typename std::decay<Handler>::type>
283 wrap(Handler&& handler);
284
285 value_type*
286 allocate(size_type n)
287 {
288 return static_cast<value_type*>(
289 this->alloc(n * sizeof(T)));
290 }
291
292 void
293 deallocate(value_type* p, size_type n)
294 {
295 this->dealloc(p, n * sizeof(T));
296 }
297
298 #if defined(BOOST_LIBSTDCXX_VERSION) && BOOST_LIBSTDCXX_VERSION < 60000
299 template<class U, class... Args>
300 void
301 construct(U* ptr, Args&&... args)
302 {
303 ::new((void*)ptr) U(std::forward<Args>(args)...);
304 }
305
306 template<class U>
307 void
308 destroy(U* ptr)
309 {
310 ptr->~U();
311 }
312 #endif
313
314 template<class U>
315 friend
316 bool
317 operator==(
318 session_alloc const& lhs,
319 session_alloc<U> const& rhs)
320 {
321 return &lhs.pool_ == &rhs.pool_;
322 }
323
324 template<class U>
325 friend
326 bool
327 operator!=(
328 session_alloc const& lhs,
329 session_alloc<U> const& rhs)
330 {
331 return ! (lhs == rhs);
332 }
333
334 protected:
335 void*
336 alloc(std::size_t n)
337 {
338 return pool_.alloc(n);
339 }
340
341 void
342 dealloc(void* p, std::size_t n)
343 {
344 pool_.dealloc(p, n);
345 }
346 };
347
348 //------------------------------------------------------------------------------
349
350 namespace detail {
351
352 template<class Handler>
353 class session_alloc_wrapper
354 {
355 // Can't friend partial specializations,
356 // so we just friend the whole thing.
357 template<class U, class Executor>
358 friend struct boost::asio::associated_executor;
359
360 Handler h_;
361 session_alloc<char> alloc_;
362
363 public:
364 session_alloc_wrapper(session_alloc_wrapper&&) = default;
365 session_alloc_wrapper(session_alloc_wrapper const&) = default;
366
367 template<class DeducedHandler>
368 session_alloc_wrapper(
369 DeducedHandler&& h,
370 session_alloc<char> const& alloc)
371 : h_(std::forward<DeducedHandler>(h))
372 , alloc_(alloc)
373 {
374 }
375
376 using allocator_type = session_alloc<char>;
377
378 allocator_type
379 get_allocator() const noexcept;
380
381 template<class... Args>
382 void
383 operator()(Args&&... args) const
384 {
385 h_(std::forward<Args>(args)...);
386 }
387
388 friend
389 bool
390 asio_handler_is_continuation(session_alloc_wrapper* w)
391 {
392 using boost::asio::asio_handler_is_continuation;
393 return asio_handler_is_continuation(std::addressof(w->h_));
394 }
395 };
396
397 template<class Handler>
398 auto
399 session_alloc_wrapper<Handler>::
400 get_allocator() const noexcept ->
401 allocator_type
402 {
403 return alloc_;
404 }
405
406 } // detail
407
408 //------------------------------------------------------------------------------
409
410 template<class T>
411 template<class Handler>
412 auto
413 session_alloc<T>::
414 wrap(Handler&& handler) ->
415 detail::session_alloc_wrapper<typename std::decay<Handler>::type>
416 {
417 return detail::session_alloc_wrapper<
418 typename std::decay<Handler>::type>(
419 std::forward<Handler>(handler), *this);
420 }
421
422 //------------------------------------------------------------------------------
423
424 namespace boost {
425 namespace asio {
426 template<class Handler, class Executor>
427 struct associated_executor<
428 ::detail::session_alloc_wrapper<Handler>, Executor>
429 {
430 using type = typename
431 associated_executor<Handler, Executor>::type;
432
433 static
434 type
435 get(::detail::session_alloc_wrapper<Handler> const& h,
436 Executor const& ex = Executor()) noexcept
437 {
438 return associated_executor<
439 Handler, Executor>::get(h.h_, ex);
440 }
441 };
442
443 } // asio
444 } // boost
445
446 #endif