diff --git a/third_party/fuchsia/repo/.clang-format b/third_party/fuchsia/repo/.clang-format index 99ee79aa8c..58381b3fdf 100644 --- a/third_party/fuchsia/repo/.clang-format +++ b/third_party/fuchsia/repo/.clang-format @@ -8,6 +8,7 @@ Standard: Cpp11 SortIncludes: true AllowShortIfStatementsOnASingleLine: false AllowShortLoopsOnASingleLine: false +BreakStringLiterals: false DerivePointerAlignment: true PointerAlignment: Left ColumnLimit: 100 diff --git a/third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/function.h b/third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/function.h index d6ce612f33..fba3e95c28 100644 --- a/third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/function.h +++ b/third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/function.h @@ -505,7 +505,8 @@ bool operator!=(decltype(nullptr), // supported on C++17 and up. On C++14, a plain lambda should be used instead. template auto bind_member(T* instance, R (T::*fn)(Args...)) { - return [instance, fn](Args... args) { return (instance->*fn)(std::forward(args)...); }; + // Use explicit type on the return to ensure perfect forwarding of references. + return [instance, fn](Args... args) -> R { return (instance->*fn)(std::forward(args)...); }; } // C++17 due to use of 'auto' template parameters and lambda parameters. @@ -515,7 +516,8 @@ namespace internal { // This ensure that the correct overload of |method| is called. template auto make_the_call(T* instance, parameter_pack) { - return [instance](Args... args) { + // Use decltype(auto) on the return to ensure perfect forwarding of references. + return [instance](Args... args) -> decltype(auto) { return (instance->*method)(std::forward(args)...); }; } diff --git a/third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/internal/result.h b/third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/internal/result.h index 4d97d485df..18a0c87514 100644 --- a/third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/internal/result.h +++ b/third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/internal/result.h @@ -37,6 +37,11 @@ struct arrow_operator { static constexpr const T* forward(const T& value) { return &value; } }; template +struct arrow_operator>> { + static constexpr T& forward(T& value) { return value; } + static constexpr const T& forward(const T& value) { return value; } +}; +template struct arrow_operator().operator->())>> { static constexpr T& forward(T& value) { return value; } static constexpr const T& forward(const T& value) { return value; } diff --git a/third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/result.h b/third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/result.h index 253848abc2..a7f77cac95 100644 --- a/third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/result.h +++ b/third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/result.h @@ -34,7 +34,8 @@ // // bool is_ok() // bool is_error() -// T value_or(default_value) // Returns value on success, or default on failure. +// T value_or(default_value) // Returns value on success, or default on failure. +// result map_error(fn) // Transforms the error value of the result using fn. // // Available only when is_ok() (will assert otherwise). // @@ -410,6 +411,44 @@ class LIB_FIT_NODISCARD result { PW_ASSERT(false); } + // Maps a result to a result by transforming the error through + // fn, where E2 is the result of invoking fn on E. Success values will be + // passed through untouched. + // + // Note that map_error is not necessary if E2 is constructible from E. + // In that case, result will be constructible from result. + // + // If the current object is an r-value, errors and successes in the current + // result object will be moved. + template + constexpr result, T> map_error(Fn&& fn) & { + if (is_error()) { + return error>(std::forward(fn)(error_value())); + } + return success(value()); + } + template + constexpr result, T> map_error(Fn&& fn) const& { + if (is_error()) { + return error>(std::forward(fn)(error_value())); + } + return success(value()); + } + template + constexpr result, T> map_error(Fn&& fn) && { + if (is_error()) { + return error>(std::forward(fn)(std::move(error_value()))); + } + return take_value(); + } + template + constexpr result, T> map_error(Fn&& fn) const&& { + if (is_error()) { + return error>(std::forward(fn)(std::move(error_value()))); + } + return success(value()); + } + constexpr void swap(result& other) { if (&other != this) { using std::swap; @@ -526,6 +565,44 @@ class LIB_FIT_NODISCARD result { PW_ASSERT(false); } + // Maps a result to a result by transforming the error through + // fn, where E2 is the result of invoking fn on E. Success values will be + // passed through untouched. + // + // Note that map_error is not necessary if E2 is constructible from E. + // In that case, result will be constructible from result. + // + // If the current object is an r-value, errors in the current result object + // will be moved. + template + constexpr result> map_error(Fn&& fn) & { + if (is_error()) { + return error>(std::forward(fn)(error_value())); + } + return success<>(); + } + template + constexpr result> map_error(Fn&& fn) const& { + if (is_error()) { + return error>(std::forward(fn)(error_value())); + } + return success<>(); + } + template + constexpr result> map_error(Fn&& fn) && { + if (is_error()) { + return error>(std::forward(fn)(std::move(error_value()))); + } + return success<>(); + } + template + constexpr result> map_error(Fn&& fn) const&& { + if (is_error()) { + return error>(std::forward(fn)(std::move(error_value()))); + } + return success<>(); + } + constexpr void swap(result& other) { if (&other != this) { using std::swap; diff --git a/third_party/fuchsia/repo/sdk/lib/fit/test/function_tests.cc b/third_party/fuchsia/repo/sdk/lib/fit/test/function_tests.cc index ba7eb5ff5d..c2a2200021 100644 --- a/third_party/fuchsia/repo/sdk/lib/fit/test/function_tests.cc +++ b/third_party/fuchsia/repo/sdk/lib/fit/test/function_tests.cc @@ -1075,3 +1075,18 @@ TEST(FunctionTests, closure_fit_inline_function_Closure_HugeCallableSize) { TEST(FunctionTests, binary_op_fit_inline_function_BinaryOp_HugeCallableSize) { binary_op>(); } + +TEST(FunctionTests, bind_return_reference) { + struct TestClass { + int& member() { return member_; } + int member_ = 0; + }; + + TestClass instance; + // Ensure that references to the original values are returned, not copies. + fit::function func = fit::bind_member<&TestClass::member>(&instance); + EXPECT_EQ(&func(), &instance.member_); + + fit::function func_deprecated = fit::bind_member(&instance, &TestClass::member); + EXPECT_EQ(&func_deprecated(), &instance.member_); +} diff --git a/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/functional.h b/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/functional.h new file mode 100644 index 0000000000..34d44e0d54 --- /dev/null +++ b/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/functional.h @@ -0,0 +1,50 @@ +// Copyright 2021 The Fuchsia Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_FUNCTIONAL_H_ +#define LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_FUNCTIONAL_H_ + +#include "internal/functional.h" + +namespace cpp20 { + +// This version is always constexpr-qualified, with no other changes from C++17. + +#if defined(__cpp_lib_invoke) && defined(__cpp_lib_constexpr_functional) && \ + __cpp_lib_invoke >= 201411L && __cpp_lib_constexpr_functional >= 201907L && \ + !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +using std::invoke; + +#else // Provide invoke() polyfill + +template +constexpr cpp17::invoke_result_t invoke(F&& f, Args&&... args) noexcept( + cpp17::is_nothrow_invocable_v) { + return ::cpp17::internal::invoke(std::forward(f), std::forward(args)...); +} + +#endif // __cpp_lib_invoke >= 201411L && __cpp_lib_constexpr_functional >= 201907L && + // !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +#if defined(__cpp_lib_bind_front) && __cpp_lib_bind_front >= 201907L && \ + !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +using std::bind_front; + +#else // Provide bind_front() polyfill + +template +constexpr ::cpp20::internal::front_binder_t bind_front(F&& f, Args&&... args) noexcept( + cpp17::is_nothrow_constructible_v<::cpp20::internal::front_binder_t, + cpp17::in_place_t, F, Args...>) { + return ::cpp20::internal::front_binder_t(cpp17::in_place, std::forward(f), + std::forward(args)...); +} + +#endif // __cpp_lib_bind_front >= 201907L && !defined(LIB_STDCOMPAT_USE_POLYFILLS) + +} // namespace cpp20 + +#endif // LIB_STDCOMPAT_INCLUDE_LIB_STDCOMPAT_FUNCTIONAL_H_ diff --git a/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/internal/type_traits.h b/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/internal/type_traits.h index f2620c19b4..dced28d9f0 100644 --- a/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/internal/type_traits.h +++ b/third_party/fuchsia/repo/sdk/lib/stdcompat/include/lib/stdcompat/internal/type_traits.h @@ -17,12 +17,11 @@ static constexpr bool is_reference_wrapper> = true; // These are from [func.require] ΒΆ 1.1-7 template -static constexpr bool invoke_pmf_base = std::is_member_function_pointer::value && - std::is_base_of>::value; +static constexpr bool invoke_pmf_base = std::is_member_function_pointer::value&& + std::is_base_of>::value; template -static constexpr bool invoke_pmf_refwrap = - std::is_member_function_pointer::value && +static constexpr bool invoke_pmf_refwrap = std::is_member_function_pointer::value&& is_reference_wrapper>>; template @@ -31,12 +30,11 @@ static constexpr bool invoke_pmf_other = !invoke_pmf_refwrap; template -static constexpr bool invoke_pmd_base = std::is_member_object_pointer::value && - std::is_base_of>::value; +static constexpr bool invoke_pmd_base = std::is_member_object_pointer::value&& + std::is_base_of>::value; template -static constexpr bool invoke_pmd_refwrap = - std::is_member_object_pointer::value && +static constexpr bool invoke_pmd_refwrap = std::is_member_object_pointer::value&& is_reference_wrapper>>; template