Sourcemeta Core 0.0.0
Loading...
Searching...
No Matches
memory_owned_or_reference.h
1#ifndef SOURCEMETA_CORE_MEMORY_OWNED_OR_REFERENCE_H_
2#define SOURCEMETA_CORE_MEMORY_OWNED_OR_REFERENCE_H_
3
4#include <cassert> // assert
5#include <concepts> // std::move_constructible, std::copy_constructible
6#include <memory> // std::addressof
7#include <optional> // std::optional, std::nullopt_t
8#include <type_traits> // std::is_object_v
9#include <utility> // std::move
10
11namespace sourcemeta::core {
12
15template <typename T>
16concept Ownable = std::is_object_v<T> && std::move_constructible<T>;
17
48template <Ownable T> class OwnedOrReference {
49public:
51 OwnedOrReference() = default;
52
54 // NOLINTNEXTLINE(google-explicit-constructor,hicpp-explicit-conversions)
55 OwnedOrReference([[maybe_unused]] const std::nullopt_t value) {}
56
58 // NOLINTNEXTLINE(google-explicit-constructor,hicpp-explicit-conversions)
59 OwnedOrReference(std::optional<T> &&value) : owned_{std::move(value)} {}
60
62 // NOLINTNEXTLINE(google-explicit-constructor,hicpp-explicit-conversions)
63 OwnedOrReference(T &&value) : owned_{std::move(value)} {}
64
67 // NOLINTNEXTLINE(google-explicit-constructor,hicpp-explicit-conversions)
68 OwnedOrReference(const T &value) : referenced_{std::addressof(value)} {}
69
70 // A constant temporary would otherwise bind to the referencing constructor
71 // and leave a dangling pointer behind
72 OwnedOrReference(const T &&value) = delete;
73
74 // Prevent accidental copies, as copying is the very thing this type exists
75 // to avoid. Take ownership through `to_owned` instead
76 OwnedOrReference(const OwnedOrReference &) = delete;
77 auto operator=(const OwnedOrReference &) -> OwnedOrReference & = delete;
81 auto operator=(OwnedOrReference &&) -> OwnedOrReference & = default;
82 ~OwnedOrReference() = default;
83
85 [[nodiscard]] auto has_value() const noexcept -> bool {
86 return this->referenced_ != nullptr || this->owned_.has_value();
87 }
88
90 [[nodiscard]] auto value() const -> const T & {
91 assert(this->has_value());
92 return this->referenced_ != nullptr ? *this->referenced_
93 : this->owned_.value();
94 }
95
97 [[nodiscard]] auto operator*() const -> const T & { return this->value(); }
98
100 [[nodiscard]] auto operator->() const -> const T * {
101 return std::addressof(this->value());
102 }
103
106 [[nodiscard]] auto to_owned() && -> T
107 requires std::copy_constructible<T>
108 {
109 assert(this->has_value());
110 if (this->referenced_ != nullptr) {
111 return *this->referenced_;
112 }
113
114 return std::move(this->owned_).value();
115 }
116
117private:
118 std::optional<T> owned_;
119 const T *referenced_{nullptr};
120};
121
122} // namespace sourcemeta::core
123
124#endif
Definition memory_owned_or_reference.h:16
auto has_value() const noexcept -> bool
Whether there is anything to read.
Definition memory_owned_or_reference.h:85
auto value() const -> const T &
Definition memory_owned_or_reference.h:90
OwnedOrReference(std::optional< T > &&value)
Take ownership of a value that may or may not be there.
Definition memory_owned_or_reference.h:59
OwnedOrReference(T &&value)
Take ownership of a value.
Definition memory_owned_or_reference.h:63
OwnedOrReference(OwnedOrReference &&)=default
Move.
OwnedOrReference(const std::nullopt_t value)
Hold nothing.
Definition memory_owned_or_reference.h:55
auto to_owned() &&-> T
Definition memory_owned_or_reference.h:106
OwnedOrReference()=default
Hold nothing.
OwnedOrReference(const T &value)
Definition memory_owned_or_reference.h:68
Definition memory_owned_or_reference.h:48