Merge pull request #8499 from haberman/sync-stage
Integrate from Piper for C++, Java, and Pythonpull/8504/head
commit
6051341ab2
63 changed files with 1543 additions and 1048 deletions
@ -0,0 +1,580 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <google/protobuf/compiler/cpp/cpp_parse_function_generator.h> |
||||
|
||||
#include <google/protobuf/wire_format.h> |
||||
#include <google/protobuf/wire_format_lite.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace cpp { |
||||
|
||||
namespace { |
||||
using google::protobuf::internal::WireFormat; |
||||
using google::protobuf::internal::WireFormatLite; |
||||
|
||||
std::vector<const FieldDescriptor*> GetOrderedFields( |
||||
const Descriptor* descriptor, const Options& options) { |
||||
std::vector<const FieldDescriptor*> ordered_fields; |
||||
for (auto field : FieldRange(descriptor)) { |
||||
if (!IsFieldStripped(field, options)) { |
||||
ordered_fields.push_back(field); |
||||
} |
||||
} |
||||
std::sort(ordered_fields.begin(), ordered_fields.end(), |
||||
[](const FieldDescriptor* a, const FieldDescriptor* b) { |
||||
return a->number() < b->number(); |
||||
}); |
||||
return ordered_fields; |
||||
} |
||||
|
||||
bool HasInternalAccessors(const FieldOptions::CType ctype) { |
||||
return ctype == FieldOptions::STRING || ctype == FieldOptions::CORD; |
||||
} |
||||
|
||||
class ParseFunctionGenerator { |
||||
public: |
||||
ParseFunctionGenerator(const Descriptor* descriptor, int num_hasbits, |
||||
const Options& options, |
||||
MessageSCCAnalyzer* scc_analyzer, io::Printer* printer) |
||||
: descriptor_(descriptor), |
||||
scc_analyzer_(scc_analyzer), |
||||
options_(options), |
||||
format_(printer), |
||||
num_hasbits_(num_hasbits) { |
||||
format_.Set("classname", ClassName(descriptor)); |
||||
format_.Set("p_ns", "::" + ProtobufNamespace(options_)); |
||||
format_.Set("pi_ns", |
||||
StrCat("::", ProtobufNamespace(options_), "::internal")); |
||||
format_.Set("GOOGLE_PROTOBUF", MacroPrefix(options_)); |
||||
std::map<std::string, std::string> vars; |
||||
SetCommonVars(options_, &vars); |
||||
SetUnknkownFieldsVariable(descriptor, options_, &vars); |
||||
format_.AddMap(vars); |
||||
} |
||||
|
||||
void GenerateLoopingParseFunction() { |
||||
format_( |
||||
"const char* $classname$::_InternalParse(const char* ptr, " |
||||
"$pi_ns$::ParseContext* ctx) {\n" |
||||
"#define CHK_(x) if (PROTOBUF_PREDICT_FALSE(!(x))) goto failure\n"); |
||||
format_.Indent(); |
||||
int hasbits_size = 0; |
||||
if (num_hasbits_ > 0) { |
||||
hasbits_size = (num_hasbits_ + 31) / 32; |
||||
} |
||||
// For now only optimize small hasbits.
|
||||
if (hasbits_size != 1) hasbits_size = 0; |
||||
if (hasbits_size) { |
||||
format_("_Internal::HasBits has_bits{};\n"); |
||||
format_.Set("has_bits", "has_bits"); |
||||
} else { |
||||
format_.Set("has_bits", "_has_bits_"); |
||||
} |
||||
format_.Set("continue", "continue"); |
||||
format_("while (!ctx->Done(&ptr)) {\n"); |
||||
format_.Indent(); |
||||
|
||||
GenerateParseIterationBody(descriptor_, |
||||
GetOrderedFields(descriptor_, options_)); |
||||
|
||||
format_.Outdent(); |
||||
format_("} // while\n"); |
||||
|
||||
format_.Outdent(); |
||||
format_("success:\n"); |
||||
if (hasbits_size) format_(" _has_bits_.Or(has_bits);\n"); |
||||
|
||||
format_( |
||||
" return ptr;\n" |
||||
"failure:\n" |
||||
" ptr = nullptr;\n" |
||||
" goto success;\n" |
||||
"#undef CHK_\n" |
||||
"}\n"); |
||||
} |
||||
|
||||
private: |
||||
const Descriptor* descriptor_; |
||||
MessageSCCAnalyzer* scc_analyzer_; |
||||
const Options& options_; |
||||
Formatter format_; |
||||
int num_hasbits_; |
||||
|
||||
void GenerateArenaString(const FieldDescriptor* field) { |
||||
if (HasHasbit(field)) { |
||||
format_("_Internal::set_has_$1$(&$has_bits$);\n", FieldName(field)); |
||||
} |
||||
std::string default_string = |
||||
field->default_value_string().empty() |
||||
? "::" + ProtobufNamespace(options_) + |
||||
"::internal::GetEmptyStringAlreadyInited()" |
||||
: QualifiedClassName(field->containing_type(), options_) + |
||||
"::" + MakeDefaultName(field) + ".get()"; |
||||
format_( |
||||
"if (arena != nullptr) {\n" |
||||
" ptr = ctx->ReadArenaString(ptr, &$1$_, arena);\n" |
||||
"} else {\n" |
||||
" ptr = " |
||||
"$pi_ns$::InlineGreedyStringParser($1$_.MutableNoArenaNoDefault(&$2$" |
||||
"), ptr, ctx);" |
||||
"\n}\n" |
||||
"const std::string* str = &$1$_.Get(); (void)str;\n", |
||||
FieldName(field), default_string); |
||||
} |
||||
|
||||
void GenerateStrings(const FieldDescriptor* field, bool check_utf8) { |
||||
FieldOptions::CType ctype = FieldOptions::STRING; |
||||
if (!options_.opensource_runtime) { |
||||
// Open source doesn't support other ctypes;
|
||||
ctype = field->options().ctype(); |
||||
} |
||||
if (!field->is_repeated() && !options_.opensource_runtime && |
||||
GetOptimizeFor(field->file(), options_) != FileOptions::LITE_RUNTIME && |
||||
// For now only use arena string for strings with empty defaults.
|
||||
field->default_value_string().empty() && |
||||
!field->real_containing_oneof() && ctype == FieldOptions::STRING) { |
||||
GenerateArenaString(field); |
||||
} else { |
||||
std::string name; |
||||
switch (ctype) { |
||||
case FieldOptions::STRING: |
||||
name = "GreedyStringParser"; |
||||
break; |
||||
case FieldOptions::CORD: |
||||
name = "CordParser"; |
||||
break; |
||||
case FieldOptions::STRING_PIECE: |
||||
name = "StringPieceParser"; |
||||
break; |
||||
} |
||||
format_( |
||||
"auto str = $1$$2$_$3$();\n" |
||||
"ptr = $pi_ns$::Inline$4$(str, ptr, ctx);\n", |
||||
HasInternalAccessors(ctype) ? "_internal_" : "", |
||||
field->is_repeated() && !field->is_packable() ? "add" : "mutable", |
||||
FieldName(field), name); |
||||
} |
||||
if (!check_utf8) return; // return if this is a bytes field
|
||||
auto level = GetUtf8CheckMode(field, options_); |
||||
switch (level) { |
||||
case Utf8CheckMode::kNone: |
||||
return; |
||||
case Utf8CheckMode::kVerify: |
||||
format_("#ifndef NDEBUG\n"); |
||||
break; |
||||
case Utf8CheckMode::kStrict: |
||||
format_("CHK_("); |
||||
break; |
||||
} |
||||
std::string field_name; |
||||
field_name = "nullptr"; |
||||
if (HasDescriptorMethods(field->file(), options_)) { |
||||
field_name = StrCat("\"", field->full_name(), "\""); |
||||
} |
||||
format_("$pi_ns$::VerifyUTF8(str, $1$)", field_name); |
||||
switch (level) { |
||||
case Utf8CheckMode::kNone: |
||||
return; |
||||
case Utf8CheckMode::kVerify: |
||||
format_( |
||||
";\n" |
||||
"#endif // !NDEBUG\n"); |
||||
break; |
||||
case Utf8CheckMode::kStrict: |
||||
format_(");\n"); |
||||
break; |
||||
} |
||||
} |
||||
|
||||
void GenerateLengthDelim(const FieldDescriptor* field) { |
||||
if (field->is_packable()) { |
||||
std::string enum_validator; |
||||
if (field->type() == FieldDescriptor::TYPE_ENUM && |
||||
!HasPreservingUnknownEnumSemantics(field)) { |
||||
enum_validator = |
||||
StrCat(", ", QualifiedClassName(field->enum_type(), options_), |
||||
"_IsValid, &_internal_metadata_, ", field->number()); |
||||
format_( |
||||
"ptr = " |
||||
"$pi_ns$::Packed$1$Parser<$unknown_fields_type$>(_internal_mutable_" |
||||
"$2$(), ptr, " |
||||
"ctx$3$);\n", |
||||
DeclaredTypeMethodName(field->type()), FieldName(field), |
||||
enum_validator); |
||||
} else { |
||||
format_( |
||||
"ptr = $pi_ns$::Packed$1$Parser(_internal_mutable_$2$(), ptr, " |
||||
"ctx$3$);\n", |
||||
DeclaredTypeMethodName(field->type()), FieldName(field), |
||||
enum_validator); |
||||
} |
||||
} else { |
||||
auto field_type = field->type(); |
||||
switch (field_type) { |
||||
case FieldDescriptor::TYPE_STRING: |
||||
GenerateStrings(field, true /* utf8 */); |
||||
break; |
||||
case FieldDescriptor::TYPE_BYTES: |
||||
GenerateStrings(field, false /* utf8 */); |
||||
break; |
||||
case FieldDescriptor::TYPE_MESSAGE: { |
||||
if (field->is_map()) { |
||||
const FieldDescriptor* val = |
||||
field->message_type()->FindFieldByName("value"); |
||||
GOOGLE_CHECK(val); |
||||
if (val->type() == FieldDescriptor::TYPE_ENUM && |
||||
!HasPreservingUnknownEnumSemantics(field)) { |
||||
format_( |
||||
"auto object = " |
||||
"::$proto_ns$::internal::InitEnumParseWrapper<$unknown_" |
||||
"fields_type$>(" |
||||
"&$1$_, $2$_IsValid, $3$, &_internal_metadata_);\n" |
||||
"ptr = ctx->ParseMessage(&object, ptr);\n", |
||||
FieldName(field), QualifiedClassName(val->enum_type()), |
||||
field->number()); |
||||
} else { |
||||
format_("ptr = ctx->ParseMessage(&$1$_, ptr);\n", |
||||
FieldName(field)); |
||||
} |
||||
} else if (IsLazy(field, options_)) { |
||||
if (field->real_containing_oneof()) { |
||||
format_( |
||||
"if (!_internal_has_$1$()) {\n" |
||||
" clear_$2$();\n" |
||||
" $2$_.$1$_ = ::$proto_ns$::Arena::CreateMessage<\n" |
||||
" $pi_ns$::LazyField>(GetArena());\n" |
||||
" set_has_$1$();\n" |
||||
"}\n" |
||||
"ptr = ctx->ParseMessage($2$_.$1$_, ptr);\n", |
||||
FieldName(field), field->containing_oneof()->name()); |
||||
} else if (HasHasbit(field)) { |
||||
format_( |
||||
"_Internal::set_has_$1$(&$has_bits$);\n" |
||||
"ptr = ctx->ParseMessage(&$1$_, ptr);\n", |
||||
FieldName(field)); |
||||
} else { |
||||
format_("ptr = ctx->ParseMessage(&$1$_, ptr);\n", |
||||
FieldName(field)); |
||||
} |
||||
} else if (IsImplicitWeakField(field, options_, scc_analyzer_)) { |
||||
if (!field->is_repeated()) { |
||||
format_( |
||||
"ptr = ctx->ParseMessage(_Internal::mutable_$1$(this), " |
||||
"ptr);\n", |
||||
FieldName(field)); |
||||
} else { |
||||
format_( |
||||
"ptr = ctx->ParseMessage($1$_.AddWeak(reinterpret_cast<const " |
||||
"::$proto_ns$::MessageLite*>($2$::_$3$_default_instance_ptr_)" |
||||
"), ptr);\n", |
||||
FieldName(field), Namespace(field->message_type(), options_), |
||||
ClassName(field->message_type())); |
||||
} |
||||
} else if (IsWeak(field, options_)) { |
||||
format_( |
||||
"{\n" |
||||
" auto* default_ = &reinterpret_cast<const Message&>($1$);\n" |
||||
" ptr = ctx->ParseMessage(_weak_field_map_.MutableMessage($2$," |
||||
" default_), ptr);\n" |
||||
"}\n", |
||||
QualifiedDefaultInstanceName(field->message_type(), options_), |
||||
field->number()); |
||||
} else { |
||||
format_("ptr = ctx->ParseMessage(_internal_$1$_$2$(), ptr);\n", |
||||
field->is_repeated() ? "add" : "mutable", FieldName(field)); |
||||
} |
||||
break; |
||||
} |
||||
default: |
||||
GOOGLE_LOG(FATAL) << "Illegal combination for length delimited wiretype " |
||||
<< " filed type is " << field->type(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Convert a 1 or 2 byte varint into the equivalent value upon a direct load.
|
||||
static uint32_t SmallVarintValue(uint32_t x) { |
||||
GOOGLE_DCHECK(x < 128 * 128); |
||||
if (x >= 128) x += (x & 0xFF80) + 128; |
||||
return x; |
||||
} |
||||
|
||||
static bool ShouldRepeat(const FieldDescriptor* descriptor, |
||||
internal::WireFormatLite::WireType wiretype) { |
||||
constexpr int kMaxTwoByteFieldNumber = 16 * 128; |
||||
return descriptor->number() < kMaxTwoByteFieldNumber && |
||||
descriptor->is_repeated() && |
||||
(!descriptor->is_packable() || |
||||
wiretype != internal::WireFormatLite::WIRETYPE_LENGTH_DELIMITED); |
||||
} |
||||
|
||||
void GenerateFieldBody(internal::WireFormatLite::WireType wiretype, |
||||
const FieldDescriptor* field) { |
||||
uint32_t tag = WireFormatLite::MakeTag(field->number(), wiretype); |
||||
switch (wiretype) { |
||||
case WireFormatLite::WIRETYPE_VARINT: { |
||||
std::string type = PrimitiveTypeName(options_, field->cpp_type()); |
||||
std::string prefix = field->is_repeated() ? "add" : "set"; |
||||
if (field->type() == FieldDescriptor::TYPE_ENUM) { |
||||
format_( |
||||
"$uint64$ val = $pi_ns$::ReadVarint64(&ptr);\n" |
||||
"CHK_(ptr);\n"); |
||||
if (!HasPreservingUnknownEnumSemantics(field)) { |
||||
format_("if (PROTOBUF_PREDICT_TRUE($1$_IsValid(val))) {\n", |
||||
QualifiedClassName(field->enum_type(), options_)); |
||||
format_.Indent(); |
||||
} |
||||
format_("_internal_$1$_$2$(static_cast<$3$>(val));\n", prefix, |
||||
FieldName(field), |
||||
QualifiedClassName(field->enum_type(), options_)); |
||||
if (!HasPreservingUnknownEnumSemantics(field)) { |
||||
format_.Outdent(); |
||||
format_( |
||||
"} else {\n" |
||||
" $pi_ns$::WriteVarint($1$, val, mutable_unknown_fields());\n" |
||||
"}\n", |
||||
field->number()); |
||||
} |
||||
} else { |
||||
std::string size = (field->type() == FieldDescriptor::TYPE_SINT32 || |
||||
field->type() == FieldDescriptor::TYPE_UINT32) |
||||
? "32" |
||||
: "64"; |
||||
std::string zigzag; |
||||
if ((field->type() == FieldDescriptor::TYPE_SINT32 || |
||||
field->type() == FieldDescriptor::TYPE_SINT64)) { |
||||
zigzag = "ZigZag"; |
||||
} |
||||
if (field->is_repeated() || field->real_containing_oneof()) { |
||||
std::string prefix = field->is_repeated() ? "add" : "set"; |
||||
format_( |
||||
"_internal_$1$_$2$($pi_ns$::ReadVarint$3$$4$(&ptr));\n" |
||||
"CHK_(ptr);\n", |
||||
prefix, FieldName(field), zigzag, size); |
||||
} else { |
||||
if (HasHasbit(field)) { |
||||
format_("_Internal::set_has_$1$(&$has_bits$);\n", |
||||
FieldName(field)); |
||||
} |
||||
format_( |
||||
"$1$_ = $pi_ns$::ReadVarint$2$$3$(&ptr);\n" |
||||
"CHK_(ptr);\n", |
||||
FieldName(field), zigzag, size); |
||||
} |
||||
} |
||||
break; |
||||
} |
||||
case WireFormatLite::WIRETYPE_FIXED32: |
||||
case WireFormatLite::WIRETYPE_FIXED64: { |
||||
std::string type = PrimitiveTypeName(options_, field->cpp_type()); |
||||
if (field->is_repeated() || field->real_containing_oneof()) { |
||||
std::string prefix = field->is_repeated() ? "add" : "set"; |
||||
format_( |
||||
"_internal_$1$_$2$($pi_ns$::UnalignedLoad<$3$>(ptr));\n" |
||||
"ptr += sizeof($3$);\n", |
||||
prefix, FieldName(field), type); |
||||
} else { |
||||
if (HasHasbit(field)) { |
||||
format_("_Internal::set_has_$1$(&$has_bits$);\n", FieldName(field)); |
||||
} |
||||
format_( |
||||
"$1$_ = $pi_ns$::UnalignedLoad<$2$>(ptr);\n" |
||||
"ptr += sizeof($2$);\n", |
||||
FieldName(field), type); |
||||
} |
||||
break; |
||||
} |
||||
case WireFormatLite::WIRETYPE_LENGTH_DELIMITED: { |
||||
GenerateLengthDelim(field); |
||||
format_("CHK_(ptr);\n"); |
||||
break; |
||||
} |
||||
case WireFormatLite::WIRETYPE_START_GROUP: { |
||||
format_( |
||||
"ptr = ctx->ParseGroup(_internal_$1$_$2$(), ptr, $3$);\n" |
||||
"CHK_(ptr);\n", |
||||
field->is_repeated() ? "add" : "mutable", FieldName(field), tag); |
||||
break; |
||||
} |
||||
case WireFormatLite::WIRETYPE_END_GROUP: { |
||||
GOOGLE_LOG(FATAL) << "Can't have end group field\n"; |
||||
break; |
||||
} |
||||
} // switch (wire_type)
|
||||
} |
||||
|
||||
// Returns the tag for this field and in case of repeated packable fields,
|
||||
// sets a fallback tag in fallback_tag_ptr.
|
||||
static uint32_t ExpectedTag(const FieldDescriptor* field, |
||||
uint32_t* fallback_tag_ptr) { |
||||
uint32_t expected_tag; |
||||
if (field->is_packable()) { |
||||
auto expected_wiretype = WireFormat::WireTypeForFieldType(field->type()); |
||||
expected_tag = |
||||
WireFormatLite::MakeTag(field->number(), expected_wiretype); |
||||
GOOGLE_CHECK(expected_wiretype != WireFormatLite::WIRETYPE_LENGTH_DELIMITED); |
||||
auto fallback_wiretype = WireFormatLite::WIRETYPE_LENGTH_DELIMITED; |
||||
uint32_t fallback_tag = |
||||
WireFormatLite::MakeTag(field->number(), fallback_wiretype); |
||||
|
||||
if (field->is_packed()) std::swap(expected_tag, fallback_tag); |
||||
*fallback_tag_ptr = fallback_tag; |
||||
} else { |
||||
auto expected_wiretype = WireFormat::WireTypeForField(field); |
||||
expected_tag = |
||||
WireFormatLite::MakeTag(field->number(), expected_wiretype); |
||||
} |
||||
return expected_tag; |
||||
} |
||||
|
||||
void GenerateParseIterationBody( |
||||
const Descriptor* descriptor, |
||||
const std::vector<const FieldDescriptor*>& ordered_fields) { |
||||
format_( |
||||
"$uint32$ tag;\n" |
||||
"ptr = $pi_ns$::ReadTag(ptr, &tag);\n"); |
||||
if (!ordered_fields.empty()) format_("switch (tag >> 3) {\n"); |
||||
|
||||
format_.Indent(); |
||||
|
||||
for (const auto* field : ordered_fields) { |
||||
PrintFieldComment(format_, field); |
||||
format_("case $1$:\n", field->number()); |
||||
format_.Indent(); |
||||
uint32_t fallback_tag = 0; |
||||
uint32_t expected_tag = ExpectedTag(field, &fallback_tag); |
||||
format_( |
||||
"if (PROTOBUF_PREDICT_TRUE(static_cast<$uint8$>(tag) == $1$)) {\n", |
||||
expected_tag & 0xFF); |
||||
format_.Indent(); |
||||
auto wiretype = WireFormatLite::GetTagWireType(expected_tag); |
||||
uint32_t tag = WireFormatLite::MakeTag(field->number(), wiretype); |
||||
int tag_size = io::CodedOutputStream::VarintSize32(tag); |
||||
bool is_repeat = ShouldRepeat(field, wiretype); |
||||
if (is_repeat) { |
||||
format_( |
||||
"ptr -= $1$;\n" |
||||
"do {\n" |
||||
" ptr += $1$;\n", |
||||
tag_size); |
||||
format_.Indent(); |
||||
} |
||||
GenerateFieldBody(wiretype, field); |
||||
if (is_repeat) { |
||||
format_.Outdent(); |
||||
format_( |
||||
" if (!ctx->DataAvailable(ptr)) break;\n" |
||||
"} while ($pi_ns$::ExpectTag<$1$>(ptr));\n", |
||||
tag); |
||||
} |
||||
format_.Outdent(); |
||||
if (fallback_tag) { |
||||
format_("} else if (static_cast<$uint8$>(tag) == $1$) {\n", |
||||
fallback_tag & 0xFF); |
||||
format_.Indent(); |
||||
GenerateFieldBody(WireFormatLite::GetTagWireType(fallback_tag), field); |
||||
format_.Outdent(); |
||||
} |
||||
format_.Outdent(); |
||||
format_( |
||||
" } else goto handle_unusual;\n" |
||||
" $continue$;\n"); |
||||
} // for loop over ordered fields
|
||||
|
||||
// Default case
|
||||
if (!ordered_fields.empty()) format_("default: {\n"); |
||||
if (!ordered_fields.empty()) format_("handle_unusual:\n"); |
||||
format_( |
||||
" if ((tag == 0) || ((tag & 7) == 4)) {\n" |
||||
" CHK_(ptr);\n" |
||||
" ctx->SetLastTag(tag);\n" |
||||
" goto success;\n" |
||||
" }\n"); |
||||
if (IsMapEntryMessage(descriptor)) { |
||||
format_(" $continue$;\n"); |
||||
} else { |
||||
if (descriptor->extension_range_count() > 0) { |
||||
format_("if ("); |
||||
for (int i = 0; i < descriptor->extension_range_count(); i++) { |
||||
const Descriptor::ExtensionRange* range = |
||||
descriptor->extension_range(i); |
||||
if (i > 0) format_(" ||\n "); |
||||
|
||||
uint32_t start_tag = WireFormatLite::MakeTag( |
||||
range->start, static_cast<WireFormatLite::WireType>(0)); |
||||
uint32_t end_tag = WireFormatLite::MakeTag( |
||||
range->end, static_cast<WireFormatLite::WireType>(0)); |
||||
|
||||
if (range->end > FieldDescriptor::kMaxNumber) { |
||||
format_("($1$u <= tag)", start_tag); |
||||
} else { |
||||
format_("($1$u <= tag && tag < $2$u)", start_tag, end_tag); |
||||
} |
||||
} |
||||
format_(") {\n"); |
||||
format_( |
||||
" ptr = _extensions_.ParseField(tag, ptr,\n" |
||||
" internal_default_instance(), &_internal_metadata_, ctx);\n" |
||||
" CHK_(ptr != nullptr);\n" |
||||
" $continue$;\n" |
||||
"}\n"); |
||||
} |
||||
format_( |
||||
" ptr = UnknownFieldParse(tag,\n" |
||||
" _internal_metadata_.mutable_unknown_fields<$unknown_" |
||||
"fields_type$>(),\n" |
||||
" ptr, ctx);\n" |
||||
" CHK_(ptr != nullptr);\n" |
||||
" $continue$;\n"); |
||||
} |
||||
if (!ordered_fields.empty()) format_("}\n"); // default case
|
||||
format_.Outdent(); |
||||
if (!ordered_fields.empty()) format_("} // switch\n"); |
||||
} |
||||
}; |
||||
|
||||
} // namespace
|
||||
|
||||
void GenerateParseFunction(const Descriptor* descriptor, int num_hasbits, |
||||
const Options& options, |
||||
MessageSCCAnalyzer* scc_analyzer, |
||||
io::Printer* printer) { |
||||
ParseFunctionGenerator generator(descriptor, num_hasbits, options, |
||||
scc_analyzer, printer); |
||||
generator.GenerateLoopingParseFunction(); |
||||
} |
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
@ -0,0 +1,54 @@ |
||||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_PARSE_FUNCTION_GENERATOR_H__ |
||||
#define GOOGLE_PROTOBUF_COMPILER_CPP_PARSE_FUNCTION_GENERATOR_H__ |
||||
|
||||
#include <google/protobuf/compiler/cpp/cpp_helpers.h> |
||||
#include <google/protobuf/compiler/cpp/cpp_options.h> |
||||
#include <google/protobuf/io/printer.h> |
||||
#include <google/protobuf/descriptor.h> |
||||
|
||||
namespace google { |
||||
namespace protobuf { |
||||
namespace compiler { |
||||
namespace cpp { |
||||
|
||||
void GenerateParseFunction(const Descriptor* descriptor, int num_hasbits, |
||||
const Options& options, |
||||
MessageSCCAnalyzer* scc_analyzer, |
||||
io::Printer* printer); |
||||
|
||||
} // namespace cpp
|
||||
} // namespace compiler
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_PARSE_FUNCTION_GENERATOR_H__
|
Loading…
Reference in new issue