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