| $$ This is a pump file for generating file templates. Pump is a python |
| $$ script that is part of the Google Test suite of utilities. Description |
| $$ can be found here: |
| $$ |
| $$ http://code.google.com/p/googletest/wiki/PumpManual |
| $$ |
| |
| $$ Maximum number of different member types in a union. |
| $var MAX_MEMBERS = 5 |
| |
| // 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 { |
| |
| $$ Skip the case where there is only one type |
| $range NUM_MEMBERS 2..MAX_MEMBERS |
| $for NUM_MEMBERS [[ |
| |
| $range TYPE 1..NUM_MEMBERS |
| |
| |
| template <$for TYPE , [[typename T$(TYPE)]]> |
| class UnionType$(NUM_MEMBERS) { |
| public: |
| |
| $range CTOR_TYPE 2..NUM_MEMBERS |
| UnionType$(NUM_MEMBERS)() : specific_type_(kUnspecified) {} |
| |
| |
| $for TYPE [[ |
| explicit UnionType$(NUM_MEMBERS)([[typename internal::UnionTypeTraits<T$(TYPE)>::ArgType arg]]) |
| : specific_type_(kTypeT$(TYPE)) { |
| new (storage_.void_data()) T$(TYPE)(arg); |
| } |
| |
| ]] |
| |
| UnionType$(NUM_MEMBERS)(const UnionType$(NUM_MEMBERS)& other) { |
| ConstructFromOther(other); |
| } |
| |
| UnionType$(NUM_MEMBERS)& operator=(const UnionType$(NUM_MEMBERS)& other) { |
| if (&other != this) { |
| Destruct(); |
| ConstructFromOther(other); |
| } |
| return *this; |
| } |
| |
| ~UnionType$(NUM_MEMBERS)() { |
| 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. |
| $for TYPE [[ |
| |
| template <bool dummy> |
| class UnionTypeCheck<T$(TYPE), dummy> { |
| static bool IsType(const UnionType$(NUM_MEMBERS)<$for TYPE , [[T$(TYPE)]]>* union_value) { |
| return union_value->specific_type_ == kTypeT$(TYPE); |
| } |
| static typename internal::UnionTypeTraits<T$(TYPE)>::ReturnType |
| AsType(UnionType$(NUM_MEMBERS)<$for TYPE , [[T$(TYPE)]]>* union_value) { |
| return *(union_value->storage_.template data_as<T$(TYPE)>()); |
| } |
| static typename internal::UnionTypeTraits<T$(TYPE)>::ConstReturnType |
| AsType(const UnionType$(NUM_MEMBERS)<$for TYPE , [[T$(TYPE)]]>* union_value) { |
| return *(union_value->storage_.template data_as<T$(TYPE)>()); |
| } |
| friend class UnionType$(NUM_MEMBERS)<$for TYPE , [[T$(TYPE)]]>; |
| }; |
| |
| ]] |
| |
| enum SpecificType { |
| kUnspecified = 0, |
| $for TYPE [[ |
| |
| kTypeT$(TYPE), |
| ]] |
| |
| }; |
| |
| union StorageUnion { |
| $for TYPE [[ |
| |
| base::AlignedMemory<sizeof(T$(TYPE)), SB_ALIGNOF(T$(TYPE))> t$(TYPE); |
| ]] |
| |
| }; |
| |
| void ConstructFromOther(const UnionType$(NUM_MEMBERS)& other) { |
| specific_type_ = other.specific_type_; |
| switch (specific_type_) { |
| $for TYPE [[ |
| |
| case kTypeT$(TYPE): |
| new (storage_.void_data()) T$(TYPE)(other.AsType<T$(TYPE)>()); |
| break; |
| ]] |
| |
| case kUnspecified: |
| // no-op |
| break; |
| } |
| } |
| |
| void Destruct() { |
| switch (specific_type_) { |
| $for TYPE [[ |
| |
| case kTypeT$(TYPE): |
| storage_.template data_as<T$(TYPE)>()->T$(TYPE)::~T$(TYPE)(); |
| break; |
| ]] |
| |
| case kUnspecified: |
| // no-op |
| break; |
| } |
| specific_type_ = kUnspecified; |
| } |
| |
| base::AlignedMemory<sizeof(StorageUnion), SB_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 = |
| $for TYPE + |
| [[(internal::UnionTypeTraits<T$(TYPE)>::is_numeric_type ? 1 : 0)]]; |
| COMPILE_ASSERT(kNumNumericTypes <= 1, AmbiguousUnionTypeConversion); |
| }; |
| |
| // Needed to instantiate base::Optional<UnionTypeN> |
| template <$for TYPE , [[typename T$(TYPE)]]> |
| inline std::ostream& operator<<( |
| std::ostream& stream, const UnionType$(NUM_MEMBERS)<$for TYPE , [[T$(TYPE)]]>& union_value) { |
| |
| $for TYPE [[ if (union_value.template IsType<T$(TYPE)>()) { |
| stream << union_value.template AsType<T$(TYPE)>(); |
| } else |
| ]] { |
| stream << "Undefined union type."; |
| } |
| |
| return stream; |
| } |
| |
| ]] $$ for NUM_MEMBERS |
| |
| } // namespace script |
| } // namespace cobalt |
| |
| #endif // COBALT_SCRIPT_UNION_TYPE_H_ |