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