xref: /aosp_15_r20/frameworks/native/include/ftl/optional.h (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker  * Copyright 2022 The Android Open Source Project
3*38e8c45fSAndroid Build Coastguard Worker  *
4*38e8c45fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*38e8c45fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*38e8c45fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*38e8c45fSAndroid Build Coastguard Worker  *
8*38e8c45fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*38e8c45fSAndroid Build Coastguard Worker  *
10*38e8c45fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*38e8c45fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*38e8c45fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*38e8c45fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*38e8c45fSAndroid Build Coastguard Worker  * limitations under the License.
15*38e8c45fSAndroid Build Coastguard Worker  */
16*38e8c45fSAndroid Build Coastguard Worker 
17*38e8c45fSAndroid Build Coastguard Worker #pragma once
18*38e8c45fSAndroid Build Coastguard Worker 
19*38e8c45fSAndroid Build Coastguard Worker #include <functional>
20*38e8c45fSAndroid Build Coastguard Worker #include <optional>
21*38e8c45fSAndroid Build Coastguard Worker #include <utility>
22*38e8c45fSAndroid Build Coastguard Worker 
23*38e8c45fSAndroid Build Coastguard Worker #include <android-base/expected.h>
24*38e8c45fSAndroid Build Coastguard Worker #include <ftl/details/optional.h>
25*38e8c45fSAndroid Build Coastguard Worker 
26*38e8c45fSAndroid Build Coastguard Worker namespace android::ftl {
27*38e8c45fSAndroid Build Coastguard Worker 
28*38e8c45fSAndroid Build Coastguard Worker // Superset of std::optional<T> with monadic operations, as proposed in https://wg21.link/P0798R8.
29*38e8c45fSAndroid Build Coastguard Worker //
30*38e8c45fSAndroid Build Coastguard Worker // TODO: Remove standard APIs in C++23.
31*38e8c45fSAndroid Build Coastguard Worker //
32*38e8c45fSAndroid Build Coastguard Worker template <typename T>
33*38e8c45fSAndroid Build Coastguard Worker struct Optional final : std::optional<T> {
34*38e8c45fSAndroid Build Coastguard Worker   using std::optional<T>::optional;
35*38e8c45fSAndroid Build Coastguard Worker 
36*38e8c45fSAndroid Build Coastguard Worker   // Implicit downcast.
Optionalfinal37*38e8c45fSAndroid Build Coastguard Worker   Optional(std::optional<T> other) : std::optional<T>(std::move(other)) {}
38*38e8c45fSAndroid Build Coastguard Worker 
39*38e8c45fSAndroid Build Coastguard Worker   using std::optional<T>::has_value;
40*38e8c45fSAndroid Build Coastguard Worker   using std::optional<T>::value;
41*38e8c45fSAndroid Build Coastguard Worker 
42*38e8c45fSAndroid Build Coastguard Worker   // Returns Optional<U> where F is a function that maps T to U.
43*38e8c45fSAndroid Build Coastguard Worker   template <typename F>
transformfinal44*38e8c45fSAndroid Build Coastguard Worker   constexpr auto transform(F&& f) const& {
45*38e8c45fSAndroid Build Coastguard Worker     using R = details::transform_result_t<F, decltype(value())>;
46*38e8c45fSAndroid Build Coastguard Worker     if (has_value()) return R(std::invoke(std::forward<F>(f), value()));
47*38e8c45fSAndroid Build Coastguard Worker     return R();
48*38e8c45fSAndroid Build Coastguard Worker   }
49*38e8c45fSAndroid Build Coastguard Worker 
50*38e8c45fSAndroid Build Coastguard Worker   template <typename F>
transformfinal51*38e8c45fSAndroid Build Coastguard Worker   constexpr auto transform(F&& f) & {
52*38e8c45fSAndroid Build Coastguard Worker     using R = details::transform_result_t<F, decltype(value())>;
53*38e8c45fSAndroid Build Coastguard Worker     if (has_value()) return R(std::invoke(std::forward<F>(f), value()));
54*38e8c45fSAndroid Build Coastguard Worker     return R();
55*38e8c45fSAndroid Build Coastguard Worker   }
56*38e8c45fSAndroid Build Coastguard Worker 
57*38e8c45fSAndroid Build Coastguard Worker   template <typename F>
transformfinal58*38e8c45fSAndroid Build Coastguard Worker   constexpr auto transform(F&& f) const&& {
59*38e8c45fSAndroid Build Coastguard Worker     using R = details::transform_result_t<F, decltype(std::move(value()))>;
60*38e8c45fSAndroid Build Coastguard Worker     if (has_value()) return R(std::invoke(std::forward<F>(f), std::move(value())));
61*38e8c45fSAndroid Build Coastguard Worker     return R();
62*38e8c45fSAndroid Build Coastguard Worker   }
63*38e8c45fSAndroid Build Coastguard Worker 
64*38e8c45fSAndroid Build Coastguard Worker   template <typename F>
transformfinal65*38e8c45fSAndroid Build Coastguard Worker   constexpr auto transform(F&& f) && {
66*38e8c45fSAndroid Build Coastguard Worker     using R = details::transform_result_t<F, decltype(std::move(value()))>;
67*38e8c45fSAndroid Build Coastguard Worker     if (has_value()) return R(std::invoke(std::forward<F>(f), std::move(value())));
68*38e8c45fSAndroid Build Coastguard Worker     return R();
69*38e8c45fSAndroid Build Coastguard Worker   }
70*38e8c45fSAndroid Build Coastguard Worker 
71*38e8c45fSAndroid Build Coastguard Worker   // Returns Optional<U> where F is a function that maps T to Optional<U>.
72*38e8c45fSAndroid Build Coastguard Worker   template <typename F>
and_thenfinal73*38e8c45fSAndroid Build Coastguard Worker   constexpr auto and_then(F&& f) const& {
74*38e8c45fSAndroid Build Coastguard Worker     using R = details::and_then_result_t<F, decltype(value())>;
75*38e8c45fSAndroid Build Coastguard Worker     if (has_value()) return std::invoke(std::forward<F>(f), value());
76*38e8c45fSAndroid Build Coastguard Worker     return R();
77*38e8c45fSAndroid Build Coastguard Worker   }
78*38e8c45fSAndroid Build Coastguard Worker 
79*38e8c45fSAndroid Build Coastguard Worker   template <typename F>
and_thenfinal80*38e8c45fSAndroid Build Coastguard Worker   constexpr auto and_then(F&& f) & {
81*38e8c45fSAndroid Build Coastguard Worker     using R = details::and_then_result_t<F, decltype(value())>;
82*38e8c45fSAndroid Build Coastguard Worker     if (has_value()) return std::invoke(std::forward<F>(f), value());
83*38e8c45fSAndroid Build Coastguard Worker     return R();
84*38e8c45fSAndroid Build Coastguard Worker   }
85*38e8c45fSAndroid Build Coastguard Worker 
86*38e8c45fSAndroid Build Coastguard Worker   template <typename F>
and_thenfinal87*38e8c45fSAndroid Build Coastguard Worker   constexpr auto and_then(F&& f) const&& {
88*38e8c45fSAndroid Build Coastguard Worker     using R = details::and_then_result_t<F, decltype(std::move(value()))>;
89*38e8c45fSAndroid Build Coastguard Worker     if (has_value()) return std::invoke(std::forward<F>(f), std::move(value()));
90*38e8c45fSAndroid Build Coastguard Worker     return R();
91*38e8c45fSAndroid Build Coastguard Worker   }
92*38e8c45fSAndroid Build Coastguard Worker 
93*38e8c45fSAndroid Build Coastguard Worker   template <typename F>
and_thenfinal94*38e8c45fSAndroid Build Coastguard Worker   constexpr auto and_then(F&& f) && {
95*38e8c45fSAndroid Build Coastguard Worker     using R = details::and_then_result_t<F, decltype(std::move(value()))>;
96*38e8c45fSAndroid Build Coastguard Worker     if (has_value()) return std::invoke(std::forward<F>(f), std::move(value()));
97*38e8c45fSAndroid Build Coastguard Worker     return R();
98*38e8c45fSAndroid Build Coastguard Worker   }
99*38e8c45fSAndroid Build Coastguard Worker 
100*38e8c45fSAndroid Build Coastguard Worker   // Returns this Optional<T> if not nullopt, or else the Optional<T> returned by the function F.
101*38e8c45fSAndroid Build Coastguard Worker   template <typename F>
102*38e8c45fSAndroid Build Coastguard Worker   constexpr auto or_else(F&& f) const& -> details::or_else_result_t<F, T> {
103*38e8c45fSAndroid Build Coastguard Worker     if (has_value()) return *this;
104*38e8c45fSAndroid Build Coastguard Worker     return std::forward<F>(f)();
105*38e8c45fSAndroid Build Coastguard Worker   }
106*38e8c45fSAndroid Build Coastguard Worker 
107*38e8c45fSAndroid Build Coastguard Worker   template <typename F>
108*38e8c45fSAndroid Build Coastguard Worker   constexpr auto or_else(F&& f) && -> details::or_else_result_t<F, T> {
109*38e8c45fSAndroid Build Coastguard Worker     if (has_value()) return std::move(*this);
110*38e8c45fSAndroid Build Coastguard Worker     return std::forward<F>(f)();
111*38e8c45fSAndroid Build Coastguard Worker   }
112*38e8c45fSAndroid Build Coastguard Worker 
113*38e8c45fSAndroid Build Coastguard Worker   // Maps this Optional<T> to expected<T, E> where nullopt becomes E.
114*38e8c45fSAndroid Build Coastguard Worker   template <typename E>
115*38e8c45fSAndroid Build Coastguard Worker   constexpr auto ok_or(E&& e) && -> base::expected<T, E> {
116*38e8c45fSAndroid Build Coastguard Worker     if (has_value()) return std::move(value());
117*38e8c45fSAndroid Build Coastguard Worker     return base::unexpected(std::forward<E>(e));
118*38e8c45fSAndroid Build Coastguard Worker   }
119*38e8c45fSAndroid Build Coastguard Worker 
120*38e8c45fSAndroid Build Coastguard Worker   // Delete new for this class. Its base doesn't have a virtual destructor, and
121*38e8c45fSAndroid Build Coastguard Worker   // if it got deleted via base class pointer, it would cause undefined
122*38e8c45fSAndroid Build Coastguard Worker   // behavior. There's not a good reason to allocate this object on the heap
123*38e8c45fSAndroid Build Coastguard Worker   // anyway.
124*38e8c45fSAndroid Build Coastguard Worker   static void* operator new(size_t) = delete;
125*38e8c45fSAndroid Build Coastguard Worker   static void* operator new[](size_t) = delete;
126*38e8c45fSAndroid Build Coastguard Worker };
127*38e8c45fSAndroid Build Coastguard Worker 
128*38e8c45fSAndroid Build Coastguard Worker template <typename T, typename U>
129*38e8c45fSAndroid Build Coastguard Worker constexpr bool operator==(const Optional<T>& lhs, const Optional<U>& rhs) {
130*38e8c45fSAndroid Build Coastguard Worker   return static_cast<std::optional<T>>(lhs) == static_cast<std::optional<U>>(rhs);
131*38e8c45fSAndroid Build Coastguard Worker }
132*38e8c45fSAndroid Build Coastguard Worker 
133*38e8c45fSAndroid Build Coastguard Worker template <typename T, typename U>
134*38e8c45fSAndroid Build Coastguard Worker constexpr bool operator!=(const Optional<T>& lhs, const Optional<U>& rhs) {
135*38e8c45fSAndroid Build Coastguard Worker   return !(lhs == rhs);
136*38e8c45fSAndroid Build Coastguard Worker }
137*38e8c45fSAndroid Build Coastguard Worker 
138*38e8c45fSAndroid Build Coastguard Worker // Deduction guides.
139*38e8c45fSAndroid Build Coastguard Worker template <typename T>
140*38e8c45fSAndroid Build Coastguard Worker Optional(T) -> Optional<T>;
141*38e8c45fSAndroid Build Coastguard Worker 
142*38e8c45fSAndroid Build Coastguard Worker template <typename T>
143*38e8c45fSAndroid Build Coastguard Worker Optional(std::optional<T>) -> Optional<T>;
144*38e8c45fSAndroid Build Coastguard Worker 
145*38e8c45fSAndroid Build Coastguard Worker }  // namespace android::ftl
146