unique_resource.hpp 64 KB

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