|  | @@ -32,6 +32,7 @@
 | 
	
		
			
				|  |  |  //  Based on original Protocol Buffers design by
 | 
	
		
			
				|  |  |  //  Sanjay Ghemawat, Jeff Dean, and others.
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +#include <functional>
 | 
	
		
			
				|  |  |  #include <limits>
 | 
	
		
			
				|  |  |  #include <map>
 | 
	
		
			
				|  |  |  #include <queue>
 | 
	
	
		
			
				|  | @@ -75,7 +76,7 @@ string DotsToColons(const string& name) {
 | 
	
		
			
				|  |  |    return StringReplace(name, ".", "::", true);
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -const char* const kKeywordList[] = {  //
 | 
	
		
			
				|  |  | +static const char* const kKeywordList[] = {  //
 | 
	
		
			
				|  |  |      "NULL",
 | 
	
		
			
				|  |  |      "alignas",
 | 
	
		
			
				|  |  |      "alignof",
 | 
	
	
		
			
				|  | @@ -160,15 +161,15 @@ const char* const kKeywordList[] = {  //
 | 
	
		
			
				|  |  |      "xor",
 | 
	
		
			
				|  |  |      "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;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -std::unordered_set<string> kKeywords = MakeKeywordsMap();
 | 
	
		
			
				|  |  | +static std::unordered_set<string>& kKeywords = *MakeKeywordsMap();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  // Returns whether the provided descriptor has an extension. This includes its
 | 
	
		
			
				|  |  |  // nested types.
 | 
	
	
		
			
				|  | @@ -255,6 +256,7 @@ void SetCommonVars(const Options& options,
 | 
	
		
			
				|  |  |          "ECK";
 | 
	
		
			
				|  |  |    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +  SetIntVar(options, "int8", variables);
 | 
	
		
			
				|  |  |    SetIntVar(options, "uint8", variables);
 | 
	
		
			
				|  |  |    SetIntVar(options, "uint32", variables);
 | 
	
		
			
				|  |  |    SetIntVar(options, "uint64", variables);
 | 
	
	
		
			
				|  | @@ -910,11 +912,7 @@ FieldOptions::CType EffectiveStringCType(const FieldDescriptor* field,
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  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) {
 | 
	
	
		
			
				|  | @@ -1302,14 +1300,20 @@ class ParseLoopGenerator {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |    void GenerateParserLoop(const Descriptor* 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("kSlopBytes",
 | 
	
		
			
				|  |  | +                static_cast<int>(internal::ParseContext::kSlopBytes));
 | 
	
		
			
				|  |  |      std::map<string, string> vars;
 | 
	
		
			
				|  |  |      SetCommonVars(options_, &vars);
 | 
	
		
			
				|  |  |      format_.AddMap(vars);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      std::vector<const FieldDescriptor*> ordered_fields;
 | 
	
		
			
				|  |  |      for (auto field : FieldRange(descriptor)) {
 | 
	
		
			
				|  |  | +      if (IsProto1(descriptor->file(), options_)) {
 | 
	
		
			
				|  |  | +        if (field->number() >= (1 << 14)) continue;
 | 
	
		
			
				|  |  | +      }
 | 
	
		
			
				|  |  |        ordered_fields.push_back(field);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      std::sort(ordered_fields.begin(), ordered_fields.end(),
 | 
	
	
		
			
				|  | @@ -1318,19 +1322,11 @@ class ParseLoopGenerator {
 | 
	
		
			
				|  |  |                });
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      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"
 | 
	
		
			
				|  |  |          "    switch (tag >> 3) {\n");
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -1338,11 +1334,7 @@ class ParseLoopGenerator {
 | 
	
		
			
				|  |  |      format_.Indent();
 | 
	
		
			
				|  |  |      format_.Indent();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    bool use_handle_unusual = false;
 | 
	
		
			
				|  |  |      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.
 | 
	
		
			
				|  |  |        // We don't want to print group bodies so we cut off after the first
 | 
	
		
			
				|  |  |        // line.
 | 
	
	
		
			
				|  | @@ -1359,22 +1351,21 @@ class ParseLoopGenerator {
 | 
	
		
			
				|  |  |            "case $2$: {\n",
 | 
	
		
			
				|  |  |            def, field->number());
 | 
	
		
			
				|  |  |        format_.Indent();
 | 
	
		
			
				|  |  | -      use_handle_unusual = true;
 | 
	
		
			
				|  |  |        GenerateCaseBody(field);
 | 
	
		
			
				|  |  |        format_.Outdent();
 | 
	
		
			
				|  |  |        format_("}\n");  // case
 | 
	
		
			
				|  |  |      }                  // for fields
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    // Default case
 | 
	
		
			
				|  |  |      format_("default: {\n");
 | 
	
		
			
				|  |  | -    if (use_handle_unusual) format_("handle_unusual:\n");
 | 
	
		
			
				|  |  | +    if (!ordered_fields.empty()) format_("handle_unusual:\n");
 | 
	
		
			
				|  |  |      format_(
 | 
	
		
			
				|  |  |          "  if ((tag & 7) == 4 || tag == 0) {\n"
 | 
	
		
			
				|  |  | -        "    ctx->EndGroup(tag);\n"
 | 
	
		
			
				|  |  | +        "    ctx->SetLastTag(tag);\n"
 | 
	
		
			
				|  |  |          "    return ptr;\n"
 | 
	
		
			
				|  |  |          "  }\n");
 | 
	
		
			
				|  |  |      if (IsMapEntryMessage(descriptor)) {
 | 
	
		
			
				|  |  | -      format_(
 | 
	
		
			
				|  |  | -          "  break;\n"
 | 
	
		
			
				|  |  | -          "}\n");
 | 
	
		
			
				|  |  | +      format_("  break;\n");
 | 
	
		
			
				|  |  |      } else {
 | 
	
		
			
				|  |  |        if (descriptor->extension_range_count() > 0) {
 | 
	
		
			
				|  |  |          format_("if (");
 | 
	
	
		
			
				|  | @@ -1396,113 +1387,59 @@ class ParseLoopGenerator {
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |          format_(") {\n");
 | 
	
		
			
				|  |  |          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"
 | 
	
		
			
				|  |  | -            "  ptr = res.first;\n"
 | 
	
		
			
				|  |  |              "  $GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr != nullptr);\n"
 | 
	
		
			
				|  |  | -            "  if (res.second) return ptr;\n"
 | 
	
		
			
				|  |  | -            "  continue;\n"
 | 
	
		
			
				|  |  | +            "  break;\n"
 | 
	
		
			
				|  |  |              "}\n");
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |        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"
 | 
	
		
			
				|  |  | -          "  if (res.second) return ptr;\n"
 | 
	
		
			
				|  |  | -          "}\n");  // default case
 | 
	
		
			
				|  |  | +          "  break;\n");
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  | +    format_("}\n");  // default case
 | 
	
		
			
				|  |  |      format_.Outdent();
 | 
	
		
			
				|  |  |      format_.Outdent();
 | 
	
		
			
				|  |  |      format_.Outdent();
 | 
	
		
			
				|  |  |      format_(
 | 
	
		
			
				|  |  |          "    }  // switch\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:
 | 
	
		
			
				|  |  |    MessageSCCAnalyzer* scc_analyzer_;
 | 
	
		
			
				|  |  |    const Options& options_;
 | 
	
		
			
				|  |  |    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 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())) {
 | 
	
		
			
				|  |  | -      format_("HasBitSetters::set_has_$1$(msg);\n", FieldName(field));
 | 
	
		
			
				|  |  | +      format_("HasBitSetters::set_has_$1$(this);\n", FieldName(field));
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      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) {
 | 
	
		
			
				|  |  |      string utf8;
 | 
	
		
			
				|  |  | +    string field_name;
 | 
	
		
			
				|  |  |      if (check_utf8) {
 | 
	
		
			
				|  |  |        utf8 = GetUtf8Suffix(field, options_);
 | 
	
		
			
				|  |  |        if (!utf8.empty()) {
 | 
	
		
			
				|  |  | -        string name = "nullptr";
 | 
	
		
			
				|  |  | +        field_name = ", nullptr";
 | 
	
		
			
				|  |  |          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;
 | 
	
	
		
			
				|  | @@ -1523,73 +1460,40 @@ class ParseLoopGenerator {
 | 
	
		
			
				|  |  |          !IsProto1(field->file(), options_) &&
 | 
	
		
			
				|  |  |          !IsStringInlined(field, options_) &&
 | 
	
		
			
				|  |  |          field->containing_oneof() == nullptr && ctype == FieldOptions::STRING) {
 | 
	
		
			
				|  |  | -      GenerateArenaString(field, utf8);
 | 
	
		
			
				|  |  | +      GenerateArenaString(field, utf8, field_name);
 | 
	
		
			
				|  |  |        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 label = "len_delim_till_end";
 | 
	
		
			
				|  |  |      switch (ctype) {
 | 
	
		
			
				|  |  |        case FieldOptions::STRING:
 | 
	
		
			
				|  |  | -        name = "GreedyStringParser";
 | 
	
		
			
				|  |  | -        use_string_ = true;
 | 
	
		
			
				|  |  | -        label = "string_till_end";
 | 
	
		
			
				|  |  | +        name = "GreedyStringParser" + utf8;
 | 
	
		
			
				|  |  |          break;
 | 
	
		
			
				|  |  |        case FieldOptions::CORD:
 | 
	
		
			
				|  |  | -        name = "CordParser";
 | 
	
		
			
				|  |  | -        format_("  static_cast<::Cord*>(object)->Clear();\n");
 | 
	
		
			
				|  |  | +        name = "CordParser" + utf8;
 | 
	
		
			
				|  |  |          break;
 | 
	
		
			
				|  |  |        case FieldOptions::STRING_PIECE:
 | 
	
		
			
				|  |  | -        name = "StringPieceParser";
 | 
	
		
			
				|  |  | -        format_(
 | 
	
		
			
				|  |  | -            "  "
 | 
	
		
			
				|  |  | -            "static_cast<::$proto_ns$::internal::StringPieceField*>(object)->"
 | 
	
		
			
				|  |  | -            "Clear();\n");
 | 
	
		
			
				|  |  | +        name = "StringPieceParser" + utf8;
 | 
	
		
			
				|  |  |          break;
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      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) {
 | 
	
		
			
				|  |  | -    format_(
 | 
	
		
			
				|  |  | -        "ptr = ::$proto_ns$::io::ReadSize(ptr, &size);\n"
 | 
	
		
			
				|  |  | -        "$GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr);\n");
 | 
	
		
			
				|  |  |      if (!IsProto1(field->file(), options_) && field->is_packable()) {
 | 
	
		
			
				|  |  | +      string enum_validator;
 | 
	
		
			
				|  |  |        if (!HasPreservingUnknownEnumSemantics(field->file()) &&
 | 
	
		
			
				|  |  |            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_(
 | 
	
		
			
				|  |  | -          "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 {
 | 
	
		
			
				|  |  |        auto field_type = field->type();
 | 
	
		
			
				|  |  |        if (IsProto1(field->file(), options_)) {
 | 
	
	
		
			
				|  | @@ -1610,106 +1514,62 @@ class ParseLoopGenerator {
 | 
	
		
			
				|  |  |            GenerateStrings(field, false /* utf8 */);
 | 
	
		
			
				|  |  |            break;
 | 
	
		
			
				|  |  |          case FieldDescriptor::TYPE_MESSAGE: {
 | 
	
		
			
				|  |  | -          GOOGLE_CHECK(field->message_type());
 | 
	
		
			
				|  |  |            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) {
 | 
	
		
			
				|  |  |                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"
 | 
	
		
			
				|  |  | -                  "auto parse_closure = msg->$2$_.$1$_->_ParseClosure();\n",
 | 
	
		
			
				|  |  | +                  "ptr = ctx->ParseMessage($2$_.$1$_, ptr);\n",
 | 
	
		
			
				|  |  |                    FieldName(field), field->containing_oneof()->name());
 | 
	
		
			
				|  |  |              } else if (HasFieldPresence(field->file())) {
 | 
	
		
			
				|  |  |                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));
 | 
	
		
			
				|  |  |              } 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()) {
 | 
	
		
			
				|  |  | -              format_("object = HasBitSetters::mutable_$1$(msg);\n",
 | 
	
		
			
				|  |  | -                      FieldName(field));
 | 
	
		
			
				|  |  | +              format_(
 | 
	
		
			
				|  |  | +                  "ptr = ctx->ParseMessage(HasBitSetters::mutable_$1$(this), "
 | 
	
		
			
				|  |  | +                  "ptr);\n",
 | 
	
		
			
				|  |  | +                  FieldName(field));
 | 
	
		
			
				|  |  |              } else {
 | 
	
		
			
				|  |  |                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()),
 | 
	
		
			
				|  |  |                    ClassName(field->message_type()));
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  | -            format_(
 | 
	
		
			
				|  |  | -                "parser_till_end = static_cast<::$proto_ns$::MessageLite*>("
 | 
	
		
			
				|  |  | -                "object)->_ParseFunc();\n");
 | 
	
		
			
				|  |  |            } else if (IsWeak(field, 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 {
 | 
	
		
			
				|  |  |                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));
 | 
	
		
			
				|  |  |              }
 | 
	
		
			
				|  |  | -            format_(
 | 
	
		
			
				|  |  | -                "parser_till_end = static_cast<::$proto_ns$::MessageLite*>("
 | 
	
		
			
				|  |  | -                "object)->_ParseFunc();\n");
 | 
	
		
			
				|  |  |            } 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;
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |          default:
 | 
	
	
		
			
				|  | @@ -1731,31 +1591,33 @@ class ParseLoopGenerator {
 | 
	
		
			
				|  |  |          string prefix = field->is_repeated() ? "add" : "set";
 | 
	
		
			
				|  |  |          if (field->type() == FieldDescriptor::TYPE_ENUM &&
 | 
	
		
			
				|  |  |              !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())) {
 | 
	
		
			
				|  |  |              format_(
 | 
	
		
			
				|  |  |                  "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"
 | 
	
		
			
				|  |  |                  "}\n",
 | 
	
		
			
				|  |  |                  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 {
 | 
	
		
			
				|  |  | +          int size = field->type() == FieldDescriptor::TYPE_SINT32 ? 32 : 64;
 | 
	
		
			
				|  |  |            string zigzag;
 | 
	
		
			
				|  |  |            if ((field->type() == FieldDescriptor::TYPE_SINT32 ||
 | 
	
		
			
				|  |  |                 field->type() == FieldDescriptor::TYPE_SINT64) &&
 | 
	
		
			
				|  |  |                !IsProto1(field->file(), options_)) {
 | 
	
		
			
				|  |  | -            int size = field->type() == FieldDescriptor::TYPE_SINT32 ? 32 : 64;
 | 
	
		
			
				|  |  |              zigzag = StrCat("ZigZag", size);
 | 
	
		
			
				|  |  |            }
 | 
	
		
			
				|  |  |            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);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  | -        format_("$GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr);\n");
 | 
	
		
			
				|  |  |          break;
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |        case WireFormatLite::WIRETYPE_FIXED32:
 | 
	
	
		
			
				|  | @@ -1763,28 +1625,20 @@ class ParseLoopGenerator {
 | 
	
		
			
				|  |  |          string prefix = field->is_repeated() ? "add" : "set";
 | 
	
		
			
				|  |  |          string type = PrimitiveTypeName(options_, field->cpp_type());
 | 
	
		
			
				|  |  |          format_(
 | 
	
		
			
				|  |  | -            "msg->$1$_$2$(::$proto_ns$::io::UnalignedLoad<$3$>(ptr));\n"
 | 
	
		
			
				|  |  | +            "$1$_$2$($pi_ns$::UnalignedLoad<$3$>(ptr));\n"
 | 
	
		
			
				|  |  |              "ptr += sizeof($3$);\n",
 | 
	
		
			
				|  |  |              prefix, FieldName(field), type);
 | 
	
		
			
				|  |  |          break;
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |        case WireFormatLite::WIRETYPE_LENGTH_DELIMITED: {
 | 
	
		
			
				|  |  | -        use_length_delimited_ = true;
 | 
	
		
			
				|  |  |          GenerateLengthDelim(field);
 | 
	
		
			
				|  |  | +        format_("$GOOGLE_PROTOBUF$_PARSER_ASSERT(ptr);\n");
 | 
	
		
			
				|  |  |          break;
 | 
	
		
			
				|  |  |        }
 | 
	
		
			
				|  |  |        case WireFormatLite::WIRETYPE_START_GROUP: {
 | 
	
		
			
				|  |  | -        use_group_ = true;
 | 
	
		
			
				|  |  |          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));
 | 
	
		
			
				|  |  |          break;
 | 
	
		
			
				|  |  |        }
 | 
	
	
		
			
				|  | @@ -1795,7 +1649,6 @@ class ParseLoopGenerator {
 | 
	
		
			
				|  |  |      }  // switch (wire_type)
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      if (ShouldRepeat(field, wiretype)) {
 | 
	
		
			
				|  |  | -      format_("if (ptr >= end) break;\n");
 | 
	
		
			
				|  |  |        uint32 x = field->number() * 8 + wiretype;
 | 
	
		
			
				|  |  |        uint64 y = 0;
 | 
	
		
			
				|  |  |        int cnt = 0;
 | 
	
	
		
			
				|  | @@ -1805,10 +1658,11 @@ class ParseLoopGenerator {
 | 
	
		
			
				|  |  |          x >>= 7;
 | 
	
		
			
				|  |  |        } while (x);
 | 
	
		
			
				|  |  |        uint64 mask = (1ull << (cnt * 8)) - 1;
 | 
	
		
			
				|  |  | +      format_("if (ctx->Done(&ptr)) return ptr;\n");
 | 
	
		
			
				|  |  |        format_.Outdent();
 | 
	
		
			
				|  |  |        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);
 | 
	
		
			
				|  |  |      }
 | 
	
		
			
				|  |  |      format_("break;\n");
 |