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