recycled.hpp 11 KB

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