123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205 |
- //
- // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
- //
- // Distributed under the Boost Software License, Version 1.0. (See accompanying
- // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
- //
- // Official repository: https://github.com/boostorg/beast
- //
- #ifndef BOOST_BEAST_EXAMPLE_FIELDS_ALLOC_HPP
- #define BOOST_BEAST_EXAMPLE_FIELDS_ALLOC_HPP
- #include <boost/throw_exception.hpp>
- #include <cstdlib>
- #include <memory>
- #include <stdexcept>
- namespace detail {
- struct static_pool
- {
- std::size_t size_;
- std::size_t refs_ = 1;
- std::size_t count_ = 0;
- char* p_;
- char*
- end()
- {
- return reinterpret_cast<char*>(this + 1) + size_;
- }
- explicit
- static_pool(std::size_t size)
- : size_(size)
- , p_(reinterpret_cast<char*>(this + 1))
- {
- }
- public:
- static
- static_pool&
- construct(std::size_t size)
- {
- auto p = new char[sizeof(static_pool) + size];
- return *(::new(p) static_pool{size});
- }
- static_pool&
- share()
- {
- ++refs_;
- return *this;
- }
- void
- destroy()
- {
- if(refs_--)
- return;
- this->~static_pool();
- delete[] reinterpret_cast<char*>(this);
- }
- void*
- alloc(std::size_t n)
- {
- auto last = p_ + n;
- if(last >= end())
- BOOST_THROW_EXCEPTION(std::bad_alloc{});
- ++count_;
- auto p = p_;
- p_ = last;
- return p;
- }
- void
- dealloc()
- {
- if(--count_)
- return;
- p_ = reinterpret_cast<char*>(this + 1);
- }
- };
- } // detail
- /** A non-thread-safe allocator optimized for @ref basic_fields.
- This allocator obtains memory from a pre-allocated memory block
- of a given size. It does nothing in deallocate until all
- previously allocated blocks are deallocated, upon which it
- resets the internal memory block for re-use.
- To use this allocator declare an instance persistent to the
- connection or session, and construct with the block size.
- A good rule of thumb is 20% more than the maximum allowed
- header size. For example if the application only allows up
- to an 8,000 byte header, the block size could be 9,600.
- Then, for every instance of `message` construct the header
- with a copy of the previously declared allocator instance.
- */
- template<class T>
- struct fields_alloc
- {
- detail::static_pool* pool_;
- public:
- using value_type = T;
- using is_always_equal = std::false_type;
- using pointer = T*;
- using reference = T&;
- using const_pointer = T const*;
- using const_reference = T const&;
- using size_type = std::size_t;
- using difference_type = std::ptrdiff_t;
- template<class U>
- struct rebind
- {
- using other = fields_alloc<U>;
- };
- #if defined(_GLIBCXX_USE_CXX11_ABI) && (_GLIBCXX_USE_CXX11_ABI == 0)
- // Workaround for g++
- // basic_string assumes that allocators are default-constructible
- // See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56437
- fields_alloc() = default;
- #endif
- explicit
- fields_alloc(std::size_t size)
- : pool_(&detail::static_pool::construct(size))
- {
- }
- fields_alloc(fields_alloc const& other)
- : pool_(&other.pool_->share())
- {
- }
- template<class U>
- fields_alloc(fields_alloc<U> const& other)
- : pool_(&other.pool_->share())
- {
- }
- ~fields_alloc()
- {
- pool_->destroy();
- }
- value_type*
- allocate(size_type n)
- {
- return static_cast<value_type*>(
- pool_->alloc(n * sizeof(T)));
- }
- void
- deallocate(value_type*, size_type)
- {
- pool_->dealloc();
- }
- #if defined(BOOST_LIBSTDCXX_VERSION) && BOOST_LIBSTDCXX_VERSION < 60000
- template<class U, class... Args>
- void
- construct(U* ptr, Args&&... args)
- {
- ::new(static_cast<void*>(ptr)) U(
- std::forward<Args>(args)...);
- }
- template<class U>
- void
- destroy(U* ptr)
- {
- ptr->~U();
- }
- #endif
- template<class U>
- friend
- bool
- operator==(
- fields_alloc const& lhs,
- fields_alloc<U> const& rhs)
- {
- return &lhs.pool_ == &rhs.pool_;
- }
- template<class U>
- friend
- bool
- operator!=(
- fields_alloc const& lhs,
- fields_alloc<U> const& rhs)
- {
- return ! (lhs == rhs);
- }
- };
- #endif
|