-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpointer_union.hpp
More file actions
298 lines (278 loc) · 8.84 KB
/
pointer_union.hpp
File metadata and controls
298 lines (278 loc) · 8.84 KB
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
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
#ifndef POINTER_UNION_HPP
#define POINTER_UNION_HPP
/*******************************************************************************
* \file
* This is the header file containing pointer unions.
*
* \author Markus Saers <masaers@gmail.com>
******************************************************************************/
#include <type_traits>
#include <cstdint>
#include <cstddef>
namespace com_masaers {
/*******************************************************************************
* A pointer union can store a pointer to a fixed set of types, and
* remembers what it currently stores; like a tagged union for
* pointers.
*
* This is useful when you have storage of values or objects already
* under controll, but whish to use them elsewhere in a homogenous way
* (eg. by putting pointers to them in an STL container). There is no
* need for a base class, and the values/objects themselves do not
* necessarily share a meaningful API.
*
* \author Markus Saers <masaers@gmail.com>
******************************************************************************/
template<typename...> struct ptrunion;
/*******************************************************************************
* The base case is the pointer union of no types; it can hold a
* <code>void*</code>.
*
* \author Markus Saers <masaers@gmail.com>
******************************************************************************/
template<>
struct ptrunion<> {
public:
typedef uint8_t size_type;
protected:
enum : size_type { my_id = 0 };
public:
template<typename U, bool dummy = true> struct id_of {
enum : size_type { value = my_id };
};
///
/// \name Constructors and destructors
///
/// \{
// ---------------------------------------------------------------------------
///
/// Default constructor.
///
inline ptrunion() : ptr_m(NULL), id_m(my_id) {}
///
/// Constructor with any pointer type.
///
template<typename ptr_T>
inline ptrunion(/// The pointer to construct the pointer union with.
ptr_T* ptr) : ptr_m((void*)ptr), id_m(my_id) {}
///
/// Constructor with any pointer type and a specific type id.
///
protected:
template<typename ptr_T>
inline ptrunion(/// The pointer to construct the poiter union with.
ptr_T* ptr,
/// The type id of the pointer.
size_type id) : ptr_m((void*)ptr), id_m(id) {}
public:
///
/// Copy constructor.
///
inline ptrunion(/// The pointer union to copy.
const ptrunion&) = default;
// ---------------------------------------------------------------------------
/// \}
///
/// \name Overloaded operators
///
/// \{
// ---------------------------------------------------------------------------
///
/// Assignment from an existing pointer union.
///
inline ptrunion& operator=(/// The pointer union to assign from.
const ptrunion& x) {
set(x.ptr_m, x.id_m);
return *this;
}
///
/// Assignment from a <code>void*</code>.
///
inline ptrunion& operator=(/// The pointer that the pointer union
/// will point to.
void* ptr) {
set(ptr, my_id);
return *this;
}
///
/// Equality operator.
///
inline bool operator==(/// The pointer union to compare to.
const ptrunion& x) const {
return ptr_m == x.ptr_m && id_m == x.id_m;
}
///
/// Inequality operator.
///
inline bool operator!=(/// The pointer union to compare to.
const ptrunion& x) const { return ! operator==(x); }
///
/// Ordering operator.
///
inline bool operator<(/// The pointer union to compare to.
const ptrunion& x) const {
return id_m != x.id_m ? id_m < x.id_m : ptr_m < x.ptr_m;
}
///
/// Cast to <code>void*</code> operator.
///
inline operator void*() const { return ptr_m; }
// ---------------------------------------------------------------------------
/// \}
///
/// \name Accessors
///
/// \{
// ---------------------------------------------------------------------------
///
/// Retrieve the type id of the pointer being held.
///
inline size_type id() const { return id_m; }
///
/// Retrieve a <code>void*</code> version of the pointer being held.
///
inline void* ptr() const { return ptr_m; }
///
/// Determines whether the the held pointer is of a specific
/// type. All pointer unions are potentially pointing to
/// <code>void</code>.
///
template<typename ptr_T>
inline typename std::enable_if<std::is_same<void, ptr_T>::value, bool>::type
is() const { return true; }
///
/// Determines whether the the held pointer is of a specific
/// type. All pointer unions are potentially pointing to
/// <code>void</code>.
///
template<typename ptr_T>
inline typename std::enable_if<! std::is_same<void, ptr_T>::value, bool>::type
is() const { return false; }
// ---------------------------------------------------------------------------
/// \}
protected:
inline void set(void* ptr, size_type id) {
ptr_m = ptr;
id_m = id;
}
private:
void* ptr_m;
size_type id_m;
};
/*******************************************************************************
* The inductive case of the pointer union has at least one type
* specified, allowing it to hold pointers to that type.
*
* \author Markus Saers <masaers@gmail.com>
******************************************************************************/
template<typename T, typename... Ts>
struct ptrunion<T, Ts...> : public ptrunion<Ts...> {
typedef ptrunion<Ts...> base_type;
public:
typedef typename base_type::size_type size_type;
protected:
enum : size_type { my_id = base_type::my_id + 1 };
public:
template<typename U, bool dummy = true> struct id_of
: public base_type::template id_of<U>
{};
template<bool dummy> struct id_of<T, dummy> {
enum : size_type { value = my_id };
};
///
/// \name Constructors and destructors
///
/// \{
// ---------------------------------------------------------------------------
///
/// Default constructor.
///
inline ptrunion() : base_type() {}
///
/// Constructor with the specific pointer type handled by this class.
///
inline ptrunion(/// The pointer to construct the pointer union with.
T* ptr) : base_type(ptr, my_id) {}
///
/// Constructor with any pointer type not handled by this class.
///
template<typename ptr_T>
inline ptrunion(/// The pointer to construct the pointer union with.
ptr_T* ptr) : base_type(ptr) {}
///
/// Constructor with any pointer with a given type id.
///
protected:
template<typename ptr_T>
inline ptrunion(/// The pointer to construct the pointer union with.
ptr_T* ptr,
/// The type id of the pointer.
size_type id) : base_type(ptr, id) {}
public:
// ---------------------------------------------------------------------------
/// \}
///
/// \name Overloaded operators
///
/// \{
// ---------------------------------------------------------------------------
///
/// Assignment operator from the specific pointer type handled by
/// this class.
///
inline ptrunion& operator=(/// The pointer to assign to the pointer union.
T* ptr) {
this->set((void*)ptr, my_id);
return *this;
}
///
/// Assignment operator from any pointer not handled by this class.
///
template<typename ptr_T>
inline ptrunion& operator=(// The pointer to assign to the pointer union.
ptr_T* ptr) {
base_type::operator=(ptr);
return *this;
}
///
/// Cast operator to the pointer type handled by this class.
///
inline operator T*() const {
T* result = NULL;
if (this->id() == my_id) {
result = static_cast<T*>(this->ptr());
}
return result;
}
///
/// Cast operator to any pointer type not handled by this class.
///
template<typename ptr_T>
inline operator ptr_T*() const {
return base_type::operator ptr_T*();
}
// ---------------------------------------------------------------------------
/// \}
///
/// \name Accessors
///
/// \{
// ---------------------------------------------------------------------------
///
/// Determines whether the held pointer is of a specific type.
///
template<typename ptr_T>
typename std::enable_if<std::is_same<T, ptr_T>::value, bool>::type
is() const { return this->id() == my_id; }
///
/// Determines whether the held pointer is of a specific type.
///
template<typename ptr_T>
typename std::enable_if<! std::is_same<T, ptr_T>::value, bool>::type
is() const { return base_type::template is<ptr_T>(); }
// ---------------------------------------------------------------------------
/// \}
};
} // namespace com_masaers
/******************************************************************************/
#endif