v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
discriminated-union.h
Go to the documentation of this file.
1// Copyright 2023 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_BASE_DISCRIMINATED_UNION_H_
6#define V8_BASE_DISCRIMINATED_UNION_H_
7
8#include <type_traits>
9#include <utility>
10
13
14namespace v8 {
15namespace base {
16
17// A variant-like discriminated union type, which takes a discriminating enum
18// and a set of types. The enum must have as many elements as the number of
19// types, with each enum value corresponding to one type in the set.
20//
21// Example usage:
22//
23// enum class FooType {
24// kBar,
25// kBaz
26// }
27// class Bar { ... };
28// class Baz { ... };
29//
30// // FooType::kBar and FooType::kBaz match Bar and Baz, respectively.
31// DiscriminatedUnion<FooType, Bar, Baz> union;
32//
33// switch (union.tag()) {
34// case FooType::kBar:
35// return process_bar(union.get<FooType::kBar>);
36// case FooType::kBaz:
37// return process_baz(union.get<FooType::kBaz>);
38// }
39template <typename TagEnum, typename... Ts>
41 public:
42 // All Ts must be trivially destructible to avoid DiscriminatedUnion needing a
43 // destructor.
44 static_assert((std::is_trivially_destructible_v<Ts> && ...));
45
46 using Tag = TagEnum;
47
51 V8_NOEXCEPT = default;
53 V8_NOEXCEPT = default;
54
55 // TODO(leszeks): Add in-place constructor.
56
57 // Construct with known tag and type (the tag is DCHECKed).
58 template <typename T>
59 constexpr explicit DiscriminatedUnion(Tag tag, T&& data) V8_NOEXCEPT {
60 constexpr size_t index = index_of_type_v<std::decay_t<T>, Ts...>;
61 static_assert(index < sizeof...(Ts));
62 static_assert(index < std::numeric_limits<uint8_t>::max());
63 // TODO(leszeks): Support unions with repeated types.
64 DCHECK_EQ(tag, static_cast<Tag>(index));
65 tag_ = static_cast<uint8_t>(index);
66 new (data_) T(std::forward<T>(data));
67 }
68
69 // Construct with known type.
70 template <typename T>
71 constexpr explicit DiscriminatedUnion(T&& data) V8_NOEXCEPT {
72 constexpr size_t index = index_of_type_v<std::decay_t<T>, Ts...>;
73 static_assert(index < sizeof...(Ts));
74 static_assert(index < std::numeric_limits<uint8_t>::max());
75 tag_ = static_cast<uint8_t>(index);
76 new (data_) T(std::forward<T>(data));
77 }
78
79 constexpr Tag tag() const { return static_cast<Tag>(tag_); }
80
81 // Get union member by tag.
82 template <Tag tag>
83 constexpr const auto& get() const {
84 using T = nth_type_t<static_cast<size_t>(tag), Ts...>;
85 DCHECK_EQ(tag, this->tag());
86 return *reinterpret_cast<const T*>(data_);
87 }
88
89 // Get union member by tag.
90 template <Tag tag>
91 constexpr auto& get() {
92 using T = nth_type_t<static_cast<size_t>(tag), Ts...>;
93 DCHECK_EQ(tag, this->tag());
94 return *reinterpret_cast<T*>(data_);
95 }
96
97 // Get union member by type.
98 template <typename T>
99 constexpr const auto& get() const {
100 DCHECK_EQ(static_cast<Tag>(index_of_type_v<T, Ts...>), this->tag());
101 return *reinterpret_cast<const T*>(data_);
102 }
103
104 // Get union member by type.
105 template <typename T>
106 constexpr auto& get() {
107 DCHECK_EQ(static_cast<Tag>(index_of_type_v<T, Ts...>), this->tag());
108 return *reinterpret_cast<T*>(data_);
109 }
110
111 private:
112 alignas(std::max({alignof(Ts)...})) char data_[std::max({sizeof(Ts)...})];
113 static_assert(sizeof...(Ts) <= std::numeric_limits<uint8_t>::max());
114 uint8_t tag_;
115};
116
117} // namespace base
118} // namespace v8
119
120#endif // V8_BASE_DISCRIMINATED_UNION_H_
#define T
constexpr DiscriminatedUnion(T &&data) V8_NOEXCEPT
constexpr const auto & get() const
char data_[std::max({sizeof(Ts)...})]
DiscriminatedUnion & operator=(DiscriminatedUnion &&other) V8_NOEXCEPT=default
DiscriminatedUnion & operator=(const DiscriminatedUnion &other) V8_NOEXCEPT=default
constexpr DiscriminatedUnion(Tag tag, T &&data) V8_NOEXCEPT
DiscriminatedUnion(DiscriminatedUnion &&other) V8_NOEXCEPT=default
DiscriminatedUnion(const DiscriminatedUnion &other) V8_NOEXCEPT=default
OptionalOpIndex index
constexpr size_t index_of_type_v
typename detail::nth_type< N, T... >::type nth_type_t
#define V8_NOEXCEPT
#define DCHECK_EQ(v1, v2)
Definition logging.h:485