diff options
Diffstat (limited to 'third_party/fuchsia/repo/sdk/lib/fit/include')
9 files changed, 319 insertions, 150 deletions
diff --git a/third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/defer.h b/third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/defer.h new file mode 100644 index 000000000..907a3b77e --- /dev/null +++ b/third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/defer.h @@ -0,0 +1,145 @@ +// Copyright 2018 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_FIT_DEFER_H_ +#define LIB_FIT_DEFER_H_ + +#include <utility> + +#include "function.h" +#include "nullable.h" + +namespace fit { + +// A move-only deferred action wrapper with RAII semantics. +// This class is not thread safe. +// +// The wrapper holds a function-like callable target with no arguments +// which it invokes when it goes out of scope unless canceled, called, or +// moved to a wrapper in a different scope. +// +// See |fit::defer()| for idiomatic usage. +template <typename T> +class deferred_action final { + public: + // Creates a deferred action without a pending target. + deferred_action() = default; + explicit deferred_action(decltype(nullptr)) {} + + // Creates a deferred action with a pending target. + explicit deferred_action(T target) : target_(std::move(target)) {} + + // Creates a deferred action with a pending target moved from another + // deferred action, leaving the other one without a pending target. + deferred_action(deferred_action&& other) : target_(std::move(other.target_)) { + other.target_.reset(); + } + + // Invokes and releases the deferred action's pending target (if any). + ~deferred_action() { call(); } + + // Returns true if the deferred action has a pending target. + explicit operator bool() const { return !!target_; } + + // Invokes and releases the deferred action's pending target (if any), + // then move-assigns it from another deferred action, leaving the latter + // one without a pending target. + deferred_action& operator=(deferred_action&& other) { + if (&other == this) + return *this; + call(); + target_ = std::move(other.target_); + other.target_.reset(); + return *this; + } + + // Invokes and releases the deferred action's pending target (if any). + void call() { + if (target_) { + // Move to a local to guard against re-entrance. + T local_target = std::move(*target_); + target_.reset(); + local_target(); + } + } + + // Releases the deferred action's pending target (if any) without + // invoking it. + void cancel() { target_.reset(); } + deferred_action& operator=(decltype(nullptr)) { + cancel(); + return *this; + } + + // Assigns a new target to the deferred action. + deferred_action& operator=(T target) { + target_ = std::move(target); + return *this; + } + + deferred_action(const deferred_action& other) = delete; + deferred_action& operator=(const deferred_action& other) = delete; + + private: + nullable<T> target_; +}; + +template <typename T> +bool operator==(const deferred_action<T>& action, decltype(nullptr)) { + return !action; +} +template <typename T> +bool operator==(decltype(nullptr), const deferred_action<T>& action) { + return !action; +} +template <typename T> +bool operator!=(const deferred_action<T>& action, decltype(nullptr)) { + return !!action; +} +template <typename T> +bool operator!=(decltype(nullptr), const deferred_action<T>& action) { + return !!action; +} + +// Defers execution of a function-like callable target with no arguments +// until the value returned by this function goes out of scope unless canceled, +// called, or moved to a wrapper in a different scope. +// +// // This example prints "Hello..." then "Goodbye!". +// void test() { +// auto d = fit::defer([]{ puts("Goodbye!"); }); +// puts("Hello..."); +// } +// +// // This example prints nothing because the deferred action is canceled. +// void do_nothing() { +// auto d = fit::defer([]{ puts("I'm not here."); }); +// d.cancel(); +// } +// +// // This example shows how the deferred action can be reassigned assuming +// // the new target has the same type and the old one, in this case by +// // representing the target as a |fit::closure|. +// void reassign() { +// auto d = fit::defer<fit::closure>([] { puts("This runs first."); }); +// d = fit::defer<fit::closure>([] { puts("This runs afterwards."); }); +// } +template <typename T> +__attribute__((__warn_unused_result__)) inline deferred_action<T> defer(T target) { + return deferred_action<T>(std::move(target)); +} + +// Alias for a deferred_action using a fit::callback. +using deferred_callback = deferred_action<fit::callback<void()>>; + +// Defers execution of a fit::callback with no arguments. See |fit::defer| for +// details. +__attribute__((__warn_unused_result__)) inline deferred_callback defer_callback( + fit::callback<void()> target) { + return deferred_callback(std::move(target)); +} + +} // namespace fit + +#endif // LIB_FIT_DEFER_H_ 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 fba3e95c2..2403dee3b 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 @@ -2,9 +2,11 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef LIB_FIT_INCLUDE_LIB_FIT_FUNCTION_H_ -#define LIB_FIT_INCLUDE_LIB_FIT_FUNCTION_H_ +#ifndef LIB_FIT_FUNCTION_H_ +#define LIB_FIT_FUNCTION_H_ +#include <cstddef> +#include <memory> #include <type_traits> #include "internal/function.h" @@ -13,14 +15,14 @@ namespace fit { -template <size_t inline_target_size, bool require_inline, typename FunctionType> +template <size_t inline_target_size, bool require_inline, typename FunctionType, typename Allocator> class function_impl { static_assert(std::is_function<FunctionType>::value, "fit::function must be instantiated with a function type, such as void() or " "int(char*, bool)"); }; -template <size_t inline_target_size, bool require_inline, typename FunctionType> +template <size_t inline_target_size, bool require_inline, typename FunctionType, typename Allocator> class callback_impl { static_assert(std::is_function<FunctionType>::value, "fit::callback must be instantiated with a function type, such as void() or " @@ -33,6 +35,10 @@ class callback_impl { // function. constexpr size_t default_inline_target_size = sizeof(void*) * 2; +// The default allocator used for allocating callables on the heap. Its `value_type` is irrelevant, +// since it must support rebinding. +using default_callable_allocator = std::allocator<std::byte>; + // A |fit::function| is a move-only polymorphic function wrapper. // // If you need a class with similar characteristics that also ensures @@ -61,6 +67,9 @@ constexpr size_t default_inline_target_size = sizeof(void*) * 2; // fit within a function without requiring heap allocation. // Defaults to |default_inline_target_size|. // +// |Allocator| is the Allocator used for heap allocation, if required. Its `value_type` is +// irrelevant, since it must support rebinding. +// // Class members are documented in |fit::function_impl|, below. // // EXAMPLES @@ -70,9 +79,10 @@ constexpr size_t default_inline_target_size = sizeof(void*) * 2; // - // https://fuchsia.googlesource.com/fuchsia/+/HEAD/sdk/lib/fit/test/examples/function_example2.cc // -template <typename T, size_t inline_target_size = default_inline_target_size> +template <typename T, size_t inline_target_size = default_inline_target_size, + typename Allocator = default_callable_allocator> using function = function_impl<internal::RoundUpToWord(inline_target_size), - /*require_inline=*/false, T>; + /*require_inline=*/false, T, Allocator>; // A move-only callable object wrapper that forces callables to be stored inline // and never performs heap allocation. @@ -82,7 +92,7 @@ using function = function_impl<internal::RoundUpToWord(inline_target_size), // compile. template <typename T, size_t inline_target_size = default_inline_target_size> using inline_function = function_impl<internal::RoundUpToWord(inline_target_size), - /*require_inline=*/true, T>; + /*require_inline=*/true, T, default_callable_allocator>; // Synonym for a function which takes no arguments and produces no result. using closure = function<void()>; @@ -153,11 +163,15 @@ using closure = function<void()>; // fit within a callback without requiring heap allocation. // Defaults to |default_inline_target_size|. // +// |Allocator| is the Allocator used for heap allocation, if required. Its `value_type` is +// irrelevant, since it must support rebinding. +// // Class members are documented in |fit::callback_impl|, below. // -template <typename T, size_t inline_target_size = default_inline_target_size> -using callback = - callback_impl<internal::RoundUpToWord(inline_target_size), /*require_inline=*/false, T>; +template <typename T, size_t inline_target_size = default_inline_target_size, + typename Allocator = default_callable_allocator> +using callback = callback_impl<internal::RoundUpToWord(inline_target_size), + /*require_inline=*/false, T, Allocator>; // A move-only, run-once, callable object wrapper that forces callables to be // stored inline and never performs heap allocation. @@ -167,19 +181,22 @@ using callback = // compile. template <typename T, size_t inline_target_size = default_inline_target_size> using inline_callback = callback_impl<internal::RoundUpToWord(inline_target_size), - /*require_inline=*/true, T>; + /*require_inline=*/true, T, default_callable_allocator>; -template <size_t inline_target_size, bool require_inline, typename Result, typename... Args> -class function_impl<inline_target_size, require_inline, Result(Args...)> final - : private ::fit::internal::function_base<inline_target_size, require_inline, Result(Args...)> { - using base = ::fit::internal::function_base<inline_target_size, require_inline, Result(Args...)>; +template <size_t inline_target_size, bool require_inline, typename Allocator, typename Result, + typename... Args> +class function_impl<inline_target_size, require_inline, Result(Args...), Allocator> final + : private ::fit::internal::function_base<inline_target_size, require_inline, Result(Args...), + Allocator> { + using base = ::fit::internal::function_base<inline_target_size, require_inline, Result(Args...), + Allocator>; // function_base requires private access during share() - friend class ::fit::internal::function_base<inline_target_size, require_inline, Result(Args...)>; + friend base; // supports target() for shared functions friend const void* ::fit::internal::get_target_type_id<>( - const function_impl<inline_target_size, require_inline, Result(Args...)>&); + const function_impl<inline_target_size, require_inline, Result(Args...), Allocator>&); template <typename U> using not_self_type = ::fit::internal::not_same_type<function_impl, U>; @@ -228,10 +245,9 @@ class function_impl<inline_target_size, require_inline, Result(Args...)> final // unexpected behavior of a |fit::function| that would otherwise fail after // one call. To explicitly allow this, simply wrap the |fit::callback| in a // pass-through lambda before passing it to the |fit::function|. - template <size_t other_inline_target_size, bool other_require_inline> - function_impl( - ::fit::callback_impl<other_inline_target_size, other_require_inline, Result(Args...)>) = - delete; + template <size_t other_inline_target_size, bool other_require_inline, typename OtherAllocator> + function_impl(::fit::callback_impl<other_inline_target_size, other_require_inline, + Result(Args...), OtherAllocator>) = delete; // Creates a function with a target moved from another function, // leaving the other function with an empty target. @@ -273,10 +289,9 @@ class function_impl<inline_target_size, require_inline, Result(Args...)> final // fail after one call. To explicitly allow this, simply wrap the // |fit::callback| in a pass-through lambda before assigning it to the // |fit::function|. - template <size_t other_inline_target_size, bool other_require_inline> - function_impl& operator=( - ::fit::callback_impl<other_inline_target_size, other_require_inline, Result(Args...)>) = - delete; + template <size_t other_inline_target_size, bool other_require_inline, typename OtherAllocator> + function_impl& operator=(::fit::callback_impl<other_inline_target_size, other_require_inline, + Result(Args...), OtherAllocator>) = delete; // Move assignment function_impl& operator=(function_impl&& other) noexcept { @@ -313,44 +328,49 @@ class function_impl<inline_target_size, require_inline, Result(Args...)> final } }; -template <size_t inline_target_size, bool require_inline, typename FunctionType> -void swap(function_impl<inline_target_size, require_inline, FunctionType>& a, - function_impl<inline_target_size, require_inline, FunctionType>& b) { +template <size_t inline_target_size, bool require_inline, typename FunctionType, typename Allocator> +void swap(function_impl<inline_target_size, require_inline, FunctionType, Allocator>& a, + function_impl<inline_target_size, require_inline, FunctionType, Allocator>& b) { a.swap(b); } -template <size_t inline_target_size, bool require_inline, typename FunctionType> -bool operator==(const function_impl<inline_target_size, require_inline, FunctionType>& f, +template <size_t inline_target_size, bool require_inline, typename FunctionType, typename Allocator> +bool operator==(const function_impl<inline_target_size, require_inline, FunctionType, Allocator>& f, decltype(nullptr)) { return !f; } -template <size_t inline_target_size, bool require_inline, typename FunctionType> -bool operator==(decltype(nullptr), - const function_impl<inline_target_size, require_inline, FunctionType>& f) { +template <size_t inline_target_size, bool require_inline, typename FunctionType, typename Allocator> +bool operator==( + decltype(nullptr), + const function_impl<inline_target_size, require_inline, FunctionType, Allocator>& f) { return !f; } -template <size_t inline_target_size, bool require_inline, typename FunctionType> -bool operator!=(const function_impl<inline_target_size, require_inline, FunctionType>& f, +template <size_t inline_target_size, bool require_inline, typename FunctionType, typename Allocator> +bool operator!=(const function_impl<inline_target_size, require_inline, FunctionType, Allocator>& f, decltype(nullptr)) { return !!f; } -template <size_t inline_target_size, bool require_inline, typename FunctionType> -bool operator!=(decltype(nullptr), - const function_impl<inline_target_size, require_inline, FunctionType>& f) { +template <size_t inline_target_size, bool require_inline, typename FunctionType, typename Allocator> +bool operator!=( + decltype(nullptr), + const function_impl<inline_target_size, require_inline, FunctionType, Allocator>& f) { return !!f; } -template <size_t inline_target_size, bool require_inline, typename Result, typename... Args> -class callback_impl<inline_target_size, require_inline, Result(Args...)> final - : private ::fit::internal::function_base<inline_target_size, require_inline, Result(Args...)> { - using base = ::fit::internal::function_base<inline_target_size, require_inline, Result(Args...)>; +template <size_t inline_target_size, bool require_inline, typename Allocator, typename Result, + typename... Args> +class callback_impl<inline_target_size, require_inline, Result(Args...), Allocator> final + : private ::fit::internal::function_base<inline_target_size, require_inline, Result(Args...), + Allocator> { + using base = ::fit::internal::function_base<inline_target_size, require_inline, Result(Args...), + Allocator>; // function_base requires private access during share() - friend class ::fit::internal::function_base<inline_target_size, require_inline, Result(Args...)>; + friend base; // supports target() for shared functions friend const void* ::fit::internal::get_target_type_id<>( - const callback_impl<inline_target_size, require_inline, Result(Args...)>&); + const callback_impl<inline_target_size, require_inline, Result(Args...), Allocator>&); template <typename U> using not_self_type = ::fit::internal::not_same_type<callback_impl, U>; @@ -469,30 +489,32 @@ class callback_impl<inline_target_size, require_inline, Result(Args...)> final } }; -template <size_t inline_target_size, bool require_inline, typename FunctionType> -void swap(callback_impl<inline_target_size, require_inline, FunctionType>& a, - callback_impl<inline_target_size, require_inline, FunctionType>& b) { +template <size_t inline_target_size, bool require_inline, typename FunctionType, typename Allocator> +void swap(callback_impl<inline_target_size, require_inline, FunctionType, Allocator>& a, + callback_impl<inline_target_size, require_inline, FunctionType, Allocator>& b) { a.swap(b); } -template <size_t inline_target_size, bool require_inline, typename FunctionType> -bool operator==(const callback_impl<inline_target_size, require_inline, FunctionType>& f, +template <size_t inline_target_size, bool require_inline, typename FunctionType, typename Allocator> +bool operator==(const callback_impl<inline_target_size, require_inline, FunctionType, Allocator>& f, decltype(nullptr)) { return !f; } -template <size_t inline_target_size, bool require_inline, typename FunctionType> -bool operator==(decltype(nullptr), - const callback_impl<inline_target_size, require_inline, FunctionType>& f) { +template <size_t inline_target_size, bool require_inline, typename FunctionType, typename Allocator> +bool operator==( + decltype(nullptr), + const callback_impl<inline_target_size, require_inline, FunctionType, Allocator>& f) { return !f; } -template <size_t inline_target_size, bool require_inline, typename FunctionType> -bool operator!=(const callback_impl<inline_target_size, require_inline, FunctionType>& f, +template <size_t inline_target_size, bool require_inline, typename FunctionType, typename Allocator> +bool operator!=(const callback_impl<inline_target_size, require_inline, FunctionType, Allocator>& f, decltype(nullptr)) { return !!f; } -template <size_t inline_target_size, bool require_inline, typename FunctionType> -bool operator!=(decltype(nullptr), - const callback_impl<inline_target_size, require_inline, FunctionType>& f) { +template <size_t inline_target_size, bool require_inline, typename FunctionType, typename Allocator> +bool operator!=( + decltype(nullptr), + const callback_impl<inline_target_size, require_inline, FunctionType, Allocator>& f) { return !!f; } @@ -537,4 +559,4 @@ auto bind_member(T* instance) { } // namespace fit -#endif // LIB_FIT_INCLUDE_LIB_FIT_FUNCTION_H_ +#endif // LIB_FIT_FUNCTION_H_ diff --git a/third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/internal/compiler.h b/third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/internal/compiler.h index 1bd806414..2b989a780 100644 --- a/third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/internal/compiler.h +++ b/third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/internal/compiler.h @@ -2,20 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef LIB_FIT_INCLUDE_LIB_FIT_INTERNAL_COMPILER_H_ -#define LIB_FIT_INCLUDE_LIB_FIT_INTERNAL_COMPILER_H_ +#ifndef LIB_FIT_INTERNAL_COMPILER_H_ +#define LIB_FIT_INTERNAL_COMPILER_H_ -// Annotate a class or function with C++17's [[nodiscard]] or similar where supported by the -// compiler. -// -// C++14 doesn't support [[nodiscard]], but Clang allows __attribute__((warn_unused_result)) -// to be placed on class declarations. GCC only allows the attribute to be used on methods. -#if __cplusplus >= 201703L -#define LIB_FIT_NODISCARD [[nodiscard]] -#elif defined(__clang__) -#define LIB_FIT_NODISCARD __attribute__((__warn_unused_result__)) -#else -#define LIB_FIT_NODISCARD /* nothing */ -#endif - -#endif // LIB_FIT_INCLUDE_LIB_FIT_INTERNAL_COMPILER_H_ +#endif // LIB_FIT_INTERNAL_COMPILER_H_ diff --git a/third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/internal/function.h b/third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/internal/function.h index dd655f3d0..b2ac66626 100644 --- a/third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/internal/function.h +++ b/third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/internal/function.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef LIB_FIT_INCLUDE_LIB_FIT_INTERNAL_FUNCTION_H_ -#define LIB_FIT_INCLUDE_LIB_FIT_INTERNAL_FUNCTION_H_ +#ifndef LIB_FIT_INTERNAL_FUNCTION_H_ +#define LIB_FIT_INTERNAL_FUNCTION_H_ #include <lib/stdcompat/bit.h> #include <stddef.h> @@ -68,7 +68,8 @@ struct target_ops final : public base_target_ops { static_assert(sizeof(target_ops<void>) == sizeof(void (*)()) * 5, "Unexpected target_ops padding"); -template <typename Callable, bool is_inline, bool is_shared, typename Result, typename... Args> +template <typename Callable, bool is_inline, bool is_shared, typename Allocator, typename Result, + typename... Args> struct target; inline void trivial_target_destroy(void* /*bits*/) {} @@ -96,9 +97,10 @@ struct null_target { static_assert(std::is_same<Unused, void>::value, "Only instantiate null_target with void"); }; -template <typename Result, typename... Args> -struct target<decltype(nullptr), /*is_inline=*/true, /*is_shared=*/false, Result, Args...> final - : public null_target<> {}; +template <typename Allocator, typename Result, typename... Args> +struct target<decltype(nullptr), /*is_inline=*/true, /*is_shared=*/false, Allocator, Result, + Args...> + final : public null_target<> {}; inline void* null_target_get(void* /*bits*/) { return nullptr; } inline void null_target_move(void* /*from_bits*/, void* /*to_bits*/) {} @@ -117,10 +119,8 @@ inline void inline_trivial_target_move(void* from_bits, void* to_bits) { std::memcpy(to_bits, from_bits, size_bytes); } -template <typename Callable, typename Result, typename... Args> -struct target<Callable, - /*is_inline=*/true, /*is_shared=*/false, Result, Args...> - final { +template <typename Callable, typename Allocator, typename Result, typename... Args> +struct target<Callable, /*is_inline=*/true, /*is_shared=*/false, Allocator, Result, Args...> final { template <typename Callable_> static void initialize(void* bits, Callable_&& target) { new (bits) Callable(std::forward<Callable_>(target)); @@ -160,23 +160,25 @@ struct target<Callable, inline void* inline_target_get(void* bits) { return bits; } -template <typename Callable, typename Result, typename... Args> -constexpr target_ops<Result, Args...> target<Callable, - /*is_inline=*/true, - /*is_shared=*/false, Result, Args...>::ops = { - &unshared_target_type_id, &inline_target_get, target::get_move_function(), - target::get_destroy_function(), &target::invoke}; +template <typename Callable, typename Allocator, typename Result, typename... Args> +constexpr target_ops<Result, Args...> + target<Callable, /*is_inline=*/true, /*is_shared=*/false, Allocator, Result, Args...>::ops = { + &unshared_target_type_id, &inline_target_get, target::get_move_function(), + target::get_destroy_function(), &target::invoke}; // vtable for pointer to target function -template <typename Callable, typename Result, typename... Args> -struct target<Callable, - /*is_inline=*/false, /*is_shared=*/false, Result, Args...> +template <typename Callable, typename Allocator, typename Result, typename... Args> +struct target<Callable, /*is_inline=*/false, /*is_shared=*/false, Allocator, Result, Args...> final { template <typename Callable_> static void initialize(void* bits, Callable_&& target) { auto ptr = static_cast<Callable**>(bits); - *ptr = new Callable(std::forward<Callable_>(target)); + CallableAllocator allocator; + *ptr = CallableAllocatorTraits::allocate(allocator, 1u); + if (*ptr) { + CallableAllocatorTraits::construct(allocator, *ptr, std::forward<Callable_>(target)); + } } static Result invoke(void* bits, Args... args) { auto& target = **static_cast<Callable**>(bits); @@ -189,19 +191,33 @@ struct target<Callable, } static void destroy(void* bits) { auto ptr = static_cast<Callable**>(bits); - delete *ptr; + if (*ptr) { + CallableAllocator allocator; + CallableAllocatorTraits::destroy(allocator, *ptr); + CallableAllocatorTraits::deallocate(allocator, *ptr, 1u); + *ptr = nullptr; + } } static const target_ops<Result, Args...> ops; + + private: + using AllocatorTraits = std::allocator_traits<Allocator>; + using CallableAllocator = typename AllocatorTraits::template rebind_alloc<Callable>; + using CallableAllocatorTraits = std::allocator_traits<CallableAllocator>; + + static_assert(CallableAllocatorTraits::is_always_equal::value, + "Objects of type Allocator must always be equal to each other: an Allocator object " + "must be able to deallocate the memory allocated by a different Allocator object."); }; inline void* heap_target_get(void* bits) { return *static_cast<void**>(bits); } -template <typename Callable, typename Result, typename... Args> -constexpr target_ops<Result, Args...> target<Callable, - /*is_inline=*/false, - /*is_shared=*/false, Result, Args...>::ops = { - &unshared_target_type_id, &heap_target_get, &target::move, &target::destroy, &target::invoke}; +template <typename Callable, typename Allocator, typename Result, typename... Args> +constexpr target_ops<Result, Args...> + target<Callable, /*is_inline=*/false, /*is_shared=*/false, Allocator, Result, Args...>::ops = { + &unshared_target_type_id, &heap_target_get, &target::move, &target::destroy, + &target::invoke}; // vtable for fit::function std::shared_ptr to target function @@ -212,13 +228,12 @@ const void* get_target_type_id(const SharedFunction& function_or_callback) { // For this vtable, // Callable by definition will be either a fit::function or fit::callback -template <typename SharedFunction, typename Result, typename... Args> -struct target<SharedFunction, - /*is_inline=*/false, /*is_shared=*/true, Result, Args...> +template <typename SharedFunction, typename Allocator, typename Result, typename... Args> +struct target<SharedFunction, /*is_inline=*/false, /*is_shared=*/true, Allocator, Result, Args...> final { static void initialize(void* bits, SharedFunction target) { new (bits) std::shared_ptr<SharedFunction>( - std::move(std::make_shared<SharedFunction>(std::move(target)))); + std::move(std::allocate_shared<SharedFunction, Allocator>(Allocator(), std::move(target)))); } static void copy_shared_ptr(void* from_bits, void* to_bits) { auto& from_shared_ptr = *static_cast<std::shared_ptr<SharedFunction>*>(from_bits); @@ -246,10 +261,9 @@ struct target<SharedFunction, static const target_ops<Result, Args...> ops; }; -template <typename SharedFunction, typename Result, typename... Args> -constexpr target_ops<Result, Args...> target<SharedFunction, - /*is_inline=*/false, - /*is_shared=*/true, Result, Args...>::ops = { +template <typename SharedFunction, typename Allocator, typename Result, typename... Args> +constexpr target_ops<Result, Args...> target< + SharedFunction, /*is_inline=*/false, /*is_shared=*/true, Allocator, Result, Args...>::ops = { &target::target_type_id, &target::get, &target::move, &target::destroy, &target::invoke}; // Calculates the alignment to use for a function of the provided @@ -388,13 +402,14 @@ class alignas(FunctionAlignment(inline_target_size)) generic_function_base { const base_target_ops* ops_; }; -template <size_t inline_target_size, bool require_inline, typename FunctionType> +template <size_t inline_target_size, bool require_inline, typename FunctionType, typename Allocator> class function_base; // Function implementation details that require the function signature. // See |fit::function| and |fit::callback| documentation for more information. -template <size_t inline_target_size, bool require_inline, typename Result, typename... Args> -class function_base<inline_target_size, require_inline, Result(Args...)> +template <size_t inline_target_size, bool require_inline, typename Allocator, typename Result, + typename... Args> +class function_base<inline_target_size, require_inline, Result(Args...), Allocator> : public generic_function_base<inline_target_size> { using base = generic_function_base<inline_target_size>; @@ -407,11 +422,10 @@ class function_base<inline_target_size, require_inline, Result(Args...)> template <typename Callable> using target_type = target<Callable, (sizeof(Callable) <= inline_target_size), - /*is_shared=*/false, Result, Args...>; + /*is_shared=*/false, Allocator, Result, Args...>; template <typename SharedFunction> - using shared_target_type = target<SharedFunction, - /*is_inline=*/false, - /*is_shared=*/true, Result, Args...>; + using shared_target_type = + target<SharedFunction, /*is_inline=*/false, /*is_shared=*/true, Allocator, Result, Args...>; using ops_type = const target_ops<Result, Args...>*; @@ -495,7 +509,7 @@ class function_base<inline_target_size, require_inline, Result(Args...)> // Note that fit::callback will release the target immediately after // invoke() (also affecting any share()d copies). // Aborts if the function's target is empty. - // TODO(b/241567321): Remove "no sanitize" after pw_protobuf is fixed. + // TODO: b/241567321 - Remove "no sanitize" after pw_protobuf is fixed. Result invoke(Args... args) const PW_NO_SANITIZE("function") { // Down cast the ops to the derived type that this function was instantiated // with, which includes the invoke function. @@ -564,4 +578,4 @@ class function_base<inline_target_size, require_inline, Result(Args...)> } // namespace internal } // namespace fit -#endif // LIB_FIT_INCLUDE_LIB_FIT_INTERNAL_FUNCTION_H_ +#endif // LIB_FIT_INTERNAL_FUNCTION_H_ 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 18a0c8751..fe90c10d3 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 @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef LIB_FIT_INCLUDE_LIB_FIT_INTERNAL_RESULT_H_ -#define LIB_FIT_INCLUDE_LIB_FIT_INTERNAL_RESULT_H_ +#ifndef LIB_FIT_INTERNAL_RESULT_H_ +#define LIB_FIT_INTERNAL_RESULT_H_ #include <lib/fit/internal/compiler.h> #include <lib/stdcompat/type_traits.h> @@ -258,12 +258,12 @@ struct storage_type<storage_class_e::non_trivial, E, T> { return *this; } - constexpr storage_type(storage_type&& other) noexcept( - std::is_nothrow_move_constructible<E>::value&& std::is_nothrow_move_constructible<T>::value) { + constexpr storage_type(storage_type&& other) noexcept(std::is_nothrow_move_constructible_v<E> && + std::is_nothrow_move_constructible_v<T>) { move_from(std::move(other)); } constexpr storage_type& operator=(storage_type&& other) noexcept( - std::is_nothrow_move_assignable<E>::value&& std::is_nothrow_move_assignable<T>::value) { + std::is_nothrow_move_assignable_v<E> && std::is_nothrow_move_assignable_v<T>) { destroy(); move_from(std::move(other)); return *this; @@ -375,12 +375,11 @@ struct storage_type<storage_class_e::non_trivial, E> { return *this; } - constexpr storage_type(storage_type&& other) noexcept( - std::is_nothrow_move_constructible<E>::value) { + constexpr storage_type(storage_type&& other) noexcept(std::is_nothrow_move_constructible_v<E>) { move_from(std::move(other)); } constexpr storage_type& operator=(storage_type&& other) noexcept( - std::is_nothrow_move_assignable<E>::value) { + std::is_nothrow_move_assignable_v<E>) { destroy(); move_from(std::move(other)); return *this; @@ -442,4 +441,4 @@ using storage = storage_type<storage_class_trait<E, Ts...>, E, Ts...>; } // namespace internal } // namespace fit -#endif // LIB_FIT_INCLUDE_LIB_FIT_INTERNAL_RESULT_H_ +#endif // LIB_FIT_INTERNAL_RESULT_H_ diff --git a/third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/internal/utility.h b/third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/internal/utility.h index 2d1f8a03a..14f887725 100644 --- a/third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/internal/utility.h +++ b/third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/internal/utility.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef LIB_FIT_INCLUDE_LIB_FIT_INTERNAL_UTILITY_H_ -#define LIB_FIT_INCLUDE_LIB_FIT_INTERNAL_UTILITY_H_ +#ifndef LIB_FIT_INTERNAL_UTILITY_H_ +#define LIB_FIT_INTERNAL_UTILITY_H_ #include <lib/stdcompat/type_traits.h> @@ -135,4 +135,4 @@ struct is_nothrow_swappable<T, } // namespace internal } // namespace fit -#endif // LIB_FIT_INCLUDE_LIB_FIT_INTERNAL_UTILITY_H_ +#endif // LIB_FIT_INTERNAL_UTILITY_H_ diff --git a/third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/nullable.h b/third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/nullable.h index d6ba9b7ff..56892693b 100644 --- a/third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/nullable.h +++ b/third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/nullable.h @@ -41,8 +41,8 @@ constexpr inline bool is_null(T&&) { // with nullptr. template <typename T> struct is_nullable - : public std::integral_constant<bool, std::is_constructible<T, decltype(nullptr)>::value && - std::is_assignable<T&, decltype(nullptr)>::value && + : public std::integral_constant<bool, std::is_constructible_v<T, decltype(nullptr)> && + std::is_assignable_v<T&, decltype(nullptr)> && is_comparable_with_null<T>::value> {}; template <> struct is_nullable<void> : public std::false_type {}; @@ -62,8 +62,8 @@ struct is_nullable<void> : public std::false_type {}; // TODO(fxbug.dev/4681): fit::nullable does not precisely mirror // cpp17::optional. This should be corrected to avoid surprises when switching // between the types. -template <typename T, bool = (is_nullable<T>::value && std::is_constructible<T, T&&>::value && - std::is_assignable<T&, T&&>::value)> +template <typename T, bool = (is_nullable<T>::value && std::is_constructible_v<T, T&&> && + std::is_assignable_v<T&, T&&>)> class nullable final { public: using value_type = T; @@ -131,30 +131,26 @@ class nullable<T, true> final { constexpr T& value() & { if (has_value()) { return value_; - } else { - PW_ASSERT(false); } + PW_ASSERT(false); } constexpr const T& value() const& { if (has_value()) { return value_; - } else { - PW_ASSERT(false); } + PW_ASSERT(false); } constexpr T&& value() && { if (has_value()) { return std::move(value_); - } else { - PW_ASSERT(false); } + PW_ASSERT(false); } constexpr const T&& value() const&& { if (has_value()) { return std::move(value_); - } else { - PW_ASSERT(false); } + PW_ASSERT(false); } template <typename U = T> 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 a7f77cac9..86bbb9041 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 @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef LIB_FIT_INCLUDE_LIB_FIT_RESULT_H_ -#define LIB_FIT_INCLUDE_LIB_FIT_RESULT_H_ +#ifndef LIB_FIT_RESULT_H_ +#define LIB_FIT_RESULT_H_ #include <lib/fit/internal/compiler.h> #include <lib/fit/internal/result.h> @@ -192,7 +192,7 @@ class success<> { #if __cplusplus >= 201703L // Deduction guides to simplify zero and single argument success expressions in C++17. -success()->success<>; +success() -> success<>; template <typename T> success(T) -> success<T>; @@ -226,9 +226,15 @@ constexpr success<> ok() { return success<>{}; } template <typename E, typename... Ts> class result; +// This suppresses the '-Wctad-maybe-unsupported' compiler warning when CTAD is used. +// +// See https://github.com/llvm/llvm-project/blob/42874f6/libcxx/include/__config#L1259-L1261. +template <class... Tag> +result(typename Tag::__allow_ctad...) -> result<Tag...>; + // Specialization of result for one value type. template <typename E, typename T> -class LIB_FIT_NODISCARD result<E, T> { +class [[nodiscard]] result<E, T> { static_assert(!::fit::internal::is_success_v<E>, "fit::success may not be used as the error type of fit::result!"); static_assert(!cpp17::is_same_v<failed, std::decay_t<T>>, @@ -473,7 +479,7 @@ class LIB_FIT_NODISCARD result<E, T> { // Specialization of the result type for zero values. template <typename E> -class LIB_FIT_NODISCARD result<E> { +class [[nodiscard]] result<E> { static_assert(!::fit::internal::is_success_v<E>, "fit::success may not be used as the error type of fit::result!"); @@ -797,4 +803,4 @@ constexpr bool operator>=(const T& lhs, const result<F, U>& rhs) { } // namespace fit -#endif // LIB_FIT_INCLUDE_LIB_FIT_RESULT_H_ +#endif // LIB_FIT_RESULT_H_ diff --git a/third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/traits.h b/third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/traits.h index 916a47507..f2c8c61f0 100644 --- a/third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/traits.h +++ b/third_party/fuchsia/repo/sdk/lib/fit/include/lib/fit/traits.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef LIB_FIT_INCLUDE_LIB_FIT_TRAITS_H_ -#define LIB_FIT_INCLUDE_LIB_FIT_TRAITS_H_ +#ifndef LIB_FIT_TRAITS_H_ +#define LIB_FIT_TRAITS_H_ #include <lib/stdcompat/type_traits.h> @@ -178,4 +178,4 @@ constexpr bool is_detected_convertible_v = is_detected_convertible<To, Op, Args. } // namespace fit -#endif // LIB_FIT_INCLUDE_LIB_FIT_TRAITS_H_ +#endif // LIB_FIT_TRAITS_H_ |