Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-14 09:10:19

0001 // Protocol Buffers - Google's data interchange format
0002 // Copyright 2008 Google Inc.  All rights reserved.
0003 //
0004 // Use of this source code is governed by a BSD-style
0005 // license that can be found in the LICENSE file or at
0006 // https://developers.google.com/open-source/licenses/bsd
0007 
0008 // This file contains declarations needed in generated headers for messages
0009 // that use tail-call table parsing. Everything in this file is for internal
0010 // use only.
0011 
0012 #ifndef GOOGLE_PROTOBUF_GENERATED_MESSAGE_TCTABLE_DECL_H__
0013 #define GOOGLE_PROTOBUF_GENERATED_MESSAGE_TCTABLE_DECL_H__
0014 
0015 #include <array>
0016 #include <atomic>
0017 #include <cstddef>
0018 #include <cstdint>
0019 #include <type_traits>
0020 
0021 #include "absl/log/absl_check.h"
0022 #include "absl/types/span.h"
0023 #include "google/protobuf/arena.h"
0024 #include "google/protobuf/message_lite.h"
0025 #include "google/protobuf/parse_context.h"
0026 #include "google/protobuf/port.h"
0027 #include "google/protobuf/wire_format_lite.h"
0028 
0029 // Must come last:
0030 #include "google/protobuf/port_def.inc"
0031 
0032 namespace google {
0033 namespace protobuf {
0034 namespace internal {
0035 
0036 // Additional information about this field:
0037 struct TcFieldData {
0038   constexpr TcFieldData() : data(0) {}
0039   explicit constexpr TcFieldData(uint64_t data) : data(data) {}
0040 
0041   // Fast table entry constructor:
0042   constexpr TcFieldData(uint16_t coded_tag, uint8_t hasbit_idx, uint8_t aux_idx,
0043                         uint16_t offset)
0044       : data(uint64_t{offset} << 48 |      //
0045              uint64_t{aux_idx} << 24 |     //
0046              uint64_t{hasbit_idx} << 16 |  //
0047              uint64_t{coded_tag}) {}
0048 
0049   // Constructor to create an explicit 'uninitialized' instance.
0050   // This constructor can be used to pass an uninitialized `data` value to a
0051   // table driven parser function that does not use `data`. The purpose of this
0052   // is that it allows the compiler to reallocate and re-purpose the register
0053   // that is currently holding its value for other data. This reduces register
0054   // allocations inside the highly optimized varint parsing functions.
0055   //
0056   // Applications not using `data` use the `PROTOBUF_TC_PARAM_NO_DATA_DECL`
0057   // macro to declare the standard input arguments with no name for the `data`
0058   // argument. Callers then use the `PROTOBUF_TC_PARAM_NO_DATA_PASS` macro.
0059   //
0060   // Example:
0061   //   if (ptr == nullptr) {
0062   //      PROTOBUF_MUSTTAIL return Error(PROTOBUF_TC_PARAM_NO_DATA_PASS);
0063   //   }
0064   struct DefaultInit {};
0065   TcFieldData(DefaultInit) {}  // NOLINT(google-explicit-constructor)
0066 
0067   // Fields used in fast table parsing:
0068   //
0069   //     Bit:
0070   //     +-----------+-------------------+
0071   //     |63    ..     32|31     ..     0|
0072   //     +---------------+---------------+
0073   //     :   .   :   .   :   . 16|=======| [16] coded_tag()
0074   //     :   .   :   .   : 24|===|   .   : [ 8] hasbit_idx()
0075   //     :   .   :   . 32|===|   :   .   : [ 8] aux_idx()
0076   //     :   . 48:---.---:   .   :   .   : [16] (unused)
0077   //     |=======|   .   :   .   :   .   : [16] offset()
0078   //     +-----------+-------------------+
0079   //     |63    ..     32|31     ..     0|
0080   //     +---------------+---------------+
0081 
0082   template <typename TagType = uint16_t>
0083   TagType coded_tag() const {
0084     return static_cast<TagType>(data);
0085   }
0086   uint8_t hasbit_idx() const { return static_cast<uint8_t>(data >> 16); }
0087   uint8_t aux_idx() const { return static_cast<uint8_t>(data >> 24); }
0088   uint16_t offset() const { return static_cast<uint16_t>(data >> 48); }
0089 
0090   // Constructor for special entries that do not represent a field.
0091   //  - End group: `nonfield_info` is the decoded tag.
0092   constexpr TcFieldData(uint16_t coded_tag, uint16_t nonfield_info)
0093       : data(uint64_t{nonfield_info} << 16 |  //
0094              uint64_t{coded_tag}) {}
0095 
0096   // Fields used in non-field entries
0097   //
0098   //     Bit:
0099   //     +-----------+-------------------+
0100   //     |63    ..     32|31     ..     0|
0101   //     +---------------+---------------+
0102   //     :   .   :   .   :   . 16|=======| [16] coded_tag()
0103   //     :   .   :   . 32|=======|   .   : [16] decoded_tag()
0104   //     :---.---:---.---:   .   :   .   : [32] (unused)
0105   //     +-----------+-------------------+
0106   //     |63    ..     32|31     ..     0|
0107   //     +---------------+---------------+
0108 
0109   uint16_t decoded_tag() const { return static_cast<uint16_t>(data >> 16); }
0110 
0111   // Fields used in mini table parsing:
0112   //
0113   //     Bit:
0114   //     +-----------+-------------------+
0115   //     |63    ..     32|31     ..     0|
0116   //     +---------------+---------------+
0117   //     :   .   :   .   |===============| [32] tag() (decoded)
0118   //     |===============|   .   :   .   : [32] entry_offset()
0119   //     +-----------+-------------------+
0120   //     |63    ..     32|31     ..     0|
0121   //     +---------------+---------------+
0122 
0123   uint32_t tag() const { return static_cast<uint32_t>(data); }
0124   uint32_t entry_offset() const { return static_cast<uint32_t>(data >> 32); }
0125 
0126   union {
0127     uint64_t data;
0128   };
0129 };
0130 
0131 struct TcParseTableBase;
0132 
0133 // TailCallParseFunc is the function pointer type used in the tailcall table.
0134 using TailCallParseFunc = PROTOBUF_CC const char* (*)(PROTOBUF_TC_PARAM_DECL);
0135 
0136 namespace field_layout {
0137 struct Offset {
0138   uint32_t off;
0139 };
0140 }  // namespace field_layout
0141 
0142 #if defined(_MSC_VER) && !defined(_WIN64)
0143 #pragma warning(push)
0144 // TcParseTableBase is intentionally overaligned on 32 bit targets.
0145 #pragma warning(disable : 4324)
0146 #endif
0147 
0148 struct FieldAuxDefaultMessage {};
0149 struct FieldAuxEnumData {};
0150 
0151 // Small type card used by mini parse to handle map entries.
0152 // Map key/values are very limited, so we can encode the whole thing in a single
0153 // byte.
0154 class MapTypeCard {
0155  public:
0156   MapTypeCard() = default;
0157   constexpr MapTypeCard(int number, WireFormatLite::WireType wiretype,
0158                         bool is_signed, bool is_zigzag, bool is_utf8)
0159       : tag_(static_cast<uint8_t>(WireFormatLite::MakeTag(number, wiretype))),
0160         is_signed_(is_signed),
0161         is_zigzag_(is_zigzag),
0162         is_utf8_(is_utf8) {}
0163 
0164   uint8_t tag() const { return tag_; }
0165 
0166   WireFormatLite::WireType wiretype() const {
0167     return static_cast<WireFormatLite::WireType>(tag_ & 7);
0168   }
0169 
0170   bool is_signed() const { return is_signed_; }
0171 
0172   bool is_zigzag() const {
0173     ABSL_DCHECK(wiretype() == WireFormatLite::WIRETYPE_VARINT);
0174     return is_zigzag_;
0175   }
0176   bool is_utf8() const {
0177     ABSL_DCHECK(wiretype() == WireFormatLite::WIRETYPE_LENGTH_DELIMITED);
0178     return is_utf8_;
0179   }
0180 
0181  private:
0182   uint8_t tag_;
0183   bool is_signed_ : 1;
0184   bool is_zigzag_ : 1;
0185   bool is_utf8_ : 1;
0186 };
0187 
0188 // Make the map entry type card for a specified field type.
0189 constexpr MapTypeCard MakeMapTypeCard(int number,
0190                                       WireFormatLite::FieldType type) {
0191   switch (type) {
0192     case WireFormatLite::TYPE_FLOAT:
0193       return {number, WireFormatLite::WIRETYPE_FIXED32, true, false, false};
0194     case WireFormatLite::TYPE_FIXED32:
0195       return {number, WireFormatLite::WIRETYPE_FIXED32, false, false, false};
0196     case WireFormatLite::TYPE_SFIXED32:
0197       return {number, WireFormatLite::WIRETYPE_FIXED32, true, false, false};
0198 
0199     case WireFormatLite::TYPE_DOUBLE:
0200       return {number, WireFormatLite::WIRETYPE_FIXED64, true, false, false};
0201     case WireFormatLite::TYPE_FIXED64:
0202       return {number, WireFormatLite::WIRETYPE_FIXED64, false, false, false};
0203     case WireFormatLite::TYPE_SFIXED64:
0204       return {number, WireFormatLite::WIRETYPE_FIXED64, true, false, false};
0205 
0206     case WireFormatLite::TYPE_BOOL:
0207       return {number, WireFormatLite::WIRETYPE_VARINT, false, false, false};
0208 
0209     case WireFormatLite::TYPE_ENUM:
0210       // Enum validation is handled via `value_is_validated_enum` below.
0211       return {number, WireFormatLite::WIRETYPE_VARINT, true, false, false};
0212     case WireFormatLite::TYPE_INT32:
0213       return {number, WireFormatLite::WIRETYPE_VARINT, true, false, false};
0214     case WireFormatLite::TYPE_UINT32:
0215       return {number, WireFormatLite::WIRETYPE_VARINT, false, false, false};
0216 
0217     case WireFormatLite::TYPE_INT64:
0218       return {number, WireFormatLite::WIRETYPE_VARINT, true, false, false};
0219     case WireFormatLite::TYPE_UINT64:
0220       return {number, WireFormatLite::WIRETYPE_VARINT, false, false, false};
0221 
0222     case WireFormatLite::TYPE_SINT32:
0223       return {number, WireFormatLite::WIRETYPE_VARINT, true, true, false};
0224     case WireFormatLite::TYPE_SINT64:
0225       return {number, WireFormatLite::WIRETYPE_VARINT, true, true, false};
0226 
0227     case WireFormatLite::TYPE_STRING:
0228       return {number, WireFormatLite::WIRETYPE_LENGTH_DELIMITED, false, false,
0229               true};
0230     case WireFormatLite::TYPE_BYTES:
0231       return {number, WireFormatLite::WIRETYPE_LENGTH_DELIMITED, false, false,
0232               false};
0233 
0234     case WireFormatLite::TYPE_MESSAGE:
0235       return {number, WireFormatLite::WIRETYPE_LENGTH_DELIMITED, false, false,
0236               false};
0237 
0238     case WireFormatLite::TYPE_GROUP:
0239     default:
0240       Unreachable();
0241   }
0242 }
0243 
0244 // Aux entry for map fields.
0245 struct MapAuxInfo {
0246   MapTypeCard key_type_card;
0247   MapTypeCard value_type_card;
0248   // When off, we fall back to table->fallback to handle the parse. An example
0249   // of this is for DynamicMessage.
0250   uint8_t is_supported : 1;
0251   // Determines if we are using LITE or the full runtime. When using the full
0252   // runtime we have to synchronize with reflection before accessing the map.
0253   uint8_t use_lite : 1;
0254   // If true UTF8 errors cause the parsing to fail.
0255   uint8_t fail_on_utf8_failure : 1;
0256   // If true UTF8 errors are logged, but they are accepted.
0257   uint8_t log_debug_utf8_failure : 1;
0258   // If true the next aux contains the enum validator.
0259   uint8_t value_is_validated_enum : 1;
0260 };
0261 static_assert(sizeof(MapAuxInfo) <= 8, "");
0262 
0263 // Base class for message-level table with info for the tail-call parser.
0264 struct alignas(uint64_t) TcParseTableBase {
0265   // Common attributes for message layout:
0266   uint16_t has_bits_offset;
0267   uint16_t extension_offset;
0268   uint32_t max_field_number;
0269   uint8_t fast_idx_mask;
0270   // Testing one bit is cheaper than testing whether post_loop_handler is null,
0271   // and we expect it to be null most of the time so no reason to load the
0272   // pointer.
0273   uint8_t has_post_loop_handler : 1;
0274   uint16_t lookup_table_offset;
0275   uint32_t skipmap32;
0276   uint32_t field_entries_offset;
0277   uint16_t num_field_entries;
0278 
0279   uint16_t num_aux_entries;
0280   uint32_t aux_offset;
0281 
0282   const ClassData* class_data;
0283   using PostLoopHandler = const char* (*)(MessageLite* msg, const char* ptr,
0284                                           ParseContext* ctx);
0285   PostLoopHandler post_loop_handler;
0286 
0287   // Handler for fields which are not handled by table dispatch.
0288   TailCallParseFunc fallback;
0289 
0290   // A sub message's table to be prefetched.
0291 #ifdef PROTOBUF_PREFETCH_PARSE_TABLE
0292   const TcParseTableBase* to_prefetch;
0293 #endif  // PROTOBUF_PREFETCH_PARSE_TABLE
0294 
0295   // This constructor exactly follows the field layout, so it's technically
0296   // not necessary.  However, it makes it much much easier to add or re-arrange
0297   // fields, because it can be overloaded with an additional constructor,
0298   // temporarily allowing both old and new protocol buffer headers to be
0299   // compiled.
0300   constexpr TcParseTableBase(uint16_t has_bits_offset,
0301                              uint16_t extension_offset,
0302                              uint32_t max_field_number, uint8_t fast_idx_mask,
0303                              uint16_t lookup_table_offset, uint32_t skipmap32,
0304                              uint32_t field_entries_offset,
0305                              uint16_t num_field_entries,
0306                              uint16_t num_aux_entries, uint32_t aux_offset,
0307                              const ClassData* class_data,
0308                              PostLoopHandler post_loop_handler,
0309                              TailCallParseFunc fallback
0310 #ifdef PROTOBUF_PREFETCH_PARSE_TABLE
0311                              ,
0312                              const TcParseTableBase* to_prefetch
0313 #endif  // PROTOBUF_PREFETCH_PARSE_TABLE
0314                              )
0315       : has_bits_offset(has_bits_offset),
0316         extension_offset(extension_offset),
0317         max_field_number(max_field_number),
0318         fast_idx_mask(fast_idx_mask),
0319         has_post_loop_handler(post_loop_handler != nullptr),
0320         lookup_table_offset(lookup_table_offset),
0321         skipmap32(skipmap32),
0322         field_entries_offset(field_entries_offset),
0323         num_field_entries(num_field_entries),
0324         num_aux_entries(num_aux_entries),
0325         aux_offset(aux_offset),
0326         class_data(class_data),
0327         post_loop_handler(post_loop_handler),
0328         fallback(fallback)
0329 #ifdef PROTOBUF_PREFETCH_PARSE_TABLE
0330         ,
0331         to_prefetch(to_prefetch)
0332 #endif  // PROTOBUF_PREFETCH_PARSE_TABLE
0333   {
0334   }
0335 
0336   // Table entry for fast-path tailcall dispatch handling.
0337   struct FastFieldEntry {
0338     // Target function for dispatch:
0339     mutable std::atomic<TailCallParseFunc> target_atomic;
0340 
0341     // Field data used during parse:
0342     TcFieldData bits;
0343 
0344     // Default initializes this instance with undefined values.
0345     FastFieldEntry() = default;
0346 
0347     // Constant initializes this instance
0348     constexpr FastFieldEntry(TailCallParseFunc func, TcFieldData bits)
0349         : target_atomic(func), bits(bits) {}
0350 
0351     // FastFieldEntry is copy-able and assignable, which is intended
0352     // mainly for testing and debugging purposes.
0353     FastFieldEntry(const FastFieldEntry& rhs) noexcept
0354         : FastFieldEntry(rhs.target(), rhs.bits) {}
0355     FastFieldEntry& operator=(const FastFieldEntry& rhs) noexcept {
0356       SetTarget(rhs.target());
0357       bits = rhs.bits;
0358       return *this;
0359     }
0360 
0361     // Protocol buffer code should use these relaxed accessors.
0362     TailCallParseFunc target() const {
0363       return target_atomic.load(std::memory_order_relaxed);
0364     }
0365     void SetTarget(TailCallParseFunc func) const {
0366       return target_atomic.store(func, std::memory_order_relaxed);
0367     }
0368   };
0369   // There is always at least one table entry.
0370   const FastFieldEntry* fast_entry(size_t idx) const {
0371     return reinterpret_cast<const FastFieldEntry*>(this + 1) + idx;
0372   }
0373   FastFieldEntry* fast_entry(size_t idx) {
0374     return reinterpret_cast<FastFieldEntry*>(this + 1) + idx;
0375   }
0376 
0377   static uint32_t RecodeTagForFastParsing(uint32_t tag) {
0378     ABSL_DCHECK_LE(tag, 0x3FFFu);
0379     // Construct the varint-coded tag. If it is more than 7 bits, we need to
0380     // shift the high bits and add a continue bit.
0381     uint32_t hibits = tag & 0xFFFFFF80;
0382     if (hibits != 0) {
0383       // hi = tag & ~0x7F
0384       // lo = tag & 0x7F
0385       // This shifts hi to the left by 1 to the next byte and sets the
0386       // continuation bit.
0387       tag = tag + hibits + 0x80;
0388     }
0389     return tag;
0390   }
0391 
0392   static constexpr size_t kMaxFastFields = 32;
0393   static uint32_t TagToIdx(uint32_t tag, uint32_t fast_table_size) {
0394     // The fast table size must be a power of two.
0395     ABSL_DCHECK_EQ((fast_table_size & (fast_table_size - 1)), uint32_t{0});
0396 
0397     // The field index is determined by the low bits of the field number, where
0398     // the table size determines the width of the mask. The largest table
0399     // supported is 32 entries. The parse loop uses these bits directly, so that
0400     // the dispatch does not require arithmetic:
0401     //        byte 0   byte 1
0402     //   tag: 1nnnnttt 0nnnnnnn
0403     //        ^^^^^
0404     //         idx (table_size_log2=5)
0405     // This means that any field number that does not fit in the lower 4 bits
0406     // will always have the top bit of its table index asserted.
0407     uint32_t idx_mask = fast_table_size - 1;
0408     return (tag >> 3) & idx_mask;
0409   }
0410 
0411   // Returns a begin iterator (pointer) to the start of the field lookup table.
0412   const uint16_t* field_lookup_begin() const {
0413     return reinterpret_cast<const uint16_t*>(reinterpret_cast<uintptr_t>(this) +
0414                                              lookup_table_offset);
0415   }
0416   uint16_t* field_lookup_begin() {
0417     return reinterpret_cast<uint16_t*>(reinterpret_cast<uintptr_t>(this) +
0418                                        lookup_table_offset);
0419   }
0420 
0421   // Field entry for all fields.
0422   struct FieldEntry {
0423     uint32_t offset;     // offset in the message object
0424     int32_t has_idx;     // has-bit index, relative to the message object
0425     uint16_t aux_idx;    // index for `field_aux`.
0426     uint16_t type_card;  // `FieldType` and `Cardinality` (see _impl.h)
0427 
0428     static constexpr uint16_t kNoAuxIdx = 0xFFFF;
0429   };
0430 
0431   // Returns a begin iterator (pointer) to the start of the field entries array.
0432   const FieldEntry* field_entries_begin() const {
0433     return reinterpret_cast<const FieldEntry*>(
0434         reinterpret_cast<uintptr_t>(this) + field_entries_offset);
0435   }
0436   absl::Span<const FieldEntry> field_entries() const {
0437     return {field_entries_begin(), num_field_entries};
0438   }
0439   FieldEntry* field_entries_begin() {
0440     return reinterpret_cast<FieldEntry*>(reinterpret_cast<uintptr_t>(this) +
0441                                          field_entries_offset);
0442   }
0443 
0444   // Auxiliary entries for field types that need extra information.
0445   union FieldAux {
0446     constexpr FieldAux() : message_default_p(nullptr) {}
0447     constexpr FieldAux(FieldAuxEnumData, const uint32_t* enum_data)
0448         : enum_data(enum_data) {}
0449     constexpr FieldAux(field_layout::Offset off) : offset(off.off) {}
0450     constexpr FieldAux(int32_t range_first, int32_t range_last)
0451         : enum_range{range_first, range_last} {}
0452     constexpr FieldAux(const MessageLite* msg) : message_default_p(msg) {}
0453     constexpr FieldAux(FieldAuxDefaultMessage, const void* msg)
0454         : message_default_p(msg) {}
0455     constexpr FieldAux(const TcParseTableBase* table) : table(table) {}
0456     constexpr FieldAux(MapAuxInfo map_info) : map_info(map_info) {}
0457     constexpr FieldAux(LazyEagerVerifyFnType verify_func)
0458         : verify_func(verify_func) {}
0459     struct {
0460       int32_t first;  // the first label in the range (inclusive)
0461       int32_t last;   // the last label in the range (inclusize)
0462     } enum_range;
0463     uint32_t offset;
0464     const void* message_default_p;
0465     const uint32_t* enum_data;
0466     const TcParseTableBase* table;
0467     MapAuxInfo map_info;
0468     LazyEagerVerifyFnType verify_func;
0469 
0470     const MessageLite* message_default() const {
0471       return static_cast<const MessageLite*>(message_default_p);
0472     }
0473     const MessageLite* message_default_weak() const {
0474       return *static_cast<const MessageLite* const*>(message_default_p);
0475     }
0476   };
0477   const FieldAux* field_aux(uint32_t idx) const {
0478     return reinterpret_cast<const FieldAux*>(reinterpret_cast<uintptr_t>(this) +
0479                                              aux_offset) +
0480            idx;
0481   }
0482   FieldAux* field_aux(uint32_t idx) {
0483     return reinterpret_cast<FieldAux*>(reinterpret_cast<uintptr_t>(this) +
0484                                        aux_offset) +
0485            idx;
0486   }
0487   const FieldAux* field_aux(const FieldEntry* entry) const {
0488     return field_aux(entry->aux_idx);
0489   }
0490 
0491   // Field name data
0492   const char* name_data() const {
0493     return reinterpret_cast<const char*>(reinterpret_cast<uintptr_t>(this) +
0494                                          aux_offset +
0495                                          num_aux_entries * sizeof(FieldAux));
0496   }
0497   char* name_data() {
0498     return reinterpret_cast<char*>(reinterpret_cast<uintptr_t>(this) +
0499                                    aux_offset +
0500                                    num_aux_entries * sizeof(FieldAux));
0501   }
0502 
0503   const MessageLite* default_instance() const { return class_data->prototype; }
0504 };
0505 
0506 #if defined(_MSC_VER) && !defined(_WIN64)
0507 #pragma warning(pop)
0508 #endif
0509 
0510 static_assert(sizeof(TcParseTableBase::FastFieldEntry) <= 16,
0511               "Fast field entry is too big.");
0512 static_assert(sizeof(TcParseTableBase::FieldEntry) <= 16,
0513               "Field entry is too big.");
0514 
0515 template <size_t kFastTableSizeLog2, size_t kNumFieldEntries = 0,
0516           size_t kNumFieldAux = 0, size_t kNameTableSize = 0,
0517           size_t kFieldLookupSize = 2>
0518 struct TcParseTable {
0519   TcParseTableBase header;
0520 
0521   // Entries for each field.
0522   //
0523   // Fields are indexed by the lowest bits of their field number. The field
0524   // number is masked to fit inside the table. Note that the parsing logic
0525   // generally calls `TailCallParseTableBase::fast_entry()` instead of accessing
0526   // this field directly.
0527   std::array<TcParseTableBase::FastFieldEntry, (1 << kFastTableSizeLog2)>
0528       fast_entries;
0529 
0530   // Just big enough to find all the field entries.
0531   std::array<uint16_t, kFieldLookupSize> field_lookup_table;
0532   // Entries for all fields:
0533   std::array<TcParseTableBase::FieldEntry, kNumFieldEntries> field_entries;
0534   std::array<TcParseTableBase::FieldAux, kNumFieldAux> aux_entries;
0535   std::array<char, kNameTableSize == 0 ? 1 : kNameTableSize> field_names;
0536 };
0537 
0538 // Partial specialization: if there are no aux entries, there will be no array.
0539 // In C++, arrays cannot have length 0, but (C++11) std::array<T, 0> is valid.
0540 // However, different implementations have different sizeof(std::array<T, 0>).
0541 // Skipping the member makes offset computations portable.
0542 template <size_t kFastTableSizeLog2, size_t kNumFieldEntries,
0543           size_t kNameTableSize, size_t kFieldLookupSize>
0544 struct TcParseTable<kFastTableSizeLog2, kNumFieldEntries, 0, kNameTableSize,
0545                     kFieldLookupSize> {
0546   TcParseTableBase header;
0547   std::array<TcParseTableBase::FastFieldEntry, (1 << kFastTableSizeLog2)>
0548       fast_entries;
0549   std::array<uint16_t, kFieldLookupSize> field_lookup_table;
0550   std::array<TcParseTableBase::FieldEntry, kNumFieldEntries> field_entries;
0551   std::array<char, kNameTableSize == 0 ? 1 : kNameTableSize> field_names;
0552 };
0553 
0554 // Partial specialization: if there are no fields at all, then we can save space
0555 // by skipping the field numbers and entries.
0556 template <size_t kNameTableSize, size_t kFieldLookupSize>
0557 struct TcParseTable<0, 0, 0, kNameTableSize, kFieldLookupSize> {
0558   TcParseTableBase header;
0559   // N.B.: the fast entries are sized by log2, so 2**0 fields = 1 entry.
0560   // The fast parsing loop will always use this entry, so it must be present.
0561   std::array<TcParseTableBase::FastFieldEntry, 1> fast_entries;
0562   std::array<uint16_t, kFieldLookupSize> field_lookup_table;
0563   std::array<char, kNameTableSize == 0 ? 1 : kNameTableSize> field_names;
0564 };
0565 
0566 static_assert(std::is_standard_layout<TcParseTable<1>>::value,
0567               "TcParseTable must be standard layout.");
0568 
0569 static_assert(offsetof(TcParseTable<1>, fast_entries) ==
0570                   sizeof(TcParseTableBase),
0571               "Table entries must be laid out after TcParseTableBase.");
0572 
0573 template <typename T,
0574           PROTOBUF_CC const char* (*func)(T*, const char*, ParseContext*)>
0575 PROTOBUF_CC const char* StubParseImpl(PROTOBUF_TC_PARAM_DECL) {
0576   return func(static_cast<T*>(msg), ptr, ctx);
0577 }
0578 
0579 template <typename T,
0580           PROTOBUF_CC const char* (*func)(T*, const char*, ParseContext*)>
0581 constexpr TcParseTable<0> CreateStubTcParseTable(
0582     const ClassData* class_data,
0583     TcParseTableBase::PostLoopHandler post_loop_handler = nullptr) {
0584   return {
0585       {
0586           0,                  // has_bits_offset
0587           0,                  // extension_offset
0588           0,                  // max_field_number
0589           0,                  // fast_idx_mask
0590           0,                  // lookup_table_offset
0591           0,                  // skipmap32
0592           0,                  // field_entries_offset
0593           0,                  // num_field_entries
0594           0,                  // num_aux_entries
0595           0,                  // aux_offset
0596           class_data,         //
0597           post_loop_handler,  //
0598           nullptr,            // fallback
0599 #ifdef PROTOBUF_PREFETCH_PARSE_TABLE
0600           nullptr,  // to_prefetch
0601 #endif              // PROTOBUF_PREFETCH_PARSE_TABLE
0602       },
0603       {{{StubParseImpl<T, func>, {}}}},
0604   };
0605 }
0606 
0607 }  // namespace internal
0608 }  // namespace protobuf
0609 }  // namespace google
0610 
0611 #include "google/protobuf/port_undef.inc"
0612 
0613 #endif  // GOOGLE_PROTOBUF_GENERATED_MESSAGE_TCTABLE_DECL_H__