diff options
author | Yilong Li <liyl@google.com> | 2021-05-07 06:51:06 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2021-05-07 06:51:06 +0000 |
commit | f4fa6a3bfbea1a79e57b4a06e89297eace1a1038 (patch) | |
tree | aff1b4461812e734d2c708f17e99ae725ca1d39a | |
parent | d79cf524db780279b22949b9e1458f096fa02a1d (diff) | |
parent | 14a93e9a8a583279d9366a4cc3e7a548378b10c4 (diff) | |
download | goldfish-opengl-f4fa6a3bfbea1a79e57b4a06e89297eace1a1038.tar.gz |
Merge "base: Add "fit" library"
-rw-r--r-- | BUILD.gn | 7 | ||||
-rw-r--r-- | android-emu/android/base/fit/Defer.h | 157 | ||||
-rw-r--r-- | android-emu/android/base/fit/Function.h | 513 | ||||
-rw-r--r-- | android-emu/android/base/fit/FunctionInternal.h | 456 | ||||
-rw-r--r-- | android-emu/android/base/fit/Nullable.h | 265 | ||||
-rw-r--r-- | android-emu/android/base/fit/README | 150 | ||||
-rw-r--r-- | android-emu/android/base/fit/ThreadChecker.h | 87 | ||||
-rw-r--r-- | android-emu/android/base/fit/ThreadSafety.h | 81 | ||||
-rw-r--r-- | android-emu/android/base/fit/UtilityInternal.h | 146 |
9 files changed, 1862 insertions, 0 deletions
@@ -16,6 +16,13 @@ shared_library("libvulkan_goldfish") { "android-emu/android/base/files/Stream.h", "android-emu/android/base/files/StreamSerializing.cpp", "android-emu/android/base/files/StreamSerializing.h", + "android-emu/android/base/fit/Defer.h", + "android-emu/android/base/fit/Function.h", + "android-emu/android/base/fit/FunctionInternal.h", + "android-emu/android/base/fit/Nullable.h", + "android-emu/android/base/fit/ThreadChecker.h", + "android-emu/android/base/fit/ThreadSafety.h", + "android-emu/android/base/fit/UtilityInternal.h", "android-emu/android/base/ring_buffer.c", "android-emu/android/base/synchronization/AndroidConditionVariable.h", "android-emu/android/base/synchronization/AndroidLock.h", diff --git a/android-emu/android/base/fit/Defer.h b/android-emu/android/base/fit/Defer.h new file mode 100644 index 00000000..d120c322 --- /dev/null +++ b/android-emu/android/base/fit/Defer.h @@ -0,0 +1,157 @@ +// Copyright 2021 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. + +// 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. + +#pragma once + +#include <utility> + +#include "Function.h" +#include "Nullable.h" + +namespace android::base { +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 DeferredAction final { +public: + // Creates a deferred action without a pending target. + DeferredAction() = default; + explicit DeferredAction(decltype(nullptr)) {} + + // Creates a deferred action with a pending target. + explicit DeferredAction(T target) : mTarget(std::move(target)) {} + + // Creates a deferred action with a pending target moved from another + // deferred action, leaving the other one without a pending target. + DeferredAction(DeferredAction&& other) : mTarget(std::move(other.mTarget)) { + other.mTarget.reset(); + } + + // Invokes and releases the deferred action's pending target (if any). + ~DeferredAction() { call(); } + + // Returns true if the deferred action has a pending target. + explicit operator bool() const { return !!mTarget; } + + // 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. + DeferredAction& operator=(DeferredAction&& other) { + if (&other == this) + return *this; + call(); + mTarget = std::move(other.mTarget); + other.mTarget.reset(); + return *this; + } + + // Invokes and releases the deferred action's pending target (if any). + void call() { + if (mTarget) { + // Move to a local to guard against re-entrance. + T local_target = std::move(*mTarget); + mTarget.reset(); + local_target(); + } + } + + // Releases the deferred action's pending target (if any) without + // invoking it. + void cancel() { mTarget.reset(); } + DeferredAction& operator=(decltype(nullptr)) { + cancel(); + return *this; + } + + // Assigns a new target to the deferred action. + DeferredAction& operator=(T target) { + mTarget = std::move(target); + return *this; + } + + DeferredAction(const DeferredAction& other) = delete; + DeferredAction& operator=(const DeferredAction& other) = delete; + +private: + Nullable<T> mTarget; +}; + +template <typename T> +bool operator==(const DeferredAction<T>& action, decltype(nullptr)) { + return !action; +} +template <typename T> +bool operator==(decltype(nullptr), const DeferredAction<T>& action) { + return !action; +} +template <typename T> +bool operator!=(const DeferredAction<T>& action, decltype(nullptr)) { + return !!action; +} +template <typename T> +bool operator!=(decltype(nullptr), const DeferredAction<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> +inline DeferredAction<T> defer(T target) { + return DeferredAction<T>(std::move(target)); +} + +// Alias for a deferred_action using a fit::Callback. +using DeferredCallback = DeferredAction<fit::Callback<void()>>; + +// Defers execution of a fit::Callback with no arguments. See |fit::defer| for +// details. +inline DeferredCallback deferCallback(fit::Callback<void()> target) { + return DeferredCallback(std::move(target)); +} + +} // namespace fit +} // namespace android::base diff --git a/android-emu/android/base/fit/Function.h b/android-emu/android/base/fit/Function.h new file mode 100644 index 00000000..4f4b17da --- /dev/null +++ b/android-emu/android/base/fit/Function.h @@ -0,0 +1,513 @@ +// Copyright 2021 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. + +// Copyright 2017 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. + +#pragma once + +#include "FunctionInternal.h" +#include "UtilityInternal.h" + +namespace android::base { +namespace fit { + +template <size_t inlineTargetSize, bool requireInline, typename Result, typename... Args> +class FunctionImpl; + +template <size_t inlineTargetSize, bool requireInline, typename Result, typename... Args> +class CallbackImpl; + +// The default size allowance for storing a target inline within a function +// object, in bytes. This default allows for inline storage of targets +// as big as two pointers, such as an object pointer and a pointer to a member +// function. +constexpr size_t kDefaultInlineTargetSize = sizeof(void*) * 2; + +// A |fit::Function| is a move-only polymorphic function wrapper. +// +// If you need a class with similar characteristics that also ensures +// "run-once" semantics (such as callbacks shared with timeouts, or for +// service requests with redundant, failover, or fallback service providers), +// see |fit::Callback|. +// +// |fit::Function<T>| behaves like |std::function<T>| except that it is +// move-only instead of copyable, so it can hold targets that cannot be copied, +// such as mutable lambdas, and immutable lambdas that capture move-only +// objects. +// +// Targets of up to |inlineTargetSize| bytes in size (rounded up for memory +// alignment) are stored inline within the function object without incurring +// any heap allocation. Larger callable objects will be moved to the heap as +// required. +// +// See also |fit::InlineFunction<T, size>| for more control over allocation +// behavior. +// +// SYNOPSIS +// +// |T| is the function's signature. e.g. void(int, std::string). +// +// |inlineTargetSize| is the minimum size of target that is guaranteed to +// fit within a function without requiring heap allocation. +// Defaults to |kDefaultInlineTargetSize|. +// +// Class members are documented in |fit::FunctionImpl|, below. +// +// EXAMPLES +// +// - +// https://fuchsia.googlesource.com/fuchsia/+/HEAD/sdk/lib/fit/test/examples/function_example1.cc +// - +// https://fuchsia.googlesource.com/fuchsia/+/HEAD/sdk/lib/fit/test/examples/function_example2.cc +// +template <typename T, size_t inlineTargetSize = kDefaultInlineTargetSize> +using function = FunctionImpl<inlineTargetSize, /*requireInline=*/false, T>; + +// A move-only callable object wrapper that forces callables to be stored inline +// and never performs heap allocation. +// +// Behaves just like |fit::Function<T, inlineTargetSize>| except that +// attempting to store a target larger than |inlineTargetSize| will fail to +// compile. +template <typename T, size_t inlineTargetSize = kDefaultInlineTargetSize> +using InlineFunction = FunctionImpl<inlineTargetSize, + /*requireInline=*/true, + T>; + +// Synonym for a function which takes no arguments and produces no result. +using closure = function<void()>; + +// A |fit::Callback| is a move-only polymorphic function wrapper that also +// ensures "run-once" semantics (such as callbacks shared with timeouts, or for +// service requests with redundant, failover, or fallback service providers). +// A |fit::Callback| releases it's resources after the first call, and can be +// inspected before calling, so a potential caller can know if it should call +// the function, or skip the call because the target was already called. +// +// If you need a move-only function class with typical function characteristics, +// that permits multiple invocations of the same function, see |fit::Function|. +// +// |fit::Callback<T>| behaves like |std::function<T>| except: +// +// 1. It is move-only instead of copyable, so it can hold targets that cannot +// be copied, such as mutable lambdas, and immutable lambdas that capture +// move-only objects. +// 2. On the first call to invoke a |fit::Callback|, the target function held +// by the |fit::Callback| cannot be called again. +// +// When a |fit::Callback| is invoked for the first time, the target function is +// released and destructed, along with any resources owned by that function +// (typically the objects captured by a lambda). +// +// A |fit::Callback| in the "already called" state has the same state as a +// |fit::Callback| that has been assigned to |nullptr|. It can be compared to +// |nullptr| (via "==" or "!=", and its "operator bool()" returns false, which +// provides a convenient way to gate whether or not the |fit::Callback| should +// be called. (Note that invoking an empty |fit::Callback| or |fit::Function| +// will cause a program abort!) +// +// As an example, sharing |fit::Callback| between both a service and a timeout +// might look something like this: +// +// void service_with_timeout(fit::Callback<void(bool)> cb, uint timeout_ms) { +// service_request([cb = cb.share()]() mutable { if (cb) cb(false); }); +// timeout(timeout_ms, [cb = std::move(cb)]() mutable { if (cb) cb(true); }); +// } +// +// Since |fit::Callback| objects are move-only, and not copyable, duplicate +// references to the same |fit::Callback| can be obtained via share(), as shown +// in the example above. This method converts the |fit::Callback| into a +// reference-counted version of the |fit::Callback| and returns a copy of the +// reference as another |fit::Callback| with the same target function. +// +// What is notable about |fit::Callback<T>.share()| is that invoking any shared +// copy will "nullify" all shared copies, as shown in the example. +// +// Note that |fit::Callback| is NOT thread-safe by default. If multi-threaded +// support is required, you would need to implement your own mutex, or similar +// guard, before checking and calling a |fit::Callback|. +// +// Targets of up to |inlineTargetSize| bytes in size (rounded up for memory +// alignment) are stored inline within the callback object without incurring +// any heap allocation. Larger callable objects will be moved to the heap as +// required. +// +// See also |fit::inline_callback<T, size>| for more control over allocation +// behavior. +// +// SYNOPSIS +// +// |T| is the callback's signature. e.g. void(int, std::string). +// +// |inlineTargetSize| is the minimum size of target that is guaranteed to +// fit within a callback without requiring heap allocation. +// Defaults to |kDefaultInlineTargetSize|. +// +// Class members are documented in |fit::CallbackImpl|, below. +// +template <typename T, size_t inlineTargetSize = kDefaultInlineTargetSize> +using Callback = CallbackImpl<inlineTargetSize, /*requireInline=*/false, T>; + +// A move-only, run-once, callable object wrapper that forces callables to be +// stored inline and never performs heap allocation. +// +// Behaves just like |fit::Callback<T, inlineTargetSize>| except that +// attempting to store a target larger than |inlineTargetSize| will fail to +// compile. +template <typename T, size_t inlineTargetSize = kDefaultInlineTargetSize> +using InlineCallback = CallbackImpl<inlineTargetSize, + /*requireInline=*/true, + T>; + +template <size_t inlineTargetSize, bool requireInline, typename Result, typename... Args> +class FunctionImpl<inlineTargetSize, requireInline, Result(Args...)> final + : private ::android::base::fit::internal:: + function_base<inlineTargetSize, requireInline, Result(Args...)> { + using Base = ::android::base::fit::internal:: + function_base<inlineTargetSize, requireInline, Result(Args...)>; + + // function_base requires private access during share() + friend class ::android::base::fit::internal:: + function_base<inlineTargetSize, requireInline, Result(Args...)>; + + // supports target() for shared functions + friend const void* ::android::base::fit::internal::get_target_type_id<>( + const FunctionImpl<inlineTargetSize, requireInline, Result(Args...)>&); + + template <typename U> + using NotSelfType = ::android::base::fit::internal::NotSameType<FunctionImpl, U>; + + template <typename... Conditions> + using RequiresConditions = ::android::base::fit::internal::RequiresConditions<Conditions...>; + + template <typename... Conditions> + using AssignmentRequiresConditions = + ::android::base::fit::internal::AssignmentRequiresConditions<FunctionImpl&, Conditions...>; + +public: + // The function's result type. + using typename Base::result_type; + + // Initializes an empty (null) function. Attempting to call an empty + // function will abort the program. + FunctionImpl() = default; + + // Creates a function with an empty target (same outcome as the default + // constructor). + FunctionImpl(decltype(nullptr)) : Base(nullptr) {} + + // Creates a function bound to the specified function pointer. + // If target == nullptr, assigns an empty target. + FunctionImpl(Result (*target)(Args...)) : Base(target) {} + + // Creates a function bound to the specified callable object. + // If target == nullptr, assigns an empty target. + // + // For functors, we need to capture the raw type but also restrict on the + // existence of an appropriate operator () to resolve overloads and implicit + // casts properly. + // + // Note that specializations of this template method that take fit::Callback + // objects as the target Callable are deleted (see below). + template <typename Callable, + RequiresConditions< + std::is_convertible<decltype(std::declval<Callable&>()(std::declval<Args>()...)), + result_type>, + NotSelfType<Callable>> = true> + FunctionImpl(Callable&& target) : Base(std::forward<Callable>(target)) {} + + // Deletes the specializations of FunctionImpl(Callable) that would allow + // a |fit::Function| to be constructed from a |fit::Callback|. This prevents + // 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 otherInlineTargetSize, bool otherRequireInline> + FunctionImpl(::android::base::fit::CallbackImpl<otherInlineTargetSize, + otherRequireInline, + Result(Args...)>) = delete; + + // Creates a function with a target moved from another function, + // leaving the other function with an empty target. + FunctionImpl(FunctionImpl&& other) : Base(static_cast<Base&&>(other)) {} + + // Destroys the function, releasing its target. + ~FunctionImpl() = default; + + // Assigns the function to an empty target. Attempting to invoke the + // function will abort the program. + FunctionImpl& operator=(decltype(nullptr)) { + Base::assign(nullptr); + return *this; + } + + // Assigns the function to the specified callable object. If target == + // nullptr, assigns an empty target. + // + // For functors, we need to capture the raw type but also restrict on the + // existence of an appropriate operator () to resolve overloads and implicit + // casts properly. + // + // Note that specializations of this template method that take fit::Callback + // objects as the target Callable are deleted (see below). + template <typename Callable> + AssignmentRequiresConditions< + std::is_convertible<decltype(std::declval<Callable&>()(std::declval<Args>()...)), + result_type>, + NotSelfType<Callable>> + operator=(Callable&& target) { + Base::assign(std::forward<Callable>(target)); + return *this; + } + + // Deletes the specializations of operator=(Callable) that would allow + // a |fit::Function| to be assigned from a |fit::Callback|. This + // prevents 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 assigning it to the + // |fit::Function|. + template <size_t otherInlineTargetSize, bool otherRequireInline> + FunctionImpl& operator=(::android::base::fit::CallbackImpl<otherInlineTargetSize, + otherRequireInline, + Result(Args...)>) = delete; + + // Move assignment + FunctionImpl& operator=(FunctionImpl&& other) { + if (&other == this) + return *this; + Base::assign(static_cast<Base&&>(other)); + return *this; + } + + // Swaps the functions' targets. + void swap(FunctionImpl& other) { Base::swap(other); } + + // Returns a pointer to the function's target. + using Base::target; + + // Returns true if the function has a non-empty target. + using Base::operator bool; + + // Invokes the function's target. + // Aborts if the function's target is empty. + Result operator()(Args... args) const { return Base::invoke(std::forward<Args>(args)...); } + + // Returns a new function object that invokes the same target. + // The target itself is not copied; it is moved to the heap and its + // lifetime is extended until all references have been released. + // + // Note: This method is not supported on |fit::InlineFunction<>| + // because it may incur a heap allocation which is contrary to + // the stated purpose of |fit::InlineFunction<>|. + FunctionImpl share() { + FunctionImpl copy; + Base::template share_with<FunctionImpl>(copy); + return copy; + } +}; + +template <size_t inlineTargetSize, bool requireInline, typename Result, typename... Args> +void swap(FunctionImpl<inlineTargetSize, requireInline, Result, Args...>& a, + FunctionImpl<inlineTargetSize, requireInline, Result, Args...>& b) { + a.swap(b); +} + +template <size_t inlineTargetSize, bool requireInline, typename Result, typename... Args> +bool operator==(const FunctionImpl<inlineTargetSize, requireInline, Result, Args...>& f, + decltype(nullptr)) { + return !f; +} +template <size_t inlineTargetSize, bool requireInline, typename Result, typename... Args> +bool operator==(decltype(nullptr), + const FunctionImpl<inlineTargetSize, requireInline, Result, Args...>& f) { + return !f; +} +template <size_t inlineTargetSize, bool requireInline, typename Result, typename... Args> +bool operator!=(const FunctionImpl<inlineTargetSize, requireInline, Result, Args...>& f, + decltype(nullptr)) { + return !!f; +} +template <size_t inlineTargetSize, bool requireInline, typename Result, typename... Args> +bool operator!=(decltype(nullptr), + const FunctionImpl<inlineTargetSize, requireInline, Result, Args...>& f) { + return !!f; +} + +template <size_t inlineTargetSize, bool requireInline, typename Result, typename... Args> +class CallbackImpl<inlineTargetSize, requireInline, Result(Args...)> final + : private ::android::base::fit::internal:: + function_base<inlineTargetSize, requireInline, Result(Args...)> { + using Base = ::android::base::fit::internal:: + function_base<inlineTargetSize, requireInline, Result(Args...)>; + + // function_base requires private access during share() + friend class ::android::base::fit::internal:: + function_base<inlineTargetSize, requireInline, Result(Args...)>; + + // supports target() for shared functions + friend const void* ::android::base::fit::internal::get_target_type_id<>( + const CallbackImpl<inlineTargetSize, requireInline, Result(Args...)>&); + + template <typename U> + using NotSelfType = ::android::base::fit::internal::NotSameType<CallbackImpl, U>; + + template <typename... Conditions> + using RequiresConditions = ::android::base::fit::internal::RequiresConditions<Conditions...>; + + template <typename... Conditions> + using AssignmentRequiresConditions = + ::android::base::fit::internal::AssignmentRequiresConditions<CallbackImpl&, Conditions...>; + +public: + // The callback function's result type. + using typename Base::result_type; + + // Initializes an empty (null) callback. Attempting to call an empty + // callback will abort the program. + CallbackImpl() = default; + + // Creates a callback with an empty target (same outcome as the default + // constructor). + CallbackImpl(decltype(nullptr)) : Base(nullptr) {} + + // Creates a callback bound to the specified function pointer. + // If target == nullptr, assigns an empty target. + CallbackImpl(Result (*target)(Args...)) : Base(target) {} + + // Creates a callback bound to the specified callable object. + // If target == nullptr, assigns an empty target. + // + // For functors, we need to capture the raw type but also restrict on the + // existence of an appropriate operator () to resolve overloads and implicit + // casts properly. + template <typename Callable, + RequiresConditions< + std::is_convertible<decltype(std::declval<Callable&>()(std::declval<Args>()...)), + result_type>, + NotSelfType<Callable>> = true> + CallbackImpl(Callable&& target) : Base(std::forward<Callable>(target)) {} + + // Creates a callback with a target moved from another callback, + // leaving the other callback with an empty target. + CallbackImpl(CallbackImpl&& other) : Base(static_cast<Base&&>(other)) {} + + // Destroys the callback, releasing its target. + ~CallbackImpl() = default; + + // Assigns the callback to an empty target. Attempting to invoke the + // callback will abort the program. + CallbackImpl& operator=(decltype(nullptr)) { + Base::assign(nullptr); + return *this; + } + + // Assigns the callback to the specified callable object. If target == + // nullptr, assigns an empty target. + // + // For functors, we need to capture the raw type but also restrict on the + // existence of an appropriate operator () to resolve overloads and implicit + // casts properly. + template <typename Callable> + AssignmentRequiresConditions< + std::is_convertible<decltype(std::declval<Callable&>()(std::declval<Args>()...)), + result_type>, + NotSelfType<Callable>> + operator=(Callable&& target) { + Base::assign(std::forward<Callable>(target)); + return *this; + } + + // Move assignment + CallbackImpl& operator=(CallbackImpl&& other) { + if (&other == this) + return *this; + Base::assign(static_cast<Base&&>(other)); + return *this; + } + + // Swaps the callbacks' targets. + void swap(CallbackImpl& other) { Base::swap(other); } + + // Returns a pointer to the callback's target. + using Base::target; + + // Returns true if the callback has a non-empty target. + using Base::operator bool; + + // Invokes the callback's target. + // Aborts if the callback's target is empty. + // |fit::Callback| must be non-const to invoke. Before the target function + // is actually called, the fit::Callback will be set to the default empty + // state (== nullptr, and operator bool() will subsequently return |false|). + // The target function will then be released after the function is called. + // If the callback was shared, any remaining copies will also be cleared. + Result operator()(Args... args) { + auto temp = std::move(*this); + return temp.invoke(std::forward<Args>(args)...); + } + + // Returns a new callback object that invokes the same target. + // The target itself is not copied; it is moved to the heap and its + // lifetime is extended until all references have been released. + // For |fit::Callback| (unlike fit::Function), the first invocation of the + // callback will release all references to the target. All callbacks + // derived from the same original callback (via share()) will be cleared, + // as if set to |nullptr|, and "operator bool()" will return false. + // + // Note: This method is not supported on |fit::InlineFunction<>| + // because it may incur a heap allocation which is contrary to + // the stated purpose of |fit::InlineFunction<>|. + CallbackImpl share() { + CallbackImpl copy; + Base::template share_with<CallbackImpl>(copy); + return copy; + } +}; + +template <size_t inlineTargetSize, bool requireInline, typename Result, typename... Args> +void swap(CallbackImpl<inlineTargetSize, requireInline, Result, Args...>& a, + CallbackImpl<inlineTargetSize, requireInline, Result, Args...>& b) { + a.swap(b); +} + +template <size_t inlineTargetSize, bool requireInline, typename Result, typename... Args> +bool operator==(const CallbackImpl<inlineTargetSize, requireInline, Result, Args...>& f, + decltype(nullptr)) { + return !f; +} +template <size_t inlineTargetSize, bool requireInline, typename Result, typename... Args> +bool operator==(decltype(nullptr), + const CallbackImpl<inlineTargetSize, requireInline, Result, Args...>& f) { + return !f; +} +template <size_t inlineTargetSize, bool requireInline, typename Result, typename... Args> +bool operator!=(const CallbackImpl<inlineTargetSize, requireInline, Result, Args...>& f, + decltype(nullptr)) { + return !!f; +} +template <size_t inlineTargetSize, bool requireInline, typename Result, typename... Args> +bool operator!=(decltype(nullptr), + const CallbackImpl<inlineTargetSize, requireInline, Result, Args...>& f) { + return !!f; +} + +// Returns a Callable object that invokes a member function of an object. +template <typename R, typename T, typename... Args> +auto bindMember(T* instance, R (T::*fn)(Args...)) { + return [instance, fn](Args... args) { return (instance->*fn)(std::forward<Args>(args)...); }; +} + +} // namespace fit +} // namespace android::base diff --git a/android-emu/android/base/fit/FunctionInternal.h b/android-emu/android/base/fit/FunctionInternal.h new file mode 100644 index 00000000..3fb1ac53 --- /dev/null +++ b/android-emu/android/base/fit/FunctionInternal.h @@ -0,0 +1,456 @@ +// Copyright 2021 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. + +// Copyright 2017 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. + +#pragma once + +#include <stddef.h> +#include <stdlib.h> + +#include <memory> + +#include "Nullable.h" + +#include <new> +#include <type_traits> +#include <utility> + +namespace android::base { +namespace fit { +namespace internal { + +template <typename Result, typename... Args> +struct target_ops final { + const void* (*target_type_id)(void* bits, const void* impl_ops); + void* (*get)(void* bits); + Result (*invoke)(void* bits, Args... args); + void (*move)(void* from_bits, void* to_bits); + void (*destroy)(void* bits); +}; + +template <typename Callable, bool is_inline, bool is_shared, typename Result, typename... Args> +struct target; + +inline const void* unshared_target_type_id(void* bits, const void* impl_ops) { + return impl_ops; +} + +// vtable for nullptr (empty target function) + +template <typename Result, typename... Args> +struct target<decltype(nullptr), + /*is_inline=*/true, + /*is_shared=*/false, + Result, + Args...> + final { + static Result invoke(void* bits, Args... args) { __builtin_abort(); } + + static const target_ops<Result, Args...> ops; +}; + +inline void* null_target_get(void* bits) { + return nullptr; +} +inline void null_target_move(void* from_bits, void* to_bits) {} +inline void null_target_destroy(void* bits) {} + +template <typename Result, typename... Args> +constexpr target_ops<Result, Args...> target<decltype(nullptr), + /*is_inline=*/true, + /*is_shared=*/false, + Result, + Args...>::ops = { + &unshared_target_type_id, &null_target_get, &target::invoke, &null_target_move, + &null_target_destroy}; + +// vtable for inline target function + +template <typename Callable, typename Result, typename... Args> +struct target<Callable, + /*is_inline=*/true, + /*is_shared=*/false, + Result, + Args...> + final { + template <typename Callable_> + static void initialize(void* bits, Callable_&& target) { + new (bits) Callable(std::forward<Callable_>(target)); + } + static Result invoke(void* bits, Args... args) { + auto& target = *static_cast<Callable*>(bits); + return target(std::forward<Args>(args)...); + } + static void move(void* from_bits, void* to_bits) { + auto& from_target = *static_cast<Callable*>(from_bits); + new (to_bits) Callable(std::move(from_target)); + from_target.~Callable(); + } + static void destroy(void* bits) { + auto& target = *static_cast<Callable*>(bits); + target.~Callable(); + } + + static const target_ops<Result, Args...> ops; +}; + +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::invoke, &target::move, &target::destroy}; + +// vtable for pointer to target function + +template <typename Callable, typename Result, typename... Args> +struct target<Callable, + /*is_inline=*/false, + /*is_shared=*/false, + 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)); + } + static Result invoke(void* bits, Args... args) { + auto& target = **static_cast<Callable**>(bits); + return target(std::forward<Args>(args)...); + } + static void move(void* from_bits, void* to_bits) { + auto from_ptr = static_cast<Callable**>(from_bits); + auto to_ptr = static_cast<Callable**>(to_bits); + *to_ptr = *from_ptr; + } + static void destroy(void* bits) { + auto ptr = static_cast<Callable**>(bits); + delete *ptr; + } + + static const target_ops<Result, Args...> ops; +}; + +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::invoke, &target::move, &target::destroy}; + +// vtable for fit::function std::shared_ptr to target function + +template <typename SharedFunction> +const void* get_target_type_id(const SharedFunction& function_or_callback) { + return function_or_callback.target_type_id(); +} + +// 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...> + final { + static void initialize(void* bits, SharedFunction target) { + new (bits) std::shared_ptr<SharedFunction>( + std::move(std::make_shared<SharedFunction>(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); + new (to_bits) std::shared_ptr<SharedFunction>(from_shared_ptr); + } + static const void* target_type_id(void* bits, const void* impl_ops) { + auto& function_or_callback = **static_cast<std::shared_ptr<SharedFunction>*>(bits); + return ::android::base::fit::internal::get_target_type_id(function_or_callback); + } + static void* get(void* bits) { + auto& function_or_callback = **static_cast<std::shared_ptr<SharedFunction>*>(bits); + return function_or_callback.template target<SharedFunction>( + /*check=*/false); // void* will fail the check + } + static Result invoke(void* bits, Args... args) { + auto& function_or_callback = **static_cast<std::shared_ptr<SharedFunction>*>(bits); + return function_or_callback(std::forward<Args>(args)...); + } + static void move(void* from_bits, void* to_bits) { + auto from_shared_ptr = std::move(*static_cast<std::shared_ptr<SharedFunction>*>(from_bits)); + new (to_bits) std::shared_ptr<SharedFunction>(std::move(from_shared_ptr)); + } + static void destroy(void* bits) { + static_cast<std::shared_ptr<SharedFunction>*>(bits)->reset(); + } + + 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 = { + &target::target_type_id, &target::get, &target::invoke, &target::move, &target::destroy}; + +template <size_t inline_target_size, bool requireInline, typename Result, typename... Args> +class function_base; + +// Function implementation details. +// See |fit::function| and |fit::callback| documentation for more information. +template <size_t inline_target_size, bool requireInline, typename Result, typename... Args> +class function_base<inline_target_size, requireInline, Result(Args...)> { + using ops_type = const target_ops<Result, Args...>*; + using storage_type = typename std::aligned_storage<( + inline_target_size >= sizeof(void*) ? inline_target_size : sizeof(void*))>:: + type; // avoid including <algorithm> for max + template <typename Callable> + using target_type = target<Callable, + (sizeof(Callable) <= sizeof(storage_type)), + /*is_shared=*/false, + Result, + Args...>; + template <typename SharedFunction> + using shared_target_type = target<SharedFunction, + /*is_inline=*/false, + /*is_shared=*/true, + Result, + Args...>; + using null_target_type = target_type<decltype(nullptr)>; + +protected: + using result_type = Result; + + function_base() { initialize_null_target(); } + + function_base(decltype(nullptr)) { initialize_null_target(); } + + function_base(Result (*target)(Args...)) { initialize_target(target); } + + template <typename Callable, + typename = std::enable_if_t< + std::is_convertible<decltype(std::declval<Callable&>()(std::declval<Args>()...)), + result_type>::value>> + function_base(Callable&& target) { + initialize_target(std::forward<Callable>(target)); + } + + function_base(function_base&& other) { move_target_from(std::move(other)); } + + ~function_base() { destroy_target(); } + + // Returns true if the function has a non-empty target. + explicit operator bool() const { return ops_->get(&bits_) != nullptr; } + + // Returns a pointer to the function's target. + // If |check| is true (the default), the function _may_ abort if the + // caller tries to assign the target to a varible of the wrong type. (This + // check is currently skipped for share()d objects.) + // Note the shared pointer vtable must set |check| to false to assign the + // target to |void*|. + template <typename Callable> + Callable* target(bool check = true) { + if (check) + check_target_type<Callable>(); + return static_cast<Callable*>(ops_->get(&bits_)); + } + + // Returns a pointer to the function's target (const version). + // If |check| is true (the default), the function _may_ abort if the + // caller tries to assign the target to a varible of the wrong type. (This + // check is currently skipped for share()d objects.) + // Note the shared pointer vtable must set |check| to false to assign the + // target to |void*|. + template <typename Callable> + const Callable* target(bool check = true) const { + if (check) + check_target_type<Callable>(); + return static_cast<Callable*>(ops_->get(&bits_)); + } + + // Used by the derived "impl" classes to implement share(). + // + // The caller creates a new object of the same type as itself, and passes in + // the empty object. This function first checks if |this| is already shared, + // and if not, creates a new version of itself containing a + // |std::shared_ptr| to its original self, and updates |ops_| to the vtable + // for the shared version. + // + // Then it copies its |shared_ptr| to the |bits_| of the given |copy|, + // and assigns the same shared pointer vtable to the copy's |ops_|. + // + // The target itself is not copied; it is moved to the heap and its + // lifetime is extended until all references have been released. + // + // Note: This method is not supported on |fit::InlineFunction<>| + // because it may incur a heap allocation which is contrary to + // the stated purpose of |fit::InlineFunction<>|. + template <typename SharedFunction> + void share_with(SharedFunction& copy) { + static_assert(!requireInline, "Inline functions cannot be shared."); + if (ops_->get(&bits_) != nullptr) { + if (ops_ != &shared_target_type<SharedFunction>::ops) { + convert_to_shared_target<SharedFunction>(); + } + copy_shared_target_to(copy); + } + } + + // Used by derived "impl" classes to implement operator()(). + // Invokes the function's target. + // 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. + Result invoke(Args... args) const { return ops_->invoke(&bits_, std::forward<Args>(args)...); } + + // Used by derived "impl" classes to implement operator=(). + // Assigns an empty target. + void assign(decltype(nullptr)) { + destroy_target(); + initialize_null_target(); + } + + // Used by derived "impl" classes to implement operator=(). + // Assigns the function's target. + // If target == nullptr, assigns an empty target. + template <typename Callable, + typename = std::enable_if_t< + std::is_convertible<decltype(std::declval<Callable&>()(std::declval<Args>()...)), + result_type>::value>> + void assign(Callable&& target) { + destroy_target(); + initialize_target(std::forward<Callable>(target)); + } + + // Used by derived "impl" classes to implement operator=(). + // Assigns the function with a target moved from another function, + // leaving the other function with an empty target. + void assign(function_base&& other) { + destroy_target(); + move_target_from(std::move(other)); + } + + void swap(function_base& other) { + if (&other == this) + return; + ops_type temp_ops = ops_; + storage_type temp_bits; + ops_->move(&bits_, &temp_bits); + + ops_ = other.ops_; + other.ops_->move(&other.bits_, &bits_); + + other.ops_ = temp_ops; + temp_ops->move(&temp_bits, &other.bits_); + } + + // returns an opaque ID unique to the |Callable| type of the target. + // Used by check_target_type. + const void* target_type_id() const { return ops_->target_type_id(&bits_, ops_); } + + // Deleted copy constructor and assign. |function_base| implementations are + // move-only. + function_base(const function_base& other) = delete; + function_base& operator=(const function_base& other) = delete; + + // Move assignment must be provided by subclasses. + function_base& operator=(function_base&& other) = delete; + +private: + // Implements the move operation, used by move construction and move + // assignment. Leaves other target initialized to null. + void move_target_from(function_base&& other) { + ops_ = other.ops_; + other.ops_->move(&other.bits_, &bits_); + other.initialize_null_target(); + } + + // fit::function and fit::callback are not directly copyable, but share() + // will create shared references to the original object. This method + // implements the copy operation for the |std::shared_ptr| wrapper. + template <typename SharedFunction> + void copy_shared_target_to(SharedFunction& copy) { + copy.destroy_target(); + assert(ops_ == &shared_target_type<SharedFunction>::ops); + shared_target_type<SharedFunction>::copy_shared_ptr(&bits_, ©.bits_); + copy.ops_ = ops_; + } + + // assumes target is uninitialized + void initialize_null_target() { ops_ = &null_target_type::ops; } + + // target may or may not be initialized. + template <typename Callable> + void initialize_target(Callable&& target) { + // Convert function or function references to function pointer. + using DecayedCallable = std::decay_t<Callable>; + static_assert( + std::alignment_of<DecayedCallable>::value <= std::alignment_of<storage_type>::value, + "Alignment of Callable must be <= alignment of max_align_t."); + static_assert(!requireInline || sizeof(DecayedCallable) <= inline_target_size, + "Callable too large to store inline as requested."); + if (is_null(target)) { + initialize_null_target(); + } else { + ops_ = &target_type<DecayedCallable>::ops; + target_type<DecayedCallable>::initialize(&bits_, std::forward<Callable>(target)); + } + } + + // assumes target is uninitialized + template <typename SharedFunction> + void convert_to_shared_target() { + shared_target_type<SharedFunction>::initialize( + &bits_, std::move(*static_cast<SharedFunction*>(this))); + ops_ = &shared_target_type<SharedFunction>::ops; + } + + // leaves target uninitialized + void destroy_target() { ops_->destroy(&bits_); } + + // Called by target() if |check| is true. + // Checks the template parameter, usually inferred from the context of + // the call to target(), and aborts the program if it can determine that + // the Callable type is not compatible with the function's Result and Args. + template <typename Callable> + void check_target_type() const { + if (target_type<Callable>::ops.target_type_id(nullptr, &target_type<Callable>::ops) != + target_type_id()) { + __builtin_abort(); + } + } + + ops_type ops_; + mutable storage_type bits_; +}; + +} // namespace internal + +} // namespace fit +} // namespace android::base diff --git a/android-emu/android/base/fit/Nullable.h b/android-emu/android/base/fit/Nullable.h new file mode 100644 index 00000000..e05021bb --- /dev/null +++ b/android-emu/android/base/fit/Nullable.h @@ -0,0 +1,265 @@ +// Copyright 2021 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. + +// 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. + +#pragma once + +#include <assert.h> + +#include <optional> +#include <type_traits> +#include <utility> + +namespace android::base { +namespace fit { + +// Determines whether a type can be compared with nullptr. +template <typename T, typename Comparable = bool> +struct IsComparableWithNull : public std::false_type {}; +template <typename T> +struct IsComparableWithNull<T, decltype(std::declval<const T&>() == nullptr)> + : public std::true_type {}; + +// Suppress the warning when the compiler can see that a nullable value is +// never equal to nullptr. +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Waddress" +template <typename T, std::enable_if_t<IsComparableWithNull<T>::value, bool> = true> +constexpr inline bool isNull(T&& value) { + return std::forward<T>(value) == nullptr; +} +#pragma GCC diagnostic pop + +template <typename T, std::enable_if_t<!IsComparableWithNull<T>::value, bool> = false> +constexpr inline bool isNull(T&&) { + return false; +} + +// Determines whether a type can be initialized, assigned, and compared +// with nullptr. +template <typename T> +struct IsNullable + : public std::integral_constant<bool, + std::is_constructible<T, decltype(nullptr)>::value && + std::is_assignable<T&, decltype(nullptr)>::value && + IsComparableWithNull<T>::value> {}; +template <> +struct IsNullable<void> : public std::false_type {}; + +// Holds a value or nullptr. +// +// This class is similar to |std::optional<T>| except that it uses less +// storage when the value type can be initialized, assigned, and compared +// with nullptr. +// +// For example: +// - sizeof(fit::nullable<void*>) == sizeof(void*) +// - sizeof(std::optional<void*>) == sizeof(struct { bool; void*; }) +// - sizeof(fit::nullable<int>) == sizeof(struct { bool; int; }) +// - sizeof(std::optional<int>) == sizeof(struct { bool; int; }) +// +// TODO(fxbug.dev/4681): fit::nullable does not precisely mirror +// std::optional. This should be corrected to avoid surprises when switching +// between the types. +template <typename T, + bool = (IsNullable<T>::value && std::is_constructible<T, T&&>::value && + std::is_assignable<T&, T&&>::value)> +class Nullable final { +public: + using value_type = T; + + ~Nullable() = default; + constexpr Nullable() = default; + + explicit constexpr Nullable(decltype(nullptr)) {} + explicit constexpr Nullable(T value) : mOpt(std::move(value)) {} + + constexpr Nullable(const Nullable& other) = default; + constexpr Nullable& operator=(const Nullable& other) = default; + + constexpr Nullable(Nullable&& other) = default; + constexpr Nullable& operator=(Nullable&& other) = default; + + constexpr T& value() & { return mOpt.value(); } + constexpr const T& value() const& { return mOpt.value(); } + constexpr T&& value() && { return std::move(mOpt.value()); } + constexpr const T&& value() const&& { return std::move(mOpt.value()); } + + template <typename U = T> + constexpr T valueOr(U&& default_value) const { + return mOpt.value_or(std::forward<U>(default_value)); + } + + constexpr T* operator->() { return &*mOpt; } + constexpr const T* operator->() const { return &*mOpt; } + constexpr T& operator*() { return *mOpt; } + constexpr const T& operator*() const { return *mOpt; } + + constexpr bool hasValue() const { return mOpt.has_value(); } + explicit constexpr operator bool() const { return hasValue(); } + + constexpr Nullable& operator=(decltype(nullptr)) { + reset(); + return *this; + } + + constexpr Nullable& operator=(T value) { + mOpt = std::move(value); + return *this; + } + + constexpr void reset() { mOpt.reset(); } + + constexpr void swap(Nullable& other) { mOpt.swap(other.mOpt); } + +private: + std::optional<T> mOpt; +}; + +template <typename T> +class Nullable<T, true> final { +public: + using value_type = T; + + constexpr Nullable() : mValue(nullptr) {} + explicit constexpr Nullable(decltype(nullptr)) : mValue(nullptr) {} + explicit constexpr Nullable(T value) : mValue(std::move(value)) {} + constexpr Nullable(const Nullable& other) = default; + constexpr Nullable(Nullable&& other) : mValue(std::move(other.value_)) {} + ~Nullable() = default; + + constexpr T& value() & { + if (hasValue()) { + return mValue; + } else { + __builtin_abort(); + } + } + constexpr const T& value() const& { + if (hasValue()) { + return mValue; + } else { + __builtin_abort(); + } + } + constexpr T&& value() && { + if (hasValue()) { + return std::move(mValue); + } else { + __builtin_abort(); + } + } + constexpr const T&& value() const&& { + if (hasValue()) { + return std::move(mValue); + } else { + __builtin_abort(); + } + } + + template <typename U = T> + constexpr T valueOr(U&& default_value) const { + return hasValue() ? mValue : static_cast<T>(std::forward<U>(default_value)); + } + + constexpr T* operator->() { return &mValue; } + constexpr const T* operator->() const { return &mValue; } + constexpr T& operator*() { return mValue; } + constexpr const T& operator*() const { return mValue; } + + constexpr bool hasValue() const { return !(mValue == nullptr); } + explicit constexpr operator bool() const { return hasValue(); } + + constexpr Nullable& operator=(const Nullable& other) = default; + constexpr Nullable& operator=(Nullable&& other) { + mValue = std::move(other.value_); + return *this; + } + + constexpr Nullable& operator=(decltype(nullptr)) { + reset(); + return *this; + } + + constexpr Nullable& operator=(T value) { + mValue = std::move(value); + return *this; + } + + constexpr void reset() { mValue = nullptr; } + + constexpr void swap(Nullable& other) { + using std::swap; + swap(mValue, other.value_); + } + +private: + T mValue; +}; + +template <typename T> +void swap(Nullable<T>& a, Nullable<T>& b) { + a.swap(b); +} + +template <typename T> +constexpr bool operator==(const Nullable<T>& lhs, decltype(nullptr)) { + return !lhs.hasValue(); +} +template <typename T> +constexpr bool operator!=(const Nullable<T>& lhs, decltype(nullptr)) { + return lhs.hasValue(); +} + +template <typename T> +constexpr bool operator==(decltype(nullptr), const Nullable<T>& rhs) { + return !rhs.hasValue(); +} +template <typename T> +constexpr bool operator!=(decltype(nullptr), const Nullable<T>& rhs) { + return rhs.hasValue(); +} + +template <typename T, typename U> +constexpr bool operator==(const Nullable<T>& lhs, const Nullable<U>& rhs) { + return (lhs.hasValue() == rhs.hasValue()) && (!lhs.hasValue() || *lhs == *rhs); +} +template <typename T, typename U> +constexpr bool operator!=(const Nullable<T>& lhs, const Nullable<U>& rhs) { + return (lhs.hasValue() != rhs.hasValue()) || (lhs.hasValue() && *lhs != *rhs); +} + +template <typename T, typename U> +constexpr bool operator==(const Nullable<T>& lhs, const U& rhs) { + return (lhs.hasValue() != isNull(rhs)) && (!lhs.hasValue() || *lhs == rhs); +} +template <typename T, typename U> +constexpr bool operator!=(const Nullable<T>& lhs, const U& rhs) { + return (lhs.hasValue() == isNull(rhs)) || (lhs.hasValue() && *lhs != rhs); +} + +template <typename T, typename U> +constexpr bool operator==(const T& lhs, const Nullable<U>& rhs) { + return (isNull(lhs) != rhs.hasValue()) && (!rhs.hasValue() || lhs == *rhs); +} +template <typename T, typename U> +constexpr bool operator!=(const T& lhs, const Nullable<U>& rhs) { + return (isNull(lhs) == rhs.hasValue()) || (rhs.hasValue() && lhs != *rhs); +} + +} // namespace fit +} // namespace android::base diff --git a/android-emu/android/base/fit/README b/android-emu/android/base/fit/README new file mode 100644 index 00000000..4b3eeebe --- /dev/null +++ b/android-emu/android/base/fit/README @@ -0,0 +1,150 @@ +libfit + +Source: https://fuchsia.googlesource.com/fuchsia/+/main/sdk/lib/fit/ +Version: 36303cd2d1611cb1b670235692d01a92e83ecd21 +License: + +Copyright 2019 The Fuchsia Authors. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +====== + +FIT is a lean library of portable C++ abstractions for control flow and +memory management beyond what is offered by the C++ 17 standard library. + +FIT only depends on the C++ language and standard library, including some C++17 +library features. It offers essential enhancements to the C++ standard library +rather than attempting to replace it or become a framework for writing +applications. FIT can be thought of as an "annex" that expresses a few ideas +we wish the C++ standard library might itself implement someday. + +FIT is lean. + +## What Belongs in FIT + +Several Fuchsia SDK libraries, such as *libfidl*, depend on FIT and on the C++ +standard library. As these libraries are broadly used, we must take care in +deciding what features to include in FIT to avoid burdening developers with +unnecessary code or dependencies. + +In general, the goal is to identify specific abstractions that make sense to +generalize across the entire ecosystem of Fuchsia C++ applications. These will +necessarily be somewhat low-level but high impact. We don't want to add code to +FIT simply because we think it's cool. We need evidence that it is a common +idiom and that a broad audience of developers will significantly benefit from +its promotion. + +Here are a few criteria to consider: + +- Is the feature lightweight, general-purpose, and platform-independent? +- Is the feature not well served by other means, particularly by the C++ + standard library? +- Is the feature needed by a Fuchsia SDK library? +- Does the feature embody a beneficial idiom that clients of the Fuchsia SDK + commonly use? +- Has the feature been re-implemented many times already leading to code + fragmentation that we would like to eliminate? + +If in doubt, leave it out. See [Justifications] below. + +## What Doesn't Belong in FIT + +FIT is not intended to become a catch-all class library. + +Specifically prohibited features: + +- Features that introduce dependencies on libraries other than the C and C++ + standard library. +- Features that only work on certain operating systems. +- Collection classes where the C++ 17 standard library already offers an + adequate (if not perfect) alternative. +- Classes that impose an implementation burden on clients such as event loops, + dispatchers, frameworks, and other glue code. + +## Implementation Considerations + +FIT is not exception safe (but could be made to be in the future). + +## Style Conventions + +The API style was modified to fit current android::base library conventions. + +In brief: + +- Class identifiers are CamelCase +- Class methods and variable identifiers use "camelCase", class fields use + "mCamelCase". +- Template parameters are `CamelCase`. +- Preprocessor macros are `UPPER_SNAKE_CASE`. + +## Justifications + +These sections explain why certain features are in FIT. + +### fit::Function + +- *libfidl*'s API needs a callable function wrapper with move semantics but + C++ 14's `std::function` only supports copyable function objects which forces + FIDL to allocate callback state on the heap making programs less efficient + and harder to write. +- Lots of other C++ code uses callbacks extensively and would benefit from move + semantics for similar reasons. +- So we should create a move-only function wrapper to use everywhere. + +### fit::Defer + +- When writing asynchronous event-driven programs, it can become challenging + to ensure that resources remain in scope for the duration of an operation + in progress and are subsequently released. +- The C++ 14 standard library offers several classes with RAII semantics, such + as `std::unique_ptr`, which are helpful in these situations. Unfortunately the + C++ 14 standard library does not offer affordances for easily invoking a + function when a block or object goes out of scope short of implementing a + new class from scratch. +- We have observed several re-implementations of the same idea throughout the + system. +- So we should create a simple way to invoke a function on scope exit. + +### fit::Nullable + +- Case study: fit::defer has a need to store a closure that may be nullable. + We were able to replace its hand-rolled lifetime management code with + fit::nullable thereby vastly simplifying its implementation. +- Case study: fit::future has a need to track its own validity along with + a continuation that may or not be present. +- Case study: We have previously observed bugs where developers were + surprised when assigning a null closure to wrappers such as fit::function + fit::defer, or fit::future left these objects in a supposedly "valid" + but uninvocable state. These objects therefore take care to detect + null closures and enter an "invalid" state. Using fit::is_null and + fit::nullable makes it easier to eliminate this redundant state and + simplifies the API for clients of these wrappers. +- std::optional can be effective here but it doesn't directly handle nullity + so it takes more care to coalesce the null and "not present" states. + std::optional also increases the size of the object to carry an extra + bool and passing, whereas fit::nullable eliminates this overhead by + taking advantage of the underlying value's null state (if there is one). +- So we introduce fit::nullable to handle both cases systematically while + still hewing close to the semantics of std::optional. diff --git a/android-emu/android/base/fit/ThreadChecker.h b/android-emu/android/base/fit/ThreadChecker.h new file mode 100644 index 00000000..3859ecf1 --- /dev/null +++ b/android-emu/android/base/fit/ThreadChecker.h @@ -0,0 +1,87 @@ +// Copyright 2021 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. + +// Copyright 2016 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. + +// A class for checking that the current thread is/isn't the same as an initial +// thread. + +#pragma once + +#include <assert.h> + +#include <thread> + +#include "ThreadSafety.h" + +namespace android::base { +namespace fit { + +// A simple class that records the identity of the thread that it was created +// on, and at later points can tell if the current thread is the same as its +// creation thread. This class is thread-safe. +// +// In addition to providing an explicit check of the current thread, +// |thread_checker| complies with BasicLockable, checking the current thread +// when |lock| is called. This allows static thread safety analysis to be used +// to ensure that resources are accessed in a context that is checked (at debug +// runtime) to ensure that it's running on the correct thread: +// +// class MyClass { +// public: +// void Foo() { +// std::lock_guard<fit::thread_checker> locker(thread_checker_); +// resource_ = 0; +// } +// private: +// fit::thread_checker thread_checker_; +// int resource_ GUARDED_BY(thread_checker_); +// } +// +// Note: |lock| checks the thread in debug builds only. +// +class CAPABILITY("mutex") ThreadChecker final { +public: + // Default constructor. Constructs a thread checker bound to the currently + // running thread. + ThreadChecker() : self_(std::this_thread::get_id()) {} + // Constructs a thread checker bound to an explicit other thread. + explicit ThreadChecker(std::thread::id self) : self_(self) {} + ~ThreadChecker() = default; + + // Returns true if the current thread is the thread this object was created + // on and false otherwise. + bool isThreadValid() const { return std::this_thread::get_id() == self_; } + + // Implementation of the BaseLockable requirement + void lock() ACQUIRE() { assert(isThreadValid()); } + + void unlock() RELEASE() {} + +private: + const std::thread::id self_; +}; + +#ifndef NDEBUG +#define DECLARE_THREAD_CHECKER(c) android::base::fit::ThreadChecker c +#define DCHECK_IS_THREAD_VALID(c) assert((c).isThreadValid()) +#else +#define DECLARE_THREAD_CHECKER(c) +#define DCHECK_IS_THREAD_VALID(c) ((void)0) +#endif + +} // namespace fit +} // namespace android::base diff --git a/android-emu/android/base/fit/ThreadSafety.h b/android-emu/android/base/fit/ThreadSafety.h new file mode 100644 index 00000000..bce528e4 --- /dev/null +++ b/android-emu/android/base/fit/ThreadSafety.h @@ -0,0 +1,81 @@ +// Copyright 2021 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. + +// 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. + +#pragma once + +// Other libraries (e.g. libbase) may have already defined these symbols. +// Only define them if they are not defined elsewhere. + +// Thread-safety annotations. +// Currently these are only supported on Clang. +#ifndef THREAD_ANNOTATION_ATTRIBUTE__ +#if defined(__clang__) && defined(_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS) && \ + __has_attribute(acquire_capability) +#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x)) +#else +#define THREAD_ANNOTATION_ATTRIBUTE__(x) +#endif +#endif // THREAD_ANNOTATION_ATTRIBUTE__ + +#ifndef CAPABILITY +#define CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(__capability__(x)) +#endif // CAPABILITY + +#ifndef GUARDED_BY +#define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(__guarded_by__(x)) +#endif // GUARDED_BY + +#ifndef ACQUIRE +#define ACQUIRE(...) THREAD_ANNOTATION_ATTRIBUTE__(__acquire_capability__(__VA_ARGS__)) +#endif // ACQUIRE + +#ifndef TRY_ACQUIRE +#define TRY_ACQUIRE(...) THREAD_ANNOTATION_ATTRIBUTE__(__try_acquire_capability__(__VA_ARGS__)) +#endif // TRY_ACQUIRE + +#ifndef ACQUIRED_BEFORE +#define ACQUIRED_BEFORE(...) THREAD_ANNOTATION_ATTRIBUTE__(__acquired_before__(__VA_ARGS__)) +#endif // ACQUIRED_BEFORE + +#ifndef ACQUIRED_AFTER +#define ACQUIRED_AFTER(...) THREAD_ANNOTATION_ATTRIBUTE__(__acquired_after__(__VA_ARGS__)) +#endif // ACQUIRED_AFTER + +#ifndef RELEASE +#define RELEASE(...) THREAD_ANNOTATION_ATTRIBUTE__(__release_capability__(__VA_ARGS__)) +#endif // RELEASE + +#ifndef REQUIRES +#define REQUIRES(...) THREAD_ANNOTATION_ATTRIBUTE__(__requires_capability__(__VA_ARGS__)) +#endif // REQUIRES + +#ifndef EXCLUDES +#define EXCLUDES(...) THREAD_ANNOTATION_ATTRIBUTE__(__locks_excluded__(__VA_ARGS__)) +#endif // EXCLUDES + +#ifndef RETURN_CAPABILITY +#define RETURN_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(__lock_returned__(x)) +#endif // RETURN_CAPABILITY + +#ifndef SCOPED_CAPABILITY +#define SCOPED_CAPABILITY THREAD_ANNOTATION_ATTRIBUTE__(__scoped_lockable__) +#endif // SCOPED_CAPABILITY + +#ifndef NO_THREAD_SAFETY_ANALYSIS +#define NO_THREAD_SAFETY_ANALYSIS THREAD_ANNOTATION_ATTRIBUTE__(__no_thread_safety_analysis__) +#endif // NO_THREAD_SAFETY_ANALYSIS diff --git a/android-emu/android/base/fit/UtilityInternal.h b/android-emu/android/base/fit/UtilityInternal.h new file mode 100644 index 00000000..274105e0 --- /dev/null +++ b/android-emu/android/base/fit/UtilityInternal.h @@ -0,0 +1,146 @@ +// Copyright 2021 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. + +// Copyright 2019 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. + +#pragma once + +#include <type_traits> +#include <utility> + +namespace android::base { +namespace fit { +namespace internal { + +// Utility to return the first type in a parameter pack. +template <typename... Ts> +struct First; +template <typename FirstType, typename... Rest> +struct First<FirstType, Rest...> { + using Type = FirstType; +}; + +template <typename... Ts> +using First_t = typename First<Ts...>::Type; + +// Utility to count the occurences of type T in the parameter pack Ts. +template <typename T, typename... Ts> +struct OccurencesOf : std::integral_constant<size_t, 0> {}; +template <typename T, typename U> +struct OccurencesOf<T, U> : std::integral_constant<size_t, std::is_same<T, U>::value> {}; +template <typename T, typename First, typename... Rest> +struct OccurencesOf<T, First, Rest...> + : std::integral_constant<size_t, + OccurencesOf<T, First>::value + OccurencesOf<T, Rest...>::value> {}; + +template <typename T, typename... Ts> +constexpr size_t occurencesOf = OccurencesOf<T, Ts...>::value; + +// Utility to remove const, volatile, and reference qualifiers. +template <typename T> +using RemoveCvref_t = std::remove_cv_t<std::remove_reference_t<T>>; + +// Evaluates to truth-like when type T matches type U with cv-reference removed. +template <typename T, typename U> +using NotSameType = std::negation<std::is_same<T, RemoveCvref_t<U>>>; + +// Concept helper for constructors. +template <typename... Conditions> +using RequiresConditions = std::enable_if_t<std::conjunction_v<Conditions...>, bool>; + +// Concept helper for assignment operators. +template <typename Return, typename... Conditions> +using AssignmentRequiresConditions = + std::enable_if_t<std::conjunction_v<Conditions...>, std::add_lvalue_reference_t<Return>>; + +// Evaluates to true when every element type of Ts is trivially destructible. +template <typename... Ts> +constexpr bool isTriviallyDestructible = std::conjunction_v<std::is_trivially_destructible<Ts>...>; + +// Evaluates to true when every element type of Ts is trivially copyable. +template <typename... Ts> +constexpr bool isTriviallyCopyable = + (std::conjunction_v<std::is_trivially_copy_assignable<Ts>...> && + std::conjunction_v<std::is_trivially_copy_constructible<Ts>...>); + +// Evaluates to true when every element type of Ts is trivially movable. +template <typename... Ts> +constexpr bool isTriviallyMovable = + (std::conjunction_v<std::is_trivially_move_assignable<Ts>...> && + std::conjunction_v<std::is_trivially_move_constructible<Ts>...>); + +// Enable if relational operator is convertible to bool and the optional +// conditions are true. +template <typename Op, typename... Conditions> +using enable_relop_t = + std::enable_if_t<(std::is_convertible<Op, bool>::value && std::conjunction_v<Conditions...>), + bool>; + +template <typename T> +struct Identity { + using Type = T; +}; + +// Evaluates to true when T is an unbounded array. +template <typename T> +struct IsUnboundedArray : std::conjunction<std::is_array<T>, std::negation<std::extent<T>>> {}; + +// Returns true when T is a complete type or an unbounded array. +template <typename T, size_t = sizeof(T)> +constexpr bool isCompleteOrUnboundedArray(Identity<T>) { + return true; +} +template <typename Identity, typename T = typename Identity::Type> +constexpr bool isCompleteOrUnboundedArray(Identity) { + return std::disjunction<std::is_reference<T>, std::is_function<T>, std::is_void<T>, + IsUnboundedArray<T>>::value; +} + +// Using swap for ADL. This directive is contained within the fit::internal +// namespace, which prevents leaking std::swap into user namespaces. Doing this +// at namespace scope is necessary to lookup swap via ADL while preserving the +// noexcept() specification of the resulting lookup. +using std::swap; + +// Evaluates to true when T is swappable. +template <typename T, typename = void> +struct IsSwappable : std::false_type { + static_assert(isCompleteOrUnboundedArray(Identity<T>{}), + "T must be a complete type or an unbounded array!"); +}; +template <typename T> +struct IsSwappable<T, std::void_t<decltype(swap(std::declval<T&>(), std::declval<T&>()))>> + : std::true_type { + static_assert(isCompleteOrUnboundedArray(Identity<T>{}), + "T must be a complete type or an unbounded array!"); +}; + +// Evaluates to true when T is nothrow swappable. +template <typename T, typename = void> +struct IsNothrowSwappable : std::false_type { + static_assert(isCompleteOrUnboundedArray(Identity<T>{}), + "T must be a complete type or an unbounded array!"); +}; +template <typename T> +struct IsNothrowSwappable<T, std::void_t<decltype(swap(std::declval<T&>(), std::declval<T&>()))>> + : std::integral_constant<bool, noexcept(swap(std::declval<T&>(), std::declval<T&>()))> { + static_assert(isCompleteOrUnboundedArray(Identity<T>{}), + "T must be a complete type or an unbounded array!"); +}; + +} // namespace internal +} // namespace fit +} // namespace android::base |