HELLO·Android
系统源代码
IT资讯
技术文章
我的收藏
注册
登录
-
我收藏的文章
创建代码块
我的代码块
我的账号
Oreo
|
8.0.0_r4
下载
查看原文件
收藏
根目录
frameworks
native
libs
vr
libpdx
private
pdx
rpc
variant.h
#ifndef ANDROID_PDX_RPC_VARIANT_H_ #define ANDROID_PDX_RPC_VARIANT_H_ #include
#include
#include
namespace android { namespace pdx { namespace rpc { // Type tag denoting an empty variant. struct EmptyVariant {}; namespace detail { // Type for matching tagged overloads. template
struct TypeTag {}; // Determines the type of the I-th element of Types.... template
using TypeForIndex = std::tuple_element_t
>; // Determines the type tag for the I-th element of Types.... template
using TypeTagForIndex = TypeTag
>; // Enable if T(Args...) is well formed. template
using EnableIfConstructible = typename std::enable_if
::value, R>::type; // Enable if T(Args...) is not well formed. template
using EnableIfNotConstructible = typename std::enable_if::value, R>::type; // Determines whether T is an element of Types...; template
struct HasType : std::false_type {}; template
struct HasType
: std::is_same
, std::decay_t
> {}; template
struct HasType
: std::integral_constant
::value || HasType
::value> {}; // Defines set operations on a set of Types... template
struct Set { // Default specialization catches the empty set, which is always a subset. template
struct IsSubset : std::true_type {}; template
struct IsSubset
: HasType
{}; template
struct IsSubset
: std::integral_constant
::value && IsSubset
::value> {}; }; // Determines the number of elements of Types... that are constructible from // From. template
struct ConstructibleCount; template
struct ConstructibleCount
: std::integral_constant
::value> {}; template
struct ConstructibleCount
: std::integral_constant
::value + ConstructibleCount
::value> {}; // Enable if T is an element of Types... template
using EnableIfElement = typename std::enable_if
::value, R>::type; // Enable if T is not an element of Types... template
using EnableIfNotElement = typename std::enable_if::value, R>::type; // Enable if T is convertible to an element of Types... T is considered // convertible IIF a single element of Types... is assignable from T and T is // not a direct element of Types... template
using EnableIfConvertible = typename std::enable_if::value && ConstructibleCount
::value == 1, R>::type; // Enable if T is assignable to an element of Types... T is considered // assignable IFF a single element of Types... is constructible from T or T is a // direct element of Types.... Note that T is REQUIRED to be an element of // Types... when multiple elements are constructible from T to prevent ambiguity // in conversion. template
using EnableIfAssignable = typename std::enable_if
::value || ConstructibleCount
::value == 1, R>::type; // Selects a type for SFINAE constructor selection. template
using Select = std::conditional_t
; // Recursive union type. template
union Union; // Specialization handling a singular type, terminating template recursion. template
union Union
{ Union() {} ~Union() {} template
Union(std::int32_t index, std::int32_t* index_out, TypeTag
, T&& value) : first_(std::forward
(value)) { *index_out = index; } template
> Union(std::int32_t index, std::int32_t* index_out, T&& value) : first_(std::forward
(value)) { *index_out = index; } Type& get(TypeTag
) { return first_; } const Type& get(TypeTag
) const { return first_; } EmptyVariant get(TypeTag
) const { return {}; } constexpr std::int32_t index(TypeTag
) const { return 0; } template
std::int32_t Construct(TypeTag
, Args&&... args) { new (&first_) Type(std::forward
(args)...); return 0; } template
EnableIfConstructible
Construct(Args&&... args) { new (&first_) Type(std::forward
(args)...); return 0; } void Destruct(std::int32_t target_index) { if (target_index == index(TypeTag
{})) { (&get(TypeTag
{}))->~Type(); } } template
bool Assign(TypeTag
, std::int32_t target_index, T&& value) { if (target_index == 0) { first_ = std::forward
(value); return true; } else { return false; } } template
EnableIfConstructible
Assign(std::int32_t target_index, T&& value) { if (target_index == 0) { first_ = std::forward
(value); return true; } else { return false; } } template
EnableIfNotConstructible
Assign(std::int32_t /*target_index*/, T&& /*value*/) { return false; } template
decltype(auto) Visit(std::int32_t target_index, Op&& op) { if (target_index == index(TypeTag
{})) return std::forward
(op)(get(TypeTag
{})); else return std::forward
(op)(get(TypeTag
{})); } template
decltype(auto) Visit(std::int32_t target_index, Op&& op) const { if (target_index == index(TypeTag
{})) return std::forward
(op)(get(TypeTag
{})); else return std::forward
(op)(get(TypeTag
{})); } template
bool Become(std::int32_t target_index, Args&&... args) { if (target_index == index(TypeTag
{})) { Construct(TypeTag
{}, std::forward
(args)...); return true; } else { return false; } } private: Type first_; }; // Specialization that recursively unions types from the paramater pack. template
union Union
{ Union() {} ~Union() {} template
Union(std::int32_t index, std::int32_t* index_out, TypeTag
, T&& value) : first_(std::forward
(value)) { *index_out = index; } template
Union(std::int32_t index, std::int32_t* index_out, TypeTag
, U&& value) : rest_(index + 1, index_out, TypeTag
{}, std::forward
(value)) {} struct FirstType {}; struct RestType {}; template
using SelectConstructor = Select
::value == 1, FirstType, RestType>; template
Union(std::int32_t index, std::int32_t* index_out, T&& value) : Union(index, index_out, std::forward
(value), SelectConstructor
{}) {} template
Union(std::int32_t index, std::int32_t* index_out, T&& value, FirstType) : first_(std::forward
(value)) { *index_out = index; } template
Union(std::int32_t index, std::int32_t* index_out, T&& value, RestType) : rest_(index + 1, index_out, std::forward
(value)) {} First& get(TypeTag
) { return first_; } const First& get(TypeTag
) const { return first_; } constexpr std::int32_t index(TypeTag
) const { return 0; } template
T& get(TypeTag
) { return rest_.template get(TypeTag
{}); } template
const T& get(TypeTag
) const { return rest_.template get(TypeTag
{}); } template
constexpr std::int32_t index(TypeTag
) const { return 1 + rest_.template index(TypeTag
{}); } template
std::int32_t Construct(TypeTag
, Args&&... args) { new (&first_) First(std::forward
(args)...); return 0; } template
std::int32_t Construct(TypeTag
, Args&&... args) { return 1 + rest_.template Construct(TypeTag
{}, std::forward
(args)...); } template
EnableIfConstructible
Construct( Args&&... args) { new (&first_) First(std::forward
(args)...); return 0; } template
EnableIfNotConstructible
Construct( Args&&... args) { return 1 + rest_.template Construct(std::forward
(args)...); } void Destruct(std::int32_t target_index) { if (target_index == index(TypeTag
{})) { (get(TypeTag
{})).~First(); } else { rest_.Destruct(target_index - 1); } } template
bool Assign(TypeTag
, std::int32_t target_index, T&& value) { if (target_index == 0) { first_ = std::forward
(value); return true; } else { return false; } } template
bool Assign(TypeTag
, std::int32_t target_index, U&& value) { return rest_.Assign(TypeTag
{}, target_index - 1, std::forward
(value)); } template
EnableIfConstructible
Assign(std::int32_t target_index, T&& value) { if (target_index == 0) { first_ = std::forward
(value); return true; } else { return rest_.Assign(target_index - 1, std::forward
(value)); } } template
EnableIfNotConstructible
Assign(std::int32_t target_index, T&& value) { return rest_.Assign(target_index - 1, std::forward
(value)); } // Recursively traverses the union and calls Op on the active value when the // active type is found. If the union is empty Op is called on EmptyVariant. // TODO(eieio): This could be refactored into an array or jump table. It's // unclear whether this would be more efficient for practical variant arity. template
decltype(auto) Visit(std::int32_t target_index, Op&& op) { if (target_index == index(TypeTag
{})) return std::forward
(op)(get(TypeTag
{})); else return rest_.Visit(target_index - 1, std::forward
(op)); } template
decltype(auto) Visit(std::int32_t target_index, Op&& op) const { if (target_index == index(TypeTag
{})) return std::forward
(op)(get(TypeTag
{})); else return rest_.Visit(target_index - 1, std::forward
(op)); } template
bool Become(std::int32_t target_index, Args&&... args) { if (target_index == index(TypeTag
{})) { Construct(TypeTag
{}, std::forward
(args)...); return true; } else { return rest_.Become(target_index - 1, std::forward
(args)...); } } private: First first_; Union
rest_; }; } // namespace detail template
class Variant { private: // Convenience types. template
using TypeTag = detail::TypeTag
; template
using DecayedTypeTag = TypeTag
>; template
using TypeForIndex = detail::TypeForIndex
; template
using TypeTagForIndex = detail::TypeTagForIndex
; template
using HasType = detail::HasType
; template
using EnableIfElement = detail::EnableIfElement
; template
using EnableIfConvertible = detail::EnableIfConvertible
; template
using EnableIfAssignable = detail::EnableIfAssignable
; struct Direct {}; struct Convert {}; template
using SelectConstructor = detail::Select
::value, Direct, Convert>; // Constructs by type tag when T is an direct element of Types... template
explicit Variant(T&& value, Direct) : value_(0, &index_, DecayedTypeTag
{}, std::forward
(value)) {} // Conversion constructor when T is not a direct element of Types... template
explicit Variant(T&& value, Convert) : value_(0, &index_, std::forward
(value)) {} public: // Variants are default construcible, regardless of whether the elements are // default constructible. Default consruction yields an empty Variant. Variant() {} explicit Variant(EmptyVariant) {} ~Variant() { Destruct(); } // Copy and move construction from Variant types. Each element of OtherTypes // must be convertible to an element of Types. template
explicit Variant(const Variant
& other) { other.Visit([this](const auto& value) { Construct(value); }); } template
explicit Variant(Variant
&& other) { other.Visit([this](auto&& value) { Construct(std::move(value)); }); } // Construction from non-Variant types. template
> explicit Variant(T&& value) : Variant(std::forward
(value), SelectConstructor
{}) {} // Performs assignment from type T belonging to Types. This overload takes // priority to prevent implicit conversion in cases where T is implicitly // convertible to multiple elements of Types. template
EnableIfElement
operator=(T&& value) { Assign(DecayedTypeTag
{}, std::forward
(value)); return *this; } // Performs assignment from type T not belonging to Types. This overload // matches in cases where conversion is the only viable option. template
EnableIfConvertible
operator=(T&& value) { Assign(std::forward
(value)); return *this; } // Handles assignment from the empty type. This overload supports assignment // in visitors using generic lambdas. Variant& operator=(EmptyVariant) { Assign(EmptyVariant{}); return *this; } // Assignment from Variant types. Each element of OtherTypes must be // convertible to an element of Types. Forwards through non-Variant assignment // operators to apply conversion checks. template
Variant& operator=(const Variant
& other) { other.Visit([this](const auto& value) { *this = value; }); return *this; } template
Variant& operator=(Variant
&& other) { other.Visit([this](auto&& value) { *this = std::move(value); }); return *this; } // Becomes the target type, constructing a new element from the given // arguments if necessary. No action is taken if the active element is already // the target type. Otherwise the active element is destroyed and replaced by // constructing an element of the new type using |Args|. An invalid target // type index results in an empty Variant. template
void Become(std::int32_t target_index, Args&&... args) { if (target_index != index()) { Destruct(); index_ = value_.Become(target_index, std::forward
(args)...) ? target_index : kEmptyIndex; } } // Invokes |Op| on the active element. If the Variant is empty |Op| is invoked // on EmptyVariant. template
decltype(auto) Visit(Op&& op) { return value_.Visit(index_, std::forward
(op)); } template
decltype(auto) Visit(Op&& op) const { return value_.Visit(index_, std::forward
(op)); } // Index returned when the Variant is empty. enum : std::int32_t { kEmptyIndex = -1 }; // Returns the index of the given type. template
constexpr std::int32_t index_of() const { static_assert(HasType
::value, "T is not an element type of Variant."); return value_.template index(DecayedTypeTag
{}); } // Returns the index of the active type. If the Variant is empty -1 is // returned. std::int32_t index() const { return index_; } // Returns true if the given type is active, false otherwise. template
bool is() const { static_assert(HasType
::value, "T is not an element type of Variant."); return index() == index_of
(); } // Returns true if the Variant is empty, false otherwise. bool empty() const { return index() == kEmptyIndex; } // Element accessors. Returns a pointer to the active value if the given // type/index is active, otherwise nullptr is returned. template
T* get() { if (is
()) return &value_.template get(DecayedTypeTag
{}); else return nullptr; } template
const T* get() const { if (is
()) return &value_.template get(DecayedTypeTag
{}); else return nullptr; } template
TypeForIndex
* get() { if (is
>()) return &value_.template get(TypeTagForIndex
{}); else return nullptr; } template
const TypeForIndex
* get() const { if (is
>()) return &value_.template get(TypeTagForIndex
{}); else return nullptr; } private: std::int32_t index_ = kEmptyIndex; detail::Union
...> value_; // Constructs an element from the given arguments and sets the Variant to the // resulting type. template
void Construct(Args&&... args) { index_ = value_.template Construct(std::forward
(args)...); } void Construct(EmptyVariant) {} // Destroys the active element of the Variant. void Destruct() { value_.Destruct(index_); } // Assigns the Variant when non-empty and the current type matches the target // type, otherwise destroys the current value and constructs a element of the // new type. Tagged assignment is used when T is an element of the Variant to // prevent implicit conversion in cases where T is implicitly convertible to // multiple element types. template
void Assign(TypeTag
, U&& value) { if (!value_.template Assign(TypeTag
{}, index_, std::forward
(value))) { Destruct(); Construct(TypeTag
{}, std::forward
(value)); } } template
void Assign(T&& value) { if (!value_.template Assign(index_, std::forward
(value))) { Destruct(); Construct(std::forward
(value)); } } // Handles assignment from an empty Variant. void Assign(EmptyVariant) { Destruct(); } }; // Utility type to extract/convert values from a variant. This class simplifies // conditional logic to get/move/swap/action values from a variant when one or // more elements are compatible with the destination type. // // Example: // Variant
v(10); // bool bool_value; // if (IfAnyOf
::Get(v, &bool_value)) { // DoSomething(bool_value); // } else { // HandleInvalidType(); // } // IfAnyOf
::Call(v, [](const auto& value) { DoSomething(value); }); // template
struct IfAnyOf { // Calls Op on the underlying value of the variant and returns true when the // variant is a valid type, otherwise does nothing and returns false. template
static bool Call(Variant
* variant, Op&& op) { static_assert( detail::Set
::template IsSubset