Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-31 10:12:20

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