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