chromium/v8/src/objects/union.h

// Copyright 2024 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_OBJECTS_UNION_H_
#define V8_OBJECTS_UNION_H_

#include "src/base/template-utils.h"
#include "src/common/globals.h"

namespace v8::internal {

// Union<Ts...> represents a union of multiple V8 types.
//
// Unions are required to be non-nested (i.e. no unions of unions), and to
// have each type only once. The UnionOf<Ts...> helper can be used to flatten
// nested unions and remove duplicates.
//
// Inheritance from Unions is forbidden because it messes with `is_subtype`
// checking.
template <typename... Ts>
class Union;

// is_union<T> is a type trait that returns true if T is a union.
template <typename... Ts>
struct is_union : public std::false_type {};
is_union<Union<Ts...>>;
is_union_v;

template <typename... Ts>
class Union final : public AllStatic {};

namespace detail {

template <typename Accumulator, typename... InputTypes>
struct FlattenUnionHelper;

// Base case: No input types, return the accumulated types.
FlattenUnionHelper<Union<OutputTs...>>;

// Recursive case: Non-union input, accumulate and continue.
FlattenUnionHelper<Union<OutputTs...>, Head, Ts...>;

// Recursive case: Smi input, normalize to always be the first element.
//
// This is a small optimization to try reduce the number of template
// specializations -- ideally we would fully sort the types but this probably
// costs more templates than it saves.
FlattenUnionHelper<Union<OutputTs...>, Smi, Ts...>;

// Recursive case: Union input, flatten and continue.
FlattenUnionHelper<Union<OutputTs...>, Union<HeadTs...>, Ts...>;

}  // namespace detail

// UnionOf<Ts...> is a helper that returns a union of multiple V8 types,
// flattening any nested unions and removing duplicate types.
UnionOf;

// Unions of unions are flattened.
static_assert;
// Unions with duplicates are deduplicated.
static_assert;
// Unions with Smis are normalized to have the Smi be the first element.
static_assert;

}  // namespace v8::internal

#endif  // V8_OBJECTS_UNION_H_