blob: 7b02bac340812cd10175258bcfdd2499a3bf2e23 [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 Laskowskia957c1c2022-08-03 12:51:43 -070023#include <ftl/details/optional.h>
24
Dominik Laskowskia7e22552022-08-01 08:23:34 -070025namespace 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//
31template <typename T>
32struct Optional final : std::optional<T> {
33 using std::optional<T>::optional;
34
Dominik Laskowskid48d8012022-08-23 08:36:32 -070035 // Implicit downcast.
36 Optional(std::optional<T> other) : std::optional<T>(std::move(other)) {}
37
Dominik Laskowskia7e22552022-08-01 08:23:34 -070038 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>
43 constexpr auto transform(F&& f) const& {
Dominik Laskowskia957c1c2022-08-03 12:51:43 -070044 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();
Dominik Laskowskia7e22552022-08-01 08:23:34 -070047 }
48
49 template <typename F>
50 constexpr auto transform(F&& f) & {
Dominik Laskowskia957c1c2022-08-03 12:51:43 -070051 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();
Dominik Laskowskia7e22552022-08-01 08:23:34 -070054 }
55
56 template <typename F>
57 constexpr auto transform(F&& f) const&& {
Dominik Laskowskia957c1c2022-08-03 12:51:43 -070058 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();
Dominik Laskowskia7e22552022-08-01 08:23:34 -070061 }
62
63 template <typename F>
64 constexpr auto transform(F&& f) && {
Dominik Laskowskia957c1c2022-08-03 12:51:43 -070065 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>
72 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>
79 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>
86 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>
93 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();
Dominik Laskowskia7e22552022-08-01 08:23:34 -070097 }
98};
99
Ady Abrahamf28341e2022-11-22 10:13:38 -0800100template <typename T, typename U>
101constexpr bool operator==(const Optional<T>& lhs, const Optional<U>& rhs) {
102 return static_cast<std::optional<T>>(lhs) == static_cast<std::optional<U>>(rhs);
103}
104
105template <typename T, typename U>
106constexpr bool operator!=(const Optional<T>& lhs, const Optional<U>& rhs) {
107 return !(lhs == rhs);
108}
109
Dominik Laskowskid48d8012022-08-23 08:36:32 -0700110// Deduction guides.
Dominik Laskowskia7e22552022-08-01 08:23:34 -0700111template <typename T>
112Optional(T) -> Optional<T>;
113
Dominik Laskowskid48d8012022-08-23 08:36:32 -0700114template <typename T>
115Optional(std::optional<T>) -> Optional<T>;
116
Dominik Laskowskia7e22552022-08-01 08:23:34 -0700117} // namespace android::ftl