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