recycled.hpp 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. //
  2. // Copyright (c) 2022 Vinnie Falco (vinnie.falco@gmail.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/url
  8. //
  9. #ifndef BOOST_URL_GRAMMAR_IMPL_RECYCLED_PTR_HPP
  10. #define BOOST_URL_GRAMMAR_IMPL_RECYCLED_PTR_HPP
  11. #include <boost/assert.hpp>
  12. namespace boost {
  13. namespace urls {
  14. namespace grammar {
  15. //------------------------------------------------
  16. template<class T>
  17. recycled<T>::
  18. ~recycled()
  19. {
  20. std::size_t n = 0;
  21. // VFALCO we should probably deallocate
  22. // in reverse order of allocation but
  23. // that requires a doubly-linked list.
  24. auto it = head_;
  25. while(it)
  26. {
  27. ++n;
  28. auto next = it->next;
  29. BOOST_ASSERT(
  30. it->refs == 0);
  31. delete it;
  32. it = next;
  33. }
  34. detail::recycled_remove(
  35. sizeof(U) * n);
  36. }
  37. template<class T>
  38. auto
  39. recycled<T>::
  40. acquire() ->
  41. U*
  42. {
  43. U* p;
  44. {
  45. #if !defined(BOOST_URL_DISABLE_THREADS)
  46. std::lock_guard<
  47. std::mutex> lock(m_);
  48. #endif
  49. p = head_;
  50. if(p)
  51. {
  52. // reuse
  53. head_ = head_->next;
  54. detail::recycled_remove(
  55. sizeof(U));
  56. ++p->refs;
  57. }
  58. else
  59. {
  60. p = new U;
  61. }
  62. }
  63. BOOST_ASSERT(p->refs == 1);
  64. return p;
  65. }
  66. template<class T>
  67. void
  68. recycled<T>::
  69. release(U* u) noexcept
  70. {
  71. if(--u->refs != 0)
  72. return;
  73. {
  74. #if !defined(BOOST_URL_DISABLE_THREADS)
  75. std::lock_guard<
  76. std::mutex> lock(m_);
  77. #endif
  78. u->next = head_;
  79. head_ = u;
  80. }
  81. detail::recycled_add(
  82. sizeof(U));
  83. }
  84. //------------------------------------------------
  85. template<class T>
  86. recycled_ptr<T>::
  87. ~recycled_ptr()
  88. {
  89. if(p_)
  90. bin_->release(p_);
  91. }
  92. template<class T>
  93. recycled_ptr<T>::
  94. recycled_ptr(
  95. recycled<T>& bin)
  96. : bin_(&bin)
  97. , p_(bin.acquire())
  98. {
  99. }
  100. template<class T>
  101. recycled_ptr<T>::
  102. recycled_ptr(
  103. recycled<T>& bin,
  104. std::nullptr_t) noexcept
  105. : bin_(&bin)
  106. {
  107. }
  108. template<class T>
  109. recycled_ptr<T>::
  110. recycled_ptr()
  111. : recycled_ptr(nullptr)
  112. {
  113. p_ = bin_->acquire();
  114. }
  115. template<class T>
  116. recycled_ptr<T>::
  117. recycled_ptr(
  118. std::nullptr_t) noexcept
  119. : recycled_ptr([]() -> B&
  120. {
  121. // VFALCO need guaranteed constexpr-init
  122. static B r;
  123. return r;
  124. }(), nullptr)
  125. {
  126. }
  127. template<class T>
  128. recycled_ptr<T>::
  129. recycled_ptr(
  130. recycled_ptr const& other) noexcept
  131. : bin_(other.bin_)
  132. , p_(other.p_)
  133. {
  134. if(p_)
  135. ++p_->refs;
  136. }
  137. template<class T>
  138. recycled_ptr<T>::
  139. recycled_ptr(
  140. recycled_ptr&& other) noexcept
  141. : bin_(other.bin_)
  142. , p_(other.p_)
  143. {
  144. other.p_ = nullptr;
  145. }
  146. template<class T>
  147. auto
  148. recycled_ptr<T>::
  149. operator=(
  150. recycled_ptr&& other) noexcept ->
  151. recycled_ptr&
  152. {
  153. BOOST_ASSERT(
  154. bin_ == other.bin_);
  155. if(p_)
  156. bin_->release(p_);
  157. p_ = other.p_;
  158. other.p_ = nullptr;
  159. return *this;
  160. }
  161. template<class T>
  162. auto
  163. recycled_ptr<T>::
  164. operator=(
  165. recycled_ptr const& other) noexcept ->
  166. recycled_ptr&
  167. {
  168. BOOST_ASSERT(
  169. bin_ == other.bin_);
  170. if(p_)
  171. bin_->release(p_);
  172. p_ = other.p_;
  173. if(p_)
  174. ++p_->refs;
  175. return *this;
  176. }
  177. template<class T>
  178. T&
  179. recycled_ptr<T>::
  180. acquire()
  181. {
  182. if(! p_)
  183. p_ = bin_->acquire();
  184. return p_->t;
  185. }
  186. template<class T>
  187. void
  188. recycled_ptr<T>::
  189. release() noexcept
  190. {
  191. if(p_)
  192. {
  193. bin_->release(p_);
  194. p_ = nullptr;
  195. }
  196. }
  197. } // grammar
  198. } // urls
  199. } // boost
  200. #endif