storage_ptr.hpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  1. //
  2. // Copyright (c) 2019 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/json
  8. //
  9. #ifndef BOOST_JSON_STORAGE_PTR_HPP
  10. #define BOOST_JSON_STORAGE_PTR_HPP
  11. #include <boost/json/detail/config.hpp>
  12. #include <boost/json/memory_resource.hpp>
  13. #include <boost/json/detail/shared_resource.hpp>
  14. #include <boost/json/detail/default_resource.hpp>
  15. #include <cstddef>
  16. #include <new>
  17. #include <type_traits>
  18. #include <utility>
  19. namespace boost {
  20. namespace json {
  21. /** A smart pointer to a @ref memory_resource
  22. This container is used to hold a pointer to a memory resource. The
  23. pointed-to resource is always valid. Depending on the means of
  24. construction, the ownership will be either:
  25. @li Non-owning, when constructing from a raw
  26. pointer to @ref memory_resource or from a
  27. @ref polymorphic_allocator. In this case the
  28. caller is responsible for ensuring that the
  29. lifetime of the memory resource extends until
  30. there are no more calls to allocate or
  31. deallocate.
  32. @li Owning, when constructing using the function
  33. @ref make_shared_resource. In this case
  34. ownership is shared; the lifetime of the memory
  35. resource extends until the last copy of the
  36. @ref storage_ptr is destroyed.
  37. @par Examples
  38. These statements create a memory resource on the
  39. stack and construct a pointer from it without
  40. taking ownership:
  41. @code
  42. monotonic_resource mr; // Create our memory resource on the stack
  43. storage_ptr sp( &mr ); // Construct a non-owning pointer to the resource
  44. @endcode
  45. This function creates a pointer to a memory
  46. resource using shared ownership and returns it.
  47. The lifetime of the memory resource extends until
  48. the last copy of the pointer is destroyed:
  49. @code
  50. // Create a counted memory resource and return it
  51. storage_ptr make_storage()
  52. {
  53. return make_shared_resource< monotonic_resource >();
  54. }
  55. @endcode
  56. @par Thread Safety
  57. Instances of this type provide the default level of
  58. thread safety for all C++ objects. Specifically, it
  59. conforms to
  60. <a href="http://eel.is/c++draft/res.on.data.races">
  61. 16.4.6.10 Data race avoidance</a>.
  62. @see
  63. @ref make_shared_resource,
  64. @ref memory_resource,
  65. @ref polymorphic_allocator
  66. */
  67. class storage_ptr
  68. {
  69. #ifndef BOOST_JSON_DOCS
  70. // VFALCO doc toolchain shows this when it shouldn't
  71. friend struct detail::shared_resource;
  72. #endif
  73. using shared_resource =
  74. detail::shared_resource;
  75. using default_resource =
  76. detail::default_resource;
  77. std::uintptr_t i_;
  78. shared_resource*
  79. get_shared() const noexcept
  80. {
  81. return static_cast<shared_resource*>(
  82. reinterpret_cast<memory_resource*>(
  83. i_ & ~3));
  84. }
  85. void
  86. addref() const noexcept
  87. {
  88. if(is_shared())
  89. get_shared()->refs.fetch_add(
  90. 1, std::memory_order_relaxed);
  91. }
  92. void
  93. release() const noexcept
  94. {
  95. if(is_shared())
  96. {
  97. auto const p = get_shared();
  98. if(p->refs.fetch_sub(1,
  99. std::memory_order_acq_rel) == 1)
  100. delete p;
  101. }
  102. }
  103. template<class T>
  104. storage_ptr(
  105. detail::shared_resource_impl<T>* p) noexcept
  106. : i_(reinterpret_cast<std::uintptr_t>(
  107. static_cast<memory_resource*>(p)) + 1 +
  108. (json::is_deallocate_trivial<T>::value ? 2 : 0))
  109. {
  110. BOOST_ASSERT(p);
  111. }
  112. public:
  113. /** Destructor
  114. If the pointer has shared ownership of the
  115. resource, the shared ownership is released.
  116. If this is the last owned copy, the memory
  117. resource is destroyed.
  118. @par Complexity
  119. Constant.
  120. @par Exception Safety
  121. No-throw guarantee.
  122. */
  123. ~storage_ptr() noexcept
  124. {
  125. release();
  126. }
  127. /** Constructor
  128. This constructs a non-owning pointer that refers
  129. to the [default memory resource].
  130. @par Complexity
  131. Constant.
  132. @par Exception Safety
  133. No-throw guarantee.
  134. [default memory resource]: json/allocators/storage_ptr.html#json.allocators.storage_ptr.default_memory_resource
  135. */
  136. storage_ptr() noexcept
  137. : i_(0)
  138. {
  139. }
  140. /** Constructor
  141. This constructs a non-owning pointer that
  142. points to the memory resource `r`.
  143. The caller is responsible for maintaining the
  144. lifetime of the pointed-to @ref memory_resource.
  145. @par Constraints
  146. @code
  147. std::is_convertible< T*, memory_resource* >::value == true
  148. @endcode
  149. @par Preconditions
  150. @code
  151. r != nullptr
  152. @endcode
  153. @par Exception Safety
  154. No-throw guarantee.
  155. @param r A pointer to the memory resource to use.
  156. This may not be null.
  157. */
  158. template<class T
  159. #ifndef BOOST_JSON_DOCS
  160. , class = typename std::enable_if<
  161. std::is_convertible<T*,
  162. memory_resource*>::value>::type
  163. #endif
  164. >
  165. storage_ptr(T* r) noexcept
  166. : i_(reinterpret_cast<std::uintptr_t>(
  167. static_cast<memory_resource *>(r)) +
  168. (json::is_deallocate_trivial<T>::value ? 2 : 0))
  169. {
  170. BOOST_ASSERT(r);
  171. }
  172. /** Constructor
  173. This constructs a non-owning pointer that
  174. points to the same memory resource as `alloc`,
  175. obtained by calling `alloc.resource()`.
  176. The caller is responsible for maintaining the
  177. lifetime of the pointed-to @ref memory_resource.
  178. @par Constraints
  179. @code
  180. std::is_convertible< T*, memory_resource* >::value == true
  181. @endcode
  182. @par Exception Safety
  183. No-throw guarantee.
  184. @param alloc A @ref polymorphic_allocator to
  185. construct from.
  186. */
  187. template<class T>
  188. storage_ptr(
  189. polymorphic_allocator<T> const& alloc) noexcept
  190. : i_(reinterpret_cast<std::uintptr_t>(
  191. alloc.resource()))
  192. {
  193. }
  194. /** Move constructor
  195. This function constructs a pointer that
  196. points to the same memory resource as `other`,
  197. with the same ownership:
  198. @li If `other` is non-owning, then `*this`
  199. will be be non-owning.
  200. @li If `other` has shared ownership, then
  201. ownership will be transferred to `*this`.
  202. After construction, `other` will point
  203. to the [default memory resource].
  204. @par Complexity
  205. Constant.
  206. @par Exception Safety
  207. No-throw guarantee.
  208. @param other The pointer to construct from.
  209. [default memory resource]: json/allocators/storage_ptr.html#json.allocators.storage_ptr.default_memory_resource
  210. */
  211. storage_ptr(
  212. storage_ptr&& other) noexcept
  213. : i_(detail::exchange(other.i_, 0))
  214. {
  215. }
  216. /** Copy constructor
  217. This function constructs a pointer that
  218. points to the same memory resource as `other`,
  219. with the same ownership:
  220. @li If `other` is non-owning, then `*this`
  221. will be be non-owning.
  222. @li If `other` has shared ownership, then
  223. `*this` will acquire shared ownership.
  224. @par Complexity
  225. Constant.
  226. @par Exception Safety
  227. No-throw guarantee.
  228. @param other The pointer to construct from.
  229. */
  230. storage_ptr(
  231. storage_ptr const& other) noexcept
  232. : i_(other.i_)
  233. {
  234. addref();
  235. }
  236. /** Move assignment
  237. This function assigns a pointer that
  238. points to the same memory resource as `other`,
  239. with the same ownership:
  240. @li If `other` is non-owning, then `*this`
  241. will be be non-owning.
  242. @li If `other` has shared ownership, then
  243. ownership will be transferred to `*this`.
  244. After assignment, `other` will point
  245. to the [default memory resource].
  246. If `*this` previously had shared ownership,
  247. it is released before the function returns.
  248. @par Complexity
  249. Constant.
  250. @par Exception Safety
  251. No-throw guarantee.
  252. @param other The storage pointer to move.
  253. [default memory resource]: json/allocators/storage_ptr.html#json.allocators.storage_ptr.default_memory_resource
  254. */
  255. storage_ptr&
  256. operator=(
  257. storage_ptr&& other) noexcept
  258. {
  259. release();
  260. i_ = detail::exchange(other.i_, 0);
  261. return *this;
  262. }
  263. /** Copy assignment.
  264. This function assigns a pointer that
  265. points to the same memory resource as `other`,
  266. with the same ownership:
  267. @li If `other` is non-owning, then `*this`
  268. will be be non-owning.
  269. @li If `other` has shared ownership, then
  270. `*this` will acquire shared ownership.
  271. If `*this` previously had shared ownership,
  272. it is released before the function returns.
  273. @par Complexity
  274. Constant.
  275. @par Exception Safety
  276. No-throw guarantee.
  277. @param other The storage pointer to copy.
  278. */
  279. storage_ptr&
  280. operator=(
  281. storage_ptr const& other) noexcept
  282. {
  283. other.addref();
  284. release();
  285. i_ = other.i_;
  286. return *this;
  287. }
  288. /** Return `true` if ownership of the memory resource is shared.
  289. This function returns true for memory resources
  290. created using @ref make_shared_resource.
  291. */
  292. bool
  293. is_shared() const noexcept
  294. {
  295. return (i_ & 1) != 0;
  296. }
  297. /** Return `true` if calling `deallocate` on the memory resource has no effect.
  298. This function is used to determine if the deallocate
  299. function of the pointed to memory resource is trivial.
  300. The value of @ref is_deallocate_trivial is evaluated
  301. and saved when the memory resource is constructed
  302. and the type is known, before the type is erased.
  303. */
  304. bool
  305. is_deallocate_trivial() const noexcept
  306. {
  307. return (i_ & 2) != 0;
  308. }
  309. /** Return `true` if ownership of the memory resource is not shared and deallocate is trivial.
  310. This function is used to determine if calls to deallocate
  311. can effectively be skipped.
  312. @par Effects
  313. Returns `! this->is_shared() && this->is_deallocate_trivial()`
  314. */
  315. bool
  316. is_not_shared_and_deallocate_is_trivial() const noexcept
  317. {
  318. return (i_ & 3) == 2;
  319. }
  320. /** Return a pointer to the memory resource.
  321. This function returns a pointer to the
  322. referenced @ref memory_resource.
  323. @par Complexity
  324. Constant.
  325. @par Exception Safety
  326. No-throw guarantee.
  327. */
  328. memory_resource*
  329. get() const noexcept
  330. {
  331. if(i_ != 0)
  332. return reinterpret_cast<
  333. memory_resource*>(i_ & ~3);
  334. return default_resource::get();
  335. }
  336. /** Return a pointer to the memory resource.
  337. This function returns a pointer to the
  338. referenced @ref memory_resource.
  339. @par Complexity
  340. Constant.
  341. @par Exception Safety
  342. No-throw guarantee.
  343. */
  344. memory_resource*
  345. operator->() const noexcept
  346. {
  347. return get();
  348. }
  349. /** Return a reference to the memory resource.
  350. This function returns a reference to the
  351. pointed-to @ref memory_resource.
  352. @par Complexity
  353. Constant.
  354. @par Exception Safety
  355. No-throw guarantee.
  356. */
  357. memory_resource&
  358. operator*() const noexcept
  359. {
  360. return *get();
  361. }
  362. template<class U, class... Args>
  363. friend
  364. storage_ptr
  365. make_shared_resource(Args&&... args);
  366. };
  367. #if defined(_MSC_VER)
  368. # pragma warning( push )
  369. # if !defined(__clang__) && _MSC_VER <= 1900
  370. # pragma warning( disable : 4702 )
  371. # endif
  372. #endif
  373. /** Return shared ownership of a new, dynamically allocated memory resource.
  374. This function dynamically allocates a new memory resource
  375. as if by `operator new` that uses shared ownership. The
  376. lifetime of the memory resource will be extended until
  377. the last @ref storage_ptr which points to it is destroyed.
  378. @par Mandates
  379. @code
  380. std::is_base_of< memory_resource, U >::value == true
  381. @endcode
  382. @par Complexity
  383. Same as `new U( std::forward<Args>(args)... )`.
  384. @par Exception Safety
  385. Strong guarantee.
  386. @tparam U The type of memory resource to create.
  387. @param args Parameters forwarded to the constructor of `U`.
  388. */
  389. template<class U, class... Args>
  390. storage_ptr
  391. make_shared_resource(Args&&... args)
  392. {
  393. // If this generates an error, it means that
  394. // `T` is not a memory resource.
  395. BOOST_STATIC_ASSERT(
  396. std::is_base_of<
  397. memory_resource, U>::value);
  398. return storage_ptr(new
  399. detail::shared_resource_impl<U>(
  400. std::forward<Args>(args)...));
  401. }
  402. #if defined(_MSC_VER)
  403. # pragma warning( pop )
  404. #endif
  405. /** Return true if two storage pointers point to the same memory resource.
  406. This function returns `true` if the @ref memory_resource
  407. objects pointed to by `lhs` and `rhs` have the
  408. same address.
  409. */
  410. inline
  411. bool
  412. operator==(
  413. storage_ptr const& lhs,
  414. storage_ptr const& rhs) noexcept
  415. {
  416. return lhs.get() == rhs.get();
  417. }
  418. /** Return true if two storage pointers point to different memory resources.
  419. This function returns `true` if the @ref memory_resource
  420. objects pointed to by `lhs` and `rhs` have different
  421. addresses.
  422. */
  423. inline
  424. bool
  425. operator!=(
  426. storage_ptr const& lhs,
  427. storage_ptr const& rhs) noexcept
  428. {
  429. return lhs.get() != rhs.get();
  430. }
  431. } // namespace json
  432. } // namespace boost
  433. #endif