13d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler/* 23d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler * Copyright (C) 2016 The Android Open Source Project 33d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler * 43d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler * Licensed under the Apache License, Version 2.0 (the "License"); 53d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler * you may not use this file except in compliance with the License. 63d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler * You may obtain a copy of the License at 73d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler * 83d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler * http://www.apache.org/licenses/LICENSE-2.0 93d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler * 103d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler * Unless required by applicable law or agreed to in writing, software 113d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler * distributed under the License is distributed on an "AS IS" BASIS, 123d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler * See the License for the specific language governing permissions and 143d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler * limitations under the License. 153d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler */ 163d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler 173d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// This file provides facilities to declare compile-time descriptors for C++ 183d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// struct types. This enables generic code to access the declared struct 193d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// members in an object. 203d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// 213d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// For example, consider the following struct type: 223d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// 233d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// struct Employee { 243d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// uint32_t id; 253d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// std::string name; 263d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// std::vector<uint32_t> reports; 273d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// }; 283d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// 293d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// The descriptor is declared as follows, providing access to |Employee|'s 303d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// members and assigning a unique field number to each of them: 313d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// 323d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// template <> 333d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// struct DescriptorForType<Employee> { 343d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// static constexpr auto kFields = 353d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// MakeFieldList(MakeField(1, &Employee::id), 363d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// MakeField(2, &Employee::name), 373d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// MakeField(3, &Employee::reports)); 383d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// }; 393d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// 403d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// Note that the |kFields| member is a constexpr, which creates a compile-time 413d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// constant, so the field meta data can be used in compile-time computations and 423d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// as template parameters. 433d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// 443d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// To access the declared members, there is a |Get()| member function template 453d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// on the declared field list, which allows to retrieve one of the field 463d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// specifications by index (zero-based declaration index, *not* field number). 473d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// Once you have the field spec for a field, you can use |FieldSpec::Get()| to 483d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// get a reference to the member within a struct instance. This can be used to 493d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// implement generic algorithms that make use of the descriptor behind the 503d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// scenes. Here is an example that shows how to build a generic comparator: 513d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// 523d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// template <typename Struct> 533d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// struct StructCompare { 543d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// template <typename Member> 553d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// int compareMember(const Member& left, const Member& right) { 563d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// return left < right ? -1 : (right < left ? 1 : 0); 573d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// } 583d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// 593d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// template <size_t... indices> 603d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// int compare(const Struct& left, 613d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// const Struct& right, 623d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// index_sequence<indices...>) { 633d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// constexpr auto kFieldSpecList = DescriptorForType<Struct>::kFields; 643d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// int results[] = {compareMember( 653d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// kFieldSpecList.template Get<indices>().Get(left), 663d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// kFieldSpecList.template Get<indices>().Get(right))...}; 673d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// for (int result : results) { 683d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// if (result != 0) { 693d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// return result; 703d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// } 713d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// } 723d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// 733d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// return 0; 743d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// } 753d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// 763d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// bool operator()(const Struct& left, const Struct& right) { 773d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// constexpr auto kFieldSpecList = DescriptorForType<Struct>::kFields; 783d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// return compare(left, right, 793d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// make_index_sequence<kFieldSpecList.kSize>()) < 0; 803d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// } 813d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// }; 823d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// 833d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// You can now use |StructCompare| as a key comparison function with std::set 843d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// like this: 853d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// 863d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// std::set<Employee, StructCompare<Employee>> employees; 873d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// employees.emplace(std::move(new_employee)); 883d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// 893d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// The ability to write generic algorithms that can process arbitrarily-typed 903d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// struct fields comes at the cost of heavy usage of template constructs. 913d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// However, potential alternatives are not without drawbacks: 923d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// * Avoiding generic code entirely and writing the necessary operations for 933d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// each struct type manually is tedious and error-prone. 943d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// * Tool-generated code is just as hard to comprehend and maintain, and code 953d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// making use of the generated constructs may need to be generated as well. 963d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// * For the intended use in message serialization, there are existing message 973d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// serialization solutions such as protobuf. Unfortunately, our serialization 983d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// code needs to run in resource-constrained environments that don't provide 993d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// a C++ standard library (which is a dependency of the regular protobuf 1003d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// implementation), and the library weighs in as a non-trivial dependency in 1013d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// terms of code size. 1023d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler 103a715cb1840f9a0c813c90707a351687f7a77950eMattias Nissler#ifndef NVRAM_MESSAGES_STRUCT_H_ 104a715cb1840f9a0c813c90707a351687f7a77950eMattias Nissler#define NVRAM_MESSAGES_STRUCT_H_ 1053d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler 106a715cb1840f9a0c813c90707a351687f7a77950eMattias Nissler#include <nvram/messages/type_traits.h> 1073d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler 1083d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslernamespace nvram { 1093d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler 1103d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// This class template is used to resolve struct types to their corresponding 1113d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// descriptors, which provide a list of struct fields that includes the field 1123d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// numbers as well as the corresponding C++ struct members in |Struct|. See the 1133d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// file comment above for an example. 1143d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslertemplate <typename Struct> 1153d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslerstruct DescriptorForType; 1163d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler 1173d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// |FieldSpec| describes a member field of the struct type |Struct|. The 1183d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// template parameters capture the C++ |Member| type of the |Struct| member that 1193d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// holds the field's data. 1203d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// 1213d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// Note that this class template is a literal type, i.e. can be used with 1223d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// constexpr. As an implication, |FieldSpec| instances can be used as 1233d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// compile-time data. 1243d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslertemplate <typename Struct, typename Member> 1253d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslerstruct FieldSpec { 1263d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler using MemberType = Member; 1273d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler 1283d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler constexpr FieldSpec(uint32_t field_number, MemberType Struct::* member) 1293d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler : kFieldNumber(field_number), kMember(member) {} 1303d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler 1313d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler const MemberType& Get(const Struct& object) const { 1323d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler return object.*kMember; 1333d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler } 1343d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler 1353d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler MemberType& Get(Struct& object) const { 1363d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler return object.*kMember; 1373d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler } 1383d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler 1393d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler // The field number for this field. 1403d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler const uint32_t kFieldNumber; 1413d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler 1423d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler // A member pointer to the |Struct| member that holds the field data. 1433d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler MemberType Struct::*const kMember; 1443d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler}; 1453d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler 1463d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// A helper function template that enables template argument deduction to be 1473d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// used to construct |FieldSpec| instances. 1483d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslertemplate <typename Struct, typename Member> 1493d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslerconstexpr FieldSpec<Struct, Member> MakeField(uint32_t field_number, 1503d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler Member Struct::*member) { 1513d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler return FieldSpec<Struct, Member>(field_number, member); 1523d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler}; 1533d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler 15486e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// Forward declaration for |TaggedUnion|, so we don't have to include the full 15586e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// header. 15686e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nisslertemplate <typename TagType, typename... Member> 15786e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nisslerclass TaggedUnion; 15886e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 15986e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// A special field specification type for protobuf fields belonging to a "oneof" 16086e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// construct, of which one field may be active at a time. This is represented by 16186e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// a |TaggedUnion| struct member. In addition to the field number and member 16286e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// pointer, the field specification also records the |TaggedUnion| tag value 16386e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// that selects the |TaggedUnion| member which corresponds to the field. 16486e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nisslertemplate <typename Struct, typename TagType, typename... Member> 16586e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nisslerstruct OneOfFieldSpec 16686e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler : public FieldSpec<Struct, TaggedUnion<TagType, Member...>> { 16786e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler using TaggedUnionType = TaggedUnion<TagType, Member...>; 16886e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 16986e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler constexpr OneOfFieldSpec(uint32_t field_number, 17086e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler TaggedUnionType Struct::*member, 17186e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler TagType tag) 17286e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler : FieldSpec<Struct, TaggedUnionType>(field_number, member), kTag(tag) {} 17386e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 17486e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler // The |TaggedUnion| tag corresponding to the |TaggedUnion| member that holds 17586e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler // the field's data. 17686e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler const TagType kTag; 17786e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler}; 17886e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 17986e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// A helper function template that simplifies |OneOfFieldSpec| creation by 18086e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler// enabling template argument type deduction. 18186e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nisslertemplate <typename Struct, typename TagType, typename... Member> 18286e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nisslerconstexpr OneOfFieldSpec<Struct, TagType, Member...> MakeOneOfField( 18386e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler uint32_t field_number, 18486e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler TaggedUnion<TagType, Member...> Struct::*member, 18586e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler TagType tag) { 18686e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler return OneOfFieldSpec<Struct, TagType, Member...>(field_number, member, tag); 18786e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler}; 18886e84547d37d7d32a5444756f839e11d81c9fc2dMattias Nissler 1893d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// A simple type list intended to hold field specification values. 1903d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// 1913d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// Note that |FieldSpecList| is a literal type so can be used with constexpr to 1923d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// hold compile-time data. 1933d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslertemplate <typename... FieldSpec> 1943d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslerstruct FieldSpecList; 1953d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler 1963d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslernamespace { 1973d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler 1983d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// A helper template that extracts the field spec at |index| from a field spec 1993d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// list. 2003d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslertemplate <size_t index, typename... FieldSpec> 2013d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslerstruct FieldSpecLookup; 2023d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler 2033d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// Recursion step: This specialization matches if |index| is larger than 0, and 2043d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// the |Get()| definition just forwards to the list tail. 2053d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslertemplate <size_t index, typename FieldSpec, typename... Tail> 2063d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslerstruct FieldSpecLookup<index, FieldSpec, Tail...> { 2073d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler using Prev = FieldSpecLookup<index - 1, Tail...>; 2083d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler using Type = typename Prev::Type; 2093d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler static constexpr Type Get(FieldSpecList<FieldSpec, Tail...> self) { 2103d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler return Prev::Get(self.kTail); 2113d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler } 2123d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler}; 2133d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler 2143d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// Recursion base case: |index| as reached 0, so |Get()| returns the field spec 2153d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// corresponding to the current |FieldSpec|. 2163d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslertemplate <typename FieldSpec, typename... Tail> 2173d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslerstruct FieldSpecLookup<0, FieldSpec, Tail...> { 2183d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler using Type = FieldSpec; 2193d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler static constexpr Type Get(FieldSpecList<FieldSpec, Tail...> self) { 2203d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler return self.kFieldSpec; 2213d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler } 2223d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler}; 2233d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler 2243d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// Produces an error message in case the provided |index| is too large, i.e. 2253d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// doesn't match any field. This specialization only matches once the 2263d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// |FieldSpec| parameters are exhausted. 2273d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslertemplate <size_t index> 2283d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslerstruct FieldSpecLookup<index> { 2293d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler // Note that |index < 0| will never be satisfied, so this static assert 2303d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler // triggers unconditionally if this template specialization ever gets 2313d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler // instantiated. It will only be instantiated if |index| exceeds the number of 2323d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler // declared fields. 2333d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler // 2343d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler // Just putting |false| as the static_assert condition would seem a saner 2353d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler // alternative, but doesn't work since the static_assert would then be 2363d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler // evaluated at declaration time. Using the |index| parameter in the condition 2373d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler // forces evaluation to take place at template instantiation time. 2383d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler static_assert(index < 0, "Out-of-bounds |index| in field spec lookup."); 2393d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler}; 2403d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler 2413d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler} // namespace 2423d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler 2433d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// |FieldSpecList| specialization that holds the data of the front-most element 2443d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// of |FieldSpecList|'s |Fields| arguments. Note that this class contains a 2453d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// nested |FieldSpecList| instance with the front-most element removed, thus 2463d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// inheriting the members for subsequent |Fields| arguments. 2473d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslertemplate <typename FieldSpec, typename... Tail> 2483d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslerstruct FieldSpecList<FieldSpec, Tail...> { 2493d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler using List = FieldSpecList<FieldSpec, Tail...>; 2503d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler using TailList = FieldSpecList<Tail...>; 2513d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler 252bb621b95ea636314c87b885107c8d5331992f9bbChih-Hung Hsieh constexpr explicit FieldSpecList(FieldSpec field_spec, Tail... tail) 2533d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler : kFieldSpec(field_spec), kTail(tail...) {} 2543d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler 2553d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler template <size_t index> 2563d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler constexpr typename FieldSpecLookup<index, FieldSpec, Tail...>::Type Get() 2573d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler const { 2583d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler return FieldSpecLookup<index, FieldSpec, Tail...>::Get(*this); 2593d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler } 2603d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler 2613d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler static constexpr size_t kSize = TailList::kSize + 1; 2623d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler const FieldSpec kFieldSpec; 2633d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler const TailList kTail; 2643d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler}; 2653d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler 2663d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// |FieldSpecList| specialization acting as the recursion base case. This 2673d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// doesn't have further members and thus stops the expansion of 2683d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// |FieldSpecList|'s |Fields| parameter. 2693d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslertemplate <> 2703d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslerstruct FieldSpecList<> { 2713d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler static constexpr size_t kSize = 0; 2723d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler}; 2733d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler 2743d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// Helper function template that enables convenient creation of |FieldSpecList| 2753d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler// instances by enabling template argument deduction. 2763d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslertemplate <typename... FieldSpec> 2773d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nisslerconstexpr FieldSpecList<FieldSpec...> MakeFieldList(FieldSpec... field_spec) { 2783d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler return FieldSpecList<FieldSpec...>(field_spec...); 2793d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler} 2803d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler 2813d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler} // namespace nvram 2823d2f13f288feb42f1dfcfe558af27955edefaad3Mattias Nissler 283a715cb1840f9a0c813c90707a351687f7a77950eMattias Nissler#endif // NVRAM_MESSAGES_STRUCT_H_ 284