forked from boostorg/beast
		
	
		
			
				
	
	
		
			206 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			206 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
//
 | 
						|
// 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
 |