| // This file was GENERATED by command: |
| // pump.py union_type.h.pump |
| // DO NOT EDIT BY HAND!!! |
| |
| |
| // Copyright 2015 The Cobalt Authors. All Rights Reserved. |
| // |
| // 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. |
| |
| #ifndef COBALT_SCRIPT_UNION_TYPE_H_ |
| #define COBALT_SCRIPT_UNION_TYPE_H_ |
| |
| // Implementation of IDL union types. |
| // http://heycam.github.io/webidl/#idl-union |
| // |
| // The member types for a given union type are set at compile-time as template |
| // parameters. Use templated IsType<> functions to check if a certain type is |
| // the specific type. |
| // http://heycam.github.io/webidl/#dfn-specific-type |
| // The template function AsType can be used to return the specific type. |
| // |
| // Attempting to instantiate a UnionType with an unsupported type will result |
| // in a compile-time assert. |
| // |
| // Attempting to query or retrieve a type that is not a part of the union will |
| // result in a compile-time assert. |
| // |
| // Each UnionTypeN allows for definition of a union type with N members. The |
| // template parameters should be the flattened member types of the union: |
| // http://heycam.github.io/webidl/#dfn-flattened-union-member-types |
| // |
| // Per the specification, there should be either 0 or 1 nullable types in union. |
| // In the case that there is one nullable type, the entire union type should |
| // be declared as nullable (with base::Optional<>). A corollary to this is that |
| // none of the member types in the UnionTypeN template should be nullable. |
| |
| #include <iosfwd> |
| #include <limits> |
| |
| #include "base/memory/aligned_memory.h" |
| #include "cobalt/script/union_type_internal.h" |
| |
| namespace cobalt { |
| namespace script { |
| |
| template <typename T1, typename T2> |
| class UnionType2 { |
| public: |
| UnionType2() : specific_type_(kUnspecified) {} |
| |
| explicit UnionType2(typename internal::UnionTypeTraits<T1>::ArgType arg) |
| : specific_type_(kTypeT1) { |
| new (storage_.void_data()) T1(arg); |
| } |
| explicit UnionType2(typename internal::UnionTypeTraits<T2>::ArgType arg) |
| : specific_type_(kTypeT2) { |
| new (storage_.void_data()) T2(arg); |
| } |
| |
| UnionType2(const UnionType2& other) { |
| ConstructFromOther(other); |
| } |
| |
| UnionType2& operator=(const UnionType2& other) { |
| if (&other != this) { |
| Destruct(); |
| ConstructFromOther(other); |
| } |
| return *this; |
| } |
| |
| ~UnionType2() { |
| Destruct(); |
| } |
| |
| // Forward these checks to the UnionTypeCheck helper class, which works around |
| // being unable to do template specializations in class scope. |
| template <typename S> |
| bool IsType() const { |
| return UnionTypeCheck<S>::IsType(this); |
| } |
| template <typename S> |
| typename internal::UnionTypeTraits<S>::ReturnType AsType() { |
| return UnionTypeCheck<S>::AsType(this); |
| } |
| template <typename S> |
| typename internal::UnionTypeTraits<S>::ConstReturnType AsType() const { |
| return UnionTypeCheck<S>::AsType(this); |
| } |
| |
| private: |
| // Internal helper class for checking and getting the union's specific type. |
| // Only partial class template specializations are allowed in class scope, |
| // hence the extra dummy template variable. |
| template <typename U, bool = false> |
| class UnionTypeCheck { |
| // Attempting to query for types that are not part of the union will |
| // result in a compile-time error. |
| COMPILE_ASSERT(sizeof(U) == 0, UnsupportedType); |
| }; |
| |
| // Specializations of the UnionTypeCheck class for each member type of the |
| // union. |
| template <bool dummy> |
| class UnionTypeCheck<T1, dummy> { |
| static bool IsType(const UnionType2<T1, T2>* union_value) { |
| return union_value->specific_type_ == kTypeT1; |
| } |
| static typename internal::UnionTypeTraits<T1>::ReturnType |
| AsType(UnionType2<T1, T2>* union_value) { |
| return *(union_value->storage_.template data_as<T1>()); |
| } |
| static typename internal::UnionTypeTraits<T1>::ConstReturnType |
| AsType(const UnionType2<T1, T2>* union_value) { |
| return *(union_value->storage_.template data_as<T1>()); |
| } |
| friend class UnionType2<T1, T2>; |
| }; |
| |
| template <bool dummy> |
| class UnionTypeCheck<T2, dummy> { |
| static bool IsType(const UnionType2<T1, T2>* union_value) { |
| return union_value->specific_type_ == kTypeT2; |
| } |
| static typename internal::UnionTypeTraits<T2>::ReturnType |
| AsType(UnionType2<T1, T2>* union_value) { |
| return *(union_value->storage_.template data_as<T2>()); |
| } |
| static typename internal::UnionTypeTraits<T2>::ConstReturnType |
| AsType(const UnionType2<T1, T2>* union_value) { |
| return *(union_value->storage_.template data_as<T2>()); |
| } |
| friend class UnionType2<T1, T2>; |
| }; |
| |
| enum SpecificType { |
| kUnspecified = 0, |
| kTypeT1, |
| kTypeT2, |
| }; |
| |
| union StorageUnion { |
| base::AlignedMemory<sizeof(T1), alignof(T1)> t1; |
| base::AlignedMemory<sizeof(T2), alignof(T2)> t2; |
| }; |
| |
| void ConstructFromOther(const UnionType2& other) { |
| specific_type_ = other.specific_type_; |
| switch (specific_type_) { |
| case kTypeT1: |
| new (storage_.void_data()) T1(other.AsType<T1>()); |
| break; |
| case kTypeT2: |
| new (storage_.void_data()) T2(other.AsType<T2>()); |
| break; |
| case kUnspecified: |
| // no-op |
| break; |
| } |
| } |
| |
| void Destruct() { |
| switch (specific_type_) { |
| case kTypeT1: |
| storage_.template data_as<T1>()->T1::~T1(); |
| break; |
| case kTypeT2: |
| storage_.template data_as<T2>()->T2::~T2(); |
| break; |
| case kUnspecified: |
| // no-op |
| break; |
| } |
| specific_type_ = kUnspecified; |
| } |
| |
| base::AlignedMemory<sizeof(StorageUnion), alignof(StorageUnion)> storage_; |
| SpecificType specific_type_; |
| |
| // Count the number of numeric types in this union. There can be a max of one. |
| // Otherwise, the JS->Cobalt conversion is ambiguous. |
| // The spec doesn't seem to describe this limitation, but this is what Blink |
| // does. |
| static const int kNumNumericTypes = |
| (internal::UnionTypeTraits<T1>::is_numeric_type ? 1 : 0) + |
| (internal::UnionTypeTraits<T2>::is_numeric_type ? 1 : 0); |
| COMPILE_ASSERT(kNumNumericTypes <= 1, AmbiguousUnionTypeConversion); |
| }; |
| |
| // Needed to instantiate base::Optional<UnionTypeN> |
| template <typename T1, typename T2> |
| inline std::ostream& operator<<( |
| std::ostream& stream, const UnionType2<T1, T2>& union_value) { |
| |
| if (union_value.template IsType<T1>()) { |
| stream << union_value.template AsType<T1>(); |
| } else if (union_value.template IsType<T2>()) { |
| stream << union_value.template AsType<T2>(); |
| } else { |
| stream << "Undefined union type."; |
| } |
| |
| return stream; |
| } |
| |
| |
| template <typename T1, typename T2, typename T3> |
| class UnionType3 { |
| public: |
| UnionType3() : specific_type_(kUnspecified) {} |
| |
| explicit UnionType3(typename internal::UnionTypeTraits<T1>::ArgType arg) |
| : specific_type_(kTypeT1) { |
| new (storage_.void_data()) T1(arg); |
| } |
| explicit UnionType3(typename internal::UnionTypeTraits<T2>::ArgType arg) |
| : specific_type_(kTypeT2) { |
| new (storage_.void_data()) T2(arg); |
| } |
| explicit UnionType3(typename internal::UnionTypeTraits<T3>::ArgType arg) |
| : specific_type_(kTypeT3) { |
| new (storage_.void_data()) T3(arg); |
| } |
| |
| UnionType3(const UnionType3& other) { |
| ConstructFromOther(other); |
| } |
| |
| UnionType3& operator=(const UnionType3& other) { |
| if (&other != this) { |
| Destruct(); |
| ConstructFromOther(other); |
| } |
| return *this; |
| } |
| |
| ~UnionType3() { |
| Destruct(); |
| } |
| |
| // Forward these checks to the UnionTypeCheck helper class, which works around |
| // being unable to do template specializations in class scope. |
| template <typename S> |
| bool IsType() const { |
| return UnionTypeCheck<S>::IsType(this); |
| } |
| template <typename S> |
| typename internal::UnionTypeTraits<S>::ReturnType AsType() { |
| return UnionTypeCheck<S>::AsType(this); |
| } |
| template <typename S> |
| typename internal::UnionTypeTraits<S>::ConstReturnType AsType() const { |
| return UnionTypeCheck<S>::AsType(this); |
| } |
| |
| private: |
| // Internal helper class for checking and getting the union's specific type. |
| // Only partial class template specializations are allowed in class scope, |
| // hence the extra dummy template variable. |
| template <typename U, bool = false> |
| class UnionTypeCheck { |
| // Attempting to query for types that are not part of the union will |
| // result in a compile-time error. |
| COMPILE_ASSERT(sizeof(U) == 0, UnsupportedType); |
| }; |
| |
| // Specializations of the UnionTypeCheck class for each member type of the |
| // union. |
| template <bool dummy> |
| class UnionTypeCheck<T1, dummy> { |
| static bool IsType(const UnionType3<T1, T2, T3>* union_value) { |
| return union_value->specific_type_ == kTypeT1; |
| } |
| static typename internal::UnionTypeTraits<T1>::ReturnType |
| AsType(UnionType3<T1, T2, T3>* union_value) { |
| return *(union_value->storage_.template data_as<T1>()); |
| } |
| static typename internal::UnionTypeTraits<T1>::ConstReturnType |
| AsType(const UnionType3<T1, T2, T3>* union_value) { |
| return *(union_value->storage_.template data_as<T1>()); |
| } |
| friend class UnionType3<T1, T2, T3>; |
| }; |
| |
| template <bool dummy> |
| class UnionTypeCheck<T2, dummy> { |
| static bool IsType(const UnionType3<T1, T2, T3>* union_value) { |
| return union_value->specific_type_ == kTypeT2; |
| } |
| static typename internal::UnionTypeTraits<T2>::ReturnType |
| AsType(UnionType3<T1, T2, T3>* union_value) { |
| return *(union_value->storage_.template data_as<T2>()); |
| } |
| static typename internal::UnionTypeTraits<T2>::ConstReturnType |
| AsType(const UnionType3<T1, T2, T3>* union_value) { |
| return *(union_value->storage_.template data_as<T2>()); |
| } |
| friend class UnionType3<T1, T2, T3>; |
| }; |
| |
| template <bool dummy> |
| class UnionTypeCheck<T3, dummy> { |
| static bool IsType(const UnionType3<T1, T2, T3>* union_value) { |
| return union_value->specific_type_ == kTypeT3; |
| } |
| static typename internal::UnionTypeTraits<T3>::ReturnType |
| AsType(UnionType3<T1, T2, T3>* union_value) { |
| return *(union_value->storage_.template data_as<T3>()); |
| } |
| static typename internal::UnionTypeTraits<T3>::ConstReturnType |
| AsType(const UnionType3<T1, T2, T3>* union_value) { |
| return *(union_value->storage_.template data_as<T3>()); |
| } |
| friend class UnionType3<T1, T2, T3>; |
| }; |
| |
| enum SpecificType { |
| kUnspecified = 0, |
| kTypeT1, |
| kTypeT2, |
| kTypeT3, |
| }; |
| |
| union StorageUnion { |
| base::AlignedMemory<sizeof(T1), alignof(T1)> t1; |
| base::AlignedMemory<sizeof(T2), alignof(T2)> t2; |
| base::AlignedMemory<sizeof(T3), alignof(T3)> t3; |
| }; |
| |
| void ConstructFromOther(const UnionType3& other) { |
| specific_type_ = other.specific_type_; |
| switch (specific_type_) { |
| case kTypeT1: |
| new (storage_.void_data()) T1(other.AsType<T1>()); |
| break; |
| case kTypeT2: |
| new (storage_.void_data()) T2(other.AsType<T2>()); |
| break; |
| case kTypeT3: |
| new (storage_.void_data()) T3(other.AsType<T3>()); |
| break; |
| case kUnspecified: |
| // no-op |
| break; |
| } |
| } |
| |
| void Destruct() { |
| switch (specific_type_) { |
| case kTypeT1: |
| storage_.template data_as<T1>()->T1::~T1(); |
| break; |
| case kTypeT2: |
| storage_.template data_as<T2>()->T2::~T2(); |
| break; |
| case kTypeT3: |
| storage_.template data_as<T3>()->T3::~T3(); |
| break; |
| case kUnspecified: |
| // no-op |
| break; |
| } |
| specific_type_ = kUnspecified; |
| } |
| |
| base::AlignedMemory<sizeof(StorageUnion), alignof(StorageUnion)> storage_; |
| SpecificType specific_type_; |
| |
| // Count the number of numeric types in this union. There can be a max of one. |
| // Otherwise, the JS->Cobalt conversion is ambiguous. |
| // The spec doesn't seem to describe this limitation, but this is what Blink |
| // does. |
| static const int kNumNumericTypes = |
| (internal::UnionTypeTraits<T1>::is_numeric_type ? 1 : 0) + |
| (internal::UnionTypeTraits<T2>::is_numeric_type ? 1 : 0) + |
| (internal::UnionTypeTraits<T3>::is_numeric_type ? 1 : 0); |
| COMPILE_ASSERT(kNumNumericTypes <= 1, AmbiguousUnionTypeConversion); |
| }; |
| |
| // Needed to instantiate base::Optional<UnionTypeN> |
| template <typename T1, typename T2, typename T3> |
| inline std::ostream& operator<<( |
| std::ostream& stream, const UnionType3<T1, T2, T3>& union_value) { |
| |
| if (union_value.template IsType<T1>()) { |
| stream << union_value.template AsType<T1>(); |
| } else if (union_value.template IsType<T2>()) { |
| stream << union_value.template AsType<T2>(); |
| } else if (union_value.template IsType<T3>()) { |
| stream << union_value.template AsType<T3>(); |
| } else { |
| stream << "Undefined union type."; |
| } |
| |
| return stream; |
| } |
| |
| |
| template <typename T1, typename T2, typename T3, typename T4> |
| class UnionType4 { |
| public: |
| UnionType4() : specific_type_(kUnspecified) {} |
| |
| explicit UnionType4(typename internal::UnionTypeTraits<T1>::ArgType arg) |
| : specific_type_(kTypeT1) { |
| new (storage_.void_data()) T1(arg); |
| } |
| explicit UnionType4(typename internal::UnionTypeTraits<T2>::ArgType arg) |
| : specific_type_(kTypeT2) { |
| new (storage_.void_data()) T2(arg); |
| } |
| explicit UnionType4(typename internal::UnionTypeTraits<T3>::ArgType arg) |
| : specific_type_(kTypeT3) { |
| new (storage_.void_data()) T3(arg); |
| } |
| explicit UnionType4(typename internal::UnionTypeTraits<T4>::ArgType arg) |
| : specific_type_(kTypeT4) { |
| new (storage_.void_data()) T4(arg); |
| } |
| |
| UnionType4(const UnionType4& other) { |
| ConstructFromOther(other); |
| } |
| |
| UnionType4& operator=(const UnionType4& other) { |
| if (&other != this) { |
| Destruct(); |
| ConstructFromOther(other); |
| } |
| return *this; |
| } |
| |
| ~UnionType4() { |
| Destruct(); |
| } |
| |
| // Forward these checks to the UnionTypeCheck helper class, which works around |
| // being unable to do template specializations in class scope. |
| template <typename S> |
| bool IsType() const { |
| return UnionTypeCheck<S>::IsType(this); |
| } |
| template <typename S> |
| typename internal::UnionTypeTraits<S>::ReturnType AsType() { |
| return UnionTypeCheck<S>::AsType(this); |
| } |
| template <typename S> |
| typename internal::UnionTypeTraits<S>::ConstReturnType AsType() const { |
| return UnionTypeCheck<S>::AsType(this); |
| } |
| |
| private: |
| // Internal helper class for checking and getting the union's specific type. |
| // Only partial class template specializations are allowed in class scope, |
| // hence the extra dummy template variable. |
| template <typename U, bool = false> |
| class UnionTypeCheck { |
| // Attempting to query for types that are not part of the union will |
| // result in a compile-time error. |
| COMPILE_ASSERT(sizeof(U) == 0, UnsupportedType); |
| }; |
| |
| // Specializations of the UnionTypeCheck class for each member type of the |
| // union. |
| template <bool dummy> |
| class UnionTypeCheck<T1, dummy> { |
| static bool IsType(const UnionType4<T1, T2, T3, T4>* union_value) { |
| return union_value->specific_type_ == kTypeT1; |
| } |
| static typename internal::UnionTypeTraits<T1>::ReturnType |
| AsType(UnionType4<T1, T2, T3, T4>* union_value) { |
| return *(union_value->storage_.template data_as<T1>()); |
| } |
| static typename internal::UnionTypeTraits<T1>::ConstReturnType |
| AsType(const UnionType4<T1, T2, T3, T4>* union_value) { |
| return *(union_value->storage_.template data_as<T1>()); |
| } |
| friend class UnionType4<T1, T2, T3, T4>; |
| }; |
| |
| template <bool dummy> |
| class UnionTypeCheck<T2, dummy> { |
| static bool IsType(const UnionType4<T1, T2, T3, T4>* union_value) { |
| return union_value->specific_type_ == kTypeT2; |
| } |
| static typename internal::UnionTypeTraits<T2>::ReturnType |
| AsType(UnionType4<T1, T2, T3, T4>* union_value) { |
| return *(union_value->storage_.template data_as<T2>()); |
| } |
| static typename internal::UnionTypeTraits<T2>::ConstReturnType |
| AsType(const UnionType4<T1, T2, T3, T4>* union_value) { |
| return *(union_value->storage_.template data_as<T2>()); |
| } |
| friend class UnionType4<T1, T2, T3, T4>; |
| }; |
| |
| template <bool dummy> |
| class UnionTypeCheck<T3, dummy> { |
| static bool IsType(const UnionType4<T1, T2, T3, T4>* union_value) { |
| return union_value->specific_type_ == kTypeT3; |
| } |
| static typename internal::UnionTypeTraits<T3>::ReturnType |
| AsType(UnionType4<T1, T2, T3, T4>* union_value) { |
| return *(union_value->storage_.template data_as<T3>()); |
| } |
| static typename internal::UnionTypeTraits<T3>::ConstReturnType |
| AsType(const UnionType4<T1, T2, T3, T4>* union_value) { |
| return *(union_value->storage_.template data_as<T3>()); |
| } |
| friend class UnionType4<T1, T2, T3, T4>; |
| }; |
| |
| template <bool dummy> |
| class UnionTypeCheck<T4, dummy> { |
| static bool IsType(const UnionType4<T1, T2, T3, T4>* union_value) { |
| return union_value->specific_type_ == kTypeT4; |
| } |
| static typename internal::UnionTypeTraits<T4>::ReturnType |
| AsType(UnionType4<T1, T2, T3, T4>* union_value) { |
| return *(union_value->storage_.template data_as<T4>()); |
| } |
| static typename internal::UnionTypeTraits<T4>::ConstReturnType |
| AsType(const UnionType4<T1, T2, T3, T4>* union_value) { |
| return *(union_value->storage_.template data_as<T4>()); |
| } |
| friend class UnionType4<T1, T2, T3, T4>; |
| }; |
| |
| enum SpecificType { |
| kUnspecified = 0, |
| kTypeT1, |
| kTypeT2, |
| kTypeT3, |
| kTypeT4, |
| }; |
| |
| union StorageUnion { |
| base::AlignedMemory<sizeof(T1), alignof(T1)> t1; |
| base::AlignedMemory<sizeof(T2), alignof(T2)> t2; |
| base::AlignedMemory<sizeof(T3), alignof(T3)> t3; |
| base::AlignedMemory<sizeof(T4), alignof(T4)> t4; |
| }; |
| |
| void ConstructFromOther(const UnionType4& other) { |
| specific_type_ = other.specific_type_; |
| switch (specific_type_) { |
| case kTypeT1: |
| new (storage_.void_data()) T1(other.AsType<T1>()); |
| break; |
| case kTypeT2: |
| new (storage_.void_data()) T2(other.AsType<T2>()); |
| break; |
| case kTypeT3: |
| new (storage_.void_data()) T3(other.AsType<T3>()); |
| break; |
| case kTypeT4: |
| new (storage_.void_data()) T4(other.AsType<T4>()); |
| break; |
| case kUnspecified: |
| // no-op |
| break; |
| } |
| } |
| |
| void Destruct() { |
| switch (specific_type_) { |
| case kTypeT1: |
| storage_.template data_as<T1>()->T1::~T1(); |
| break; |
| case kTypeT2: |
| storage_.template data_as<T2>()->T2::~T2(); |
| break; |
| case kTypeT3: |
| storage_.template data_as<T3>()->T3::~T3(); |
| break; |
| case kTypeT4: |
| storage_.template data_as<T4>()->T4::~T4(); |
| break; |
| case kUnspecified: |
| // no-op |
| break; |
| } |
| specific_type_ = kUnspecified; |
| } |
| |
| base::AlignedMemory<sizeof(StorageUnion), alignof(StorageUnion)> storage_; |
| SpecificType specific_type_; |
| |
| // Count the number of numeric types in this union. There can be a max of one. |
| // Otherwise, the JS->Cobalt conversion is ambiguous. |
| // The spec doesn't seem to describe this limitation, but this is what Blink |
| // does. |
| static const int kNumNumericTypes = |
| (internal::UnionTypeTraits<T1>::is_numeric_type ? 1 : 0) + |
| (internal::UnionTypeTraits<T2>::is_numeric_type ? 1 : 0) + |
| (internal::UnionTypeTraits<T3>::is_numeric_type ? 1 : 0) + |
| (internal::UnionTypeTraits<T4>::is_numeric_type ? 1 : 0); |
| COMPILE_ASSERT(kNumNumericTypes <= 1, AmbiguousUnionTypeConversion); |
| }; |
| |
| // Needed to instantiate base::Optional<UnionTypeN> |
| template <typename T1, typename T2, typename T3, typename T4> |
| inline std::ostream& operator<<( |
| std::ostream& stream, const UnionType4<T1, T2, T3, T4>& union_value) { |
| |
| if (union_value.template IsType<T1>()) { |
| stream << union_value.template AsType<T1>(); |
| } else if (union_value.template IsType<T2>()) { |
| stream << union_value.template AsType<T2>(); |
| } else if (union_value.template IsType<T3>()) { |
| stream << union_value.template AsType<T3>(); |
| } else if (union_value.template IsType<T4>()) { |
| stream << union_value.template AsType<T4>(); |
| } else { |
| stream << "Undefined union type."; |
| } |
| |
| return stream; |
| } |
| |
| |
| template <typename T1, typename T2, typename T3, typename T4, typename T5> |
| class UnionType5 { |
| public: |
| UnionType5() : specific_type_(kUnspecified) {} |
| |
| explicit UnionType5(typename internal::UnionTypeTraits<T1>::ArgType arg) |
| : specific_type_(kTypeT1) { |
| new (storage_.void_data()) T1(arg); |
| } |
| explicit UnionType5(typename internal::UnionTypeTraits<T2>::ArgType arg) |
| : specific_type_(kTypeT2) { |
| new (storage_.void_data()) T2(arg); |
| } |
| explicit UnionType5(typename internal::UnionTypeTraits<T3>::ArgType arg) |
| : specific_type_(kTypeT3) { |
| new (storage_.void_data()) T3(arg); |
| } |
| explicit UnionType5(typename internal::UnionTypeTraits<T4>::ArgType arg) |
| : specific_type_(kTypeT4) { |
| new (storage_.void_data()) T4(arg); |
| } |
| explicit UnionType5(typename internal::UnionTypeTraits<T5>::ArgType arg) |
| : specific_type_(kTypeT5) { |
| new (storage_.void_data()) T5(arg); |
| } |
| |
| UnionType5(const UnionType5& other) { ConstructFromOther(other); } |
| |
| UnionType5& operator=(const UnionType5& other) { |
| if (&other != this) { |
| Destruct(); |
| ConstructFromOther(other); |
| } |
| return *this; |
| } |
| |
| ~UnionType5() { Destruct(); } |
| |
| // Forward these checks to the UnionTypeCheck helper class, which works around |
| // being unable to do template specializations in class scope. |
| template <typename S> |
| bool IsType() const { |
| return UnionTypeCheck<S>::IsType(this); |
| } |
| template <typename S> |
| typename internal::UnionTypeTraits<S>::ReturnType AsType() { |
| return UnionTypeCheck<S>::AsType(this); |
| } |
| template <typename S> |
| typename internal::UnionTypeTraits<S>::ConstReturnType AsType() const { |
| return UnionTypeCheck<S>::AsType(this); |
| } |
| |
| private: |
| // Internal helper class for checking and getting the union's specific type. |
| // Only partial class template specializations are allowed in class scope, |
| // hence the extra dummy template variable. |
| template <typename U, bool = false> |
| class UnionTypeCheck { |
| // Attempting to query for types that are not part of the union will |
| // result in a compile-time error. |
| COMPILE_ASSERT(sizeof(U) == 0, UnsupportedType); |
| }; |
| |
| // Specializations of the UnionTypeCheck class for each member type of the |
| // union. |
| template <bool dummy> |
| class UnionTypeCheck<T1, dummy> { |
| static bool IsType(const UnionType5<T1, T2, T3, T4, T5>* union_value) { |
| return union_value->specific_type_ == kTypeT1; |
| } |
| static typename internal::UnionTypeTraits<T1>::ReturnType AsType( |
| UnionType5<T1, T2, T3, T4, T5>* union_value) { |
| return *(union_value->storage_.template data_as<T1>()); |
| } |
| static typename internal::UnionTypeTraits<T1>::ConstReturnType AsType( |
| const UnionType5<T1, T2, T3, T4, T5>* union_value) { |
| return *(union_value->storage_.template data_as<T1>()); |
| } |
| friend class UnionType5<T1, T2, T3, T4, T5>; |
| }; |
| |
| template <bool dummy> |
| class UnionTypeCheck<T2, dummy> { |
| static bool IsType(const UnionType5<T1, T2, T3, T4, T5>* union_value) { |
| return union_value->specific_type_ == kTypeT2; |
| } |
| static typename internal::UnionTypeTraits<T2>::ReturnType AsType( |
| UnionType5<T1, T2, T3, T4, T5>* union_value) { |
| return *(union_value->storage_.template data_as<T2>()); |
| } |
| static typename internal::UnionTypeTraits<T2>::ConstReturnType AsType( |
| const UnionType5<T1, T2, T3, T4, T5>* union_value) { |
| return *(union_value->storage_.template data_as<T2>()); |
| } |
| friend class UnionType5<T1, T2, T3, T4, T5>; |
| }; |
| |
| template <bool dummy> |
| class UnionTypeCheck<T3, dummy> { |
| static bool IsType(const UnionType5<T1, T2, T3, T4, T5>* union_value) { |
| return union_value->specific_type_ == kTypeT3; |
| } |
| static typename internal::UnionTypeTraits<T3>::ReturnType AsType( |
| UnionType5<T1, T2, T3, T4, T5>* union_value) { |
| return *(union_value->storage_.template data_as<T3>()); |
| } |
| static typename internal::UnionTypeTraits<T3>::ConstReturnType AsType( |
| const UnionType5<T1, T2, T3, T4, T5>* union_value) { |
| return *(union_value->storage_.template data_as<T3>()); |
| } |
| friend class UnionType5<T1, T2, T3, T4, T5>; |
| }; |
| |
| template <bool dummy> |
| class UnionTypeCheck<T4, dummy> { |
| static bool IsType(const UnionType5<T1, T2, T3, T4, T5>* union_value) { |
| return union_value->specific_type_ == kTypeT4; |
| } |
| static typename internal::UnionTypeTraits<T4>::ReturnType AsType( |
| UnionType5<T1, T2, T3, T4, T5>* union_value) { |
| return *(union_value->storage_.template data_as<T4>()); |
| } |
| static typename internal::UnionTypeTraits<T4>::ConstReturnType AsType( |
| const UnionType5<T1, T2, T3, T4, T5>* union_value) { |
| return *(union_value->storage_.template data_as<T4>()); |
| } |
| friend class UnionType5<T1, T2, T3, T4, T5>; |
| }; |
| |
| template <bool dummy> |
| class UnionTypeCheck<T5, dummy> { |
| static bool IsType(const UnionType5<T1, T2, T3, T4, T5>* union_value) { |
| return union_value->specific_type_ == kTypeT5; |
| } |
| static typename internal::UnionTypeTraits<T5>::ReturnType AsType( |
| UnionType5<T1, T2, T3, T4, T5>* union_value) { |
| return *(union_value->storage_.template data_as<T5>()); |
| } |
| static typename internal::UnionTypeTraits<T5>::ConstReturnType AsType( |
| const UnionType5<T1, T2, T3, T4, T5>* union_value) { |
| return *(union_value->storage_.template data_as<T5>()); |
| } |
| friend class UnionType5<T1, T2, T3, T4, T5>; |
| }; |
| |
| enum SpecificType { |
| kUnspecified = 0, |
| kTypeT1, |
| kTypeT2, |
| kTypeT3, |
| kTypeT4, |
| kTypeT5, |
| }; |
| |
| union StorageUnion { |
| base::AlignedMemory<sizeof(T1), alignof(T1)> t1; |
| base::AlignedMemory<sizeof(T2), alignof(T2)> t2; |
| base::AlignedMemory<sizeof(T3), alignof(T3)> t3; |
| base::AlignedMemory<sizeof(T4), alignof(T4)> t4; |
| base::AlignedMemory<sizeof(T5), alignof(T5)> t5; |
| }; |
| |
| void ConstructFromOther(const UnionType5& other) { |
| specific_type_ = other.specific_type_; |
| switch (specific_type_) { |
| case kTypeT1: |
| new (storage_.void_data()) T1(other.AsType<T1>()); |
| break; |
| case kTypeT2: |
| new (storage_.void_data()) T2(other.AsType<T2>()); |
| break; |
| case kTypeT3: |
| new (storage_.void_data()) T3(other.AsType<T3>()); |
| break; |
| case kTypeT4: |
| new (storage_.void_data()) T4(other.AsType<T4>()); |
| break; |
| case kTypeT5: |
| new (storage_.void_data()) T5(other.AsType<T5>()); |
| break; |
| case kUnspecified: |
| // no-op |
| break; |
| } |
| } |
| |
| void Destruct() { |
| switch (specific_type_) { |
| case kTypeT1: |
| storage_.template data_as<T1>()->T1::~T1(); |
| break; |
| case kTypeT2: |
| storage_.template data_as<T2>()->T2::~T2(); |
| break; |
| case kTypeT3: |
| storage_.template data_as<T3>()->T3::~T3(); |
| break; |
| case kTypeT4: |
| storage_.template data_as<T4>()->T4::~T4(); |
| break; |
| case kTypeT5: |
| storage_.template data_as<T5>()->T5::~T5(); |
| break; |
| case kUnspecified: |
| // no-op |
| break; |
| } |
| specific_type_ = kUnspecified; |
| } |
| |
| base::AlignedMemory<sizeof(StorageUnion), alignof(StorageUnion)> storage_; |
| SpecificType specific_type_; |
| |
| // Count the number of numeric types in this union. There can be a max of one. |
| // Otherwise, the JS->Cobalt conversion is ambiguous. |
| // The spec doesn't seem to describe this limitation, but this is what Blink |
| // does. |
| static const int kNumNumericTypes = |
| (internal::UnionTypeTraits<T1>::is_numeric_type ? 1 : 0) + |
| (internal::UnionTypeTraits<T2>::is_numeric_type ? 1 : 0) + |
| (internal::UnionTypeTraits<T3>::is_numeric_type ? 1 : 0) + |
| (internal::UnionTypeTraits<T4>::is_numeric_type ? 1 : 0) + |
| (internal::UnionTypeTraits<T5>::is_numeric_type ? 1 : 0); |
| COMPILE_ASSERT(kNumNumericTypes <= 1, AmbiguousUnionTypeConversion); |
| }; |
| |
| // Needed to instantiate base::Optional<UnionTypeN> |
| template <typename T1, typename T2, typename T3, typename T4, typename T5> |
| inline std::ostream& operator<<( |
| std::ostream& stream, const UnionType5<T1, T2, T3, T4, T5>& union_value) { |
| if (union_value.template IsType<T1>()) { |
| stream << union_value.template AsType<T1>(); |
| } else if (union_value.template IsType<T2>()) { |
| stream << union_value.template AsType<T2>(); |
| } else if (union_value.template IsType<T3>()) { |
| stream << union_value.template AsType<T3>(); |
| } else if (union_value.template IsType<T4>()) { |
| stream << union_value.template AsType<T4>(); |
| } else if (union_value.template IsType<T5>()) { |
| stream << union_value.template AsType<T5>(); |
| } else { |
| stream << "Undefined union type."; |
| } |
| |
| return stream; |
| } |
| |
| } // namespace script |
| } // namespace cobalt |
| |
| #endif // COBALT_SCRIPT_UNION_TYPE_H_ |