• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (c) 2016-2019 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_FIELDS_ALLOC_HPP
11 #define BOOST_BEAST_EXAMPLE_FIELDS_ALLOC_HPP
12 
13 #include <boost/throw_exception.hpp>
14 #include <cstdlib>
15 #include <memory>
16 #include <stdexcept>
17 
18 namespace detail {
19 
20 struct static_pool
21 {
22     std::size_t size_;
23     std::size_t refs_ = 1;
24     std::size_t count_ = 0;
25     char* p_;
26 
27     char*
enddetail::static_pool28     end()
29     {
30         return reinterpret_cast<char*>(this + 1) + size_;
31     }
32 
33     explicit
static_pooldetail::static_pool34     static_pool(std::size_t size)
35         : size_(size)
36         , p_(reinterpret_cast<char*>(this + 1))
37     {
38     }
39 
40 public:
41     static
42     static_pool&
constructdetail::static_pool43     construct(std::size_t size)
44     {
45         auto p = new char[sizeof(static_pool) + size];
46         return *(::new(p) static_pool{size});
47     }
48 
49     static_pool&
sharedetail::static_pool50     share()
51     {
52         ++refs_;
53         return *this;
54     }
55 
56     void
destroydetail::static_pool57     destroy()
58     {
59         if(refs_--)
60             return;
61         this->~static_pool();
62         delete[] reinterpret_cast<char*>(this);
63     }
64 
65     void*
allocdetail::static_pool66     alloc(std::size_t n)
67     {
68         auto last = p_ + n;
69         if(last >= end())
70             BOOST_THROW_EXCEPTION(std::bad_alloc{});
71         ++count_;
72         auto p = p_;
73         p_ = last;
74         return p;
75     }
76 
77     void
deallocdetail::static_pool78     dealloc()
79     {
80         if(--count_)
81             return;
82         p_ = reinterpret_cast<char*>(this + 1);
83     }
84 };
85 
86 } // detail
87 
88 /** A non-thread-safe allocator optimized for @ref basic_fields.
89 
90     This allocator obtains memory from a pre-allocated memory block
91     of a given size. It does nothing in deallocate until all
92     previously allocated blocks are deallocated, upon which it
93     resets the internal memory block for re-use.
94 
95     To use this allocator declare an instance persistent to the
96     connection or session, and construct with the block size.
97     A good rule of thumb is 20% more than the maximum allowed
98     header size. For example if the application only allows up
99     to an 8,000 byte header, the block size could be 9,600.
100 
101     Then, for every instance of `message` construct the header
102     with a copy of the previously declared allocator instance.
103 */
104 template<class T>
105 struct fields_alloc
106 {
107     detail::static_pool* pool_;
108 
109 public:
110     using value_type = T;
111     using is_always_equal = std::false_type;
112     using pointer = T*;
113     using reference = T&;
114     using const_pointer = T const*;
115     using const_reference = T const&;
116     using size_type = std::size_t;
117     using difference_type = std::ptrdiff_t;
118 
119     template<class U>
120     struct rebind
121     {
122         using other = fields_alloc<U>;
123     };
124 
125 #if defined(_GLIBCXX_USE_CXX11_ABI) && (_GLIBCXX_USE_CXX11_ABI == 0)
126     // Workaround for g++
127     // basic_string assumes that allocators are default-constructible
128     // See: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=56437
129     fields_alloc() = default;
130 #endif
131 
132     explicit
fields_allocfields_alloc133     fields_alloc(std::size_t size)
134         : pool_(&detail::static_pool::construct(size))
135     {
136     }
137 
fields_allocfields_alloc138     fields_alloc(fields_alloc const& other)
139         : pool_(&other.pool_->share())
140     {
141     }
142 
143     template<class U>
fields_allocfields_alloc144     fields_alloc(fields_alloc<U> const& other)
145         : pool_(&other.pool_->share())
146     {
147     }
148 
~fields_allocfields_alloc149     ~fields_alloc()
150     {
151         pool_->destroy();
152     }
153 
154     value_type*
allocatefields_alloc155     allocate(size_type n)
156     {
157         return static_cast<value_type*>(
158             pool_->alloc(n * sizeof(T)));
159     }
160 
161     void
deallocatefields_alloc162     deallocate(value_type*, size_type)
163     {
164         pool_->dealloc();
165     }
166 
167 #if defined(BOOST_LIBSTDCXX_VERSION) && BOOST_LIBSTDCXX_VERSION < 60000
168     template<class U, class... Args>
169     void
constructfields_alloc170     construct(U* ptr, Args&&... args)
171     {
172         ::new(static_cast<void*>(ptr)) U(
173             std::forward<Args>(args)...);
174     }
175 
176     template<class U>
177     void
destroyfields_alloc178     destroy(U* ptr)
179     {
180         ptr->~U();
181     }
182 #endif
183 
184     template<class U>
185     friend
186     bool
operator ==(fields_alloc const & lhs,fields_alloc<U> const & rhs)187     operator==(
188         fields_alloc const& lhs,
189         fields_alloc<U> const& rhs)
190     {
191         return &lhs.pool_ == &rhs.pool_;
192     }
193 
194     template<class U>
195     friend
196     bool
operator !=(fields_alloc const & lhs,fields_alloc<U> const & rhs)197     operator!=(
198         fields_alloc const& lhs,
199         fields_alloc<U> const& rhs)
200     {
201         return ! (lhs == rhs);
202     }
203 };
204 
205 #endif
206