2 // Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
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)
7 // Official repository: https://github.com/boostorg/beast
10 #ifndef BOOST_BEAST_EXAMPLE_COMMON_SESSION_ALLOC_HPP
11 #define BOOST_BEAST_EXAMPLE_COMMON_SESSION_ALLOC_HPP
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>
25 template<class Context>
26 class session_alloc_base
32 boost::intrusive::list_base_hook<
33 boost::intrusive::link_mode<
34 boost::intrusive::normal_link>>;
36 class element : public hook_type
44 element(std::size_t size, std::size_t used)
65 return data() + size_;
71 return const_cast<char*>(
73 char const *>(this + 1));
77 using list_type = typename
78 boost::intrusive::make_list<element,
79 boost::intrusive::constant_time_size<
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
104 alloc(std::size_t n);
107 dealloc(void* pv, std::size_t n);
111 template<class Context>
113 session_alloc_base<Context>::
118 return *(new pool_t);
121 template<class Context>
122 session_alloc_base<Context>::
126 BOOST_ASSERT(list_.size() == 0);
131 template<class Context>
133 session_alloc_base<Context>::
142 template<class Context>
144 session_alloc_base<Context>::
153 template<class Context>
155 session_alloc_base<Context>::
159 if(list_.empty() && size_ < high_)
163 buf_ = new char[high_];
173 used = sizeof(element) + n;
177 end = list_.back().end();
178 used = list_.back().used() +
181 if(end >= buf_ && end +
182 sizeof(element) + n <= buf_ + size_)
184 auto& e = *new(end) element{n, used};
186 high_ = (std::max)(high_, used);
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};
196 high_ = (std::max)(high_, used);
200 template<class Context>
202 session_alloc_base<Context>::
204 dealloc(void* pv, std::size_t n)
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_)
212 list_.erase(list_.iterator_to(e));
214 delete[] reinterpret_cast<char*>(&e);
217 list_.erase(list_.iterator_to(e));
223 //------------------------------------------------------------------------------
226 template<class Handler>
227 class session_alloc_wrapper;
232 : private detail::session_alloc_base<void>
235 friend class session_alloc;
237 using pool_t = typename
238 detail::session_alloc_base<void>::pool_t;
243 using value_type = T;
244 using is_always_equal = std::false_type;
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;
255 using other = session_alloc<U>;
258 session_alloc& operator=(session_alloc const&) = delete;
266 : pool_(pool_t::construct())
270 session_alloc(session_alloc const& other) noexcept
271 : pool_(other.pool_.addref())
276 session_alloc(session_alloc<U> const& other) noexcept
281 template<class Handler>
282 detail::session_alloc_wrapper<typename std::decay<Handler>::type>
283 wrap(Handler&& handler);
286 allocate(size_type n)
288 return static_cast<value_type*>(
289 this->alloc(n * sizeof(T)));
293 deallocate(value_type* p, size_type n)
295 this->dealloc(p, n * sizeof(T));
298 #if defined(BOOST_LIBSTDCXX_VERSION) && BOOST_LIBSTDCXX_VERSION < 60000
299 template<class U, class... Args>
301 construct(U* ptr, Args&&... args)
303 ::new((void*)ptr) U(std::forward<Args>(args)...);
318 session_alloc const& lhs,
319 session_alloc<U> const& rhs)
321 return &lhs.pool_ == &rhs.pool_;
328 session_alloc const& lhs,
329 session_alloc<U> const& rhs)
331 return ! (lhs == rhs);
338 return pool_.alloc(n);
342 dealloc(void* p, std::size_t n)
348 //------------------------------------------------------------------------------
352 template<class Handler>
353 class session_alloc_wrapper
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;
361 session_alloc<char> alloc_;
364 session_alloc_wrapper(session_alloc_wrapper&&) = default;
365 session_alloc_wrapper(session_alloc_wrapper const&) = default;
367 template<class DeducedHandler>
368 session_alloc_wrapper(
370 session_alloc<char> const& alloc)
371 : h_(std::forward<DeducedHandler>(h))
376 using allocator_type = session_alloc<char>;
379 get_allocator() const noexcept;
381 template<class... Args>
383 operator()(Args&&... args) const
385 h_(std::forward<Args>(args)...);
390 asio_handler_is_continuation(session_alloc_wrapper* w)
392 using boost::asio::asio_handler_is_continuation;
393 return asio_handler_is_continuation(std::addressof(w->h_));
397 template<class Handler>
399 session_alloc_wrapper<Handler>::
400 get_allocator() const noexcept ->
408 //------------------------------------------------------------------------------
411 template<class Handler>
414 wrap(Handler&& handler) ->
415 detail::session_alloc_wrapper<typename std::decay<Handler>::type>
417 return detail::session_alloc_wrapper<
418 typename std::decay<Handler>::type>(
419 std::forward<Handler>(handler), *this);
422 //------------------------------------------------------------------------------
426 template<class Handler, class Executor>
427 struct associated_executor<
428 ::detail::session_alloc_wrapper<Handler>, Executor>
430 using type = typename
431 associated_executor<Handler, Executor>::type;
435 get(::detail::session_alloc_wrapper<Handler> const& h,
436 Executor const& ex = Executor()) noexcept
438 return associated_executor<
439 Handler, Executor>::get(h.h_, ex);