mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
708 lines
22 KiB
C++
708 lines
22 KiB
C++
//===- ExternalUnion.h - A union with an external discriminator -*- C++ -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file defines the ExternalUnion class, which allows clients to
|
|
// conveniently define unions of possibly non-trivial types whose
|
|
// discriminator will be provided externally.
|
|
//
|
|
// It's the client's responsibility to call the appropriate
|
|
// "special members" within its own special members.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_BASIC_EXTERNALUNION_H
|
|
#define SWIFT_BASIC_EXTERNALUNION_H
|
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
#include "swift/Basic/type_traits.h"
|
|
#include <cassert>
|
|
#include <cstdint>
|
|
#include <utility>
|
|
|
|
namespace swift {
|
|
|
|
namespace ExternalUnionImpl {
|
|
|
|
/// A helper class for finding the index of a type in a parameter pack.
|
|
/// 'indexOf<T, List...>::value' will either be the index or -1.
|
|
template <class T, class... Members>
|
|
struct indexOf;
|
|
|
|
template <class T>
|
|
struct indexOf<T> {
|
|
constexpr static const int value = -1;
|
|
};
|
|
|
|
template <class T, class U, class... Members>
|
|
struct indexOf<T, U, Members...> {
|
|
private:
|
|
constexpr static const int indexInTail = indexOf<T, Members...>::value;
|
|
public:
|
|
constexpr static const int value =
|
|
(std::is_same<T, U>::value ? 0 :
|
|
indexInTail != -1 ? indexInTail + 1 : -1);
|
|
};
|
|
|
|
/// A helper class for deriving information and rule-of-five operations
|
|
/// for the storage of a union.
|
|
template <class... Members>
|
|
struct MembersHelper;
|
|
|
|
template <unsigned NumMembers>
|
|
struct OptimalKindTypeHelper;
|
|
|
|
} // end namespace ExternalUnionImpl
|
|
|
|
/// A class used to define the list of member types which need to be
|
|
/// stored in an ExternalUnion. As a special case, you may use 'void'
|
|
/// to indicate that an empty state is required in the union.
|
|
template <class... Members>
|
|
struct ExternalUnionMembers {
|
|
// (private to the implementation)
|
|
using Info = ExternalUnionImpl::MembersHelper<Members...>;
|
|
|
|
enum : bool {
|
|
is_copy_constructible = Info::is_copy_constructible,
|
|
is_nothrow_copy_constructible = Info::is_nothrow_copy_constructible,
|
|
is_move_constructible = Info::is_move_constructible,
|
|
is_nothrow_move_constructible = Info::is_nothrow_move_constructible,
|
|
is_copy_assignable = Info::is_copy_assignable,
|
|
is_nothrow_copy_assignable = Info::is_nothrow_copy_assignable,
|
|
is_move_assignable = Info::is_move_assignable,
|
|
is_nothrow_move_assignable = Info::is_nothrow_move_assignable,
|
|
};
|
|
|
|
/// The type of indices into the union member type list.
|
|
enum Index : unsigned {};
|
|
|
|
/// Return the index for the given type, asserting that it is a member
|
|
/// of the list.
|
|
template <class T>
|
|
static constexpr Index indexOf() {
|
|
static_assert(ExternalUnionImpl::indexOf<T, Members...>::value != -1,
|
|
"type not registered in union");
|
|
return Index(ExternalUnionImpl::indexOf<T, Members...>::value);
|
|
}
|
|
|
|
/// Return the index for the given type or -1 if it is not a member
|
|
/// of the list. If it is not -1, it may be safely converted to an Index.
|
|
template <class T>
|
|
static constexpr int maybeIndexOf() {
|
|
return ExternalUnionImpl::indexOf<T, Members...>::value;
|
|
}
|
|
|
|
template <class T>
|
|
static constexpr bool contains() {
|
|
return ExternalUnionImpl::indexOf<T, Members...>::value != -1;
|
|
}
|
|
};
|
|
|
|
/// An external union that uses the member-list index as the user-facing
|
|
/// discriminator kind.
|
|
///
|
|
/// This type can be used directly, but it's generally better to use
|
|
/// ExternalUnion instead. If nothing else, it's not a good idea to
|
|
/// cement the assumption that you won't have two cases that need the
|
|
/// same storage.
|
|
///
|
|
/// The external union itself is a trivial type, and it is the
|
|
/// responsibility of the client to call the "special member functions"
|
|
/// at the appropriate time.
|
|
template <class Members>
|
|
class BasicExternalUnion {
|
|
|
|
/// The value storage.
|
|
alignas(Members::Info::alignment) char Storage[Members::Info::size];
|
|
|
|
template <class T>
|
|
static constexpr int maybeIndexOfMember() {
|
|
return Members::template maybeIndexOf<T>();
|
|
}
|
|
|
|
public:
|
|
enum : bool {
|
|
union_is_trivially_copyable = Members::Info::is_trivially_copyable
|
|
};
|
|
|
|
using Index = typename Members::Index;
|
|
|
|
/// Construct a union member in-place.
|
|
template <class T, class... Args>
|
|
T &emplaceWithoutIndex(Args &&... args) {
|
|
constexpr int typeIndex = maybeIndexOfMember<T>();
|
|
static_assert(typeIndex != -1, "type not in union");
|
|
|
|
return *(::new ((void*) &Storage) T(std::forward<Args>(args)...));
|
|
}
|
|
|
|
/// Construct a union member in-place.
|
|
template <class T, class... Args>
|
|
T &emplace(Index index, Args &&... args) {
|
|
constexpr int typeIndex = maybeIndexOfMember<T>();
|
|
static_assert(typeIndex != -1, "type not in union");
|
|
assert(index == Index(typeIndex) && "current kind is wrong for value");
|
|
|
|
return *(::new ((void*) &Storage) T(std::forward<Args>(args)...));
|
|
}
|
|
|
|
/// Construct a union member in-place using list-initialization ({}).
|
|
template <class T, class... Args>
|
|
T &emplaceAggregateWithoutIndex(Args &&... args) {
|
|
constexpr int typeIndex = maybeIndexOfMember<T>();
|
|
static_assert(typeIndex != -1, "type not in union");
|
|
|
|
return *(::new ((void*) &Storage) T{std::forward<Args>(args)...});
|
|
}
|
|
|
|
/// Construct a union member in-place using list-initialization ({}).
|
|
template <class T, class... Args>
|
|
T &emplaceAggregate(Index index, Args &&... args) {
|
|
constexpr int typeIndex = maybeIndexOfMember<T>();
|
|
static_assert(typeIndex != -1, "type not in union");
|
|
assert(index == Index(typeIndex) && "current kind is wrong for value");
|
|
|
|
return *(::new ((void*) &Storage) T{std::forward<Args>(args)...});
|
|
}
|
|
|
|
/// Return a reference to a union member.
|
|
template <class T>
|
|
T &getWithoutIndex() {
|
|
constexpr int typeIndex = maybeIndexOfMember<T>();
|
|
static_assert(typeIndex != -1, "type not in union");
|
|
|
|
return reinterpret_cast<T &>(Storage);
|
|
}
|
|
|
|
/// Return a reference to a union member.
|
|
template <class T>
|
|
const T &getWithoutIndex() const {
|
|
constexpr int typeIndex = maybeIndexOfMember<T>();
|
|
static_assert(typeIndex != -1, "type not in union");
|
|
|
|
return reinterpret_cast<const T &>(Storage);
|
|
}
|
|
|
|
/// Return a reference to a union member, asserting that the current
|
|
/// kind matches the type being extracted.
|
|
template <class T>
|
|
T &get(Index index) {
|
|
constexpr int typeIndex = maybeIndexOfMember<T>();
|
|
static_assert(typeIndex != -1, "type not in union");
|
|
assert(index == Index(typeIndex) && "current kind is wrong for access");
|
|
|
|
return reinterpret_cast<T &>(Storage);
|
|
}
|
|
|
|
/// Return a reference to a union member, asserting that the current
|
|
/// kind matches the type being extracted.
|
|
template <class T>
|
|
const T &get(Index index) const {
|
|
constexpr int typeIndex = maybeIndexOfMember<T>();
|
|
static_assert(typeIndex != -1, "type not in union");
|
|
assert(index == Index(typeIndex) && "current kind is wrong for access");
|
|
|
|
return reinterpret_cast<const T &>(Storage);
|
|
}
|
|
|
|
/// Destruct the current union member.
|
|
template <class T>
|
|
void resetToEmptyWithoutIndex() {
|
|
constexpr int typeIndex = maybeIndexOfMember<T>();
|
|
static_assert(typeIndex != -1, "type not in union");
|
|
|
|
reinterpret_cast<T&>(Storage).T::~T();
|
|
}
|
|
|
|
/// Destroy the current union member.
|
|
template <class T>
|
|
void resetToEmpty(Index oldIndex, Index newIndex) {
|
|
constexpr int typeIndex = maybeIndexOfMember<T>();
|
|
static_assert(typeIndex != -1, "type not in union");
|
|
constexpr int voidTypeIndex = maybeIndexOfMember<void>();
|
|
static_assert(voidTypeIndex != -1, "union has not empty storage");
|
|
assert(oldIndex == Index(typeIndex) && "current kind is wrong for value");
|
|
assert(newIndex == Index(voidTypeIndex) && "new kind is not in union");
|
|
|
|
reinterpret_cast<T&>(Storage).T::~T();
|
|
}
|
|
|
|
/// Copy-construct the union from another union.
|
|
void copyConstruct(Index index, const BasicExternalUnion &other) {
|
|
Members::Info::copyConstruct(Storage, unsigned(index), other.Storage);
|
|
}
|
|
|
|
/// Move-construct the union from another union.
|
|
void moveConstruct(Index index, BasicExternalUnion &&other) {
|
|
Members::Info::moveConstruct(Storage, unsigned(index), other.Storage);
|
|
}
|
|
|
|
/// Copy-assign the union from another union.
|
|
void copyAssign(Index thisIndex, Index otherIndex,
|
|
const BasicExternalUnion &other) {
|
|
if (this == &other) {
|
|
// do nothing
|
|
} else if (thisIndex == otherIndex) {
|
|
Members::Info::copyAssignSame(unsigned(thisIndex),
|
|
Storage, other.Storage);
|
|
} else {
|
|
destruct(thisIndex);
|
|
copyConstruct(otherIndex, other);
|
|
}
|
|
}
|
|
|
|
/// Move-assign the union from another union.
|
|
void moveAssign(Index thisIndex, Index otherIndex,
|
|
BasicExternalUnion &&other) {
|
|
assert(this != &other && "move-constructing value into itself?");
|
|
|
|
if (thisIndex == otherIndex) {
|
|
Members::Info::moveAssignSame(unsigned(thisIndex),
|
|
Storage, other.Storage);
|
|
} else {
|
|
destruct(thisIndex);
|
|
moveConstruct(otherIndex, std::move(other));
|
|
}
|
|
}
|
|
|
|
/// Destroy the union from another union.
|
|
void destruct(Index index) {
|
|
Members::Info::destruct(unsigned(index), Storage);
|
|
}
|
|
};
|
|
|
|
/// An external union whose membership is determined by a kind type
|
|
/// whose members are not necessarily 1-1 with the members of the union.
|
|
///
|
|
/// Clients must provide a function which translates the kind type
|
|
/// into an index into the union's members list. The expected pattern
|
|
/// here is something like this:
|
|
///
|
|
/// using Members = ExternalUnionMembers<void, int, std::string>;
|
|
/// static Members::Index getIndexForKind(Kind kind) {
|
|
/// switch (kind) {
|
|
/// case Kind::Nothing: return Members::indexOf<void>();
|
|
/// case Kind::Happy: return Members::indexOf<int>();
|
|
/// case Kind::Sad: return Members::indexOf<int>();
|
|
/// case Kind::Funny: return Members::indexOf<std::string>();
|
|
/// case Kind::Angry: return Members::indexOf<std::string>();
|
|
/// }
|
|
/// llvm_unreachable("bad kind");
|
|
/// }
|
|
/// ExternalUnion<Kind, Members, getIndexForKind> Storage;
|
|
///
|
|
template <class Kind, class Members,
|
|
typename Members::Index (&GetIndexForKind)(Kind)>
|
|
class ExternalUnion {
|
|
BasicExternalUnion<Members> Union;
|
|
|
|
public:
|
|
enum : bool {
|
|
union_is_trivially_copyable = decltype(Union)::union_is_trivially_copyable
|
|
};
|
|
|
|
/// Construct a union member in-place.
|
|
template <class T, class... Args>
|
|
T &emplace(Kind kind, Args &&... args) {
|
|
#ifndef NDEBUG
|
|
return Union.template emplace<T>(GetIndexForKind(kind),
|
|
std::forward<Args>(args)...);
|
|
#else
|
|
return Union.template emplaceWithoutIndex<T>(std::forward<Args>(args)...);
|
|
#endif
|
|
}
|
|
|
|
/// Construct a union member in-place using list-initialization ({}).
|
|
template <class T, class... Args>
|
|
T &emplaceAggregate(Kind kind, Args &&... args) {
|
|
#ifndef NDEBUG
|
|
return Union.template emplaceAggregate<T>(GetIndexForKind(kind),
|
|
std::forward<Args>(args)...);
|
|
#else
|
|
return Union.template emplaceAggregateWithoutIndex<T>(
|
|
std::forward<Args>(args)...);
|
|
#endif
|
|
}
|
|
|
|
/// Destroy the current member of the union and switch to a member
|
|
/// that has no storage.
|
|
template <class T>
|
|
void resetToEmpty(Kind curKind, Kind newKind) {
|
|
#ifndef NDEBUG
|
|
return Union.template resetToEmpty<T>(GetIndexForKind(curKind),
|
|
GetIndexForKind(newKind));
|
|
#else
|
|
return Union.template resetToEmptyWithoutIndex<T>();
|
|
#endif
|
|
}
|
|
|
|
/// Return a reference to a union member, asserting that the current
|
|
/// kind is right.
|
|
template <class T>
|
|
T &get(Kind kind) {
|
|
#ifndef NDEBUG
|
|
return Union.template get<T>(GetIndexForKind(kind));
|
|
#else
|
|
return Union.template getWithoutIndex<T>();
|
|
#endif
|
|
}
|
|
|
|
/// Return a reference to a union member, asserting that the current
|
|
/// kind is right.
|
|
template <class T>
|
|
const T &get(Kind kind) const {
|
|
#ifndef NDEBUG
|
|
return Union.template get<T>(GetIndexForKind(kind));
|
|
#else
|
|
return Union.template getWithoutIndex<T>();
|
|
#endif
|
|
}
|
|
|
|
/// Copy-construct the union from another union.
|
|
void copyConstruct(Kind kind, const ExternalUnion &other) {
|
|
Union.copyConstruct(GetIndexForKind(kind), other.Union);
|
|
}
|
|
|
|
/// Move-construct the union from another union.
|
|
void moveConstruct(Kind kind, ExternalUnion &&other) {
|
|
Union.moveConstruct(GetIndexForKind(kind), std::move(other.Union));
|
|
}
|
|
|
|
/// Copy-assign the union from another union.
|
|
void copyAssign(Kind thisKind, Kind otherKind, const ExternalUnion &other) {
|
|
Union.copyAssign(GetIndexForKind(thisKind), GetIndexForKind(otherKind),
|
|
other.Union);
|
|
}
|
|
|
|
/// Move-assign the union from another union.
|
|
void moveAssign(Kind thisKind, Kind otherKind, ExternalUnion &&other) {
|
|
Union.moveAssign(GetIndexForKind(thisKind), GetIndexForKind(otherKind),
|
|
std::move(other.Union));
|
|
}
|
|
|
|
/// Destroy the union from another union.
|
|
void destruct(Kind kind) {
|
|
Union.destruct(GetIndexForKind(kind));
|
|
}
|
|
};
|
|
|
|
template <class KindHelper, class Members>
|
|
class SimpleExternalUnionBase
|
|
: public ExternalUnion<typename KindHelper::Kind, Members,
|
|
KindHelper::template coerceKindToIndex<typename Members::Index>> {
|
|
public:
|
|
using Kind = typename KindHelper::Kind;
|
|
|
|
template <class T>
|
|
static constexpr Kind kindForMember() {
|
|
return KindHelper::coerceIndexToKind(Members::template indexOf<T>());
|
|
}
|
|
|
|
template <class T>
|
|
T *dyn_cast(Kind kind) {
|
|
return (kind == kindForMember<T>()
|
|
? &this->template get<T>(kind) : nullptr);
|
|
}
|
|
|
|
template <class T>
|
|
const T *dyn_cast(Kind kind) const {
|
|
return (kind == kindForMember<T>()
|
|
? &this->template get<T>(kind) : nullptr);
|
|
}
|
|
};
|
|
|
|
/// A particularly simple form of ExternalUnion suitable for unions where
|
|
/// the kind only exists to distinguish between cases of the union.
|
|
///
|
|
/// Recommended usage:
|
|
/// using Union = SimpleExternalUnion<void, int, std::string>;
|
|
/// Union::Kind Kind : 2 = Union::kindForMember<void>();
|
|
/// ...
|
|
/// Union Storage;
|
|
template <class... Members>
|
|
class SimpleExternalUnion
|
|
: public SimpleExternalUnionBase<
|
|
ExternalUnionImpl::OptimalKindTypeHelper<sizeof...(Members)>,
|
|
ExternalUnionMembers<Members...> > {
|
|
};
|
|
|
|
namespace ExternalUnionImpl {
|
|
|
|
/// The MembersHelper base case.
|
|
template <>
|
|
struct MembersHelper<> {
|
|
enum : bool {
|
|
is_trivially_copyable = true,
|
|
is_copy_constructible = true,
|
|
is_nothrow_copy_constructible = true,
|
|
is_move_constructible = true,
|
|
is_nothrow_move_constructible = true,
|
|
is_copy_assignable = true,
|
|
is_nothrow_copy_assignable = true,
|
|
is_move_assignable = true,
|
|
is_nothrow_move_assignable = true,
|
|
};
|
|
|
|
enum : size_t {
|
|
size = 1,
|
|
alignment = 1
|
|
};
|
|
|
|
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
|
static void copyConstruct(void *self, int index, const void *other) {
|
|
assert(false && "bad index");
|
|
}
|
|
|
|
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
|
static void moveConstruct(void *self, int index, void *other) {
|
|
assert(false && "bad index");
|
|
}
|
|
|
|
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
|
static void copyAssignSame(int index, void *self, const void *other) {
|
|
assert(false && "bad index");
|
|
}
|
|
|
|
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
|
static void moveAssignSame(int index, void *self, void *other) {
|
|
assert(false && "bad index");
|
|
}
|
|
|
|
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
|
static void destruct(int index, void *self) {
|
|
assert(false && "bad index");
|
|
}
|
|
};
|
|
|
|
template <class T>
|
|
struct UnionMemberInfo;
|
|
|
|
/// The helper class for defining special members.
|
|
template <class H, class... T>
|
|
struct MembersHelper<H, T...> {
|
|
private:
|
|
using Member = UnionMemberInfo<H>;
|
|
using Others = MembersHelper<T...>;
|
|
|
|
public:
|
|
enum : bool {
|
|
is_trivially_copyable =
|
|
Member::is_trivially_copyable &&
|
|
Others::is_trivially_copyable,
|
|
is_copy_constructible =
|
|
Member::is_copy_constructible &&
|
|
Others::is_copy_constructible,
|
|
is_nothrow_copy_constructible =
|
|
Member::is_nothrow_copy_constructible &&
|
|
Others::is_nothrow_copy_constructible,
|
|
is_move_constructible =
|
|
Member::is_move_constructible &&
|
|
Others::is_move_constructible,
|
|
is_nothrow_move_constructible =
|
|
Member::is_nothrow_move_constructible &&
|
|
Others::is_nothrow_move_constructible,
|
|
is_copy_assignable =
|
|
Member::is_copy_assignable &&
|
|
Others::is_copy_assignable,
|
|
is_nothrow_copy_assignable =
|
|
Member::is_nothrow_copy_assignable &&
|
|
Others::is_nothrow_copy_assignable,
|
|
is_move_assignable =
|
|
Member::is_move_assignable &&
|
|
Others::is_move_assignable,
|
|
is_nothrow_move_assignable =
|
|
Member::is_nothrow_move_assignable &&
|
|
Others::is_nothrow_move_assignable,
|
|
};
|
|
|
|
enum : size_t {
|
|
size = Member::size > Others::size
|
|
? Member::size : Others::size,
|
|
alignment = Member::alignment > Others::alignment
|
|
? Member::alignment : Others::alignment
|
|
};
|
|
|
|
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
|
static void copyConstruct(void *self, unsigned index, const void *other) {
|
|
if (index == 0) {
|
|
Member::copyConstruct(self, other);
|
|
} else {
|
|
Others::copyConstruct(self, index - 1, other);
|
|
}
|
|
}
|
|
|
|
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
|
static void moveConstruct(void *self, unsigned index, void *other) {
|
|
if (index == 0) {
|
|
Member::moveConstruct(self, other);
|
|
} else {
|
|
Others::moveConstruct(self, index - 1, other);
|
|
}
|
|
}
|
|
|
|
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
|
static void copyAssignSame(unsigned index, void *self, const void *other) {
|
|
if (index == 0) {
|
|
Member::copyAssignSame(self, other);
|
|
} else {
|
|
Others::copyAssignSame(index - 1, self, other);
|
|
}
|
|
}
|
|
|
|
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
|
static void moveAssignSame(unsigned index, void *self, void *other) {
|
|
if (index == 0) {
|
|
Member::moveAssignSame(self, other);
|
|
} else {
|
|
Others::moveAssignSame(index - 1, self, other);
|
|
}
|
|
}
|
|
|
|
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
|
static void destruct(int index, void *self) {
|
|
if (index == 0) {
|
|
Member::destruct(self);
|
|
} else {
|
|
Others::destruct(index - 1, self);
|
|
}
|
|
}
|
|
};
|
|
|
|
/// The standard implementation of UnionMemberInfo.
|
|
template <class T>
|
|
struct UnionMemberInfo {
|
|
enum : bool {
|
|
is_trivially_copyable = IsTriviallyCopyable<T>::value,
|
|
is_copy_constructible = std::is_copy_constructible<T>::value,
|
|
is_nothrow_copy_constructible =
|
|
std::is_nothrow_copy_constructible<T>::value,
|
|
is_move_constructible = std::is_move_constructible<T>::value,
|
|
is_nothrow_move_constructible =
|
|
std::is_nothrow_move_constructible<T>::value,
|
|
is_copy_assignable = std::is_copy_assignable<T>::value,
|
|
is_nothrow_copy_assignable =
|
|
std::is_nothrow_copy_assignable<T>::value,
|
|
is_move_assignable = std::is_move_assignable<T>::value,
|
|
is_nothrow_move_assignable =
|
|
std::is_nothrow_move_assignable<T>::value,
|
|
};
|
|
|
|
enum : size_t {
|
|
size = sizeof(T),
|
|
alignment = alignof(T)
|
|
};
|
|
|
|
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
|
static void copyConstruct(void *self, const void *other) {
|
|
::new (self) T(*static_cast<const T *>(other));
|
|
}
|
|
|
|
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
|
static void moveConstruct(void *self, void *other) {
|
|
::new (self) T(std::move(*static_cast<T *>(other)));
|
|
}
|
|
|
|
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
|
static void copyAssignSame(void *self, const void *other) {
|
|
*static_cast<T*>(self) = *static_cast<const T *>(other);
|
|
}
|
|
|
|
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
|
static void moveAssignSame(void *self, void *other) {
|
|
*static_cast<T*>(self) = std::move(*static_cast<T *>(other));
|
|
}
|
|
|
|
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
|
static void destruct(void *self) {
|
|
static_cast<T*>(self)->T::~T();
|
|
}
|
|
};
|
|
|
|
/// An explicit specialization of UnionMemberInfo for 'void', which
|
|
/// represents the empty state.
|
|
template <>
|
|
struct UnionMemberInfo<void> {
|
|
enum : bool {
|
|
is_trivially_copyable = true,
|
|
is_copy_constructible = true,
|
|
is_nothrow_copy_constructible = true,
|
|
is_move_constructible = true,
|
|
is_nothrow_move_constructible = true,
|
|
is_copy_assignable = true,
|
|
is_nothrow_copy_assignable = true,
|
|
is_move_assignable = true,
|
|
is_nothrow_move_assignable = true,
|
|
};
|
|
|
|
enum : size_t {
|
|
size = 0,
|
|
alignment = 1
|
|
};
|
|
|
|
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
|
static void copyConstruct(void *self, const void *other) {}
|
|
|
|
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
|
static void moveConstruct(void *self, void *other) {}
|
|
|
|
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
|
static void copyAssignSame(void *self, const void *other) {}
|
|
|
|
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
|
static void moveAssignSame(void *self, void *other) {}
|
|
|
|
LLVM_ATTRIBUTE_ALWAYS_INLINE
|
|
static void destruct(void *self) {}
|
|
};
|
|
|
|
template <unsigned NumMembers,
|
|
bool FitsInUInt8 = (NumMembers < (1 << sizeof(uint8_t))),
|
|
bool FitsInUInt16 = (NumMembers < (1 << sizeof(uint16_t)))>
|
|
struct OptimalUnderlyingType;
|
|
|
|
template <unsigned NumMembers>
|
|
struct OptimalUnderlyingType<NumMembers, true, true> {
|
|
using type = uint8_t;
|
|
};
|
|
|
|
template <unsigned NumMembers>
|
|
struct OptimalUnderlyingType<NumMembers, false, true> {
|
|
using type = uint16_t;
|
|
};
|
|
|
|
template <unsigned NumMembers>
|
|
struct OptimalUnderlyingType<NumMembers, false, false> {
|
|
using type = unsigned;
|
|
};
|
|
|
|
template <unsigned NumMembers>
|
|
struct OptimalKindTypeHelper {
|
|
private:
|
|
using UnderlyingType = typename OptimalUnderlyingType<NumMembers>::type;
|
|
public:
|
|
enum Kind : UnderlyingType {};
|
|
|
|
template <class IndexType>
|
|
static constexpr IndexType coerceKindToIndex(Kind kind) {
|
|
return IndexType(UnderlyingType(kind));
|
|
}
|
|
|
|
template <class IndexType>
|
|
static constexpr Kind coerceIndexToKind(IndexType index) {
|
|
return Kind(UnderlyingType(index));
|
|
}
|
|
};
|
|
|
|
} // end namespace ExternalUnionImpl
|
|
} // end namespace swift
|
|
|
|
#endif // SWIFT_BASIC_CLUSTEREDBITVECTOR_H
|