186e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler/* 286e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler * Copyright (C) 2016 The Android Open Source Project 386e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler * 486e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler * Licensed under the Apache License, Version 2.0 (the "License"); 586e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler * you may not use this file except in compliance with the License. 686e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler * You may obtain a copy of the License at 786e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler * 886e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler * http://www.apache.org/licenses/LICENSE-2.0 986e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler * 1086e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler * Unless required by applicable law or agreed to in writing, software 1186e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler * distributed under the License is distributed on an "AS IS" BASIS, 1286e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1386e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler * See the License for the specific language governing permissions and 1486e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler * limitations under the License. 1586e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler */ 1686e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 1786e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// This file defines the |TaggedUnion| class template. It implements a tagged 1886e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// union, i.e. it both holds a value of one of a set of pre-determined types, as 1986e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// well as an enum value indicating which union member is active. The enum type 2086e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// used as tag and the set of union member types a specified as template 2186e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// parameters. 2286e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// 2386e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// For example, consider this declaration of a simple variant type: 2486e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// 2586e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// enum VariantType { 2686e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// Variant_Int = 0, 2786e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// Variant_Double = 1, 2886e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// Variant_Boolean = 3, 2986e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// Variant_String = 2, 3086e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// }; 3186e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// 3286e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// using Variant = TaggedUnion<VariantType, 3386e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// TaggedUnionMember<Variant_Int, int>, 3486e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// TaggedUnionMember<Variant_Double, double>, 3586e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// TaggedUnionMember<Variant_Boolean, bool>, 3686e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// TaggedUnionMember<Variant_String, std::string>>; 3786e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// 3886e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// |TaggedUnion::which()| can be used to determine what the active member is, 3986e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// and |TaggedUnion::get()| returns a pointer to the member as long as that 4086e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// member is active: 4186e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// 4286e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// Variant value; 4386e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// ASSERT_EQ(Variant_Int, value.which()); 4486e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// ASSERT_NE(nullptr, value.get<Variant_Int>()); 4586e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// ASSERT_EQ(0, *value.get<Variant_Int>()); 4686e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// 4786e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// |TaggedUnion::Activate()| activates a member. It returns a reference to the 4886e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// activated member: 4986e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// 5086e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// value.Activate<Variant_String>() = "-1"; 5186e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// ASSERT_EQ(Variant_String, value.which()); 5286e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// 5386e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// To allow generic code to process a |TaggedUnion|, you can use a variant of 5486e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// what is commonly known as "the indices trick". The idea is to use template 5586e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// parameter pack expansion on |TaggedUnion|'s |Member| parameter to invoke some 5686e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// function for each member. For example, the following code determines the 5786e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// integer value of a |Variant| value as declared above: 5886e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// 5986e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// template <typename Type> 6086e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// void MemberToInt(const Type* member, int* value) { 6186e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// if (member) { 6286e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// *value = static_cast<int>(*member); 6386e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// } 6486e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// } 6586e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// 6686e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// void MemberToInt(const std::string* member, int* value) { 6786e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// if (member) { 6886e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// *value = std::stoi(*member); 6986e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// } 7086e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// } 7186e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// 7286e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// template <typename... Member> 7386e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// int VariantToInt(const TaggedUnion<VariantType, Member...>& variant) { 7486e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// int value = 0; 7586e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// int dummy[] = { 7686e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// (MemberToInt( 7786e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// variant.template get<static_cast<VariantType>(Member::kTag)>(), 7886e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// &value), 7986e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// 0)...}; 8086e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// (void)dummy; 8186e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// return value; 8286e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// }; 8386e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// 8486e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// Using this, you can convert a |Variant| in arbitrary state to an integer: 8586e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// 8686e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// ASSERT_EQ(-1, VariantToInt(value)); 8786e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 88a715cb1840f9a0c813c90707a351687f7a77950eMattias Nissler#ifndef NVRAM_MESSAGES_TAGGED_UNION_H_ 89a715cb1840f9a0c813c90707a351687f7a77950eMattias Nissler#define NVRAM_MESSAGES_TAGGED_UNION_H_ 9086e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 9186e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nisslerextern "C" { 9286e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler#include <stddef.h> 9386e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler} 9486e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 9586e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler#include <new> 9686e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 97a715cb1840f9a0c813c90707a351687f7a77950eMattias Nissler#include <nvram/messages/compiler.h> 9886e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 9986e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nisslernamespace nvram { 10086e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 10186e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nisslertemplate <uint64_t tag, typename Member> 10286e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nisslerstruct TaggedUnionMember { 10386e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler static constexpr uint64_t kTag = tag; 10486e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler using Type = Member; 10586e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler}; 10686e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 10786e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nisslertemplate <typename TagType, typename... Members> 10886e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nisslerclass TaggedUnion; 10986e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 11086e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nisslernamespace detail { 11186e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 11286e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// A compile-time maximum implementation. 11386e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nisslertemplate <size_t... Values> 11486e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nisslerstruct Max; 11586e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 11686e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nisslertemplate <> 11786e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nisslerstruct Max<> { 11886e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler static constexpr size_t value = 0; 11986e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler}; 12086e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 12186e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nisslertemplate <size_t head, size_t... tail> 12286e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nisslerstruct Max<head, tail...> { 12386e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler static constexpr size_t value = 12486e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler head > Max<tail...>::value ? head : Max<tail...>::value; 12586e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler}; 12686e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 12786e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// A helper template that determines the |TaggedUnionMember| type corresponding 12886e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// to |tag| via recursive expansion of the |Member| parameter list. 12986e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nisslertemplate <typename TagType, TagType tag, typename... Member> 13086e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nisslerstruct MemberForTag; 13186e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 13286e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nisslertemplate <typename TagType, 13386e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler TagType tag, 13486e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler uint64_t member_tag, 13586e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler typename MemberType, 13686e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler typename... Tail> 13786e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nisslerstruct MemberForTag<TagType, 13886e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler tag, 13986e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler TaggedUnionMember<member_tag, MemberType>, 14086e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler Tail...> { 14186e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler using Type = typename MemberForTag<TagType, tag, Tail...>::Type; 14286e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler}; 14386e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 14486e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nisslertemplate <typename TagType, TagType tag, typename MemberType, typename... Tail> 14586e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nisslerstruct MemberForTag<TagType, 14686e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler tag, 14786e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler TaggedUnionMember<static_cast<uint64_t>(tag), MemberType>, 14886e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler Tail...> { 14986e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler using Type = TaggedUnionMember<tag, MemberType>; 15086e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler}; 15186e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 15286e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// Extracts the first element of its template parameter list. 15386e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nisslertemplate <typename Elem, typename...Tail> 15486e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nisslerstruct Head { 15586e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler using Type = Elem; 15686e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler}; 15786e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 15886e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler} // namespace detail 15986e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 16086e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nisslertemplate <typename TagType, typename... Member> 16186e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nisslerclass TaggedUnion { 16286e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler public: 16386e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler template <TagType tag> 16486e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler struct MemberLookup { 16586e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler using Type = typename detail::MemberForTag<TagType, tag, Member...>::Type; 16686e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler }; 16786e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 16886e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler // Construct a |TaggedUnion| object. Note that the constructor will activate 16986e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler // the first declared union member. 17086e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler TaggedUnion() { 17186e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler Construct<static_cast<TagType>(detail::Head<Member...>::Type::kTag)>(); 17286e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler } 17386e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 17486e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler ~TaggedUnion() { 17586e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler Destroy(); 17686e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler } 17786e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 17886e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler // |TaggedUnion| is copyable and movable, provided the members have suitable 17986e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler // copy and move assignment operators. 18086e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler TaggedUnion(const TaggedUnion<TagType, Member...>& other) { 18186e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler CopyFrom(other); 18286e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler } 18386e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler TaggedUnion(TaggedUnion<TagType, Member...>&& other) { 18486e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler MoveFrom(other); 18586e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler } 18686e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler TaggedUnion<TagType, Member...>& operator=( 18786e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler const TaggedUnion<TagType, Member...>& other) { 18886e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler CopyFrom(other); 18986e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler } 19086e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler TaggedUnion<TagType, Member...>& operator=( 19186e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler TaggedUnion<TagType, Member...>&& other) { 19286e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler MoveFrom(other); 19386e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler } 19486e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 19586e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler // Returns the tag value corresponding to the active member. 19686e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler TagType which() const { return which_; } 19786e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 19886e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler // Get a pointer to the member corresponding to |tag|. Returns nullptr if 19986e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler // |tag| doesn't correspond to the active member. 20086e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler template <TagType tag> 20186e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler const typename MemberLookup<tag>::Type::Type* get() const { 20286e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler return which_ == tag ? GetUnchecked<tag>() : nullptr; 20386e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler } 20486e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 20586e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler // Get a pointer to the member corresponding to |tag|. Returns nullptr if 20686e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler // |tag| doesn't correspond to the active member. 20786e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler template <TagType tag> 20886e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler typename MemberLookup<tag>::Type::Type* get() { 20986e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler return which_ == tag ? GetUnchecked<tag>() : nullptr; 21086e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler } 21186e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 21286e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler // Activate the member identified by |tag|. First, the currently active member 21386e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler // will be destroyed. Then, the member corresponding to |tag| will be 21486e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler // constructed (i.e. value-initialized). Returns a reference to the activated 21586e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler // member. 21686e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler template <TagType tag> 21786e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler typename MemberLookup<tag>::Type::Type& Activate() { 21886e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler Destroy(); 21986e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler Construct<tag>(); 22086e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler return *GetUnchecked<tag>(); 22186e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler } 22286e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 22386e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler private: 22486e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler template<TagType tag> 22586e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler const typename MemberLookup<tag>::Type::Type* GetUnchecked() const { 22686e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler return reinterpret_cast<const typename MemberLookup<tag>::Type::Type*>( 22786e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler storage_); 22886e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler } 22986e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 23086e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler template<TagType tag> 23186e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler typename MemberLookup<tag>::Type::Type* GetUnchecked() { 23286e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler return reinterpret_cast<typename MemberLookup<tag>::Type::Type*>(storage_); 23386e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler } 23486e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 23586e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler template <TagType tag> 23686e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler void Construct() { 23786e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler using MemberType = typename MemberLookup<tag>::Type::Type; 23886e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler new (storage_) MemberType(); 23986e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler which_ = tag; 24086e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler } 24186e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 24286e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler template <typename CurrentMember> 24386e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler void DestroyMember() { 24486e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler using MemberType = typename CurrentMember::Type; 24586e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler if (CurrentMember::kTag == which_) { 24686e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler GetUnchecked<static_cast<TagType>(CurrentMember::kTag)>()->~MemberType(); 24786e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler } 24886e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler } 24986e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 25086e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler // This is marked noinline to prevent bloat due to the compiler inlining 25186e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler // |Destroy()| into each instance of the |Activate()| function. 25286e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler NVRAM_NOINLINE void Destroy() { 25386e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler int dummy[] = {(DestroyMember<Member>(), 0)...}; 25486e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler (void)dummy; 25586e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler } 25686e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 25786e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler template <typename CurrentMember> 25886e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler void CopyMember(const typename CurrentMember::Type* member) { 25986e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler if (member) { 26086e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler if (CurrentMember::kTag != which_) { 26186e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler Activate<CurrentMember::kTag>(); 26286e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler } 26386e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler *GetUnchecked<static_cast<TagType>(CurrentMember::kTag)>() = *member; 26486e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler } 26586e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler } 26686e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 26786e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler NVRAM_NOINLINE void CopyFrom(const TaggedUnion<TagType, Member...>& other) { 26886e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler int dummy[] = { 26986e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler (CopyMember<Member>( 27086e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler other.template get<static_cast<TagType>(Member::kTag)>()), 27186e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 0)...}; 27286e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler (void)dummy; 27386e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler } 27486e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 27586e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler template <typename CurrentMember> 27686e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler void MoveMember(const typename CurrentMember::Type* member) { 27786e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler if (member) { 27886e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler if (CurrentMember::kTag != which_) { 27986e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler Activate<CurrentMember::kTag>(); 28086e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler } 28186e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler *GetUnchecked<static_cast<TagType>(CurrentMember::kTag)>() = 28286e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler static_cast<typename CurrentMember::Type&&>(*member); 28386e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler } 28486e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler } 28586e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 28686e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler NVRAM_NOINLINE void MoveFrom(const TaggedUnion<TagType, Member...>& other) { 28786e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler int dummy[] = { 28886e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler (MoveMember<Member>( 28986e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler other.template get<static_cast<TagType>(Member::kTag)>()), 29086e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 0)...}; 29186e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler (void)dummy; 29286e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler } 29386e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 29486e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler // The + 0 is required to work around a G++ bug: 29586e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55382 29686e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler alignas(detail::Max<alignof(typename Member::Type)...>::value + 0) 29786e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler uint8_t storage_[detail::Max<sizeof(typename Member::Type)...>::value]; 29886e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler TagType which_; 29986e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler}; 30086e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 30186e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler} // namespace nvram 30286e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 303a715cb1840f9a0c813c90707a351687f7a77950eMattias Nissler#endif // NVRAM_MESSAGES_TAGGED_UNION_H_ 304