-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathunique_resource.hpp
111 lines (109 loc) · 4.01 KB
/
unique_resource.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// unique_resource
// Copyright (c) 2015 okdshin
// Portions Copyright (c) 2020 D3 Engineering, LLC.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// This implementation is based on C++ standards committee paper N4189.
#ifndef UNIQUE_RESOURCE_H_
#define UNIQUE_RESOURCE_H_
#include <utility>
// workaround for GCC
#if defined(__GNUC__)
#ifdef UNIQUE_RESOURCE_ALLOW_DELETER_CALL_THROWING_EXCEPTION
#define UNIQUE_RESOURCE_NOEXCEPT
#else
#define UNIQUE_RESOURCE_NOEXCEPT noexcept
#endif
#define UNIQUE_RESOURCE_NOEXCEPT_NOEXCEPT_THIS_RESET UNIQUE_RESOURCE_NOEXCEPT
#define UNIQUE_RESOURCE_NOEXCEPT_NOEXCEPT_THIS_DELETER_CALL \
UNIQUE_RESOURCE_NOEXCEPT
#else
#define UNIQUE_RESOURCE_NOEXCEPT_NOEXCEPT_THIS_RESET \
noexcept(noexcept(this->reset()))
#define UNIQUE_RESOURCE_NOEXCEPT_NOEXCEPT_THIS_DELETER_CALL \
noexcept(noexcept(this->get_deleter()(resource)))
#endif
namespace std_experimental {
// By Herb Sutter, <https://herbsutter.com/gotw/_102/>.
// Copied here since C++11 doesn't have std::make_unique().
template<typename T, typename ...Args>
std::unique_ptr<T> make_unique( Args&& ...args )
{
return std::unique_ptr<T>( new T( std::forward<Args>(args)... ) );
}
template <typename R, typename D> class unique_resource {
R resource;
D deleter;
bool execute_on_destruction; // exposition only
unique_resource &operator=(unique_resource const &) = delete;
unique_resource(unique_resource const &) = delete; // no copies!
public:
// construction
explicit unique_resource(R &&resource_, D &&deleter_,
bool shouldrun = true) noexcept
: resource(std::move(resource_)),
deleter(std::move(deleter_)),
execute_on_destruction{shouldrun} {}
// move
unique_resource(unique_resource &&other) noexcept
: resource(std::move(other.resource)),
deleter(std::move(other.deleter)),
execute_on_destruction{other.execute_on_destruction} {
other.release();
}
unique_resource &operator=(unique_resource &&other)
UNIQUE_RESOURCE_NOEXCEPT_NOEXCEPT_THIS_RESET {
this->reset();
this->deleter = std::move(other.deleter);
this->resource = std::move(other.resource);
this->execute_on_destruction = other.execute_on_destruction;
other.release();
return *this;
}
// resource release
~unique_resource() UNIQUE_RESOURCE_NOEXCEPT_NOEXCEPT_THIS_RESET {
this->reset();
}
void reset() UNIQUE_RESOURCE_NOEXCEPT_NOEXCEPT_THIS_DELETER_CALL {
if (execute_on_destruction) {
this->execute_on_destruction = false;
this->get_deleter()(resource);
}
}
void reset(R &&newresource) UNIQUE_RESOURCE_NOEXCEPT_NOEXCEPT_THIS_RESET {
this->reset();
this->resource = std::move(newresource);
this->execute_on_destruction = true;
}
R const &release() noexcept {
this->execute_on_destruction = false;
return this->get();
}
// resource access
R const &get() const noexcept { return this->resource; }
operator R const &() const noexcept { return this->resource; }
R operator->() const noexcept { return this->resource; }
typename std::add_lvalue_reference<
typename std::remove_pointer<R>::type>::type
operator*() const {
return *this->resource;
}
// deleter access
const D &get_deleter() const noexcept { return this->deleter; }
};
// factories
template <typename R, typename D>
unique_resource<R, typename std::remove_reference<D>::type>
make_unique_resource(R &&r, D &&d) noexcept {
return unique_resource<R, typename std::remove_reference<D>::type>(
std::move(r), std::forward<typename std::remove_reference<D>::type>(d),
true);
}
template <typename R, typename D>
unique_resource<R, D> make_unique_resource_checked(R r, R invalid,
D d) noexcept {
bool shouldrun = not bool(r == invalid);
return unique_resource<R, D>(std::move(r), std::move(d), shouldrun);
}
}
#endif /* UNIQUE_RESOURCE_H_ */