Go to the documentation of this file.
37 #include <google/protobuf/compiler/cpp/cpp_helpers.h>
38 #include <google/protobuf/wire_format.h>
50 std::vector<const FieldDescriptor*> GetOrderedFields(
52 std::vector<const FieldDescriptor*> ordered_fields;
55 ordered_fields.push_back(
field);
58 std::sort(ordered_fields.begin(), ordered_fields.end(),
60 return a->number() < b->number();
62 return ordered_fields;
70 if (field_number < 16)
return 1;
72 <<
"coded tag for " << field_number <<
" too big for uint16_t";
76 const char* CodedTagType(
int tag_size) {
77 return tag_size == 1 ?
"uint8_t" :
"uint16_t";
81 return CodedTagType(TagSize(
field->number()));
86 "::internal::TcParser::");
91 if (
field->message_type()->field_count() == 0 ||
98 (
field->is_repeated() ?
"Repeated" :
"Singular"),
101 ", ", TagType(
field),
">");
104 return StrCat(
"PROTOBUF_TC_PARSE_",
105 (
field->is_repeated() ?
"REPEATED" :
"SINGULAR"),
106 TagSize(
field->number()),
"(",
117 const std::vector<int>& has_bit_indices,
119 std::vector<const FieldDescriptor*> ordered_fields =
127 : ordered_fields.size() >= 8 ? 4
128 : ordered_fields.size() >= 4 ? 3
129 : ordered_fields.size() >= 2 ? 2
137 for (
const auto*
field : ordered_fields) {
143 if (
field->is_map())
continue;
144 if (
field->real_containing_oneof())
continue;
145 if (
field->options().weak())
continue;
155 if (
tag >= 1 << 14) {
157 }
else if (
tag >= 1 << 7) {
158 tag = ((
tag << 1) & 0x7F00) | 0x80 | (
tag & 0x7F);
178 hasbit_idx = has_bit_indices[
field->index()];
183 if (hasbit_idx >= 32)
continue;
193 switch (
field->type()) {
216 field->default_value_string().empty() &&
246 const std::vector<int>& has_bit_indices,
247 const std::vector<int>& inlined_string_indices,
const Options&
options,
249 const std::map<std::string, std::string>& vars)
251 scc_analyzer_(scc_analyzer),
254 inlined_string_indices_(inlined_string_indices),
255 num_hasbits_(max_has_bit_index) {
258 has_bit_indices, scc_analyzer));
268 auto declare_function = [&
format](
const char*
name,
270 if (!guard.empty()) {
272 format(
"#if $1$\n", guard);
275 format(
"static const char* $1$(PROTOBUF_TC_PARAM_DECL);\n",
name);
276 if (!guard.empty()) {
278 format(
"#endif // $1$\n", guard);
284 format(
"#ifdef PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n");
287 format(
"// The Tct_* functions are internal to the protobuf runtime:\n");
289 declare_function(
"Tct_ParseS1",
"PROTOBUF_TC_STATIC_PARSE_SINGULAR1");
290 declare_function(
"Tct_ParseS2",
"PROTOBUF_TC_STATIC_PARSE_SINGULAR2");
291 declare_function(
"Tct_ParseR1",
"PROTOBUF_TC_STATIC_PARSE_REPEATED1");
292 declare_function(
"Tct_ParseR2",
"PROTOBUF_TC_STATIC_PARSE_REPEATED2");
298 declare_function(
"Tct_ParseFallback",
"");
309 "const char* _InternalParse(const char* ptr, "
310 "::$proto_ns$::internal::ParseContext* ctx) final;\n");
315 bool need_parse_function =
true;
318 need_parse_function =
false;
320 "const char* $classname$::_InternalParse(const char* ptr,\n"
321 " ::$proto_ns$::internal::ParseContext* ctx) {\n"
322 "$annotate_deserialize$"
323 " return _extensions_.ParseMessageSet(ptr, \n"
324 " internal_default_instance(), &_internal_metadata_, ctx);\n"
328 if (need_parse_function) {
334 format(
"#ifdef PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n\n");
336 if (need_parse_function) {
344 if (need_parse_function) {
345 format(
"\n#else // PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n\n");
348 format(
"\n#endif // PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n");
364 "const char* $classname$::_InternalParse(\n"
365 " const char* ptr, ::$proto_ns$::internal::ParseContext* ctx) {\n"
366 "$annotate_deserialize$"
367 " ptr = ::$proto_ns$::internal::TcParser::ParseLoop(\n"
368 " this, ptr, ctx, &_table_.header);\n");
378 "const char* $classname$::Tct_ParseFallback(PROTOBUF_TC_PARAM_DECL) {\n"
379 "#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) return nullptr\n");
381 format(
"auto* typed_msg = static_cast<$classname$*>(msg);\n");
385 format(
"typed_msg->_has_bits_[0] = hasbits;\n");
388 format.Set(
"msg",
"typed_msg->");
389 format.Set(
"this",
"typed_msg");
390 format.Set(
"has_bits",
"typed_msg->_has_bits_");
391 format.Set(
"next_tag",
"goto next_tag");
412 }
const kTagLayouts[] = {
417 for (
const auto&
layout : kTagLayouts) {
420 "#if PROTOBUF_TC_STATIC_PARSE_SINGULAR$1$\n"
421 "const char* $classname$::Tct_ParseS$1$(PROTOBUF_TC_PARAM_DECL) {\n"
422 " if (PROTOBUF_PREDICT_FALSE(data.coded_tag<$2$>() != 0))\n"
423 " PROTOBUF_MUSTTAIL "
424 "return table->fallback(PROTOBUF_TC_PARAM_PASS);\n"
426 " hasbits |= (uint64_t{1} << data.hasbit_idx());\n"
427 " ::$proto_ns$::internal::TcParser::SyncHasbits"
428 "(msg, hasbits, table);\n"
429 " auto& field = ::$proto_ns$::internal::TcParser::"
430 "RefAt<$classtype$*>(msg, data.offset());\n"
431 " if (field == nullptr)\n"
432 " field = CreateMaybeMessage<$classtype$>(ctx->data().arena);\n"
433 " return ctx->ParseMessage(field, ptr);\n"
435 "#endif // PROTOBUF_TC_STATIC_PARSE_SINGULAR$1$\n",
439 for (
const auto&
layout : kTagLayouts) {
442 "#if PROTOBUF_TC_STATIC_PARSE_REPEATED$1$\n"
443 "const char* $classname$::Tct_ParseR$1$(PROTOBUF_TC_PARAM_DECL) {\n"
444 " if (PROTOBUF_PREDICT_FALSE(data.coded_tag<$2$>() != 0)) {\n"
445 " PROTOBUF_MUSTTAIL "
446 "return table->fallback(PROTOBUF_TC_PARAM_PASS);\n"
449 " auto& field = ::$proto_ns$::internal::TcParser::RefAt<"
450 "::$proto_ns$::RepeatedPtrField<$classname$>>(msg, data.offset());\n"
451 " ::$proto_ns$::internal::TcParser::SyncHasbits"
452 "(msg, hasbits, table);\n"
453 " ptr = ctx->ParseMessage(field.Add(), ptr);\n"
456 "#endif // PROTOBUF_TC_STATIC_PARSE_REPEATED$1$\n",
468 format(
"#ifdef PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n");
472 "static const ::$proto_ns$::internal::TcParseTable<$1$>\n"
477 format(
"#endif // PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n");
488 format(
"#ifdef PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n");
492 format(
"#endif // PROTOBUF_TAIL_CALL_TABLE_PARSER_ENABLED\n");
498 "const char* $classname$::_InternalParse(const char* ptr, "
499 "::$proto_ns$::internal::ParseContext* ctx) {\n"
500 "$annotate_deserialize$"
501 "#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure\n");
504 format.Set(
"this",
"this");
505 int hasbits_size = 0;
510 if (hasbits_size != 1) hasbits_size = 0;
512 format(
"_Internal::HasBits has_bits{};\n");
513 format.Set(
"has_bits",
"has_bits");
515 format.Set(
"has_bits",
"_has_bits_");
517 format.Set(
"next_tag",
"continue");
518 format(
"while (!ctx->Done(&ptr)) {\n");
528 format(
"message_done:\n");
529 if (hasbits_size)
format(
" _has_bits_.Or(has_bits);\n");
535 " goto message_done;\n"
547 fallback = TcParserName(
options_) +
"GenericFallback";
562 "const ::$proto_ns$::internal::TcParseTable<$1$>\n"
563 " $classname$::_table_ = {\n",
566 auto table_scope =
format.ScopedIndent();
569 auto header_scope =
format.ScopedIndent();
571 format(
"PROTOBUF_FIELD_OFFSET($classname$, _has_bits_),\n");
573 format(
"0, // no _has_bits_\n");
577 "PROTOBUF_FIELD_OFFSET($classname$, _extensions_),\n"
578 "$1$, $2$, // extension_range_{low,high}\n",
582 format(
"0, 0, 0, // no _extensions_\n");
585 "$1$, 0, $2$, // fast_idx_mask, reserved, num_fields\n"
594 auto fast_scope =
format.ScopedIndent();
605 if (info.field !=
nullptr) {
608 format(
"{$1$, ", info.func_name.empty() ? fallback : info.func_name);
609 if (info.bits.data) {
613 "static_cast<uint16_t>(PROTOBUF_FIELD_OFFSET($classname$, $3$_))}",
614 info.bits.coded_tag(), info.bits.hasbit_idx(),
FieldName(info.field));
628 field->default_value_string().empty()
630 "::internal::GetEmptyStringAlreadyInited()"
634 "if (arena != nullptr) {\n"
635 " ptr = ctx->ReadArenaString(ptr, &$msg$$name$_, arena");
641 ", $msg$_internal_$name$_donated()"
642 ", &$msg$_inlined_string_donated_[$1$]"
644 inlined_string_index / 32,
652 " ptr = ::$proto_ns$::internal::InlineGreedyStringParser("
653 "$msg$$name$_.MutableNoArenaNoDefault(&$1$), ptr, ctx);\n"
655 "const std::string* str = &$msg$$name$_.Get(); (void)str;\n",
665 ctype =
field->options().ctype();
670 field->default_value_string().empty() &&
677 parser_name =
"GreedyStringParser";
680 parser_name =
"CordParser";
683 parser_name =
"StringPieceParser";
687 "auto str = $msg$$1$$2$_$name$();\n"
688 "ptr = ::$proto_ns$::internal::Inline$3$(str, ptr, ctx);\n",
689 HasInternalAccessors(ctype) ?
"_internal_" :
"",
690 field->is_repeated() && !
field->is_packable() ?
"add" :
"mutable",
693 if (!check_utf8)
return;
699 format(
"#ifndef NDEBUG\n");
706 field_name =
"nullptr";
708 field_name =
StrCat(
"\"",
field->full_name(),
"\"");
710 format(
"::$proto_ns$::internal::VerifyUTF8(str, $1$)", field_name);
717 "#endif // !NDEBUG\n");
727 if (
field->is_packable()) {
733 "::$proto_ns$::internal::Packed$1$Parser<$unknown_fields_type$>("
734 "$msg$_internal_mutable_$name$(), ptr, ctx, $2$_IsValid, "
735 "&$msg$_internal_metadata_, $3$);\n",
739 "ptr = ::$proto_ns$::internal::Packed$1$Parser("
740 "$msg$_internal_mutable_$name$(), ptr, ctx);\n",
753 if (
field->is_map()) {
755 field->message_type()->FindFieldByName(
"value");
761 "::$proto_ns$::internal::InitEnumParseWrapper<"
762 "$unknown_fields_type$>(&$msg$$name$_, $1$_IsValid, "
763 "$2$, &$msg$_internal_metadata_);\n"
764 "ptr = ctx->ParseMessage(&object, ptr);\n",
768 format(
"ptr = ctx->ParseMessage(&$msg$$name$_, ptr);\n");
771 if (
field->real_containing_oneof()) {
773 "if (!$msg$_internal_has_$name$()) {\n"
774 " $msg$clear_$1$();\n"
775 " $msg$$1$_.$name$_ = ::$proto_ns$::Arena::CreateMessage<\n"
776 " ::$proto_ns$::internal::LazyField>("
777 "$msg$GetArenaForAllocation());\n"
778 " $msg$set_has_$name$();\n"
780 "auto* lazy_field = $msg$$1$_.$name$_;\n",
781 field->containing_oneof()->name());
784 "_Internal::set_has_$name$(&$has_bits$);\n"
785 "auto* lazy_field = &$msg$$name$_;\n");
787 format(
"auto* lazy_field = &$msg$$name$_;\n");
790 "::$proto_ns$::internal::LazyFieldParseHelper<\n"
791 " ::$proto_ns$::internal::LazyField> parse_helper(\n"
792 " $1$::default_instance(),\n"
793 " $msg$GetArenaForAllocation(), lazy_field);\n"
794 "ptr = ctx->ParseMessage(&parse_helper, ptr);\n",
797 if (!
field->is_repeated()) {
799 "ptr = ctx->ParseMessage(_Internal::mutable_$name$($this$), "
803 "ptr = ctx->ParseMessage($msg$$name$_.AddWeak("
804 "reinterpret_cast<const ::$proto_ns$::MessageLite*>($1$ptr_)"
811 " auto* default_ = &reinterpret_cast<const Message&>($1$);\n"
812 " ptr = ctx->ParseMessage($msg$_weak_field_map_.MutableMessage("
813 "$2$, default_), ptr);\n"
819 "ptr = ctx->ParseMessage($msg$_internal_$mutable_field$(), "
825 GOOGLE_LOG(
FATAL) <<
"Illegal combination for length delimited wiretype "
826 <<
" filed type is " <<
field->type();
833 constexpr
int kMaxTwoByteFieldNumber = 16 * 128;
834 return descriptor->number() < kMaxTwoByteFieldNumber &&
847 if (
field->is_repeated()) {
863 "$uint64$ val = ::$proto_ns$::internal::ReadVarint64(&ptr);\n"
866 format(
"if (PROTOBUF_PREDICT_TRUE($enum_type$_IsValid(val))) {\n");
869 format(
"$msg$_internal_$put_field$(static_cast<$enum_type$>(val));\n");
874 " ::$proto_ns$::internal::WriteVarint("
875 "$1$, val, $msg$mutable_unknown_fields());\n"
890 if (
field->is_repeated() ||
field->real_containing_oneof()) {
892 "$msg$_internal_$put_field$("
893 "::$proto_ns$::internal::ReadVarint$1$$2$(&ptr));\n"
898 format(
"_Internal::set_has_$name$(&$has_bits$);\n");
901 "$msg$$name$_ = ::$proto_ns$::internal::ReadVarint$1$$2$(&ptr);\n"
910 if (
field->is_repeated() ||
field->real_containing_oneof()) {
912 "$msg$_internal_$put_field$("
913 "::$proto_ns$::internal::UnalignedLoad<$primitive_type$>(ptr));\n"
914 "ptr += sizeof($primitive_type$);\n");
917 format(
"_Internal::set_has_$name$(&$has_bits$);\n");
921 "::$proto_ns$::internal::UnalignedLoad<$primitive_type$>(ptr);\n"
922 "ptr += sizeof($primitive_type$);\n");
933 "ptr = ctx->ParseGroup($msg$_internal_$mutable_field$(), ptr, $1$);\n"
950 if (
field->is_packable()) {
959 *fallback_tag_ptr = fallback_tag;
986 const std::vector<const FieldDescriptor*>& ordered_fields) {
989 "ptr = ::$proto_ns$::internal::ReadTag(ptr, &tag);\n");
991 if (!ordered_fields.empty()) {
997 format(
"handle_unusual:\n");
1003 "if ((tag == 0) || ((tag & 7) == 4)) {\n"
1005 " ctx->SetLastTag(tag);\n"
1006 " goto message_done;\n"
1011 if (
descriptor->extension_range_count() > 0) {
1013 for (
int i = 0;
i <
descriptor->extension_range_count();
i++) {
1014 const Descriptor::ExtensionRange*
range =
1024 format(
"($1$u <= tag)", start_tag);
1026 format(
"($1$u <= tag && tag < $2$u)", start_tag, end_tag);
1031 " ptr = $msg$_extensions_.ParseField(tag, ptr, "
1032 "internal_default_instance(), &$msg$_internal_metadata_, ctx);\n"
1033 " CHK_(ptr != nullptr);\n"
1038 "ptr = UnknownFieldParse(\n"
1040 " $msg$_internal_metadata_.mutable_unknown_fields<"
1041 "$unknown_fields_type$>(),\n"
1043 "CHK_(ptr != nullptr);\n");
1049 const std::vector<const FieldDescriptor*>& ordered_fields) {
1050 format(
"switch (tag >> 3) {\n");
1053 for (
const auto*
field : ordered_fields) {
1059 format(
"if (PROTOBUF_PREDICT_TRUE(static_cast<$uint8$>(tag) == $1$)) {\n",
1060 expected_tag & 0xFF);
1078 " if (!ctx->DataAvailable(ptr)) break;\n"
1079 "} while (::$proto_ns$::internal::ExpectTag<$1$>(ptr));\n",
1084 format(
"} else if (static_cast<$uint8$>(tag) == $1$) {\n",
1085 fallback_tag & 0xFF);
1093 " goto handle_unusual;\n"
1100 " goto handle_unusual;\n");
1116 switch (
field->type()) {
1187 int tag_length_bytes,
1197 name.append(
"Singular");
1200 name.append(
"Oneof");
1203 name.append(
"Repeated");
1206 name.append(
"Packed");
1211 switch (type_format) {
1214 name.append(
"Fixed");
1222 name.append(
"Varint");
1228 name.append(
"String");
1239 switch (type_format) {
1242 name.append(
"uint64_t, ");
1246 name.append(
"int64_t, ");
1251 name.append(
"uint32_t, ");
1255 name.append(
"int32_t, ");
1259 name.append(
"bool, ");
1266 name.append(CodedTagType(tag_length_bytes));
1268 switch (type_format) {
bool HasGeneratedMethods(const FileDescriptor *file, const Options &options)
bool HasHasbit(const FieldDescriptor *field)
std::string FieldName(const FieldDescriptor *field)
std::map< std::string, std::string > variables_
MessageSCCAnalyzer * scc_analyzer_
std::string ProtobufNamespace(const Options &options)
void GenerateArenaString(Formatter &format, const FieldDescriptor *field)
#define GOOGLE_CHECK_LT(A, B)
OPENSSL_EXPORT pem_password_cb void * u
std::string QualifiedClassName(const Descriptor *d, const Options &options)
void GenerateFieldBody(Formatter &format, google::protobuf::internal::WireFormatLite::WireType wiretype, const FieldDescriptor *field)
bool IsStringInlined(const FieldDescriptor *descriptor, const Options &options)
bool HasPreservingUnknownEnumSemantics(const FieldDescriptor *field)
static upb_StringView default_string(upb_ToProto_Context *ctx, const upb_FieldDef *f)
std::vector< int > inlined_string_indices_
bool should_generate_tctable() const
std::string MakeDefaultName(const FieldDescriptor *field)
void SetUnknownFieldsVariable(const Descriptor *descriptor, const Options &options, std::map< std::string, std::string > *variables)
FileOptions_OptimizeMode GetOptimizeFor(const FileDescriptor *file, const Options &options)
string StrCat(const AlphaNum &a, const AlphaNum &b)
const char * DeclaredTypeMethodName(FieldDescriptor::Type type)
static constexpr CType CORD
bool IsWeak(const FieldDescriptor *field, const Options &options)
const MessageOptions & options() const
void GenerateMethodImpls(io::Printer *printer)
std::vector< FieldInfo > fast_path_fields
void GenerateTailcallFallbackFunction(Formatter &format)
static bool ShouldRepeat(const FieldDescriptor *descriptor, WireFormatLite::WireType wiretype)
const Descriptor * descriptor_
static void * tag(intptr_t t)
bool use_generated_fallback
const ExtensionRange * extension_range(int index) const
bool IsLazy(const FieldDescriptor *field, const Options &options)
ParseFunctionGenerator(const Descriptor *descriptor, int max_has_bit_index, const std::vector< int > &has_bit_indices, const std::vector< int > &inlined_string_indices, const Options &options, MessageSCCAnalyzer *scc_analyzer, const std::map< std::string, std::string > &vars)
bool IsImplicitWeakField(const FieldDescriptor *field, const Options &options, MessageSCCAnalyzer *scc_analyzer)
void GenerateMethodDecls(io::Printer *printer)
bool IsMapEntryMessage(const Descriptor *descriptor)
enum google::protobuf::compiler::cpp::Options::@466 tctable_mode
static size_t VarintSize32(uint32 value)
std::string FieldMessageTypeName(const FieldDescriptor *field, const Options &options)
void swap(Json::Value &a, Json::Value &b)
Specialize std::swap() for Json::Value.
static constexpr OptimizeMode LITE_RUNTIME
void GenerateTailcallParseFunction(Formatter &format)
void GenerateStrings(Formatter &format, const FieldDescriptor *field, bool check_utf8)
void GenerateParseIterationBody(Formatter &format, const Descriptor *descriptor, const std::vector< const FieldDescriptor * > &ordered_fields)
static constexpr CType STRING_PIECE
int extension_range_count() const
void SetCommonVars(const Options &options, std::map< std::string, std::string > *variables)
std::string QualifiedDefaultInstanceName(const Descriptor *descriptor, const Options &options)
std::vector< const FieldDescriptor * > fallback_fields
bool HasDescriptorMethods(const FileDescriptor *file, const Options &options)
const EnumDescriptor * enum_type
static constexpr CType STRING
FieldRangeImpl< T > FieldRange(const T *desc)
TailCallTableInfo(const Descriptor *descriptor, const Options &options, const std::vector< int > &has_bit_indices, MessageSCCAnalyzer *scc_analyzer)
void PrintFieldComment(const Formatter &format, const T *field)
std::string GetTailCallFieldHandlerName(ParseCardinality card, TypeFormat type_format, int tag_length_bytes, const Options &options)
const FieldDescriptor * field
static const int kMaxNumber
DebugStringOptions options_
std::string DefaultInstanceName(const Descriptor *descriptor, const Options &options)
bool IsFieldStripped(const FieldDescriptor *, const Options &)
void GenerateTailcallFieldParseFunctions(Formatter &format)
static uint32_t ExpectedTag(const FieldDescriptor *field, uint32_t *fallback_tag_ptr)
zend_class_entry * field_type
void GenerateLoopingParseFunction(Formatter &format)
const FileDescriptor * file() const
std::string ClassName(const Descriptor *descriptor)
#define GOOGLE_CHECK(EXPRESSION)
const char * PrimitiveTypeName(FieldDescriptor::CppType type)
void GenerateDataDefinitions(io::Printer *printer)
static Utf8CheckMode GetUtf8CheckMode(const FieldDescriptor *field, const Options &options)
void GenerateDataDecls(io::Printer *printer)
#define GOOGLE_CHECK_NE(A, B)
bool should_generate_guarded_tctable() const
std::unique_ptr< TailCallTableInfo > tc_table_info_
std::map< std::string, std::string > variables_
#define GOOGLE_LOG(LEVEL)
void GenerateLengthDelim(Formatter &format, const FieldDescriptor *field)
static const char descriptor[1336]
void GenerateTailCallTable(Formatter &format)
void GenerateFastFieldEntries(Formatter &format, const std::string &fallback)
bool message_set_wire_format() const
void StrAppend(string *result, const AlphaNum &a)
void GenerateFieldSwitch(Formatter &format, const std::vector< const FieldDescriptor * > &ordered_fields)
grpc
Author(s):
autogenerated on Thu Mar 13 2025 02:58:59