|
@@ -32,6 +32,7 @@
|
|
// Based on original Protocol Buffers design by
|
|
// Based on original Protocol Buffers design by
|
|
// Sanjay Ghemawat, Jeff Dean, and others.
|
|
// Sanjay Ghemawat, Jeff Dean, and others.
|
|
|
|
|
|
|
|
+#include <functional>
|
|
#include <limits>
|
|
#include <limits>
|
|
#include <map>
|
|
#include <map>
|
|
#include <queue>
|
|
#include <queue>
|
|
@@ -75,7 +76,7 @@ string DotsToColons(const string& name) {
|
|
return StringReplace(name, ".", "::", true);
|
|
return StringReplace(name, ".", "::", true);
|
|
}
|
|
}
|
|
|
|
|
|
-const char* const kKeywordList[] = { //
|
|
|
|
|
|
+static const char* const kKeywordList[] = { //
|
|
"NULL",
|
|
"NULL",
|
|
"alignas",
|
|
"alignas",
|
|
"alignof",
|
|
"alignof",
|
|
@@ -160,15 +161,15 @@ const char* const kKeywordList[] = { //
|
|
"xor",
|
|
"xor",
|
|
"xor_eq"};
|
|
"xor_eq"};
|
|
|
|
|
|
-std::unordered_set<string> MakeKeywordsMap() {
|
|
|
|
- std::unordered_set<string> result;
|
|
|
|
- for (int i = 0; i < GOOGLE_ARRAYSIZE(kKeywordList); i++) {
|
|
|
|
- result.insert(kKeywordList[i]);
|
|
|
|
|
|
+static std::unordered_set<string>* MakeKeywordsMap() {
|
|
|
|
+ auto* result = new std::unordered_set<string>();
|
|
|
|
+ for (const auto keyword : kKeywordList) {
|
|
|
|
+ result->emplace(keyword);
|
|
}
|
|
}
|
|
return result;
|
|
return result;
|
|
}
|
|
}
|
|
|
|
|
|
-std::unordered_set<string> kKeywords = MakeKeywordsMap();
|
|
|
|
|
|
+static std::unordered_set<string>& kKeywords = *MakeKeywordsMap();
|
|
|
|
|
|
// Returns whether the provided descriptor has an extension. This includes its
|
|
// Returns whether the provided descriptor has an extension. This includes its
|
|
// nested types.
|
|
// nested types.
|
|
@@ -255,6 +256,7 @@ void SetCommonVars(const Options& options,
|
|
"ECK";
|
|
"ECK";
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ SetIntVar(options, "int8", variables);
|
|
SetIntVar(options, "uint8", variables);
|
|
SetIntVar(options, "uint8", variables);
|
|
SetIntVar(options, "uint32", variables);
|
|
SetIntVar(options, "uint32", variables);
|
|
SetIntVar(options, "uint64", variables);
|
|
SetIntVar(options, "uint64", variables);
|
|
@@ -910,11 +912,7 @@ FieldOptions::CType EffectiveStringCType(const FieldDescriptor* field,
|
|
}
|
|
}
|
|
|
|
|
|
bool IsAnyMessage(const FileDescriptor* descriptor, const Options& options) {
|
|
bool IsAnyMessage(const FileDescriptor* descriptor, const Options& options) {
|
|
- // For now we do not support Any in lite mode, so if we're building for lite
|
|
|
|
- // then we just treat Any as if it's an ordinary message with no special
|
|
|
|
- // behavior.
|
|
|
|
- return descriptor->name() == kAnyProtoFile &&
|
|
|
|
- GetOptimizeFor(descriptor, options) != FileOptions::LITE_RUNTIME;
|
|
|
|
|
|
+ return descriptor->name() == kAnyProtoFile;
|
|
}
|
|
}
|
|
|
|
|
|
bool IsAnyMessage(const Descriptor* descriptor, const Options& options) {
|
|
bool IsAnyMessage(const Descriptor* descriptor, const Options& options) {
|
|
@@ -1302,14 +1300,20 @@ class ParseLoopGenerator {
|
|
|
|
|
|
void GenerateParserLoop(const Descriptor* descriptor) {
|
|
void GenerateParserLoop(const Descriptor* descriptor) {
|
|
format_.Set("classname", ClassName(descriptor));
|
|
format_.Set("classname", ClassName(descriptor));
|
|
- format_.Set("proto_ns", ProtobufNamespace(options_));
|
|
|
|
|
|
+ format_.Set("p_ns", "::" + ProtobufNamespace(options_));
|
|
|
|
+ format_.Set("pi_ns", StrCat("::", ProtobufNamespace(options_), "::internal"));
|
|
format_.Set("GOOGLE_PROTOBUF", MacroPrefix(options_));
|
|
format_.Set("GOOGLE_PROTOBUF", MacroPrefix(options_));
|
|
|
|
+ format_.Set("kSlopBytes",
|
|
|
|
+ static_cast<int>(internal::ParseContext::kSlopBytes));
|
|
std::map<string, string> vars;
|
|
std::map<string, string> vars;
|
|
SetCommonVars(options_, &vars);
|
|
SetCommonVars(options_, &vars);
|
|
format_.AddMap(vars);
|
|
format_.AddMap(vars);
|
|
|
|
|
|
std::vector<const FieldDescriptor*> ordered_fields;
|
|
std::vector<const FieldDescriptor*> ordered_fields;
|
|
for (auto field : FieldRange(descriptor)) {
|
|
for (auto field : FieldRange(descriptor)) {
|
|
|
|
+ if (IsProto1(descriptor->file(), options_)) {
|
|
|
|
+ if (field->number() >= (1 << 14)) continue;
|
|
|
|
+ }
|
|
ordered_fields.push_back(field);
|
|
ordered_fields.push_back(field);
|
|
}
|
|
}
|
|
std::sort(ordered_fields.begin(), ordered_fields.end(),
|
|
std::sort(ordered_fields.begin(), ordered_fields.end(),
|
|
@@ -1318,19 +1322,11 @@ class ParseLoopGenerator {
|
|
});
|
|
});
|
|
|
|
|
|
format_(
|
|
format_(
|
|
- "const char* $classname$::_InternalParse(const char* begin, const "
|
|
|
|
- "char* "
|
|
|
|
- "end, void* object,\n"
|
|
|
|
- " ::$proto_ns$::internal::ParseContext* ctx) {\n"
|
|
|
|
- " auto msg = static_cast<$classname$*>(object);\n"
|
|
|
|
- " $int32$ size; (void)size;\n"
|
|
|
|
- " int depth; (void)depth;\n"
|
|
|
|
- " $uint32$ tag;\n"
|
|
|
|
- " ::$proto_ns$::internal::ParseFunc parser_till_end; "
|
|
|
|
- "(void)parser_till_end;\n"
|
|
|
|
- " auto ptr = begin;\n"
|
|
|
|
- " while (ptr < end) {\n"
|
|
|
|
- " ptr = ::$proto_ns$::io::Parse32(ptr, &tag);\n"
|
|
|
|
|
|
+ "const char* $classname$::_InternalParse(const char* ptr, "
|
|
|
|
+ "$pi_ns$::ParseContext* ctx) {\n"
|
|
|
|
+ " while (!ctx->Done(&ptr)) {\n"
|
|
|
|
+ " $uint32$ tag;\n"
|
|
|
|
+ " ptr = $pi_ns$::ReadTag(ptr, &tag);\n"
|
|
" $GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr);\n"
|
|
" $GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr);\n"
|
|
" switch (tag >> 3) {\n");
|
|
" switch (tag >> 3) {\n");
|
|
|
|
|
|
@@ -1338,11 +1334,7 @@ class ParseLoopGenerator {
|
|
format_.Indent();
|
|
format_.Indent();
|
|
format_.Indent();
|
|
format_.Indent();
|
|
|
|
|
|
- bool use_handle_unusual = false;
|
|
|
|
for (const auto* field : ordered_fields) {
|
|
for (const auto* field : ordered_fields) {
|
|
- if (IsProto1(descriptor->file(), options_)) {
|
|
|
|
- if (field->number() >= (1 << 14)) continue;
|
|
|
|
- }
|
|
|
|
// Print the field's (or oneof's) proto-syntax definition as a comment.
|
|
// Print the field's (or oneof's) proto-syntax definition as a comment.
|
|
// We don't want to print group bodies so we cut off after the first
|
|
// We don't want to print group bodies so we cut off after the first
|
|
// line.
|
|
// line.
|
|
@@ -1359,22 +1351,21 @@ class ParseLoopGenerator {
|
|
"case $2$: {\n",
|
|
"case $2$: {\n",
|
|
def, field->number());
|
|
def, field->number());
|
|
format_.Indent();
|
|
format_.Indent();
|
|
- use_handle_unusual = true;
|
|
|
|
GenerateCaseBody(field);
|
|
GenerateCaseBody(field);
|
|
format_.Outdent();
|
|
format_.Outdent();
|
|
format_("}\n"); // case
|
|
format_("}\n"); // case
|
|
} // for fields
|
|
} // for fields
|
|
|
|
+
|
|
|
|
+ // Default case
|
|
format_("default: {\n");
|
|
format_("default: {\n");
|
|
- if (use_handle_unusual) format_("handle_unusual:\n");
|
|
|
|
|
|
+ if (!ordered_fields.empty()) format_("handle_unusual:\n");
|
|
format_(
|
|
format_(
|
|
" if ((tag & 7) == 4 || tag == 0) {\n"
|
|
" if ((tag & 7) == 4 || tag == 0) {\n"
|
|
- " ctx->EndGroup(tag);\n"
|
|
|
|
|
|
+ " ctx->SetLastTag(tag);\n"
|
|
" return ptr;\n"
|
|
" return ptr;\n"
|
|
" }\n");
|
|
" }\n");
|
|
if (IsMapEntryMessage(descriptor)) {
|
|
if (IsMapEntryMessage(descriptor)) {
|
|
- format_(
|
|
|
|
- " break;\n"
|
|
|
|
- "}\n");
|
|
|
|
|
|
+ format_(" break;\n");
|
|
} else {
|
|
} else {
|
|
if (descriptor->extension_range_count() > 0) {
|
|
if (descriptor->extension_range_count() > 0) {
|
|
format_("if (");
|
|
format_("if (");
|
|
@@ -1396,113 +1387,59 @@ class ParseLoopGenerator {
|
|
}
|
|
}
|
|
format_(") {\n");
|
|
format_(") {\n");
|
|
format_(
|
|
format_(
|
|
- " auto res = msg->_extensions_.ParseField(tag, {_InternalParse, "
|
|
|
|
- "msg}, ptr, end,\n"
|
|
|
|
- " internal_default_instance(), &msg->_internal_metadata_, "
|
|
|
|
|
|
+ " ptr = _extensions_.ParseField(tag, ptr, \n"
|
|
|
|
+ " internal_default_instance(), &_internal_metadata_, "
|
|
"ctx);\n"
|
|
"ctx);\n"
|
|
- " ptr = res.first;\n"
|
|
|
|
" $GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr != nullptr);\n"
|
|
" $GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr != nullptr);\n"
|
|
- " if (res.second) return ptr;\n"
|
|
|
|
- " continue;\n"
|
|
|
|
|
|
+ " break;\n"
|
|
"}\n");
|
|
"}\n");
|
|
}
|
|
}
|
|
format_(
|
|
format_(
|
|
- " auto res = UnknownFieldParse(tag, {_InternalParse, msg},\n"
|
|
|
|
- " ptr, end, msg->_internal_metadata_.mutable_unknown_fields(), "
|
|
|
|
- "ctx);\n"
|
|
|
|
- " ptr = res.first;\n"
|
|
|
|
|
|
+ " ptr = UnknownFieldParse(tag,\n"
|
|
|
|
+ " _internal_metadata_.mutable_unknown_fields(), ptr, ctx);\n"
|
|
" $GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr != nullptr);\n"
|
|
" $GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr != nullptr);\n"
|
|
- " if (res.second) return ptr;\n"
|
|
|
|
- "}\n"); // default case
|
|
|
|
|
|
+ " break;\n");
|
|
}
|
|
}
|
|
|
|
+ format_("}\n"); // default case
|
|
format_.Outdent();
|
|
format_.Outdent();
|
|
format_.Outdent();
|
|
format_.Outdent();
|
|
format_.Outdent();
|
|
format_.Outdent();
|
|
format_(
|
|
format_(
|
|
" } // switch\n"
|
|
" } // switch\n"
|
|
" } // while\n"
|
|
" } // while\n"
|
|
- " return ptr;\n");
|
|
|
|
- if (use_string_) {
|
|
|
|
- format_(
|
|
|
|
- "string_till_end:\n"
|
|
|
|
- " static_cast<$string$*>(object)->clear();\n"
|
|
|
|
- // TODO(gerbens) evaluate security
|
|
|
|
- " static_cast<$string$*>(object)->reserve(size);\n"
|
|
|
|
- " goto len_delim_till_end;\n");
|
|
|
|
- }
|
|
|
|
- if (use_arena_string_) {
|
|
|
|
- format_(
|
|
|
|
- "arena_string_till_end:\n"
|
|
|
|
- " object = "
|
|
|
|
- "static_cast<::$proto_ns$::internal::ArenaStringPtr*>(object)->"
|
|
|
|
- "Mutable(&::google::protobuf::internal::GetEmptyStringAlreadyInited(), "
|
|
|
|
- "msg->GetArenaNoVirtual());\n"
|
|
|
|
- " static_cast<$string$*>(object)->clear();\n"
|
|
|
|
- // TODO(gerbens) evaluate security
|
|
|
|
- " static_cast<$string$*>(object)->reserve(size);\n"
|
|
|
|
- " goto len_delim_till_end;\n");
|
|
|
|
- }
|
|
|
|
- if (use_length_delimited_) {
|
|
|
|
- format_(
|
|
|
|
- "len_delim_till_end:\n"
|
|
|
|
- " return ctx->StoreAndTailCall(ptr, end, {_InternalParse, msg},\n"
|
|
|
|
- " {parser_till_end, object}, size);\n");
|
|
|
|
- }
|
|
|
|
- if (use_group_) {
|
|
|
|
- // Group crossed end and must be continued. Either this a parse failure
|
|
|
|
- // or we need to resume on the next chunk and thus save the state.
|
|
|
|
- format_(
|
|
|
|
- "group_continues:\n"
|
|
|
|
- " $DCHK$(ptr >= end);\n"
|
|
|
|
- " $GOOGLE_PROTOBUF$_PARSER_ASSERT(ctx->StoreGroup(\n "
|
|
|
|
- " {_InternalParse, msg}, {parser_till_end, object}, depth, tag));\n"
|
|
|
|
- " return ptr;\n");
|
|
|
|
- }
|
|
|
|
- format_("}\n");
|
|
|
|
|
|
+ " return ptr;\n"
|
|
|
|
+ "}\n");
|
|
}
|
|
}
|
|
|
|
|
|
private:
|
|
private:
|
|
MessageSCCAnalyzer* scc_analyzer_;
|
|
MessageSCCAnalyzer* scc_analyzer_;
|
|
const Options& options_;
|
|
const Options& options_;
|
|
Formatter format_;
|
|
Formatter format_;
|
|
- bool use_length_delimited_ = false;
|
|
|
|
- bool use_group_ = false;
|
|
|
|
- bool use_string_ = false;
|
|
|
|
- bool use_arena_string_ = false;
|
|
|
|
|
|
|
|
using WireFormat = internal::WireFormat;
|
|
using WireFormat = internal::WireFormat;
|
|
using WireFormatLite = internal::WireFormatLite;
|
|
using WireFormatLite = internal::WireFormatLite;
|
|
|
|
|
|
- void GenerateArenaString(const FieldDescriptor* field, const string& utf8) {
|
|
|
|
- use_arena_string_ = true;
|
|
|
|
|
|
+ void GenerateArenaString(const FieldDescriptor* field, const string& utf8,
|
|
|
|
+ const string& field_name) {
|
|
if (HasFieldPresence(field->file())) {
|
|
if (HasFieldPresence(field->file())) {
|
|
- format_("HasBitSetters::set_has_$1$(msg);\n", FieldName(field));
|
|
|
|
|
|
+ format_("HasBitSetters::set_has_$1$(this);\n", FieldName(field));
|
|
}
|
|
}
|
|
format_(
|
|
format_(
|
|
- "if (size > end - ptr + "
|
|
|
|
- "::$proto_ns$::internal::ParseContext::kSlopBytes) {\n"
|
|
|
|
- " object = &msg->$1$_;\n"
|
|
|
|
- " parser_till_end = ::$proto_ns$::internal::GreedyStringParser$2$;\n"
|
|
|
|
- " goto arena_string_till_end;\n"
|
|
|
|
- "}\n"
|
|
|
|
- "$GOOGLE_PROTOBUF$_PARSER_ASSERT(::$proto_ns$::internal::StringCheck$2$"
|
|
|
|
- "(ptr, size, ctx));\n"
|
|
|
|
- "::$proto_ns$::internal::CopyIntoArenaString(ptr, size, &msg->$1$_, "
|
|
|
|
- "msg->GetArenaNoVirtual());\n"
|
|
|
|
- "ptr += size;\n",
|
|
|
|
- FieldName(field), utf8);
|
|
|
|
|
|
+ "ptr = $pi_ns$::InlineCopyIntoArenaString$1$(&$2$_, ptr, ctx, "
|
|
|
|
+ "GetArenaNoVirtual()$3$);\n",
|
|
|
|
+ utf8, FieldName(field), field_name);
|
|
}
|
|
}
|
|
|
|
|
|
void GenerateStrings(const FieldDescriptor* field, bool check_utf8) {
|
|
void GenerateStrings(const FieldDescriptor* field, bool check_utf8) {
|
|
string utf8;
|
|
string utf8;
|
|
|
|
+ string field_name;
|
|
if (check_utf8) {
|
|
if (check_utf8) {
|
|
utf8 = GetUtf8Suffix(field, options_);
|
|
utf8 = GetUtf8Suffix(field, options_);
|
|
if (!utf8.empty()) {
|
|
if (!utf8.empty()) {
|
|
- string name = "nullptr";
|
|
|
|
|
|
+ field_name = ", nullptr";
|
|
if (HasDescriptorMethods(field->file(), options_)) {
|
|
if (HasDescriptorMethods(field->file(), options_)) {
|
|
- name = "\"" + field->full_name() + "\"";
|
|
|
|
|
|
+ field_name = StrCat(", \"", field->full_name(), "\"");
|
|
}
|
|
}
|
|
- format_("ctx->extra_parse_data().SetFieldName($1$);\n", name);
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
FieldOptions::CType ctype = FieldOptions::STRING;
|
|
FieldOptions::CType ctype = FieldOptions::STRING;
|
|
@@ -1523,73 +1460,40 @@ class ParseLoopGenerator {
|
|
!IsProto1(field->file(), options_) &&
|
|
!IsProto1(field->file(), options_) &&
|
|
!IsStringInlined(field, options_) &&
|
|
!IsStringInlined(field, options_) &&
|
|
field->containing_oneof() == nullptr && ctype == FieldOptions::STRING) {
|
|
field->containing_oneof() == nullptr && ctype == FieldOptions::STRING) {
|
|
- GenerateArenaString(field, utf8);
|
|
|
|
|
|
+ GenerateArenaString(field, utf8, field_name);
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
- format_(
|
|
|
|
- "object = msg->$1$_$2$();\n"
|
|
|
|
- "if (size > end - ptr + "
|
|
|
|
- "::$proto_ns$::internal::ParseContext::kSlopBytes) {\n",
|
|
|
|
- field->is_repeated() && !field->is_packable() ? "add" : "mutable",
|
|
|
|
- FieldName(field));
|
|
|
|
string name;
|
|
string name;
|
|
- string label = "len_delim_till_end";
|
|
|
|
switch (ctype) {
|
|
switch (ctype) {
|
|
case FieldOptions::STRING:
|
|
case FieldOptions::STRING:
|
|
- name = "GreedyStringParser";
|
|
|
|
- use_string_ = true;
|
|
|
|
- label = "string_till_end";
|
|
|
|
|
|
+ name = "GreedyStringParser" + utf8;
|
|
break;
|
|
break;
|
|
case FieldOptions::CORD:
|
|
case FieldOptions::CORD:
|
|
- name = "CordParser";
|
|
|
|
- format_(" static_cast<::Cord*>(object)->Clear();\n");
|
|
|
|
|
|
+ name = "CordParser" + utf8;
|
|
break;
|
|
break;
|
|
case FieldOptions::STRING_PIECE:
|
|
case FieldOptions::STRING_PIECE:
|
|
- name = "StringPieceParser";
|
|
|
|
- format_(
|
|
|
|
- " "
|
|
|
|
- "static_cast<::$proto_ns$::internal::StringPieceField*>(object)->"
|
|
|
|
- "Clear();\n");
|
|
|
|
|
|
+ name = "StringPieceParser" + utf8;
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
format_(
|
|
format_(
|
|
- " parser_till_end = ::$proto_ns$::internal::$1$$2$;\n"
|
|
|
|
- " goto $3$;\n"
|
|
|
|
- "}\n"
|
|
|
|
- "$GOOGLE_PROTOBUF$_PARSER_ASSERT(::$proto_ns$::internal::StringCheck$2$"
|
|
|
|
- "(ptr, size, ctx));\n"
|
|
|
|
- "::$proto_ns$::internal::Inline$1$(object, ptr, size, ctx);\n"
|
|
|
|
- "ptr += size;\n",
|
|
|
|
- name, utf8, label);
|
|
|
|
|
|
+ "ptr = $pi_ns$::Inline$1$($2$_$3$(), ptr, ctx$4$);\n",
|
|
|
|
+ name, field->is_repeated() && !field->is_packable() ? "add" : "mutable",
|
|
|
|
+ FieldName(field), field_name);
|
|
}
|
|
}
|
|
|
|
|
|
void GenerateLengthDelim(const FieldDescriptor* field) {
|
|
void GenerateLengthDelim(const FieldDescriptor* field) {
|
|
- format_(
|
|
|
|
- "ptr = ::$proto_ns$::io::ReadSize(ptr, &size);\n"
|
|
|
|
- "$GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr);\n");
|
|
|
|
if (!IsProto1(field->file(), options_) && field->is_packable()) {
|
|
if (!IsProto1(field->file(), options_) && field->is_packable()) {
|
|
|
|
+ string enum_validator;
|
|
if (!HasPreservingUnknownEnumSemantics(field->file()) &&
|
|
if (!HasPreservingUnknownEnumSemantics(field->file()) &&
|
|
field->type() == FieldDescriptor::TYPE_ENUM) {
|
|
field->type() == FieldDescriptor::TYPE_ENUM) {
|
|
- format_(
|
|
|
|
- "ctx->extra_parse_data().SetEnumValidator($1$_IsValid, "
|
|
|
|
- "msg->mutable_unknown_fields(), $2$);\n"
|
|
|
|
- "parser_till_end = "
|
|
|
|
- "::$proto_ns$::internal::PackedValidEnumParser$3$;\n"
|
|
|
|
- "object = msg->mutable_$4$();\n",
|
|
|
|
- QualifiedClassName(field->enum_type()), field->number(),
|
|
|
|
- UseUnknownFieldSet(field->file(), options_) ? "" : "Lite",
|
|
|
|
- FieldName(field));
|
|
|
|
- } else {
|
|
|
|
- format_(
|
|
|
|
- "parser_till_end = ::$proto_ns$::internal::Packed$1$Parser;\n"
|
|
|
|
- "object = msg->mutable_$2$();\n",
|
|
|
|
- DeclaredTypeMethodName(field->type()), FieldName(field));
|
|
|
|
|
|
+ enum_validator = StrCat(
|
|
|
|
+ ", ", QualifiedClassName(field->enum_type()),
|
|
|
|
+ "_IsValid, mutable_unknown_fields(), ", field->number());
|
|
}
|
|
}
|
|
format_(
|
|
format_(
|
|
- "if (size > end - ptr) goto len_delim_till_end;\n"
|
|
|
|
- "auto newend = ptr + size;\n"
|
|
|
|
- "if (size) ptr = parser_till_end(ptr, newend, object, ctx);\n"
|
|
|
|
- "$GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr == newend);\n");
|
|
|
|
|
|
+ "ptr = $pi_ns$::Packed$1$Parser(mutable_$2$(), ptr, ctx$3$);\n",
|
|
|
|
+ DeclaredTypeMethodName(field->type()), FieldName(field),
|
|
|
|
+ enum_validator);
|
|
} else {
|
|
} else {
|
|
auto field_type = field->type();
|
|
auto field_type = field->type();
|
|
if (IsProto1(field->file(), options_)) {
|
|
if (IsProto1(field->file(), options_)) {
|
|
@@ -1610,106 +1514,62 @@ class ParseLoopGenerator {
|
|
GenerateStrings(field, false /* utf8 */);
|
|
GenerateStrings(field, false /* utf8 */);
|
|
break;
|
|
break;
|
|
case FieldDescriptor::TYPE_MESSAGE: {
|
|
case FieldDescriptor::TYPE_MESSAGE: {
|
|
- GOOGLE_CHECK(field->message_type());
|
|
|
|
if (!IsProto1(field->file(), options_) && field->is_map()) {
|
|
if (!IsProto1(field->file(), options_) && field->is_map()) {
|
|
- const FieldDescriptor* val =
|
|
|
|
- field->message_type()->FindFieldByName("value");
|
|
|
|
- GOOGLE_CHECK(val);
|
|
|
|
- if (HasFieldPresence(field->file()) &&
|
|
|
|
- val->type() == FieldDescriptor::TYPE_ENUM) {
|
|
|
|
- format_(
|
|
|
|
- "ctx->extra_parse_data().field_number = $1$;\n"
|
|
|
|
- "ctx->extra_parse_data().unknown_fields = "
|
|
|
|
- "&msg->_internal_metadata_;\n",
|
|
|
|
- field->number());
|
|
|
|
- }
|
|
|
|
- format_(
|
|
|
|
- "parser_till_end = "
|
|
|
|
- "::$proto_ns$::internal::SlowMapEntryParser;\n"
|
|
|
|
- "auto parse_map = $1$::_ParseMap;\n"
|
|
|
|
- "ctx->extra_parse_data().payload.clear();\n"
|
|
|
|
- "ctx->extra_parse_data().parse_map = parse_map;\n"
|
|
|
|
- "object = &msg->$2$_;\n"
|
|
|
|
- "if (size > end - ptr) goto len_delim_till_end;\n"
|
|
|
|
- "auto newend = ptr + size;\n"
|
|
|
|
- "$GOOGLE_PROTOBUF$_PARSER_ASSERT(parse_map(ptr, newend, "
|
|
|
|
- "object, ctx));\n"
|
|
|
|
- "ptr = newend;\n",
|
|
|
|
- QualifiedClassName(field->message_type()), FieldName(field));
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- if (!IsProto1(field->file(), options_) && IsLazy(field, options_)) {
|
|
|
|
|
|
+ format_("ptr = ctx->ParseMessage(&$1$_, ptr);\n", FieldName(field));
|
|
|
|
+ } else if (!IsProto1(field->file(), options_) &&
|
|
|
|
+ IsLazy(field, options_)) {
|
|
if (field->containing_oneof() != nullptr) {
|
|
if (field->containing_oneof() != nullptr) {
|
|
format_(
|
|
format_(
|
|
- "if (!msg->has_$1$()) {\n"
|
|
|
|
- " msg->clear_$1$();\n"
|
|
|
|
- " msg->$2$_.$1$_ = ::$proto_ns$::Arena::CreateMessage<\n"
|
|
|
|
- " ::$proto_ns$::internal::LazyField>("
|
|
|
|
- "msg->GetArenaNoVirtual());\n"
|
|
|
|
- " msg->set_has_$1$();\n"
|
|
|
|
|
|
+ "if (!has_$1$()) {\n"
|
|
|
|
+ " clear_$1$();\n"
|
|
|
|
+ " $2$_.$1$_ = ::$proto_ns$::Arena::CreateMessage<\n"
|
|
|
|
+ " $pi_ns$::LazyField>("
|
|
|
|
+ "GetArenaNoVirtual());\n"
|
|
|
|
+ " set_has_$1$();\n"
|
|
"}\n"
|
|
"}\n"
|
|
- "auto parse_closure = msg->$2$_.$1$_->_ParseClosure();\n",
|
|
|
|
|
|
+ "ptr = ctx->ParseMessage($2$_.$1$_, ptr);\n",
|
|
FieldName(field), field->containing_oneof()->name());
|
|
FieldName(field), field->containing_oneof()->name());
|
|
} else if (HasFieldPresence(field->file())) {
|
|
} else if (HasFieldPresence(field->file())) {
|
|
format_(
|
|
format_(
|
|
- "HasBitSetters::set_has_$1$(msg);\n"
|
|
|
|
- "auto parse_closure = msg->$1$_._ParseClosure();\n",
|
|
|
|
|
|
+ "HasBitSetters::set_has_$1$(this);\n"
|
|
|
|
+ "ptr = ctx->ParseMessage(&$1$_, ptr);\n",
|
|
FieldName(field));
|
|
FieldName(field));
|
|
} else {
|
|
} else {
|
|
- format_("auto parse_closure = msg->$1$_._ParseClosure();\n",
|
|
|
|
- FieldName(field));
|
|
|
|
|
|
+ format_(
|
|
|
|
+ "ptr = ctx->ParseMessage(&$1$_, ptr);\n", FieldName(field));
|
|
}
|
|
}
|
|
- format_(
|
|
|
|
- "parser_till_end = parse_closure.func;\n"
|
|
|
|
- "object = parse_closure.object;\n"
|
|
|
|
- "if (size > end - ptr) goto len_delim_till_end;\n"
|
|
|
|
- "auto newend = ptr + size;\n"
|
|
|
|
- "$GOOGLE_PROTOBUF$_PARSER_ASSERT(ctx->ParseExactRange(\n"
|
|
|
|
- " parse_closure, ptr, newend));\n"
|
|
|
|
- "ptr = newend;\n");
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- if (IsImplicitWeakField(field, options_, scc_analyzer_)) {
|
|
|
|
|
|
+ } else if (IsImplicitWeakField(field, options_, scc_analyzer_)) {
|
|
if (!field->is_repeated()) {
|
|
if (!field->is_repeated()) {
|
|
- format_("object = HasBitSetters::mutable_$1$(msg);\n",
|
|
|
|
- FieldName(field));
|
|
|
|
|
|
+ format_(
|
|
|
|
+ "ptr = ctx->ParseMessage(HasBitSetters::mutable_$1$(this), "
|
|
|
|
+ "ptr);\n",
|
|
|
|
+ FieldName(field));
|
|
} else {
|
|
} else {
|
|
format_(
|
|
format_(
|
|
- "object = "
|
|
|
|
- "CastToBase(&msg->$1$_)->AddWeak(reinterpret_cast<const "
|
|
|
|
- "::$proto_ns$::MessageLite*>(&$2$::_$3$_default_instance_));"
|
|
|
|
- "\n",
|
|
|
|
|
|
+ "ptr = ctx->ParseMessage("
|
|
|
|
+ "CastToBase(&$1$_)->AddWeak(reinterpret_cast<const "
|
|
|
|
+ "::$proto_ns$::MessageLite*>(&$2$::_$3$_default_instance_)), "
|
|
|
|
+ "ptr);\n",
|
|
FieldName(field), Namespace(field->message_type()),
|
|
FieldName(field), Namespace(field->message_type()),
|
|
ClassName(field->message_type()));
|
|
ClassName(field->message_type()));
|
|
}
|
|
}
|
|
- format_(
|
|
|
|
- "parser_till_end = static_cast<::$proto_ns$::MessageLite*>("
|
|
|
|
- "object)->_ParseFunc();\n");
|
|
|
|
} else if (IsWeak(field, options_)) {
|
|
} else if (IsWeak(field, options_)) {
|
|
if (IsProto1(field->file(), options_)) {
|
|
if (IsProto1(field->file(), options_)) {
|
|
- format_("object = msg->internal_mutable_$1$();\n",
|
|
|
|
- FieldName(field));
|
|
|
|
|
|
+ format_(
|
|
|
|
+ "ptr = ctx->ParseMessage("
|
|
|
|
+ "reinterpret_cast<$p_ns$::MessageLite*>(internal_mutable_$1$("
|
|
|
|
+ ")), ptr);\n",
|
|
|
|
+ FieldName(field));
|
|
} else {
|
|
} else {
|
|
format_(
|
|
format_(
|
|
- "object = msg->_weak_field_map_.MutableMessage($1$, "
|
|
|
|
- "_$classname$_default_instance_.$2$_);\n",
|
|
|
|
|
|
+ "ptr = ctx->ParseMessage(_weak_field_map_.MutableMessage($1$,"
|
|
|
|
+ " _$classname$_default_instance_.$2$_), ptr);\n",
|
|
field->number(), FieldName(field));
|
|
field->number(), FieldName(field));
|
|
}
|
|
}
|
|
- format_(
|
|
|
|
- "parser_till_end = static_cast<::$proto_ns$::MessageLite*>("
|
|
|
|
- "object)->_ParseFunc();\n");
|
|
|
|
} else {
|
|
} else {
|
|
- format_(
|
|
|
|
- "parser_till_end = $1$::_InternalParse;\n"
|
|
|
|
- "object = msg->$2$_$3$();\n",
|
|
|
|
- QualifiedClassName(field->message_type()),
|
|
|
|
- field->is_repeated() ? "add" : "mutable", FieldName(field));
|
|
|
|
|
|
+ format_("ptr = ctx->ParseMessage($1$_$2$(), ptr);\n",
|
|
|
|
+ field->is_repeated() ? "add" : "mutable", FieldName(field));
|
|
}
|
|
}
|
|
- format_(
|
|
|
|
- "if (size > end - ptr) goto len_delim_till_end;\n"
|
|
|
|
- "ptr += size;\n"
|
|
|
|
- "$GOOGLE_PROTOBUF$_PARSER_ASSERT(ctx->ParseExactRange(\n"
|
|
|
|
- " {parser_till_end, object}, ptr - size, ptr));\n");
|
|
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
default:
|
|
default:
|
|
@@ -1731,31 +1591,33 @@ class ParseLoopGenerator {
|
|
string prefix = field->is_repeated() ? "add" : "set";
|
|
string prefix = field->is_repeated() ? "add" : "set";
|
|
if (field->type() == FieldDescriptor::TYPE_ENUM &&
|
|
if (field->type() == FieldDescriptor::TYPE_ENUM &&
|
|
!IsProto1(field->file(), options_)) {
|
|
!IsProto1(field->file(), options_)) {
|
|
- format_("$uint64$ val = ::$proto_ns$::internal::ReadVarint(&ptr);\n");
|
|
|
|
|
|
+ format_(
|
|
|
|
+ "$uint64$ val = $pi_ns$::ReadVarint(&ptr);\n"
|
|
|
|
+ "$GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr);\n");
|
|
if (!HasPreservingUnknownEnumSemantics(field->file())) {
|
|
if (!HasPreservingUnknownEnumSemantics(field->file())) {
|
|
format_(
|
|
format_(
|
|
"if (!$1$_IsValid(val)) {\n"
|
|
"if (!$1$_IsValid(val)) {\n"
|
|
- " ::$proto_ns$::internal::WriteVarint($2$, val, "
|
|
|
|
- "msg->mutable_unknown_fields());\n"
|
|
|
|
|
|
+ " $pi_ns$::WriteVarint($2$, val, "
|
|
|
|
+ "mutable_unknown_fields());\n"
|
|
" break;\n"
|
|
" break;\n"
|
|
"}\n",
|
|
"}\n",
|
|
QualifiedClassName(field->enum_type()), field->number());
|
|
QualifiedClassName(field->enum_type()), field->number());
|
|
}
|
|
}
|
|
- format_("msg->$1$_$2$(static_cast<$3$>(val));\n", prefix,
|
|
|
|
- FieldName(field), QualifiedClassName(field->enum_type()));
|
|
|
|
|
|
+ format_("$1$_$2$(static_cast<$3$>(val));\n", prefix, FieldName(field),
|
|
|
|
+ QualifiedClassName(field->enum_type()));
|
|
} else {
|
|
} else {
|
|
|
|
+ int size = field->type() == FieldDescriptor::TYPE_SINT32 ? 32 : 64;
|
|
string zigzag;
|
|
string zigzag;
|
|
if ((field->type() == FieldDescriptor::TYPE_SINT32 ||
|
|
if ((field->type() == FieldDescriptor::TYPE_SINT32 ||
|
|
field->type() == FieldDescriptor::TYPE_SINT64) &&
|
|
field->type() == FieldDescriptor::TYPE_SINT64) &&
|
|
!IsProto1(field->file(), options_)) {
|
|
!IsProto1(field->file(), options_)) {
|
|
- int size = field->type() == FieldDescriptor::TYPE_SINT32 ? 32 : 64;
|
|
|
|
zigzag = StrCat("ZigZag", size);
|
|
zigzag = StrCat("ZigZag", size);
|
|
}
|
|
}
|
|
format_(
|
|
format_(
|
|
- "msg->$1$_$2$(::$proto_ns$::internal::ReadVarint$3$(&ptr));\n",
|
|
|
|
|
|
+ "$1$_$2$($pi_ns$::ReadVarint$3$(&ptr));\n"
|
|
|
|
+ "$GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr);\n",
|
|
prefix, FieldName(field), zigzag);
|
|
prefix, FieldName(field), zigzag);
|
|
}
|
|
}
|
|
- format_("$GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr);\n");
|
|
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
case WireFormatLite::WIRETYPE_FIXED32:
|
|
case WireFormatLite::WIRETYPE_FIXED32:
|
|
@@ -1763,28 +1625,20 @@ class ParseLoopGenerator {
|
|
string prefix = field->is_repeated() ? "add" : "set";
|
|
string prefix = field->is_repeated() ? "add" : "set";
|
|
string type = PrimitiveTypeName(options_, field->cpp_type());
|
|
string type = PrimitiveTypeName(options_, field->cpp_type());
|
|
format_(
|
|
format_(
|
|
- "msg->$1$_$2$(::$proto_ns$::io::UnalignedLoad<$3$>(ptr));\n"
|
|
|
|
|
|
+ "$1$_$2$($pi_ns$::UnalignedLoad<$3$>(ptr));\n"
|
|
"ptr += sizeof($3$);\n",
|
|
"ptr += sizeof($3$);\n",
|
|
prefix, FieldName(field), type);
|
|
prefix, FieldName(field), type);
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
case WireFormatLite::WIRETYPE_LENGTH_DELIMITED: {
|
|
case WireFormatLite::WIRETYPE_LENGTH_DELIMITED: {
|
|
- use_length_delimited_ = true;
|
|
|
|
GenerateLengthDelim(field);
|
|
GenerateLengthDelim(field);
|
|
|
|
+ format_("$GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr);\n");
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
case WireFormatLite::WIRETYPE_START_GROUP: {
|
|
case WireFormatLite::WIRETYPE_START_GROUP: {
|
|
- use_group_ = true;
|
|
|
|
format_(
|
|
format_(
|
|
- "parser_till_end = $1$::_InternalParse;\n"
|
|
|
|
- "object = msg->$2$_$3$();\n"
|
|
|
|
- "auto res = ctx->ParseGroup(tag, {parser_till_end, object}, ptr, "
|
|
|
|
- "end, "
|
|
|
|
- "&depth);\n"
|
|
|
|
- "ptr = res.first;\n"
|
|
|
|
- "$GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr);\n"
|
|
|
|
- "if (res.second) goto group_continues;\n",
|
|
|
|
- QualifiedClassName(field->message_type()),
|
|
|
|
|
|
+ "ptr = ctx->ParseGroup($1$_$2$(), ptr, tag);\n"
|
|
|
|
+ "$GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr);\n",
|
|
field->is_repeated() ? "add" : "mutable", FieldName(field));
|
|
field->is_repeated() ? "add" : "mutable", FieldName(field));
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
@@ -1795,7 +1649,6 @@ class ParseLoopGenerator {
|
|
} // switch (wire_type)
|
|
} // switch (wire_type)
|
|
|
|
|
|
if (ShouldRepeat(field, wiretype)) {
|
|
if (ShouldRepeat(field, wiretype)) {
|
|
- format_("if (ptr >= end) break;\n");
|
|
|
|
uint32 x = field->number() * 8 + wiretype;
|
|
uint32 x = field->number() * 8 + wiretype;
|
|
uint64 y = 0;
|
|
uint64 y = 0;
|
|
int cnt = 0;
|
|
int cnt = 0;
|
|
@@ -1805,10 +1658,11 @@ class ParseLoopGenerator {
|
|
x >>= 7;
|
|
x >>= 7;
|
|
} while (x);
|
|
} while (x);
|
|
uint64 mask = (1ull << (cnt * 8)) - 1;
|
|
uint64 mask = (1ull << (cnt * 8)) - 1;
|
|
|
|
+ format_("if (ctx->Done(&ptr)) return ptr;\n");
|
|
format_.Outdent();
|
|
format_.Outdent();
|
|
format_(
|
|
format_(
|
|
- "} while ((::$proto_ns$::io::UnalignedLoad<$uint64$>(ptr) & $1$) == "
|
|
|
|
- "$2$ && (ptr += $3$));\n",
|
|
|
|
|
|
+ "} while (($pi_ns$::UnalignedLoad<$uint64$>(ptr)"
|
|
|
|
+ " & $1$) == $2$ && (ptr += $3$));\n",
|
|
mask, y, cnt);
|
|
mask, y, cnt);
|
|
}
|
|
}
|
|
format_("break;\n");
|
|
format_("break;\n");
|