blob: e245d88c1c8a83d473392d8331ed067ab2a7b76e [file] [log] [blame]
Dominik Laskowskia7e22552022-08-01 08:23:34 -07001/*
2 * Copyright 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#pragma once
18
19#include <functional>
20#include <optional>
Dominik Laskowskia7e22552022-08-01 08:23:34 -070021#include <utility>
22
Dominik Laskowski189d1822024-05-03 17:30:26 -040023#include <android-base/expected.h>
Dominik Laskowskia957c1c2022-08-03 12:51:43 -070024#include <ftl/details/optional.h>
25
Dominik Laskowskia7e22552022-08-01 08:23:34 -070026namespace android::ftl {
27
28// Superset of std::optional<T> with monadic operations, as proposed in https://wg21.link/P0798R8.
29//
Dominik Laskowski189d1822024-05-03 17:30:26 -040030// TODO: Remove standard APIs in C++23.
Dominik Laskowskia7e22552022-08-01 08:23:34 -070031//
32template <typename T>
33struct Optional final : std::optional<T> {
34 using std::optional<T>::optional;
35
Dominik Laskowskid48d8012022-08-23 08:36:32 -070036 // Implicit downcast.
37 Optional(std::optional<T> other) : std::optional<T>(std::move(other)) {}
38
Dominik Laskowskia7e22552022-08-01 08:23:34 -070039 using std::optional<T>::has_value;
40 using std::optional<T>::value;
41
42 // Returns Optional<U> where F is a function that maps T to U.
43 template <typename F>
44 constexpr auto transform(F&& f) const& {
Dominik Laskowskia957c1c2022-08-03 12:51:43 -070045 using R = details::transform_result_t<F, decltype(value())>;
46 if (has_value()) return R(std::invoke(std::forward<F>(f), value()));
47 return R();
Dominik Laskowskia7e22552022-08-01 08:23:34 -070048 }
49
50 template <typename F>
51 constexpr auto transform(F&& f) & {
Dominik Laskowskia957c1c2022-08-03 12:51:43 -070052 using R = details::transform_result_t<F, decltype(value())>;
53 if (has_value()) return R(std::invoke(std::forward<F>(f), value()));
54 return R();
Dominik Laskowskia7e22552022-08-01 08:23:34 -070055 }
56
57 template <typename F>
58 constexpr auto transform(F&& f) const&& {
Dominik Laskowskia957c1c2022-08-03 12:51:43 -070059 using R = details::transform_result_t<F, decltype(std::move(value()))>;
60 if (has_value()) return R(std::invoke(std::forward<F>(f), std::move(value())));
61 return R();
Dominik Laskowskia7e22552022-08-01 08:23:34 -070062 }
63
64 template <typename F>
65 constexpr auto transform(F&& f) && {
Dominik Laskowskia957c1c2022-08-03 12:51:43 -070066 using R = details::transform_result_t<F, decltype(std::move(value()))>;
67 if (has_value()) return R(std::invoke(std::forward<F>(f), std::move(value())));
68 return R();
69 }
70
71 // Returns Optional<U> where F is a function that maps T to Optional<U>.
72 template <typename F>
73 constexpr auto and_then(F&& f) const& {
74 using R = details::and_then_result_t<F, decltype(value())>;
75 if (has_value()) return std::invoke(std::forward<F>(f), value());
76 return R();
77 }
78
79 template <typename F>
80 constexpr auto and_then(F&& f) & {
81 using R = details::and_then_result_t<F, decltype(value())>;
82 if (has_value()) return std::invoke(std::forward<F>(f), value());
83 return R();
84 }
85
86 template <typename F>
87 constexpr auto and_then(F&& f) const&& {
88 using R = details::and_then_result_t<F, decltype(std::move(value()))>;
89 if (has_value()) return std::invoke(std::forward<F>(f), std::move(value()));
90 return R();
91 }
92
93 template <typename F>
94 constexpr auto and_then(F&& f) && {
95 using R = details::and_then_result_t<F, decltype(std::move(value()))>;
96 if (has_value()) return std::invoke(std::forward<F>(f), std::move(value()));
97 return R();
Dominik Laskowskia7e22552022-08-01 08:23:34 -070098 }
Leon Scroggins IIIb19461b2022-12-01 12:33:43 -050099
Dominik Laskowski07a71cd2022-09-28 10:38:46 -0400100 // Returns this Optional<T> if not nullopt, or else the Optional<T> returned by the function F.
101 template <typename F>
102 constexpr auto or_else(F&& f) const& -> details::or_else_result_t<F, T> {
103 if (has_value()) return *this;
104 return std::forward<F>(f)();
105 }
106
107 template <typename F>
108 constexpr auto or_else(F&& f) && -> details::or_else_result_t<F, T> {
109 if (has_value()) return std::move(*this);
110 return std::forward<F>(f)();
111 }
112
Dominik Laskowski189d1822024-05-03 17:30:26 -0400113 // Maps this Optional<T> to expected<T, E> where nullopt becomes E.
114 template <typename E>
115 constexpr auto ok_or(E&& e) && -> base::expected<T, E> {
116 if (has_value()) return std::move(value());
117 return base::unexpected(std::forward<E>(e));
118 }
119
Leon Scroggins IIIb19461b2022-12-01 12:33:43 -0500120 // Delete new for this class. Its base doesn't have a virtual destructor, and
121 // if it got deleted via base class pointer, it would cause undefined
122 // behavior. There's not a good reason to allocate this object on the heap
123 // anyway.
124 static void* operator new(size_t) = delete;
125 static void* operator new[](size_t) = delete;
Dominik Laskowskia7e22552022-08-01 08:23:34 -0700126};
127
Ady Abrahamf28341e2022-11-22 10:13:38 -0800128template <typename T, typename U>
129constexpr bool operator==(const Optional<T>& lhs, const Optional<U>& rhs) {
130 return static_cast<std::optional<T>>(lhs) == static_cast<std::optional<U>>(rhs);
131}
132
133template <typename T, typename U>
134constexpr bool operator!=(const Optional<T>& lhs, const Optional<U>& rhs) {
135 return !(lhs == rhs);
136}
137
Dominik Laskowskid48d8012022-08-23 08:36:32 -0700138// Deduction guides.
Dominik Laskowskia7e22552022-08-01 08:23:34 -0700139template <typename T>
140Optional(T) -> Optional<T>;
141
Dominik Laskowskid48d8012022-08-23 08:36:32 -0700142template <typename T>
143Optional(std::optional<T>) -> Optional<T>;
144
Dominik Laskowskia7e22552022-08-01 08:23:34 -0700145} // namespace android::ftl