1 // unique_resource
2 // Copyright (c) 2015 okdshin
3 // Distributed under the Boost Software License, Version 1.0. (See accompanying
4 // file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5 // This implementation is based on C++ standards committee paper N4189.
6 #ifndef UNIQUE_RESOURCE_H_
7 #define UNIQUE_RESOURCE_H_
8 #include <utility>
9 // workaround for GCC
10 #if defined(__GNUC__)
11 #ifdef UNIQUE_RESOURCE_ALLOW_DELETER_CALL_THROWING_EXCEPTION
12 #define UNIQUE_RESOURCE_NOEXCEPT
13 #else
14 #define UNIQUE_RESOURCE_NOEXCEPT noexcept
15 #endif
16 #define UNIQUE_RESOURCE_NOEXCEPT_NOEXCEPT_THIS_RESET UNIQUE_RESOURCE_NOEXCEPT
17 #define UNIQUE_RESOURCE_NOEXCEPT_NOEXCEPT_THIS_DELETER_CALL                    \
18   UNIQUE_RESOURCE_NOEXCEPT
19 #else
20 #define UNIQUE_RESOURCE_NOEXCEPT_NOEXCEPT_THIS_RESET                           \
21   noexcept(noexcept(this->reset()))
22 #define UNIQUE_RESOURCE_NOEXCEPT_NOEXCEPT_THIS_DELETER_CALL                    \
23   noexcept(noexcept(this->get_deleter()(resource)))
24 #endif
25 namespace std_experimental {
26 template <typename R, typename D> class unique_resource {
27   R resource;
28   D deleter;
29   bool execute_on_destruction; // exposition only
30   unique_resource &operator=(unique_resource const &) = delete;
31   unique_resource(unique_resource const &) = delete; // no copies!
32 public:
33   // construction
unique_resource(R && resource_,D && deleter_,bool shouldrun=true)34   explicit unique_resource(R &&resource_, D &&deleter_,
35                            bool shouldrun = true) noexcept
36       : resource(std::move(resource_)),
37         deleter(std::move(deleter_)),
38         execute_on_destruction{shouldrun} {}
39   // move
unique_resource(unique_resource && other)40   unique_resource(unique_resource &&other) noexcept
41       : resource(std::move(other.resource)),
42         deleter(std::move(other.deleter)),
43         execute_on_destruction{other.execute_on_destruction} {
44     other.release();
45   }
operator =(unique_resource && other)46   unique_resource &operator=(unique_resource &&other)
47       UNIQUE_RESOURCE_NOEXCEPT_NOEXCEPT_THIS_RESET {
48     this->reset();
49     this->deleter = std::move(other.deleter);
50     this->resource = std::move(other.resource);
51     this->execute_on_destruction = other.execute_on_destruction;
52     other.release();
53     return *this;
54   }
55   // resource release
~unique_resource()56   ~unique_resource() UNIQUE_RESOURCE_NOEXCEPT_NOEXCEPT_THIS_RESET {
57     this->reset();
58   }
reset()59   void reset() UNIQUE_RESOURCE_NOEXCEPT_NOEXCEPT_THIS_DELETER_CALL {
60     if (execute_on_destruction) {
61       this->execute_on_destruction = false;
62       this->get_deleter()(resource);
63     }
64   }
reset(R && newresource)65   void reset(R &&newresource) UNIQUE_RESOURCE_NOEXCEPT_NOEXCEPT_THIS_RESET {
66     this->reset();
67     this->resource = std::move(newresource);
68     this->execute_on_destruction = true;
69   }
release()70   R const &release() noexcept {
71     this->execute_on_destruction = false;
72     return this->get();
73   }
74   // resource access
get() const75   R const &get() const noexcept { return this->resource; }
operator R const&() const76   operator R const &() const noexcept { return this->resource; }
operator ->() const77   R operator->() const noexcept { return this->resource; }
78   typename std::add_lvalue_reference<
79       typename std::remove_pointer<R>::type>::type
operator *() const80   operator*() const {
81     return *this->resource;
82   }
83   // deleter access
get_deleter() const84   const D &get_deleter() const noexcept { return this->deleter; }
85 };
86 // factories
87 template <typename R, typename D>
88 unique_resource<R, typename std::remove_reference<D>::type>
make_unique_resource(R && r,D && d)89 make_unique_resource(R &&r, D &&d) noexcept {
90   return unique_resource<R, typename std::remove_reference<D>::type>(
91       std::move(r), std::forward<typename std::remove_reference<D>::type>(d),
92       true);
93 }
94 template <typename R, typename D>
make_unique_resource_checked(R r,R invalid,D d)95 unique_resource<R, D> make_unique_resource_checked(R r, R invalid,
96                                                    D d) noexcept {
97   bool shouldrun = not bool(r == invalid);
98   return unique_resource<R, D>(std::move(r), std::move(d), shouldrun);
99 }
100 }
101 #endif /* UNIQUE_RESOURCE_H_ */
102