|
| 1 | +// RUN: %clang_cc1 -std=c++20 -verify %s |
| 2 | +// expected-no-diagnostics |
| 3 | + |
| 4 | +template <int __v> struct integral_constant { |
| 5 | + static constexpr int value = __v; |
| 6 | +}; |
| 7 | +template <bool _Val> using _BoolConstant = integral_constant<_Val>; |
| 8 | +template <int, class> struct tuple_element; |
| 9 | +template <class...> class tuple; |
| 10 | +template <int _Ip, class... _Tp> struct tuple_element<_Ip, tuple<_Tp...>> { |
| 11 | + using type = __type_pack_element<_Ip, _Tp...>; |
| 12 | +}; |
| 13 | +template <class> struct tuple_size; |
| 14 | +template <bool> using __enable_if_t = int; |
| 15 | +template <template <class> class _BaseType, class _Tp, _Tp _SequenceSize> |
| 16 | +using __make_integer_sequence_impl = |
| 17 | + __make_integer_seq<_BaseType, _Tp, _SequenceSize>; |
| 18 | +template <class _Tp, _Tp...> struct __integer_sequence; |
| 19 | +template <int... _Indices> |
| 20 | +using __index_sequence = __integer_sequence<int, _Indices...>; |
| 21 | +template <int _SequenceSize> |
| 22 | +using __make_index_sequence = |
| 23 | + __make_integer_sequence_impl<__integer_sequence, int, _SequenceSize>; |
| 24 | +template <class _Tp, _Tp...> struct integer_sequence {}; |
| 25 | +template <int... _Ip> using index_sequence = integer_sequence<int, _Ip...>; |
| 26 | +template <class _Tp, _Tp _Ep> |
| 27 | +using make_integer_sequence = |
| 28 | + __make_integer_sequence_impl<integer_sequence, _Tp, _Ep>; |
| 29 | +template <int _Np> using make_index_sequence = make_integer_sequence<int, _Np>; |
| 30 | +enum __element_count : int; |
| 31 | +constexpr void __constexpr_memmove(char *__dest, const char *__src, |
| 32 | + __element_count __n) { |
| 33 | + __builtin_memmove(__dest, __src, __n); |
| 34 | +} |
| 35 | +template <class _Tp> using __underlying_type_t = __underlying_type(_Tp); |
| 36 | +template <class _Tp> using underlying_type_t = __underlying_type_t<_Tp>; |
| 37 | +template <class _Tp, class> using __enable_if_tuple_size_imp = _Tp; |
| 38 | +template <class _Tp> |
| 39 | +struct 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> {}; |
| 42 | +template <class... _Tp> |
| 43 | +struct tuple_size<tuple<_Tp...>> : integral_constant<sizeof...(_Tp)> {}; |
| 44 | +template <class _Tp> constexpr int tuple_size_v = tuple_size<_Tp>::value; |
| 45 | +template <class _T1, class _T2> struct pair { |
| 46 | + _T1 first; |
| 47 | + _T2 second; |
| 48 | +}; |
| 49 | +template <class _T1> constexpr pair<_T1, char *> make_pair(_T1, char *__t2) { |
| 50 | + return pair(_T1(), __t2); |
| 51 | +} |
| 52 | +template <int, class _Hp> struct __tuple_leaf { |
| 53 | + _Hp __value_; |
| 54 | + constexpr const _Hp &get() const { return __value_; } |
| 55 | +}; |
| 56 | +template <class...> struct __tuple_impl; |
| 57 | +template <int... _Indx, class... _Tp> |
| 58 | +struct __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 | +}; |
| 64 | +template <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 | +}; |
| 68 | +template <int _Ip, class... _Tp> |
| 69 | +constexpr const tuple_element<_Ip, tuple<_Tp...>>::type & |
| 70 | +get(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 | +} |
| 75 | +template <class... _Tp> constexpr tuple<_Tp...> make_tuple(_Tp... __t) { |
| 76 | + return tuple<_Tp...>(__t...); |
| 77 | +} |
| 78 | +constexpr int __char_traits_length_checked(const char *__s) { |
| 79 | + return __builtin_strlen(__s); |
| 80 | +} |
| 81 | +struct 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 | +}; |
| 92 | +template <class _Algorithm> |
| 93 | +constexpr 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 | +} |
| 100 | +struct __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 | +}; |
| 108 | +constexpr char *copy(const char *__first, const char *__last, char *__result) { |
| 109 | + return __copy_move_unwrap_iters<__copy_impl>(__first, __last, __result).second; |
| 110 | +} |
| 111 | +constexpr char *copy_n(const char *__first, int __orig_n, char *__result) { |
| 112 | + return copy(__first, __first + __orig_n, __result); |
| 113 | +} |
| 114 | +template <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 | + |
| 122 | +template <typename> struct FieldId; |
| 123 | + |
| 124 | +template <FieldId field> constexpr auto FieldIdToInnerValue() { |
| 125 | + return field.template ToInnerValue<field>(); |
| 126 | +} |
| 127 | +struct FieldNameEnum { |
| 128 | + enum class type; |
| 129 | +}; |
| 130 | +template <int N> using FieldName = FieldNameEnum::type; |
| 131 | +template <typename, auto> struct GetParentMessageAtIndexImpl; |
| 132 | +template <typename, auto> struct FieldInfoHelper; |
| 133 | +template <FieldId...> struct PathImpl; |
| 134 | +template <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 | +}; |
| 143 | +template <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 | +} |
| 150 | +template <LongPathLiteral kLongPath> |
| 151 | +constexpr auto kFieldComponents = get_field_components<kLongPath>(); |
| 152 | +template <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 | +}; |
| 159 | +template <typename T> struct PathFieldId { |
| 160 | + template <typename Arg> constexpr PathFieldId(Arg &arg) : value(arg) {} |
| 161 | + T value; |
| 162 | +}; |
| 163 | +template <PathFieldId...> constexpr auto PathImplHelper(); |
| 164 | + |
| 165 | +template <int N> using FieldName = FieldName<N>; |
| 166 | +enum class FieldNumber; |
| 167 | +template <PathFieldId... fields> |
| 168 | +constexpr auto Path = PathImplHelper<fields...>(); |
| 169 | +template <typename Proto, FieldId field> |
| 170 | +using FieldInfo = |
| 171 | + FieldInfoHelper<Proto, FieldIdToInnerValue<field>()>::type; |
| 172 | +template <> 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 | +}; |
| 180 | +FieldId(basic_string_view) -> FieldId<FieldNameEnum::type>; |
| 181 | +template <typename Proto, FieldId field, int index> |
| 182 | +using GetParentMessageAtIndex = GetParentMessageAtIndexImpl< |
| 183 | + Proto, FieldIdToInnerValue<field>()>::type; |
| 184 | + |
| 185 | +template <typename T> |
| 186 | +PathFieldId(T &t) -> PathFieldId<decltype(LongPathLiteral(t))>; |
| 187 | +template <FieldId... fields1, FieldId... fields2> |
| 188 | +constexpr PathImpl<fields1..., fields2...> *ConcatPath(PathImpl<fields1...> *, |
| 189 | + PathImpl<fields2...> *) { |
| 190 | + return nullptr; |
| 191 | +} |
| 192 | +template <LongPathLiteral long_path_literal> |
| 193 | +constexpr LongPathHelper<long_path_literal>::type *SinglePath() { |
| 194 | + return nullptr; |
| 195 | +} |
| 196 | +template <PathFieldId... fields> constexpr auto PathImplHelper() { |
| 197 | + return ConcatPath(SinglePath<fields.value>()...); |
| 198 | +} |
| 199 | +template <auto hash_prime, auto offset_bias> |
| 200 | +constexpr 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 | +} |
| 208 | +constexpr auto HashField(basic_string_view str) { |
| 209 | + return Fnv1a<1099511628211u, 1039346656037>(str); |
| 210 | +} |
| 211 | +template <typename FI> struct FieldInfoValueTypeAlias : FI {}; |
| 212 | +template <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 | +}; |
| 220 | +template <typename Proto, auto field> struct FieldInfoHelper { |
| 221 | + using type = FieldInfoValueTypeAlias< |
| 222 | + typename FieldInfoHelperBase<Proto, field>::internal_type>; |
| 223 | +}; |
| 224 | + |
| 225 | +template <auto... fields> |
| 226 | +struct 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 | +}; |
| 233 | +template <auto... fields> |
| 234 | +FieldId(PathImpl<fields...> *) |
| 235 | + -> FieldId<const PathImpl<fields...> *>; |
| 236 | + |
| 237 | +template <auto> struct UnpackedField { |
| 238 | + static constexpr bool is_path = false; |
| 239 | +}; |
| 240 | +template <auto... fields, const PathImpl<fields...> *path> |
| 241 | +struct UnpackedField<path> { |
| 242 | + static constexpr auto value = make_tuple(fields...); |
| 243 | + static constexpr bool is_path = true; |
| 244 | +}; |
| 245 | +template <typename Proto, FieldId... fields, const PathImpl<fields...> *path> |
| 246 | +struct GetParentMessageAtIndexImpl<Proto, path> { |
| 247 | + using type = Proto; |
| 248 | +}; |
| 249 | + |
| 250 | +constexpr FieldId<FieldNameEnum::type>::FieldId(basic_string_view str) |
| 251 | + : size(), hash(HashField(str)) {} |
| 252 | +template <FieldId field> constexpr bool IsPath() { |
| 253 | + return UnpackedField< |
| 254 | + FieldIdToInnerValue<field>()>::is_path; |
| 255 | +} |
| 256 | +template <FieldId field> constexpr auto UnpackFieldToTuple() { |
| 257 | + return UnpackedField<FieldIdToInnerValue<field>()>::value; |
| 258 | +} |
| 259 | +template <int> struct CompileTimeString { |
| 260 | + consteval CompileTimeString(basic_string_view &v) : internal_view_(v) {} |
| 261 | + basic_string_view &internal_view_; |
| 262 | +}; |
| 263 | +CompileTimeString(basic_string_view) -> CompileTimeString<0>; |
| 264 | + |
| 265 | +template <CompileTimeString... parts> struct NameJoiner { |
| 266 | + template <CompileTimeString... after> |
| 267 | + NameJoiner<parts...> operator+(NameJoiner<after...>); |
| 268 | +}; |
| 269 | +template <FieldId> struct FieldNameBuilder; |
| 270 | +template <FieldId field> |
| 271 | + requires(!IsPath<field>()) |
| 272 | +struct FieldNameBuilder<field> { |
| 273 | + template <typename Proto> static auto Get() { |
| 274 | + return NameJoiner<FieldInfo<Proto, field>::name>(); |
| 275 | + } |
| 276 | +}; |
| 277 | +template <FieldId field> |
| 278 | + requires(IsPath<field>()) |
| 279 | +struct 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 | + |
| 292 | +struct T { |
| 293 | + template <typename FieldType, FieldType> struct FieldInfoImpl; |
| 294 | +}; |
| 295 | +void AddPathsToFieldMask() { |
| 296 | + FieldNameBuilder<Path<"message_field", "int32_field">>::Get<T>(); |
| 297 | +} |
| 298 | +template <> struct T::FieldInfoImpl<FieldNumber, FieldNumber{1}> { |
| 299 | + static basic_string_view name; |
| 300 | +}; |
| 301 | +template <> |
| 302 | +struct T::FieldInfoImpl<FieldName<1>, FieldName<1>{12}> |
| 303 | + : FieldInfoImpl<FieldNumber, FieldNumber{1}> {}; |
| 304 | +template <> struct T::FieldInfoImpl<FieldNumber, FieldNumber{10}> { |
| 305 | + static basic_string_view name; |
| 306 | +}; |
| 307 | +template <> |
| 308 | +struct T::FieldInfoImpl<FieldName<3>, FieldName<3>{11}> |
| 309 | + : FieldInfoImpl<FieldNumber, FieldNumber{10}> {}; |
0 commit comments