/
extendable_unique_ownership.h
191 lines (158 loc) · 6.25 KB
/
extendable_unique_ownership.h
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
#ifndef _EXTENDABLE_UNIQUE_OWNERSHIP_
#define _EXTENDABLE_UNIQUE_OWNERSHIP_
#include <atomic>
#include <memory>
template <typename T> class weak_extender;
template <typename T> class scoped_extender;
/**
* @brief Smart pointer which in terms of lifetime management concepts is
* uniquely responsible for a lifetime of a certain resource (meaning, when this
* object is destroyed, the resource should be considered destroyed as well) but
* provides means to extend the lifetime of that resource for a short period of
* time
* @details Short lifetime extension is useful to make the resource existence
* thread-safe (in case the outside user started to work with the resource in a
* different thread before the destruction of this object took place) while
* retaining the logical concept of unique ownership.
*
* The only ways to access the underlying resource is either by direct access
* to the unique_extendable_ptr or by @see weak_extender + @see scoped_extender
* usage.
*
* In most cases the lifetime of a resource may be extended by @see scoped_extender
* beyond the lifetime of the unique_extendable_ptr only for a very short period
* of time. An infinite loop may break this guarantee, but in general an infinite
* loop is hard to miss, relatively easy to diagnose and almost never desired.
*
* @tparam T Type of the owned resource
*/
template <typename T>
class unique_extendable_ptr {
public:
/**
* @brief Counstructs and empty smart pointer that does not own anything
*/
unique_extendable_ptr() = default;
/**
* @brief Constructor that consumes ownership of a heap-allocated resource
* @details Is intentionnaly not marked "explicit" to work with raw owning
* pointers as well as std::unique_ptr
*/
unique_extendable_ptr(std::unique_ptr<T>);
/**
* @brief @see reset()
*/
~unique_extendable_ptr();
unique_extendable_ptr(const unique_extendable_ptr&) = delete;
unique_extendable_ptr& operator=(const unique_extendable_ptr&) = delete;
unique_extendable_ptr(unique_extendable_ptr&&) = default;
unique_extendable_ptr& operator=(unique_extendable_ptr&&) = default;
T* get() const;
T* operator->() const;
/**
* @brief Stops owning the resource and destroys it if its lifetime was not
* temporarily extended by @see scoped_extender
* @details If the lifetime of a resource was temporarily extended by
* @see scoped_extender (i.e. in another thread) then it will be destroyed
* when the last scoped_extender leaves the scope
*/
void reset();
private:
friend class weak_extender<T>;
friend class scoped_extender<T>;
struct resource_owner;
using strong_lifetime_link = std::shared_ptr<resource_owner>;
using weak_lifetime_link = std::weak_ptr<resource_owner>;
strong_lifetime_link resource;
};
/**
* @brief unique_extendable_ptr internal struct
*/
template <typename T>
struct unique_extendable_ptr<T>::resource_owner {
public:
resource_owner();
explicit resource_owner(std::unique_ptr<T>);
resource_owner(const resource_owner&) = delete;
resource_owner& operator=(const resource_owner&) = delete;
resource_owner(resource_owner&&) = delete;
resource_owner& operator=(resource_owner&&) = delete;
T* get() const;
T* operator->() const;
std::unique_ptr<T> resource;
/**
* @brief Used to stop providing access to the resource immidiately
* after the unique_extendable_ptr was destroyed (in case the access is
* requested through a @see weak_extender that is still alive)
*/
std::atomic_bool marked_for_destruction;
};
/**
* @brief A convinience function with the same goals and behaviour as
* std::make_unique<>()
*/
template <typename T, typename... CtorArgTypes>
unique_extendable_ptr<T> make_unique_extendable(CtorArgTypes&&... ctorArgs);
/**
* @brief An object that does not extend the lifetime of a resource owned by
* the corresponding @see unique_extendable_ptr but provides the means to
* access it in a thread-safe way
* @details Can be copied and moved without any impact on the lifetime of
* the resource owned by @see unique_extendable_ptr
*/
template <typename T>
class weak_extender {
public:
weak_extender() = default;
explicit weak_extender(const unique_extendable_ptr<T>&);
weak_extender(const weak_extender&) = default;
weak_extender& operator=(const weak_extender&) = default;
weak_extender(weak_extender&&) = default;
weak_extender& operator=(weak_extender&&) = default;
/**
* @brief Returns an object that provides access to the resource
* owned by @see unique_extendable_ptr
*/
scoped_extender<T> lock() const;
/**
* @brief Stops assotiating itself with the corresponding @see unique_extendable_ptr
*/
void reset();
private:
friend class scoped_extender<T>;
using resource = typename unique_extendable_ptr<T>::resource_owner;
using weak_lifetime_link = typename unique_extendable_ptr<T>::weak_lifetime_link;
static bool not_marked_for_destruction(const resource*);
weak_lifetime_link link;
};
/**
* @brief Provides thread-safe access to the resource owned by a corresponding
* @see unique_extendable_ptr. An uncopiable and unmovable object that may be
* retrieved only by weak_extender::lock() and may be caught only by const
* reference. Can not be stored in a container or another object which makes it
* in most cases to extend the lifetime of the resource only for a very short
* time.
*/
template <typename T>
class scoped_extender {
public:
scoped_extender(const scoped_extender&) = delete;
scoped_extender& operator=(const scoped_extender&) = delete;
scoped_extender& operator=(scoped_extender&&) = delete;
T* get() const;
T* operator->() const;
bool empty() const;
/**
* @brief Stops assotiating itself with the corresponding @see unique_extendable_ptr
*/
void reset();
private:
friend class weak_extender<T>;
using strong_lifetime_link = typename unique_extendable_ptr<T>::strong_lifetime_link;
scoped_extender() = default;
explicit scoped_extender(strong_lifetime_link);
scoped_extender(scoped_extender&&) = default;
strong_lifetime_link link;
};
#include "extendable_unique_ownership_impl.h"
#endif // _EXTENDABLE_UNIQUE_OWNERSHIP_