unique_resource.hpp 63 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642
  1. /*
  2. * Distributed under the Boost Software License, Version 1.0.
  3. * (See accompanying file LICENSE_1_0.txt or copy at
  4. * https://www.boost.org/LICENSE_1_0.txt)
  5. *
  6. * Copyright (c) 2022-2024 Andrey Semashev
  7. */
  8. /*!
  9. * \file scope/unique_resource.hpp
  10. *
  11. * This header contains definition of \c unique_resource template.
  12. */
  13. #ifndef BOOST_SCOPE_UNIQUE_RESOURCE_HPP_INCLUDED_
  14. #define BOOST_SCOPE_UNIQUE_RESOURCE_HPP_INCLUDED_
  15. #include <new> // for placement new
  16. #include <type_traits>
  17. #include <boost/core/addressof.hpp>
  18. #include <boost/core/invoke_swap.hpp>
  19. #include <boost/scope/unique_resource_fwd.hpp>
  20. #include <boost/scope/detail/config.hpp>
  21. #include <boost/scope/detail/compact_storage.hpp>
  22. #include <boost/scope/detail/move_or_copy_assign_ref.hpp>
  23. #include <boost/scope/detail/move_or_copy_construct_ref.hpp>
  24. #include <boost/scope/detail/is_nonnull_default_constructible.hpp>
  25. #include <boost/scope/detail/type_traits/is_swappable.hpp>
  26. #include <boost/scope/detail/type_traits/is_nothrow_swappable.hpp>
  27. #include <boost/scope/detail/type_traits/is_nothrow_invocable.hpp>
  28. #include <boost/scope/detail/type_traits/negation.hpp>
  29. #include <boost/scope/detail/type_traits/conjunction.hpp>
  30. #include <boost/scope/detail/type_traits/disjunction.hpp>
  31. #include <boost/scope/detail/header.hpp>
  32. #ifdef BOOST_HAS_PRAGMA_ONCE
  33. #pragma once
  34. #endif
  35. namespace boost {
  36. namespace scope {
  37. #if !defined(BOOST_NO_CXX17_FOLD_EXPRESSIONS) && !defined(BOOST_NO_CXX17_AUTO_NONTYPE_TEMPLATE_PARAMS)
  38. /*!
  39. * \brief Simple resource traits for one or more unallocated resource values.
  40. *
  41. * This class template generates resource traits for `unique_resource` that specify
  42. * one or more unallocated resource values. The first value, specified in the \c DefaultValue
  43. * non-type template parameter, is considered the default. The other values, listed in
  44. * \c UnallocatedValues, are optional. Any resource values other than \c DefaultValue
  45. * or listed in \c UnallocatedValues are considered as allocated.
  46. *
  47. * In order for the generated resource traits to enable optimized implementation of
  48. * `unique_resource`, the resource type must support non-throwing construction and assignment
  49. * from, and comparison for (in)equality with \c DefaultValue or any of the resource
  50. * values listed in \c UnallocatedValues.
  51. */
  52. template< auto DefaultValue, auto... UnallocatedValues >
  53. struct unallocated_resource
  54. {
  55. //! Returns the default resource value
  56. static decltype(DefaultValue) make_default() noexcept
  57. {
  58. return DefaultValue;
  59. }
  60. //! Tests if \a res is an allocated resource value
  61. template< typename Resource >
  62. static bool is_allocated(Resource const& res) noexcept
  63. {
  64. static_assert(noexcept(res != DefaultValue && (... && (res != UnallocatedValues))),
  65. "Invalid unallocated resource value types: comparing resource values with the unallocated values must be noexcept");
  66. return res != DefaultValue && (... && (res != UnallocatedValues));
  67. }
  68. };
  69. #endif // !defined(BOOST_NO_CXX17_FOLD_EXPRESSIONS) && !defined(BOOST_NO_CXX17_AUTO_NONTYPE_TEMPLATE_PARAMS)
  70. struct default_resource_t { };
  71. //! Keyword representing default, unallocated resource argument
  72. BOOST_INLINE_VARIABLE constexpr default_resource_t default_resource = { };
  73. namespace detail {
  74. // The type trait indicates whether \c T is a possibly qualified \c default_resource_t type
  75. template< typename T >
  76. struct is_default_resource : public std::false_type { };
  77. template< >
  78. struct is_default_resource< default_resource_t > : public std::true_type { };
  79. template< >
  80. struct is_default_resource< const default_resource_t > : public std::true_type { };
  81. template< >
  82. struct is_default_resource< volatile default_resource_t > : public std::true_type { };
  83. template< >
  84. struct is_default_resource< const volatile default_resource_t > : public std::true_type { };
  85. template< typename T >
  86. struct is_default_resource< T& > : public is_default_resource< T >::type { };
  87. // Lightweight reference wrapper
  88. template< typename T >
  89. class ref_wrapper
  90. {
  91. private:
  92. T* m_value;
  93. public:
  94. explicit
  95. #if !defined(BOOST_CORE_NO_CONSTEXPR_ADDRESSOF)
  96. constexpr
  97. #endif
  98. ref_wrapper(T& value) noexcept :
  99. m_value(boost::addressof(value))
  100. {
  101. }
  102. ref_wrapper& operator= (T& value) noexcept
  103. {
  104. m_value = boost::addressof(value);
  105. return *this;
  106. }
  107. ref_wrapper(T&&) = delete;
  108. ref_wrapper& operator= (T&&) = delete;
  109. operator T& () const noexcept
  110. {
  111. return *m_value;
  112. }
  113. template< typename... Args >
  114. void operator() (Args&&... args) const noexcept(detail::is_nothrow_invocable< T&, Args&&... >::value)
  115. {
  116. (*m_value)(static_cast< Args&& >(args)...);
  117. }
  118. };
  119. template< typename T >
  120. struct wrap_reference
  121. {
  122. using type = T;
  123. };
  124. template< typename T >
  125. struct wrap_reference< T& >
  126. {
  127. using type = ref_wrapper< T >;
  128. };
  129. template< typename Resource, bool UseCompactStorage >
  130. class resource_holder :
  131. public detail::compact_storage< typename wrap_reference< Resource >::type >
  132. {
  133. public:
  134. using resource_type = Resource;
  135. using internal_resource_type = typename wrap_reference< resource_type >::type;
  136. private:
  137. using resource_base = detail::compact_storage< internal_resource_type >;
  138. public:
  139. template<
  140. bool Requires = std::is_default_constructible< internal_resource_type >::value,
  141. typename = typename std::enable_if< Requires >::type
  142. >
  143. constexpr resource_holder() noexcept(std::is_nothrow_default_constructible< internal_resource_type >::value) :
  144. resource_base()
  145. {
  146. }
  147. template<
  148. typename R,
  149. typename = typename std::enable_if< std::is_constructible< internal_resource_type, R >::value >::type
  150. >
  151. explicit resource_holder(R&& res) noexcept(std::is_nothrow_constructible< internal_resource_type, R >::value) :
  152. resource_base(static_cast< R&& >(res))
  153. {
  154. }
  155. template<
  156. typename R,
  157. typename D,
  158. typename = typename std::enable_if< std::is_constructible< internal_resource_type, R >::value >::type
  159. >
  160. explicit resource_holder(R&& res, D&& del, bool allocated) noexcept(std::is_nothrow_constructible< internal_resource_type, R >::value) :
  161. resource_holder(static_cast< R&& >(res), static_cast< D&& >(del), allocated, typename std::is_nothrow_constructible< resource_type, R >::type())
  162. {
  163. }
  164. resource_type& get() noexcept
  165. {
  166. return resource_base::get();
  167. }
  168. resource_type const& get() const noexcept
  169. {
  170. return resource_base::get();
  171. }
  172. internal_resource_type& get_internal() noexcept
  173. {
  174. return resource_base::get();
  175. }
  176. internal_resource_type const& get_internal() const noexcept
  177. {
  178. return resource_base::get();
  179. }
  180. void move_from(internal_resource_type&& that) noexcept(std::is_nothrow_move_assignable< internal_resource_type >::value)
  181. {
  182. resource_base::get() = static_cast< internal_resource_type&& >(that);
  183. }
  184. private:
  185. template< typename R, typename D >
  186. explicit resource_holder(R&& res, D&& del, bool allocated, std::true_type) noexcept :
  187. resource_base(static_cast< R&& >(res))
  188. {
  189. }
  190. template< typename R, typename D >
  191. explicit resource_holder(R&& res, D&& del, bool allocated, std::false_type) try :
  192. resource_base(res)
  193. {
  194. }
  195. catch (...)
  196. {
  197. if (allocated)
  198. del(res);
  199. }
  200. };
  201. template< typename Resource >
  202. class resource_holder< Resource, false >
  203. {
  204. public:
  205. using resource_type = Resource;
  206. using internal_resource_type = typename wrap_reference< resource_type >::type;
  207. private:
  208. // Note: Not using compact_storage since we will need to reuse storage for this complete object in move_from
  209. internal_resource_type m_resource;
  210. public:
  211. template<
  212. bool Requires = std::is_default_constructible< internal_resource_type >::value,
  213. typename = typename std::enable_if< Requires >::type
  214. >
  215. constexpr resource_holder() noexcept(std::is_nothrow_default_constructible< internal_resource_type >::value) :
  216. m_resource()
  217. {
  218. }
  219. template<
  220. typename R,
  221. typename = typename std::enable_if< std::is_constructible< internal_resource_type, R >::value >::type
  222. >
  223. explicit resource_holder(R&& res) noexcept(std::is_nothrow_constructible< internal_resource_type, R >::value) :
  224. m_resource(static_cast< R&& >(res))
  225. {
  226. }
  227. template<
  228. typename R,
  229. typename D,
  230. typename = typename std::enable_if< std::is_constructible< internal_resource_type, R >::value >::type
  231. >
  232. explicit resource_holder(R&& res, D&& del, bool allocated) noexcept(std::is_nothrow_constructible< internal_resource_type, R >::value) :
  233. resource_holder(static_cast< R&& >(res), static_cast< D&& >(del), allocated, typename std::is_nothrow_constructible< resource_type, R >::type())
  234. {
  235. }
  236. resource_type& get() noexcept
  237. {
  238. return m_resource;
  239. }
  240. resource_type const& get() const noexcept
  241. {
  242. return m_resource;
  243. }
  244. internal_resource_type& get_internal() noexcept
  245. {
  246. return m_resource;
  247. }
  248. internal_resource_type const& get_internal() const noexcept
  249. {
  250. return m_resource;
  251. }
  252. void move_from(internal_resource_type&& that)
  253. noexcept(std::is_nothrow_constructible< internal_resource_type, typename detail::move_or_copy_construct_ref< resource_type >::type >::value)
  254. {
  255. internal_resource_type* p = boost::addressof(m_resource);
  256. p->~internal_resource_type();
  257. new (p) internal_resource_type(static_cast< typename detail::move_or_copy_construct_ref< resource_type >::type >(that));
  258. }
  259. private:
  260. template< typename R, typename D >
  261. explicit resource_holder(R&& res, D&& del, bool allocated, std::true_type) noexcept :
  262. m_resource(static_cast< R&& >(res))
  263. {
  264. }
  265. template< typename R, typename D >
  266. explicit resource_holder(R&& res, D&& del, bool allocated, std::false_type) try :
  267. m_resource(res)
  268. {
  269. }
  270. catch (...)
  271. {
  272. if (allocated)
  273. del(res);
  274. }
  275. };
  276. template< typename Resource, typename Deleter >
  277. class deleter_holder :
  278. public detail::compact_storage< typename wrap_reference< Deleter >::type >
  279. {
  280. public:
  281. using resource_type = Resource;
  282. using deleter_type = Deleter;
  283. using internal_deleter_type = typename wrap_reference< deleter_type >::type;
  284. private:
  285. using deleter_base = detail::compact_storage< internal_deleter_type >;
  286. public:
  287. template<
  288. bool Requires = detail::is_nonnull_default_constructible< internal_deleter_type >::value,
  289. typename = typename std::enable_if< Requires >::type
  290. >
  291. constexpr deleter_holder() noexcept(detail::is_nothrow_nonnull_default_constructible< internal_deleter_type >::value) :
  292. deleter_base()
  293. {
  294. }
  295. template<
  296. typename D,
  297. typename = typename std::enable_if< std::is_constructible< internal_deleter_type, D >::value >::type
  298. >
  299. explicit deleter_holder(D&& del) noexcept(std::is_nothrow_constructible< internal_deleter_type, D >::value) :
  300. deleter_base(static_cast< D&& >(del))
  301. {
  302. }
  303. template<
  304. typename D,
  305. typename = typename std::enable_if< std::is_constructible< internal_deleter_type, D >::value >::type
  306. >
  307. explicit deleter_holder(D&& del, resource_type& res, bool allocated) noexcept(std::is_nothrow_constructible< internal_deleter_type, D >::value) :
  308. deleter_holder(static_cast< D&& >(del), res, allocated, typename std::is_nothrow_constructible< internal_deleter_type, D >::type())
  309. {
  310. }
  311. deleter_type& get() noexcept
  312. {
  313. return deleter_base::get();
  314. }
  315. deleter_type const& get() const noexcept
  316. {
  317. return deleter_base::get();
  318. }
  319. internal_deleter_type& get_internal() noexcept
  320. {
  321. return deleter_base::get();
  322. }
  323. internal_deleter_type const& get_internal() const noexcept
  324. {
  325. return deleter_base::get();
  326. }
  327. private:
  328. template< typename D >
  329. explicit deleter_holder(D&& del, resource_type& res, bool allocated, std::true_type) noexcept :
  330. deleter_base(static_cast< D&& >(del))
  331. {
  332. }
  333. template< typename D >
  334. explicit deleter_holder(D&& del, resource_type& res, bool allocated, std::false_type) try :
  335. deleter_base(del)
  336. {
  337. }
  338. catch (...)
  339. {
  340. if (BOOST_LIKELY(allocated))
  341. del(res);
  342. }
  343. };
  344. /*
  345. * This metafunction indicates whether \c resource_holder should use \c compact_storage
  346. * to optimize storage for the resource object. Its definition must be coherent with
  347. * `resource_holder::move_from` definition and move constructor implementation in
  348. * \c unique_resource_data.
  349. *
  350. * There is one tricky case with \c unique_resource move constructor, when the resource move
  351. * constructor is noexcept and deleter's move and copy constructors are not. It is possible
  352. * that \c unique_resource_data move constructor moves the resource into the object being
  353. * constructed but fails to construct the deleter. In this case we want to move the resource
  354. * back to the original \c unique_resource_data object (which is guaranteed to not throw since
  355. * the resource's move constructor is non-throwing).
  356. *
  357. * However, if we use the move constructor to move the resource back, we need to use placement
  358. * new, and this only lets us create a complete object of the resource type, which prohibits
  359. * the use of \c compact_storage, as it may create the resource object as a base subobject of
  360. * \c compact_storage. Using placement new on a base subobject may corrupt data that is placed
  361. * in the trailing padding bits of the resource type.
  362. *
  363. * To work around this limitation, we also test if move assignment of the resource type is
  364. * also non-throwing (which is reasonable to expect, given that the move constructor is
  365. * non-throwing). If it is, we can avoid having to destroy and move-construct the resource and
  366. * use move-assignment instead. This doesn't require a complete object of the resource type
  367. * and allows us to use \c compact_storage. If move assignment is not noexcept then we have
  368. * to use the move constructor and disable the \c compact_storage optimization.
  369. *
  370. * So this trait has to detect (a) whether we are affected by this tricky case of the
  371. * \c unique_resource move constructor in the first place and (b) whether we can use move
  372. * assignment to move the resource back to the original \c unique_resource object. If we're
  373. * not affected or we can use move assignment then we enable \c compact_storage.
  374. */
  375. template< typename Resource, typename Deleter >
  376. using use_resource_compact_storage = detail::disjunction<
  377. std::is_nothrow_move_assignable< typename wrap_reference< Resource >::type >,
  378. std::is_nothrow_constructible< typename wrap_reference< Deleter >::type, typename detail::move_or_copy_construct_ref< Deleter >::type >,
  379. detail::negation< std::is_nothrow_constructible< typename wrap_reference< Resource >::type, typename detail::move_or_copy_construct_ref< Resource >::type > >
  380. >;
  381. template< typename Resource, typename Deleter, typename Traits >
  382. class unique_resource_data :
  383. public detail::resource_holder< Resource, use_resource_compact_storage< Resource, Deleter >::value >,
  384. public detail::deleter_holder< Resource, Deleter >
  385. {
  386. public:
  387. using resource_type = Resource;
  388. using deleter_type = Deleter;
  389. using traits_type = Traits;
  390. private:
  391. using resource_holder = detail::resource_holder< resource_type, use_resource_compact_storage< resource_type, deleter_type >::value >;
  392. using deleter_holder = detail::deleter_holder< resource_type, deleter_type >;
  393. using result_of_make_default = decltype(traits_type::make_default());
  394. public:
  395. using internal_resource_type = typename resource_holder::internal_resource_type;
  396. using internal_deleter_type = typename deleter_holder::internal_deleter_type;
  397. static_assert(noexcept(traits_type::make_default()), "Invalid unique_resource resource traits: make_default must be noexcept");
  398. static_assert(std::is_nothrow_assignable< internal_resource_type&, result_of_make_default >::value,
  399. "Invalid unique_resource resource traits: resource must be nothrow-assignable from the result of make_default");
  400. static_assert(noexcept(traits_type::is_allocated(std::declval< resource_type const& >())), "Invalid unique_resource resource traits: is_allocated must be noexcept");
  401. public:
  402. template<
  403. bool Requires = detail::conjunction<
  404. std::is_constructible< resource_holder, result_of_make_default >,
  405. std::is_default_constructible< deleter_holder >
  406. >::value,
  407. typename = typename std::enable_if< Requires >::type
  408. >
  409. constexpr unique_resource_data()
  410. noexcept(detail::conjunction<
  411. std::is_nothrow_constructible< resource_holder, result_of_make_default >,
  412. std::is_nothrow_default_constructible< deleter_holder >
  413. >::value) :
  414. resource_holder(traits_type::make_default()),
  415. deleter_holder()
  416. {
  417. }
  418. unique_resource_data(unique_resource_data const&) = delete;
  419. unique_resource_data& operator= (unique_resource_data const&) = delete;
  420. unique_resource_data(unique_resource_data&& that)
  421. noexcept(detail::conjunction<
  422. std::is_nothrow_constructible< internal_resource_type, typename detail::move_or_copy_construct_ref< resource_type >::type >,
  423. std::is_nothrow_constructible< internal_deleter_type, typename detail::move_or_copy_construct_ref< deleter_type >::type >
  424. >::value) :
  425. unique_resource_data
  426. (
  427. static_cast< unique_resource_data&& >(that),
  428. typename std::is_nothrow_constructible< internal_resource_type, typename detail::move_or_copy_construct_ref< resource_type >::type >::type(),
  429. typename std::is_nothrow_constructible< internal_deleter_type, typename detail::move_or_copy_construct_ref< deleter_type >::type >::type()
  430. )
  431. {
  432. }
  433. template<
  434. typename D,
  435. typename = typename std::enable_if< detail::conjunction<
  436. std::is_constructible< resource_holder, result_of_make_default >,
  437. std::is_constructible< deleter_holder, D >
  438. >::value >::type
  439. >
  440. explicit unique_resource_data(default_resource_t, D&& del)
  441. noexcept(detail::conjunction<
  442. std::is_nothrow_constructible< resource_holder, result_of_make_default >,
  443. std::is_nothrow_constructible< deleter_holder, D >
  444. >::value) :
  445. resource_holder(traits_type::make_default()),
  446. deleter_holder(static_cast< D&& >(del))
  447. {
  448. }
  449. template<
  450. typename R,
  451. typename D,
  452. typename = typename std::enable_if< detail::conjunction<
  453. detail::negation< detail::is_default_resource< R > >,
  454. std::is_constructible< resource_holder, R, D, bool >,
  455. std::is_constructible< deleter_holder, D, resource_type&, bool >
  456. >::value >::type
  457. >
  458. explicit unique_resource_data(R&& res, D&& del)
  459. noexcept(detail::conjunction<
  460. std::is_nothrow_constructible< resource_holder, R, D, bool >,
  461. std::is_nothrow_constructible< deleter_holder, D, resource_type&, bool >
  462. >::value) :
  463. unique_resource_data(static_cast< R&& >(res), static_cast< D&& >(del), traits_type::is_allocated(res)) // don't forward res to is_allocated to make sure res is not moved-from on resource construction
  464. {
  465. // Since res may not be of the resource type, the is_allocated call made above may require a type conversion or pick a different overload.
  466. // We still require it to be noexcept, as we need to know whether we should deallocate it. Otherwise we may leak the resource.
  467. static_assert(noexcept(traits_type::is_allocated(res)), "Invalid unique_resource resource traits: is_allocated must be noexcept");
  468. }
  469. template<
  470. bool Requires = detail::conjunction<
  471. std::is_assignable< internal_resource_type&, typename detail::move_or_copy_assign_ref< resource_type >::type >,
  472. std::is_assignable< internal_deleter_type&, typename detail::move_or_copy_assign_ref< deleter_type >::type >
  473. >::value
  474. >
  475. typename std::enable_if< Requires, unique_resource_data& >::type operator= (unique_resource_data&& that)
  476. noexcept(detail::conjunction<
  477. std::is_nothrow_assignable< internal_resource_type&, typename detail::move_or_copy_assign_ref< resource_type >::type >,
  478. std::is_nothrow_assignable< internal_deleter_type&, typename detail::move_or_copy_assign_ref< deleter_type >::type >
  479. >::value)
  480. {
  481. assign(static_cast< unique_resource_data&& >(that), typename std::is_nothrow_move_assignable< internal_deleter_type >::type());
  482. return *this;
  483. }
  484. resource_type& get_resource() noexcept
  485. {
  486. return resource_holder::get();
  487. }
  488. resource_type const& get_resource() const noexcept
  489. {
  490. return resource_holder::get();
  491. }
  492. internal_resource_type& get_internal_resource() noexcept
  493. {
  494. return resource_holder::get_internal();
  495. }
  496. internal_resource_type const& get_internal_resource() const noexcept
  497. {
  498. return resource_holder::get_internal();
  499. }
  500. deleter_type& get_deleter() noexcept
  501. {
  502. return deleter_holder::get();
  503. }
  504. deleter_type const& get_deleter() const noexcept
  505. {
  506. return deleter_holder::get();
  507. }
  508. internal_deleter_type& get_internal_deleter() noexcept
  509. {
  510. return deleter_holder::get_internal();
  511. }
  512. internal_deleter_type const& get_internal_deleter() const noexcept
  513. {
  514. return deleter_holder::get_internal();
  515. }
  516. bool is_allocated() const noexcept
  517. {
  518. return traits_type::is_allocated(get_resource());
  519. }
  520. void set_unallocated() noexcept
  521. {
  522. get_internal_resource() = traits_type::make_default();
  523. }
  524. template< typename R >
  525. void assign_resource(R&& res) noexcept(std::is_nothrow_assignable< internal_resource_type&, R >::value)
  526. {
  527. get_internal_resource() = static_cast< R&& >(res);
  528. }
  529. template<
  530. bool Requires = detail::conjunction<
  531. detail::is_swappable< internal_resource_type >,
  532. detail::is_swappable< internal_deleter_type >,
  533. detail::disjunction<
  534. detail::is_nothrow_swappable< internal_resource_type >,
  535. detail::is_nothrow_swappable< internal_deleter_type >
  536. >
  537. >::value
  538. >
  539. typename std::enable_if< Requires >::type swap(unique_resource_data& that)
  540. noexcept(detail::conjunction< detail::is_nothrow_swappable< internal_resource_type >, detail::is_nothrow_swappable< internal_deleter_type > >::value)
  541. {
  542. swap_impl
  543. (
  544. that,
  545. std::integral_constant< bool, detail::is_nothrow_swappable< internal_resource_type >::value >(),
  546. std::integral_constant< bool, detail::conjunction<
  547. detail::is_nothrow_swappable< internal_resource_type >,
  548. detail::is_nothrow_swappable< internal_deleter_type >
  549. >::value >()
  550. );
  551. }
  552. private:
  553. unique_resource_data(unique_resource_data&& that, std::true_type, std::true_type) noexcept :
  554. resource_holder(static_cast< typename detail::move_or_copy_construct_ref< resource_type >::type >(that.get_resource())),
  555. deleter_holder(static_cast< typename detail::move_or_copy_construct_ref< deleter_type >::type >(that.get_deleter()))
  556. {
  557. that.set_unallocated();
  558. }
  559. unique_resource_data(unique_resource_data&& that, std::false_type, std::true_type) :
  560. resource_holder(static_cast< resource_type const& >(that.get_resource())),
  561. deleter_holder(static_cast< typename detail::move_or_copy_construct_ref< deleter_type >::type >(that.get_deleter()))
  562. {
  563. that.set_unallocated();
  564. }
  565. unique_resource_data(unique_resource_data&& that, std::true_type, std::false_type) try :
  566. resource_holder(static_cast< typename detail::move_or_copy_construct_ref< resource_type >::type >(that.get_resource())),
  567. deleter_holder(static_cast< deleter_type const& >(that.get_deleter()))
  568. {
  569. that.set_unallocated();
  570. }
  571. catch (...)
  572. {
  573. // Since only the deleter's constructor could have thrown an exception here, move the resource back
  574. // to the original unique_resource. This is guaranteed to not throw.
  575. that.resource_holder::move_from(static_cast< internal_resource_type&& >(resource_holder::get_internal()));
  576. }
  577. unique_resource_data(unique_resource_data&& that, std::false_type, std::false_type) :
  578. resource_holder(static_cast< resource_type const& >(that.get_resource())),
  579. deleter_holder(static_cast< deleter_type const& >(that.get_deleter()))
  580. {
  581. that.set_unallocated();
  582. }
  583. template<
  584. typename R,
  585. typename D,
  586. typename = typename std::enable_if< detail::conjunction<
  587. std::is_constructible< resource_holder, R, D, bool >,
  588. std::is_constructible< deleter_holder, D, resource_type&, bool >
  589. >::value >::type
  590. >
  591. explicit unique_resource_data(R&& res, D&& del, bool allocated)
  592. noexcept(detail::conjunction<
  593. std::is_nothrow_constructible< resource_holder, R, D, bool >,
  594. std::is_nothrow_constructible< deleter_holder, D, resource_type&, bool >
  595. >::value) :
  596. resource_holder(static_cast< R&& >(res), static_cast< D&& >(del), allocated),
  597. deleter_holder(static_cast< D&& >(del), resource_holder::get(), allocated)
  598. {
  599. }
  600. void assign(unique_resource_data&& that, std::true_type)
  601. noexcept(std::is_nothrow_assignable< internal_resource_type&, typename detail::move_or_copy_assign_ref< resource_type >::type >::value)
  602. {
  603. get_internal_resource() = static_cast< typename detail::move_or_copy_assign_ref< resource_type >::type >(that.get_resource());
  604. get_internal_deleter() = static_cast< typename detail::move_or_copy_assign_ref< deleter_type >::type >(that.get_deleter());
  605. that.set_unallocated();
  606. }
  607. void assign(unique_resource_data&& that, std::false_type)
  608. {
  609. get_internal_deleter() = static_cast< typename detail::move_or_copy_assign_ref< deleter_type >::type >(that.get_deleter());
  610. get_internal_resource() = static_cast< typename detail::move_or_copy_assign_ref< resource_type >::type >(that.get_resource());
  611. that.set_unallocated();
  612. }
  613. void swap_impl(unique_resource_data& that, std::true_type, std::true_type) noexcept
  614. {
  615. boost::core::invoke_swap(get_internal_resource(), that.get_internal_resource());
  616. boost::core::invoke_swap(get_internal_deleter(), that.get_internal_deleter());
  617. }
  618. void swap_impl(unique_resource_data& that, std::true_type, std::false_type)
  619. {
  620. boost::core::invoke_swap(get_internal_deleter(), that.get_internal_deleter());
  621. boost::core::invoke_swap(get_internal_resource(), that.get_internal_resource());
  622. }
  623. void swap_impl(unique_resource_data& that, std::false_type, std::false_type)
  624. {
  625. boost::core::invoke_swap(get_internal_resource(), that.get_internal_resource());
  626. boost::core::invoke_swap(get_internal_deleter(), that.get_internal_deleter());
  627. }
  628. };
  629. template< typename Resource, typename Deleter >
  630. class unique_resource_data< Resource, Deleter, void > :
  631. public detail::resource_holder< Resource, use_resource_compact_storage< Resource, Deleter >::value >,
  632. public detail::deleter_holder< Resource, Deleter >
  633. {
  634. public:
  635. using resource_type = Resource;
  636. using deleter_type = Deleter;
  637. using traits_type = void;
  638. private:
  639. using resource_holder = detail::resource_holder< resource_type, use_resource_compact_storage< resource_type, deleter_type >::value >;
  640. using deleter_holder = detail::deleter_holder< resource_type, deleter_type >;
  641. public:
  642. using internal_resource_type = typename resource_holder::internal_resource_type;
  643. using internal_deleter_type = typename deleter_holder::internal_deleter_type;
  644. private:
  645. bool m_allocated;
  646. public:
  647. template<
  648. bool Requires = detail::conjunction< std::is_default_constructible< resource_holder >, std::is_default_constructible< deleter_holder > >::value,
  649. typename = typename std::enable_if< Requires >::type
  650. >
  651. constexpr unique_resource_data()
  652. noexcept(detail::conjunction< std::is_nothrow_default_constructible< resource_holder >, std::is_nothrow_default_constructible< deleter_holder > >::value) :
  653. resource_holder(),
  654. deleter_holder(),
  655. m_allocated(false)
  656. {
  657. }
  658. unique_resource_data(unique_resource_data const&) = delete;
  659. unique_resource_data& operator= (unique_resource_data const&) = delete;
  660. template<
  661. bool Requires = detail::conjunction<
  662. std::is_constructible< internal_resource_type, typename detail::move_or_copy_construct_ref< resource_type >::type >,
  663. std::is_constructible< internal_deleter_type, typename detail::move_or_copy_construct_ref< deleter_type >::type >
  664. >::value,
  665. typename = typename std::enable_if< Requires >::type
  666. >
  667. unique_resource_data(unique_resource_data&& that)
  668. noexcept(detail::conjunction<
  669. std::is_nothrow_constructible< internal_resource_type, typename detail::move_or_copy_construct_ref< resource_type >::type >,
  670. std::is_nothrow_constructible< internal_deleter_type, typename detail::move_or_copy_construct_ref< deleter_type >::type >
  671. >::value) :
  672. unique_resource_data
  673. (
  674. static_cast< unique_resource_data&& >(that),
  675. typename std::is_nothrow_constructible< internal_resource_type, typename detail::move_or_copy_construct_ref< resource_type >::type >::type(),
  676. typename std::is_nothrow_constructible< internal_deleter_type, typename detail::move_or_copy_construct_ref< deleter_type >::type >::type()
  677. )
  678. {
  679. }
  680. template<
  681. typename D,
  682. typename = typename std::enable_if< detail::conjunction<
  683. std::is_default_constructible< resource_holder >,
  684. std::is_constructible< deleter_holder, D >
  685. >::value >::type
  686. >
  687. explicit unique_resource_data(default_resource_t, D&& del)
  688. noexcept(detail::conjunction<
  689. std::is_nothrow_default_constructible< resource_holder >,
  690. std::is_nothrow_constructible< deleter_holder, D >
  691. >::value) :
  692. resource_holder(),
  693. deleter_holder(static_cast< D&& >(del)),
  694. m_allocated(false)
  695. {
  696. }
  697. template<
  698. typename R,
  699. typename D,
  700. typename = typename std::enable_if< detail::conjunction<
  701. detail::negation< detail::is_default_resource< R > >,
  702. std::is_constructible< resource_holder, R, D, bool >,
  703. std::is_constructible< deleter_holder, D, resource_type&, bool >
  704. >::value >::type
  705. >
  706. explicit unique_resource_data(R&& res, D&& del)
  707. noexcept(detail::conjunction<
  708. std::is_nothrow_constructible< resource_holder, R, D, bool >,
  709. std::is_nothrow_constructible< deleter_holder, D, resource_type&, bool >
  710. >::value) :
  711. resource_holder(static_cast< R&& >(res), static_cast< D&& >(del), true),
  712. deleter_holder(static_cast< D&& >(del), resource_holder::get(), true),
  713. m_allocated(true)
  714. {
  715. }
  716. template<
  717. bool Requires = detail::conjunction<
  718. std::is_assignable< internal_resource_type&, typename detail::move_or_copy_assign_ref< resource_type >::type >,
  719. std::is_assignable< internal_deleter_type&, typename detail::move_or_copy_assign_ref< deleter_type >::type >
  720. >::value
  721. >
  722. typename std::enable_if< Requires, unique_resource_data& >::type operator= (unique_resource_data&& that)
  723. noexcept(detail::conjunction<
  724. std::is_nothrow_assignable< internal_resource_type&, typename detail::move_or_copy_assign_ref< resource_type >::type >,
  725. std::is_nothrow_assignable< internal_deleter_type&, typename detail::move_or_copy_assign_ref< deleter_type >::type >
  726. >::value)
  727. {
  728. assign(static_cast< unique_resource_data&& >(that), typename std::is_nothrow_move_assignable< internal_deleter_type >::type());
  729. return *this;
  730. }
  731. resource_type& get_resource() noexcept
  732. {
  733. return resource_holder::get();
  734. }
  735. resource_type const& get_resource() const noexcept
  736. {
  737. return resource_holder::get();
  738. }
  739. internal_resource_type& get_internal_resource() noexcept
  740. {
  741. return resource_holder::get_internal();
  742. }
  743. internal_resource_type const& get_internal_resource() const noexcept
  744. {
  745. return resource_holder::get_internal();
  746. }
  747. deleter_type& get_deleter() noexcept
  748. {
  749. return deleter_holder::get();
  750. }
  751. deleter_type const& get_deleter() const noexcept
  752. {
  753. return deleter_holder::get();
  754. }
  755. internal_deleter_type& get_internal_deleter() noexcept
  756. {
  757. return deleter_holder::get_internal();
  758. }
  759. internal_deleter_type const& get_internal_deleter() const noexcept
  760. {
  761. return deleter_holder::get_internal();
  762. }
  763. bool is_allocated() const noexcept
  764. {
  765. return m_allocated;
  766. }
  767. void set_unallocated() noexcept
  768. {
  769. m_allocated = false;
  770. }
  771. template< typename R >
  772. void assign_resource(R&& res) noexcept(std::is_nothrow_assignable< internal_resource_type&, R >::value)
  773. {
  774. get_internal_resource() = static_cast< R&& >(res);
  775. m_allocated = true;
  776. }
  777. template<
  778. bool Requires = detail::conjunction<
  779. detail::is_swappable< internal_resource_type >,
  780. detail::is_swappable< internal_deleter_type >,
  781. detail::disjunction<
  782. detail::is_nothrow_swappable< internal_resource_type >,
  783. detail::is_nothrow_swappable< internal_deleter_type >
  784. >
  785. >::value
  786. >
  787. typename std::enable_if< Requires >::type swap(unique_resource_data& that)
  788. noexcept(detail::conjunction< detail::is_nothrow_swappable< internal_resource_type >, detail::is_nothrow_swappable< internal_deleter_type > >::value)
  789. {
  790. swap_impl
  791. (
  792. that,
  793. std::integral_constant< bool, detail::is_nothrow_swappable< internal_resource_type >::value >(),
  794. std::integral_constant< bool, detail::conjunction<
  795. detail::is_nothrow_swappable< internal_resource_type >,
  796. detail::is_nothrow_swappable< internal_deleter_type >
  797. >::value >()
  798. );
  799. }
  800. private:
  801. unique_resource_data(unique_resource_data&& that, std::true_type, std::true_type) noexcept :
  802. resource_holder(static_cast< typename detail::move_or_copy_construct_ref< resource_type >::type >(that.get_resource())),
  803. deleter_holder(static_cast< typename detail::move_or_copy_construct_ref< deleter_type >::type >(that.get_deleter())),
  804. m_allocated(that.m_allocated)
  805. {
  806. that.m_allocated = false;
  807. }
  808. unique_resource_data(unique_resource_data&& that, std::false_type, std::true_type) :
  809. resource_holder(static_cast< resource_type const& >(that.get_resource())),
  810. deleter_holder(static_cast< typename detail::move_or_copy_construct_ref< deleter_type >::type >(that.get_deleter())),
  811. m_allocated(that.m_allocated)
  812. {
  813. that.m_allocated = false;
  814. }
  815. unique_resource_data(unique_resource_data&& that, std::true_type, std::false_type) try :
  816. resource_holder(static_cast< typename detail::move_or_copy_construct_ref< resource_type >::type >(that.get_resource())),
  817. deleter_holder(static_cast< deleter_type const& >(that.get_deleter())),
  818. m_allocated(that.m_allocated)
  819. {
  820. that.m_allocated = false;
  821. }
  822. catch (...)
  823. {
  824. // Since only the deleter's constructor could have thrown an exception here, move the resource back
  825. // to the original unique_resource. This is guaranteed to not throw.
  826. that.resource_holder::move_from(static_cast< internal_resource_type&& >(resource_holder::get_internal()));
  827. }
  828. unique_resource_data(unique_resource_data&& that, std::false_type, std::false_type) :
  829. resource_holder(static_cast< resource_type const& >(that.get_resource())),
  830. deleter_holder(static_cast< deleter_type const& >(that.get_deleter())),
  831. m_allocated(that.m_allocated)
  832. {
  833. that.m_allocated = false;
  834. }
  835. void assign(unique_resource_data&& that, std::true_type)
  836. noexcept(std::is_nothrow_assignable< internal_resource_type&, typename detail::move_or_copy_assign_ref< resource_type >::type >::value)
  837. {
  838. get_internal_resource() = static_cast< typename detail::move_or_copy_assign_ref< resource_type >::type >(that.get_resource());
  839. get_internal_deleter() = static_cast< typename detail::move_or_copy_assign_ref< deleter_type >::type >(that.get_deleter());
  840. m_allocated = that.m_allocated;
  841. that.m_allocated = false;
  842. }
  843. void assign(unique_resource_data&& that, std::false_type)
  844. {
  845. get_internal_deleter() = static_cast< typename detail::move_or_copy_assign_ref< deleter_type >::type >(that.get_deleter());
  846. get_internal_resource() = static_cast< typename detail::move_or_copy_assign_ref< resource_type >::type >(that.get_resource());
  847. m_allocated = that.m_allocated;
  848. that.m_allocated = false;
  849. }
  850. void swap_impl(unique_resource_data& that, std::true_type, std::true_type) noexcept
  851. {
  852. boost::core::invoke_swap(get_internal_resource(), that.get_internal_resource());
  853. boost::core::invoke_swap(get_internal_deleter(), that.get_internal_deleter());
  854. boost::core::invoke_swap(m_allocated, that.m_allocated);
  855. }
  856. void swap_impl(unique_resource_data& that, std::true_type, std::false_type)
  857. {
  858. boost::core::invoke_swap(get_internal_deleter(), that.get_internal_deleter());
  859. boost::core::invoke_swap(get_internal_resource(), that.get_internal_resource());
  860. boost::core::invoke_swap(m_allocated, that.m_allocated);
  861. }
  862. void swap_impl(unique_resource_data& that, std::false_type, std::false_type)
  863. {
  864. boost::core::invoke_swap(get_internal_resource(), that.get_internal_resource());
  865. boost::core::invoke_swap(get_internal_deleter(), that.get_internal_deleter());
  866. boost::core::invoke_swap(m_allocated, that.m_allocated);
  867. }
  868. };
  869. template< typename T >
  870. struct is_dereferenceable_impl
  871. {
  872. template< typename U, typename R = decltype(*std::declval< U const& >()) >
  873. static std::true_type _is_dereferenceable_check(int);
  874. template< typename U >
  875. static std::false_type _is_dereferenceable_check(...);
  876. using type = decltype(is_dereferenceable_impl::_is_dereferenceable_check< T >(0));
  877. };
  878. template< typename T >
  879. struct is_dereferenceable : public is_dereferenceable_impl< T >::type { };
  880. template< >
  881. struct is_dereferenceable< void* > : public std::false_type { };
  882. template< >
  883. struct is_dereferenceable< const void* > : public std::false_type { };
  884. template< >
  885. struct is_dereferenceable< volatile void* > : public std::false_type { };
  886. template< >
  887. struct is_dereferenceable< const volatile void* > : public std::false_type { };
  888. template< >
  889. struct is_dereferenceable< void*& > : public std::false_type { };
  890. template< >
  891. struct is_dereferenceable< const void*& > : public std::false_type { };
  892. template< >
  893. struct is_dereferenceable< volatile void*& > : public std::false_type { };
  894. template< >
  895. struct is_dereferenceable< const volatile void*& > : public std::false_type { };
  896. template< >
  897. struct is_dereferenceable< void* const& > : public std::false_type { };
  898. template< >
  899. struct is_dereferenceable< const void* const& > : public std::false_type { };
  900. template< >
  901. struct is_dereferenceable< volatile void* const& > : public std::false_type { };
  902. template< >
  903. struct is_dereferenceable< const volatile void* const& > : public std::false_type { };
  904. template< >
  905. struct is_dereferenceable< void* volatile& > : public std::false_type { };
  906. template< >
  907. struct is_dereferenceable< const void* volatile& > : public std::false_type { };
  908. template< >
  909. struct is_dereferenceable< volatile void* volatile& > : public std::false_type { };
  910. template< >
  911. struct is_dereferenceable< const volatile void* volatile& > : public std::false_type { };
  912. template< >
  913. struct is_dereferenceable< void* const volatile& > : public std::false_type { };
  914. template< >
  915. struct is_dereferenceable< const void* const volatile& > : public std::false_type { };
  916. template< >
  917. struct is_dereferenceable< volatile void* const volatile& > : public std::false_type { };
  918. template< >
  919. struct is_dereferenceable< const volatile void* const volatile& > : public std::false_type { };
  920. template< typename T, bool = detail::is_dereferenceable< T >::value >
  921. struct dereference_traits { };
  922. template< typename T >
  923. struct dereference_traits< T, true >
  924. {
  925. using result_type = decltype(*std::declval< T const& >());
  926. static constexpr bool is_noexcept = noexcept(*std::declval< T const& >());
  927. };
  928. } // namespace detail
  929. /*!
  930. * \brief RAII wrapper for automatically reclaiming arbitrary resources.
  931. *
  932. * A \c unique_resource object exclusively owns wrapped resource and invokes
  933. * the deleter function object on it on destruction. The wrapped resource can have
  934. * any type that is:
  935. *
  936. * \li Move-constructible, where the move constructor is marked as `noexcept`, or
  937. * \li Copy-constructible, or
  938. * \li An lvalue reference to an object type.
  939. *
  940. * The deleter must be a function object type that is callable on an lvalue
  941. * of the resource type. The deleter must be copy-constructible.
  942. *
  943. * An optional resource traits template parameter may be specified. Resource
  944. * traits can be used to optimize \c unique_resource implementation when
  945. * the following conditions are met:
  946. *
  947. * \li There is at least one value of the resource type that is considered
  948. * unallocated (that is, no allocated resource shall be equal to one of
  949. * the unallocated resource values). The unallocated resource values need not
  950. * be deallocated using the deleter.
  951. * \li One of the unallocated resource values can be considered the default.
  952. * Constructing the default resource value and assigning it to a resource
  953. * object (whether allocated or not) shall not throw exceptions.
  954. * \li Resource objects can be tested for being unallocated. Such a test shall
  955. * not throw exceptions.
  956. *
  957. * If specified, the resource traits must be a class type that has the following
  958. * public static members:
  959. *
  960. * \li `R make_default() noexcept` - must return the default resource value such
  961. * that `std::is_constructible< Resource, R >::value &&
  962. * std::is_nothrow_assignable< Resource&, R >::value` is \c true.
  963. * \li `bool is_allocated(Resource const& res) noexcept` - must return \c true
  964. * if \c res is not one of the unallocated resource values and \c false
  965. * otherwise.
  966. *
  967. * Note that `is_allocated(make_default())` must always return \c false.
  968. *
  969. * When resource traits satisfying the above requirements are specified,
  970. * \c unique_resource will be able to avoid storing additional indication of
  971. * whether the owned resource object needs to be deallocated with the deleter
  972. * on destruction. It will use the default resource value to initialize the owned
  973. * resource object when \c unique_resource is not in the allocated state.
  974. * Additionally, it will be possible to construct \c unique_resource with
  975. * unallocated resource values, which will create \c unique_resource objects in
  976. * unallocated state (the deleter will not be called on unallocated resource
  977. * values).
  978. *
  979. * \tparam Resource Resource type.
  980. * \tparam Deleter Resource deleter function object type.
  981. * \tparam Traits Optional resource traits type.
  982. */
  983. template< typename Resource, typename Deleter, typename Traits BOOST_SCOPE_DETAIL_DOC(= void) >
  984. class unique_resource
  985. {
  986. public:
  987. //! Resource type
  988. using resource_type = Resource;
  989. //! Deleter type
  990. using deleter_type = Deleter;
  991. //! Resource traits
  992. using traits_type = Traits;
  993. //! \cond
  994. private:
  995. using data = detail::unique_resource_data< resource_type, deleter_type, traits_type >;
  996. using internal_resource_type = typename data::internal_resource_type;
  997. using internal_deleter_type = typename data::internal_deleter_type;
  998. data m_data;
  999. //! \endcond
  1000. public:
  1001. /*!
  1002. * \brief Constructs an unallocated unique resource guard.
  1003. *
  1004. * **Requires:** Default \c Resource value can be constructed. \c Deleter is default-constructible
  1005. * and is not a pointer to function.
  1006. *
  1007. * **Effects:** Initializes the \c Resource object with the default resource value. Default-constructs
  1008. * the \c Deleter object.
  1009. *
  1010. * **Throws:** Nothing, unless construction of \c Resource or \c Deleter throws.
  1011. *
  1012. * \post `this->allocated() == false`
  1013. */
  1014. //! \cond
  1015. template<
  1016. bool Requires = std::is_default_constructible< data >::value,
  1017. typename = typename std::enable_if< Requires >::type
  1018. >
  1019. //! \endcond
  1020. constexpr unique_resource() noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(std::is_nothrow_default_constructible< data >::value))
  1021. {
  1022. }
  1023. /*!
  1024. * \brief Constructs an unallocated unique resource guard with the given deleter.
  1025. *
  1026. * **Requires:** Default \c Resource value can be constructed and \c Deleter is constructible from \a del.
  1027. *
  1028. * **Effects:** Initializes the \c Resource value with the default resource value. If \c Deleter is nothrow
  1029. * constructible from `D&&` then constructs \c Deleter from `std::forward< D >(del)`,
  1030. * otherwise constructs from `del`.
  1031. *
  1032. * **Throws:** Nothing, unless construction of \c Resource or \c Deleter throws.
  1033. *
  1034. * \param res A tag argument indicating default resource value.
  1035. * \param del Resource deleter function object.
  1036. *
  1037. * \post `this->allocated() == false`
  1038. */
  1039. template<
  1040. typename D
  1041. //! \cond
  1042. , typename = typename std::enable_if<
  1043. std::is_constructible< data, default_resource_t, typename detail::move_or_copy_construct_ref< D, deleter_type >::type >::value
  1044. >::type
  1045. //! \endcond
  1046. >
  1047. unique_resource(default_resource_t res, D&& del)
  1048. noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(
  1049. std::is_nothrow_constructible<
  1050. data,
  1051. default_resource_t,
  1052. typename detail::move_or_copy_construct_ref< D, deleter_type >::type
  1053. >::value
  1054. )) :
  1055. m_data
  1056. (
  1057. res,
  1058. static_cast< typename detail::move_or_copy_construct_ref< D, deleter_type >::type >(del)
  1059. )
  1060. {
  1061. }
  1062. /*!
  1063. * \brief Constructs a unique resource guard with the given resource and a default-constructed deleter.
  1064. *
  1065. * **Requires:** \c Resource is constructible from \a res. \c Deleter is default-constructible and
  1066. * is not a pointer to function.
  1067. *
  1068. * **Effects:** Constructs the unique resource object as if by calling
  1069. * `unique_resource(std::forward< R >(res), Deleter())`.
  1070. *
  1071. * **Throws:** Nothing, unless construction of \c Resource or \c Deleter throws.
  1072. *
  1073. * \param res Resource object.
  1074. */
  1075. template<
  1076. typename R
  1077. //! \cond
  1078. , typename = typename std::enable_if< detail::conjunction<
  1079. detail::is_nothrow_nonnull_default_constructible< deleter_type >,
  1080. std::is_constructible< data, typename detail::move_or_copy_construct_ref< R, resource_type >::type, typename detail::move_or_copy_construct_ref< deleter_type >::type >,
  1081. detail::disjunction< detail::negation< std::is_reference< resource_type > >, std::is_reference< R > > // prevent binding lvalue-reference resource to an rvalue
  1082. >::value >::type
  1083. //! \endcond
  1084. >
  1085. explicit unique_resource(R&& res)
  1086. noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(
  1087. std::is_nothrow_constructible<
  1088. data,
  1089. typename detail::move_or_copy_construct_ref< R, resource_type >::type,
  1090. typename detail::move_or_copy_construct_ref< deleter_type >::type
  1091. >::value
  1092. )) :
  1093. m_data
  1094. (
  1095. static_cast< typename detail::move_or_copy_construct_ref< R, resource_type >::type >(res),
  1096. static_cast< typename detail::move_or_copy_construct_ref< deleter_type >::type >(deleter_type())
  1097. )
  1098. {
  1099. }
  1100. /*!
  1101. * \brief Constructs a unique resource guard with the given resource and deleter.
  1102. *
  1103. * **Requires:** \c Resource is constructible from \a res and \c Deleter is constructible from \a del.
  1104. *
  1105. * **Effects:** If \c Resource is nothrow constructible from `R&&` then constructs \c Resource
  1106. * from `std::forward< R >(res)`, otherwise constructs from `res`. If \c Deleter
  1107. * is nothrow constructible from `D&&` then constructs \c Deleter from
  1108. * `std::forward< D >(del)`, otherwise constructs from `del`.
  1109. *
  1110. * If construction of \c Resource or \c Deleter throws and \a res is not an unallocated resource
  1111. * value, invokes \a del on \a res (if \c Resource construction failed) or the constructed
  1112. * \c Resource object (if \c Deleter construction failed).
  1113. *
  1114. * **Throws:** Nothing, unless construction of \c Resource or \c Deleter throws.
  1115. *
  1116. * \param res Resource object.
  1117. * \param del Resource deleter function object.
  1118. *
  1119. * \post If \a res is an unallocated resource value then `this->allocated() == false`, otherwise
  1120. * `this->allocated() == true`.
  1121. */
  1122. template<
  1123. typename R,
  1124. typename D
  1125. //! \cond
  1126. , typename = typename std::enable_if< detail::conjunction<
  1127. std::is_constructible< data, typename detail::move_or_copy_construct_ref< R, resource_type >::type, typename detail::move_or_copy_construct_ref< D, deleter_type >::type >,
  1128. detail::disjunction< detail::negation< std::is_reference< resource_type > >, std::is_reference< R > > // prevent binding lvalue-reference resource to an rvalue
  1129. >::value >::type
  1130. //! \endcond
  1131. >
  1132. unique_resource(R&& res, D&& del)
  1133. noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(
  1134. std::is_nothrow_constructible<
  1135. data,
  1136. typename detail::move_or_copy_construct_ref< R, resource_type >::type,
  1137. typename detail::move_or_copy_construct_ref< D, deleter_type >::type
  1138. >::value
  1139. )) :
  1140. m_data
  1141. (
  1142. static_cast< typename detail::move_or_copy_construct_ref< R, resource_type >::type >(res),
  1143. static_cast< typename detail::move_or_copy_construct_ref< D, deleter_type >::type >(del)
  1144. )
  1145. {
  1146. }
  1147. unique_resource(unique_resource const&) = delete;
  1148. unique_resource& operator= (unique_resource const&) = delete;
  1149. /*!
  1150. * \brief Move-constructs a unique resource guard.
  1151. *
  1152. * **Requires:** \c Resource and \c Deleter are move-constructible.
  1153. *
  1154. * **Effects:** If \c Resource is nothrow move-constructible then move-constructs \c Resource,
  1155. * otherwise copy-constructs. If \c Deleter is nothrow move-constructible then move-constructs
  1156. * \c Deleter, otherwise copy-constructs. Deactivates the moved-from unique resource object.
  1157. *
  1158. * If an exception is thrown during construction, \a that is left in its original state.
  1159. *
  1160. * \note This logic ensures that in case of exception the resource is not leaked and remains owned by the
  1161. * move source.
  1162. *
  1163. * **Throws:** Nothing, unless construction of \c Resource or \c Deleter throws.
  1164. *
  1165. * \param that Move source.
  1166. *
  1167. * \post Let \c allocated be equal to `that.allocated()` prior to the operation. Then
  1168. * `this->allocated() == allocated` and `that.allocated() == false`.
  1169. */
  1170. //! \cond
  1171. template<
  1172. bool Requires = std::is_move_constructible< data >::value,
  1173. typename = typename std::enable_if< Requires >::type
  1174. >
  1175. //! \endcond
  1176. unique_resource(unique_resource&& that) noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(std::is_nothrow_move_constructible< data >::value)) :
  1177. m_data(static_cast< data&& >(that.m_data))
  1178. {
  1179. }
  1180. /*!
  1181. * \brief Move-assigns a unique resource guard.
  1182. *
  1183. * **Requires:** \c Resource and \c Deleter are move-assignable.
  1184. *
  1185. * **Effects:** Calls `this->reset()`. Then, if \c Deleter is nothrow move-assignable, move-assigns
  1186. * the \c Deleter object first and the \c Resource object next. Otherwise, move-assigns
  1187. * the objects in reverse order. Lastly, deactivates the moved-from unique resource object.
  1188. *
  1189. * If an exception is thrown, \a that is left in its original state.
  1190. *
  1191. * \note The different orders of assignment ensure that in case of exception the resource is not leaked
  1192. * and remains owned by the move source.
  1193. *
  1194. * **Throws:** Nothing, unless assignment of \c Resource or \c Deleter throws.
  1195. *
  1196. * \param that Move source.
  1197. *
  1198. * \post Let \c allocated be equal to `that.allocated()` prior to the operation. Then
  1199. * `this->allocated() == allocated` and `that.allocated() == false`.
  1200. */
  1201. #if !defined(BOOST_SCOPE_DOXYGEN)
  1202. template< bool Requires = std::is_move_assignable< data >::value >
  1203. typename std::enable_if< Requires, unique_resource& >::type
  1204. #else
  1205. unique_resource&
  1206. #endif
  1207. operator= (unique_resource&& that)
  1208. noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(std::is_nothrow_move_assignable< data >::value))
  1209. {
  1210. reset();
  1211. m_data = static_cast< data&& >(that.m_data);
  1212. return *this;
  1213. }
  1214. /*!
  1215. * \brief If the resource is allocated, calls the deleter function on it. Destroys the resource and the deleter.
  1216. *
  1217. * **Throws:** Nothing, unless invoking the deleter throws.
  1218. */
  1219. ~unique_resource() noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(detail::is_nothrow_invocable< deleter_type&, resource_type& >::value))
  1220. {
  1221. if (BOOST_LIKELY(m_data.is_allocated()))
  1222. m_data.get_deleter()(m_data.get_resource());
  1223. }
  1224. /*!
  1225. * \brief Returns \c true if the resource is allocated and to be reclaimed by the deleter, otherwise \c false.
  1226. *
  1227. * \note This method does not test the value of the resource.
  1228. *
  1229. * **Throws:** Nothing.
  1230. */
  1231. explicit operator bool () const noexcept
  1232. {
  1233. return m_data.is_allocated();
  1234. }
  1235. /*!
  1236. * \brief Returns \c true if the resource is allocated and to be reclaimed by the deleter, otherwise \c false.
  1237. *
  1238. * **Throws:** Nothing.
  1239. */
  1240. bool allocated() const noexcept
  1241. {
  1242. return m_data.is_allocated();
  1243. }
  1244. /*!
  1245. * \brief Returns a reference to the resource object.
  1246. *
  1247. * **Throws:** Nothing.
  1248. */
  1249. resource_type const& get() const noexcept
  1250. {
  1251. return m_data.get_resource();
  1252. }
  1253. /*!
  1254. * \brief Returns a reference to the deleter object.
  1255. *
  1256. * **Throws:** Nothing.
  1257. */
  1258. deleter_type const& get_deleter() const noexcept
  1259. {
  1260. return m_data.get_deleter();
  1261. }
  1262. /*!
  1263. * \brief Marks the resource as unallocated. Does not call the deleter if the resource was previously allocated.
  1264. *
  1265. * **Throws:** Nothing.
  1266. *
  1267. * \post `this->allocated() == false`
  1268. */
  1269. void release() noexcept
  1270. {
  1271. m_data.set_unallocated();
  1272. }
  1273. /*!
  1274. * \brief If the resource is allocated, calls the deleter function on it and marks the resource as unallocated.
  1275. *
  1276. * **Throws:** Nothing, unless invoking the deleter throws.
  1277. *
  1278. * \post `this->allocated() == false`
  1279. */
  1280. void reset() noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(detail::is_nothrow_invocable< deleter_type&, resource_type& >::value))
  1281. {
  1282. if (BOOST_LIKELY(m_data.is_allocated()))
  1283. {
  1284. m_data.get_deleter()(m_data.get_resource());
  1285. m_data.set_unallocated();
  1286. }
  1287. }
  1288. /*!
  1289. * \brief Assigns a new resource object to the unique resource wrapper.
  1290. *
  1291. * **Effects:** Calls `this->reset()`. Then, if \c Resource is nothrow assignable from `R&&`,
  1292. * assigns `std::forward< R >(res)` to the stored resource object, otherwise assigns
  1293. * `res`.
  1294. *
  1295. * If \a res is not an unallocated resource value and an exception is thrown during the operation,
  1296. * invokes the stored deleter on \a res before returning with the exception.
  1297. *
  1298. * **Throws:** Nothing, unless invoking the deleter throws.
  1299. *
  1300. * \param res Resource object to assign.
  1301. *
  1302. * \post `this->allocated() == false`
  1303. */
  1304. template< typename R >
  1305. #if !defined(BOOST_SCOPE_DOXYGEN)
  1306. typename std::enable_if< detail::conjunction<
  1307. std::is_assignable< internal_resource_type&, typename detail::move_or_copy_assign_ref< R, resource_type >::type >,
  1308. detail::disjunction< detail::negation< std::is_reference< resource_type > >, std::is_reference< R > > // prevent binding lvalue-reference resource to an rvalue
  1309. >::value >::type
  1310. #else
  1311. void
  1312. #endif
  1313. reset(R&& res)
  1314. noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(
  1315. detail::conjunction<
  1316. detail::is_nothrow_invocable< deleter_type&, resource_type& >,
  1317. std::is_nothrow_assignable< internal_resource_type&, typename detail::move_or_copy_assign_ref< R, resource_type >::type >
  1318. >::value
  1319. ))
  1320. {
  1321. reset_impl
  1322. (
  1323. static_cast< R&& >(res),
  1324. typename detail::conjunction<
  1325. detail::is_nothrow_invocable< deleter_type&, resource_type& >,
  1326. std::is_nothrow_assignable< internal_resource_type&, typename detail::move_or_copy_assign_ref< R, resource_type >::type >
  1327. >::type()
  1328. );
  1329. }
  1330. /*!
  1331. * \brief Invokes indirection on the resource object.
  1332. *
  1333. * **Requires:** \c Resource is dereferenceable.
  1334. *
  1335. * **Effects:** Returns a reference to the resource object as if by calling `get()`.
  1336. *
  1337. * \note If \c Resource is not a pointer type, the compiler will invoke its `operator->`.
  1338. * Such call sequence will continue until a pointer is obtained.
  1339. *
  1340. * **Throws:** Nothing. Note that any implicit subsequent calls to other `operator->`
  1341. * functions that are caused by this call may have different throw conditions.
  1342. */
  1343. #if !defined(BOOST_SCOPE_DOXYGEN)
  1344. template< bool Requires = detail::is_dereferenceable< resource_type >::value >
  1345. typename std::enable_if< Requires, resource_type const& >::type
  1346. #else
  1347. resource_type const&
  1348. #endif
  1349. operator-> () const noexcept
  1350. {
  1351. return get();
  1352. }
  1353. /*!
  1354. * \brief Dereferences the resource object.
  1355. *
  1356. * **Requires:** \c Resource is dereferenceable.
  1357. *
  1358. * **Effects:** Returns the result of dereferencing the resource object as if by calling `*get()`.
  1359. *
  1360. * **Throws:** Nothing, unless dereferencing the resource object throws.
  1361. */
  1362. #if !defined(BOOST_SCOPE_DOXYGEN)
  1363. template< bool Requires = detail::is_dereferenceable< resource_type >::value >
  1364. typename detail::dereference_traits< resource_type, Requires >::result_type
  1365. #else
  1366. auto
  1367. #endif
  1368. operator* () const
  1369. noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(detail::dereference_traits< resource_type, Requires >::is_noexcept))
  1370. {
  1371. return *get();
  1372. }
  1373. /*!
  1374. * \brief Swaps two unique resource wrappers.
  1375. *
  1376. * **Requires:** \c Resource and \c Deleter are swappable. At least one of \c Resource and \c Deleter
  1377. * is nothrow swappable.
  1378. *
  1379. * **Effects:** Swaps the resource objects and deleter objects stored in `*this` and \a that
  1380. * as if by calling unqualified `swap` in a context where `std::swap` is
  1381. * found by overload resolution.
  1382. *
  1383. * If an exception is thrown, and the failed swap operation supports strong exception
  1384. * guarantee, both `*this` and \a that are left in their original states.
  1385. *
  1386. * **Throws:** Nothing, unless swapping the resource objects or deleters throw.
  1387. *
  1388. * \param that Unique resource wrapper to swap with.
  1389. */
  1390. #if !defined(BOOST_SCOPE_DOXYGEN)
  1391. template< bool Requires = detail::is_swappable< data >::value >
  1392. typename std::enable_if< Requires >::type
  1393. #else
  1394. void
  1395. #endif
  1396. swap(unique_resource& that)
  1397. noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(detail::is_nothrow_swappable< data >::value))
  1398. {
  1399. m_data.swap(that.m_data);
  1400. }
  1401. /*!
  1402. * \brief Swaps two unique resource wrappers.
  1403. *
  1404. * **Effects:** As if `left.swap(right)`.
  1405. */
  1406. #if !defined(BOOST_SCOPE_DOXYGEN)
  1407. template< bool Requires = detail::is_swappable< data >::value >
  1408. friend typename std::enable_if< Requires >::type
  1409. #else
  1410. friend void
  1411. #endif
  1412. swap(unique_resource& left, unique_resource& right)
  1413. noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(detail::is_nothrow_swappable< data >::value))
  1414. {
  1415. left.swap(right);
  1416. }
  1417. //! \cond
  1418. private:
  1419. //! Assigns a new resource object to the unique resource wrapper.
  1420. template< typename R >
  1421. void reset_impl(R&& res, std::true_type) noexcept
  1422. {
  1423. reset();
  1424. m_data.assign_resource(static_cast< typename detail::move_or_copy_assign_ref< R, resource_type >::type >(res));
  1425. }
  1426. //! Assigns a new resource object to the unique resource wrapper.
  1427. template< typename R >
  1428. void reset_impl(R&& res, std::false_type)
  1429. {
  1430. try
  1431. {
  1432. reset();
  1433. m_data.assign_resource(static_cast< typename detail::move_or_copy_assign_ref< R, resource_type >::type >(res));
  1434. }
  1435. catch (...)
  1436. {
  1437. m_data.get_deleter()(static_cast< R&& >(res));
  1438. throw;
  1439. }
  1440. }
  1441. //! \endcond
  1442. };
  1443. #if !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES)
  1444. template<
  1445. typename Resource,
  1446. typename Deleter,
  1447. typename = typename std::enable_if< !detail::is_default_resource< Resource >::value >::type
  1448. >
  1449. unique_resource(Resource, Deleter) -> unique_resource< Resource, Deleter >;
  1450. #endif // !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES)
  1451. /*!
  1452. * \brief Checks if the resource is valid and creates a \c unique_resource wrapper.
  1453. *
  1454. * **Effects:** If the resource \a res is not equal to \a invalid, creates a unique resource wrapper
  1455. * that is in allocated state and owns \a res. Otherwise creates a unique resource wrapper
  1456. * in unallocated state.
  1457. *
  1458. * \note This function does not call \a del if \a res is equal to \a invalid.
  1459. *
  1460. * **Throws:** Nothing, unless \c unique_resource constructor throws.
  1461. *
  1462. * \param res Resource to wrap.
  1463. * \param invalid An invalid value for the resource.
  1464. * \param del A deleter to invoke on the resource to free it.
  1465. */
  1466. template< typename Resource, typename Deleter, typename Invalid >
  1467. inline unique_resource< typename std::decay< Resource >::type, typename std::decay< Deleter >::type >
  1468. make_unique_resource_checked(Resource&& res, Invalid const& invalid, Deleter&& del)
  1469. noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(
  1470. detail::conjunction<
  1471. std::is_nothrow_constructible< typename std::decay< Resource >::type, typename detail::move_or_copy_construct_ref< Resource, typename std::decay< Resource >::type >::type >,
  1472. std::is_nothrow_constructible< typename std::decay< Deleter >::type, typename detail::move_or_copy_construct_ref< Deleter, typename std::decay< Deleter >::type >::type >
  1473. >::value
  1474. ))
  1475. {
  1476. using unique_resource_type = unique_resource< typename std::decay< Resource >::type, typename std::decay< Deleter >::type >;
  1477. if (!(res == invalid))
  1478. return unique_resource_type(static_cast< Resource&& >(res), static_cast< Deleter&& >(del));
  1479. else
  1480. return unique_resource_type(default_resource_t(), static_cast< Deleter&& >(del));
  1481. }
  1482. } // namespace scope
  1483. } // namespace boost
  1484. #include <boost/scope/detail/footer.hpp>
  1485. #endif // BOOST_SCOPE_UNIQUE_RESOURCE_HPP_INCLUDED_