310 lines · cpp
1// RUN: %clang_cc1 -std=c++20 -verify %s2// expected-no-diagnostics3 4template <int __v> struct integral_constant {5 static constexpr int value = __v;6};7template <bool _Val> using _BoolConstant = integral_constant<_Val>;8template <int, class> struct tuple_element;9template <class...> class tuple;10template <int _Ip, class... _Tp> struct tuple_element<_Ip, tuple<_Tp...>> {11 using type = __type_pack_element<_Ip, _Tp...>;12};13template <class> struct tuple_size;14template <bool> using __enable_if_t = int;15template <template <class> class _BaseType, class _Tp, _Tp _SequenceSize>16using __make_integer_sequence_impl =17 __make_integer_seq<_BaseType, _Tp, _SequenceSize>;18template <class _Tp, _Tp...> struct __integer_sequence;19template <int... _Indices>20using __index_sequence = __integer_sequence<int, _Indices...>;21template <int _SequenceSize>22using __make_index_sequence =23 __make_integer_sequence_impl<__integer_sequence, int, _SequenceSize>;24template <class _Tp, _Tp...> struct integer_sequence {};25template <int... _Ip> using index_sequence = integer_sequence<int, _Ip...>;26template <class _Tp, _Tp _Ep>27using make_integer_sequence =28 __make_integer_sequence_impl<integer_sequence, _Tp, _Ep>;29template <int _Np> using make_index_sequence = make_integer_sequence<int, _Np>;30enum __element_count : int;31constexpr void __constexpr_memmove(char *__dest, const char *__src,32 __element_count __n) {33 __builtin_memmove(__dest, __src, __n);34}35template <class _Tp> using __underlying_type_t = __underlying_type(_Tp);36template <class _Tp> using underlying_type_t = __underlying_type_t<_Tp>;37template <class _Tp, class> using __enable_if_tuple_size_imp = _Tp;38template <class _Tp>39struct tuple_size<__enable_if_tuple_size_imp<40 const _Tp, __enable_if_t<_BoolConstant<__is_volatile(int)>::value>>>41 : integral_constant<tuple_size<_Tp>::value> {};42template <class... _Tp>43struct tuple_size<tuple<_Tp...>> : integral_constant<sizeof...(_Tp)> {};44template <class _Tp> constexpr int tuple_size_v = tuple_size<_Tp>::value;45template <class _T1, class _T2> struct pair {46 _T1 first;47 _T2 second;48};49template <class _T1> constexpr pair<_T1, char *> make_pair(_T1, char *__t2) {50 return pair(_T1(), __t2);51}52template <int, class _Hp> struct __tuple_leaf {53 _Hp __value_;54 constexpr const _Hp &get() const { return __value_; }55};56template <class...> struct __tuple_impl;57template <int... _Indx, class... _Tp>58struct __tuple_impl<__index_sequence<_Indx...>, _Tp...>59 : __tuple_leaf<_Indx, _Tp>... {60 template <class... _Args>61 constexpr __tuple_impl(int, _Args... __args)62 : __tuple_leaf<_Indx, _Tp>(__args)... {}63};64template <class... _Tp> struct tuple {65 __tuple_impl<__make_index_sequence<sizeof...(_Tp)>, _Tp...> __base_;66 template <class... _Up> constexpr tuple(_Up... __u) : __base_({}, __u...) {}67};68template <int _Ip, class... _Tp>69constexpr const tuple_element<_Ip, tuple<_Tp...>>::type &70get(const tuple<_Tp...> &__t) noexcept {71 return static_cast<const __tuple_leaf<72 _Ip, typename tuple_element<_Ip, tuple<_Tp...>>::type> &>(__t.__base_)73 .get();74}75template <class... _Tp> constexpr tuple<_Tp...> make_tuple(_Tp... __t) {76 return tuple<_Tp...>(__t...);77}78constexpr int __char_traits_length_checked(const char *__s) {79 return __builtin_strlen(__s);80}81struct basic_string_view {82 constexpr basic_string_view() {}83 constexpr basic_string_view(const char *__s)84 : __data_(__s), __size_(__char_traits_length_checked(__s)) {}85 constexpr const char *begin() { return __data_; }86 constexpr const char *end() {87 return __data_ + __size_;88 }89 const char *__data_;90 int __size_;91};92template <class _Algorithm>93constexpr pair<const char *, char *>94__copy_move_unwrap_iters(const char *__first, const char *__last,95 char *__out_first) {96 pair<const char *, const char *> __range = {__first, __last};97 auto __result = _Algorithm()(__range.first, __range.second, __out_first);98 return make_pair(__result.first, __result.second);99}100struct __copy_impl {101 constexpr pair<const char *, char *>102 operator()(const char *__first, const char *__last, char *__result) {103 const int __n(__last - __first);104 __constexpr_memmove(__result, __first, __element_count(__n));105 return make_pair(__last, __result);106 }107};108constexpr char *copy(const char *__first, const char *__last, char *__result) {109 return __copy_move_unwrap_iters<__copy_impl>(__first, __last, __result).second;110}111constexpr char *copy_n(const char *__first, int __orig_n, char *__result) {112 return copy(__first, __first + __orig_n, __result);113}114template <int _Size> struct array {115 basic_string_view __elems_[_Size];116 constexpr basic_string_view &operator[](int __n) { return __elems_[__n]; }117 constexpr basic_string_view operator[](int __n) const {118 return __elems_[__n];119 }120};121 122template <typename> struct FieldId;123 124template <FieldId field> constexpr auto FieldIdToInnerValue() {125 return field.template ToInnerValue<field>();126}127struct FieldNameEnum {128 enum class type;129};130template <int N> using FieldName = FieldNameEnum::type;131template <typename, auto> struct GetParentMessageAtIndexImpl;132template <typename, auto> struct FieldInfoHelper;133template <FieldId...> struct PathImpl;134template <int N> struct LongPathLiteral {135 consteval LongPathLiteral(const char (&s)[N]) {136 copy_n(s, N, long_path)[N] = field_count = long_path_size = 1;137 }138 consteval basic_string_view to_string_view() const { return long_path; }139 char long_path[N + 1];140 int long_path_size;141 int field_count;142};143template <LongPathLiteral kLongPath> consteval auto get_field_components() {144 basic_string_view long_path(kLongPath.to_string_view());145 array<kLongPath.field_count> ret;146 for (int i = 0; i < kLongPath.field_count; ++i)147 ret[i] = long_path;148 return ret;149}150template <LongPathLiteral kLongPath>151constexpr auto kFieldComponents = get_field_components<kLongPath>();152template <LongPathLiteral kLongPath> struct LongPathHelper {153 template <int... I>154 static PathImpl<kFieldComponents<kLongPath>[I]...>155 PathForLongPath(index_sequence<I...>);156 using type =157 decltype(PathForLongPath(make_index_sequence<kLongPath.field_count>{}));158};159template <typename T> struct PathFieldId {160 template <typename Arg> constexpr PathFieldId(Arg &arg) : value(arg) {}161 T value;162};163template <PathFieldId...> constexpr auto PathImplHelper();164 165template <int N> using FieldName = FieldName<N>;166enum class FieldNumber;167template <PathFieldId... fields>168constexpr auto Path = PathImplHelper<fields...>();169template <typename Proto, FieldId field>170using FieldInfo =171 FieldInfoHelper<Proto, FieldIdToInnerValue<field>()>::type;172template <> struct FieldId<FieldNameEnum::type> {173 constexpr FieldId(basic_string_view);174 int size;175 long hash;176 template <auto field> static constexpr auto ToInnerValue() {177 return static_cast<FieldNameEnum::type>(field.hash);178 }179};180FieldId(basic_string_view) -> FieldId<FieldNameEnum::type>;181template <typename Proto, FieldId field, int index>182using GetParentMessageAtIndex = GetParentMessageAtIndexImpl<183 Proto, FieldIdToInnerValue<field>()>::type;184 185template <typename T>186PathFieldId(T &t) -> PathFieldId<decltype(LongPathLiteral(t))>;187template <FieldId... fields1, FieldId... fields2>188constexpr PathImpl<fields1..., fields2...> *ConcatPath(PathImpl<fields1...> *,189 PathImpl<fields2...> *) {190 return nullptr;191}192template <LongPathLiteral long_path_literal>193constexpr LongPathHelper<long_path_literal>::type *SinglePath() {194 return nullptr;195}196template <PathFieldId... fields> constexpr auto PathImplHelper() {197 return ConcatPath(SinglePath<fields.value>()...);198}199template <auto hash_prime, auto offset_bias>200constexpr auto Fnv1a(basic_string_view str) {201 auto hash = offset_bias;202 for (char c : str) {203 hash ^= c;204 hash *= hash_prime;205 }206 return hash;207}208constexpr auto HashField(basic_string_view str) {209 return Fnv1a<1099511628211u, 1039346656037>(str);210}211template <typename FI> struct FieldInfoValueTypeAlias : FI {};212template <typename Proto, auto field> struct FieldInfoHelperBase {213 static constexpr auto MaskFieldNameHash() {214 using FieldEnum = decltype(field);215 return FieldEnum{static_cast<underlying_type_t<FieldEnum>>(field) & 31};216 }217 using internal_type =218 Proto::template FieldInfoImpl<decltype(field), MaskFieldNameHash()>;219};220template <typename Proto, auto field> struct FieldInfoHelper {221 using type = FieldInfoValueTypeAlias<222 typename FieldInfoHelperBase<Proto, field>::internal_type>;223};224 225template <auto... fields>226struct FieldId<const PathImpl<fields...> *> {227 constexpr FieldId(PathImpl<fields...> *) : path() {}228 template <auto field> static constexpr auto ToInnerValue() {229 return field.path;230 }231 const PathImpl<fields...> *path;232};233template <auto... fields>234FieldId(PathImpl<fields...> *)235 -> FieldId<const PathImpl<fields...> *>;236 237template <auto> struct UnpackedField {238 static constexpr bool is_path = false;239};240template <auto... fields, const PathImpl<fields...> *path>241struct UnpackedField<path> {242 static constexpr auto value = make_tuple(fields...);243 static constexpr bool is_path = true;244};245template <typename Proto, FieldId... fields, const PathImpl<fields...> *path>246struct GetParentMessageAtIndexImpl<Proto, path> {247 using type = Proto;248};249 250constexpr FieldId<FieldNameEnum::type>::FieldId(basic_string_view str)251 : size(), hash(HashField(str)) {}252template <FieldId field> constexpr bool IsPath() {253 return UnpackedField<254 FieldIdToInnerValue<field>()>::is_path;255}256template <FieldId field> constexpr auto UnpackFieldToTuple() {257 return UnpackedField<FieldIdToInnerValue<field>()>::value;258}259template <int> struct CompileTimeString {260 consteval CompileTimeString(basic_string_view &v) : internal_view_(v) {}261 basic_string_view &internal_view_;262};263CompileTimeString(basic_string_view) -> CompileTimeString<0>;264 265template <CompileTimeString... parts> struct NameJoiner {266 template <CompileTimeString... after>267 NameJoiner<parts...> operator+(NameJoiner<after...>);268};269template <FieldId> struct FieldNameBuilder;270template <FieldId field>271 requires(!IsPath<field>())272struct FieldNameBuilder<field> {273 template <typename Proto> static auto Get() {274 return NameJoiner<FieldInfo<Proto, field>::name>();275 }276};277template <FieldId field>278 requires(IsPath<field>())279struct FieldNameBuilder<field> {280 static constexpr auto kTuple = UnpackFieldToTuple<field>();281 static constexpr int kTupleSize = tuple_size_v<decltype(kTuple)>;282 template <typename Proto, int... Is> static void Get(index_sequence<Is...>) {283 (FieldNameBuilder<get<Is>(284 kTuple)>::template Get<GetParentMessageAtIndex<Proto, field, Is>>() +285 ...);286 }287 template <typename Proto> static void Get() {288 Get<Proto>(make_index_sequence<kTupleSize>());289 }290};291 292struct T {293 template <typename FieldType, FieldType> struct FieldInfoImpl;294};295void AddPathsToFieldMask() {296 FieldNameBuilder<Path<"message_field", "int32_field">>::Get<T>();297}298template <> struct T::FieldInfoImpl<FieldNumber, FieldNumber{1}> {299 static basic_string_view name;300};301template <>302struct T::FieldInfoImpl<FieldName<1>, FieldName<1>{12}>303 : FieldInfoImpl<FieldNumber, FieldNumber{1}> {};304template <> struct T::FieldInfoImpl<FieldNumber, FieldNumber{10}> {305 static basic_string_view name;306};307template <>308struct T::FieldInfoImpl<FieldName<3>, FieldName<3>{11}>309 : FieldInfoImpl<FieldNumber, FieldNumber{10}> {};310