recycled.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510
  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_RECYCLED_HPP
  10. #define BOOST_URL_GRAMMAR_RECYCLED_HPP
  11. #include <boost/url/detail/config.hpp>
  12. #include <boost/url/grammar/detail/recycled.hpp>
  13. #include <atomic>
  14. #include <cstddef>
  15. #include <type_traits>
  16. #include <stddef.h> // ::max_align_t
  17. #if !defined(BOOST_URL_DISABLE_THREADS)
  18. # include <mutex>
  19. #endif
  20. namespace boost {
  21. namespace urls {
  22. namespace grammar {
  23. /** Provides an aligned storage buffer aligned for T
  24. */
  25. #ifdef BOOST_URL_DOCS
  26. template<class T>
  27. struct aligned_storage
  28. {
  29. /** Return a pointer to the aligned storage area
  30. */
  31. void* addr() noexcept;
  32. /** Return a pointer to the aligned storage area
  33. */
  34. void const* addr() const noexcept;
  35. };
  36. #else
  37. template<class T>
  38. using aligned_storage =
  39. detail::aligned_storage_impl<
  40. detail::nearest_pow2(sizeof(T), 64),
  41. (alignof(::max_align_t) > alignof(T)) ?
  42. alignof(::max_align_t) : alignof(T)>;
  43. #endif
  44. //------------------------------------------------
  45. /** A thread-safe collection of instances of T
  46. Instances of this type may be used to control
  47. where recycled instances of T come from when
  48. used with @ref recycled_ptr.
  49. @par Example
  50. @code
  51. static recycled< std::string > bin;
  52. recycled_ptr< std::string > ps( bin );
  53. // Put the string into a known state
  54. ps->clear();
  55. @endcode
  56. @see
  57. @ref recycled_ptr.
  58. */
  59. template<class T>
  60. class recycled
  61. {
  62. public:
  63. /** Destructor
  64. All recycled instances of T are destroyed.
  65. Undefined behavior results if there are
  66. any @ref recycled_ptr which reference
  67. this recycle bin.
  68. */
  69. ~recycled();
  70. /** Constructor
  71. */
  72. constexpr recycled() = default;
  73. private:
  74. template<class>
  75. friend class recycled_ptr;
  76. struct U
  77. {
  78. T t;
  79. U* next = nullptr;
  80. #if !defined(BOOST_URL_DISABLE_THREADS)
  81. std::atomic<
  82. std::size_t> refs;
  83. #else
  84. std::size_t refs;
  85. #endif
  86. U()
  87. : refs{1}
  88. {
  89. }
  90. };
  91. struct report;
  92. U* acquire();
  93. void release(U* u) noexcept;
  94. U* head_ = nullptr;
  95. #if !defined(BOOST_URL_DISABLE_THREADS)
  96. std::mutex m_;
  97. #endif
  98. };
  99. //------------------------------------------------
  100. /** A pointer to shared instance of T
  101. This is a smart pointer container which can
  102. acquire shared ownership of an instance of
  103. `T` upon or after construction. The instance
  104. is guaranteed to be in a valid, but unknown
  105. state. Every recycled pointer references
  106. a valid recycle bin.
  107. @par Example
  108. @code
  109. static recycled< std::string > bin;
  110. recycled_ptr< std::string > ps( bin );
  111. // Put the string into a known state
  112. ps->clear();
  113. @endcode
  114. @tparam T the type of object to
  115. acquire, which must be
  116. <em>DefaultConstructible</em>.
  117. */
  118. template<class T>
  119. class recycled_ptr
  120. {
  121. // T must be default constructible!
  122. static_assert(
  123. std::is_default_constructible<T>::value,
  124. "T must be DefaultConstructible");
  125. friend class recycled<T>;
  126. using B = recycled<T>;
  127. using U = typename B::U;
  128. B* bin_ = nullptr;
  129. U* p_ = nullptr;
  130. public:
  131. /** Destructor
  132. If this is not empty, shared ownership
  133. of the pointee is released. If this was
  134. the last reference, the object is
  135. returned to the original recycle bin.
  136. @par Effects
  137. @code
  138. this->release();
  139. @endcode
  140. */
  141. ~recycled_ptr();
  142. /** Constructor
  143. Upon construction, this acquires
  144. exclusive access to an object of type
  145. `T` which is either recycled from the
  146. specified bin, or newly allocated.
  147. The object is in an unknown but
  148. valid state.
  149. @par Example
  150. @code
  151. static recycled< std::string > bin;
  152. recycled_ptr< std::string > ps( bin );
  153. // Put the string into a known state
  154. ps->clear();
  155. @endcode
  156. @par Postconditions
  157. @code
  158. &this->bin() == &bin && ! this->empty()
  159. @endcode
  160. @param bin The recycle bin to use
  161. @see
  162. @ref recycled.
  163. */
  164. explicit
  165. recycled_ptr(recycled<T>& bin);
  166. /** Constructor
  167. After construction, this is empty and
  168. refers to the specified recycle bin.
  169. @par Example
  170. @code
  171. static recycled< std::string > bin;
  172. recycled_ptr< std::string > ps( bin, nullptr );
  173. // Acquire a string and put it into a known state
  174. ps->acquire();
  175. ps->clear();
  176. @endcode
  177. @par Postconditions
  178. @code
  179. &this->bin() == &bin && this->empty()
  180. @endcode
  181. @par Exception Safety
  182. Throws nothing.
  183. @param bin The recycle bin to use
  184. @see
  185. @ref acquire,
  186. @ref recycled,
  187. @ref release.
  188. */
  189. recycled_ptr(
  190. recycled<T>& bin,
  191. std::nullptr_t) noexcept;
  192. /** Constructor
  193. Upon construction, this acquires
  194. exclusive access to an object of type
  195. `T` which is either recycled from a
  196. global recycle bin, or newly allocated.
  197. The object is in an unknown but
  198. valid state.
  199. @par Example
  200. @code
  201. recycled_ptr< std::string > ps;
  202. // Put the string into a known state
  203. ps->clear();
  204. @endcode
  205. @par Postconditions
  206. @code
  207. &this->bin() != nullptr && ! this->empty()
  208. @endcode
  209. @see
  210. @ref recycled.
  211. */
  212. recycled_ptr();
  213. /** Constructor
  214. After construction, this is empty
  215. and refers to a global recycle bin.
  216. @par Example
  217. @code
  218. recycled_ptr< std::string > ps( nullptr );
  219. // Acquire a string and put it into a known state
  220. ps->acquire();
  221. ps->clear();
  222. @endcode
  223. @par Postconditions
  224. @code
  225. &this->bin() != nullptr && this->empty()
  226. @endcode
  227. @par Exception Safety
  228. Throws nothing.
  229. @see
  230. @ref acquire,
  231. @ref recycled,
  232. @ref release.
  233. */
  234. recycled_ptr(
  235. std::nullptr_t) noexcept;
  236. /** Constructor
  237. If `other` references an object, the
  238. newly constructed pointer acquires
  239. shared ownership. Otherwise this is
  240. empty. The new pointer references
  241. the same recycle bin as `other`.
  242. @par Postconditions
  243. @code
  244. &this->bin() == &other->bin() && this->get() == other.get()
  245. @endcode
  246. @par Exception Safety
  247. Throws nothing.
  248. @param other The pointer to copy
  249. */
  250. recycled_ptr(
  251. recycled_ptr const& other) noexcept;
  252. /** Constructor
  253. If `other` references an object,
  254. ownership is transferred including
  255. a reference to the recycle bin. After
  256. the move, the moved-from object is empty.
  257. @par Postconditions
  258. @code
  259. &this->bin() == &other->bin() && ! this->empty() && other.empty()
  260. @endcode
  261. @par Exception Safety
  262. Throws nothing.
  263. @param other The pointer to move from
  264. */
  265. recycled_ptr(
  266. recycled_ptr&& other) noexcept;
  267. /** Assignment
  268. If `other` references an object,
  269. ownership is transferred including
  270. a reference to the recycle bin. After
  271. the move, the moved-from object is empty.
  272. @par Effects
  273. @code
  274. this->release()
  275. @endcode
  276. @par Postconditions
  277. @code
  278. &this->bin() == &other->bin()
  279. @endcode
  280. @par Exception Safety
  281. Throws nothing.
  282. @param other The pointer to move from
  283. */
  284. recycled_ptr&
  285. operator=(
  286. recycled_ptr&& other) noexcept;
  287. /** Assignment
  288. If `other` references an object,
  289. this acquires shared ownership and
  290. references the same recycle bin as
  291. `other`. The previous object if any
  292. is released.
  293. @par Effects
  294. @code
  295. this->release()
  296. @endcode
  297. @par Postconditions
  298. @code
  299. &this->bin() == &other->bin() && this->get() == other.get()
  300. @endcode
  301. @par Exception Safety
  302. Throws nothing.
  303. @param other The pointer to copy from
  304. */
  305. recycled_ptr&
  306. operator=(
  307. recycled_ptr const& other) noexcept;
  308. /** Return true if this does not reference an object
  309. @par Exception Safety
  310. Throws nothing.
  311. */
  312. bool
  313. empty() const noexcept
  314. {
  315. return p_ == nullptr;
  316. }
  317. /** Return true if this references an object
  318. @par Effects
  319. @code
  320. return ! this->empty();
  321. @endcode
  322. @par Exception Safety
  323. Throws nothing.
  324. */
  325. explicit
  326. operator bool() const noexcept
  327. {
  328. return p_ != nullptr;
  329. }
  330. /** Return the referenced recycle bin
  331. @par Exception Safety
  332. Throws nothing.
  333. */
  334. recycled<T>&
  335. bin() const noexcept
  336. {
  337. return *bin_;
  338. }
  339. /** Return the referenced object
  340. If this is empty, `nullptr` is returned.
  341. @par Exception Safety
  342. Throws nothing.
  343. */
  344. T* get() const noexcept
  345. {
  346. return &p_->t;
  347. }
  348. /** Return the referenced object
  349. If this is empty, `nullptr` is returned.
  350. @par Exception Safety
  351. Throws nothing.
  352. */
  353. T* operator->() const noexcept
  354. {
  355. return get();
  356. }
  357. /** Return the referenced object
  358. @par Preconditions
  359. @code
  360. not this->empty()
  361. @endcode
  362. */
  363. T& operator*() const noexcept
  364. {
  365. return *get();
  366. }
  367. /** Return the referenced object
  368. If this references an object, it is
  369. returned. Otherwise, exclusive ownership
  370. of a new object of type `T` is acquired
  371. and returned.
  372. @par Postconditions
  373. @code
  374. not this->empty()
  375. @endcode
  376. */
  377. T& acquire();
  378. /** Release the referenced object
  379. If this references an object, it is
  380. released to the referenced recycle bin.
  381. The pointer continues to reference
  382. the same recycle bin.
  383. @par Postconditions
  384. @code
  385. this->empty()
  386. @endcode
  387. @par Exception Safety
  388. Throws nothing.
  389. */
  390. void release() noexcept;
  391. };
  392. } // grammar
  393. } // urls
  394. } // boost
  395. #include <boost/url/grammar/impl/recycled.hpp>
  396. #endif