LeviLamina
Loading...
Searching...
No Matches
optional_ref.h
1#pragma once
2
3#include <optional>
4#include <stdexcept>
5#include <type_traits>
6
7#include "ll/api/base/Meta.h"
8
9template <typename T>
10class optional_ref {
11private:
12 T* mPtr = nullptr;
13 // NOLINTBEGIN
14 static_assert(!std::is_reference_v<T>);
15
16public:
17 [[nodiscard]] constexpr optional_ref() noexcept = default;
18
19 [[nodiscard]] constexpr optional_ref(std::nullopt_t) noexcept {}
20
21 [[nodiscard]] constexpr optional_ref(std::nullptr_t) noexcept {}
22
23
24 template <class U>
25 requires(std::is_convertible_v<U*, T*>)
26 constexpr optional_ref(U const&& r) noexcept = delete;
27
28
29 template <class U>
30 requires(std::is_convertible_v<U*, T*>)
31 [[nodiscard]] constexpr optional_ref(std::optional<U>& o) noexcept : mPtr(o ? std::addressof(*o) : nullptr) {}
32
33
34 template <class U>
35 requires(std::is_convertible_v<U*, T*>)
36 [[nodiscard]] constexpr optional_ref(U* p) noexcept : mPtr(p) {}
37
38
39 template <class U>
40 requires(std::is_convertible_v<U*, T*>)
41 [[nodiscard]] constexpr optional_ref(U& r) noexcept : mPtr(std::addressof(r)) {}
42
43
44 template <class U>
45 requires(std::is_convertible_v<U*, T*>)
46 [[nodiscard]] constexpr optional_ref(U const& r) noexcept : mPtr(std::addressof(r)) {}
47
48
49 template <class U>
50 requires(std::is_convertible_v<U*, T*>)
51 [[nodiscard]] constexpr optional_ref(const std::optional<U>& o) noexcept : mPtr(o ? &*o : nullptr) {}
52
53 template <typename U>
54 requires(std::is_convertible_v<U*, T*>)
55 [[nodiscard]] constexpr optional_ref(optional_ref<U> rhs) noexcept : mPtr(rhs.as_ptr()) {}
56
57 [[nodiscard]] constexpr optional_ref(optional_ref&&) noexcept = default;
58
59 LL_MAY_CONSTEXPR optional_ref& operator=(optional_ref&&) noexcept = default;
60
61 [[nodiscard]] constexpr optional_ref(optional_ref const&) noexcept = default;
62
63 LL_MAY_CONSTEXPR optional_ref& operator=(optional_ref const&) noexcept = default;
64
65 [[nodiscard]] constexpr explicit operator bool() const noexcept { return mPtr != nullptr; }
66
67 [[nodiscard]] constexpr bool has_value() const noexcept { return mPtr != nullptr; }
68
69 [[nodiscard]] constexpr T* as_ptr() const noexcept { return mPtr; }
70
71 [[nodiscard]] constexpr T& value() const {
72 if (!has_value()) {
73 throw std::bad_optional_access{};
74 }
75 return *mPtr;
76 }
77
78 [[nodiscard]] constexpr T& get() const { return value(); }
79 [[nodiscard]] constexpr T& operator*() const noexcept { return *as_ptr(); }
80 [[nodiscard]] constexpr T* operator->() const noexcept { return as_ptr(); }
81
82 [[nodiscard]] constexpr operator T&() const { return value(); }
83 [[nodiscard]] constexpr operator T*() const noexcept { return as_ptr(); }
84
85 template <class U>
86 [[nodiscard]] constexpr T& value_or(U& right) const& {
87 if (has_value()) {
88 return *mPtr;
89 }
90 return static_cast<T&>(right);
91 }
92
93 template <class U>
94 [[nodiscard]] constexpr T value_or(U&& right) const&& {
95 if (has_value()) {
96 return *mPtr;
97 }
98 return std::forward<U>(right);
99 }
100
101 template <typename U = std::decay_t<T>>
102 requires(std::is_constructible_v<U, T>)
103 [[nodiscard]] constexpr std::optional<U> copy_as_optional() const {
104 return mPtr ? std::optional<U>(*mPtr) : std::nullopt;
105 }
106
107 template <class... Types>
108 constexpr decltype(auto)
109 operator()(Types&&... args) const noexcept(noexcept(std::invoke(value(), static_cast<Types&&>(args)...))) {
110 return (std::invoke(value(), static_cast<Types&&>(args)...));
111 }
112 template <class Arg>
113 [[nodiscard]] constexpr decltype(auto) operator[](Arg&& index) const {
114 return (value()[std::forward<Arg>(index)]);
115 }
116 [[nodiscard]] constexpr decltype(auto) end() const { return (value().end()); }
117 [[nodiscard]] constexpr decltype(auto) begin() const { return (value().begin()); }
118 [[nodiscard]] constexpr decltype(auto) cend() const { return (value().cend()); }
119 [[nodiscard]] constexpr decltype(auto) cbegin() const { return (value().cbegin()); }
120 [[nodiscard]] constexpr decltype(auto) rend() const { return (value().rend()); }
121 [[nodiscard]] constexpr decltype(auto) rbegin() const { return (value().rbegin()); }
122 [[nodiscard]] constexpr decltype(auto) crend() const { return (value().crend()); }
123 [[nodiscard]] constexpr decltype(auto) crbegin() const { return (value().crbegin()); }
124
125 template <class Fn>
126 constexpr auto and_then(Fn&& fn) const {
127 using Ret = std::invoke_result_t<Fn, T&>;
128 if (has_value()) {
129 return std::invoke(std::forward<Fn>(fn), static_cast<T&>(*mPtr));
130 } else {
131 return std::remove_cvref_t<Ret>{};
132 }
133 }
134 template <class Fn>
135 constexpr auto transform(Fn&& fn) const {
136 using Ret = std::invoke_result_t<Fn, T&>;
137 if constexpr (std::is_lvalue_reference_v<Ret> || std::is_pointer_v<Ret>) {
138 using UnwrapT = std::remove_pointer_t<std::remove_reference_t<Ret>>;
139 if (has_value()) {
140 return optional_ref<UnwrapT>{std::invoke(std::forward<Fn>(fn), static_cast<T&>(*mPtr))};
141 } else {
142 return optional_ref<UnwrapT>{};
143 }
144 } else {
145 using UnwrapT = std::remove_cv_t<Ret>;
146 if (has_value()) {
147 return std::optional<UnwrapT>{ll::meta::elide(std::forward<Fn>(fn), static_cast<T&>(*mPtr))};
148 } else {
149 return std::optional<UnwrapT>{};
150 }
151 }
152 }
153 template <std::invocable<> Fn>
154 constexpr auto or_else(Fn&& fn) const -> std::invoke_result_t<Fn> {
155 if (has_value()) {
156 return *this;
157 } else {
158 return std::invoke(std::forward<Fn>(fn));
159 }
160 }
161};
162// NOLINTEND
163template <typename T>
165
166template <typename T>
168
169template <typename T>
170optional_ref(std::optional<T> const&) -> optional_ref<const T>;
171
172template <typename T>
173optional_ref(std::optional<T>&) -> optional_ref<T>;
174
175template <typename T>
Definition Meta.h:247
Definition optional_ref.h:10