blob: 19a85628a797e69f82a21ed833ccadd39ada2c8d [file] [log] [blame]
// 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_