1*38e8c45fSAndroid Build Coastguard Worker /* 2*38e8c45fSAndroid Build Coastguard Worker * Copyright 2022 The Android Open Source Project 3*38e8c45fSAndroid Build Coastguard Worker * 4*38e8c45fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*38e8c45fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*38e8c45fSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*38e8c45fSAndroid Build Coastguard Worker * 8*38e8c45fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*38e8c45fSAndroid Build Coastguard Worker * 10*38e8c45fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*38e8c45fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*38e8c45fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*38e8c45fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*38e8c45fSAndroid Build Coastguard Worker * limitations under the License. 15*38e8c45fSAndroid Build Coastguard Worker */ 16*38e8c45fSAndroid Build Coastguard Worker 17*38e8c45fSAndroid Build Coastguard Worker #pragma once 18*38e8c45fSAndroid Build Coastguard Worker 19*38e8c45fSAndroid Build Coastguard Worker #include <functional> 20*38e8c45fSAndroid Build Coastguard Worker #include <optional> 21*38e8c45fSAndroid Build Coastguard Worker #include <utility> 22*38e8c45fSAndroid Build Coastguard Worker 23*38e8c45fSAndroid Build Coastguard Worker #include <android-base/expected.h> 24*38e8c45fSAndroid Build Coastguard Worker #include <ftl/details/optional.h> 25*38e8c45fSAndroid Build Coastguard Worker 26*38e8c45fSAndroid Build Coastguard Worker namespace android::ftl { 27*38e8c45fSAndroid Build Coastguard Worker 28*38e8c45fSAndroid Build Coastguard Worker // Superset of std::optional<T> with monadic operations, as proposed in https://wg21.link/P0798R8. 29*38e8c45fSAndroid Build Coastguard Worker // 30*38e8c45fSAndroid Build Coastguard Worker // TODO: Remove standard APIs in C++23. 31*38e8c45fSAndroid Build Coastguard Worker // 32*38e8c45fSAndroid Build Coastguard Worker template <typename T> 33*38e8c45fSAndroid Build Coastguard Worker struct Optional final : std::optional<T> { 34*38e8c45fSAndroid Build Coastguard Worker using std::optional<T>::optional; 35*38e8c45fSAndroid Build Coastguard Worker 36*38e8c45fSAndroid Build Coastguard Worker // Implicit downcast. Optionalfinal37*38e8c45fSAndroid Build Coastguard Worker Optional(std::optional<T> other) : std::optional<T>(std::move(other)) {} 38*38e8c45fSAndroid Build Coastguard Worker 39*38e8c45fSAndroid Build Coastguard Worker using std::optional<T>::has_value; 40*38e8c45fSAndroid Build Coastguard Worker using std::optional<T>::value; 41*38e8c45fSAndroid Build Coastguard Worker 42*38e8c45fSAndroid Build Coastguard Worker // Returns Optional<U> where F is a function that maps T to U. 43*38e8c45fSAndroid Build Coastguard Worker template <typename F> transformfinal44*38e8c45fSAndroid Build Coastguard Worker constexpr auto transform(F&& f) const& { 45*38e8c45fSAndroid Build Coastguard Worker using R = details::transform_result_t<F, decltype(value())>; 46*38e8c45fSAndroid Build Coastguard Worker if (has_value()) return R(std::invoke(std::forward<F>(f), value())); 47*38e8c45fSAndroid Build Coastguard Worker return R(); 48*38e8c45fSAndroid Build Coastguard Worker } 49*38e8c45fSAndroid Build Coastguard Worker 50*38e8c45fSAndroid Build Coastguard Worker template <typename F> transformfinal51*38e8c45fSAndroid Build Coastguard Worker constexpr auto transform(F&& f) & { 52*38e8c45fSAndroid Build Coastguard Worker using R = details::transform_result_t<F, decltype(value())>; 53*38e8c45fSAndroid Build Coastguard Worker if (has_value()) return R(std::invoke(std::forward<F>(f), value())); 54*38e8c45fSAndroid Build Coastguard Worker return R(); 55*38e8c45fSAndroid Build Coastguard Worker } 56*38e8c45fSAndroid Build Coastguard Worker 57*38e8c45fSAndroid Build Coastguard Worker template <typename F> transformfinal58*38e8c45fSAndroid Build Coastguard Worker constexpr auto transform(F&& f) const&& { 59*38e8c45fSAndroid Build Coastguard Worker using R = details::transform_result_t<F, decltype(std::move(value()))>; 60*38e8c45fSAndroid Build Coastguard Worker if (has_value()) return R(std::invoke(std::forward<F>(f), std::move(value()))); 61*38e8c45fSAndroid Build Coastguard Worker return R(); 62*38e8c45fSAndroid Build Coastguard Worker } 63*38e8c45fSAndroid Build Coastguard Worker 64*38e8c45fSAndroid Build Coastguard Worker template <typename F> transformfinal65*38e8c45fSAndroid Build Coastguard Worker constexpr auto transform(F&& f) && { 66*38e8c45fSAndroid Build Coastguard Worker using R = details::transform_result_t<F, decltype(std::move(value()))>; 67*38e8c45fSAndroid Build Coastguard Worker if (has_value()) return R(std::invoke(std::forward<F>(f), std::move(value()))); 68*38e8c45fSAndroid Build Coastguard Worker return R(); 69*38e8c45fSAndroid Build Coastguard Worker } 70*38e8c45fSAndroid Build Coastguard Worker 71*38e8c45fSAndroid Build Coastguard Worker // Returns Optional<U> where F is a function that maps T to Optional<U>. 72*38e8c45fSAndroid Build Coastguard Worker template <typename F> and_thenfinal73*38e8c45fSAndroid Build Coastguard Worker constexpr auto and_then(F&& f) const& { 74*38e8c45fSAndroid Build Coastguard Worker using R = details::and_then_result_t<F, decltype(value())>; 75*38e8c45fSAndroid Build Coastguard Worker if (has_value()) return std::invoke(std::forward<F>(f), value()); 76*38e8c45fSAndroid Build Coastguard Worker return R(); 77*38e8c45fSAndroid Build Coastguard Worker } 78*38e8c45fSAndroid Build Coastguard Worker 79*38e8c45fSAndroid Build Coastguard Worker template <typename F> and_thenfinal80*38e8c45fSAndroid Build Coastguard Worker constexpr auto and_then(F&& f) & { 81*38e8c45fSAndroid Build Coastguard Worker using R = details::and_then_result_t<F, decltype(value())>; 82*38e8c45fSAndroid Build Coastguard Worker if (has_value()) return std::invoke(std::forward<F>(f), value()); 83*38e8c45fSAndroid Build Coastguard Worker return R(); 84*38e8c45fSAndroid Build Coastguard Worker } 85*38e8c45fSAndroid Build Coastguard Worker 86*38e8c45fSAndroid Build Coastguard Worker template <typename F> and_thenfinal87*38e8c45fSAndroid Build Coastguard Worker constexpr auto and_then(F&& f) const&& { 88*38e8c45fSAndroid Build Coastguard Worker using R = details::and_then_result_t<F, decltype(std::move(value()))>; 89*38e8c45fSAndroid Build Coastguard Worker if (has_value()) return std::invoke(std::forward<F>(f), std::move(value())); 90*38e8c45fSAndroid Build Coastguard Worker return R(); 91*38e8c45fSAndroid Build Coastguard Worker } 92*38e8c45fSAndroid Build Coastguard Worker 93*38e8c45fSAndroid Build Coastguard Worker template <typename F> and_thenfinal94*38e8c45fSAndroid Build Coastguard Worker constexpr auto and_then(F&& f) && { 95*38e8c45fSAndroid Build Coastguard Worker using R = details::and_then_result_t<F, decltype(std::move(value()))>; 96*38e8c45fSAndroid Build Coastguard Worker if (has_value()) return std::invoke(std::forward<F>(f), std::move(value())); 97*38e8c45fSAndroid Build Coastguard Worker return R(); 98*38e8c45fSAndroid Build Coastguard Worker } 99*38e8c45fSAndroid Build Coastguard Worker 100*38e8c45fSAndroid Build Coastguard Worker // Returns this Optional<T> if not nullopt, or else the Optional<T> returned by the function F. 101*38e8c45fSAndroid Build Coastguard Worker template <typename F> 102*38e8c45fSAndroid Build Coastguard Worker constexpr auto or_else(F&& f) const& -> details::or_else_result_t<F, T> { 103*38e8c45fSAndroid Build Coastguard Worker if (has_value()) return *this; 104*38e8c45fSAndroid Build Coastguard Worker return std::forward<F>(f)(); 105*38e8c45fSAndroid Build Coastguard Worker } 106*38e8c45fSAndroid Build Coastguard Worker 107*38e8c45fSAndroid Build Coastguard Worker template <typename F> 108*38e8c45fSAndroid Build Coastguard Worker constexpr auto or_else(F&& f) && -> details::or_else_result_t<F, T> { 109*38e8c45fSAndroid Build Coastguard Worker if (has_value()) return std::move(*this); 110*38e8c45fSAndroid Build Coastguard Worker return std::forward<F>(f)(); 111*38e8c45fSAndroid Build Coastguard Worker } 112*38e8c45fSAndroid Build Coastguard Worker 113*38e8c45fSAndroid Build Coastguard Worker // Maps this Optional<T> to expected<T, E> where nullopt becomes E. 114*38e8c45fSAndroid Build Coastguard Worker template <typename E> 115*38e8c45fSAndroid Build Coastguard Worker constexpr auto ok_or(E&& e) && -> base::expected<T, E> { 116*38e8c45fSAndroid Build Coastguard Worker if (has_value()) return std::move(value()); 117*38e8c45fSAndroid Build Coastguard Worker return base::unexpected(std::forward<E>(e)); 118*38e8c45fSAndroid Build Coastguard Worker } 119*38e8c45fSAndroid Build Coastguard Worker 120*38e8c45fSAndroid Build Coastguard Worker // Delete new for this class. Its base doesn't have a virtual destructor, and 121*38e8c45fSAndroid Build Coastguard Worker // if it got deleted via base class pointer, it would cause undefined 122*38e8c45fSAndroid Build Coastguard Worker // behavior. There's not a good reason to allocate this object on the heap 123*38e8c45fSAndroid Build Coastguard Worker // anyway. 124*38e8c45fSAndroid Build Coastguard Worker static void* operator new(size_t) = delete; 125*38e8c45fSAndroid Build Coastguard Worker static void* operator new[](size_t) = delete; 126*38e8c45fSAndroid Build Coastguard Worker }; 127*38e8c45fSAndroid Build Coastguard Worker 128*38e8c45fSAndroid Build Coastguard Worker template <typename T, typename U> 129*38e8c45fSAndroid Build Coastguard Worker constexpr bool operator==(const Optional<T>& lhs, const Optional<U>& rhs) { 130*38e8c45fSAndroid Build Coastguard Worker return static_cast<std::optional<T>>(lhs) == static_cast<std::optional<U>>(rhs); 131*38e8c45fSAndroid Build Coastguard Worker } 132*38e8c45fSAndroid Build Coastguard Worker 133*38e8c45fSAndroid Build Coastguard Worker template <typename T, typename U> 134*38e8c45fSAndroid Build Coastguard Worker constexpr bool operator!=(const Optional<T>& lhs, const Optional<U>& rhs) { 135*38e8c45fSAndroid Build Coastguard Worker return !(lhs == rhs); 136*38e8c45fSAndroid Build Coastguard Worker } 137*38e8c45fSAndroid Build Coastguard Worker 138*38e8c45fSAndroid Build Coastguard Worker // Deduction guides. 139*38e8c45fSAndroid Build Coastguard Worker template <typename T> 140*38e8c45fSAndroid Build Coastguard Worker Optional(T) -> Optional<T>; 141*38e8c45fSAndroid Build Coastguard Worker 142*38e8c45fSAndroid Build Coastguard Worker template <typename T> 143*38e8c45fSAndroid Build Coastguard Worker Optional(std::optional<T>) -> Optional<T>; 144*38e8c45fSAndroid Build Coastguard Worker 145*38e8c45fSAndroid Build Coastguard Worker } // namespace android::ftl 146