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 instance) {
14 typename Type::element_type;
15 requires std::same_as<typename Type::element_type, Value>;
16 { instance.get() } -> std::same_as<Value*>;
28template<
typename Type>
33 using value_type = Type;
34 using pointer = value_type*;
35 using const_pointer =
const value_type*;
45 template<smart_po
inter<value_type> Po
inter>
47 : _value{value.get()} { }
49 template<
typename Other>
50 requires (std::is_convertible_v<Other*, pointer>)
52 : _value{
reinterpret_cast<pointer
>(other.get())} { }
64 constexpr auto operator=(std::nullptr_t)
noexcept ->
observer_ptr& {
69 constexpr auto operator=(pointer value)
noexcept ->
observer_ptr& {
74 constexpr auto release()
noexcept -> pointer {
80 constexpr auto reset(pointer value =
nullptr)
noexcept ->
void {
84 constexpr auto swap(
observer_ptr& other)
noexcept ->
void {
85 std::swap(_value, other._value);
88 constexpr auto is_valid()
const noexcept ->
bool {
89 return _value !=
nullptr;
92 constexpr operator bool()
const noexcept {
96 constexpr auto operator->()
const noexcept -> const_pointer {
97 utility::assert_that(is_valid(),
"Cannot dereference a null pointer.");
101 constexpr auto operator->()
noexcept -> pointer {
102 utility::assert_that(is_valid(),
"Cannot dereference a null pointer.");
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.");
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.");
116 constexpr auto get()
const noexcept -> const_pointer {
120 constexpr auto get()
noexcept -> pointer {
140template<
typename Type>
142 return lhs.get() == rhs.get();
145template<
typename Type>
146constexpr auto operator==(
const observer_ptr<Type>& lhs, std::nullptr_t)
noexcept ->
bool {
147 return lhs.get() ==
nullptr;
150template<
typename Type, smart_po
inter<Type> Po
inter>
151constexpr auto operator==(
const observer_ptr<Type>& lhs,
const Pointer& rhs)
noexcept ->
bool {
152 return lhs.get() == rhs.get();
165template<
typename Type>
166constexpr auto make_observer(Type* value)
noexcept -> observer_ptr<Type> {
167 return observer_ptr<Type>{value};
170template<
typename Type>
171constexpr auto make_observer(Type& value)
noexcept -> observer_ptr<Type> {
172 return observer_ptr<Type>{std::addressof(value)};
175template<
typename Type, smart_po
inter<Type> Po
inter>
176constexpr auto make_observer(Pointer& value)
noexcept -> observer_ptr<Type> {
177 return observer_ptr<Type>{value.get()};
182template<
typename Type>
183struct std::hash<sbx::memory::observer_ptr<Type>> {
185 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:29