2#ifndef LIBSBX_MEMORY_OBSERVER_PTR_HPP_
3#define LIBSBX_MEMORY_OBSERVER_PTR_HPP_
8#include <libsbx/utility/assert.hpp>
10namespace sbx::memory {
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>;
27template<
typename Type>
32 using value_type = Type;
33 using pointer = value_type*;
34 using const_pointer =
const value_type*;
44 template<smart_po
inter<value_type> Po
inter>
46 : _value{value.get()} { }
48 template<
typename Other>
49 requires (std::is_convertible_v<Other*, pointer>)
51 : _value{
reinterpret_cast<pointer
>(other.get())} { }
63 constexpr auto operator=(std::nullptr_t)
noexcept ->
observer_ptr& {
68 constexpr auto operator=(pointer value)
noexcept ->
observer_ptr& {
73 constexpr auto release()
noexcept -> pointer {
79 constexpr auto reset(pointer value =
nullptr)
noexcept ->
void {
83 constexpr auto swap(
observer_ptr& other)
noexcept ->
void {
84 std::swap(_value, other._value);
87 constexpr auto is_valid()
const noexcept ->
bool {
88 return _value !=
nullptr;
91 constexpr operator bool()
const noexcept {
95 constexpr auto operator->()
const noexcept -> const_pointer {
96 utility::assert_that(is_valid(),
"Cannot dereference a null pointer.");
100 constexpr auto operator->()
noexcept -> pointer {
101 utility::assert_that(is_valid(),
"Cannot dereference a null pointer.");
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.");
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.");
115 constexpr auto get()
const noexcept -> const_pointer {
119 constexpr auto get()
noexcept -> pointer {
139template<
typename Type>
141 return lhs.get() == rhs.get();
144template<
typename Type>
145constexpr auto operator==(
const observer_ptr<Type>& lhs, std::nullptr_t)
noexcept ->
bool {
146 return lhs.get() ==
nullptr;
149template<
typename Type, smart_po
inter<Type> Po
inter>
150constexpr auto operator==(
const observer_ptr<Type>& lhs,
const Pointer& rhs)
noexcept ->
bool {
151 return lhs.get() == rhs.get();
164template<
typename Type>
165constexpr auto make_observer(Type* value)
noexcept -> observer_ptr<Type> {
166 return observer_ptr<Type>{value};
169template<
typename Type>
170constexpr auto make_observer(Type& value)
noexcept -> observer_ptr<Type> {
171 return observer_ptr<Type>{std::addressof(value)};
174template<
typename Type, smart_po
inter<Type> Po
inter>
175constexpr auto make_observer(Pointer& value)
noexcept -> observer_ptr<Type> {
176 return observer_ptr<Type>{value.get()};
181template<
typename Type>
182struct std::hash<sbx::memory::observer_ptr<Type>> {
184 return std::hash<std::uintptr_t>{}(
reinterpret_cast<std::uintptr_t
>(value.get()));
A non-owning pointer that can be used to observe the value of a pointer.
Definition: observer_ptr.hpp:28