-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrich_typed_ptr.hpp
186 lines (150 loc) · 4.98 KB
/
rich_typed_ptr.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
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
/*
Copyright 2013 Julian Gonggrijp
Version 0, alpha 1.
*/
#ifndef JG_RICH_TYPED_PTR_HPP
#define JG_RICH_TYPED_PTR_HPP
#include <utility>
#include <type_traits>
#include <cstddef>
#include <cassert>
namespace rich_typed_ptr {
template <class T> class data_ptr;
template <class T> class weak_ptr;
template <class T>
class owner_ptr {
public:
using value_type = T;
// move-constructible but not copyable or assignable
owner_ptr ( ) = delete;
owner_ptr (owner_ptr && source) : pointer(source.pointer) {
source.pointer = nullptr;
}
~owner_ptr ( ) { if (pointer) delete pointer; }
owner_ptr & operator= (owner_ptr &&) = delete;
// factory functions
template <class U, class ... Us>
friend owner_ptr<U> make (Us&& ...);
template <class U1, class U2, class ... Us>
friend owner_ptr<U1> make_dynamic (Us&& ...);
// dereferenceable
T & operator* ( ) const { assert(pointer); return *pointer; }
T * operator-> ( ) const { assert(pointer); return pointer; }
// comparisons
bool operator== (std::nullptr_t) const { return pointer == nullptr; }
friend bool operator== (const owner_ptr & left, const owner_ptr & right) {
return left.pointer == right.pointer;
}
friend bool operator!= (const owner_ptr & left, const owner_ptr & right) {
return left.pointer != right.pointer;
}
// distributed access, usage as initializer
friend weak_ptr<T>;
friend data_ptr<T>;
private:
T * pointer;
owner_ptr (T * raw) : pointer(raw) { }
};
template <class T, class ... Ts>
owner_ptr<T> make (Ts&& ... init) {
return new T(std::forward<Ts>(init)...);
}
// safe dynamic binding
template <class T1, class T2, class ... Ts>
owner_ptr<T1> make_dynamic (Ts&& ... init) {
static_assert( std::is_base_of<T1, T2>::value,
"Rich-typed ptr to base can only reference "
"base or derived" );
static_assert( std::has_virtual_destructor<T1>::value,
"Base type must have virtual destructor "
"in order to prevent memory leaks" );
return new T2(std::forward<Ts>(init)...);
}
template <class T>
class data_ptr {
public:
using value_type = T;
// like owner_ptr, also assignable and initializable from nullptr
data_ptr ( ) = delete;
data_ptr (std::nullptr_t) : pointer(nullptr) { }
data_ptr (data_ptr && source) : pointer(source.pointer) {
source.pointer = nullptr;
}
data_ptr (owner_ptr<T> && source) : pointer(source.pointer) {
source.pointer = nullptr;
}
~data_ptr ( ) { if (pointer) delete pointer; }
data_ptr & operator= (data_ptr && source) {
assert(! pointer);
std::swap(pointer, source.pointer);
return *this;
}
// dereferenceable
T & operator* ( ) const { assert(pointer); return *pointer; }
T * operator-> ( ) const { assert(pointer); return pointer; }
// comparisons
bool operator== (std::nullptr_t) const { return pointer == nullptr; }
friend bool operator== (const data_ptr & left, const data_ptr & right) {
return left.pointer == right.pointer;
}
friend bool operator!= (const data_ptr & left, const data_ptr & right) {
return left.pointer != right.pointer;
}
// distributed access
friend weak_ptr<T>;
private:
T * pointer;
};
template <class T>
class weak_ptr {
public:
using value_type = T;
// copyable but not default-constructible
weak_ptr ( ) = delete;
weak_ptr (const owner_ptr<T> & source) : pointer(source.pointer) { }
weak_ptr (const data_ptr<T> & source) : pointer(source.pointer) { }
weak_ptr & operator= (const owner_ptr<T> & source) {
pointer = source.pointer;
return *this;
}
weak_ptr & operator= (const data_ptr<T> & source) {
pointer = source.pointer;
return *this;
}
// dereferenceable
T & operator* ( ) const { assert(pointer); return *pointer; }
T * operator-> ( ) const { assert(pointer); return pointer; }
// comparisons
bool operator== (std::nullptr_t) const { return pointer == nullptr; }
friend bool operator== (weak_ptr left, weak_ptr right) {
return left.pointer == right.pointer;
}
friend bool operator!= (weak_ptr left, weak_ptr right) {
return left.pointer != right.pointer;
}
private:
T * pointer;
};
template <class T>
inline bool operator!= (const T & left, std::nullptr_t) {
return !(left == nullptr);
}
template <class Ptr>
struct ptr_traits {
using value_type = typename Ptr::value_type;
using weak_ptr_t = weak_ptr<value_type>;
};
template <class Ptr>
typename ptr_traits<Ptr>::weak_ptr_t
weak (const Ptr & pointer) {
static_assert(
std::is_convertible<
Ptr,
typename ptr_traits<Ptr>::weak_ptr_t
>::value,
"Argument to rich_typed_ptr::weak must be a rich typed pointer"
);
return pointer;
}
} // namespace rich_typed_ptr
#endif // JG_RICH_TYPED_PTR_HPP