-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathobject_ptr.hpp
More file actions
224 lines (194 loc) · 8.03 KB
/
object_ptr.hpp
File metadata and controls
224 lines (194 loc) · 8.03 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
#ifndef JSS_OBJECT_PTR_HPP
#define JSS_OBJECT_PTR_HPP
#include <cstddef>
#include <utility>
#include <functional>
#include <memory>
#include <type_traits>
namespace jss {
namespace detail {
/// Detect the presence of operator*, operator-> and .get() for the
/// given type
template <typename Ptr, bool= std::is_class<Ptr>::value>
struct has_smart_pointer_ops {
using false_test= char;
template <typename T> struct true_test { false_test dummy[2]; };
template <typename T> static false_test test_op_star(...);
template <typename T>
static true_test<decltype(*std::declval<T const &>())>
test_op_star(T *);
template <typename T> static false_test test_op_arrow(...);
template <typename T>
static true_test<decltype(std::declval<T const &>().operator->())>
test_op_arrow(T *);
template <typename T> static false_test test_get(...);
template <typename T>
static true_test<decltype(std::declval<T const &>().get())>
test_get(T *);
static constexpr bool value=
!std::is_same<decltype(test_get<Ptr>(0)), false_test>::value &&
!std::is_same<
decltype(test_op_arrow<Ptr>(0)), false_test>::value &&
!std::is_same<
decltype(test_op_star<Ptr>(0)), false_test>::value;
};
/// Non-class types can't be smart pointers
template <typename Ptr>
struct has_smart_pointer_ops<Ptr, false> : std::false_type {};
/// Ensure that the smart pointer operations give consistent return
/// types
template <typename Ptr>
struct smart_pointer_ops_consistent
: std::integral_constant<
bool,
std::is_pointer<decltype(
std::declval<Ptr const &>().get())>::value &&
std::is_reference<decltype(
*std::declval<Ptr const &>())>::value &&
std::is_pointer<decltype(
std::declval<Ptr const &>().operator->())>::value &&
std::is_same<
decltype(std::declval<Ptr const &>().get()),
decltype(std::declval<Ptr const &>().
operator->())>::value &&
std::is_same<
decltype(*std::declval<Ptr const &>().get()),
decltype(*std::declval<Ptr const &>())>::value> {};
/// Assume Ptr is a smart pointer if it has the relevant ops and they
/// are consistent
template <typename Ptr, bool= has_smart_pointer_ops<Ptr>::value>
struct is_smart_pointer
: std::integral_constant<
bool, smart_pointer_ops_consistent<Ptr>::value> {};
/// If Ptr doesn't have the relevant ops then it can't be a smart
/// pointer
template <typename Ptr>
struct is_smart_pointer<Ptr, false> : std::false_type {};
/// Check if Ptr is a smart pointer that holds a pointer convertible to
/// T*
template <typename Ptr, typename T, bool= is_smart_pointer<Ptr>::value>
struct is_convertible_smart_pointer
: std::integral_constant<
bool, std::is_convertible<
decltype(std::declval<Ptr const &>().get()),
T *>::value> {};
/// If Ptr isn't a smart pointer then we don't want it
template <typename Ptr, typename T>
struct is_convertible_smart_pointer<Ptr, T, false> : std::false_type {};
}
/// A basic "smart" pointer that points to an individual object it does not
/// own. Unlike a raw pointer, it does not support pointer arithmetic or
/// array operations, and the pointee cannot be accidentally deleted. It
/// supports implicit conversion from any smart pointer that holds a pointer
/// convertible to T*
template <typename T> class object_ptr {
public:
/// Construct a null pointer
constexpr object_ptr() noexcept : ptr(nullptr) {}
/// Construct a null pointer
constexpr object_ptr(std::nullptr_t) noexcept : ptr(nullptr) {}
/// Construct an object_ptr from a raw pointer
constexpr object_ptr(T *ptr_) noexcept : ptr(ptr_) {}
/// Construct an object_ptr from a raw pointer convertible to T*, such
/// as BaseOfT*
template <
typename U,
typename= std::enable_if_t<std::is_convertible<U *, T *>::value>>
constexpr object_ptr(U *ptr_) noexcept : ptr(ptr_) {}
/// Construct an object_ptr from a smart pointer that holds a pointer
/// convertible to T*,
/// such as shared_ptr<T> or unique_ptr<BaseOfT>
template <
typename Ptr,
typename= std::enable_if_t<
detail::is_convertible_smart_pointer<Ptr, T>::value>>
constexpr object_ptr(Ptr const &other) noexcept : ptr(other.get()) {}
/// Get the raw pointer value
constexpr T *get() const noexcept {
return ptr;
}
/// Dereference the pointer
constexpr T &operator*() const noexcept {
return *ptr;
}
/// Dereference the pointer for ptr->m usage
constexpr T *operator->() const noexcept {
return ptr;
}
/// Allow if(ptr) to test for null
constexpr explicit operator bool() const noexcept {
return ptr != nullptr;
}
/// Convert to a raw pointer where necessary
constexpr explicit operator T *() const noexcept {
return ptr;
}
/// !ptr is true iff ptr is null
constexpr bool operator!() const noexcept {
return !ptr;
}
/// Change the value
void reset(T *ptr_= nullptr) noexcept {
ptr= ptr_;
}
/// Check for equality
friend constexpr bool
operator==(object_ptr const &lhs, object_ptr const &rhs) noexcept {
return lhs.ptr == rhs.ptr;
}
/// Check for inequality
friend constexpr bool
operator!=(object_ptr const &lhs, object_ptr const &rhs) noexcept {
return !(lhs == rhs);
}
/// a<b provides a total order
friend constexpr bool
operator<(object_ptr const &lhs, object_ptr const &rhs) noexcept {
return std::less<void>()(lhs.ptr, rhs.ptr);
}
/// a>b is b<a
friend constexpr bool
operator>(object_ptr const &lhs, object_ptr const &rhs) noexcept {
return rhs < lhs;
}
/// a<=b is !(b<a)
friend constexpr bool
operator<=(object_ptr const &lhs, object_ptr const &rhs) noexcept {
return !(rhs < lhs);
}
/// a<=b is b<=a
friend constexpr bool
operator>=(object_ptr const &lhs, object_ptr const &rhs) noexcept {
return rhs <= lhs;
}
private:
/// The stored pointer
T *ptr;
};
}
namespace std {
/// Allow hashing object_ptrs so they can be used as keys in unordered_map
template <typename T> struct hash<jss::object_ptr<T>> {
constexpr size_t operator()(jss::object_ptr<T> const &p) const
noexcept {
return hash<T *>()(p.get());
}
};
/// Do a static_cast with object_ptr
template <typename To, typename From>
typename std::enable_if<
sizeof(decltype(static_cast<To *>(std::declval<From *>()))) != 0,
jss::object_ptr<To>>::type
static_pointer_cast(jss::object_ptr<From> p) {
return static_cast<To *>(p.get());
}
/// Do a dynamic_cast with object_ptr
template <typename To, typename From>
typename std::enable_if<
sizeof(decltype(dynamic_cast<To *>(std::declval<From *>()))) != 0,
jss::object_ptr<To>>::type
dynamic_pointer_cast(jss::object_ptr<From> p) {
return dynamic_cast<To *>(p.get());
}
}
#endif