blob: a0a95c4b9a0fe4443b2584bab12187d16002c310 [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
35 using std::optional<T>::has_value;
36 using std::optional<T>::value;
37
38 // Returns Optional<U> where F is a function that maps T to U.
39 template <typename F>
40 constexpr auto transform(F&& f) const& {
Dominik Laskowskia957c1c2022-08-03 12:51:43 -070041 using R = details::transform_result_t<F, decltype(value())>;
42 if (has_value()) return R(std::invoke(std::forward<F>(f), value()));
43 return R();
Dominik Laskowskia7e22552022-08-01 08:23:34 -070044 }
45
46 template <typename F>
47 constexpr auto transform(F&& f) & {
Dominik Laskowskia957c1c2022-08-03 12:51:43 -070048 using R = details::transform_result_t<F, decltype(value())>;
49 if (has_value()) return R(std::invoke(std::forward<F>(f), value()));
50 return R();
Dominik Laskowskia7e22552022-08-01 08:23:34 -070051 }
52
53 template <typename F>
54 constexpr auto transform(F&& f) const&& {
Dominik Laskowskia957c1c2022-08-03 12:51:43 -070055 using R = details::transform_result_t<F, decltype(std::move(value()))>;
56 if (has_value()) return R(std::invoke(std::forward<F>(f), std::move(value())));
57 return R();
Dominik Laskowskia7e22552022-08-01 08:23:34 -070058 }
59
60 template <typename F>
61 constexpr auto transform(F&& f) && {
Dominik Laskowskia957c1c2022-08-03 12:51:43 -070062 using R = details::transform_result_t<F, decltype(std::move(value()))>;
63 if (has_value()) return R(std::invoke(std::forward<F>(f), std::move(value())));
64 return R();
65 }
66
67 // Returns Optional<U> where F is a function that maps T to Optional<U>.
68 template <typename F>
69 constexpr auto and_then(F&& f) const& {
70 using R = details::and_then_result_t<F, decltype(value())>;
71 if (has_value()) return std::invoke(std::forward<F>(f), value());
72 return R();
73 }
74
75 template <typename F>
76 constexpr auto and_then(F&& f) & {
77 using R = details::and_then_result_t<F, decltype(value())>;
78 if (has_value()) return std::invoke(std::forward<F>(f), value());
79 return R();
80 }
81
82 template <typename F>
83 constexpr auto and_then(F&& f) const&& {
84 using R = details::and_then_result_t<F, decltype(std::move(value()))>;
85 if (has_value()) return std::invoke(std::forward<F>(f), std::move(value()));
86 return R();
87 }
88
89 template <typename F>
90 constexpr auto and_then(F&& f) && {
91 using R = details::and_then_result_t<F, decltype(std::move(value()))>;
92 if (has_value()) return std::invoke(std::forward<F>(f), std::move(value()));
93 return R();
Dominik Laskowskia7e22552022-08-01 08:23:34 -070094 }
95};
96
97// Deduction guide.
98template <typename T>
99Optional(T) -> Optional<T>;
100
101} // namespace android::ftl