fields_alloc.hpp 4.3 KB

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