From a957c1c1dacc826df97fb20392ddeb44476f076f Mon Sep 17 00:00:00 2001 From: Dominik Laskowski Date: Wed, 3 Aug 2022 12:51:43 -0700 Subject: FTL: Add Optional::and_then Bug: 185536303 Test: ftl_test Change-Id: Ic907a662a2090ad1363bd329e7d758b2acef55ad --- include/ftl/details/optional.h | 58 +++++++++++++++++++++++++++++++++++++++ include/ftl/details/type_traits.h | 27 ++++++++++++++++++ include/ftl/optional.h | 56 ++++++++++++++++++++++++++++--------- include/ftl/small_vector.h | 9 ++---- 4 files changed, 131 insertions(+), 19 deletions(-) create mode 100644 include/ftl/details/optional.h create mode 100644 include/ftl/details/type_traits.h (limited to 'include/ftl') diff --git a/include/ftl/details/optional.h b/include/ftl/details/optional.h new file mode 100644 index 0000000000..bff7c1e000 --- /dev/null +++ b/include/ftl/details/optional.h @@ -0,0 +1,58 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include + +namespace android::ftl { + +template +struct Optional; + +namespace details { + +template +struct is_optional : std::false_type {}; + +template +struct is_optional> : std::true_type {}; + +template +struct is_optional> : std::true_type {}; + +template +struct transform_result { + using type = Optional>>; +}; + +template +using transform_result_t = typename transform_result::type; + +template +struct and_then_result { + using type = remove_cvref_t>; + static_assert(is_optional{}, "and_then function must return an optional"); +}; + +template +using and_then_result_t = typename and_then_result::type; + +} // namespace details +} // namespace android::ftl diff --git a/include/ftl/details/type_traits.h b/include/ftl/details/type_traits.h new file mode 100644 index 0000000000..7092ec50fb --- /dev/null +++ b/include/ftl/details/type_traits.h @@ -0,0 +1,27 @@ +/* + * Copyright 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace android::ftl::details { + +// TODO: Replace with std::remove_cvref_t in C++20. +template +using remove_cvref_t = std::remove_cv_t>; + +} // namespace android::ftl::details diff --git a/include/ftl/optional.h b/include/ftl/optional.h index daf4502bd2..a0a95c4b9a 100644 --- a/include/ftl/optional.h +++ b/include/ftl/optional.h @@ -18,9 +18,10 @@ #include #include -#include #include +#include + namespace android::ftl { // Superset of std::optional with monadic operations, as proposed in https://wg21.link/P0798R8. @@ -37,30 +38,59 @@ struct Optional final : std::optional { // Returns Optional where F is a function that maps T to U. template constexpr auto transform(F&& f) const& { - using U = std::remove_cv_t>; - if (has_value()) return Optional(std::invoke(std::forward(f), value())); - return Optional(); + using R = details::transform_result_t; + if (has_value()) return R(std::invoke(std::forward(f), value())); + return R(); } template constexpr auto transform(F&& f) & { - using U = std::remove_cv_t>; - if (has_value()) return Optional(std::invoke(std::forward(f), value())); - return Optional(); + using R = details::transform_result_t; + if (has_value()) return R(std::invoke(std::forward(f), value())); + return R(); } template constexpr auto transform(F&& f) const&& { - using U = std::invoke_result_t; - if (has_value()) return Optional(std::invoke(std::forward(f), std::move(value()))); - return Optional(); + using R = details::transform_result_t; + if (has_value()) return R(std::invoke(std::forward(f), std::move(value()))); + return R(); } template constexpr auto transform(F&& f) && { - using U = std::invoke_result_t; - if (has_value()) return Optional(std::invoke(std::forward(f), std::move(value()))); - return Optional(); + using R = details::transform_result_t; + if (has_value()) return R(std::invoke(std::forward(f), std::move(value()))); + return R(); + } + + // Returns Optional where F is a function that maps T to Optional. + template + constexpr auto and_then(F&& f) const& { + using R = details::and_then_result_t; + if (has_value()) return std::invoke(std::forward(f), value()); + return R(); + } + + template + constexpr auto and_then(F&& f) & { + using R = details::and_then_result_t; + if (has_value()) return std::invoke(std::forward(f), value()); + return R(); + } + + template + constexpr auto and_then(F&& f) const&& { + using R = details::and_then_result_t; + if (has_value()) return std::invoke(std::forward(f), std::move(value())); + return R(); + } + + template + constexpr auto and_then(F&& f) && { + using R = details::and_then_result_t; + if (has_value()) return std::invoke(std::forward(f), std::move(value())); + return R(); } }; diff --git a/include/ftl/small_vector.h b/include/ftl/small_vector.h index 339726e4ea..11294c3ac8 100644 --- a/include/ftl/small_vector.h +++ b/include/ftl/small_vector.h @@ -21,11 +21,12 @@ #include #include -#include #include #include #include +#include + namespace android::ftl { template @@ -80,10 +81,6 @@ class SmallVector final : details::ArrayTraits, details::ArrayComparators; using Dynamic = SmallVector; - // TODO: Replace with std::remove_cvref_t in C++20. - template - using remove_cvref_t = std::remove_cv_t>; - public: FTL_ARRAY_TRAIT(T, value_type); FTL_ARRAY_TRAIT(T, size_type); @@ -104,7 +101,7 @@ class SmallVector final : details::ArrayTraits, details::ArrayComparators>{}>> + typename = std::enable_if_t>{}>> SmallVector(Arg&& arg, Args&&... args) : vector_(std::in_place_type, std::forward(arg), std::forward(args)...) {} -- cgit v1.2.3-59-g8ed1b