• 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 <ftl/details/optional.h>
24 
25 namespace android::ftl {
26 
27 // Superset of std::optional<T> with monadic operations, as proposed in https://wg21.link/P0798R8.
28 //
29 // TODO: Remove in C++23.
30 //
31 template <typename T>
32 struct Optional final : std::optional<T> {
33   using std::optional<T>::optional;
34 
35   // Implicit downcast.
Optionalfinal36   Optional(std::optional<T> other) : std::optional<T>(std::move(other)) {}
37 
38   using std::optional<T>::has_value;
39   using std::optional<T>::value;
40 
41   // Returns Optional<U> where F is a function that maps T to U.
42   template <typename F>
transformfinal43   constexpr auto transform(F&& f) const& {
44     using R = details::transform_result_t<F, decltype(value())>;
45     if (has_value()) return R(std::invoke(std::forward<F>(f), value()));
46     return R();
47   }
48 
49   template <typename F>
transformfinal50   constexpr auto transform(F&& f) & {
51     using R = details::transform_result_t<F, decltype(value())>;
52     if (has_value()) return R(std::invoke(std::forward<F>(f), value()));
53     return R();
54   }
55 
56   template <typename F>
transformfinal57   constexpr auto transform(F&& f) const&& {
58     using R = details::transform_result_t<F, decltype(std::move(value()))>;
59     if (has_value()) return R(std::invoke(std::forward<F>(f), std::move(value())));
60     return R();
61   }
62 
63   template <typename F>
transformfinal64   constexpr auto transform(F&& f) && {
65     using R = details::transform_result_t<F, decltype(std::move(value()))>;
66     if (has_value()) return R(std::invoke(std::forward<F>(f), std::move(value())));
67     return R();
68   }
69 
70   // Returns Optional<U> where F is a function that maps T to Optional<U>.
71   template <typename F>
and_thenfinal72   constexpr auto and_then(F&& f) const& {
73     using R = details::and_then_result_t<F, decltype(value())>;
74     if (has_value()) return std::invoke(std::forward<F>(f), value());
75     return R();
76   }
77 
78   template <typename F>
and_thenfinal79   constexpr auto and_then(F&& f) & {
80     using R = details::and_then_result_t<F, decltype(value())>;
81     if (has_value()) return std::invoke(std::forward<F>(f), value());
82     return R();
83   }
84 
85   template <typename F>
and_thenfinal86   constexpr auto and_then(F&& f) const&& {
87     using R = details::and_then_result_t<F, decltype(std::move(value()))>;
88     if (has_value()) return std::invoke(std::forward<F>(f), std::move(value()));
89     return R();
90   }
91 
92   template <typename F>
and_thenfinal93   constexpr auto and_then(F&& f) && {
94     using R = details::and_then_result_t<F, decltype(std::move(value()))>;
95     if (has_value()) return std::invoke(std::forward<F>(f), std::move(value()));
96     return R();
97   }
98 
99   // Returns this Optional<T> if not nullopt, or else the Optional<T> returned by the function F.
100   template <typename F>
101   constexpr auto or_else(F&& f) const& -> details::or_else_result_t<F, T> {
102     if (has_value()) return *this;
103     return std::forward<F>(f)();
104   }
105 
106   template <typename F>
107   constexpr auto or_else(F&& f) && -> details::or_else_result_t<F, T> {
108     if (has_value()) return std::move(*this);
109     return std::forward<F>(f)();
110   }
111 
112   // Delete new for this class. Its base doesn't have a virtual destructor, and
113   // if it got deleted via base class pointer, it would cause undefined
114   // behavior. There's not a good reason to allocate this object on the heap
115   // anyway.
116   static void* operator new(size_t) = delete;
117   static void* operator new[](size_t) = delete;
118 };
119 
120 template <typename T, typename U>
121 constexpr bool operator==(const Optional<T>& lhs, const Optional<U>& rhs) {
122   return static_cast<std::optional<T>>(lhs) == static_cast<std::optional<U>>(rhs);
123 }
124 
125 template <typename T, typename U>
126 constexpr bool operator!=(const Optional<T>& lhs, const Optional<U>& rhs) {
127   return !(lhs == rhs);
128 }
129 
130 // Deduction guides.
131 template <typename T>
132 Optional(T) -> Optional<T>;
133 
134 template <typename T>
135 Optional(std::optional<T>) -> Optional<T>;
136 
137 }  // namespace android::ftl
138