• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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>
21 #include <utility>
22 
23 #include <android-base/expected.h>
24 #include <ftl/details/optional.h>
25 
26 namespace android::ftl {
27 
28 // Superset of std::optional<T> with monadic operations, as proposed in https://wg21.link/P0798R8.
29 //
30 // TODO: Remove standard APIs in C++23.
31 //
32 template <typename T>
33 struct Optional final : std::optional<T> {
34   using std::optional<T>::optional;
35 
36   // Implicit downcast.
Optionalfinal37   Optional(std::optional<T> other) : std::optional<T>(std::move(other)) {}
38 
39   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>
transformfinal44   constexpr auto transform(F&& f) const& {
45     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();
48   }
49 
50   template <typename F>
transformfinal51   constexpr auto transform(F&& f) & {
52     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();
55   }
56 
57   template <typename F>
transformfinal58   constexpr auto transform(F&& f) const&& {
59     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();
62   }
63 
64   template <typename F>
transformfinal65   constexpr auto transform(F&& f) && {
66     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>
and_thenfinal73   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>
and_thenfinal80   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>
and_thenfinal87   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>
and_thenfinal94   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();
98   }
99 
100   // 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 
113   // 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 
120   // 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;
126 };
127 
128 template <typename T, typename U>
129 constexpr 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 
133 template <typename T, typename U>
134 constexpr bool operator!=(const Optional<T>& lhs, const Optional<U>& rhs) {
135   return !(lhs == rhs);
136 }
137 
138 // Deduction guides.
139 template <typename T>
140 Optional(T) -> Optional<T>;
141 
142 template <typename T>
143 Optional(std::optional<T>) -> Optional<T>;
144 
145 }  // namespace android::ftl
146