sandbox
Loading...
Searching...
No Matches
observer_ptr.hpp
1#ifndef LIBSBX_MEMORY_OBSERVER_PTR_HPP_
2#define LIBSBX_MEMORY_OBSERVER_PTR_HPP_
3
4#include <memory>
5#include <utility>
6
7#include <libsbx/utility/assert.hpp>
8
9namespace sbx::memory {
10
11template<typename Type, typename Value>
12concept smart_pointer = requires(Type t, Value v) {
13 { Type::value_type} -> std::same_as<Value>;
14 { t.get() } -> std::same_as<Value>;
15}; // concept smart_pointer
16
26template<typename Type>
28
29public:
30
31 using value_type = Type;
32 using pointer = value_type*;
33 using const_pointer = const value_type*;
34
35 constexpr observer_ptr() noexcept = default;
36
37 constexpr observer_ptr(std::nullptr_t) noexcept
38 : _value{nullptr} { }
39
40 constexpr observer_ptr(pointer value) noexcept
41 : _value{value} { }
42
43 template<smart_pointer<value_type> Pointer>
44 constexpr observer_ptr(const Pointer& value) noexcept
45 : _value{value.get()} { }
46
47 template<typename Other>
48 requires (std::is_convertible_v<Other*, pointer>)
49 constexpr observer_ptr(observer_ptr<Other>& other) noexcept
50 : _value{reinterpret_cast<pointer>(other.get())} { }
51
52 constexpr observer_ptr(const observer_ptr&) noexcept = default;
53
54 constexpr observer_ptr(observer_ptr&&) noexcept = default;
55
56 constexpr ~observer_ptr() noexcept = default;
57
58 constexpr auto operator=(const observer_ptr&) noexcept -> observer_ptr& = default;
59
60 constexpr auto operator=(observer_ptr&&) noexcept -> observer_ptr& = default;
61
62 constexpr auto operator=(std::nullptr_t) noexcept -> observer_ptr& {
63 _value = nullptr;
64 return *this;
65 }
66
67 constexpr auto operator=(pointer value) noexcept -> observer_ptr& {
68 _value = value;
69 return *this;
70 }
71
72 constexpr auto release() noexcept -> pointer {
73 auto value = _value;
74 _value = nullptr;
75 return value;
76 }
77
78 constexpr auto reset(pointer value = nullptr) noexcept -> void {
79 _value = value;
80 }
81
82 constexpr auto swap(observer_ptr& other) noexcept -> void {
83 std::swap(_value, other._value);
84 }
85
86 constexpr auto is_valid() const noexcept -> bool {
87 return _value != nullptr;
88 }
89
90 constexpr operator bool() const noexcept {
91 return is_valid();
92 }
93
94 constexpr auto operator->() const noexcept -> const_pointer {
95 utility::assert_that(is_valid(), "Cannot dereference a null pointer.");
96 return _value;
97 }
98
99 constexpr auto operator->() noexcept -> pointer {
100 utility::assert_that(is_valid(), "Cannot dereference a null pointer.");
101 return _value;
102 }
103
104 constexpr auto operator*() const noexcept(noexcept(*std::declval<pointer>())) -> std::add_const_t<std::add_lvalue_reference_t<value_type>> {
105 utility::assert_that(is_valid(), "Cannot dereference a null pointer.");
106 return *_value;
107 }
108
109 constexpr auto operator*() noexcept(noexcept(*std::declval<pointer>())) -> std::add_lvalue_reference_t<value_type> {
110 utility::assert_that(is_valid(), "Cannot dereference a null pointer.");
111 return *_value;
112 }
113
114 constexpr auto get() const noexcept -> const_pointer {
115 return _value;
116 }
117
118 constexpr auto get() noexcept -> pointer {
119 return _value;
120 }
121
122private:
123
124 pointer _value{};
125
126}; // class observer_ptr
127
138template<typename Type>
139constexpr auto operator==(const observer_ptr<Type>& lhs, const observer_ptr<Type>& rhs) noexcept -> bool {
140 return lhs.get() == rhs.get();
141}
142
143template<typename Type, smart_pointer<Type> Pointer>
144constexpr auto operator==(const observer_ptr<Type>& lhs, const Pointer& rhs) noexcept -> bool {
145 return lhs.get() == rhs.get();
146}
147
157template<typename Type>
158constexpr auto make_observer(Type* value) noexcept -> observer_ptr<Type> {
159 return observer_ptr<Type>{value};
160}
161
162template<typename Type>
163constexpr auto make_observer(Type& value) noexcept -> observer_ptr<Type> {
164 return observer_ptr<Type>{std::addressof(value)};
165}
166
167template<typename Type, smart_pointer<Type> Pointer>
168constexpr auto make_observer(Pointer& value) noexcept -> observer_ptr<Type> {
169 return observer_ptr<Type>{value.get()};
170}
171
172} // namespace sbx::memory
173
174template<typename Type>
175struct std::hash<sbx::memory::observer_ptr<Type>> {
176 constexpr auto operator()(const sbx::memory::observer_ptr<Type>& value) const noexcept -> std::size_t {
177 return std::hash<Type*>{}(value.get());
178 }
179};
180
181#endif // LIBSBX_MEMORY_OBSERVER_PTR_HPP_
A non-owning pointer that can be used to observe the value of a pointer.
Definition: observer_ptr.hpp:27