Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-04-19 08:44:22

0001 /*
0002  * Distributed under the Boost Software License, Version 1.0.
0003  * (See accompanying file LICENSE_1_0.txt or copy at
0004  * https://www.boost.org/LICENSE_1_0.txt)
0005  *
0006  * Copyright (c) 2022-2024 Andrey Semashev
0007  */
0008 /*!
0009  * \file scope/unique_resource.hpp
0010  *
0011  * This header contains definition of \c unique_resource template.
0012  */
0013 
0014 #ifndef BOOST_SCOPE_UNIQUE_RESOURCE_HPP_INCLUDED_
0015 #define BOOST_SCOPE_UNIQUE_RESOURCE_HPP_INCLUDED_
0016 
0017 #include <new> // for placement new
0018 #include <type_traits>
0019 #include <boost/core/addressof.hpp>
0020 #include <boost/core/invoke_swap.hpp>
0021 #include <boost/scope/unique_resource_fwd.hpp>
0022 #include <boost/scope/detail/config.hpp>
0023 #include <boost/scope/detail/compact_storage.hpp>
0024 #include <boost/scope/detail/move_or_copy_assign_ref.hpp>
0025 #include <boost/scope/detail/move_or_copy_construct_ref.hpp>
0026 #include <boost/scope/detail/is_nonnull_default_constructible.hpp>
0027 #include <boost/scope/detail/type_traits/is_swappable.hpp>
0028 #include <boost/scope/detail/type_traits/is_nothrow_swappable.hpp>
0029 #include <boost/scope/detail/type_traits/is_nothrow_invocable.hpp>
0030 #include <boost/scope/detail/type_traits/negation.hpp>
0031 #include <boost/scope/detail/type_traits/conjunction.hpp>
0032 #include <boost/scope/detail/type_traits/disjunction.hpp>
0033 #include <boost/scope/detail/header.hpp>
0034 
0035 #ifdef BOOST_HAS_PRAGMA_ONCE
0036 #pragma once
0037 #endif
0038 
0039 namespace boost {
0040 namespace scope {
0041 
0042 #if !defined(BOOST_NO_CXX17_FOLD_EXPRESSIONS) && !defined(BOOST_NO_CXX17_AUTO_NONTYPE_TEMPLATE_PARAMS)
0043 
0044 /*!
0045  * \brief Simple resource traits for one or more unallocated resource values.
0046  *
0047  * This class template generates resource traits for `unique_resource` that specify
0048  * one or more unallocated resource values. The first value, specified in the \c DefaultValue
0049  * non-type template parameter, is considered the default. The other values, listed in
0050  * \c UnallocatedValues, are optional. Any resource values other than \c DefaultValue
0051  * or listed in \c UnallocatedValues are considered as allocated.
0052  *
0053  * In order for the generated resource traits to enable optimized implementation of
0054  * `unique_resource`, the resource type must support non-throwing construction and assignment
0055  * from, and comparison for (in)equality with \c DefaultValue or any of the resource
0056  * values listed in \c UnallocatedValues.
0057  */
0058 template< auto DefaultValue, auto... UnallocatedValues >
0059 struct unallocated_resource
0060 {
0061     //! Returns the default resource value
0062     static decltype(DefaultValue) make_default() noexcept
0063     {
0064         return DefaultValue;
0065     }
0066 
0067     //! Tests if \a res is an allocated resource value
0068     template< typename Resource >
0069     static bool is_allocated(Resource const& res) noexcept
0070     {
0071         static_assert(noexcept(res != DefaultValue && (... && (res != UnallocatedValues))),
0072             "Invalid unallocated resource value types: comparing resource values with the unallocated values must be noexcept");
0073         return res != DefaultValue && (... && (res != UnallocatedValues));
0074     }
0075 };
0076 
0077 #endif // !defined(BOOST_NO_CXX17_FOLD_EXPRESSIONS) && !defined(BOOST_NO_CXX17_AUTO_NONTYPE_TEMPLATE_PARAMS)
0078 
0079 struct default_resource_t { };
0080 
0081 //! Keyword representing default, unallocated resource argument
0082 BOOST_INLINE_VARIABLE constexpr default_resource_t default_resource = { };
0083 
0084 namespace detail {
0085 
0086 // The type trait indicates whether \c T is a possibly qualified \c default_resource_t type
0087 template< typename T >
0088 struct is_default_resource : public std::false_type { };
0089 template< >
0090 struct is_default_resource< default_resource_t > : public std::true_type { };
0091 template< >
0092 struct is_default_resource< const default_resource_t > : public std::true_type { };
0093 template< >
0094 struct is_default_resource< volatile default_resource_t > : public std::true_type { };
0095 template< >
0096 struct is_default_resource< const volatile default_resource_t > : public std::true_type { };
0097 template< typename T >
0098 struct is_default_resource< T& > : public is_default_resource< T >::type { };
0099 
0100 // Lightweight reference wrapper
0101 template< typename T >
0102 class ref_wrapper
0103 {
0104 private:
0105     T* m_value;
0106 
0107 public:
0108     explicit
0109 #if !defined(BOOST_CORE_NO_CONSTEXPR_ADDRESSOF)
0110     constexpr
0111 #endif
0112     ref_wrapper(T& value) noexcept :
0113         m_value(boost::addressof(value))
0114     {
0115     }
0116 
0117     ref_wrapper& operator= (T& value) noexcept
0118     {
0119         m_value = boost::addressof(value);
0120         return *this;
0121     }
0122 
0123     ref_wrapper(T&&) = delete;
0124     ref_wrapper& operator= (T&&) = delete;
0125 
0126     operator T& () const noexcept
0127     {
0128         return *m_value;
0129     }
0130 
0131     template< typename... Args >
0132     void operator() (Args&&... args) const noexcept(detail::is_nothrow_invocable< T&, Args&&... >::value)
0133     {
0134         (*m_value)(static_cast< Args&& >(args)...);
0135     }
0136 };
0137 
0138 template< typename T >
0139 struct wrap_reference
0140 {
0141     using type = T;
0142 };
0143 
0144 template< typename T >
0145 struct wrap_reference< T& >
0146 {
0147     using type = ref_wrapper< T >;
0148 };
0149 
0150 template< typename Resource, bool UseCompactStorage >
0151 class resource_holder :
0152     public detail::compact_storage< typename wrap_reference< Resource >::type >
0153 {
0154 public:
0155     using resource_type = Resource;
0156     using internal_resource_type = typename wrap_reference< resource_type >::type;
0157 
0158 private:
0159     using resource_base = detail::compact_storage< internal_resource_type >;
0160 
0161 public:
0162     template<
0163         bool Requires = std::is_default_constructible< internal_resource_type >::value,
0164         typename = typename std::enable_if< Requires >::type
0165     >
0166     constexpr resource_holder() noexcept(std::is_nothrow_default_constructible< internal_resource_type >::value) :
0167         resource_base()
0168     {
0169     }
0170 
0171     template<
0172         typename R,
0173         typename = typename std::enable_if< std::is_constructible< internal_resource_type, R >::value >::type
0174     >
0175     explicit resource_holder(R&& res) noexcept(std::is_nothrow_constructible< internal_resource_type, R >::value) :
0176         resource_base(static_cast< R&& >(res))
0177     {
0178     }
0179 
0180     template<
0181         typename R,
0182         typename D,
0183         typename = typename std::enable_if< std::is_constructible< internal_resource_type, R >::value >::type
0184     >
0185     explicit resource_holder(R&& res, D&& del, bool allocated) noexcept(std::is_nothrow_constructible< internal_resource_type, R >::value) :
0186         resource_holder(static_cast< R&& >(res), static_cast< D&& >(del), allocated, typename std::is_nothrow_constructible< resource_type, R >::type())
0187     {
0188     }
0189 
0190     resource_type& get() noexcept
0191     {
0192         return resource_base::get();
0193     }
0194 
0195     resource_type const& get() const noexcept
0196     {
0197         return resource_base::get();
0198     }
0199 
0200     internal_resource_type& get_internal() noexcept
0201     {
0202         return resource_base::get();
0203     }
0204 
0205     internal_resource_type const& get_internal() const noexcept
0206     {
0207         return resource_base::get();
0208     }
0209 
0210     void move_from(internal_resource_type&& that) noexcept(std::is_nothrow_move_assignable< internal_resource_type >::value)
0211     {
0212         resource_base::get() = static_cast< internal_resource_type&& >(that);
0213     }
0214 
0215 private:
0216     template< typename R, typename D >
0217     explicit resource_holder(R&& res, D&& del, bool allocated, std::true_type) noexcept :
0218         resource_base(static_cast< R&& >(res))
0219     {
0220     }
0221 
0222     template< typename R, typename D >
0223     explicit resource_holder(R&& res, D&& del, bool allocated, std::false_type) try :
0224         resource_base(res)
0225     {
0226     }
0227     catch (...)
0228     {
0229         if (allocated)
0230             del(res);
0231     }
0232 };
0233 
0234 template< typename Resource >
0235 class resource_holder< Resource, false >
0236 {
0237 public:
0238     using resource_type = Resource;
0239     using internal_resource_type = typename wrap_reference< resource_type >::type;
0240 
0241 private:
0242     // Note: Not using compact_storage since we will need to reuse storage for this complete object in move_from
0243     internal_resource_type m_resource;
0244 
0245 public:
0246     template<
0247         bool Requires = std::is_default_constructible< internal_resource_type >::value,
0248         typename = typename std::enable_if< Requires >::type
0249     >
0250     constexpr resource_holder() noexcept(std::is_nothrow_default_constructible< internal_resource_type >::value) :
0251         m_resource()
0252     {
0253     }
0254 
0255     template<
0256         typename R,
0257         typename = typename std::enable_if< std::is_constructible< internal_resource_type, R >::value >::type
0258     >
0259     explicit resource_holder(R&& res) noexcept(std::is_nothrow_constructible< internal_resource_type, R >::value) :
0260         m_resource(static_cast< R&& >(res))
0261     {
0262     }
0263 
0264     template<
0265         typename R,
0266         typename D,
0267         typename = typename std::enable_if< std::is_constructible< internal_resource_type, R >::value >::type
0268     >
0269     explicit resource_holder(R&& res, D&& del, bool allocated) noexcept(std::is_nothrow_constructible< internal_resource_type, R >::value) :
0270         resource_holder(static_cast< R&& >(res), static_cast< D&& >(del), allocated, typename std::is_nothrow_constructible< resource_type, R >::type())
0271     {
0272     }
0273 
0274     resource_type& get() noexcept
0275     {
0276         return m_resource;
0277     }
0278 
0279     resource_type const& get() const noexcept
0280     {
0281         return m_resource;
0282     }
0283 
0284     internal_resource_type& get_internal() noexcept
0285     {
0286         return m_resource;
0287     }
0288 
0289     internal_resource_type const& get_internal() const noexcept
0290     {
0291         return m_resource;
0292     }
0293 
0294     void move_from(internal_resource_type&& that)
0295         noexcept(std::is_nothrow_constructible< internal_resource_type, typename detail::move_or_copy_construct_ref< resource_type >::type >::value)
0296     {
0297         internal_resource_type* p = boost::addressof(m_resource);
0298         p->~internal_resource_type();
0299         new (p) internal_resource_type(static_cast< typename detail::move_or_copy_construct_ref< resource_type >::type >(that));
0300     }
0301 
0302 private:
0303     template< typename R, typename D >
0304     explicit resource_holder(R&& res, D&& del, bool allocated, std::true_type) noexcept :
0305         m_resource(static_cast< R&& >(res))
0306     {
0307     }
0308 
0309     template< typename R, typename D >
0310     explicit resource_holder(R&& res, D&& del, bool allocated, std::false_type) try :
0311         m_resource(res)
0312     {
0313     }
0314     catch (...)
0315     {
0316         if (allocated)
0317             del(res);
0318     }
0319 };
0320 
0321 template< typename Resource, typename Deleter >
0322 class deleter_holder :
0323     public detail::compact_storage< typename wrap_reference< Deleter >::type >
0324 {
0325 public:
0326     using resource_type = Resource;
0327     using deleter_type = Deleter;
0328     using internal_deleter_type = typename wrap_reference< deleter_type >::type;
0329 
0330 private:
0331     using deleter_base = detail::compact_storage< internal_deleter_type >;
0332 
0333 public:
0334     template<
0335         bool Requires = detail::is_nonnull_default_constructible< internal_deleter_type >::value,
0336         typename = typename std::enable_if< Requires >::type
0337     >
0338     constexpr deleter_holder() noexcept(detail::is_nothrow_nonnull_default_constructible< internal_deleter_type >::value) :
0339         deleter_base()
0340     {
0341     }
0342 
0343     template<
0344         typename D,
0345         typename = typename std::enable_if< std::is_constructible< internal_deleter_type, D >::value >::type
0346     >
0347     explicit deleter_holder(D&& del) noexcept(std::is_nothrow_constructible< internal_deleter_type, D >::value) :
0348         deleter_base(static_cast< D&& >(del))
0349     {
0350     }
0351 
0352     template<
0353         typename D,
0354         typename = typename std::enable_if< std::is_constructible< internal_deleter_type, D >::value >::type
0355     >
0356     explicit deleter_holder(D&& del, resource_type& res, bool allocated) noexcept(std::is_nothrow_constructible< internal_deleter_type, D >::value) :
0357         deleter_holder(static_cast< D&& >(del), res, allocated, typename std::is_nothrow_constructible< internal_deleter_type, D >::type())
0358     {
0359     }
0360 
0361     deleter_type& get() noexcept
0362     {
0363         return deleter_base::get();
0364     }
0365 
0366     deleter_type const& get() const noexcept
0367     {
0368         return deleter_base::get();
0369     }
0370 
0371     internal_deleter_type& get_internal() noexcept
0372     {
0373         return deleter_base::get();
0374     }
0375 
0376     internal_deleter_type const& get_internal() const noexcept
0377     {
0378         return deleter_base::get();
0379     }
0380 
0381 private:
0382     template< typename D >
0383     explicit deleter_holder(D&& del, resource_type& res, bool allocated, std::true_type) noexcept :
0384         deleter_base(static_cast< D&& >(del))
0385     {
0386     }
0387 
0388     template< typename D >
0389     explicit deleter_holder(D&& del, resource_type& res, bool allocated, std::false_type) try :
0390         deleter_base(del)
0391     {
0392     }
0393     catch (...)
0394     {
0395         if (BOOST_LIKELY(allocated))
0396             del(res);
0397     }
0398 };
0399 
0400 /*
0401  * This metafunction indicates whether \c resource_holder should use \c compact_storage
0402  * to optimize storage for the resource object. Its definition must be coherent with
0403  * `resource_holder::move_from` definition and move constructor implementation in
0404  * \c unique_resource_data.
0405  *
0406  * There is one tricky case with \c unique_resource move constructor, when the resource move
0407  * constructor is noexcept and deleter's move and copy constructors are not. It is possible
0408  * that \c unique_resource_data move constructor moves the resource into the object being
0409  * constructed but fails to construct the deleter. In this case we want to move the resource
0410  * back to the original \c unique_resource_data object (which is guaranteed to not throw since
0411  * the resource's move constructor is non-throwing).
0412  *
0413  * However, if we use the move constructor to move the resource back, we need to use placement
0414  * new, and this only lets us create a complete object of the resource type, which prohibits
0415  * the use of \c compact_storage, as it may create the resource object as a base subobject of
0416  * \c compact_storage. Using placement new on a base subobject may corrupt data that is placed
0417  * in the trailing padding bits of the resource type.
0418  *
0419  * To work around this limitation, we also test if move assignment of the resource type is
0420  * also non-throwing (which is reasonable to expect, given that the move constructor is
0421  * non-throwing). If it is, we can avoid having to destroy and move-construct the resource and
0422  * use move-assignment instead. This doesn't require a complete object of the resource type
0423  * and allows us to use \c compact_storage. If move assignment is not noexcept then we have
0424  * to use the move constructor and disable the \c compact_storage optimization.
0425  *
0426  * So this trait has to detect (a) whether we are affected by this tricky case of the
0427  * \c unique_resource move constructor in the first place and (b) whether we can use move
0428  * assignment to move the resource back to the original \c unique_resource object. If we're
0429  * not affected or we can use move assignment then we enable \c compact_storage.
0430  */
0431 template< typename Resource, typename Deleter >
0432 using use_resource_compact_storage = detail::disjunction<
0433     std::is_nothrow_move_assignable< typename wrap_reference< Resource >::type >,
0434     std::is_nothrow_constructible< typename wrap_reference< Deleter >::type, typename detail::move_or_copy_construct_ref< Deleter >::type >,
0435     detail::negation< std::is_nothrow_constructible< typename wrap_reference< Resource >::type, typename detail::move_or_copy_construct_ref< Resource >::type > >
0436 >;
0437 
0438 template< typename Resource, typename Deleter, typename Traits >
0439 class unique_resource_data :
0440     public detail::resource_holder< Resource, use_resource_compact_storage< Resource, Deleter >::value >,
0441     public detail::deleter_holder< Resource, Deleter >
0442 {
0443 public:
0444     using resource_type = Resource;
0445     using deleter_type = Deleter;
0446     using traits_type = Traits;
0447 
0448 private:
0449     using resource_holder = detail::resource_holder< resource_type, use_resource_compact_storage< resource_type, deleter_type >::value >;
0450     using deleter_holder = detail::deleter_holder< resource_type, deleter_type >;
0451     using result_of_make_default = decltype(traits_type::make_default());
0452 
0453 public:
0454     using internal_resource_type = typename resource_holder::internal_resource_type;
0455     using internal_deleter_type = typename deleter_holder::internal_deleter_type;
0456 
0457     static_assert(noexcept(traits_type::make_default()), "Invalid unique_resource resource traits: make_default must be noexcept");
0458     static_assert(std::is_nothrow_assignable< internal_resource_type&, result_of_make_default >::value,
0459         "Invalid unique_resource resource traits: resource must be nothrow-assignable from the result of make_default");
0460     static_assert(noexcept(traits_type::is_allocated(std::declval< resource_type const& >())), "Invalid unique_resource resource traits: is_allocated must be noexcept");
0461 
0462 public:
0463     template<
0464         bool Requires = detail::conjunction<
0465             std::is_constructible< resource_holder, result_of_make_default >,
0466             std::is_default_constructible< deleter_holder >
0467         >::value,
0468         typename = typename std::enable_if< Requires >::type
0469     >
0470     constexpr unique_resource_data()
0471         noexcept(detail::conjunction<
0472             std::is_nothrow_constructible< resource_holder, result_of_make_default >,
0473             std::is_nothrow_default_constructible< deleter_holder >
0474         >::value) :
0475         resource_holder(traits_type::make_default()),
0476         deleter_holder()
0477     {
0478     }
0479 
0480     unique_resource_data(unique_resource_data const&) = delete;
0481     unique_resource_data& operator= (unique_resource_data const&) = delete;
0482 
0483     unique_resource_data(unique_resource_data&& that)
0484         noexcept(detail::conjunction<
0485             std::is_nothrow_constructible< internal_resource_type, typename detail::move_or_copy_construct_ref< resource_type >::type >,
0486             std::is_nothrow_constructible< internal_deleter_type, typename detail::move_or_copy_construct_ref< deleter_type >::type >
0487         >::value) :
0488         unique_resource_data
0489         (
0490             static_cast< unique_resource_data&& >(that),
0491             typename std::is_nothrow_constructible< internal_resource_type, typename detail::move_or_copy_construct_ref< resource_type >::type >::type(),
0492             typename std::is_nothrow_constructible< internal_deleter_type, typename detail::move_or_copy_construct_ref< deleter_type >::type >::type()
0493         )
0494     {
0495     }
0496 
0497     template<
0498         typename D,
0499         typename = typename std::enable_if< detail::conjunction<
0500             std::is_constructible< resource_holder, result_of_make_default >,
0501             std::is_constructible< deleter_holder, D >
0502         >::value >::type
0503     >
0504     explicit unique_resource_data(default_resource_t, D&& del)
0505         noexcept(detail::conjunction<
0506             std::is_nothrow_constructible< resource_holder, result_of_make_default >,
0507             std::is_nothrow_constructible< deleter_holder, D >
0508         >::value) :
0509         resource_holder(traits_type::make_default()),
0510         deleter_holder(static_cast< D&& >(del))
0511     {
0512     }
0513 
0514     template<
0515         typename R,
0516         typename D,
0517         typename = typename std::enable_if< detail::conjunction<
0518             detail::negation< detail::is_default_resource< R > >,
0519             std::is_constructible< resource_holder, R, D, bool >,
0520             std::is_constructible< deleter_holder, D, resource_type&, bool >
0521         >::value >::type
0522     >
0523     explicit unique_resource_data(R&& res, D&& del)
0524         noexcept(detail::conjunction<
0525             std::is_nothrow_constructible< resource_holder, R, D, bool >,
0526             std::is_nothrow_constructible< deleter_holder, D, resource_type&, bool >
0527         >::value) :
0528         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
0529     {
0530         // 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.
0531         // We still require it to be noexcept, as we need to know whether we should deallocate it. Otherwise we may leak the resource.
0532         static_assert(noexcept(traits_type::is_allocated(res)), "Invalid unique_resource resource traits: is_allocated must be noexcept");
0533     }
0534 
0535     template<
0536         bool Requires = detail::conjunction<
0537             std::is_assignable< internal_resource_type&, typename detail::move_or_copy_assign_ref< resource_type >::type >,
0538             std::is_assignable< internal_deleter_type&, typename detail::move_or_copy_assign_ref< deleter_type >::type >
0539         >::value
0540     >
0541     typename std::enable_if< Requires, unique_resource_data& >::type operator= (unique_resource_data&& that)
0542         noexcept(detail::conjunction<
0543             std::is_nothrow_assignable< internal_resource_type&, typename detail::move_or_copy_assign_ref< resource_type >::type >,
0544             std::is_nothrow_assignable< internal_deleter_type&, typename detail::move_or_copy_assign_ref< deleter_type >::type >
0545         >::value)
0546     {
0547         assign(static_cast< unique_resource_data&& >(that), typename std::is_nothrow_move_assignable< internal_deleter_type >::type());
0548         return *this;
0549     }
0550 
0551     resource_type& get_resource() noexcept
0552     {
0553         return resource_holder::get();
0554     }
0555 
0556     resource_type const& get_resource() const noexcept
0557     {
0558         return resource_holder::get();
0559     }
0560 
0561     internal_resource_type& get_internal_resource() noexcept
0562     {
0563         return resource_holder::get_internal();
0564     }
0565 
0566     internal_resource_type const& get_internal_resource() const noexcept
0567     {
0568         return resource_holder::get_internal();
0569     }
0570 
0571     deleter_type& get_deleter() noexcept
0572     {
0573         return deleter_holder::get();
0574     }
0575 
0576     deleter_type const& get_deleter() const noexcept
0577     {
0578         return deleter_holder::get();
0579     }
0580 
0581     internal_deleter_type& get_internal_deleter() noexcept
0582     {
0583         return deleter_holder::get_internal();
0584     }
0585 
0586     internal_deleter_type const& get_internal_deleter() const noexcept
0587     {
0588         return deleter_holder::get_internal();
0589     }
0590 
0591     bool is_allocated() const noexcept
0592     {
0593         return traits_type::is_allocated(get_resource());
0594     }
0595 
0596     void set_unallocated() noexcept
0597     {
0598         get_internal_resource() = traits_type::make_default();
0599     }
0600 
0601     template< typename R >
0602     void assign_resource(R&& res) noexcept(std::is_nothrow_assignable< internal_resource_type&, R >::value)
0603     {
0604         get_internal_resource() = static_cast< R&& >(res);
0605     }
0606 
0607     template<
0608         bool Requires = detail::conjunction<
0609             detail::is_swappable< internal_resource_type >,
0610             detail::is_swappable< internal_deleter_type >,
0611             detail::disjunction<
0612                 detail::is_nothrow_swappable< internal_resource_type >,
0613                 detail::is_nothrow_swappable< internal_deleter_type >
0614             >
0615         >::value
0616     >
0617     typename std::enable_if< Requires >::type swap(unique_resource_data& that)
0618         noexcept(detail::conjunction< detail::is_nothrow_swappable< internal_resource_type >, detail::is_nothrow_swappable< internal_deleter_type > >::value)
0619     {
0620         swap_impl
0621         (
0622             that,
0623             std::integral_constant< bool, detail::is_nothrow_swappable< internal_resource_type >::value >(),
0624             std::integral_constant< bool, detail::conjunction<
0625                 detail::is_nothrow_swappable< internal_resource_type >,
0626                 detail::is_nothrow_swappable< internal_deleter_type >
0627             >::value >()
0628         );
0629     }
0630 
0631 private:
0632     unique_resource_data(unique_resource_data&& that, std::true_type, std::true_type) noexcept :
0633         resource_holder(static_cast< typename detail::move_or_copy_construct_ref< resource_type >::type >(that.get_resource())),
0634         deleter_holder(static_cast< typename detail::move_or_copy_construct_ref< deleter_type >::type >(that.get_deleter()))
0635     {
0636         that.set_unallocated();
0637     }
0638 
0639     unique_resource_data(unique_resource_data&& that, std::false_type, std::true_type) :
0640         resource_holder(static_cast< resource_type const& >(that.get_resource())),
0641         deleter_holder(static_cast< typename detail::move_or_copy_construct_ref< deleter_type >::type >(that.get_deleter()))
0642     {
0643         that.set_unallocated();
0644     }
0645 
0646     unique_resource_data(unique_resource_data&& that, std::true_type, std::false_type) try :
0647         resource_holder(static_cast< typename detail::move_or_copy_construct_ref< resource_type >::type >(that.get_resource())),
0648         deleter_holder(static_cast< deleter_type const& >(that.get_deleter()))
0649     {
0650         that.set_unallocated();
0651     }
0652     catch (...)
0653     {
0654         // Since only the deleter's constructor could have thrown an exception here, move the resource back
0655         // to the original unique_resource. This is guaranteed to not throw.
0656         that.resource_holder::move_from(static_cast< internal_resource_type&& >(resource_holder::get_internal()));
0657     }
0658 
0659     unique_resource_data(unique_resource_data&& that, std::false_type, std::false_type) :
0660         resource_holder(static_cast< resource_type const& >(that.get_resource())),
0661         deleter_holder(static_cast< deleter_type const& >(that.get_deleter()))
0662     {
0663         that.set_unallocated();
0664     }
0665 
0666     template<
0667         typename R,
0668         typename D,
0669         typename = typename std::enable_if< detail::conjunction<
0670             std::is_constructible< resource_holder, R, D, bool >,
0671             std::is_constructible< deleter_holder, D, resource_type&, bool >
0672         >::value >::type
0673     >
0674     explicit unique_resource_data(R&& res, D&& del, bool allocated)
0675         noexcept(detail::conjunction<
0676             std::is_nothrow_constructible< resource_holder, R, D, bool >,
0677             std::is_nothrow_constructible< deleter_holder, D, resource_type&, bool >
0678         >::value) :
0679         resource_holder(static_cast< R&& >(res), static_cast< D&& >(del), allocated),
0680         deleter_holder(static_cast< D&& >(del), resource_holder::get(), allocated)
0681     {
0682     }
0683 
0684     void assign(unique_resource_data&& that, std::true_type)
0685         noexcept(std::is_nothrow_assignable< internal_resource_type&, typename detail::move_or_copy_assign_ref< resource_type >::type >::value)
0686     {
0687         get_internal_resource() = static_cast< typename detail::move_or_copy_assign_ref< resource_type >::type >(that.get_resource());
0688         get_internal_deleter() = static_cast< typename detail::move_or_copy_assign_ref< deleter_type >::type >(that.get_deleter());
0689 
0690         that.set_unallocated();
0691     }
0692 
0693     void assign(unique_resource_data&& that, std::false_type)
0694     {
0695         get_internal_deleter() = static_cast< typename detail::move_or_copy_assign_ref< deleter_type >::type >(that.get_deleter());
0696         get_internal_resource() = static_cast< typename detail::move_or_copy_assign_ref< resource_type >::type >(that.get_resource());
0697 
0698         that.set_unallocated();
0699     }
0700 
0701     void swap_impl(unique_resource_data& that, std::true_type, std::true_type) noexcept
0702     {
0703         boost::core::invoke_swap(get_internal_resource(), that.get_internal_resource());
0704         boost::core::invoke_swap(get_internal_deleter(), that.get_internal_deleter());
0705     }
0706 
0707     void swap_impl(unique_resource_data& that, std::true_type, std::false_type)
0708     {
0709         boost::core::invoke_swap(get_internal_deleter(), that.get_internal_deleter());
0710         boost::core::invoke_swap(get_internal_resource(), that.get_internal_resource());
0711     }
0712 
0713     void swap_impl(unique_resource_data& that, std::false_type, std::false_type)
0714     {
0715         boost::core::invoke_swap(get_internal_resource(), that.get_internal_resource());
0716         boost::core::invoke_swap(get_internal_deleter(), that.get_internal_deleter());
0717     }
0718 };
0719 
0720 template< typename Resource, typename Deleter >
0721 class unique_resource_data< Resource, Deleter, void > :
0722     public detail::resource_holder< Resource, use_resource_compact_storage< Resource, Deleter >::value >,
0723     public detail::deleter_holder< Resource, Deleter >
0724 {
0725 public:
0726     using resource_type = Resource;
0727     using deleter_type = Deleter;
0728     using traits_type = void;
0729 
0730 private:
0731     using resource_holder = detail::resource_holder< resource_type, use_resource_compact_storage< resource_type, deleter_type >::value >;
0732     using deleter_holder = detail::deleter_holder< resource_type, deleter_type >;
0733 
0734 public:
0735     using internal_resource_type = typename resource_holder::internal_resource_type;
0736     using internal_deleter_type = typename deleter_holder::internal_deleter_type;
0737 
0738 private:
0739     bool m_allocated;
0740 
0741 public:
0742     template<
0743         bool Requires = detail::conjunction< std::is_default_constructible< resource_holder >, std::is_default_constructible< deleter_holder > >::value,
0744         typename = typename std::enable_if< Requires >::type
0745     >
0746     constexpr unique_resource_data()
0747         noexcept(detail::conjunction< std::is_nothrow_default_constructible< resource_holder >, std::is_nothrow_default_constructible< deleter_holder > >::value) :
0748         resource_holder(),
0749         deleter_holder(),
0750         m_allocated(false)
0751     {
0752     }
0753 
0754     unique_resource_data(unique_resource_data const&) = delete;
0755     unique_resource_data& operator= (unique_resource_data const&) = delete;
0756 
0757     template<
0758         bool Requires = detail::conjunction<
0759             std::is_constructible< internal_resource_type, typename detail::move_or_copy_construct_ref< resource_type >::type >,
0760             std::is_constructible< internal_deleter_type, typename detail::move_or_copy_construct_ref< deleter_type >::type >
0761         >::value,
0762         typename = typename std::enable_if< Requires >::type
0763     >
0764     unique_resource_data(unique_resource_data&& that)
0765         noexcept(detail::conjunction<
0766             std::is_nothrow_constructible< internal_resource_type, typename detail::move_or_copy_construct_ref< resource_type >::type >,
0767             std::is_nothrow_constructible< internal_deleter_type, typename detail::move_or_copy_construct_ref< deleter_type >::type >
0768         >::value) :
0769         unique_resource_data
0770         (
0771             static_cast< unique_resource_data&& >(that),
0772             typename std::is_nothrow_constructible< internal_resource_type, typename detail::move_or_copy_construct_ref< resource_type >::type >::type(),
0773             typename std::is_nothrow_constructible< internal_deleter_type, typename detail::move_or_copy_construct_ref< deleter_type >::type >::type()
0774         )
0775     {
0776     }
0777 
0778     template<
0779         typename D,
0780         typename = typename std::enable_if< detail::conjunction<
0781             std::is_default_constructible< resource_holder >,
0782             std::is_constructible< deleter_holder, D >
0783         >::value >::type
0784     >
0785     explicit unique_resource_data(default_resource_t, D&& del)
0786         noexcept(detail::conjunction<
0787             std::is_nothrow_default_constructible< resource_holder >,
0788             std::is_nothrow_constructible< deleter_holder, D >
0789         >::value) :
0790         resource_holder(),
0791         deleter_holder(static_cast< D&& >(del)),
0792         m_allocated(false)
0793     {
0794     }
0795 
0796     template<
0797         typename R,
0798         typename D,
0799         typename = typename std::enable_if< detail::conjunction<
0800             detail::negation< detail::is_default_resource< R > >,
0801             std::is_constructible< resource_holder, R, D, bool >,
0802             std::is_constructible< deleter_holder, D, resource_type&, bool >
0803         >::value >::type
0804     >
0805     explicit unique_resource_data(R&& res, D&& del)
0806         noexcept(detail::conjunction<
0807             std::is_nothrow_constructible< resource_holder, R, D, bool >,
0808             std::is_nothrow_constructible< deleter_holder, D, resource_type&, bool >
0809         >::value) :
0810         resource_holder(static_cast< R&& >(res), static_cast< D&& >(del), true),
0811         deleter_holder(static_cast< D&& >(del), resource_holder::get(), true),
0812         m_allocated(true)
0813     {
0814     }
0815 
0816     template<
0817         bool Requires = detail::conjunction<
0818             std::is_assignable< internal_resource_type&, typename detail::move_or_copy_assign_ref< resource_type >::type >,
0819             std::is_assignable< internal_deleter_type&, typename detail::move_or_copy_assign_ref< deleter_type >::type >
0820         >::value
0821     >
0822     typename std::enable_if< Requires, unique_resource_data& >::type operator= (unique_resource_data&& that)
0823         noexcept(detail::conjunction<
0824             std::is_nothrow_assignable< internal_resource_type&, typename detail::move_or_copy_assign_ref< resource_type >::type >,
0825             std::is_nothrow_assignable< internal_deleter_type&, typename detail::move_or_copy_assign_ref< deleter_type >::type >
0826         >::value)
0827     {
0828         assign(static_cast< unique_resource_data&& >(that), typename std::is_nothrow_move_assignable< internal_deleter_type >::type());
0829         return *this;
0830     }
0831 
0832     resource_type& get_resource() noexcept
0833     {
0834         return resource_holder::get();
0835     }
0836 
0837     resource_type const& get_resource() const noexcept
0838     {
0839         return resource_holder::get();
0840     }
0841 
0842     internal_resource_type& get_internal_resource() noexcept
0843     {
0844         return resource_holder::get_internal();
0845     }
0846 
0847     internal_resource_type const& get_internal_resource() const noexcept
0848     {
0849         return resource_holder::get_internal();
0850     }
0851 
0852     deleter_type& get_deleter() noexcept
0853     {
0854         return deleter_holder::get();
0855     }
0856 
0857     deleter_type const& get_deleter() const noexcept
0858     {
0859         return deleter_holder::get();
0860     }
0861 
0862     internal_deleter_type& get_internal_deleter() noexcept
0863     {
0864         return deleter_holder::get_internal();
0865     }
0866 
0867     internal_deleter_type const& get_internal_deleter() const noexcept
0868     {
0869         return deleter_holder::get_internal();
0870     }
0871 
0872     bool is_allocated() const noexcept
0873     {
0874         return m_allocated;
0875     }
0876 
0877     void set_unallocated() noexcept
0878     {
0879         m_allocated = false;
0880     }
0881 
0882     template< typename R >
0883     void assign_resource(R&& res) noexcept(std::is_nothrow_assignable< internal_resource_type&, R >::value)
0884     {
0885         get_internal_resource() = static_cast< R&& >(res);
0886         m_allocated = true;
0887     }
0888 
0889     template<
0890         bool Requires = detail::conjunction<
0891             detail::is_swappable< internal_resource_type >,
0892             detail::is_swappable< internal_deleter_type >,
0893             detail::disjunction<
0894                 detail::is_nothrow_swappable< internal_resource_type >,
0895                 detail::is_nothrow_swappable< internal_deleter_type >
0896             >
0897         >::value
0898     >
0899     typename std::enable_if< Requires >::type swap(unique_resource_data& that)
0900         noexcept(detail::conjunction< detail::is_nothrow_swappable< internal_resource_type >, detail::is_nothrow_swappable< internal_deleter_type > >::value)
0901     {
0902         swap_impl
0903         (
0904             that,
0905             std::integral_constant< bool, detail::is_nothrow_swappable< internal_resource_type >::value >(),
0906             std::integral_constant< bool, detail::conjunction<
0907                 detail::is_nothrow_swappable< internal_resource_type >,
0908                 detail::is_nothrow_swappable< internal_deleter_type >
0909             >::value >()
0910         );
0911     }
0912 
0913 private:
0914     unique_resource_data(unique_resource_data&& that, std::true_type, std::true_type) noexcept :
0915         resource_holder(static_cast< typename detail::move_or_copy_construct_ref< resource_type >::type >(that.get_resource())),
0916         deleter_holder(static_cast< typename detail::move_or_copy_construct_ref< deleter_type >::type >(that.get_deleter())),
0917         m_allocated(that.m_allocated)
0918     {
0919         that.m_allocated = false;
0920     }
0921 
0922     unique_resource_data(unique_resource_data&& that, std::false_type, std::true_type) :
0923         resource_holder(static_cast< resource_type const& >(that.get_resource())),
0924         deleter_holder(static_cast< typename detail::move_or_copy_construct_ref< deleter_type >::type >(that.get_deleter())),
0925         m_allocated(that.m_allocated)
0926     {
0927         that.m_allocated = false;
0928     }
0929 
0930     unique_resource_data(unique_resource_data&& that, std::true_type, std::false_type) try :
0931         resource_holder(static_cast< typename detail::move_or_copy_construct_ref< resource_type >::type >(that.get_resource())),
0932         deleter_holder(static_cast< deleter_type const& >(that.get_deleter())),
0933         m_allocated(that.m_allocated)
0934     {
0935         that.m_allocated = false;
0936     }
0937     catch (...)
0938     {
0939         // Since only the deleter's constructor could have thrown an exception here, move the resource back
0940         // to the original unique_resource. This is guaranteed to not throw.
0941         that.resource_holder::move_from(static_cast< internal_resource_type&& >(resource_holder::get_internal()));
0942     }
0943 
0944     unique_resource_data(unique_resource_data&& that, std::false_type, std::false_type) :
0945         resource_holder(static_cast< resource_type const& >(that.get_resource())),
0946         deleter_holder(static_cast< deleter_type const& >(that.get_deleter())),
0947         m_allocated(that.m_allocated)
0948     {
0949         that.m_allocated = false;
0950     }
0951 
0952     void assign(unique_resource_data&& that, std::true_type)
0953         noexcept(std::is_nothrow_assignable< internal_resource_type&, typename detail::move_or_copy_assign_ref< resource_type >::type >::value)
0954     {
0955         get_internal_resource() = static_cast< typename detail::move_or_copy_assign_ref< resource_type >::type >(that.get_resource());
0956         get_internal_deleter() = static_cast< typename detail::move_or_copy_assign_ref< deleter_type >::type >(that.get_deleter());
0957 
0958         m_allocated = that.m_allocated;
0959         that.m_allocated = false;
0960     }
0961 
0962     void assign(unique_resource_data&& that, std::false_type)
0963     {
0964         get_internal_deleter() = static_cast< typename detail::move_or_copy_assign_ref< deleter_type >::type >(that.get_deleter());
0965         get_internal_resource() = static_cast< typename detail::move_or_copy_assign_ref< resource_type >::type >(that.get_resource());
0966 
0967         m_allocated = that.m_allocated;
0968         that.m_allocated = false;
0969     }
0970 
0971     void swap_impl(unique_resource_data& that, std::true_type, std::true_type) noexcept
0972     {
0973         boost::core::invoke_swap(get_internal_resource(), that.get_internal_resource());
0974         boost::core::invoke_swap(get_internal_deleter(), that.get_internal_deleter());
0975         boost::core::invoke_swap(m_allocated, that.m_allocated);
0976     }
0977 
0978     void swap_impl(unique_resource_data& that, std::true_type, std::false_type)
0979     {
0980         boost::core::invoke_swap(get_internal_deleter(), that.get_internal_deleter());
0981         boost::core::invoke_swap(get_internal_resource(), that.get_internal_resource());
0982         boost::core::invoke_swap(m_allocated, that.m_allocated);
0983     }
0984 
0985     void swap_impl(unique_resource_data& that, std::false_type, std::false_type)
0986     {
0987         boost::core::invoke_swap(get_internal_resource(), that.get_internal_resource());
0988         boost::core::invoke_swap(get_internal_deleter(), that.get_internal_deleter());
0989         boost::core::invoke_swap(m_allocated, that.m_allocated);
0990     }
0991 };
0992 
0993 template< typename T >
0994 struct is_dereferenceable_impl
0995 {
0996     template< typename U, typename R = decltype(*std::declval< U const& >()) >
0997     static std::true_type _is_dereferenceable_check(int);
0998     template< typename U >
0999     static std::false_type _is_dereferenceable_check(...);
1000 
1001     using type = decltype(is_dereferenceable_impl::_is_dereferenceable_check< T >(0));
1002 };
1003 
1004 template< typename T >
1005 struct is_dereferenceable : public is_dereferenceable_impl< T >::type { };
1006 template< >
1007 struct is_dereferenceable< void* > : public std::false_type { };
1008 template< >
1009 struct is_dereferenceable< const void* > : public std::false_type { };
1010 template< >
1011 struct is_dereferenceable< volatile void* > : public std::false_type { };
1012 template< >
1013 struct is_dereferenceable< const volatile void* > : public std::false_type { };
1014 template< >
1015 struct is_dereferenceable< void*& > : public std::false_type { };
1016 template< >
1017 struct is_dereferenceable< const void*& > : public std::false_type { };
1018 template< >
1019 struct is_dereferenceable< volatile void*& > : public std::false_type { };
1020 template< >
1021 struct is_dereferenceable< const volatile void*& > : public std::false_type { };
1022 template< >
1023 struct is_dereferenceable< void* const& > : public std::false_type { };
1024 template< >
1025 struct is_dereferenceable< const void* const& > : public std::false_type { };
1026 template< >
1027 struct is_dereferenceable< volatile void* const& > : public std::false_type { };
1028 template< >
1029 struct is_dereferenceable< const volatile void* const& > : public std::false_type { };
1030 template< >
1031 struct is_dereferenceable< void* volatile& > : public std::false_type { };
1032 template< >
1033 struct is_dereferenceable< const void* volatile& > : public std::false_type { };
1034 template< >
1035 struct is_dereferenceable< volatile void* volatile& > : public std::false_type { };
1036 template< >
1037 struct is_dereferenceable< const volatile void* volatile& > : public std::false_type { };
1038 template< >
1039 struct is_dereferenceable< void* const volatile& > : public std::false_type { };
1040 template< >
1041 struct is_dereferenceable< const void* const volatile& > : public std::false_type { };
1042 template< >
1043 struct is_dereferenceable< volatile void* const volatile& > : public std::false_type { };
1044 template< >
1045 struct is_dereferenceable< const volatile void* const volatile& > : public std::false_type { };
1046 
1047 template< typename T, bool = detail::is_dereferenceable< T >::value >
1048 struct dereference_traits { };
1049 template< typename T >
1050 struct dereference_traits< T, true >
1051 {
1052     using result_type = decltype(*std::declval< T const& >());
1053     static constexpr bool is_noexcept = noexcept(*std::declval< T const& >());
1054 };
1055 
1056 } // namespace detail
1057 
1058 /*!
1059  * \brief RAII wrapper for automatically reclaiming arbitrary resources.
1060  *
1061  * A \c unique_resource object exclusively owns wrapped resource and invokes
1062  * the deleter function object on it on destruction. The wrapped resource can have
1063  * any type that is:
1064  *
1065  * \li Move-constructible, where the move constructor is marked as `noexcept`, or
1066  * \li Copy-constructible, or
1067  * \li An lvalue reference to an object type.
1068  *
1069  * The deleter must be a function object type that is callable on an lvalue
1070  * of the resource type. The deleter must be copy-constructible.
1071  *
1072  * An optional resource traits template parameter may be specified. Resource
1073  * traits can be used to optimize \c unique_resource implementation when
1074  * the following conditions are met:
1075  *
1076  * \li There is at least one value of the resource type that is considered
1077  *     unallocated (that is, no allocated resource shall be equal to one of
1078  *     the unallocated resource values). The unallocated resource values need not
1079  *     be deallocated using the deleter.
1080  * \li One of the unallocated resource values can be considered the default.
1081  *     Constructing the default resource value and assigning it to a resource
1082  *     object (whether allocated or not) shall not throw exceptions.
1083  * \li Resource objects can be tested for being unallocated. Such a test shall
1084  *     not throw exceptions.
1085  *
1086  * If specified, the resource traits must be a class type that has the following
1087  * public static members:
1088  *
1089  * \li `R make_default() noexcept` - must return the default resource value such
1090  *     that `std::is_constructible< Resource, R >::value &&
1091  *     std::is_nothrow_assignable< Resource&, R >::value` is \c true.
1092  * \li `bool is_allocated(Resource const& res) noexcept` - must return \c true
1093  *     if \c res is not one of the unallocated resource values and \c false
1094  *     otherwise.
1095  *
1096  * Note that `is_allocated(make_default())` must always return \c false.
1097  *
1098  * When resource traits satisfying the above requirements are specified,
1099  * \c unique_resource will be able to avoid storing additional indication of
1100  * whether the owned resource object needs to be deallocated with the deleter
1101  * on destruction. It will use the default resource value to initialize the owned
1102  * resource object when \c unique_resource is not in the allocated state.
1103  * Additionally, it will be possible to construct \c unique_resource with
1104  * unallocated resource values, which will create \c unique_resource objects in
1105  * unallocated state (the deleter will not be called on unallocated resource
1106  * values).
1107  * 
1108  * \tparam Resource Resource type.
1109  * \tparam Deleter Resource deleter function object type.
1110  * \tparam Traits Optional resource traits type.
1111  */
1112 template< typename Resource, typename Deleter, typename Traits BOOST_SCOPE_DETAIL_DOC(= void) >
1113 class unique_resource
1114 {
1115 public:
1116     //! Resource type
1117     using resource_type = Resource;
1118     //! Deleter type
1119     using deleter_type = Deleter;
1120     //! Resource traits
1121     using traits_type = Traits;
1122 
1123 //! \cond
1124 private:
1125     using data = detail::unique_resource_data< resource_type, deleter_type, traits_type >;
1126     using internal_resource_type = typename data::internal_resource_type;
1127     using internal_deleter_type = typename data::internal_deleter_type;
1128 
1129     data m_data;
1130 
1131 //! \endcond
1132 public:
1133     /*!
1134      * \brief Constructs an unallocated unique resource guard.
1135      *
1136      * **Requires:** Default \c Resource value can be constructed. \c Deleter is default-constructible
1137      *               and is not a pointer to function.
1138      *
1139      * **Effects:** Initializes the \c Resource object with the default resource value. Default-constructs
1140      *              the \c Deleter object.
1141      *
1142      * **Throws:** Nothing, unless construction of \c Resource or \c Deleter throws.
1143      *
1144      * \post `this->allocated() == false`
1145      */
1146     //! \cond
1147     template<
1148         bool Requires = std::is_default_constructible< data >::value,
1149         typename = typename std::enable_if< Requires >::type
1150     >
1151     //! \endcond
1152     constexpr unique_resource() noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(std::is_nothrow_default_constructible< data >::value))
1153     {
1154     }
1155 
1156     /*!
1157      * \brief Constructs an unallocated unique resource guard with the given deleter.
1158      *
1159      * **Requires:** Default \c Resource value can be constructed and \c Deleter is constructible from \a del.
1160      *
1161      * **Effects:** Initializes the \c Resource value with the default resource value. If \c Deleter is nothrow
1162      *              constructible from `D&&` then constructs \c Deleter from `std::forward< D >(del)`,
1163      *              otherwise constructs from `del`.
1164      *
1165      * **Throws:** Nothing, unless construction of \c Resource or \c Deleter throws.
1166      *
1167      * \param res A tag argument indicating default resource value.
1168      * \param del Resource deleter function object.
1169      *
1170      * \post `this->allocated() == false`
1171      */
1172     template<
1173         typename D
1174         //! \cond
1175         , typename = typename std::enable_if<
1176             std::is_constructible< data, default_resource_t, typename detail::move_or_copy_construct_ref< D, deleter_type >::type >::value
1177         >::type
1178         //! \endcond
1179     >
1180     unique_resource(default_resource_t res, D&& del)
1181         noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(
1182             std::is_nothrow_constructible<
1183                 data,
1184                 default_resource_t,
1185                 typename detail::move_or_copy_construct_ref< D, deleter_type >::type
1186             >::value
1187         )) :
1188         m_data
1189         (
1190             res,
1191             static_cast< typename detail::move_or_copy_construct_ref< D, deleter_type >::type >(del)
1192         )
1193     {
1194     }
1195 
1196     /*!
1197      * \brief Constructs a unique resource guard with the given resource and a default-constructed deleter.
1198      *
1199      * **Requires:** \c Resource is constructible from \a res. \c Deleter is default-constructible and
1200      *               is not a pointer to function.
1201      *
1202      * **Effects:** Constructs the unique resource object as if by calling
1203      *              `unique_resource(std::forward< R >(res), Deleter())`.
1204      *
1205      * **Throws:** Nothing, unless construction of \c Resource or \c Deleter throws.
1206      *
1207      * \param res Resource object.
1208      */
1209     template<
1210         typename R
1211         //! \cond
1212         , typename = typename std::enable_if< detail::conjunction<
1213             detail::is_nothrow_nonnull_default_constructible< deleter_type >,
1214             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 >,
1215             detail::disjunction< detail::negation< std::is_reference< resource_type > >, std::is_reference< R > > // prevent binding lvalue-reference resource to an rvalue
1216         >::value >::type
1217         //! \endcond
1218     >
1219     explicit unique_resource(R&& res)
1220         noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(
1221             std::is_nothrow_constructible<
1222                 data,
1223                 typename detail::move_or_copy_construct_ref< R, resource_type >::type,
1224                 typename detail::move_or_copy_construct_ref< deleter_type >::type
1225             >::value
1226         )) :
1227         m_data
1228         (
1229             static_cast< typename detail::move_or_copy_construct_ref< R, resource_type >::type >(res),
1230             static_cast< typename detail::move_or_copy_construct_ref< deleter_type >::type >(deleter_type())
1231         )
1232     {
1233     }
1234 
1235     /*!
1236      * \brief Constructs a unique resource guard with the given resource and deleter.
1237      *
1238      * **Requires:** \c Resource is constructible from \a res and \c Deleter is constructible from \a del.
1239      *
1240      * **Effects:** If \c Resource is nothrow constructible from `R&&` then constructs \c Resource
1241      *              from `std::forward< R >(res)`, otherwise constructs from `res`. If \c Deleter
1242      *              is nothrow constructible from `D&&` then constructs \c Deleter from
1243      *              `std::forward< D >(del)`, otherwise constructs from `del`.
1244      *
1245      *              If construction of \c Resource or \c Deleter throws and \a res is not an unallocated resource
1246      *              value, invokes \a del on \a res (if \c Resource construction failed) or the constructed
1247      *              \c Resource object (if \c Deleter construction failed).
1248      *
1249      * **Throws:** Nothing, unless construction of \c Resource or \c Deleter throws.
1250      *
1251      * \param res Resource object.
1252      * \param del Resource deleter function object.
1253      *
1254      * \post If \a res is an unallocated resource value then `this->allocated() == false`, otherwise
1255      *       `this->allocated() == true`.
1256      */
1257     template<
1258         typename R,
1259         typename D
1260         //! \cond
1261         , typename = typename std::enable_if< detail::conjunction<
1262             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 >,
1263             detail::disjunction< detail::negation< std::is_reference< resource_type > >, std::is_reference< R > > // prevent binding lvalue-reference resource to an rvalue
1264         >::value >::type
1265         //! \endcond
1266     >
1267     unique_resource(R&& res, D&& del)
1268         noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(
1269             std::is_nothrow_constructible<
1270                 data,
1271                 typename detail::move_or_copy_construct_ref< R, resource_type >::type,
1272                 typename detail::move_or_copy_construct_ref< D, deleter_type >::type
1273             >::value
1274         )) :
1275         m_data
1276         (
1277             static_cast< typename detail::move_or_copy_construct_ref< R, resource_type >::type >(res),
1278             static_cast< typename detail::move_or_copy_construct_ref< D, deleter_type >::type >(del)
1279         )
1280     {
1281     }
1282 
1283     unique_resource(unique_resource const&) = delete;
1284     unique_resource& operator= (unique_resource const&) = delete;
1285 
1286     /*!
1287      * \brief Move-constructs a unique resource guard.
1288      *
1289      * **Requires:** \c Resource and \c Deleter are move-constructible.
1290      *
1291      * **Effects:** If \c Resource is nothrow move-constructible then move-constructs \c Resource,
1292      *              otherwise copy-constructs. If \c Deleter is nothrow move-constructible then move-constructs
1293      *              \c Deleter, otherwise copy-constructs. Deactivates the moved-from unique resource object.
1294      *
1295      *              If an exception is thrown during construction, \a that is left in its original state.
1296      *
1297      * \note This logic ensures that in case of exception the resource is not leaked and remains owned by the
1298      *       move source.
1299      *
1300      * **Throws:** Nothing, unless construction of \c Resource or \c Deleter throws.
1301      *
1302      * \param that Move source.
1303      *
1304      * \post Let \c allocated be equal to `that.allocated()` prior to the operation. Then
1305      *       `this->allocated() == allocated` and `that.allocated() == false`.
1306      */
1307     //! \cond
1308     template<
1309         bool Requires = std::is_move_constructible< data >::value,
1310         typename = typename std::enable_if< Requires >::type
1311     >
1312     //! \endcond
1313     unique_resource(unique_resource&& that) noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(std::is_nothrow_move_constructible< data >::value)) :
1314         m_data(static_cast< data&& >(that.m_data))
1315     {
1316     }
1317 
1318     /*!
1319      * \brief Move-assigns a unique resource guard.
1320      *
1321      * **Requires:** \c Resource and \c Deleter are move-assignable.
1322      *
1323      * **Effects:** Calls `this->reset()`. Then, if \c Deleter is nothrow move-assignable, move-assigns
1324      *              the \c Deleter object first and the \c Resource object next. Otherwise, move-assigns
1325      *              the objects in reverse order. Lastly, deactivates the moved-from unique resource object.
1326      *
1327      *              If an exception is thrown, \a that is left in its original state.
1328      *
1329      * \note The different orders of assignment ensure that in case of exception the resource is not leaked
1330      *       and remains owned by the move source.
1331      *
1332      * **Throws:** Nothing, unless assignment of \c Resource or \c Deleter throws.
1333      *
1334      * \param that Move source.
1335      *
1336      * \post Let \c allocated be equal to `that.allocated()` prior to the operation. Then
1337      *       `this->allocated() == allocated` and `that.allocated() == false`.
1338      */
1339 #if !defined(BOOST_SCOPE_DOXYGEN)
1340     template< bool Requires = std::is_move_assignable< data >::value >
1341     typename std::enable_if< Requires, unique_resource& >::type
1342 #else
1343     unique_resource&
1344 #endif
1345     operator= (unique_resource&& that)
1346         noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(std::is_nothrow_move_assignable< data >::value))
1347     {
1348         reset();
1349         m_data = static_cast< data&& >(that.m_data);
1350         return *this;
1351     }
1352 
1353     /*!
1354      * \brief If the resource is allocated, calls the deleter function on it. Destroys the resource and the deleter.
1355      *
1356      * **Throws:** Nothing, unless invoking the deleter throws.
1357      */
1358     ~unique_resource() noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(detail::is_nothrow_invocable< deleter_type&, resource_type& >::value))
1359     {
1360         if (BOOST_LIKELY(m_data.is_allocated()))
1361             m_data.get_deleter()(m_data.get_resource());
1362     }
1363 
1364     /*!
1365      * \brief Returns \c true if the resource is allocated and to be reclaimed by the deleter, otherwise \c false.
1366      *
1367      * \note This method does not test the value of the resource.
1368      * 
1369      * **Throws:** Nothing.
1370      */
1371     explicit operator bool () const noexcept
1372     {
1373         return m_data.is_allocated();
1374     }
1375 
1376     /*!
1377      * \brief Returns \c true if the resource is allocated and to be reclaimed by the deleter, otherwise \c false.
1378      *
1379      * **Throws:** Nothing.
1380      */
1381     bool allocated() const noexcept
1382     {
1383         return m_data.is_allocated();
1384     }
1385 
1386     /*!
1387      * \brief Returns a reference to the resource object.
1388      *
1389      * **Throws:** Nothing.
1390      */
1391     resource_type const& get() const noexcept
1392     {
1393         return m_data.get_resource();
1394     }
1395 
1396     /*!
1397      * \brief Returns a reference to the deleter object.
1398      *
1399      * **Throws:** Nothing.
1400      */
1401     deleter_type const& get_deleter() const noexcept
1402     {
1403         return m_data.get_deleter();
1404     }
1405 
1406     /*!
1407      * \brief Marks the resource as unallocated. Does not call the deleter if the resource was previously allocated.
1408      *
1409      * **Throws:** Nothing.
1410      *
1411      * \post `this->allocated() == false`
1412      */
1413     void release() noexcept
1414     {
1415         m_data.set_unallocated();
1416     }
1417 
1418     /*!
1419      * \brief If the resource is allocated, calls the deleter function on it and marks the resource as unallocated.
1420      *
1421      * **Throws:** Nothing, unless invoking the deleter throws.
1422      *
1423      * \post `this->allocated() == false`
1424      */
1425     void reset() noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(detail::is_nothrow_invocable< deleter_type&, resource_type& >::value))
1426     {
1427         if (BOOST_LIKELY(m_data.is_allocated()))
1428         {
1429             m_data.get_deleter()(m_data.get_resource());
1430             m_data.set_unallocated();
1431         }
1432     }
1433 
1434     /*!
1435      * \brief Assigns a new resource object to the unique resource wrapper.
1436      *
1437      * **Effects:** Calls `this->reset()`. Then, if \c Resource is nothrow assignable from `R&&`,
1438      *              assigns `std::forward< R >(res)` to the stored resource object, otherwise assigns
1439      *              `res`.
1440      *
1441      *              If \a res is not an unallocated resource value and an exception is thrown during the operation,
1442      *              invokes the stored deleter on \a res before returning with the exception.
1443      *
1444      * **Throws:** Nothing, unless invoking the deleter throws.
1445      *
1446      * \param res Resource object to assign.
1447      *
1448      * \post `this->allocated() == false`
1449      */
1450     template< typename R >
1451 #if !defined(BOOST_SCOPE_DOXYGEN)
1452     typename std::enable_if< detail::conjunction<
1453         std::is_assignable< internal_resource_type&, typename detail::move_or_copy_assign_ref< R, resource_type >::type >,
1454         detail::disjunction< detail::negation< std::is_reference< resource_type > >, std::is_reference< R > > // prevent binding lvalue-reference resource to an rvalue
1455     >::value >::type
1456 #else
1457     void
1458 #endif
1459     reset(R&& res)
1460         noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(
1461             detail::conjunction<
1462                 detail::is_nothrow_invocable< deleter_type&, resource_type& >,
1463                 std::is_nothrow_assignable< internal_resource_type&, typename detail::move_or_copy_assign_ref< R, resource_type >::type >
1464             >::value
1465         ))
1466     {
1467         reset_impl
1468         (
1469             static_cast< R&& >(res),
1470             typename detail::conjunction<
1471                 detail::is_nothrow_invocable< deleter_type&, resource_type& >,
1472                 std::is_nothrow_assignable< internal_resource_type&, typename detail::move_or_copy_assign_ref< R, resource_type >::type >
1473             >::type()
1474         );
1475     }
1476 
1477     /*!
1478      * \brief Invokes indirection on the resource object.
1479      *
1480      * **Requires:** \c Resource is dereferenceable.
1481      *
1482      * **Effects:** Returns a reference to the resource object as if by calling `get()`.
1483      *
1484      * \note If \c Resource is not a pointer type, the compiler will invoke its `operator->`.
1485      *       Such call sequence will continue until a pointer is obtained.
1486      *
1487      * **Throws:** Nothing. Note that any implicit subsequent calls to other `operator->`
1488      *             functions that are caused by this call may have different throw conditions.
1489      */
1490 #if !defined(BOOST_SCOPE_DOXYGEN)
1491     template< bool Requires = detail::is_dereferenceable< resource_type >::value >
1492     typename std::enable_if< Requires, resource_type const& >::type
1493 #else
1494     resource_type const&
1495 #endif
1496     operator-> () const noexcept
1497     {
1498         return get();
1499     }
1500 
1501     /*!
1502      * \brief Dereferences the resource object.
1503      *
1504      * **Requires:** \c Resource is dereferenceable.
1505      *
1506      * **Effects:** Returns the result of dereferencing the resource object as if by calling `*get()`.
1507      *
1508      * **Throws:** Nothing, unless dereferencing the resource object throws.
1509      */
1510 #if !defined(BOOST_SCOPE_DOXYGEN)
1511     template< bool Requires = detail::is_dereferenceable< resource_type >::value >
1512     typename detail::dereference_traits< resource_type, Requires >::result_type
1513 #else
1514     auto
1515 #endif
1516     operator* () const
1517         noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(detail::dereference_traits< resource_type, Requires >::is_noexcept))
1518     {
1519         return *get();
1520     }
1521 
1522     /*!
1523      * \brief Swaps two unique resource wrappers.
1524      *
1525      * **Requires:** \c Resource and \c Deleter are swappable. At least one of \c Resource and \c Deleter
1526      *               is nothrow swappable.
1527      *
1528      * **Effects:** Swaps the resource objects and deleter objects stored in `*this` and \a that
1529      *              as if by calling unqualified `swap` in a context where `std::swap` is
1530      *              found by overload resolution.
1531      *
1532      *              If an exception is thrown, and the failed swap operation supports strong exception
1533      *              guarantee, both `*this` and \a that are left in their original states.
1534      *
1535      * **Throws:** Nothing, unless swapping the resource objects or deleters throw.
1536      *
1537      * \param that Unique resource wrapper to swap with.
1538      */
1539 #if !defined(BOOST_SCOPE_DOXYGEN)
1540     template< bool Requires = detail::is_swappable< data >::value >
1541     typename std::enable_if< Requires >::type
1542 #else
1543     void
1544 #endif
1545     swap(unique_resource& that)
1546         noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(detail::is_nothrow_swappable< data >::value))
1547     {
1548         m_data.swap(that.m_data);
1549     }
1550 
1551     /*!
1552      * \brief Swaps two unique resource wrappers.
1553      *
1554      * **Effects:** As if `left.swap(right)`.
1555      */
1556 #if !defined(BOOST_SCOPE_DOXYGEN)
1557     template< bool Requires = detail::is_swappable< data >::value >
1558     friend typename std::enable_if< Requires >::type
1559 #else
1560     friend void
1561 #endif
1562     swap(unique_resource& left, unique_resource& right)
1563         noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(detail::is_nothrow_swappable< data >::value))
1564     {
1565         left.swap(right);
1566     }
1567 
1568 //! \cond
1569 private:
1570     //! Assigns a new resource object to the unique resource wrapper.
1571     template< typename R >
1572     void reset_impl(R&& res, std::true_type) noexcept
1573     {
1574         reset();
1575         m_data.assign_resource(static_cast< typename detail::move_or_copy_assign_ref< R, resource_type >::type >(res));
1576     }
1577 
1578     //! Assigns a new resource object to the unique resource wrapper.
1579     template< typename R >
1580     void reset_impl(R&& res, std::false_type)
1581     {
1582         try
1583         {
1584             reset();
1585             m_data.assign_resource(static_cast< typename detail::move_or_copy_assign_ref< R, resource_type >::type >(res));
1586         }
1587         catch (...)
1588         {
1589             m_data.get_deleter()(static_cast< R&& >(res));
1590             throw;
1591         }
1592     }
1593 //! \endcond
1594 };
1595 
1596 #if !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES)
1597 template<
1598     typename Resource,
1599     typename Deleter,
1600     typename = typename std::enable_if< !detail::is_default_resource< Resource >::value >::type
1601 >
1602 unique_resource(Resource, Deleter) -> unique_resource< Resource, Deleter >;
1603 #endif // !defined(BOOST_NO_CXX17_DEDUCTION_GUIDES)
1604 
1605 /*!
1606  * \brief Checks if the resource is valid and creates a \c unique_resource wrapper.
1607  *
1608  * **Effects:** If the resource \a res is not equal to \a invalid, creates a unique resource wrapper
1609  *              that is in allocated state and owns \a res. Otherwise creates a unique resource wrapper
1610  *              in unallocated state.
1611  *
1612  * \note This function does not call \a del if \a res is equal to \a invalid.
1613  *
1614  * **Throws:** Nothing, unless \c unique_resource constructor throws.
1615  *
1616  * \param res Resource to wrap.
1617  * \param invalid An invalid value for the resource.
1618  * \param del A deleter to invoke on the resource to free it.
1619  */
1620 template< typename Resource, typename Deleter, typename Invalid >
1621 inline unique_resource< typename std::decay< Resource >::type, typename std::decay< Deleter >::type >
1622 make_unique_resource_checked(Resource&& res, Invalid const& invalid, Deleter&& del)
1623     noexcept(BOOST_SCOPE_DETAIL_DOC_HIDDEN(
1624         detail::conjunction<
1625             std::is_nothrow_constructible< typename std::decay< Resource >::type, typename detail::move_or_copy_construct_ref< Resource, typename std::decay< Resource >::type >::type >,
1626             std::is_nothrow_constructible< typename std::decay< Deleter >::type, typename detail::move_or_copy_construct_ref< Deleter, typename std::decay< Deleter >::type >::type >
1627         >::value
1628     ))
1629 {
1630     using unique_resource_type = unique_resource< typename std::decay< Resource >::type, typename std::decay< Deleter >::type >;
1631     if (!(res == invalid))
1632         return unique_resource_type(static_cast< Resource&& >(res), static_cast< Deleter&& >(del));
1633     else
1634         return unique_resource_type(default_resource_t(), static_cast< Deleter&& >(del));
1635 }
1636 
1637 } // namespace scope
1638 } // namespace boost
1639 
1640 #include <boost/scope/detail/footer.hpp>
1641 
1642 #endif // BOOST_SCOPE_UNIQUE_RESOURCE_HPP_INCLUDED_