aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am1
-rw-r--r--src/google/protobuf/compiler/command_line_interface.cc3
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_enum_field.cc91
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message.cc25
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message_field.cc10
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_primitive_field.cc82
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_string_field.cc10
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto8
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_unittest.cc8
-rw-r--r--src/google/protobuf/compiler/java/java_enum.cc3
-rw-r--r--src/google/protobuf/compiler/java/java_enum_field.cc86
-rw-r--r--src/google/protobuf/compiler/java/java_message.cc12
-rw-r--r--src/google/protobuf/compiler/java/java_message_field.cc9
-rw-r--r--src/google/protobuf/compiler/java/java_primitive_field.cc155
-rw-r--r--src/google/protobuf/compiler/python/python_generator.cc1
-rw-r--r--src/google/protobuf/descriptor.cc344
-rw-r--r--src/google/protobuf/descriptor.h50
-rw-r--r--src/google/protobuf/descriptor.pb.cc211
-rw-r--r--src/google/protobuf/descriptor.pb.h37
-rw-r--r--src/google/protobuf/descriptor.proto6
-rw-r--r--src/google/protobuf/descriptor_unittest.cc245
-rw-r--r--src/google/protobuf/dynamic_message_unittest.cc16
-rw-r--r--src/google/protobuf/extension_set_unittest.cc25
-rw-r--r--src/google/protobuf/io/coded_stream.cc28
-rw-r--r--src/google/protobuf/io/coded_stream.h28
-rw-r--r--src/google/protobuf/io/coded_stream_unittest.cc70
-rw-r--r--src/google/protobuf/message.cc26
-rw-r--r--src/google/protobuf/message.h8
-rw-r--r--src/google/protobuf/message_unittest.cc32
-rw-r--r--src/google/protobuf/test_util.cc479
-rw-r--r--src/google/protobuf/test_util.h25
-rw-r--r--src/google/protobuf/unittest.proto40
-rw-r--r--src/google/protobuf/unknown_field_set.cc40
-rw-r--r--src/google/protobuf/unknown_field_set.h152
-rw-r--r--src/google/protobuf/unknown_field_set_unittest.cc86
-rw-r--r--src/google/protobuf/wire_format.cc316
-rw-r--r--src/google/protobuf/wire_format.h42
-rw-r--r--src/google/protobuf/wire_format_inl.h100
-rw-r--r--src/google/protobuf/wire_format_unittest.cc55
39 files changed, 2551 insertions, 414 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index c13a723e..18167482 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -160,6 +160,7 @@ EXTRA_DIST = \
$(protoc_inputs) \
solaris/libstdc++.la \
google/protobuf/testdata/golden_message \
+ google/protobuf/testdata/golden_packed_fields_message \
google/protobuf/testdata/text_format_unittest_data.txt \
google/protobuf/testdata/text_format_unittest_extensions_data.txt \
google/protobuf/package_info.h \
diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc
index 089844f4..09473ec7 100644
--- a/src/google/protobuf/compiler/command_line_interface.cc
+++ b/src/google/protobuf/compiler/command_line_interface.cc
@@ -751,7 +751,8 @@ bool CommandLineInterface::GenerateOutput(
if (!output_directive.generator->Generate(
parsed_file, output_directive.parameter, &output_directory, &error)) {
// Generator returned an error.
- cerr << output_directive.name << ": " << error << endl;
+ cerr << parsed_file->name() << ": " << output_directive.name << ": "
+ << error << endl;
return false;
}
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
index c998f20b..19779a8a 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
@@ -158,7 +158,13 @@ RepeatedEnumFieldGenerator::~RepeatedEnumFieldGenerator() {}
void RepeatedEnumFieldGenerator::
GeneratePrivateMembers(io::Printer* printer) const {
- printer->Print(variables_, "::google::protobuf::RepeatedField<int> $name$_;\n");
+ printer->Print(variables_,
+ "::google::protobuf::RepeatedField<int> $name$_;\n");
+ if (descriptor_->options().packed() &&
+ descriptor_->file()->options().optimize_for() == FileOptions::SPEED) {
+ printer->Print(variables_,
+ "mutable int _$name$_cached_byte_size_;\n");
+ }
}
void RepeatedEnumFieldGenerator::
@@ -217,31 +223,84 @@ GenerateInitializer(io::Printer* printer) const {
void RepeatedEnumFieldGenerator::
GenerateMergeFromCodedStream(io::Printer* printer) const {
- printer->Print(variables_,
- "int value;\n"
- "DO_(::google::protobuf::internal::WireFormat::ReadEnum(input, &value));\n"
- "if ($type$_IsValid(value)) {\n"
- " add_$name$(static_cast< $type$ >(value));\n"
- "} else {\n"
- " mutable_unknown_fields()->AddField($number$)->add_varint(value);\n"
- "}\n");
+ if (descriptor_->options().packed()) {
+ printer->Print(variables_,
+ "::google::protobuf::uint32 length;\n"
+ "DO_(input->ReadVarint32(&length));\n"
+ "::google::protobuf::io::CodedInputStream::Limit limit = "
+ "input->PushLimit(length);\n"
+ "while (input->BytesUntilLimit() > 0) {\n"
+ " int value;\n"
+ " DO_(::google::protobuf::internal::WireFormat::ReadEnum(input, &value));\n"
+ " if ($type$_IsValid(value)) {\n"
+ " add_$name$(static_cast< $type$ >(value));\n"
+ " }\n"
+ "}\n"
+ "input->PopLimit(limit);\n");
+ } else {
+ printer->Print(variables_,
+ "int value;\n"
+ "DO_(::google::protobuf::internal::WireFormat::ReadEnum(input, &value));\n"
+ "if ($type$_IsValid(value)) {\n"
+ " add_$name$(static_cast< $type$ >(value));\n"
+ "} else {\n"
+ " mutable_unknown_fields()->AddField($number$)->add_varint(value);\n"
+ "}\n");
+ }
}
void RepeatedEnumFieldGenerator::
GenerateSerializeWithCachedSizes(io::Printer* printer) const {
+ if (descriptor_->options().packed()) {
+ // Write the tag and the size.
+ printer->Print(variables_,
+ "if (this->$name$_size() > 0) {\n"
+ " DO_(::google::protobuf::internal::WireFormat::WriteTag("
+ "$number$, ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED,"
+ "output));\n"
+ " DO_(output->WriteVarint32(_$name$_cached_byte_size_));\n"
+ "}\n");
+ }
printer->Print(variables_,
- "DO_(::google::protobuf::internal::WireFormat::WriteEnum("
- "$number$, this->$name$(i), output));\n");
+ "for (int i = 0; i < this->$name$_size(); i++) {\n");
+ if (descriptor_->options().packed()) {
+ printer->Print(variables_,
+ " DO_(::google::protobuf::internal::WireFormat::WriteEnumNoTag("
+ "this->$name$(i), output));\n");
+ } else {
+ printer->Print(variables_,
+ " DO_(::google::protobuf::internal::WireFormat::WriteEnum("
+ "$number$, this->$name$(i), output));\n");
+ }
+ printer->Print("}\n");
}
void RepeatedEnumFieldGenerator::
GenerateByteSize(io::Printer* printer) const {
printer->Print(variables_,
- "total_size += $tag_size$ * $name$_size();\n"
- "for (int i = 0; i < $name$_size(); i++) {\n"
- " total_size += ::google::protobuf::internal::WireFormat::EnumSize(\n"
- " this->$name$(i));\n"
- "}\n");
+ "{\n"
+ " int data_size = 0;\n");
+ printer->Indent();
+ printer->Print(variables_,
+ "for (int i = 0; i < this->$name$_size(); i++) {\n"
+ " data_size += ::google::protobuf::internal::WireFormat::EnumSize(\n"
+ " this->$name$(i));\n"
+ "}\n");
+
+ if (descriptor_->options().packed()) {
+ printer->Print(variables_,
+ "if (data_size > 0) {\n"
+ " total_size += $tag_size$ + "
+ "::google::protobuf::internal::WireFormat::Int32Size(data_size);\n"
+ "}\n"
+ "_$name$_cached_byte_size_ = data_size;\n"
+ "total_size += data_size;\n");
+ } else {
+ printer->Print(variables_,
+ "total_size += $tag_size$ * this->$name$_size() + data_size;\n");
+ }
+ printer->Outdent();
+ printer->Print("}\n");
}
} // namespace cpp
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc
index eacceeaf..c6843e93 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message.cc
@@ -41,7 +41,7 @@
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/coded_stream.h>
-#include <google/protobuf/wire_format.h>
+#include <google/protobuf/wire_format_inl.h>
#include <google/protobuf/descriptor.pb.h>
namespace google {
@@ -1169,10 +1169,9 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
" goto handle_uninterpreted;\n"
" }\n",
"number", SimpleItoa(field->number()),
- "wiretype", kWireTypeNames[
- WireFormat::WireTypeForFieldType(field->type())]);
+ "wiretype", kWireTypeNames[WireFormat::WireTypeForField(field)]);
- if (i > 0 || field->is_repeated()) {
+ if (i > 0 || (field->is_repeated() && !field->options().packed())) {
printer->Print(
" parse_$name$:\n",
"name", field->name());
@@ -1184,7 +1183,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
// switch() is slow since it can't be predicted well. Insert some if()s
// here that attempt to predict the next tag.
- if (field->is_repeated()) {
+ if (field->is_repeated() && !field->options().packed()) {
// Expect repeats of this field.
printer->Print(
"if (input->ExpectTag($tag$)) goto parse_$name$;\n",
@@ -1283,22 +1282,20 @@ void MessageGenerator::GenerateSerializeOneField(
io::Printer* printer, const FieldDescriptor* field) {
PrintFieldComment(printer, field);
- if (field->is_repeated()) {
- printer->Print(
- "for (int i = 0; i < $name$_.size(); i++) {\n",
- "name", FieldName(field));
- } else {
+ if (!field->is_repeated()) {
printer->Print(
"if (_has_bit($index$)) {\n",
"index", SimpleItoa(field->index()));
+ printer->Indent();
}
- printer->Indent();
-
field_generators_.get(field).GenerateSerializeWithCachedSizes(printer);
- printer->Outdent();
- printer->Print("}\n\n");
+ if (!field->is_repeated()) {
+ printer->Outdent();
+ printer->Print("}\n");
+ }
+ printer->Print("\n");
}
void MessageGenerator::GenerateSerializeOneExtensionRange(
diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.cc b/src/google/protobuf/compiler/cpp/cpp_message_field.cc
index d1c31067..7d57a6df 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc
@@ -232,15 +232,17 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
void RepeatedMessageFieldGenerator::
GenerateSerializeWithCachedSizes(io::Printer* printer) const {
printer->Print(variables_,
- "DO_(::google::protobuf::internal::WireFormat::Write$declared_type$NoVirtual("
- "$number$, this->$name$(i), output));\n");
+ "for (int i = 0; i < this->$name$_size(); i++) {\n"
+ " DO_(::google::protobuf::internal::WireFormat::Write$declared_type$NoVirtual("
+ "$number$, this->$name$(i), output));\n"
+ "}\n");
}
void RepeatedMessageFieldGenerator::
GenerateByteSize(io::Printer* printer) const {
printer->Print(variables_,
- "total_size += $tag_size$ * $name$_size();\n"
- "for (int i = 0; i < $name$_size(); i++) {\n"
+ "total_size += $tag_size$ * this->$name$_size();\n"
+ "for (int i = 0; i < this->$name$_size(); i++) {\n"
" total_size +=\n"
" ::google::protobuf::internal::WireFormat::$declared_type$SizeNoVirtual(\n"
" this->$name$(i));\n"
diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
index ef4072f0..768d30cc 100644
--- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
@@ -227,6 +227,11 @@ void RepeatedPrimitiveFieldGenerator::
GeneratePrivateMembers(io::Printer* printer) const {
printer->Print(variables_,
"::google::protobuf::RepeatedField< $type$ > $name$_;\n");
+ if (descriptor_->options().packed() &&
+ descriptor_->file()->options().optimize_for() == FileOptions::SPEED) {
+ printer->Print(variables_,
+ "mutable int _$name$_cached_byte_size_;\n");
+ }
}
void RepeatedPrimitiveFieldGenerator::
@@ -283,33 +288,90 @@ GenerateInitializer(io::Printer* printer) const {
void RepeatedPrimitiveFieldGenerator::
GenerateMergeFromCodedStream(io::Printer* printer) const {
- printer->Print(variables_,
- "$type$ value;\n"
- "DO_(::google::protobuf::internal::WireFormat::Read$declared_type$(input, &value));\n"
- "add_$name$(value);\n");
+ if (descriptor_->options().packed()) {
+ printer->Print("{\n");
+ printer->Indent();
+ printer->Print(variables_,
+ "::google::protobuf::uint32 length;\n"
+ "DO_(input->ReadVarint32(&length));\n"
+ "::google::protobuf::io::CodedInputStream::Limit limit = "
+ "input->PushLimit(length);\n"
+ "while (input->BytesUntilLimit() > 0) {\n"
+ " $type$ value;\n"
+ " DO_(::google::protobuf::internal::WireFormat::Read$declared_type$("
+ "input, &value));\n"
+ " add_$name$(value);\n"
+ "}\n"
+ "input->PopLimit(limit);\n");
+ printer->Outdent();
+ printer->Print("}\n");
+ } else {
+ printer->Print(variables_,
+ "$type$ value;\n"
+ "DO_(::google::protobuf::internal::WireFormat::Read$declared_type$("
+ "input, &value));\n"
+ "add_$name$(value);\n");
+ }
}
void RepeatedPrimitiveFieldGenerator::
GenerateSerializeWithCachedSizes(io::Printer* printer) const {
+ if (descriptor_->options().packed()) {
+ // Write the tag and the size.
+ printer->Print(variables_,
+ "if (this->$name$_size() > 0) {\n"
+ " DO_(::google::protobuf::internal::WireFormat::WriteTag("
+ "$number$, ::google::protobuf::internal::WireFormat::WIRETYPE_LENGTH_DELIMITED,"
+ "output));\n"
+ " DO_(output->WriteVarint32(_$name$_cached_byte_size_));\n"
+ "}\n");
+ }
printer->Print(variables_,
- "DO_(::google::protobuf::internal::WireFormat::Write$declared_type$("
- "$number$, this->$name$(i), output));\n");
+ "for (int i = 0; i < this->$name$_size(); i++) {\n");
+ if (descriptor_->options().packed()) {
+ printer->Print(variables_,
+ " DO_(::google::protobuf::internal::WireFormat::Write$declared_type$NoTag("
+ "this->$name$(i), output));\n");
+ } else {
+ printer->Print(variables_,
+ " DO_(::google::protobuf::internal::WireFormat::Write$declared_type$("
+ "$number$, this->$name$(i), output));\n");
+ }
+ printer->Print("}\n");
}
void RepeatedPrimitiveFieldGenerator::
GenerateByteSize(io::Printer* printer) const {
+ printer->Print(variables_,
+ "{\n"
+ " int data_size = 0;\n");
+ printer->Indent();
int fixed_size = FixedSize(descriptor_->type());
if (fixed_size == -1) {
printer->Print(variables_,
- "total_size += $tag_size$ * $name$_size();\n"
- "for (int i = 0; i < $name$_size(); i++) {\n"
- " total_size += ::google::protobuf::internal::WireFormat::$declared_type$Size(\n"
+ "for (int i = 0; i < this->$name$_size(); i++) {\n"
+ " data_size += ::google::protobuf::internal::WireFormat::$declared_type$Size(\n"
" this->$name$(i));\n"
"}\n");
} else {
printer->Print(variables_,
- "total_size += ($tag_size$ + $fixed_size$) * $name$_size();\n");
+ "data_size = $fixed_size$ * this->$name$_size();\n");
+ }
+
+ if (descriptor_->options().packed()) {
+ printer->Print(variables_,
+ "if (data_size > 0) {\n"
+ " total_size += $tag_size$ + "
+ "::google::protobuf::internal::WireFormat::Int32Size(data_size);\n"
+ "}\n"
+ "_$name$_cached_byte_size_ = data_size;\n"
+ "total_size += data_size;\n");
+ } else {
+ printer->Print(variables_,
+ "total_size += $tag_size$ * this->$name$_size() + data_size;\n");
}
+ printer->Outdent();
+ printer->Print("}\n");
}
} // namespace cpp
diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
index 3e694ab7..200e3d68 100644
--- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
@@ -374,15 +374,17 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
void RepeatedStringFieldGenerator::
GenerateSerializeWithCachedSizes(io::Printer* printer) const {
printer->Print(variables_,
- "DO_(::google::protobuf::internal::WireFormat::Write$declared_type$("
- "$number$, this->$name$(i), output));\n");
+ "for (int i = 0; i < this->$name$_size(); i++) {\n"
+ " DO_(::google::protobuf::internal::WireFormat::Write$declared_type$("
+ "$number$, this->$name$(i), output));\n"
+ "}\n");
}
void RepeatedStringFieldGenerator::
GenerateByteSize(io::Printer* printer) const {
printer->Print(variables_,
- "total_size += $tag_size$ * $name$_size();\n"
- "for (int i = 0; i < $name$_size(); i++) {\n"
+ "total_size += $tag_size$ * this->$name$_size();\n"
+ "for (int i = 0; i < this->$name$_size(); i++) {\n"
" total_size += ::google::protobuf::internal::WireFormat::$declared_type$Size(\n"
" this->$name$(i));\n"
"}\n");
diff --git a/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto b/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
index a4d96ac5..79971a95 100644
--- a/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
+++ b/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.proto
@@ -54,6 +54,14 @@ message TestConflictingSymbolNames {
optional int32 total_size = 6;
optional int32 tag = 7;
+ enum TestEnum { FOO = 1; }
+ message Data1 { repeated int32 data = 1; }
+ message Data2 { repeated TestEnum data = 1; }
+ message Data3 { repeated string data = 1; }
+ message Data4 { repeated Data4 data = 1; }
+ message Data5 { repeated string data = 1 [ctype=STRING_PIECE]; }
+ message Data6 { repeated string data = 1 [ctype=CORD]; }
+
optional int32 source = 8;
optional int32 value = 9;
optional int32 file = 10;
diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
index 393c923b..c7e4ee3d 100644
--- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
@@ -225,7 +225,6 @@ TEST(GeneratedMessageTest, ClearOneField) {
TEST(GeneratedMessageTest, CopyFrom) {
unittest::TestAllTypes message1, message2;
- string data;
TestUtil::SetAllFields(&message1);
message2.CopyFrom(message1);
@@ -413,6 +412,13 @@ TEST(GeneratedMessageTest, Serialization) {
EXPECT_TRUE(message2.ParseFromString(data));
TestUtil::ExpectAllFieldsSet(message2);
+
+ unittest::TestPackedTypes packed_message1, packed_message2;
+ string packed_data;
+ TestUtil::SetPackedFields(&packed_message1);
+ packed_message1.SerializeToString(&packed_data);
+ EXPECT_TRUE(packed_message2.ParseFromString(packed_data));
+ TestUtil::ExpectPackedFieldsSet(packed_message2);
}
diff --git a/src/google/protobuf/compiler/java/java_enum.cc b/src/google/protobuf/compiler/java/java_enum.cc
index b1484763..4aac6493 100644
--- a/src/google/protobuf/compiler/java/java_enum.cc
+++ b/src/google/protobuf/compiler/java/java_enum.cc
@@ -71,7 +71,8 @@ void EnumGenerator::Generate(io::Printer* printer) {
descriptor_->containing_type() == NULL &&
descriptor_->file()->options().java_multiple_files();
printer->Print(
- "public $static$ enum $classname$ {\n",
+ "public $static$ enum $classname$\n"
+ " implements com.google.protobuf.ProtocolMessageEnum {\n",
"static", is_own_file ? "" : "static",
"classname", descriptor_->name());
printer->Indent();
diff --git a/src/google/protobuf/compiler/java/java_enum_field.cc b/src/google/protobuf/compiler/java/java_enum_field.cc
index e95fdab4..2153042d 100644
--- a/src/google/protobuf/compiler/java/java_enum_field.cc
+++ b/src/google/protobuf/compiler/java/java_enum_field.cc
@@ -39,6 +39,7 @@
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/compiler/java/java_helpers.h>
#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format_inl.h>
#include <google/protobuf/stubs/strutil.h>
namespace google {
@@ -64,6 +65,9 @@ void SetEnumVariables(const FieldDescriptor* descriptor,
(*variables)["number"] = SimpleItoa(descriptor->number());
(*variables)["type"] = type;
(*variables)["default"] = type + "." + default_value->name();
+ (*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
+ (*variables)["tag_size"] = SimpleItoa(
+ internal::WireFormat::TagSize(descriptor->number(), descriptor->type()));
}
} // namespace
@@ -97,6 +101,9 @@ GenerateBuilderMembers(io::Printer* printer) const {
" return result.get$capitalized_name$();\n"
"}\n"
"public Builder set$capitalized_name$($type$ value) {\n"
+ " if (value == null) {\n"
+ " throw new NullPointerException();\n"
+ " }\n"
" result.has$capitalized_name$ = true;\n"
" result.$name$_ = value;\n"
" return this;\n"
@@ -176,6 +183,12 @@ GenerateMembers(io::Printer* printer) const {
"public $type$ get$capitalized_name$(int index) {\n"
" return $name$_.get(index);\n"
"}\n");
+
+ if (descriptor_->options().packed() &&
+ descriptor_->file()->options().optimize_for() == FileOptions::SPEED) {
+ printer->Print(variables_,
+ "private int $name$MemoizedSerializedSize;\n");
+ }
}
void RepeatedEnumFieldGenerator::
@@ -195,10 +208,16 @@ GenerateBuilderMembers(io::Printer* printer) const {
" return result.get$capitalized_name$(index);\n"
"}\n"
"public Builder set$capitalized_name$(int index, $type$ value) {\n"
+ " if (value == null) {\n"
+ " throw new NullPointerException();\n"
+ " }\n"
" result.$name$_.set(index, value);\n"
" return this;\n"
"}\n"
"public Builder add$capitalized_name$($type$ value) {\n"
+ " if (value == null) {\n"
+ " throw new NullPointerException();\n"
+ " }\n"
" if (result.$name$_.isEmpty()) {\n"
" result.$name$_ = new java.util.ArrayList<$type$>();\n"
" }\n"
@@ -241,6 +260,16 @@ GenerateBuildingCode(io::Printer* printer) const {
void RepeatedEnumFieldGenerator::
GenerateParsingCode(io::Printer* printer) const {
+ // If packed, set up the while loop
+ if (descriptor_->options().packed()) {
+ printer->Print(variables_,
+ "int length = input.readRawVarint32();\n"
+ "int oldLimit = input.pushLimit(length);\n"
+ "while(input.getBytesUntilLimit() > 0) {\n");
+ printer->Indent();
+ }
+
+ // Read and store the enum
printer->Print(variables_,
"int rawValue = input.readEnum();\n"
"$type$ value = $type$.valueOf(rawValue);\n"
@@ -249,23 +278,68 @@ GenerateParsingCode(io::Printer* printer) const {
"} else {\n"
" add$capitalized_name$(value);\n"
"}\n");
+
+ if (descriptor_->options().packed()) {
+ printer->Outdent();
+ printer->Print(variables_,
+ "}\n"
+ "input.popLimit(oldLimit);\n");
+ }
}
void RepeatedEnumFieldGenerator::
GenerateSerializationCode(io::Printer* printer) const {
- printer->Print(variables_,
- "for ($type$ element : get$capitalized_name$List()) {\n"
- " output.writeEnum($number$, element.getNumber());\n"
- "}\n");
+ if (descriptor_->options().packed()) {
+ printer->Print(variables_,
+ "if (get$capitalized_name$List().size() > 0) {\n"
+ " output.writeRawVarint32($tag$);\n"
+ " output.writeRawVarint32($name$MemoizedSerializedSize);\n"
+ "}\n"
+ "for ($type$ element : get$capitalized_name$List()) {\n"
+ " output.writeEnumNoTag(element.getNumber());\n"
+ "}\n");
+ } else {
+ printer->Print(variables_,
+ "for ($type$ element : get$capitalized_name$List()) {\n"
+ " output.writeEnum($number$, element.getNumber());\n"
+ "}\n");
+ }
}
void RepeatedEnumFieldGenerator::
GenerateSerializedSizeCode(io::Printer* printer) const {
printer->Print(variables_,
+ "{\n"
+ " int dataSize = 0;\n");
+ printer->Indent();
+
+ printer->Print(variables_,
"for ($type$ element : get$capitalized_name$List()) {\n"
- " size += com.google.protobuf.CodedOutputStream\n"
- " .computeEnumSize($number$, element.getNumber());\n"
+ " dataSize += com.google.protobuf.CodedOutputStream\n"
+ " .computeEnumSizeNoTag(element.getNumber());\n"
"}\n");
+ printer->Print(
+ "size += dataSize;\n");
+ if (descriptor_->options().packed()) {
+ printer->Print(variables_,
+ "if (!get$capitalized_name$List().isEmpty()) {"
+ " size += $tag_size$;\n"
+ " size += com.google.protobuf.CodedOutputStream\n"
+ " .computeRawVarint32Size(dataSize);\n"
+ "}");
+ } else {
+ printer->Print(variables_,
+ "size += $tag_size$ * get$capitalized_name$List().size();\n");
+ }
+
+ // cache the data size for packed fields.
+ if (descriptor_->options().packed()) {
+ printer->Print(variables_,
+ "$name$MemoizedSerializedSize = dataSize;\n");
+ }
+
+ printer->Outdent();
+ printer->Print("}\n");
}
string RepeatedEnumFieldGenerator::GetBoxedType() const {
diff --git a/src/google/protobuf/compiler/java/java_message.cc b/src/google/protobuf/compiler/java/java_message.cc
index 3fdd1d57..9a4b2f79 100644
--- a/src/google/protobuf/compiler/java/java_message.cc
+++ b/src/google/protobuf/compiler/java/java_message.cc
@@ -41,7 +41,7 @@
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/io/coded_stream.h>
-#include <google/protobuf/wire_format.h>
+#include <google/protobuf/wire_format_inl.h>
#include <google/protobuf/descriptor.pb.h>
namespace google {
@@ -500,6 +500,7 @@ void MessageGenerator::GenerateBuilder(io::Printer* printer) {
"public static Builder newBuilder($classname$ prototype) {\n"
" return new Builder().mergeFrom(prototype);\n"
"}\n"
+ "public Builder toBuilder() { return newBuilder(this); }\n"
"\n",
"classname", ClassName(descriptor_));
@@ -634,6 +635,13 @@ void MessageGenerator::GenerateCommonBuilderMethods(io::Printer* printer) {
}
printer->Outdent();
+
+ // if message type has extensions
+ if (descriptor_->extension_range_count() > 0) {
+ printer->Print(
+ " this.mergeExtensionFields(other);\n");
+ }
+
printer->Print(
" this.mergeUnknownFields(other.getUnknownFields());\n"
" return this;\n"
@@ -692,7 +700,7 @@ void MessageGenerator::GenerateBuilderParsingMethods(io::Printer* printer) {
for (int i = 0; i < descriptor_->field_count(); i++) {
const FieldDescriptor* field = sorted_fields[i];
uint32 tag = WireFormat::MakeTag(field->number(),
- WireFormat::WireTypeForFieldType(field->type()));
+ WireFormat::WireTypeForField(field));
printer->Print(
"case $tag$: {\n",
diff --git a/src/google/protobuf/compiler/java/java_message_field.cc b/src/google/protobuf/compiler/java/java_message_field.cc
index c85a1598..bbddddde 100644
--- a/src/google/protobuf/compiler/java/java_message_field.cc
+++ b/src/google/protobuf/compiler/java/java_message_field.cc
@@ -94,6 +94,9 @@ GenerateBuilderMembers(io::Printer* printer) const {
" return result.get$capitalized_name$();\n"
"}\n"
"public Builder set$capitalized_name$($type$ value) {\n"
+ " if (value == null) {\n"
+ " throw new NullPointerException();\n"
+ " }\n"
" result.has$capitalized_name$ = true;\n"
" result.$name$_ = value;\n"
" return this;\n"
@@ -216,6 +219,9 @@ GenerateBuilderMembers(io::Printer* printer) const {
" return result.get$capitalized_name$(index);\n"
"}\n"
"public Builder set$capitalized_name$(int index, $type$ value) {\n"
+ " if (value == null) {\n"
+ " throw new NullPointerException();\n"
+ " }\n"
" result.$name$_.set(index, value);\n"
" return this;\n"
"}\n"
@@ -225,6 +231,9 @@ GenerateBuilderMembers(io::Printer* printer) const {
" return this;\n"
"}\n"
"public Builder add$capitalized_name$($type$ value) {\n"
+ " if (value == null) {\n"
+ " throw new NullPointerException();\n"
+ " }\n"
" if (result.$name$_.isEmpty()) {\n"
" result.$name$_ = new java.util.ArrayList<$type$>();\n"
" }\n"
diff --git a/src/google/protobuf/compiler/java/java_primitive_field.cc b/src/google/protobuf/compiler/java/java_primitive_field.cc
index fb4e650f..798e8608 100644
--- a/src/google/protobuf/compiler/java/java_primitive_field.cc
+++ b/src/google/protobuf/compiler/java/java_primitive_field.cc
@@ -39,6 +39,7 @@
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/compiler/java/java_helpers.h>
#include <google/protobuf/io/printer.h>
+#include <google/protobuf/wire_format_inl.h>
#include <google/protobuf/stubs/strutil.h>
#include <google/protobuf/stubs/substitute.h>
@@ -47,6 +48,8 @@ namespace protobuf {
namespace compiler {
namespace java {
+using internal::WireFormat;
+
namespace {
const char* PrimitiveTypeName(JavaType type) {
@@ -69,6 +72,26 @@ const char* PrimitiveTypeName(JavaType type) {
return NULL;
}
+bool IsReferenceType(JavaType type) {
+ switch (type) {
+ case JAVATYPE_INT : return false;
+ case JAVATYPE_LONG : return false;
+ case JAVATYPE_FLOAT : return false;
+ case JAVATYPE_DOUBLE : return false;
+ case JAVATYPE_BOOLEAN: return false;
+ case JAVATYPE_STRING : return true;
+ case JAVATYPE_BYTES : return true;
+ case JAVATYPE_ENUM : return true;
+ case JAVATYPE_MESSAGE: return true;
+
+ // No default because we want the compiler to complain if any new
+ // JavaTypes are added.
+ }
+
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return false;
+}
+
const char* GetCapitalizedType(const FieldDescriptor* field) {
switch (field->type()) {
case FieldDescriptor::TYPE_INT32 : return "Int32" ;
@@ -108,6 +131,38 @@ bool AllPrintableAscii(const string& text) {
return true;
}
+// For encodings with fixed sizes, returns that size in bytes. Otherwise
+// returns -1.
+int FixedSize(FieldDescriptor::Type type) {
+ switch (type) {
+ case FieldDescriptor::TYPE_INT32 : return -1;
+ case FieldDescriptor::TYPE_INT64 : return -1;
+ case FieldDescriptor::TYPE_UINT32 : return -1;
+ case FieldDescriptor::TYPE_UINT64 : return -1;
+ case FieldDescriptor::TYPE_SINT32 : return -1;
+ case FieldDescriptor::TYPE_SINT64 : return -1;
+ case FieldDescriptor::TYPE_FIXED32 : return WireFormat::kFixed32Size;
+ case FieldDescriptor::TYPE_FIXED64 : return WireFormat::kFixed64Size;
+ case FieldDescriptor::TYPE_SFIXED32: return WireFormat::kSFixed32Size;
+ case FieldDescriptor::TYPE_SFIXED64: return WireFormat::kSFixed64Size;
+ case FieldDescriptor::TYPE_FLOAT : return WireFormat::kFloatSize;
+ case FieldDescriptor::TYPE_DOUBLE : return WireFormat::kDoubleSize;
+
+ case FieldDescriptor::TYPE_BOOL : return WireFormat::kBoolSize;
+ case FieldDescriptor::TYPE_ENUM : return -1;
+
+ case FieldDescriptor::TYPE_STRING : return -1;
+ case FieldDescriptor::TYPE_BYTES : return -1;
+ case FieldDescriptor::TYPE_GROUP : return -1;
+ case FieldDescriptor::TYPE_MESSAGE : return -1;
+
+ // No default because we want the compiler to complain if any new
+ // types are added.
+ }
+ GOOGLE_LOG(FATAL) << "Can't get here.";
+ return -1;
+}
+
string DefaultValue(const FieldDescriptor* field) {
// Switch on cpp_type since we need to know which default_value_* method
// of FieldDescriptor to call.
@@ -177,8 +232,22 @@ void SetPrimitiveVariables(const FieldDescriptor* descriptor,
(*variables)["boxed_type"] = BoxedPrimitiveTypeName(GetJavaType(descriptor));
(*variables)["default"] = DefaultValue(descriptor);
(*variables)["capitalized_type"] = GetCapitalizedType(descriptor);
+ (*variables)["tag"] = SimpleItoa(WireFormat::MakeTag(descriptor));
+ (*variables)["tag_size"] = SimpleItoa(
+ WireFormat::TagSize(descriptor->number(), descriptor->type()));
+ if (IsReferenceType(GetJavaType(descriptor))) {
+ (*variables)["null_check"] =
+ " if (value == null) {\n"
+ " throw new NullPointerException();\n"
+ " }\n";
+ } else {
+ (*variables)["null_check"] = "";
+ }
+ int fixed_size = FixedSize(descriptor->type());
+ if (fixed_size != -1) {
+ (*variables)["fixed_size"] = SimpleItoa(fixed_size);
+ }
}
-
} // namespace
// ===================================================================
@@ -210,6 +279,7 @@ GenerateBuilderMembers(io::Printer* printer) const {
" return result.get$capitalized_name$();\n"
"}\n"
"public Builder set$capitalized_name$($type$ value) {\n"
+ "$null_check$"
" result.has$capitalized_name$ = true;\n"
" result.$name$_ = value;\n"
" return this;\n"
@@ -283,6 +353,12 @@ GenerateMembers(io::Printer* printer) const {
"public $type$ get$capitalized_name$(int index) {\n"
" return $name$_.get(index);\n"
"}\n");
+
+ if (descriptor_->options().packed() &&
+ descriptor_->file()->options().optimize_for() == FileOptions::SPEED) {
+ printer->Print(variables_,
+ "private int $name$MemoizedSerializedSize;\n");
+ }
}
void RepeatedPrimitiveFieldGenerator::
@@ -302,10 +378,12 @@ GenerateBuilderMembers(io::Printer* printer) const {
" return result.get$capitalized_name$(index);\n"
"}\n"
"public Builder set$capitalized_name$(int index, $type$ value) {\n"
+ "$null_check$"
" result.$name$_.set(index, value);\n"
" return this;\n"
"}\n"
"public Builder add$capitalized_name$($type$ value) {\n"
+ "$null_check$"
" if (result.$name$_.isEmpty()) {\n"
" result.$name$_ = new java.util.ArrayList<$boxed_type$>();\n"
" }\n"
@@ -348,25 +426,80 @@ GenerateBuildingCode(io::Printer* printer) const {
void RepeatedPrimitiveFieldGenerator::
GenerateParsingCode(io::Printer* printer) const {
- printer->Print(variables_,
- "add$capitalized_name$(input.read$capitalized_type$());\n");
+ if (descriptor_->options().packed()) {
+ printer->Print(variables_,
+ "int length = input.readRawVarint32();\n"
+ "int limit = input.pushLimit(length);\n"
+ "while (input.getBytesUntilLimit() > 0) {\n"
+ " add$capitalized_name$(input.read$capitalized_type$());\n"
+ "}\n"
+ "input.popLimit(limit);\n");
+ } else {
+ printer->Print(variables_,
+ "add$capitalized_name$(input.read$capitalized_type$());\n");
+ }
}
void RepeatedPrimitiveFieldGenerator::
GenerateSerializationCode(io::Printer* printer) const {
- printer->Print(variables_,
- "for ($type$ element : get$capitalized_name$List()) {\n"
- " output.write$capitalized_type$($number$, element);\n"
- "}\n");
+ if (descriptor_->options().packed()) {
+ printer->Print(variables_,
+ "if (get$capitalized_name$List().size() > 0) {\n"
+ " output.writeRawVarint32($tag$);\n"
+ " output.writeRawVarint32($name$MemoizedSerializedSize);\n"
+ "}\n"
+ "for ($type$ element : get$capitalized_name$List()) {\n"
+ " output.write$capitalized_type$NoTag(element);\n"
+ "}\n");
+ } else {
+ printer->Print(variables_,
+ "for ($type$ element : get$capitalized_name$List()) {\n"
+ " output.write$capitalized_type$($number$, element);\n"
+ "}\n");
+ }
}
void RepeatedPrimitiveFieldGenerator::
GenerateSerializedSizeCode(io::Printer* printer) const {
printer->Print(variables_,
- "for ($type$ element : get$capitalized_name$List()) {\n"
- " size += com.google.protobuf.CodedOutputStream\n"
- " .compute$capitalized_type$Size($number$, element);\n"
- "}\n");
+ "{\n"
+ " int dataSize = 0;\n");
+ printer->Indent();
+
+ if (FixedSize(descriptor_->type()) == -1) {
+ printer->Print(variables_,
+ "for ($type$ element : get$capitalized_name$List()) {\n"
+ " dataSize += com.google.protobuf.CodedOutputStream\n"
+ " .compute$capitalized_type$SizeNoTag(element);\n"
+ "}\n");
+ } else {
+ printer->Print(variables_,
+ "dataSize = $fixed_size$ * get$capitalized_name$List().size();\n");
+ }
+
+ printer->Print(
+ "size += dataSize;\n");
+
+ if (descriptor_->options().packed()) {
+ printer->Print(variables_,
+ "if (!get$capitalized_name$List().isEmpty()) {\n"
+ " size += $tag_size$;\n"
+ " size += com.google.protobuf.CodedOutputStream\n"
+ " .computeInt32SizeNoTag(dataSize);\n"
+ "}\n");
+ } else {
+ printer->Print(variables_,
+ "size += $tag_size$ * get$capitalized_name$List().size();\n");
+ }
+
+ // cache the data size for packed fields.
+ if (descriptor_->options().packed()) {
+ printer->Print(variables_,
+ "$name$MemoizedSerializedSize = dataSize;\n");
+ }
+
+ printer->Outdent();
+ printer->Print("}\n");
}
string RepeatedPrimitiveFieldGenerator::GetBoxedType() const {
diff --git a/src/google/protobuf/compiler/python/python_generator.cc b/src/google/protobuf/compiler/python/python_generator.cc
index 754dcbda..ca69fd4c 100644
--- a/src/google/protobuf/compiler/python/python_generator.cc
+++ b/src/google/protobuf/compiler/python/python_generator.cc
@@ -111,7 +111,6 @@ void PrintTopBoilerplate(
io::Printer* printer, const FileDescriptor* file, bool descriptor_proto) {
// TODO(robinson): Allow parameterization of Python version?
printer->Print(
- "#!/usr/bin/python2.4\n"
"# Generated by the protocol buffer compiler. DO NOT EDIT!\n"
"\n"
"from google.protobuf import descriptor\n"
diff --git a/src/google/protobuf/descriptor.cc b/src/google/protobuf/descriptor.cc
index 21c709fb..eb5b5937 100644
--- a/src/google/protobuf/descriptor.cc
+++ b/src/google/protobuf/descriptor.cc
@@ -122,6 +122,35 @@ namespace {
const string kEmptyString;
+string ToCamelCase(const string& input) {
+ bool capitalize_next = false;
+ string result;
+ result.reserve(input.size());
+
+ for (int i = 0; i < input.size(); i++) {
+ if (input[i] == '_') {
+ capitalize_next = true;
+ } else if (capitalize_next) {
+ // Note: I distrust ctype.h due to locales.
+ if ('a' <= input[i] && input[i] <= 'z') {
+ result.push_back(input[i] - 'a' + 'A');
+ } else {
+ result.push_back(input[i]);
+ }
+ capitalize_next = false;
+ } else {
+ result.push_back(input[i]);
+ }
+ }
+
+ // Lower-case the first letter.
+ if (!result.empty() && 'A' <= result[0] && result[0] <= 'Z') {
+ result[0] = result[0] - 'A' + 'a';
+ }
+
+ return result;
+}
+
// A DescriptorPool contains a bunch of hash_maps to implement the
// various Find*By*() methods. Since hashtable lookups are O(1), it's
// most efficient to construct a fixed set of large hash_maps used by
@@ -253,6 +282,9 @@ typedef hash_map<PointerStringPair, Symbol,
typedef hash_map<const char*, const FileDescriptor*,
hash<const char*>, CStringEqual>
FilesByNameMap;
+typedef hash_map<PointerStringPair, const FieldDescriptor*,
+ PointerStringPairHash, PointerStringPairEqual>
+ FieldsByNameMap;
typedef hash_map<DescriptorIntPair, const FieldDescriptor*,
PointerIntegerPairHash<DescriptorIntPair> >
FieldsByNumberMap;
@@ -296,21 +328,29 @@ class DescriptorPool::Tables {
// Finding items.
// Find symbols. These return a null Symbol (symbol.IsNull() is true)
- // if not found. FindSymbolOfType() additionally returns null if the
- // symbol is not of the given type.
+ // if not found.
inline Symbol FindSymbol(const string& key) const;
- inline Symbol FindSymbolOfType(const string& key,
- const Symbol::Type type) const;
inline Symbol FindNestedSymbol(const void* parent,
const string& name) const;
inline Symbol FindNestedSymbolOfType(const void* parent,
const string& name,
const Symbol::Type type) const;
+ // This implements the body of DescriptorPool::Find*ByName(). It should
+ // really be a private method of DescriptorPool, but that would require
+ // declaring Symbol in descriptor.h, which would drag all kinds of other
+ // stuff into the header. Yay C++.
+ Symbol FindByNameHelper(
+ const DescriptorPool* pool, const string& name) const;
+
// These return NULL if not found.
inline const FileDescriptor* FindFile(const string& key) const;
inline const FieldDescriptor* FindFieldByNumber(
const Descriptor* parent, int number) const;
+ inline const FieldDescriptor* FindFieldByLowercaseName(
+ const void* parent, const string& lowercase_name) const;
+ inline const FieldDescriptor* FindFieldByCamelcaseName(
+ const void* parent, const string& camelcase_name) const;
inline const EnumValueDescriptor* FindEnumValueByNumber(
const EnumDescriptor* parent, int number) const;
@@ -330,6 +370,10 @@ class DescriptorPool::Tables {
bool AddFieldByNumber(const FieldDescriptor* field);
bool AddEnumValueByNumber(const EnumValueDescriptor* value);
+ // Adds the field to the lowercase_name and camelcase_name maps. Never
+ // fails because we allow duplicates; the first field by the name wins.
+ void AddFieldByStylizedNames(const FieldDescriptor* field);
+
// Like AddSymbol(), but only adds to symbols_by_parent_, not
// symbols_by_name_. Used for enum values, which need to be registered
// under multiple parents (their type and its parent).
@@ -364,6 +408,8 @@ class DescriptorPool::Tables {
SymbolsByNameMap symbols_by_name_;
SymbolsByParentMap symbols_by_parent_;
FilesByNameMap files_by_name_;
+ FieldsByNameMap fields_by_lowercase_name_;
+ FieldsByNameMap fields_by_camelcase_name_;
FieldsByNumberMap fields_by_number_; // Includes extensions.
EnumValuesByNumberMap enum_values_by_number_;
@@ -373,6 +419,8 @@ class DescriptorPool::Tables {
vector<const char* > symbols_after_checkpoint_;
vector<PointerStringPair> symbols_by_parent_after_checkpoint_;
vector<const char* > files_after_checkpoint_;
+ vector<PointerStringPair> field_lowercase_names_after_checkpoint_;
+ vector<PointerStringPair> field_camelcase_names_after_checkpoint_;
vector<DescriptorIntPair> field_numbers_after_checkpoint_;
vector<EnumIntPair > enum_numbers_after_checkpoint_;
@@ -404,6 +452,8 @@ void DescriptorPool::Tables::Checkpoint() {
symbols_after_checkpoint_.clear();
symbols_by_parent_after_checkpoint_.clear();
files_after_checkpoint_.clear();
+ field_lowercase_names_after_checkpoint_.clear();
+ field_camelcase_names_after_checkpoint_.clear();
field_numbers_after_checkpoint_.clear();
enum_numbers_after_checkpoint_.clear();
}
@@ -418,6 +468,12 @@ void DescriptorPool::Tables::Rollback() {
for (int i = 0; i < files_after_checkpoint_.size(); i++) {
files_by_name_.erase(files_after_checkpoint_[i]);
}
+ for (int i = 0; i < field_lowercase_names_after_checkpoint_.size(); i++) {
+ fields_by_lowercase_name_.erase(field_lowercase_names_after_checkpoint_[i]);
+ }
+ for (int i = 0; i < field_camelcase_names_after_checkpoint_.size(); i++) {
+ fields_by_camelcase_name_.erase(field_camelcase_names_after_checkpoint_[i]);
+ }
for (int i = 0; i < field_numbers_after_checkpoint_.size(); i++) {
fields_by_number_.erase(field_numbers_after_checkpoint_[i]);
}
@@ -428,6 +484,8 @@ void DescriptorPool::Tables::Rollback() {
symbols_after_checkpoint_.clear();
symbols_by_parent_after_checkpoint_.clear();
files_after_checkpoint_.clear();
+ field_lowercase_names_after_checkpoint_.clear();
+ field_camelcase_names_after_checkpoint_.clear();
field_numbers_after_checkpoint_.clear();
enum_numbers_after_checkpoint_.clear();
@@ -455,13 +513,6 @@ inline Symbol DescriptorPool::Tables::FindSymbol(const string& key) const {
}
}
-inline Symbol DescriptorPool::Tables::FindSymbolOfType(
- const string& key, const Symbol::Type type) const {
- Symbol result = FindSymbol(key);
- if (result.type != type) return kNullSymbol;
- return result;
-}
-
inline Symbol DescriptorPool::Tables::FindNestedSymbol(
const void* parent, const string& name) const {
const Symbol* result =
@@ -480,6 +531,27 @@ inline Symbol DescriptorPool::Tables::FindNestedSymbolOfType(
return result;
}
+Symbol DescriptorPool::Tables::FindByNameHelper(
+ const DescriptorPool* pool, const string& name) const {
+ MutexLockMaybe lock(pool->mutex_);
+ Symbol result = FindSymbol(name);
+
+ if (result.IsNull() && pool->underlay_ != NULL) {
+ // Symbol not found; check the underlay.
+ result =
+ pool->underlay_->tables_->FindByNameHelper(pool->underlay_, name);
+ }
+
+ if (result.IsNull()) {
+ // Symbol still not found, so check fallback database.
+ if (pool->TryFindSymbolInFallbackDatabase(name)) {
+ result = FindSymbol(name);
+ }
+ }
+
+ return result;
+}
+
inline const FileDescriptor* DescriptorPool::Tables::FindFile(
const string& key) const {
return FindPtrOrNull(files_by_name_, key.c_str());
@@ -490,6 +562,18 @@ inline const FieldDescriptor* DescriptorPool::Tables::FindFieldByNumber(
return FindPtrOrNull(fields_by_number_, make_pair(parent, number));
}
+inline const FieldDescriptor* DescriptorPool::Tables::FindFieldByLowercaseName(
+ const void* parent, const string& lowercase_name) const {
+ return FindPtrOrNull(fields_by_lowercase_name_,
+ PointerStringPair(parent, lowercase_name.c_str()));
+}
+
+inline const FieldDescriptor* DescriptorPool::Tables::FindFieldByCamelcaseName(
+ const void* parent, const string& camelcase_name) const {
+ return FindPtrOrNull(fields_by_camelcase_name_,
+ PointerStringPair(parent, camelcase_name.c_str()));
+}
+
inline const EnumValueDescriptor* DescriptorPool::Tables::FindEnumValueByNumber(
const EnumDescriptor* parent, int number) const {
return FindPtrOrNull(enum_values_by_number_, make_pair(parent, number));
@@ -537,6 +621,30 @@ bool DescriptorPool::Tables::AddFile(const FileDescriptor* file) {
}
}
+void DescriptorPool::Tables::AddFieldByStylizedNames(
+ const FieldDescriptor* field) {
+ const void* parent;
+ if (field->is_extension()) {
+ if (field->extension_scope() == NULL) {
+ parent = field->file();
+ } else {
+ parent = field->extension_scope();
+ }
+ } else {
+ parent = field->containing_type();
+ }
+
+ PointerStringPair lowercase_key(parent, field->lowercase_name().c_str());
+ if (InsertIfNotPresent(&fields_by_lowercase_name_, lowercase_key, field)) {
+ field_lowercase_names_after_checkpoint_.push_back(lowercase_key);
+ }
+
+ PointerStringPair camelcase_key(parent, field->camelcase_name().c_str());
+ if (InsertIfNotPresent(&fields_by_camelcase_name_, camelcase_key, field)) {
+ field_camelcase_names_after_checkpoint_.push_back(camelcase_key);
+ }
+}
+
bool DescriptorPool::Tables::AddFieldByNumber(const FieldDescriptor* field) {
DescriptorIntPair key(field->containing_type(), field->number());
if (InsertIfNotPresent(&fields_by_number_, key, field)) {
@@ -689,122 +797,55 @@ const FileDescriptor* DescriptorPool::FindFileContainingSymbol(
const Descriptor* DescriptorPool::FindMessageTypeByName(
const string& name) const {
- MutexLockMaybe lock(mutex_);
- Symbol result = tables_->FindSymbolOfType(name, Symbol::MESSAGE);
- if (!result.IsNull()) return result.descriptor;
- if (underlay_ != NULL) {
- const Descriptor* result = underlay_->FindMessageTypeByName(name);
- if (result != NULL) return result;
- }
- if (TryFindSymbolInFallbackDatabase(name)) {
- Symbol result = tables_->FindSymbolOfType(name, Symbol::MESSAGE);
- if (!result.IsNull()) return result.descriptor;
- }
- return NULL;
+ Symbol result = tables_->FindByNameHelper(this, name);
+ return (result.type == Symbol::MESSAGE) ? result.descriptor : NULL;
}
const FieldDescriptor* DescriptorPool::FindFieldByName(
const string& name) const {
- MutexLockMaybe lock(mutex_);
- Symbol result = tables_->FindSymbolOfType(name, Symbol::FIELD);
- if (!result.IsNull() && !result.field_descriptor->is_extension()) {
+ Symbol result = tables_->FindByNameHelper(this, name);
+ if (result.type == Symbol::FIELD &&
+ !result.field_descriptor->is_extension()) {
return result.field_descriptor;
+ } else {
+ return NULL;
}
- if (underlay_ != NULL) {
- const FieldDescriptor* result = underlay_->FindFieldByName(name);
- if (result != NULL) return result;
- }
- if (TryFindSymbolInFallbackDatabase(name)) {
- Symbol result = tables_->FindSymbolOfType(name, Symbol::FIELD);
- if (!result.IsNull() && !result.field_descriptor->is_extension()) {
- return result.field_descriptor;
- }
- }
- return NULL;
}
const FieldDescriptor* DescriptorPool::FindExtensionByName(
const string& name) const {
- MutexLockMaybe lock(mutex_);
- Symbol result = tables_->FindSymbolOfType(name, Symbol::FIELD);
- if (!result.IsNull() && result.field_descriptor->is_extension()) {
+ Symbol result = tables_->FindByNameHelper(this, name);
+ if (result.type == Symbol::FIELD &&
+ result.field_descriptor->is_extension()) {
return result.field_descriptor;
+ } else {
+ return NULL;
}
- if (underlay_ != NULL) {
- const FieldDescriptor* result = underlay_->FindExtensionByName(name);
- if (result != NULL) return result;
- }
- if (TryFindSymbolInFallbackDatabase(name)) {
- Symbol result = tables_->FindSymbolOfType(name, Symbol::FIELD);
- if (!result.IsNull() && result.field_descriptor->is_extension()) {
- return result.field_descriptor;
- }
- }
- return NULL;
}
const EnumDescriptor* DescriptorPool::FindEnumTypeByName(
const string& name) const {
- MutexLockMaybe lock(mutex_);
- Symbol result = tables_->FindSymbolOfType(name, Symbol::ENUM);
- if (!result.IsNull()) return result.enum_descriptor;
- if (underlay_ != NULL) {
- const EnumDescriptor* result = underlay_->FindEnumTypeByName(name);
- if (result != NULL) return result;
- }
- if (TryFindSymbolInFallbackDatabase(name)) {
- Symbol result = tables_->FindSymbolOfType(name, Symbol::ENUM);
- if (!result.IsNull()) return result.enum_descriptor;
- }
- return NULL;
+ Symbol result = tables_->FindByNameHelper(this, name);
+ return (result.type == Symbol::ENUM) ? result.enum_descriptor : NULL;
}
const EnumValueDescriptor* DescriptorPool::FindEnumValueByName(
const string& name) const {
- MutexLockMaybe lock(mutex_);
- Symbol result = tables_->FindSymbolOfType(name, Symbol::ENUM_VALUE);
- if (!result.IsNull()) return result.enum_value_descriptor;
- if (underlay_ != NULL) {
- const EnumValueDescriptor* result = underlay_->FindEnumValueByName(name);
- if (result != NULL) return result;
- }
- if (TryFindSymbolInFallbackDatabase(name)) {
- Symbol result = tables_->FindSymbolOfType(name, Symbol::ENUM_VALUE);
- if (!result.IsNull()) return result.enum_value_descriptor;
- }
- return NULL;
+ Symbol result = tables_->FindByNameHelper(this, name);
+ return (result.type == Symbol::ENUM_VALUE) ?
+ result.enum_value_descriptor : NULL;
}
const ServiceDescriptor* DescriptorPool::FindServiceByName(
const string& name) const {
- MutexLockMaybe lock(mutex_);
- Symbol result = tables_->FindSymbolOfType(name, Symbol::SERVICE);
- if (!result.IsNull()) return result.service_descriptor;
- if (underlay_ != NULL) {
- const ServiceDescriptor* result = underlay_->FindServiceByName(name);
- if (result != NULL) return result;
- }
- if (TryFindSymbolInFallbackDatabase(name)) {
- Symbol result = tables_->FindSymbolOfType(name, Symbol::SERVICE);
- if (!result.IsNull()) return result.service_descriptor;
- }
- return NULL;
+ Symbol result = tables_->FindByNameHelper(this, name);
+ return (result.type == Symbol::SERVICE) ? result.service_descriptor : NULL;
}
const MethodDescriptor* DescriptorPool::FindMethodByName(
const string& name) const {
- MutexLockMaybe lock(mutex_);
- Symbol result = tables_->FindSymbolOfType(name, Symbol::METHOD);
- if (!result.IsNull()) return result.method_descriptor;
- if (underlay_ != NULL) {
- const MethodDescriptor* result = underlay_->FindMethodByName(name);
- if (result != NULL) return result;
- }
- if (TryFindSymbolInFallbackDatabase(name)) {
- Symbol result = tables_->FindSymbolOfType(name, Symbol::METHOD);
- if (!result.IsNull()) return result.method_descriptor;
- }
- return NULL;
+ Symbol result = tables_->FindByNameHelper(this, name);
+ return (result.type == Symbol::METHOD) ? result.method_descriptor : NULL;
}
const FieldDescriptor* DescriptorPool::FindExtensionByNumber(
@@ -844,6 +885,30 @@ Descriptor::FindFieldByNumber(int key) const {
}
const FieldDescriptor*
+Descriptor::FindFieldByLowercaseName(const string& key) const {
+ MutexLockMaybe lock(file()->pool()->mutex_);
+ const FieldDescriptor* result =
+ file()->pool()->tables_->FindFieldByLowercaseName(this, key);
+ if (result == NULL || result->is_extension()) {
+ return NULL;
+ } else {
+ return result;
+ }
+}
+
+const FieldDescriptor*
+Descriptor::FindFieldByCamelcaseName(const string& key) const {
+ MutexLockMaybe lock(file()->pool()->mutex_);
+ const FieldDescriptor* result =
+ file()->pool()->tables_->FindFieldByCamelcaseName(this, key);
+ if (result == NULL || result->is_extension()) {
+ return NULL;
+ } else {
+ return result;
+ }
+}
+
+const FieldDescriptor*
Descriptor::FindFieldByName(const string& key) const {
MutexLockMaybe lock(file()->pool()->mutex_);
Symbol result =
@@ -867,6 +932,30 @@ Descriptor::FindExtensionByName(const string& key) const {
}
}
+const FieldDescriptor*
+Descriptor::FindExtensionByLowercaseName(const string& key) const {
+ MutexLockMaybe lock(file()->pool()->mutex_);
+ const FieldDescriptor* result =
+ file()->pool()->tables_->FindFieldByLowercaseName(this, key);
+ if (result == NULL || !result->is_extension()) {
+ return NULL;
+ } else {
+ return result;
+ }
+}
+
+const FieldDescriptor*
+Descriptor::FindExtensionByCamelcaseName(const string& key) const {
+ MutexLockMaybe lock(file()->pool()->mutex_);
+ const FieldDescriptor* result =
+ file()->pool()->tables_->FindFieldByCamelcaseName(this, key);
+ if (result == NULL || !result->is_extension()) {
+ return NULL;
+ } else {
+ return result;
+ }
+}
+
const Descriptor*
Descriptor::FindNestedTypeByName(const string& key) const {
MutexLockMaybe lock(file()->pool()->mutex_);
@@ -995,6 +1084,30 @@ FileDescriptor::FindExtensionByName(const string& key) const {
}
}
+const FieldDescriptor*
+FileDescriptor::FindExtensionByLowercaseName(const string& key) const {
+ MutexLockMaybe lock(pool()->mutex_);
+ const FieldDescriptor* result =
+ pool()->tables_->FindFieldByLowercaseName(this, key);
+ if (result == NULL || !result->is_extension()) {
+ return NULL;
+ } else {
+ return result;
+ }
+}
+
+const FieldDescriptor*
+FileDescriptor::FindExtensionByCamelcaseName(const string& key) const {
+ MutexLockMaybe lock(pool()->mutex_);
+ const FieldDescriptor* result =
+ pool()->tables_->FindFieldByCamelcaseName(this, key);
+ if (result == NULL || !result->is_extension()) {
+ return NULL;
+ } else {
+ return result;
+ }
+}
+
bool Descriptor::IsExtensionNumber(int number) const {
// Linear search should be fine because we don't expect a message to have
// more than a couple extension ranges.
@@ -2504,6 +2617,22 @@ void DescriptorBuilder::BuildFieldOrExtension(const FieldDescriptorProto& proto,
result->number_ = proto.number();
result->is_extension_ = is_extension;
+ // If .proto files follow the style guide then the name should already be
+ // lower-cased. If that's the case we can just reuse the string we already
+ // allocated rather than allocate a new one.
+ string lowercase_name(proto.name());
+ LowerString(&lowercase_name);
+ if (lowercase_name == proto.name()) {
+ result->lowercase_name_ = result->name_;
+ } else {
+ result->lowercase_name_ = tables_->AllocateString(lowercase_name);
+ }
+
+ // Don't bother with the above optimization for camel-case names since
+ // .proto files that follow the guide shouldn't be using names in this
+ // format, so the optimization wouldn't help much.
+ result->camelcase_name_ = tables_->AllocateString(ToCamelCase(proto.name()));
+
// Some compilers do not allow static_cast directly between two enum types,
// so we must cast to int first.
result->type_ = static_cast<FieldDescriptor::Type>(
@@ -3042,6 +3171,9 @@ void DescriptorBuilder::CrossLinkField(
conflicting_field->name()));
}
}
+
+ // Add the field to the lowercase-name and camelcase-name tables.
+ tables_->AddFieldByStylizedNames(field);
}
void DescriptorBuilder::CrossLinkEnum(
@@ -3136,6 +3268,20 @@ void DescriptorBuilder::ValidateFieldOptions(FieldDescriptor* field,
ValidateMapKey(field, proto);
}
+ // Only repeated primitive fields may be packed.
+ if (field->options().packed()) {
+ if (!field->is_repeated() ||
+ field->type() == FieldDescriptor::TYPE_STRING ||
+ field->type() == FieldDescriptor::TYPE_GROUP ||
+ field->type() == FieldDescriptor::TYPE_MESSAGE ||
+ field->type() == FieldDescriptor::TYPE_BYTES) {
+ AddError(
+ field->full_name(), proto,
+ DescriptorPool::ErrorCollector::TYPE,
+ "[packed = true] can only be specified for repeated primitive fields.");
+ }
+ }
+
// Note: Default instance may not yet be initialized here, so we have to
// avoid reading from it.
if (field->containing_type_ != NULL &&
diff --git a/src/google/protobuf/descriptor.h b/src/google/protobuf/descriptor.h
index 6d496e99..918aafbc 100644
--- a/src/google/protobuf/descriptor.h
+++ b/src/google/protobuf/descriptor.h
@@ -156,6 +156,19 @@ class LIBPROTOBUF_EXPORT Descriptor {
// Looks up a field by name. Returns NULL if no such field exists.
const FieldDescriptor* FindFieldByName(const string& name) const;
+ // Looks up a field by lowercased name (as returned by lowercase_name()).
+ // This lookup may be ambiguous if multiple field names differ only by case,
+ // in which case the field returned is chosen arbitrarily from the matches.
+ const FieldDescriptor* FindFieldByLowercaseName(
+ const string& lowercase_name) const;
+
+ // Looks up a field by camel-case name (as returned by camelcase_name()).
+ // This lookup may be ambiguous if multiple field names differ in a way that
+ // leads them to have identical camel-case names, in which case the field
+ // returned is chosen arbitrarily from the matches.
+ const FieldDescriptor* FindFieldByCamelcaseName(
+ const string& camelcase_name) const;
+
// Nested type stuff -----------------------------------------------
// The number of nested types in this message type.
@@ -213,6 +226,14 @@ class LIBPROTOBUF_EXPORT Descriptor {
// defined within this message type's scope.
const FieldDescriptor* FindExtensionByName(const string& name) const;
+ // Similar to FindFieldByLowercaseName(), but finds extensions defined within
+ // this message type's scope.
+ const FieldDescriptor* FindExtensionByLowercaseName(const string& name) const;
+
+ // Similar to FindFieldByCamelcaseName(), but finds extensions defined within
+ // this message type's scope.
+ const FieldDescriptor* FindExtensionByCamelcaseName(const string& name) const;
+
private:
typedef MessageOptions OptionsType;
@@ -336,6 +357,25 @@ class LIBPROTOBUF_EXPORT FieldDescriptor {
bool is_extension() const; // Is this an extension field?
int number() const; // Declared tag number.
+ // Same as name() except converted to lower-case. This (and especially the
+ // FindFieldByLowercaseName() method) can be useful when parsing formats
+ // which prefer to use lowercase naming style. (Although, technically
+ // field names should be lowercased anyway according to the protobuf style
+ // guide, so this only makes a difference when dealing with old .proto files
+ // which do not follow the guide.)
+ const string& lowercase_name() const;
+
+ // Same as name() except converted to camel-case. In this conversion, any
+ // time an underscore appears in the name, it is removed and the next
+ // letter is capitalized. Furthermore, the first letter of the name is
+ // lower-cased. Examples:
+ // FooBar -> fooBar
+ // foo_bar -> fooBar
+ // fooBar -> fooBar
+ // This (and especially the FindFieldByCamelcaseName() method) can be useful
+ // when parsing formats which prefer to use camel-case naming style.
+ const string& camelcase_name() const;
+
Type type() const; // Declared type of this field.
CppType cpp_type() const; // C++ type of this field.
Label label() const; // optional/required/repeated
@@ -431,6 +471,8 @@ class LIBPROTOBUF_EXPORT FieldDescriptor {
const string* name_;
const string* full_name_;
+ const string* lowercase_name_;
+ const string* camelcase_name_;
const FileDescriptor* file_;
int number_;
Type type_;
@@ -773,6 +815,12 @@ class LIBPROTOBUF_EXPORT FileDescriptor {
const ServiceDescriptor* FindServiceByName(const string& name) const;
// Find a top-level extension definition by name. Returns NULL if not found.
const FieldDescriptor* FindExtensionByName(const string& name) const;
+ // Similar to FindExtensionByName(), but searches by lowercased-name. See
+ // Descriptor::FindFieldByLowercaseName().
+ const FieldDescriptor* FindExtensionByLowercaseName(const string& name) const;
+ // Similar to FindExtensionByName(), but searches by camelcased-name. See
+ // Descriptor::FindFieldByCamelcaseName().
+ const FieldDescriptor* FindExtensionByCamelcaseName(const string& name) const;
// See Descriptor::CopyTo().
void CopyTo(FileDescriptorProto* proto) const;
@@ -1084,6 +1132,8 @@ PROTOBUF_DEFINE_OPTIONS_ACCESSOR(Descriptor, MessageOptions);
PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, name)
PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, full_name)
+PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, lowercase_name)
+PROTOBUF_DEFINE_STRING_ACCESSOR(FieldDescriptor, camelcase_name)
PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, file, const FileDescriptor*)
PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, number, int)
PROTOBUF_DEFINE_ACCESSOR(FieldDescriptor, is_extension, bool)
diff --git a/src/google/protobuf/descriptor.pb.cc b/src/google/protobuf/descriptor.pb.cc
index ceb99bf1..0df3f3bd 100644
--- a/src/google/protobuf/descriptor.pb.cc
+++ b/src/google/protobuf/descriptor.pb.cc
@@ -301,8 +301,9 @@ void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescr
MessageOptions_descriptor_, MessageOptions::default_instance_);
FieldOptions_descriptor_ = file->message_type(10);
FieldOptions::default_instance_ = new FieldOptions();
- static const int FieldOptions_offsets_[3] = {
+ static const int FieldOptions_offsets_[4] = {
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, ctype_),
+ GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, packed_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, experimental_map_key_),
GOOGLE_PROTOBUF_GENERATED_MESSAGE_FIELD_OFFSET(FieldOptions, uninterpreted_option_),
};
@@ -519,30 +520,30 @@ void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto() {
"\n\016MessageOptions\022&\n\027message_set_wire_for"
"mat\030\001 \001(\010:\005false\022C\n\024uninterpreted_option"
"\030\347\007 \003(\0132$.google.protobuf.UninterpretedO"
- "ption*\t\010\350\007\020\200\200\200\200\002\"\325\001\n\014FieldOptions\0222\n\005cty"
+ "ption*\t\010\350\007\020\200\200\200\200\002\"\345\001\n\014FieldOptions\0222\n\005cty"
"pe\030\001 \001(\0162#.google.protobuf.FieldOptions."
- "CType\022\034\n\024experimental_map_key\030\t \001(\t\022C\n\024u"
- "ninterpreted_option\030\347\007 \003(\0132$.google.prot"
- "obuf.UninterpretedOption\"#\n\005CType\022\010\n\004COR"
- "D\020\001\022\020\n\014STRING_PIECE\020\002*\t\010\350\007\020\200\200\200\200\002\"]\n\013Enum"
- "Options\022C\n\024uninterpreted_option\030\347\007 \003(\0132$"
- ".google.protobuf.UninterpretedOption*\t\010\350"
- "\007\020\200\200\200\200\002\"b\n\020EnumValueOptions\022C\n\024uninterpr"
- "eted_option\030\347\007 \003(\0132$.google.protobuf.Uni"
- "nterpretedOption*\t\010\350\007\020\200\200\200\200\002\"`\n\016ServiceOp"
- "tions\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.g"
- "oogle.protobuf.UninterpretedOption*\t\010\350\007\020"
- "\200\200\200\200\002\"_\n\rMethodOptions\022C\n\024uninterpreted_"
- "option\030\347\007 \003(\0132$.google.protobuf.Uninterp"
- "retedOption*\t\010\350\007\020\200\200\200\200\002\"\205\002\n\023Uninterpreted"
- "Option\022;\n\004name\030\002 \003(\0132-.google.protobuf.U"
- "ninterpretedOption.NamePart\022\030\n\020identifie"
- "r_value\030\003 \001(\t\022\032\n\022positive_int_value\030\004 \001("
- "\004\022\032\n\022negative_int_value\030\005 \001(\003\022\024\n\014double_"
- "value\030\006 \001(\001\022\024\n\014string_value\030\007 \001(\014\0323\n\010Nam"
- "ePart\022\021\n\tname_part\030\001 \002(\t\022\024\n\014is_extension"
- "\030\002 \002(\010B)\n\023com.google.protobufB\020Descripto"
- "rProtosH\001", 3449,
+ "CType\022\016\n\006packed\030\002 \001(\010\022\034\n\024experimental_ma"
+ "p_key\030\t \001(\t\022C\n\024uninterpreted_option\030\347\007 \003"
+ "(\0132$.google.protobuf.UninterpretedOption"
+ "\"#\n\005CType\022\010\n\004CORD\020\001\022\020\n\014STRING_PIECE\020\002*\t\010"
+ "\350\007\020\200\200\200\200\002\"]\n\013EnumOptions\022C\n\024uninterpreted"
+ "_option\030\347\007 \003(\0132$.google.protobuf.Uninter"
+ "pretedOption*\t\010\350\007\020\200\200\200\200\002\"b\n\020EnumValueOpti"
+ "ons\022C\n\024uninterpreted_option\030\347\007 \003(\0132$.goo"
+ "gle.protobuf.UninterpretedOption*\t\010\350\007\020\200\200"
+ "\200\200\002\"`\n\016ServiceOptions\022C\n\024uninterpreted_o"
+ "ption\030\347\007 \003(\0132$.google.protobuf.Uninterpr"
+ "etedOption*\t\010\350\007\020\200\200\200\200\002\"_\n\rMethodOptions\022C"
+ "\n\024uninterpreted_option\030\347\007 \003(\0132$.google.p"
+ "rotobuf.UninterpretedOption*\t\010\350\007\020\200\200\200\200\002\"\205"
+ "\002\n\023UninterpretedOption\022;\n\004name\030\002 \003(\0132-.g"
+ "oogle.protobuf.UninterpretedOption.NameP"
+ "art\022\030\n\020identifier_value\030\003 \001(\t\022\032\n\022positiv"
+ "e_int_value\030\004 \001(\004\022\032\n\022negative_int_value\030"
+ "\005 \001(\003\022\024\n\014double_value\030\006 \001(\001\022\024\n\014string_va"
+ "lue\030\007 \001(\014\0323\n\010NamePart\022\021\n\tname_part\030\001 \002(\t"
+ "\022\024\n\014is_extension\030\002 \002(\010B)\n\023com.google.pro"
+ "tobufB\020DescriptorProtosH\001", 3465,
&protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescriptors);
}
@@ -639,7 +640,7 @@ bool FileDescriptorSet::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
// repeated .google.protobuf.FileDescriptorProto file = 1;
- for (int i = 0; i < file_.size(); i++) {
+ for (int i = 0; i < this->file_size(); i++) {
DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(1, this->file(i), output));
}
@@ -655,8 +656,8 @@ int FileDescriptorSet::ByteSize() const {
int total_size = 0;
// repeated .google.protobuf.FileDescriptorProto file = 1;
- total_size += 1 * file_size();
- for (int i = 0; i < file_size(); i++) {
+ total_size += 1 * this->file_size();
+ for (int i = 0; i < this->file_size(); i++) {
total_size +=
::google::protobuf::internal::WireFormat::MessageSizeNoVirtual(
this->file(i));
@@ -954,27 +955,27 @@ bool FileDescriptorProto::SerializeWithCachedSizes(
}
// repeated string dependency = 3;
- for (int i = 0; i < dependency_.size(); i++) {
+ for (int i = 0; i < this->dependency_size(); i++) {
DO_(::google::protobuf::internal::WireFormat::WriteString(3, this->dependency(i), output));
}
// repeated .google.protobuf.DescriptorProto message_type = 4;
- for (int i = 0; i < message_type_.size(); i++) {
+ for (int i = 0; i < this->message_type_size(); i++) {
DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(4, this->message_type(i), output));
}
// repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
- for (int i = 0; i < enum_type_.size(); i++) {
+ for (int i = 0; i < this->enum_type_size(); i++) {
DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(5, this->enum_type(i), output));
}
// repeated .google.protobuf.ServiceDescriptorProto service = 6;
- for (int i = 0; i < service_.size(); i++) {
+ for (int i = 0; i < this->service_size(); i++) {
DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(6, this->service(i), output));
}
// repeated .google.protobuf.FieldDescriptorProto extension = 7;
- for (int i = 0; i < extension_.size(); i++) {
+ for (int i = 0; i < this->extension_size(); i++) {
DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(7, this->extension(i), output));
}
@@ -1016,39 +1017,39 @@ int FileDescriptorProto::ByteSize() const {
}
// repeated string dependency = 3;
- total_size += 1 * dependency_size();
- for (int i = 0; i < dependency_size(); i++) {
+ total_size += 1 * this->dependency_size();
+ for (int i = 0; i < this->dependency_size(); i++) {
total_size += ::google::protobuf::internal::WireFormat::StringSize(
this->dependency(i));
}
// repeated .google.protobuf.DescriptorProto message_type = 4;
- total_size += 1 * message_type_size();
- for (int i = 0; i < message_type_size(); i++) {
+ total_size += 1 * this->message_type_size();
+ for (int i = 0; i < this->message_type_size(); i++) {
total_size +=
::google::protobuf::internal::WireFormat::MessageSizeNoVirtual(
this->message_type(i));
}
// repeated .google.protobuf.EnumDescriptorProto enum_type = 5;
- total_size += 1 * enum_type_size();
- for (int i = 0; i < enum_type_size(); i++) {
+ total_size += 1 * this->enum_type_size();
+ for (int i = 0; i < this->enum_type_size(); i++) {
total_size +=
::google::protobuf::internal::WireFormat::MessageSizeNoVirtual(
this->enum_type(i));
}
// repeated .google.protobuf.ServiceDescriptorProto service = 6;
- total_size += 1 * service_size();
- for (int i = 0; i < service_size(); i++) {
+ total_size += 1 * this->service_size();
+ for (int i = 0; i < this->service_size(); i++) {
total_size +=
::google::protobuf::internal::WireFormat::MessageSizeNoVirtual(
this->service(i));
}
// repeated .google.protobuf.FieldDescriptorProto extension = 7;
- total_size += 1 * extension_size();
- for (int i = 0; i < extension_size(); i++) {
+ total_size += 1 * this->extension_size();
+ for (int i = 0; i < this->extension_size(); i++) {
total_size +=
::google::protobuf::internal::WireFormat::MessageSizeNoVirtual(
this->extension(i));
@@ -1564,27 +1565,27 @@ bool DescriptorProto::SerializeWithCachedSizes(
}
// repeated .google.protobuf.FieldDescriptorProto field = 2;
- for (int i = 0; i < field_.size(); i++) {
+ for (int i = 0; i < this->field_size(); i++) {
DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(2, this->field(i), output));
}
// repeated .google.protobuf.DescriptorProto nested_type = 3;
- for (int i = 0; i < nested_type_.size(); i++) {
+ for (int i = 0; i < this->nested_type_size(); i++) {
DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(3, this->nested_type(i), output));
}
// repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
- for (int i = 0; i < enum_type_.size(); i++) {
+ for (int i = 0; i < this->enum_type_size(); i++) {
DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(4, this->enum_type(i), output));
}
// repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
- for (int i = 0; i < extension_range_.size(); i++) {
+ for (int i = 0; i < this->extension_range_size(); i++) {
DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(5, this->extension_range(i), output));
}
// repeated .google.protobuf.FieldDescriptorProto extension = 6;
- for (int i = 0; i < extension_.size(); i++) {
+ for (int i = 0; i < this->extension_size(); i++) {
DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(6, this->extension(i), output));
}
@@ -1620,40 +1621,40 @@ int DescriptorProto::ByteSize() const {
}
// repeated .google.protobuf.FieldDescriptorProto field = 2;
- total_size += 1 * field_size();
- for (int i = 0; i < field_size(); i++) {
+ total_size += 1 * this->field_size();
+ for (int i = 0; i < this->field_size(); i++) {
total_size +=
::google::protobuf::internal::WireFormat::MessageSizeNoVirtual(
this->field(i));
}
// repeated .google.protobuf.FieldDescriptorProto extension = 6;
- total_size += 1 * extension_size();
- for (int i = 0; i < extension_size(); i++) {
+ total_size += 1 * this->extension_size();
+ for (int i = 0; i < this->extension_size(); i++) {
total_size +=
::google::protobuf::internal::WireFormat::MessageSizeNoVirtual(
this->extension(i));
}
// repeated .google.protobuf.DescriptorProto nested_type = 3;
- total_size += 1 * nested_type_size();
- for (int i = 0; i < nested_type_size(); i++) {
+ total_size += 1 * this->nested_type_size();
+ for (int i = 0; i < this->nested_type_size(); i++) {
total_size +=
::google::protobuf::internal::WireFormat::MessageSizeNoVirtual(
this->nested_type(i));
}
// repeated .google.protobuf.EnumDescriptorProto enum_type = 4;
- total_size += 1 * enum_type_size();
- for (int i = 0; i < enum_type_size(); i++) {
+ total_size += 1 * this->enum_type_size();
+ for (int i = 0; i < this->enum_type_size(); i++) {
total_size +=
::google::protobuf::internal::WireFormat::MessageSizeNoVirtual(
this->enum_type(i));
}
// repeated .google.protobuf.DescriptorProto.ExtensionRange extension_range = 5;
- total_size += 1 * extension_range_size();
- for (int i = 0; i < extension_range_size(); i++) {
+ total_size += 1 * this->extension_range_size();
+ for (int i = 0; i < this->extension_range_size(); i++) {
total_size +=
::google::protobuf::internal::WireFormat::MessageSizeNoVirtual(
this->extension_range(i));
@@ -2407,7 +2408,7 @@ bool EnumDescriptorProto::SerializeWithCachedSizes(
}
// repeated .google.protobuf.EnumValueDescriptorProto value = 2;
- for (int i = 0; i < value_.size(); i++) {
+ for (int i = 0; i < this->value_size(); i++) {
DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(2, this->value(i), output));
}
@@ -2443,8 +2444,8 @@ int EnumDescriptorProto::ByteSize() const {
}
// repeated .google.protobuf.EnumValueDescriptorProto value = 2;
- total_size += 1 * value_size();
- for (int i = 0; i < value_size(); i++) {
+ total_size += 1 * this->value_size();
+ for (int i = 0; i < this->value_size(); i++) {
total_size +=
::google::protobuf::internal::WireFormat::MessageSizeNoVirtual(
this->value(i));
@@ -2919,7 +2920,7 @@ bool ServiceDescriptorProto::SerializeWithCachedSizes(
}
// repeated .google.protobuf.MethodDescriptorProto method = 2;
- for (int i = 0; i < method_.size(); i++) {
+ for (int i = 0; i < this->method_size(); i++) {
DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(2, this->method(i), output));
}
@@ -2955,8 +2956,8 @@ int ServiceDescriptorProto::ByteSize() const {
}
// repeated .google.protobuf.MethodDescriptorProto method = 2;
- total_size += 1 * method_size();
- for (int i = 0; i < method_size(); i++) {
+ total_size += 1 * this->method_size();
+ for (int i = 0; i < this->method_size(); i++) {
total_size +=
::google::protobuf::internal::WireFormat::MessageSizeNoVirtual(
this->method(i));
@@ -3561,7 +3562,7 @@ bool FileOptions::SerializeWithCachedSizes(
}
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- for (int i = 0; i < uninterpreted_option_.size(); i++) {
+ for (int i = 0; i < this->uninterpreted_option_size(); i++) {
DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(999, this->uninterpreted_option(i), output));
}
@@ -3606,8 +3607,8 @@ int FileOptions::ByteSize() const {
}
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- total_size += 2 * uninterpreted_option_size();
- for (int i = 0; i < uninterpreted_option_size(); i++) {
+ total_size += 2 * this->uninterpreted_option_size();
+ for (int i = 0; i < this->uninterpreted_option_size(); i++) {
total_size +=
::google::protobuf::internal::WireFormat::MessageSizeNoVirtual(
this->uninterpreted_option(i));
@@ -3821,7 +3822,7 @@ bool MessageOptions::SerializeWithCachedSizes(
}
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- for (int i = 0; i < uninterpreted_option_.size(); i++) {
+ for (int i = 0; i < this->uninterpreted_option_size(); i++) {
DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(999, this->uninterpreted_option(i), output));
}
@@ -3848,8 +3849,8 @@ int MessageOptions::ByteSize() const {
}
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- total_size += 2 * uninterpreted_option_size();
- for (int i = 0; i < uninterpreted_option_size(); i++) {
+ total_size += 2 * this->uninterpreted_option_size();
+ for (int i = 0; i < this->uninterpreted_option_size(); i++) {
total_size +=
::google::protobuf::internal::WireFormat::MessageSizeNoVirtual(
this->uninterpreted_option(i));
@@ -3954,6 +3955,7 @@ const FieldOptions_CType FieldOptions::CType_MIN;
const FieldOptions_CType FieldOptions::CType_MAX;
#endif // _MSC_VER
+
const ::std::string FieldOptions::_default_experimental_map_key_;
FieldOptions::FieldOptions()
@@ -3963,6 +3965,7 @@ FieldOptions::FieldOptions()
::google::protobuf::MessageFactory::generated_factory()),
_cached_size_(0),
ctype_(1),
+ packed_(false),
experimental_map_key_(const_cast< ::std::string*>(&_default_experimental_map_key_)) {
::memset(_has_bits_, 0, sizeof(_has_bits_));
}
@@ -3976,6 +3979,7 @@ FieldOptions::FieldOptions(const FieldOptions& from)
::google::protobuf::MessageFactory::generated_factory()),
_cached_size_(0),
ctype_(1),
+ packed_(false),
experimental_map_key_(const_cast< ::std::string*>(&_default_experimental_map_key_)) {
::memset(_has_bits_, 0, sizeof(_has_bits_));
MergeFrom(from);
@@ -4009,7 +4013,8 @@ void FieldOptions::Clear() {
_extensions_.Clear();
if (_has_bits_[0 / 32] & (0xffu << (0 % 32))) {
ctype_ = 1;
- if (_has_bit(1)) {
+ packed_ = false;
+ if (_has_bit(2)) {
if (experimental_map_key_ != &_default_experimental_map_key_) {
experimental_map_key_->clear();
}
@@ -4039,6 +4044,20 @@ bool FieldOptions::MergePartialFromCodedStream(
} else {
mutable_unknown_fields()->AddField(1)->add_varint(value);
}
+ if (input->ExpectTag(16)) goto parse_packed;
+ break;
+ }
+
+ // optional bool packed = 2;
+ case 2: {
+ if (::google::protobuf::internal::WireFormat::GetTagWireType(tag) !=
+ ::google::protobuf::internal::WireFormat::WIRETYPE_VARINT) {
+ goto handle_uninterpreted;
+ }
+ parse_packed:
+ DO_(::google::protobuf::internal::WireFormat::ReadBool(
+ input, &packed_));
+ _set_bit(1);
if (input->ExpectTag(74)) goto parse_experimental_map_key;
break;
}
@@ -4097,13 +4116,18 @@ bool FieldOptions::SerializeWithCachedSizes(
DO_(::google::protobuf::internal::WireFormat::WriteEnum(1, this->ctype(), output));
}
- // optional string experimental_map_key = 9;
+ // optional bool packed = 2;
if (_has_bit(1)) {
+ DO_(::google::protobuf::internal::WireFormat::WriteBool(2, this->packed(), output));
+ }
+
+ // optional string experimental_map_key = 9;
+ if (_has_bit(2)) {
DO_(::google::protobuf::internal::WireFormat::WriteString(9, this->experimental_map_key(), output));
}
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- for (int i = 0; i < uninterpreted_option_.size(); i++) {
+ for (int i = 0; i < this->uninterpreted_option_size(); i++) {
DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(999, this->uninterpreted_option(i), output));
}
@@ -4129,6 +4153,11 @@ int FieldOptions::ByteSize() const {
::google::protobuf::internal::WireFormat::EnumSize(this->ctype());
}
+ // optional bool packed = 2;
+ if (has_packed()) {
+ total_size += 1 + 1;
+ }
+
// optional string experimental_map_key = 9;
if (has_experimental_map_key()) {
total_size += 1 +
@@ -4137,8 +4166,8 @@ int FieldOptions::ByteSize() const {
}
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- total_size += 2 * uninterpreted_option_size();
- for (int i = 0; i < uninterpreted_option_size(); i++) {
+ total_size += 2 * this->uninterpreted_option_size();
+ for (int i = 0; i < this->uninterpreted_option_size(); i++) {
total_size +=
::google::protobuf::internal::WireFormat::MessageSizeNoVirtual(
this->uninterpreted_option(i));
@@ -4175,6 +4204,9 @@ void FieldOptions::MergeFrom(const FieldOptions& from) {
set_ctype(from.ctype());
}
if (from._has_bit(1)) {
+ set_packed(from.packed());
+ }
+ if (from._has_bit(2)) {
set_experimental_map_key(from.experimental_map_key());
}
}
@@ -4197,6 +4229,7 @@ void FieldOptions::CopyFrom(const FieldOptions& from) {
void FieldOptions::Swap(FieldOptions* other) {
if (other != this) {
std::swap(ctype_, other->ctype_);
+ std::swap(packed_, other->packed_);
std::swap(experimental_map_key_, other->experimental_map_key_);
uninterpreted_option_.Swap(&other->uninterpreted_option_);
std::swap(_has_bits_[0], other->_has_bits_[0]);
@@ -4320,7 +4353,7 @@ bool EnumOptions::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- for (int i = 0; i < uninterpreted_option_.size(); i++) {
+ for (int i = 0; i < this->uninterpreted_option_size(); i++) {
DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(999, this->uninterpreted_option(i), output));
}
@@ -4340,8 +4373,8 @@ int EnumOptions::ByteSize() const {
int total_size = 0;
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- total_size += 2 * uninterpreted_option_size();
- for (int i = 0; i < uninterpreted_option_size(); i++) {
+ total_size += 2 * this->uninterpreted_option_size();
+ for (int i = 0; i < this->uninterpreted_option_size(); i++) {
total_size +=
::google::protobuf::internal::WireFormat::MessageSizeNoVirtual(
this->uninterpreted_option(i));
@@ -4513,7 +4546,7 @@ bool EnumValueOptions::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- for (int i = 0; i < uninterpreted_option_.size(); i++) {
+ for (int i = 0; i < this->uninterpreted_option_size(); i++) {
DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(999, this->uninterpreted_option(i), output));
}
@@ -4533,8 +4566,8 @@ int EnumValueOptions::ByteSize() const {
int total_size = 0;
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- total_size += 2 * uninterpreted_option_size();
- for (int i = 0; i < uninterpreted_option_size(); i++) {
+ total_size += 2 * this->uninterpreted_option_size();
+ for (int i = 0; i < this->uninterpreted_option_size(); i++) {
total_size +=
::google::protobuf::internal::WireFormat::MessageSizeNoVirtual(
this->uninterpreted_option(i));
@@ -4706,7 +4739,7 @@ bool ServiceOptions::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- for (int i = 0; i < uninterpreted_option_.size(); i++) {
+ for (int i = 0; i < this->uninterpreted_option_size(); i++) {
DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(999, this->uninterpreted_option(i), output));
}
@@ -4726,8 +4759,8 @@ int ServiceOptions::ByteSize() const {
int total_size = 0;
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- total_size += 2 * uninterpreted_option_size();
- for (int i = 0; i < uninterpreted_option_size(); i++) {
+ total_size += 2 * this->uninterpreted_option_size();
+ for (int i = 0; i < this->uninterpreted_option_size(); i++) {
total_size +=
::google::protobuf::internal::WireFormat::MessageSizeNoVirtual(
this->uninterpreted_option(i));
@@ -4899,7 +4932,7 @@ bool MethodOptions::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- for (int i = 0; i < uninterpreted_option_.size(); i++) {
+ for (int i = 0; i < this->uninterpreted_option_size(); i++) {
DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(999, this->uninterpreted_option(i), output));
}
@@ -4919,8 +4952,8 @@ int MethodOptions::ByteSize() const {
int total_size = 0;
// repeated .google.protobuf.UninterpretedOption uninterpreted_option = 999;
- total_size += 2 * uninterpreted_option_size();
- for (int i = 0; i < uninterpreted_option_size(); i++) {
+ total_size += 2 * this->uninterpreted_option_size();
+ for (int i = 0; i < this->uninterpreted_option_size(); i++) {
total_size +=
::google::protobuf::internal::WireFormat::MessageSizeNoVirtual(
this->uninterpreted_option(i));
@@ -5398,7 +5431,7 @@ bool UninterpretedOption::SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const {
#define DO_(EXPRESSION) if (!(EXPRESSION)) return false
// repeated .google.protobuf.UninterpretedOption.NamePart name = 2;
- for (int i = 0; i < name_.size(); i++) {
+ for (int i = 0; i < this->name_size(); i++) {
DO_(::google::protobuf::internal::WireFormat::WriteMessageNoVirtual(2, this->name(i), output));
}
@@ -5472,8 +5505,8 @@ int UninterpretedOption::ByteSize() const {
}
// repeated .google.protobuf.UninterpretedOption.NamePart name = 2;
- total_size += 1 * name_size();
- for (int i = 0; i < name_size(); i++) {
+ total_size += 1 * this->name_size();
+ for (int i = 0; i < this->name_size(); i++) {
total_size +=
::google::protobuf::internal::WireFormat::MessageSizeNoVirtual(
this->name(i));
diff --git a/src/google/protobuf/descriptor.pb.h b/src/google/protobuf/descriptor.pb.h
index 8fa51dd6..e5077aae 100644
--- a/src/google/protobuf/descriptor.pb.h
+++ b/src/google/protobuf/descriptor.pb.h
@@ -12,7 +12,7 @@
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
-#if 2000003 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
+#if 2000004 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.
@@ -1645,6 +1645,12 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message {
inline ::google::protobuf::FieldOptions_CType ctype() const;
inline void set_ctype(::google::protobuf::FieldOptions_CType value);
+ // optional bool packed = 2;
+ inline bool has_packed() const;
+ inline void clear_packed();
+ inline bool packed() const;
+ inline void set_packed(bool value);
+
// optional string experimental_map_key = 9;
inline bool has_experimental_map_key() const;
inline void clear_experimental_map_key();
@@ -1749,12 +1755,13 @@ class LIBPROTOBUF_EXPORT FieldOptions : public ::google::protobuf::Message {
mutable int _cached_size_;
int ctype_;
+ bool packed_;
::std::string* experimental_map_key_;
static const ::std::string _default_experimental_map_key_;
::google::protobuf::RepeatedPtrField< ::google::protobuf::UninterpretedOption > uninterpreted_option_;
friend void protobuf_BuildDesc_google_2fprotobuf_2fdescriptor_2eproto_AssignGlobalDescriptors(
const ::google::protobuf::FileDescriptor* file);
- ::google::protobuf::uint32 _has_bits_[(3 + 31) / 32];
+ ::google::protobuf::uint32 _has_bits_[(4 + 31) / 32];
// WHY DOES & HAVE LOWER PRECEDENCE THAN != !?
inline bool _has_bit(int index) const {
@@ -3908,35 +3915,51 @@ inline void FieldOptions::set_ctype(::google::protobuf::FieldOptions_CType value
ctype_ = value;
}
+// optional bool packed = 2;
+inline bool FieldOptions::has_packed() const {
+ return _has_bit(1);
+}
+inline void FieldOptions::clear_packed() {
+ packed_ = false;
+ _clear_bit(1);
+}
+inline bool FieldOptions::packed() const {
+ return packed_;
+}
+inline void FieldOptions::set_packed(bool value) {
+ _set_bit(1);
+ packed_ = value;
+}
+
// optional string experimental_map_key = 9;
inline bool FieldOptions::has_experimental_map_key() const {
- return _has_bit(1);
+ return _has_bit(2);
}
inline void FieldOptions::clear_experimental_map_key() {
if (experimental_map_key_ != &_default_experimental_map_key_) {
experimental_map_key_->clear();
}
- _clear_bit(1);
+ _clear_bit(2);
}
inline const ::std::string& FieldOptions::experimental_map_key() const {
return *experimental_map_key_;
}
inline void FieldOptions::set_experimental_map_key(const ::std::string& value) {
- _set_bit(1);
+ _set_bit(2);
if (experimental_map_key_ == &_default_experimental_map_key_) {
experimental_map_key_ = new ::std::string;
}
experimental_map_key_->assign(value);
}
inline void FieldOptions::set_experimental_map_key(const char* value) {
- _set_bit(1);
+ _set_bit(2);
if (experimental_map_key_ == &_default_experimental_map_key_) {
experimental_map_key_ = new ::std::string;
}
experimental_map_key_->assign(value);
}
inline ::std::string* FieldOptions::mutable_experimental_map_key() {
- _set_bit(1);
+ _set_bit(2);
if (experimental_map_key_ == &_default_experimental_map_key_) {
experimental_map_key_ = new ::std::string;
}
diff --git a/src/google/protobuf/descriptor.proto b/src/google/protobuf/descriptor.proto
index 9cdd61c5..e0e6f7f2 100644
--- a/src/google/protobuf/descriptor.proto
+++ b/src/google/protobuf/descriptor.proto
@@ -253,6 +253,7 @@ message FileOptions {
optional OptimizeMode optimize_for = 9 [default=CODE_SIZE];
+
// The parser stores options it doesn't recognize here. See above.
repeated UninterpretedOption uninterpreted_option = 999;
@@ -299,6 +300,11 @@ message FieldOptions {
STRING_PIECE = 2;
}
+ // The packed option can be enabled for repeated primitive fields to enable
+ // a more efficient representation on the wire. Rather than repeatedly
+ // writing the tag and type for each element, the entire array is encoded as
+ // a single length-delimited blob.
+ optional bool packed = 2;
// EXPERIMENTAL. DO NOT USE.
// For "map" fields, the name of the field in the enclosed type that
diff --git a/src/google/protobuf/descriptor_unittest.cc b/src/google/protobuf/descriptor_unittest.cc
index f4e60b3a..5ffaea77 100644
--- a/src/google/protobuf/descriptor_unittest.cc
+++ b/src/google/protobuf/descriptor_unittest.cc
@@ -53,7 +53,8 @@
namespace google {
namespace protobuf {
-namespace GOOGLE_ANONYMOUS_NAMESPACE{
+// Can't use an anonymous namespace here due to brokenness of Tru64 compiler.
+namespace descriptor_unittest {
// Some helpers to make assembling descriptors faster.
DescriptorProto* AddMessage(FileDescriptorProto* file, const string& name) {
@@ -631,6 +632,188 @@ TEST_F(DescriptorTest, FieldEnumType) {
// ===================================================================
+class StylizedFieldNamesTest : public testing::Test {
+ protected:
+ void SetUp() {
+ FileDescriptorProto file;
+ file.set_name("foo.proto");
+
+ AddExtensionRange(AddMessage(&file, "ExtendableMessage"), 1, 1000);
+
+ DescriptorProto* message = AddMessage(&file, "TestMessage");
+ AddField(message, "foo_foo", 1,
+ FieldDescriptorProto::LABEL_OPTIONAL,
+ FieldDescriptorProto::TYPE_INT32);
+ AddField(message, "FooBar", 2,
+ FieldDescriptorProto::LABEL_OPTIONAL,
+ FieldDescriptorProto::TYPE_INT32);
+ AddField(message, "fooBaz", 3,
+ FieldDescriptorProto::LABEL_OPTIONAL,
+ FieldDescriptorProto::TYPE_INT32);
+ AddField(message, "fooFoo", 4, // Camel-case conflict with foo_foo.
+ FieldDescriptorProto::LABEL_OPTIONAL,
+ FieldDescriptorProto::TYPE_INT32);
+ AddField(message, "foobar", 5, // Lower-case conflict with FooBar.
+ FieldDescriptorProto::LABEL_OPTIONAL,
+ FieldDescriptorProto::TYPE_INT32);
+
+ AddNestedExtension(message, "ExtendableMessage", "bar_foo", 1,
+ FieldDescriptorProto::LABEL_OPTIONAL,
+ FieldDescriptorProto::TYPE_INT32);
+ AddNestedExtension(message, "ExtendableMessage", "BarBar", 2,
+ FieldDescriptorProto::LABEL_OPTIONAL,
+ FieldDescriptorProto::TYPE_INT32);
+ AddNestedExtension(message, "ExtendableMessage", "BarBaz", 3,
+ FieldDescriptorProto::LABEL_OPTIONAL,
+ FieldDescriptorProto::TYPE_INT32);
+ AddNestedExtension(message, "ExtendableMessage", "barFoo", 4, // Conflict
+ FieldDescriptorProto::LABEL_OPTIONAL,
+ FieldDescriptorProto::TYPE_INT32);
+ AddNestedExtension(message, "ExtendableMessage", "barbar", 5, // Conflict
+ FieldDescriptorProto::LABEL_OPTIONAL,
+ FieldDescriptorProto::TYPE_INT32);
+
+ AddExtension(&file, "ExtendableMessage", "baz_foo", 11,
+ FieldDescriptorProto::LABEL_OPTIONAL,
+ FieldDescriptorProto::TYPE_INT32);
+ AddExtension(&file, "ExtendableMessage", "BazBar", 12,
+ FieldDescriptorProto::LABEL_OPTIONAL,
+ FieldDescriptorProto::TYPE_INT32);
+ AddExtension(&file, "ExtendableMessage", "BazBaz", 13,
+ FieldDescriptorProto::LABEL_OPTIONAL,
+ FieldDescriptorProto::TYPE_INT32);
+ AddExtension(&file, "ExtendableMessage", "bazFoo", 14, // Conflict
+ FieldDescriptorProto::LABEL_OPTIONAL,
+ FieldDescriptorProto::TYPE_INT32);
+ AddExtension(&file, "ExtendableMessage", "bazbar", 15, // Conflict
+ FieldDescriptorProto::LABEL_OPTIONAL,
+ FieldDescriptorProto::TYPE_INT32);
+
+ file_ = pool_.BuildFile(file);
+ ASSERT_TRUE(file_ != NULL);
+ ASSERT_EQ(2, file_->message_type_count());
+ message_ = file_->message_type(1);
+ ASSERT_EQ("TestMessage", message_->name());
+ ASSERT_EQ(5, message_->field_count());
+ ASSERT_EQ(5, message_->extension_count());
+ ASSERT_EQ(5, file_->extension_count());
+ }
+
+ DescriptorPool pool_;
+ const FileDescriptor* file_;
+ const Descriptor* message_;
+};
+
+TEST_F(StylizedFieldNamesTest, LowercaseName) {
+ EXPECT_EQ("foo_foo", message_->field(0)->lowercase_name());
+ EXPECT_EQ("foobar" , message_->field(1)->lowercase_name());
+ EXPECT_EQ("foobaz" , message_->field(2)->lowercase_name());
+ EXPECT_EQ("foofoo" , message_->field(3)->lowercase_name());
+ EXPECT_EQ("foobar" , message_->field(4)->lowercase_name());
+
+ EXPECT_EQ("bar_foo", message_->extension(0)->lowercase_name());
+ EXPECT_EQ("barbar" , message_->extension(1)->lowercase_name());
+ EXPECT_EQ("barbaz" , message_->extension(2)->lowercase_name());
+ EXPECT_EQ("barfoo" , message_->extension(3)->lowercase_name());
+ EXPECT_EQ("barbar" , message_->extension(4)->lowercase_name());
+
+ EXPECT_EQ("baz_foo", file_->extension(0)->lowercase_name());
+ EXPECT_EQ("bazbar" , file_->extension(1)->lowercase_name());
+ EXPECT_EQ("bazbaz" , file_->extension(2)->lowercase_name());
+ EXPECT_EQ("bazfoo" , file_->extension(3)->lowercase_name());
+ EXPECT_EQ("bazbar" , file_->extension(4)->lowercase_name());
+}
+
+TEST_F(StylizedFieldNamesTest, CamelcaseName) {
+ EXPECT_EQ("fooFoo", message_->field(0)->camelcase_name());
+ EXPECT_EQ("fooBar", message_->field(1)->camelcase_name());
+ EXPECT_EQ("fooBaz", message_->field(2)->camelcase_name());
+ EXPECT_EQ("fooFoo", message_->field(3)->camelcase_name());
+ EXPECT_EQ("foobar", message_->field(4)->camelcase_name());
+
+ EXPECT_EQ("barFoo", message_->extension(0)->camelcase_name());
+ EXPECT_EQ("barBar", message_->extension(1)->camelcase_name());
+ EXPECT_EQ("barBaz", message_->extension(2)->camelcase_name());
+ EXPECT_EQ("barFoo", message_->extension(3)->camelcase_name());
+ EXPECT_EQ("barbar", message_->extension(4)->camelcase_name());
+
+ EXPECT_EQ("bazFoo", file_->extension(0)->camelcase_name());
+ EXPECT_EQ("bazBar", file_->extension(1)->camelcase_name());
+ EXPECT_EQ("bazBaz", file_->extension(2)->camelcase_name());
+ EXPECT_EQ("bazFoo", file_->extension(3)->camelcase_name());
+ EXPECT_EQ("bazbar", file_->extension(4)->camelcase_name());
+}
+
+TEST_F(StylizedFieldNamesTest, FindByLowercaseName) {
+ EXPECT_EQ(message_->field(0),
+ message_->FindFieldByLowercaseName("foo_foo"));
+ EXPECT_EQ(message_->field(1),
+ message_->FindFieldByLowercaseName("foobar"));
+ EXPECT_EQ(message_->field(2),
+ message_->FindFieldByLowercaseName("foobaz"));
+ EXPECT_TRUE(message_->FindFieldByLowercaseName("FooBar") == NULL);
+ EXPECT_TRUE(message_->FindFieldByLowercaseName("fooBaz") == NULL);
+ EXPECT_TRUE(message_->FindFieldByLowercaseName("bar_foo") == NULL);
+ EXPECT_TRUE(message_->FindFieldByLowercaseName("nosuchfield") == NULL);
+
+ EXPECT_EQ(message_->extension(0),
+ message_->FindExtensionByLowercaseName("bar_foo"));
+ EXPECT_EQ(message_->extension(1),
+ message_->FindExtensionByLowercaseName("barbar"));
+ EXPECT_EQ(message_->extension(2),
+ message_->FindExtensionByLowercaseName("barbaz"));
+ EXPECT_TRUE(message_->FindExtensionByLowercaseName("BarBar") == NULL);
+ EXPECT_TRUE(message_->FindExtensionByLowercaseName("barBaz") == NULL);
+ EXPECT_TRUE(message_->FindExtensionByLowercaseName("foo_foo") == NULL);
+ EXPECT_TRUE(message_->FindExtensionByLowercaseName("nosuchfield") == NULL);
+
+ EXPECT_EQ(file_->extension(0),
+ file_->FindExtensionByLowercaseName("baz_foo"));
+ EXPECT_EQ(file_->extension(1),
+ file_->FindExtensionByLowercaseName("bazbar"));
+ EXPECT_EQ(file_->extension(2),
+ file_->FindExtensionByLowercaseName("bazbaz"));
+ EXPECT_TRUE(file_->FindExtensionByLowercaseName("BazBar") == NULL);
+ EXPECT_TRUE(file_->FindExtensionByLowercaseName("bazBaz") == NULL);
+ EXPECT_TRUE(file_->FindExtensionByLowercaseName("nosuchfield") == NULL);
+}
+
+TEST_F(StylizedFieldNamesTest, FindByCamelcaseName) {
+ EXPECT_EQ(message_->field(0),
+ message_->FindFieldByCamelcaseName("fooFoo"));
+ EXPECT_EQ(message_->field(1),
+ message_->FindFieldByCamelcaseName("fooBar"));
+ EXPECT_EQ(message_->field(2),
+ message_->FindFieldByCamelcaseName("fooBaz"));
+ EXPECT_TRUE(message_->FindFieldByCamelcaseName("foo_foo") == NULL);
+ EXPECT_TRUE(message_->FindFieldByCamelcaseName("FooBar") == NULL);
+ EXPECT_TRUE(message_->FindFieldByCamelcaseName("barFoo") == NULL);
+ EXPECT_TRUE(message_->FindFieldByCamelcaseName("nosuchfield") == NULL);
+
+ EXPECT_EQ(message_->extension(0),
+ message_->FindExtensionByCamelcaseName("barFoo"));
+ EXPECT_EQ(message_->extension(1),
+ message_->FindExtensionByCamelcaseName("barBar"));
+ EXPECT_EQ(message_->extension(2),
+ message_->FindExtensionByCamelcaseName("barBaz"));
+ EXPECT_TRUE(message_->FindExtensionByCamelcaseName("bar_foo") == NULL);
+ EXPECT_TRUE(message_->FindExtensionByCamelcaseName("BarBar") == NULL);
+ EXPECT_TRUE(message_->FindExtensionByCamelcaseName("fooFoo") == NULL);
+ EXPECT_TRUE(message_->FindExtensionByCamelcaseName("nosuchfield") == NULL);
+
+ EXPECT_EQ(file_->extension(0),
+ file_->FindExtensionByCamelcaseName("bazFoo"));
+ EXPECT_EQ(file_->extension(1),
+ file_->FindExtensionByCamelcaseName("bazBar"));
+ EXPECT_EQ(file_->extension(2),
+ file_->FindExtensionByCamelcaseName("bazBaz"));
+ EXPECT_TRUE(file_->FindExtensionByCamelcaseName("baz_foo") == NULL);
+ EXPECT_TRUE(file_->FindExtensionByCamelcaseName("BazBar") == NULL);
+ EXPECT_TRUE(file_->FindExtensionByCamelcaseName("nosuchfield") == NULL);
+}
+
+// ===================================================================
+
// Test enum descriptors.
class EnumDescriptorTest : public testing::Test {
protected:
@@ -2457,6 +2640,36 @@ TEST_F(ValidationErrorTest, OutputTypeNotAMessage) {
"foo.proto: TestService.A: OUTPUT_TYPE: \"Bar\" is not a message type.\n");
}
+TEST_F(ValidationErrorTest, IllegalPackedField) {
+ BuildFileWithErrors(
+ "name: \"foo.proto\" "
+ "message_type {\n"
+ " name: \"Foo\""
+ " field { name:\"packed_string\" number:1 label:LABEL_REPEATED "
+ " type:TYPE_STRING "
+ " options { uninterpreted_option {"
+ " name { name_part: \"packed\" is_extension: false }"
+ " identifier_value: \"true\" }}}\n"
+ " field { name:\"packed_message\" number:3 label:LABEL_REPEATED "
+ " type_name: \"Foo\""
+ " options { uninterpreted_option {"
+ " name { name_part: \"packed\" is_extension: false }"
+ " identifier_value: \"true\" }}}\n"
+ " field { name:\"optional_int32\" number: 4 label: LABEL_OPTIONAL "
+ " type:TYPE_INT32 "
+ " options { uninterpreted_option {"
+ " name { name_part: \"packed\" is_extension: false }"
+ " identifier_value: \"true\" }}}\n"
+ "}",
+
+ "foo.proto: Foo.packed_string: TYPE: [packed = true] can only be "
+ "specified for repeated primitive fields.\n"
+ "foo.proto: Foo.packed_message: TYPE: [packed = true] can only be "
+ "specified for repeated primitive fields.\n"
+ "foo.proto: Foo.optional_int32: TYPE: [packed = true] can only be "
+ "specified for repeated primitive fields.\n"
+ );
+}
TEST_F(ValidationErrorTest, OptionWrongType) {
BuildFileWithErrors(
@@ -3255,6 +3468,34 @@ TEST_F(DatabaseBackedPoolTest, DoesntReloadKnownBadFiles) {
EXPECT_EQ("", error_collector.text_);
}
-} // anonymous namespace
+TEST_F(DatabaseBackedPoolTest, DoesntFallbackOnWrongType) {
+ // If a lookup finds a symbol of the wrong type (e.g. we pass a type name
+ // to FindFieldByName()), we should fail fast, without checking the fallback
+ // database.
+ CallCountingDatabase call_counter(&database_);
+ DescriptorPool pool(&call_counter);
+
+ const FileDescriptor* file = pool.FindFileByName("foo.proto");
+ ASSERT_TRUE(file != NULL);
+ const Descriptor* foo = pool.FindMessageTypeByName("Foo");
+ ASSERT_TRUE(foo != NULL);
+ const EnumDescriptor* test_enum = pool.FindEnumTypeByName("TestEnum");
+ ASSERT_TRUE(test_enum != NULL);
+
+ EXPECT_NE(0, call_counter.call_count_);
+ call_counter.Clear();
+
+ EXPECT_TRUE(pool.FindMessageTypeByName("TestEnum") == NULL);
+ EXPECT_TRUE(pool.FindFieldByName("Foo") == NULL);
+ EXPECT_TRUE(pool.FindExtensionByName("Foo") == NULL);
+ EXPECT_TRUE(pool.FindEnumTypeByName("Foo") == NULL);
+ EXPECT_TRUE(pool.FindEnumValueByName("Foo") == NULL);
+ EXPECT_TRUE(pool.FindServiceByName("Foo") == NULL);
+ EXPECT_TRUE(pool.FindMethodByName("Foo") == NULL);
+
+ EXPECT_EQ(0, call_counter.call_count_);
+}
+
+} // namespace descriptor_unittest
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/dynamic_message_unittest.cc b/src/google/protobuf/dynamic_message_unittest.cc
index 5f7af94e..41b89ab5 100644
--- a/src/google/protobuf/dynamic_message_unittest.cc
+++ b/src/google/protobuf/dynamic_message_unittest.cc
@@ -61,6 +61,8 @@ class DynamicMessageTest : public testing::Test {
const Message* prototype_;
const Descriptor* extensions_descriptor_;
const Message* extensions_prototype_;
+ const Descriptor* packed_descriptor_;
+ const Message* packed_prototype_;
DynamicMessageTest(): factory_(&pool_) {}
@@ -87,6 +89,11 @@ class DynamicMessageTest : public testing::Test {
pool_.FindMessageTypeByName("protobuf_unittest.TestAllExtensions");
ASSERT_TRUE(extensions_descriptor_ != NULL);
extensions_prototype_ = factory_.GetPrototype(extensions_descriptor_);
+
+ packed_descriptor_ =
+ pool_.FindMessageTypeByName("protobuf_unittest.TestPackedTypes");
+ ASSERT_TRUE(packed_descriptor_ != NULL);
+ packed_prototype_ = factory_.GetPrototype(packed_descriptor_);
}
};
@@ -127,6 +134,15 @@ TEST_F(DynamicMessageTest, Extensions) {
reflection_tester.ExpectAllFieldsSetViaReflection(*message);
}
+TEST_F(DynamicMessageTest, PackedFields) {
+ // Check that packed fields work properly.
+ scoped_ptr<Message> message(packed_prototype_->New());
+ TestUtil::ReflectionTester reflection_tester(packed_descriptor_);
+
+ reflection_tester.SetPackedFieldsViaReflection(message.get());
+ reflection_tester.ExpectPackedFieldsSetViaReflection(*message);
+}
+
TEST_F(DynamicMessageTest, SpaceUsed) {
// Test that SpaceUsed() works properly
diff --git a/src/google/protobuf/extension_set_unittest.cc b/src/google/protobuf/extension_set_unittest.cc
index c3ac7ce7..631bbc43 100644
--- a/src/google/protobuf/extension_set_unittest.cc
+++ b/src/google/protobuf/extension_set_unittest.cc
@@ -179,6 +179,19 @@ TEST(ExtensionSetTest, Serialization) {
TestUtil::ExpectAllFieldsSet(destination);
}
+TEST(ExtensionSetTest, PackedSerialization) {
+ // Serialize as TestPackedExtensions and parse as TestPackedTypes to insure
+ // wire compatibility of extensions.
+ unittest::TestPackedExtensions source;
+ unittest::TestPackedTypes destination;
+ string data;
+
+ TestUtil::SetPackedExtensions(&source);
+ source.SerializeToString(&data);
+ EXPECT_TRUE(destination.ParseFromString(data));
+ TestUtil::ExpectPackedFieldsSet(destination);
+}
+
TEST(ExtensionSetTest, Parsing) {
// Serialize as TestAllTypes and parse as TestAllExtensions.
unittest::TestAllTypes source;
@@ -191,6 +204,18 @@ TEST(ExtensionSetTest, Parsing) {
TestUtil::ExpectAllExtensionsSet(destination);
}
+TEST(ExtensionSetTest, PackedParsing) {
+ // Serialize as TestPackedTypes and parse as TestPackedExtensions.
+ unittest::TestPackedTypes source;
+ unittest::TestPackedExtensions destination;
+ string data;
+
+ TestUtil::SetPackedFields(&source);
+ source.SerializeToString(&data);
+ EXPECT_TRUE(destination.ParseFromString(data));
+ TestUtil::ExpectPackedExtensionsSet(destination);
+}
+
TEST(ExtensionSetTest, IsInitialized) {
// Test that IsInitialized() returns false if required fields in nested
// extensions are missing.
diff --git a/src/google/protobuf/io/coded_stream.cc b/src/google/protobuf/io/coded_stream.cc
index 66f95906..a0f08571 100644
--- a/src/google/protobuf/io/coded_stream.cc
+++ b/src/google/protobuf/io/coded_stream.cc
@@ -207,6 +207,14 @@ bool CodedInputStream::Skip(int count) {
return input_->Skip(count);
}
+bool CodedInputStream::GetDirectBufferPointer(const void** data, int* size) {
+ if (buffer_size_ == 0 && !Refresh()) return false;
+
+ *data = buffer_;
+ *size = buffer_size_;
+ return true;
+}
+
bool CodedInputStream::ReadRaw(void* buffer, int size) {
while (buffer_size_ < size) {
// Reading past end of buffer. Copy what we have, then refresh.
@@ -515,6 +523,26 @@ CodedOutputStream::~CodedOutputStream() {
}
}
+bool CodedOutputStream::Skip(int count) {
+ if (count < 0) return false;
+
+ while (count > buffer_size_) {
+ count -= buffer_size_;
+ if (!Refresh()) return false;
+ }
+
+ Advance(count);
+ return true;
+}
+
+bool CodedOutputStream::GetDirectBufferPointer(void** data, int* size) {
+ if (buffer_size_ == 0 && !Refresh()) return false;
+
+ *data = buffer_;
+ *size = buffer_size_;
+ return true;
+}
+
bool CodedOutputStream::WriteRaw(const void* data, int size) {
while (buffer_size_ < size) {
memcpy(buffer_, data, buffer_size_);
diff --git a/src/google/protobuf/io/coded_stream.h b/src/google/protobuf/io/coded_stream.h
index a73ac0ba..8ebe4b35 100644
--- a/src/google/protobuf/io/coded_stream.h
+++ b/src/google/protobuf/io/coded_stream.h
@@ -149,6 +149,15 @@ class LIBPROTOBUF_EXPORT CodedInputStream {
// occurs.
bool Skip(int count);
+ // Sets *data to point directly at the unread part of the CodedInputStream's
+ // underlying buffer, and *size to the size of that buffer, but does not
+ // advance the stream's current position. This will always either produce
+ // a non-empty buffer or return false. If the caller consumes any of
+ // this data, it should then call Skip() to skip over the consumed bytes.
+ // This may be useful for implementing external fast parsing routines for
+ // types of data not covered by the CodedInputStream interface.
+ bool GetDirectBufferPointer(const void** data, int* size);
+
// Read raw bytes, copying them into the given buffer.
bool ReadRaw(void* buffer, int size);
@@ -381,6 +390,21 @@ class LIBPROTOBUF_EXPORT CodedOutputStream {
// ZeroCopyOutputStream immediately after the last byte written.
~CodedOutputStream();
+ // Skips a number of bytes, leaving the bytes unmodified in the underlying
+ // buffer. Returns false if an underlying write error occurs. This is
+ // mainly useful with GetDirectBufferPointer().
+ bool Skip(int count);
+
+ // Sets *data to point directly at the unwritten part of the
+ // CodedOutputStream's underlying buffer, and *size to the size of that
+ // buffer, but does not advance the stream's current position. This will
+ // always either produce a non-empty buffer or return false. If the caller
+ // writes any data to this buffer, it should then call Skip() to skip over
+ // the consumed bytes. This may be useful for implementing external fast
+ // serialization routines for types of data not covered by the
+ // CodedOutputStream interface.
+ bool GetDirectBufferPointer(void** data, int* size);
+
// Write raw bytes, copying them from the given buffer.
bool WriteRaw(const void* buffer, int size);
@@ -518,7 +542,7 @@ inline bool CodedInputStream::ExpectAtEnd() {
inline bool CodedOutputStream::WriteVarint32(uint32 value) {
if (value < 0x80 && buffer_size_ > 0) {
- *buffer_ = value;
+ *buffer_ = static_cast<uint8>(value);
Advance(1);
return true;
} else {
@@ -537,7 +561,7 @@ inline bool CodedOutputStream::WriteVarint32SignExtended(int32 value) {
inline bool CodedOutputStream::WriteTag(uint32 value) {
if (value < (1 << 7)) {
if (buffer_size_ != 0) {
- buffer_[0] = value;
+ buffer_[0] = static_cast<uint8>(value);
Advance(1);
return true;
}
diff --git a/src/google/protobuf/io/coded_stream_unittest.cc b/src/google/protobuf/io/coded_stream_unittest.cc
index 459b94a6..6a6eafe9 100644
--- a/src/google/protobuf/io/coded_stream_unittest.cc
+++ b/src/google/protobuf/io/coded_stream_unittest.cc
@@ -77,6 +77,9 @@ namespace {
// which failed will be printed. The case type must be printable using
// ostream::operator<<.
+// TODO(kenton): gTest now supports "parameterized tests" which would be
+// a better way to accomplish this. Rewrite when time permits.
+
#define TEST_1D(FIXTURE, NAME, CASES) \
class FIXTURE##_##NAME##_DD : public FIXTURE { \
protected: \
@@ -614,6 +617,73 @@ TEST_1D(CodedStreamTest, SkipInput, kBlockSizes) {
}
// -------------------------------------------------------------------
+// GetDirectBufferPointer
+
+TEST_F(CodedStreamTest, GetDirectBufferPointerInput) {
+ ArrayInputStream input(buffer_, sizeof(buffer_), 8);
+ CodedInputStream coded_input(&input);
+
+ const void* ptr;
+ int size;
+
+ EXPECT_TRUE(coded_input.GetDirectBufferPointer(&ptr, &size));
+ EXPECT_EQ(buffer_, ptr);
+ EXPECT_EQ(8, size);
+
+ // Peeking again should return the same pointer.
+ EXPECT_TRUE(coded_input.GetDirectBufferPointer(&ptr, &size));
+ EXPECT_EQ(buffer_, ptr);
+ EXPECT_EQ(8, size);
+
+ // Skip forward in the same buffer then peek again.
+ EXPECT_TRUE(coded_input.Skip(3));
+ EXPECT_TRUE(coded_input.GetDirectBufferPointer(&ptr, &size));
+ EXPECT_EQ(buffer_ + 3, ptr);
+ EXPECT_EQ(5, size);
+
+ // Skip to end of buffer and peek -- should get next buffer.
+ EXPECT_TRUE(coded_input.Skip(5));
+ EXPECT_TRUE(coded_input.GetDirectBufferPointer(&ptr, &size));
+ EXPECT_EQ(buffer_ + 8, ptr);
+ EXPECT_EQ(8, size);
+}
+
+TEST_F(CodedStreamTest, GetDirectBufferPointerOutput) {
+ ArrayOutputStream output(buffer_, sizeof(buffer_), 8);
+ CodedOutputStream coded_output(&output);
+
+ void* ptr;
+ int size;
+
+ EXPECT_TRUE(coded_output.GetDirectBufferPointer(&ptr, &size));
+ EXPECT_EQ(buffer_, ptr);
+ EXPECT_EQ(8, size);
+
+ // Peeking again should return the same pointer.
+ EXPECT_TRUE(coded_output.GetDirectBufferPointer(&ptr, &size));
+ EXPECT_EQ(buffer_, ptr);
+ EXPECT_EQ(8, size);
+
+ // Skip forward in the same buffer then peek again.
+ EXPECT_TRUE(coded_output.Skip(3));
+ EXPECT_TRUE(coded_output.GetDirectBufferPointer(&ptr, &size));
+ EXPECT_EQ(buffer_ + 3, ptr);
+ EXPECT_EQ(5, size);
+
+ // Skip to end of buffer and peek -- should get next buffer.
+ EXPECT_TRUE(coded_output.Skip(5));
+ EXPECT_TRUE(coded_output.GetDirectBufferPointer(&ptr, &size));
+ EXPECT_EQ(buffer_ + 8, ptr);
+ EXPECT_EQ(8, size);
+
+ // Skip over multiple buffers.
+ EXPECT_TRUE(coded_output.Skip(22));
+ EXPECT_TRUE(coded_output.GetDirectBufferPointer(&ptr, &size));
+ EXPECT_EQ(buffer_ + 30, ptr);
+ EXPECT_EQ(2, size);
+}
+
+// -------------------------------------------------------------------
// Limits
TEST_1D(CodedStreamTest, BasicLimit, kBlockSizes) {
diff --git a/src/google/protobuf/message.cc b/src/google/protobuf/message.cc
index f6c932ff..097411cb 100644
--- a/src/google/protobuf/message.cc
+++ b/src/google/protobuf/message.cc
@@ -145,24 +145,42 @@ bool Message::ParsePartialFromZeroCopyStream(io::ZeroCopyInputStream* input) {
decoder.ConsumedEntireMessage();
}
+bool Message::ParseFromBoundedZeroCopyStream(
+ io::ZeroCopyInputStream* input, int size) {
+ io::CodedInputStream decoder(input);
+ decoder.PushLimit(size);
+ return ParseFromCodedStream(&decoder) &&
+ decoder.ConsumedEntireMessage() &&
+ decoder.BytesUntilLimit() == 0;
+}
+
+bool Message::ParsePartialFromBoundedZeroCopyStream(
+ io::ZeroCopyInputStream* input, int size) {
+ io::CodedInputStream decoder(input);
+ decoder.PushLimit(size);
+ return ParsePartialFromCodedStream(&decoder) &&
+ decoder.ConsumedEntireMessage() &&
+ decoder.BytesUntilLimit() == 0;
+}
+
bool Message::ParseFromString(const string& data) {
io::ArrayInputStream input(data.data(), data.size());
- return ParseFromZeroCopyStream(&input);
+ return ParseFromBoundedZeroCopyStream(&input, data.size());
}
bool Message::ParsePartialFromString(const string& data) {
io::ArrayInputStream input(data.data(), data.size());
- return ParsePartialFromZeroCopyStream(&input);
+ return ParsePartialFromBoundedZeroCopyStream(&input, data.size());
}
bool Message::ParseFromArray(const void* data, int size) {
io::ArrayInputStream input(data, size);
- return ParseFromZeroCopyStream(&input);
+ return ParseFromBoundedZeroCopyStream(&input, size);
}
bool Message::ParsePartialFromArray(const void* data, int size) {
io::ArrayInputStream input(data, size);
- return ParsePartialFromZeroCopyStream(&input);
+ return ParsePartialFromBoundedZeroCopyStream(&input, size);
}
bool Message::ParseFromFileDescriptor(int file_descriptor) {
diff --git a/src/google/protobuf/message.h b/src/google/protobuf/message.h
index d96fcc60..0674a12c 100644
--- a/src/google/protobuf/message.h
+++ b/src/google/protobuf/message.h
@@ -232,6 +232,14 @@ class LIBPROTOBUF_EXPORT Message {
// Like ParseFromZeroCopyStream(), but accepts messages that are missing
// required fields.
bool ParsePartialFromZeroCopyStream(io::ZeroCopyInputStream* input);
+ // Read a protocol buffer from the given zero-copy input stream, expecting
+ // the message to be exactly "size" bytes long. If successful, exactly
+ // this many bytes will have been consumed from the input.
+ bool ParseFromBoundedZeroCopyStream(io::ZeroCopyInputStream* input, int size);
+ // Like ParseFromBoundedZeroCopyStream(), but accepts messages that are
+ // missing required fields.
+ bool ParsePartialFromBoundedZeroCopyStream(io::ZeroCopyInputStream* input,
+ int size);
// Parse a protocol buffer contained in a string.
bool ParseFromString(const string& data);
// Like ParseFromString(), but accepts messages that are missing
diff --git a/src/google/protobuf/message_unittest.cc b/src/google/protobuf/message_unittest.cc
index da99741b..46e68446 100644
--- a/src/google/protobuf/message_unittest.cc
+++ b/src/google/protobuf/message_unittest.cc
@@ -107,6 +107,19 @@ TEST(MessageTest, ParseFromFileDescriptor) {
EXPECT_GE(close(file), 0);
}
+TEST(MessageTest, ParsePackedFromFileDescriptor) {
+ string filename =
+ TestSourceDir() +
+ "/google/protobuf/testdata/golden_packed_fields_message";
+ int file = open(filename.c_str(), O_RDONLY | O_BINARY);
+
+ unittest::TestPackedTypes message;
+ EXPECT_TRUE(message.ParseFromFileDescriptor(file));
+ TestUtil::ExpectPackedFieldsSet(message);
+
+ EXPECT_GE(close(file), 0);
+}
+
TEST(MessageTest, ParseHelpers) {
// TODO(kenton): Test more helpers? They're all two-liners so it seems
// like a waste of time.
@@ -134,6 +147,25 @@ TEST(MessageTest, ParseHelpers) {
EXPECT_TRUE(stream.eof());
TestUtil::ExpectAllFieldsSet(message);
}
+
+ {
+ // Test ParseFromBoundedZeroCopyStream.
+ string data_with_junk(data);
+ data_with_junk.append("some junk on the end");
+ io::ArrayInputStream stream(data_with_junk.data(), data_with_junk.size());
+ protobuf_unittest::TestAllTypes message;
+ EXPECT_TRUE(message.ParseFromBoundedZeroCopyStream(&stream, data.size()));
+ TestUtil::ExpectAllFieldsSet(message);
+ }
+
+ {
+ // Test that ParseFromBoundedZeroCopyStream fails (but doesn't crash) if
+ // EOF is reached before the expected number of bytes.
+ io::ArrayInputStream stream(data.data(), data.size());
+ protobuf_unittest::TestAllTypes message;
+ EXPECT_FALSE(
+ message.ParseFromBoundedZeroCopyStream(&stream, data.size() + 1));
+ }
}
TEST(MessageTest, ParseFailsIfNotInitialized) {
diff --git a/src/google/protobuf/test_util.cc b/src/google/protobuf/test_util.cc
index 40120d95..c1e9fa78 100644
--- a/src/google/protobuf/test_util.cc
+++ b/src/google/protobuf/test_util.cc
@@ -636,6 +636,180 @@ void TestUtil::ExpectRepeatedFieldsModified(
}
+// -------------------------------------------------------------------
+
+void TestUtil::SetPackedFields(unittest::TestPackedTypes* message) {
+ message->add_packed_int32 (601);
+ message->add_packed_int64 (602);
+ message->add_packed_uint32 (603);
+ message->add_packed_uint64 (604);
+ message->add_packed_sint32 (605);
+ message->add_packed_sint64 (606);
+ message->add_packed_fixed32 (607);
+ message->add_packed_fixed64 (608);
+ message->add_packed_sfixed32(609);
+ message->add_packed_sfixed64(610);
+ message->add_packed_float (611);
+ message->add_packed_double (612);
+ message->add_packed_bool (true);
+ message->add_packed_enum (unittest::FOREIGN_BAR);
+ // add a second one of each field
+ message->add_packed_int32 (701);
+ message->add_packed_int64 (702);
+ message->add_packed_uint32 (703);
+ message->add_packed_uint64 (704);
+ message->add_packed_sint32 (705);
+ message->add_packed_sint64 (706);
+ message->add_packed_fixed32 (707);
+ message->add_packed_fixed64 (708);
+ message->add_packed_sfixed32(709);
+ message->add_packed_sfixed64(710);
+ message->add_packed_float (711);
+ message->add_packed_double (712);
+ message->add_packed_bool (false);
+ message->add_packed_enum (unittest::FOREIGN_BAZ);
+}
+
+// -------------------------------------------------------------------
+
+void TestUtil::ModifyPackedFields(unittest::TestPackedTypes* message) {
+ message->set_packed_int32 (1, 801);
+ message->set_packed_int64 (1, 802);
+ message->set_packed_uint32 (1, 803);
+ message->set_packed_uint64 (1, 804);
+ message->set_packed_sint32 (1, 805);
+ message->set_packed_sint64 (1, 806);
+ message->set_packed_fixed32 (1, 807);
+ message->set_packed_fixed64 (1, 808);
+ message->set_packed_sfixed32(1, 809);
+ message->set_packed_sfixed64(1, 810);
+ message->set_packed_float (1, 811);
+ message->set_packed_double (1, 812);
+ message->set_packed_bool (1, true);
+ message->set_packed_enum (1, unittest::FOREIGN_FOO);
+}
+
+// -------------------------------------------------------------------
+
+void TestUtil::ExpectPackedFieldsSet(const unittest::TestPackedTypes& message) {
+ ASSERT_EQ(2, message.packed_int32_size ());
+ ASSERT_EQ(2, message.packed_int64_size ());
+ ASSERT_EQ(2, message.packed_uint32_size ());
+ ASSERT_EQ(2, message.packed_uint64_size ());
+ ASSERT_EQ(2, message.packed_sint32_size ());
+ ASSERT_EQ(2, message.packed_sint64_size ());
+ ASSERT_EQ(2, message.packed_fixed32_size ());
+ ASSERT_EQ(2, message.packed_fixed64_size ());
+ ASSERT_EQ(2, message.packed_sfixed32_size());
+ ASSERT_EQ(2, message.packed_sfixed64_size());
+ ASSERT_EQ(2, message.packed_float_size ());
+ ASSERT_EQ(2, message.packed_double_size ());
+ ASSERT_EQ(2, message.packed_bool_size ());
+ ASSERT_EQ(2, message.packed_enum_size ());
+
+ EXPECT_EQ(601 , message.packed_int32 (0));
+ EXPECT_EQ(602 , message.packed_int64 (0));
+ EXPECT_EQ(603 , message.packed_uint32 (0));
+ EXPECT_EQ(604 , message.packed_uint64 (0));
+ EXPECT_EQ(605 , message.packed_sint32 (0));
+ EXPECT_EQ(606 , message.packed_sint64 (0));
+ EXPECT_EQ(607 , message.packed_fixed32 (0));
+ EXPECT_EQ(608 , message.packed_fixed64 (0));
+ EXPECT_EQ(609 , message.packed_sfixed32(0));
+ EXPECT_EQ(610 , message.packed_sfixed64(0));
+ EXPECT_EQ(611 , message.packed_float (0));
+ EXPECT_EQ(612 , message.packed_double (0));
+ EXPECT_EQ(true , message.packed_bool (0));
+ EXPECT_EQ(unittest::FOREIGN_BAR, message.packed_enum(0));
+
+ EXPECT_EQ(701 , message.packed_int32 (1));
+ EXPECT_EQ(702 , message.packed_int64 (1));
+ EXPECT_EQ(703 , message.packed_uint32 (1));
+ EXPECT_EQ(704 , message.packed_uint64 (1));
+ EXPECT_EQ(705 , message.packed_sint32 (1));
+ EXPECT_EQ(706 , message.packed_sint64 (1));
+ EXPECT_EQ(707 , message.packed_fixed32 (1));
+ EXPECT_EQ(708 , message.packed_fixed64 (1));
+ EXPECT_EQ(709 , message.packed_sfixed32(1));
+ EXPECT_EQ(710 , message.packed_sfixed64(1));
+ EXPECT_EQ(711 , message.packed_float (1));
+ EXPECT_EQ(712 , message.packed_double (1));
+ EXPECT_EQ(false, message.packed_bool (1));
+ EXPECT_EQ(unittest::FOREIGN_BAZ, message.packed_enum(1));
+}
+
+// -------------------------------------------------------------------
+
+void TestUtil::ExpectPackedClear(
+ const unittest::TestPackedTypes& message) {
+ // Packed repeated fields are empty.
+ EXPECT_EQ(0, message.packed_int32_size ());
+ EXPECT_EQ(0, message.packed_int64_size ());
+ EXPECT_EQ(0, message.packed_uint32_size ());
+ EXPECT_EQ(0, message.packed_uint64_size ());
+ EXPECT_EQ(0, message.packed_sint32_size ());
+ EXPECT_EQ(0, message.packed_sint64_size ());
+ EXPECT_EQ(0, message.packed_fixed32_size ());
+ EXPECT_EQ(0, message.packed_fixed64_size ());
+ EXPECT_EQ(0, message.packed_sfixed32_size());
+ EXPECT_EQ(0, message.packed_sfixed64_size());
+ EXPECT_EQ(0, message.packed_float_size ());
+ EXPECT_EQ(0, message.packed_double_size ());
+ EXPECT_EQ(0, message.packed_bool_size ());
+ EXPECT_EQ(0, message.packed_enum_size ());
+}
+
+// -------------------------------------------------------------------
+
+void TestUtil::ExpectPackedFieldsModified(
+ const unittest::TestPackedTypes& message) {
+ // Do the same for packed repeated fields.
+ ASSERT_EQ(2, message.packed_int32_size ());
+ ASSERT_EQ(2, message.packed_int64_size ());
+ ASSERT_EQ(2, message.packed_uint32_size ());
+ ASSERT_EQ(2, message.packed_uint64_size ());
+ ASSERT_EQ(2, message.packed_sint32_size ());
+ ASSERT_EQ(2, message.packed_sint64_size ());
+ ASSERT_EQ(2, message.packed_fixed32_size ());
+ ASSERT_EQ(2, message.packed_fixed64_size ());
+ ASSERT_EQ(2, message.packed_sfixed32_size());
+ ASSERT_EQ(2, message.packed_sfixed64_size());
+ ASSERT_EQ(2, message.packed_float_size ());
+ ASSERT_EQ(2, message.packed_double_size ());
+ ASSERT_EQ(2, message.packed_bool_size ());
+ ASSERT_EQ(2, message.packed_enum_size ());
+
+ EXPECT_EQ(601 , message.packed_int32 (0));
+ EXPECT_EQ(602 , message.packed_int64 (0));
+ EXPECT_EQ(603 , message.packed_uint32 (0));
+ EXPECT_EQ(604 , message.packed_uint64 (0));
+ EXPECT_EQ(605 , message.packed_sint32 (0));
+ EXPECT_EQ(606 , message.packed_sint64 (0));
+ EXPECT_EQ(607 , message.packed_fixed32 (0));
+ EXPECT_EQ(608 , message.packed_fixed64 (0));
+ EXPECT_EQ(609 , message.packed_sfixed32(0));
+ EXPECT_EQ(610 , message.packed_sfixed64(0));
+ EXPECT_EQ(611 , message.packed_float (0));
+ EXPECT_EQ(612 , message.packed_double (0));
+ EXPECT_EQ(true , message.packed_bool (0));
+ EXPECT_EQ(unittest::FOREIGN_BAR, message.packed_enum(0));
+ // Actually verify the second (modified) elements now.
+ EXPECT_EQ(801 , message.packed_int32 (1));
+ EXPECT_EQ(802 , message.packed_int64 (1));
+ EXPECT_EQ(803 , message.packed_uint32 (1));
+ EXPECT_EQ(804 , message.packed_uint64 (1));
+ EXPECT_EQ(805 , message.packed_sint32 (1));
+ EXPECT_EQ(806 , message.packed_sint64 (1));
+ EXPECT_EQ(807 , message.packed_fixed32 (1));
+ EXPECT_EQ(808 , message.packed_fixed64 (1));
+ EXPECT_EQ(809 , message.packed_sfixed32(1));
+ EXPECT_EQ(810 , message.packed_sfixed64(1));
+ EXPECT_EQ(811 , message.packed_float (1));
+ EXPECT_EQ(812 , message.packed_double (1));
+ EXPECT_EQ(true , message.packed_bool (1));
+ EXPECT_EQ(unittest::FOREIGN_FOO, message.packed_enum(1));
+}
+
// ===================================================================
// Extensions
//
@@ -1246,6 +1420,183 @@ void TestUtil::ExpectRepeatedExtensionsModified(
// -------------------------------------------------------------------
+void TestUtil::SetPackedExtensions(unittest::TestPackedExtensions* message) {
+ message->AddExtension(unittest::packed_int32_extension , 601);
+ message->AddExtension(unittest::packed_int64_extension , 602);
+ message->AddExtension(unittest::packed_uint32_extension , 603);
+ message->AddExtension(unittest::packed_uint64_extension , 604);
+ message->AddExtension(unittest::packed_sint32_extension , 605);
+ message->AddExtension(unittest::packed_sint64_extension , 606);
+ message->AddExtension(unittest::packed_fixed32_extension , 607);
+ message->AddExtension(unittest::packed_fixed64_extension , 608);
+ message->AddExtension(unittest::packed_sfixed32_extension, 609);
+ message->AddExtension(unittest::packed_sfixed64_extension, 610);
+ message->AddExtension(unittest::packed_float_extension , 611);
+ message->AddExtension(unittest::packed_double_extension , 612);
+ message->AddExtension(unittest::packed_bool_extension , true);
+ message->AddExtension(unittest::packed_enum_extension, unittest::FOREIGN_BAR);
+ // add a second one of each field
+ message->AddExtension(unittest::packed_int32_extension , 701);
+ message->AddExtension(unittest::packed_int64_extension , 702);
+ message->AddExtension(unittest::packed_uint32_extension , 703);
+ message->AddExtension(unittest::packed_uint64_extension , 704);
+ message->AddExtension(unittest::packed_sint32_extension , 705);
+ message->AddExtension(unittest::packed_sint64_extension , 706);
+ message->AddExtension(unittest::packed_fixed32_extension , 707);
+ message->AddExtension(unittest::packed_fixed64_extension , 708);
+ message->AddExtension(unittest::packed_sfixed32_extension, 709);
+ message->AddExtension(unittest::packed_sfixed64_extension, 710);
+ message->AddExtension(unittest::packed_float_extension , 711);
+ message->AddExtension(unittest::packed_double_extension , 712);
+ message->AddExtension(unittest::packed_bool_extension , false);
+ message->AddExtension(unittest::packed_enum_extension, unittest::FOREIGN_BAZ);
+}
+
+// -------------------------------------------------------------------
+
+void TestUtil::ModifyPackedExtensions(unittest::TestPackedExtensions* message) {
+ message->SetExtension(unittest::packed_int32_extension , 1, 801);
+ message->SetExtension(unittest::packed_int64_extension , 1, 802);
+ message->SetExtension(unittest::packed_uint32_extension , 1, 803);
+ message->SetExtension(unittest::packed_uint64_extension , 1, 804);
+ message->SetExtension(unittest::packed_sint32_extension , 1, 805);
+ message->SetExtension(unittest::packed_sint64_extension , 1, 806);
+ message->SetExtension(unittest::packed_fixed32_extension , 1, 807);
+ message->SetExtension(unittest::packed_fixed64_extension , 1, 808);
+ message->SetExtension(unittest::packed_sfixed32_extension, 1, 809);
+ message->SetExtension(unittest::packed_sfixed64_extension, 1, 810);
+ message->SetExtension(unittest::packed_float_extension , 1, 811);
+ message->SetExtension(unittest::packed_double_extension , 1, 812);
+ message->SetExtension(unittest::packed_bool_extension , 1, true);
+ message->SetExtension(unittest::packed_enum_extension , 1,
+ unittest::FOREIGN_FOO);
+}
+
+// -------------------------------------------------------------------
+
+void TestUtil::ExpectPackedExtensionsSet(
+ const unittest::TestPackedExtensions& message) {
+ ASSERT_EQ(2, message.ExtensionSize(unittest::packed_int32_extension ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::packed_int64_extension ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::packed_uint32_extension ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::packed_uint64_extension ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::packed_sint32_extension ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::packed_sint64_extension ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::packed_fixed32_extension ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::packed_fixed64_extension ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::packed_sfixed32_extension));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::packed_sfixed64_extension));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::packed_float_extension ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::packed_double_extension ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::packed_bool_extension ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::packed_enum_extension ));
+
+ EXPECT_EQ(601 , message.GetExtension(unittest::packed_int32_extension , 0));
+ EXPECT_EQ(602 , message.GetExtension(unittest::packed_int64_extension , 0));
+ EXPECT_EQ(603 , message.GetExtension(unittest::packed_uint32_extension , 0));
+ EXPECT_EQ(604 , message.GetExtension(unittest::packed_uint64_extension , 0));
+ EXPECT_EQ(605 , message.GetExtension(unittest::packed_sint32_extension , 0));
+ EXPECT_EQ(606 , message.GetExtension(unittest::packed_sint64_extension , 0));
+ EXPECT_EQ(607 , message.GetExtension(unittest::packed_fixed32_extension , 0));
+ EXPECT_EQ(608 , message.GetExtension(unittest::packed_fixed64_extension , 0));
+ EXPECT_EQ(609 , message.GetExtension(unittest::packed_sfixed32_extension, 0));
+ EXPECT_EQ(610 , message.GetExtension(unittest::packed_sfixed64_extension, 0));
+ EXPECT_EQ(611 , message.GetExtension(unittest::packed_float_extension , 0));
+ EXPECT_EQ(612 , message.GetExtension(unittest::packed_double_extension , 0));
+ EXPECT_EQ(true , message.GetExtension(unittest::packed_bool_extension , 0));
+ EXPECT_EQ(unittest::FOREIGN_BAR,
+ message.GetExtension(unittest::packed_enum_extension, 0));
+ EXPECT_EQ(701 , message.GetExtension(unittest::packed_int32_extension , 1));
+ EXPECT_EQ(702 , message.GetExtension(unittest::packed_int64_extension , 1));
+ EXPECT_EQ(703 , message.GetExtension(unittest::packed_uint32_extension , 1));
+ EXPECT_EQ(704 , message.GetExtension(unittest::packed_uint64_extension , 1));
+ EXPECT_EQ(705 , message.GetExtension(unittest::packed_sint32_extension , 1));
+ EXPECT_EQ(706 , message.GetExtension(unittest::packed_sint64_extension , 1));
+ EXPECT_EQ(707 , message.GetExtension(unittest::packed_fixed32_extension , 1));
+ EXPECT_EQ(708 , message.GetExtension(unittest::packed_fixed64_extension , 1));
+ EXPECT_EQ(709 , message.GetExtension(unittest::packed_sfixed32_extension, 1));
+ EXPECT_EQ(710 , message.GetExtension(unittest::packed_sfixed64_extension, 1));
+ EXPECT_EQ(711 , message.GetExtension(unittest::packed_float_extension , 1));
+ EXPECT_EQ(712 , message.GetExtension(unittest::packed_double_extension , 1));
+ EXPECT_EQ(false, message.GetExtension(unittest::packed_bool_extension , 1));
+ EXPECT_EQ(unittest::FOREIGN_BAZ,
+ message.GetExtension(unittest::packed_enum_extension, 1));
+}
+
+// -------------------------------------------------------------------
+
+void TestUtil::ExpectPackedExtensionsClear(
+ const unittest::TestPackedExtensions& message) {
+ EXPECT_EQ(0, message.ExtensionSize(unittest::packed_int32_extension ));
+ EXPECT_EQ(0, message.ExtensionSize(unittest::packed_int64_extension ));
+ EXPECT_EQ(0, message.ExtensionSize(unittest::packed_uint32_extension ));
+ EXPECT_EQ(0, message.ExtensionSize(unittest::packed_uint64_extension ));
+ EXPECT_EQ(0, message.ExtensionSize(unittest::packed_sint32_extension ));
+ EXPECT_EQ(0, message.ExtensionSize(unittest::packed_sint64_extension ));
+ EXPECT_EQ(0, message.ExtensionSize(unittest::packed_fixed32_extension ));
+ EXPECT_EQ(0, message.ExtensionSize(unittest::packed_fixed64_extension ));
+ EXPECT_EQ(0, message.ExtensionSize(unittest::packed_sfixed32_extension));
+ EXPECT_EQ(0, message.ExtensionSize(unittest::packed_sfixed64_extension));
+ EXPECT_EQ(0, message.ExtensionSize(unittest::packed_float_extension ));
+ EXPECT_EQ(0, message.ExtensionSize(unittest::packed_double_extension ));
+ EXPECT_EQ(0, message.ExtensionSize(unittest::packed_bool_extension ));
+ EXPECT_EQ(0, message.ExtensionSize(unittest::packed_enum_extension ));
+}
+
+// -------------------------------------------------------------------
+
+void TestUtil::ExpectPackedExtensionsModified(
+ const unittest::TestPackedExtensions& message) {
+ ASSERT_EQ(2, message.ExtensionSize(unittest::packed_int32_extension ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::packed_int64_extension ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::packed_uint32_extension ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::packed_uint64_extension ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::packed_sint32_extension ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::packed_sint64_extension ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::packed_fixed32_extension ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::packed_fixed64_extension ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::packed_sfixed32_extension));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::packed_sfixed64_extension));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::packed_float_extension ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::packed_double_extension ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::packed_bool_extension ));
+ ASSERT_EQ(2, message.ExtensionSize(unittest::packed_enum_extension ));
+ EXPECT_EQ(601 , message.GetExtension(unittest::packed_int32_extension , 0));
+ EXPECT_EQ(602 , message.GetExtension(unittest::packed_int64_extension , 0));
+ EXPECT_EQ(603 , message.GetExtension(unittest::packed_uint32_extension , 0));
+ EXPECT_EQ(604 , message.GetExtension(unittest::packed_uint64_extension , 0));
+ EXPECT_EQ(605 , message.GetExtension(unittest::packed_sint32_extension , 0));
+ EXPECT_EQ(606 , message.GetExtension(unittest::packed_sint64_extension , 0));
+ EXPECT_EQ(607 , message.GetExtension(unittest::packed_fixed32_extension , 0));
+ EXPECT_EQ(608 , message.GetExtension(unittest::packed_fixed64_extension , 0));
+ EXPECT_EQ(609 , message.GetExtension(unittest::packed_sfixed32_extension, 0));
+ EXPECT_EQ(610 , message.GetExtension(unittest::packed_sfixed64_extension, 0));
+ EXPECT_EQ(611 , message.GetExtension(unittest::packed_float_extension , 0));
+ EXPECT_EQ(612 , message.GetExtension(unittest::packed_double_extension , 0));
+ EXPECT_EQ(true , message.GetExtension(unittest::packed_bool_extension , 0));
+ EXPECT_EQ(unittest::FOREIGN_BAR,
+ message.GetExtension(unittest::packed_enum_extension, 0));
+
+ // Actually verify the second (modified) elements now.
+ EXPECT_EQ(801 , message.GetExtension(unittest::packed_int32_extension , 1));
+ EXPECT_EQ(802 , message.GetExtension(unittest::packed_int64_extension , 1));
+ EXPECT_EQ(803 , message.GetExtension(unittest::packed_uint32_extension , 1));
+ EXPECT_EQ(804 , message.GetExtension(unittest::packed_uint64_extension , 1));
+ EXPECT_EQ(805 , message.GetExtension(unittest::packed_sint32_extension , 1));
+ EXPECT_EQ(806 , message.GetExtension(unittest::packed_sint64_extension , 1));
+ EXPECT_EQ(807 , message.GetExtension(unittest::packed_fixed32_extension , 1));
+ EXPECT_EQ(808 , message.GetExtension(unittest::packed_fixed64_extension , 1));
+ EXPECT_EQ(809 , message.GetExtension(unittest::packed_sfixed32_extension, 1));
+ EXPECT_EQ(810 , message.GetExtension(unittest::packed_sfixed64_extension, 1));
+ EXPECT_EQ(811 , message.GetExtension(unittest::packed_float_extension , 1));
+ EXPECT_EQ(812 , message.GetExtension(unittest::packed_double_extension , 1));
+ EXPECT_EQ(true , message.GetExtension(unittest::packed_bool_extension , 1));
+ EXPECT_EQ(unittest::FOREIGN_FOO,
+ message.GetExtension(unittest::packed_enum_extension, 1));
+}
+
+// -------------------------------------------------------------------
+
void TestUtil::ExpectAllFieldsAndExtensionsInOrder(const string& serialized) {
// We set each field individually, serialize separately, and concatenate all
// the strings in canonical order to determine the expected serialization.
@@ -1335,7 +1686,8 @@ TestUtil::ReflectionTester::ReflectionTester(
// Shorthand to get a FieldDescriptor for a field of unittest::TestAllTypes.
const FieldDescriptor* TestUtil::ReflectionTester::F(const string& name) {
const FieldDescriptor* result = NULL;
- if (base_descriptor_->name() == "TestAllExtensions") {
+ if (base_descriptor_->name() == "TestAllExtensions" ||
+ base_descriptor_->name() == "TestPackedExtensions") {
result = base_descriptor_->file()->FindExtensionByName(name + "_extension");
} else {
result = base_descriptor_->FindFieldByName(name);
@@ -1475,6 +1827,40 @@ void TestUtil::ReflectionTester::SetAllFieldsViaReflection(Message* message) {
reflection->SetString(message, F("default_cord"), "425");
}
+void TestUtil::ReflectionTester::SetPackedFieldsViaReflection(
+ Message* message) {
+ const Reflection* reflection = message->GetReflection();
+ reflection->AddInt32 (message, F("packed_int32" ), 601);
+ reflection->AddInt64 (message, F("packed_int64" ), 602);
+ reflection->AddUInt32(message, F("packed_uint32" ), 603);
+ reflection->AddUInt64(message, F("packed_uint64" ), 604);
+ reflection->AddInt32 (message, F("packed_sint32" ), 605);
+ reflection->AddInt64 (message, F("packed_sint64" ), 606);
+ reflection->AddUInt32(message, F("packed_fixed32" ), 607);
+ reflection->AddUInt64(message, F("packed_fixed64" ), 608);
+ reflection->AddInt32 (message, F("packed_sfixed32"), 609);
+ reflection->AddInt64 (message, F("packed_sfixed64"), 610);
+ reflection->AddFloat (message, F("packed_float" ), 611);
+ reflection->AddDouble(message, F("packed_double" ), 612);
+ reflection->AddBool (message, F("packed_bool" ), true);
+ reflection->AddEnum (message, F("packed_enum" ), foreign_bar_);
+
+ reflection->AddInt32 (message, F("packed_int32" ), 701);
+ reflection->AddInt64 (message, F("packed_int64" ), 702);
+ reflection->AddUInt32(message, F("packed_uint32" ), 703);
+ reflection->AddUInt64(message, F("packed_uint64" ), 704);
+ reflection->AddInt32 (message, F("packed_sint32" ), 705);
+ reflection->AddInt64 (message, F("packed_sint64" ), 706);
+ reflection->AddUInt32(message, F("packed_fixed32" ), 707);
+ reflection->AddUInt64(message, F("packed_fixed64" ), 708);
+ reflection->AddInt32 (message, F("packed_sfixed32"), 709);
+ reflection->AddInt64 (message, F("packed_sfixed64"), 710);
+ reflection->AddFloat (message, F("packed_float" ), 711);
+ reflection->AddDouble(message, F("packed_double" ), 712);
+ reflection->AddBool (message, F("packed_bool" ), false);
+ reflection->AddEnum (message, F("packed_enum" ), foreign_baz_);
+}
+
// -------------------------------------------------------------------
void TestUtil::ReflectionTester::ExpectAllFieldsSetViaReflection(
@@ -1725,6 +2111,58 @@ void TestUtil::ReflectionTester::ExpectAllFieldsSetViaReflection(
EXPECT_EQ("425", reflection->GetStringReference(message, F("default_cord"), &scratch));
}
+void TestUtil::ReflectionTester::ExpectPackedFieldsSetViaReflection(
+ const Message& message) {
+ const Reflection* reflection = message.GetReflection();
+
+ ASSERT_EQ(2, reflection->FieldSize(message, F("packed_int32" )));
+ ASSERT_EQ(2, reflection->FieldSize(message, F("packed_int64" )));
+ ASSERT_EQ(2, reflection->FieldSize(message, F("packed_uint32" )));
+ ASSERT_EQ(2, reflection->FieldSize(message, F("packed_uint64" )));
+ ASSERT_EQ(2, reflection->FieldSize(message, F("packed_sint32" )));
+ ASSERT_EQ(2, reflection->FieldSize(message, F("packed_sint64" )));
+ ASSERT_EQ(2, reflection->FieldSize(message, F("packed_fixed32" )));
+ ASSERT_EQ(2, reflection->FieldSize(message, F("packed_fixed64" )));
+ ASSERT_EQ(2, reflection->FieldSize(message, F("packed_sfixed32")));
+ ASSERT_EQ(2, reflection->FieldSize(message, F("packed_sfixed64")));
+ ASSERT_EQ(2, reflection->FieldSize(message, F("packed_float" )));
+ ASSERT_EQ(2, reflection->FieldSize(message, F("packed_double" )));
+ ASSERT_EQ(2, reflection->FieldSize(message, F("packed_bool" )));
+ ASSERT_EQ(2, reflection->FieldSize(message, F("packed_enum" )));
+
+ EXPECT_EQ(601 , reflection->GetRepeatedInt32 (message, F("packed_int32" ), 0));
+ EXPECT_EQ(602 , reflection->GetRepeatedInt64 (message, F("packed_int64" ), 0));
+ EXPECT_EQ(603 , reflection->GetRepeatedUInt32(message, F("packed_uint32" ), 0));
+ EXPECT_EQ(604 , reflection->GetRepeatedUInt64(message, F("packed_uint64" ), 0));
+ EXPECT_EQ(605 , reflection->GetRepeatedInt32 (message, F("packed_sint32" ), 0));
+ EXPECT_EQ(606 , reflection->GetRepeatedInt64 (message, F("packed_sint64" ), 0));
+ EXPECT_EQ(607 , reflection->GetRepeatedUInt32(message, F("packed_fixed32" ), 0));
+ EXPECT_EQ(608 , reflection->GetRepeatedUInt64(message, F("packed_fixed64" ), 0));
+ EXPECT_EQ(609 , reflection->GetRepeatedInt32 (message, F("packed_sfixed32"), 0));
+ EXPECT_EQ(610 , reflection->GetRepeatedInt64 (message, F("packed_sfixed64"), 0));
+ EXPECT_EQ(611 , reflection->GetRepeatedFloat (message, F("packed_float" ), 0));
+ EXPECT_EQ(612 , reflection->GetRepeatedDouble(message, F("packed_double" ), 0));
+ EXPECT_EQ(true , reflection->GetRepeatedBool (message, F("packed_bool" ), 0));
+ EXPECT_EQ(foreign_bar_,
+ reflection->GetRepeatedEnum(message, F("packed_enum"), 0));
+
+ EXPECT_EQ(701 , reflection->GetRepeatedInt32 (message, F("packed_int32" ), 1));
+ EXPECT_EQ(702 , reflection->GetRepeatedInt64 (message, F("packed_int64" ), 1));
+ EXPECT_EQ(703 , reflection->GetRepeatedUInt32(message, F("packed_uint32" ), 1));
+ EXPECT_EQ(704 , reflection->GetRepeatedUInt64(message, F("packed_uint64" ), 1));
+ EXPECT_EQ(705 , reflection->GetRepeatedInt32 (message, F("packed_sint32" ), 1));
+ EXPECT_EQ(706 , reflection->GetRepeatedInt64 (message, F("packed_sint64" ), 1));
+ EXPECT_EQ(707 , reflection->GetRepeatedUInt32(message, F("packed_fixed32" ), 1));
+ EXPECT_EQ(708 , reflection->GetRepeatedUInt64(message, F("packed_fixed64" ), 1));
+ EXPECT_EQ(709 , reflection->GetRepeatedInt32 (message, F("packed_sfixed32"), 1));
+ EXPECT_EQ(710 , reflection->GetRepeatedInt64 (message, F("packed_sfixed64"), 1));
+ EXPECT_EQ(711 , reflection->GetRepeatedFloat (message, F("packed_float" ), 1));
+ EXPECT_EQ(712 , reflection->GetRepeatedDouble(message, F("packed_double" ), 1));
+ EXPECT_EQ(false, reflection->GetRepeatedBool (message, F("packed_bool" ), 1));
+ EXPECT_EQ(foreign_baz_,
+ reflection->GetRepeatedEnum(message, F("packed_enum"), 1));
+}
+
// -------------------------------------------------------------------
void TestUtil::ReflectionTester::ExpectClearViaReflection(
@@ -1890,6 +2328,26 @@ void TestUtil::ReflectionTester::ExpectClearViaReflection(
EXPECT_EQ("123", reflection->GetStringReference(message, F("default_cord"), &scratch));
}
+void TestUtil::ReflectionTester::ExpectPackedClearViaReflection(
+ const Message& message) {
+ const Reflection* reflection = message.GetReflection();
+
+ EXPECT_EQ(0, reflection->FieldSize(message, F("packed_int32" )));
+ EXPECT_EQ(0, reflection->FieldSize(message, F("packed_int64" )));
+ EXPECT_EQ(0, reflection->FieldSize(message, F("packed_uint32" )));
+ EXPECT_EQ(0, reflection->FieldSize(message, F("packed_uint64" )));
+ EXPECT_EQ(0, reflection->FieldSize(message, F("packed_sint32" )));
+ EXPECT_EQ(0, reflection->FieldSize(message, F("packed_sint64" )));
+ EXPECT_EQ(0, reflection->FieldSize(message, F("packed_fixed32" )));
+ EXPECT_EQ(0, reflection->FieldSize(message, F("packed_fixed64" )));
+ EXPECT_EQ(0, reflection->FieldSize(message, F("packed_sfixed32")));
+ EXPECT_EQ(0, reflection->FieldSize(message, F("packed_sfixed64")));
+ EXPECT_EQ(0, reflection->FieldSize(message, F("packed_float" )));
+ EXPECT_EQ(0, reflection->FieldSize(message, F("packed_double" )));
+ EXPECT_EQ(0, reflection->FieldSize(message, F("packed_bool" )));
+ EXPECT_EQ(0, reflection->FieldSize(message, F("packed_enum" )));
+}
+
// -------------------------------------------------------------------
void TestUtil::ReflectionTester::ModifyRepeatedFieldsViaReflection(
@@ -1930,5 +2388,24 @@ void TestUtil::ReflectionTester::ModifyRepeatedFieldsViaReflection(
reflection->SetRepeatedString(message, F("repeated_cord"), 1, "525");
}
+void TestUtil::ReflectionTester::ModifyPackedFieldsViaReflection(
+ Message* message) {
+ const Reflection* reflection = message->GetReflection();
+ reflection->SetRepeatedInt32 (message, F("packed_int32" ), 1, 801);
+ reflection->SetRepeatedInt64 (message, F("packed_int64" ), 1, 802);
+ reflection->SetRepeatedUInt32(message, F("packed_uint32" ), 1, 803);
+ reflection->SetRepeatedUInt64(message, F("packed_uint64" ), 1, 804);
+ reflection->SetRepeatedInt32 (message, F("packed_sint32" ), 1, 805);
+ reflection->SetRepeatedInt64 (message, F("packed_sint64" ), 1, 806);
+ reflection->SetRepeatedUInt32(message, F("packed_fixed32" ), 1, 807);
+ reflection->SetRepeatedUInt64(message, F("packed_fixed64" ), 1, 808);
+ reflection->SetRepeatedInt32 (message, F("packed_sfixed32"), 1, 809);
+ reflection->SetRepeatedInt64 (message, F("packed_sfixed64"), 1, 810);
+ reflection->SetRepeatedFloat (message, F("packed_float" ), 1, 811);
+ reflection->SetRepeatedDouble(message, F("packed_double" ), 1, 812);
+ reflection->SetRepeatedBool (message, F("packed_bool" ), 1, true);
+ reflection->SetRepeatedEnum (message, F("packed_enum" ), 1, foreign_foo_);
+}
+
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/test_util.h b/src/google/protobuf/test_util.h
index af03afc3..ca840c71 100644
--- a/src/google/protobuf/test_util.h
+++ b/src/google/protobuf/test_util.h
@@ -52,30 +52,44 @@ class TestUtil {
static void SetAllFields(unittest::TestAllTypes* message);
static void SetAllExtensions(unittest::TestAllExtensions* message);
static void SetAllFieldsAndExtensions(unittest::TestFieldOrderings* message);
+ static void SetPackedFields(unittest::TestPackedTypes* message);
+ static void SetPackedExtensions(unittest::TestPackedExtensions* message);
// Use the repeated versions of the set_*() accessors to modify all the
// repeated fields of the messsage (which should already have been
- // initialized with SetAllFields()). SetAllFields() itself only tests
+ // initialized with Set*Fields()). Set*Fields() itself only tests
// the add_*() accessors.
static void ModifyRepeatedFields(unittest::TestAllTypes* message);
static void ModifyRepeatedExtensions(unittest::TestAllExtensions* message);
+ static void ModifyPackedFields(unittest::TestPackedTypes* message);
+ static void ModifyPackedExtensions(unittest::TestPackedExtensions* message);
// Check that all fields have the values that they should have after
- // SetAllFields() is called.
+ // Set*Fields() is called.
static void ExpectAllFieldsSet(const unittest::TestAllTypes& message);
static void ExpectAllExtensionsSet(
const unittest::TestAllExtensions& message);
+ static void ExpectPackedFieldsSet(const unittest::TestPackedTypes& message);
+ static void ExpectPackedExtensionsSet(
+ const unittest::TestPackedExtensions& message);
// Expect that the message is modified as would be expected from
- // ModifyRepeatedFields().
+ // Modify*Fields().
static void ExpectRepeatedFieldsModified(
const unittest::TestAllTypes& message);
static void ExpectRepeatedExtensionsModified(
const unittest::TestAllExtensions& message);
+ static void ExpectPackedFieldsModified(
+ const unittest::TestPackedTypes& message);
+ static void ExpectPackedExtensionsModified(
+ const unittest::TestPackedExtensions& message);
// Check that all fields have their default values.
static void ExpectClear(const unittest::TestAllTypes& message);
static void ExpectExtensionsClear(const unittest::TestAllExtensions& message);
+ static void ExpectPackedClear(const unittest::TestPackedTypes& message);
+ static void ExpectPackedExtensionsClear(
+ const unittest::TestPackedExtensions& message);
// Check that the passed-in serialization is the canonical serialization we
// expect for a TestFieldOrderings message filled in by
@@ -97,6 +111,11 @@ class TestUtil {
void ExpectAllFieldsSetViaReflection(const Message& message);
void ExpectClearViaReflection(const Message& message);
+ void SetPackedFieldsViaReflection(Message* message);
+ void ModifyPackedFieldsViaReflection(Message* message);
+ void ExpectPackedFieldsSetViaReflection(const Message& message);
+ void ExpectPackedClearViaReflection(const Message& message);
+
private:
const FieldDescriptor* F(const string& name);
diff --git a/src/google/protobuf/unittest.proto b/src/google/protobuf/unittest.proto
index 0aa66b9f..46ce77c3 100644
--- a/src/google/protobuf/unittest.proto
+++ b/src/google/protobuf/unittest.proto
@@ -461,6 +461,46 @@ message OneBytes {
optional bytes data = 1;
}
+// Test messages for packed fields
+
+message TestPackedTypes {
+ repeated int32 packed_int32 = 90 [packed = true];
+ repeated int64 packed_int64 = 91 [packed = true];
+ repeated uint32 packed_uint32 = 92 [packed = true];
+ repeated uint64 packed_uint64 = 93 [packed = true];
+ repeated sint32 packed_sint32 = 94 [packed = true];
+ repeated sint64 packed_sint64 = 95 [packed = true];
+ repeated fixed32 packed_fixed32 = 96 [packed = true];
+ repeated fixed64 packed_fixed64 = 97 [packed = true];
+ repeated sfixed32 packed_sfixed32 = 98 [packed = true];
+ repeated sfixed64 packed_sfixed64 = 99 [packed = true];
+ repeated float packed_float = 100 [packed = true];
+ repeated double packed_double = 101 [packed = true];
+ repeated bool packed_bool = 102 [packed = true];
+ repeated ForeignEnum packed_enum = 103 [packed = true];
+}
+
+message TestPackedExtensions {
+ extensions 1 to max;
+}
+
+extend TestPackedExtensions {
+ repeated int32 packed_int32_extension = 90 [packed = true];
+ repeated int64 packed_int64_extension = 91 [packed = true];
+ repeated uint32 packed_uint32_extension = 92 [packed = true];
+ repeated uint64 packed_uint64_extension = 93 [packed = true];
+ repeated sint32 packed_sint32_extension = 94 [packed = true];
+ repeated sint64 packed_sint64_extension = 95 [packed = true];
+ repeated fixed32 packed_fixed32_extension = 96 [packed = true];
+ repeated fixed64 packed_fixed64_extension = 97 [packed = true];
+ repeated sfixed32 packed_sfixed32_extension = 98 [packed = true];
+ repeated sfixed64 packed_sfixed64_extension = 99 [packed = true];
+ repeated float packed_float_extension = 100 [packed = true];
+ repeated double packed_double_extension = 101 [packed = true];
+ repeated bool packed_bool_extension = 102 [packed = true];
+ repeated ForeignEnum packed_enum_extension = 103 [packed = true];
+}
+
// Test that RPC services work.
message FooRequest {}
message FooResponse {}
diff --git a/src/google/protobuf/unknown_field_set.cc b/src/google/protobuf/unknown_field_set.cc
index 6a9be5a4..f42f9a59 100644
--- a/src/google/protobuf/unknown_field_set.cc
+++ b/src/google/protobuf/unknown_field_set.cc
@@ -154,6 +154,46 @@ int UnknownFieldSet::SpaceUsed() const {
return sizeof(*this) + SpaceUsedExcludingSelf();
}
+UnknownFieldSet::Internal::FieldMap UnknownFieldSet::kEmptyMap;
+const UnknownFieldSet::iterator UnknownFieldSet::kEmptyIterator(
+ kEmptyMap.end(), &kEmptyMap);
+const UnknownFieldSet::const_iterator UnknownFieldSet::kEmptyConstIterator(
+ kEmptyMap.end(), &kEmptyMap);
+
+void UnknownFieldSet::iterator::AdvanceToNonEmpty() {
+ while (inner_iterator_ != inner_map_->end() &&
+ (inner_iterator_->second->index() == -1 ||
+ inner_iterator_->second->empty())) {
+ ++inner_iterator_;
+ }
+}
+
+void UnknownFieldSet::const_iterator::AdvanceToNonEmpty() {
+ while (inner_iterator_ != inner_map_->end() &&
+ (inner_iterator_->second->index() == -1 ||
+ inner_iterator_->second->empty())) {
+ ++inner_iterator_;
+ }
+}
+
+UnknownFieldSet::iterator UnknownFieldSet::begin() {
+ if (internal_ == NULL) return kEmptyIterator;
+
+ UnknownFieldSet::iterator result(internal_->fields_.begin(),
+ &internal_->fields_);
+ result.AdvanceToNonEmpty();
+ return result;
+}
+
+UnknownFieldSet::const_iterator UnknownFieldSet::begin() const {
+ if (internal_ == NULL) return kEmptyIterator;
+
+ UnknownFieldSet::const_iterator result(internal_->fields_.begin(),
+ &internal_->fields_);
+ result.AdvanceToNonEmpty();
+ return result;
+}
+
UnknownField::UnknownField(int number)
: number_(number),
index_(-1) {
diff --git a/src/google/protobuf/unknown_field_set.h b/src/google/protobuf/unknown_field_set.h
index 55eec6e2..f17012df 100644
--- a/src/google/protobuf/unknown_field_set.h
+++ b/src/google/protobuf/unknown_field_set.h
@@ -70,6 +70,13 @@ class LIBPROTOBUF_EXPORT UnknownFieldSet {
void Clear();
// Is this set empty?
+ //
+ // Note that this is equivalent to field_count() == 0 but is NOT necessarily
+ // equivalent to begin() == end(). The iterator class skips fields which are
+ // themselves empty, so if field_count() is non-zero but field(i)->empty() is
+ // true for all i, then begin() will be equal to end() but empty() will return
+ // false. This inconsistency almost never occurs in practice because typical
+ // code does not add empty fields to an UnknownFieldSet.
inline bool empty() const;
// Merge the contents of some other UnknownFieldSet with this one.
@@ -78,6 +85,117 @@ class LIBPROTOBUF_EXPORT UnknownFieldSet {
// Swaps the contents of some other UnknownFieldSet with this one.
inline void Swap(UnknownFieldSet* x);
+ // Find a field by field number. Returns NULL if not found.
+ const UnknownField* FindFieldByNumber(int number) const;
+
+ // Add a field by field number. If the field number already exists, returns
+ // the existing UnknownField.
+ UnknownField* AddField(int number);
+
+ // Computes (an estimate of) the total number of bytes currently used for
+ // storing the unknown fields in memory. Does NOT include
+ // sizeof(*this) in the calculation.
+ int SpaceUsedExcludingSelf() const;
+
+ // Version of SpaceUsed() including sizeof(*this).
+ int SpaceUsed() const;
+
+ // STL-style iteration ---------------------------------------------
+ // These iterate over the non-empty UnknownFields in order by field
+ // number. All iterators are invalidated whenever the UnknownFieldSet
+ // is modified.
+
+ class const_iterator;
+
+ class LIBPROTOBUF_EXPORT iterator {
+ public:
+ iterator() {}
+
+ bool operator==(const iterator& other) {
+ return inner_iterator_ == other.inner_iterator_;
+ }
+ bool operator!=(const iterator& other) {
+ return inner_iterator_ != other.inner_iterator_;
+ }
+
+ UnknownField& operator*() { return *inner_iterator_->second; }
+ UnknownField* operator->() { return inner_iterator_->second; }
+ iterator& operator++() {
+ ++inner_iterator_;
+ AdvanceToNonEmpty();
+ return *this;
+ }
+ iterator operator++(int) {
+ iterator copy(*this);
+ ++*this;
+ return copy;
+ }
+
+ private:
+ friend class UnknownFieldSet;
+ friend class LIBPROTOBUF_EXPORT UnknownFieldSet::const_iterator;
+ iterator(map<int, UnknownField*>::iterator inner_iterator,
+ map<int, UnknownField*>* inner_map)
+ : inner_iterator_(inner_iterator), inner_map_(inner_map) {}
+
+ void AdvanceToNonEmpty();
+
+ map<int, UnknownField*>::iterator inner_iterator_;
+ map<int, UnknownField*>* inner_map_;
+ };
+
+ class LIBPROTOBUF_EXPORT const_iterator {
+ public:
+ const_iterator() {}
+ const_iterator(const iterator& other)
+ : inner_iterator_(other.inner_iterator_), inner_map_(other.inner_map_) {}
+
+ bool operator==(const const_iterator& other) {
+ return inner_iterator_ == other.inner_iterator_;
+ }
+ bool operator!=(const const_iterator& other) {
+ return inner_iterator_ != other.inner_iterator_;
+ }
+
+ UnknownField& operator*() { return *inner_iterator_->second; }
+ UnknownField* operator->() { return inner_iterator_->second; }
+ const_iterator& operator++() {
+ ++inner_iterator_;
+ AdvanceToNonEmpty();
+ return *this;
+ }
+ const_iterator operator++(int) {
+ const_iterator copy(*this);
+ ++*this;
+ return copy;
+ }
+
+ private:
+ friend class UnknownFieldSet;
+ const_iterator(map<int, UnknownField*>::const_iterator inner_iterator,
+ const map<int, UnknownField*>* inner_map)
+ : inner_iterator_(inner_iterator), inner_map_(inner_map) {}
+
+ void AdvanceToNonEmpty();
+
+ map<int, UnknownField*>::const_iterator inner_iterator_;
+ const map<int, UnknownField*>* inner_map_;
+ };
+
+ iterator begin();
+ iterator end() {
+ return internal_ == NULL ? kEmptyIterator :
+ iterator(internal_->fields_.end(), &internal_->fields_);
+ }
+ const_iterator begin() const;
+ const_iterator end() const {
+ return internal_ == NULL ? kEmptyConstIterator :
+ const_iterator(internal_->fields_.end(), &internal_->fields_);
+ }
+
+ // Old-style iteration ---------------------------------------------
+ // New code should use begin() and end() rather than these methods.
+
// Returns the number of fields present in the UnknownFieldSet.
inline int field_count() const;
// Get a field in the set, where 0 <= index < field_count(). The fields
@@ -87,13 +205,6 @@ class LIBPROTOBUF_EXPORT UnknownFieldSet {
// 0 <= index < field_count(). The fields appear in arbitrary order.
inline UnknownField* mutable_field(int index);
- // Find a field by field number. Returns NULL if not found.
- const UnknownField* FindFieldByNumber(int number) const;
-
- // Add a field by field number. If the field number already exists, returns
- // the existing UnknownField.
- UnknownField* AddField(int number);
-
// Parsing helpers -------------------------------------------------
// These work exactly like the similarly-named methods of Message.
@@ -105,13 +216,6 @@ class LIBPROTOBUF_EXPORT UnknownFieldSet {
return ParseFromArray(data.data(), data.size());
}
- // Computes (an estimate of) the total number of bytes currently used for
- // storing the unknown fields in memory. Does NOT include
- // sizeof(*this) in the calculation.
- int SpaceUsedExcludingSelf() const;
- // Version of SpaceUsed() including sizeof(*this).
- int SpaceUsed() const;
-
private:
// "Active" fields are ones which have been added since the last time Clear()
// was called. Inactive fields are objects we are keeping around incase
@@ -139,6 +243,11 @@ class LIBPROTOBUF_EXPORT UnknownFieldSet {
// Don't keep more inactive fields than this.
static const int kMaxInactiveFields = 100;
+ // Used by begin() and end() when internal_ is NULL.
+ static Internal::FieldMap kEmptyMap;
+ static const iterator kEmptyIterator;
+ static const const_iterator kEmptyConstIterator;
+
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(UnknownFieldSet);
};
@@ -160,6 +269,9 @@ class LIBPROTOBUF_EXPORT UnknownField {
// Clears all fields.
void Clear();
+ // Is this field empty? (I.e. all of the *_size() methods return zero.)
+ inline bool empty() const;
+
// Merge the contents of some other UnknownField with this one. For each
// wire type, the values are simply concatenated.
void MergeFrom(const UnknownField& other);
@@ -256,6 +368,14 @@ inline UnknownField* UnknownFieldSet::mutable_field(int index) {
return internal_->active_fields_[index];
}
+inline bool UnknownField::empty() const {
+ return varint_.size() == 0 &&
+ fixed32_.size() == 0 &&
+ fixed64_.size() == 0 &&
+ length_delimited_.size() == 0 &&
+ group_.size() == 0;
+}
+
inline int UnknownField::number() const { return number_; }
inline int UnknownField::index () const { return index_; }
@@ -322,8 +442,8 @@ inline UnknownFieldSet* UnknownField::add_group() {
}
inline void UnknownField::clear_varint () { varint_.Clear(); }
-inline void UnknownField::clear_fixed32() { varint_.Clear(); }
-inline void UnknownField::clear_fixed64() { varint_.Clear(); }
+inline void UnknownField::clear_fixed32() { fixed32_.Clear(); }
+inline void UnknownField::clear_fixed64() { fixed64_.Clear(); }
inline void UnknownField::clear_length_delimited() {
length_delimited_.Clear();
}
diff --git a/src/google/protobuf/unknown_field_set_unittest.cc b/src/google/protobuf/unknown_field_set_unittest.cc
index c7e78b23..0a75af9f 100644
--- a/src/google/protobuf/unknown_field_set_unittest.cc
+++ b/src/google/protobuf/unknown_field_set_unittest.cc
@@ -516,6 +516,92 @@ TEST_F(UnknownFieldSetTest, SpaceUsed) {
EXPECT_EQ(expected_size, unknown_fields.SpaceUsed());
}
+TEST_F(UnknownFieldSetTest, Empty) {
+ UnknownFieldSet unknown_fields;
+ EXPECT_TRUE(unknown_fields.empty());
+ unknown_fields.AddField(6)->add_varint(123);
+ EXPECT_FALSE(unknown_fields.empty());
+ unknown_fields.Clear();
+ EXPECT_TRUE(unknown_fields.empty());
+}
+
+TEST_F(UnknownFieldSetTest, FieldEmpty) {
+ UnknownFieldSet unknown_fields;
+ UnknownField* field = unknown_fields.AddField(1);
+
+ EXPECT_TRUE(field->empty());
+
+ field->add_varint(1);
+ EXPECT_FALSE(field->empty());
+ field->Clear();
+ EXPECT_TRUE(field->empty());
+
+ field->add_fixed32(1);
+ EXPECT_FALSE(field->empty());
+ field->Clear();
+ EXPECT_TRUE(field->empty());
+
+ field->add_fixed64(1);
+ EXPECT_FALSE(field->empty());
+ field->Clear();
+ EXPECT_TRUE(field->empty());
+
+ field->add_length_delimited("foo");
+ EXPECT_FALSE(field->empty());
+ field->Clear();
+ EXPECT_TRUE(field->empty());
+
+ field->add_group();
+ EXPECT_FALSE(field->empty());
+ field->Clear();
+ EXPECT_TRUE(field->empty());
+}
+
+TEST_F(UnknownFieldSetTest, Iterator) {
+ UnknownFieldSet unknown_fields;
+ EXPECT_TRUE(unknown_fields.begin() == unknown_fields.end());
+
+ // Populate the UnknownFieldSet with some inactive fields by adding some
+ // fields and then clearing.
+ unknown_fields.AddField(6);
+ unknown_fields.AddField(4);
+ unknown_fields.Clear();
+
+ // Add a bunch of "active" fields.
+ UnknownField* a = unknown_fields.AddField(5);
+ unknown_fields.AddField(3);
+ unknown_fields.AddField(9);
+ unknown_fields.AddField(1);
+ UnknownField* b = unknown_fields.AddField(2);
+
+ // Only make some of them non-empty.
+ a->add_varint(1);
+ b->add_length_delimited("foo");
+
+ // Iterate!
+ {
+ UnknownFieldSet::iterator iter = unknown_fields.begin();
+ ASSERT_TRUE(iter != unknown_fields.end());
+ EXPECT_EQ(b, &*iter);
+ ++iter;
+ ASSERT_TRUE(iter != unknown_fields.end());
+ EXPECT_EQ(a, &*iter);
+ ++iter;
+ EXPECT_TRUE(iter == unknown_fields.end());
+ }
+
+ {
+ UnknownFieldSet::const_iterator iter = unknown_fields.begin();
+ ASSERT_TRUE(iter != unknown_fields.end());
+ EXPECT_EQ(b, &*iter);
+ ++iter;
+ ASSERT_TRUE(iter != unknown_fields.end());
+ EXPECT_EQ(a, &*iter);
+ ++iter;
+ EXPECT_TRUE(iter == unknown_fields.end());
+ }
+}
+
} // namespace
} // namespace protobuf
} // namespace google
diff --git a/src/google/protobuf/wire_format.cc b/src/google/protobuf/wire_format.cc
index 99ea619b..aeea3ccb 100644
--- a/src/google/protobuf/wire_format.cc
+++ b/src/google/protobuf/wire_format.cc
@@ -369,93 +369,155 @@ bool WireFormat::ParseAndMergeField(
const Reflection* message_reflection = message->GetReflection();
if (field == NULL ||
- GetTagWireType(tag) != WireTypeForFieldType(field->type())) {
+ GetTagWireType(tag) != WireTypeForField(field)) {
// We don't recognize this field. Either the field number is unknown
// or the wire type doesn't match. Put it in our unknown field set.
return SkipField(input, tag,
message_reflection->MutableUnknownFields(message));
}
- switch (field->type()) {
-#define HANDLE_TYPE(TYPE, TYPE_METHOD, CPPTYPE, CPPTYPE_METHOD) \
- case FieldDescriptor::TYPE_##TYPE: { \
- CPPTYPE value; \
- if (!Read##TYPE_METHOD(input, &value)) return false; \
- if (field->is_repeated()) { \
- message_reflection->Add##CPPTYPE_METHOD(message, field, value); \
- } else { \
- message_reflection->Set##CPPTYPE_METHOD(message, field, value); \
- } \
- break; \
- }
-
- HANDLE_TYPE( INT32, Int32, int32, Int32)
- HANDLE_TYPE( INT64, Int64, int64, Int64)
- HANDLE_TYPE(SINT32, SInt32, int32, Int32)
- HANDLE_TYPE(SINT64, SInt64, int64, Int64)
- HANDLE_TYPE(UINT32, UInt32, uint32, UInt32)
- HANDLE_TYPE(UINT64, UInt64, uint64, UInt64)
-
- HANDLE_TYPE( FIXED32, Fixed32, uint32, UInt32)
- HANDLE_TYPE( FIXED64, Fixed64, uint64, UInt64)
- HANDLE_TYPE(SFIXED32, SFixed32, int32, Int32)
- HANDLE_TYPE(SFIXED64, SFixed64, int64, Int64)
-
- HANDLE_TYPE(FLOAT , Float , float , Float )
- HANDLE_TYPE(DOUBLE, Double, double, Double)
-
- HANDLE_TYPE(BOOL, Bool, bool, Bool)
-
- HANDLE_TYPE(STRING, String, string, String)
- HANDLE_TYPE(BYTES, Bytes, string, String)
+ if (field->options().packed()) {
+ uint32 length;
+ if (!input->ReadVarint32(&length)) return false;
+ io::CodedInputStream::Limit limit = input->PushLimit(length);
-#undef HANDLE_TYPE
+ switch (field->type()) {
+#define HANDLE_PACKED_TYPE(TYPE, TYPE_METHOD, CPPTYPE, CPPTYPE_METHOD) \
+ case FieldDescriptor::TYPE_##TYPE: { \
+ while (input->BytesUntilLimit() > 0) { \
+ CPPTYPE value; \
+ if (!Read##TYPE_METHOD(input, &value)) return false; \
+ message_reflection->Add##CPPTYPE_METHOD(message, field, value); \
+ } \
+ break; \
+ }
- case FieldDescriptor::TYPE_ENUM: {
- int value;
- if (!ReadEnum(input, &value)) return false;
- const EnumValueDescriptor* enum_value =
- field->enum_type()->FindValueByNumber(value);
- if (enum_value != NULL) {
- if (field->is_repeated()) {
- message_reflection->AddEnum(message, field, enum_value);
- } else {
- message_reflection->SetEnum(message, field, enum_value);
+ HANDLE_PACKED_TYPE( INT32, Int32, int32, Int32)
+ HANDLE_PACKED_TYPE( INT64, Int64, int64, Int64)
+ HANDLE_PACKED_TYPE(SINT32, SInt32, int32, Int32)
+ HANDLE_PACKED_TYPE(SINT64, SInt64, int64, Int64)
+ HANDLE_PACKED_TYPE(UINT32, UInt32, uint32, UInt32)
+ HANDLE_PACKED_TYPE(UINT64, UInt64, uint64, UInt64)
+
+ HANDLE_PACKED_TYPE( FIXED32, Fixed32, uint32, UInt32)
+ HANDLE_PACKED_TYPE( FIXED64, Fixed64, uint64, UInt64)
+ HANDLE_PACKED_TYPE(SFIXED32, SFixed32, int32, Int32)
+ HANDLE_PACKED_TYPE(SFIXED64, SFixed64, int64, Int64)
+
+ HANDLE_PACKED_TYPE(FLOAT , Float , float , Float )
+ HANDLE_PACKED_TYPE(DOUBLE, Double, double, Double)
+
+ HANDLE_PACKED_TYPE(BOOL, Bool, bool, Bool)
+#undef HANDLE_PACKED_TYPE
+
+ case FieldDescriptor::TYPE_ENUM: {
+ while (input->BytesUntilLimit() > 0) {
+ int value;
+ if (!ReadEnum(input, &value)) return false;
+ const EnumValueDescriptor* enum_value =
+ field->enum_type()->FindValueByNumber(value);
+ if (enum_value != NULL) {
+ message_reflection->AddEnum(message, field, enum_value);
+ }
}
- } else {
- // The enum value is not one of the known values. Add it to the
- // UnknownFieldSet.
- int64 sign_extended_value = static_cast<int64>(value);
- message_reflection->MutableUnknownFields(message)
- ->AddField(GetTagFieldNumber(tag))
- ->add_varint(sign_extended_value);
+
+ break;
}
- break;
+
+ case FieldDescriptor::TYPE_STRING:
+ case FieldDescriptor::TYPE_GROUP:
+ case FieldDescriptor::TYPE_MESSAGE:
+ case FieldDescriptor::TYPE_BYTES:
+ // Can't have packed fields of these types: these should be caught by
+ // the protocol compiler.
+ return false;
+ break;
}
+ input->PopLimit(limit);
+ } else {
+ switch (field->type()) {
+#define HANDLE_TYPE(TYPE, TYPE_METHOD, CPPTYPE, CPPTYPE_METHOD) \
+ case FieldDescriptor::TYPE_##TYPE: { \
+ CPPTYPE value; \
+ if (!Read##TYPE_METHOD(input, &value)) return false; \
+ if (field->is_repeated()) { \
+ message_reflection->Add##CPPTYPE_METHOD(message, field, value); \
+ } else { \
+ message_reflection->Set##CPPTYPE_METHOD(message, field, value); \
+ } \
+ break; \
+ }
+
+ HANDLE_TYPE( INT32, Int32, int32, Int32)
+ HANDLE_TYPE( INT64, Int64, int64, Int64)
+ HANDLE_TYPE(SINT32, SInt32, int32, Int32)
+ HANDLE_TYPE(SINT64, SInt64, int64, Int64)
+ HANDLE_TYPE(UINT32, UInt32, uint32, UInt32)
+ HANDLE_TYPE(UINT64, UInt64, uint64, UInt64)
- case FieldDescriptor::TYPE_GROUP: {
- Message* sub_message;
- if (field->is_repeated()) {
- sub_message = message_reflection->AddMessage(message, field);
- } else {
- sub_message = message_reflection->MutableMessage(message, field);
+ HANDLE_TYPE( FIXED32, Fixed32, uint32, UInt32)
+ HANDLE_TYPE( FIXED64, Fixed64, uint64, UInt64)
+ HANDLE_TYPE(SFIXED32, SFixed32, int32, Int32)
+ HANDLE_TYPE(SFIXED64, SFixed64, int64, Int64)
+
+ HANDLE_TYPE(FLOAT , Float , float , Float )
+ HANDLE_TYPE(DOUBLE, Double, double, Double)
+
+ HANDLE_TYPE(BOOL, Bool, bool, Bool)
+
+ HANDLE_TYPE(STRING, String, string, String)
+ HANDLE_TYPE(BYTES, Bytes, string, String)
+
+#undef HANDLE_TYPE
+
+ case FieldDescriptor::TYPE_ENUM: {
+ int value;
+ if (!ReadEnum(input, &value)) return false;
+ const EnumValueDescriptor* enum_value =
+ field->enum_type()->FindValueByNumber(value);
+ if (enum_value != NULL) {
+ if (field->is_repeated()) {
+ message_reflection->AddEnum(message, field, enum_value);
+ } else {
+ message_reflection->SetEnum(message, field, enum_value);
+ }
+ } else {
+ // The enum value is not one of the known values. Add it to the
+ // UnknownFieldSet.
+ int64 sign_extended_value = static_cast<int64>(value);
+ message_reflection->MutableUnknownFields(message)
+ ->AddField(GetTagFieldNumber(tag))
+ ->add_varint(sign_extended_value);
+ }
+ break;
}
- if (!ReadGroup(GetTagFieldNumber(tag), input, sub_message)) return false;
- break;
- }
- case FieldDescriptor::TYPE_MESSAGE: {
- Message* sub_message;
- if (field->is_repeated()) {
- sub_message = message_reflection->AddMessage(message, field);
- } else {
- sub_message = message_reflection->MutableMessage(message, field);
+ case FieldDescriptor::TYPE_GROUP: {
+ Message* sub_message;
+ if (field->is_repeated()) {
+ sub_message = message_reflection->AddMessage(message, field);
+ } else {
+ sub_message = message_reflection->MutableMessage(message, field);
+ }
+
+ if (!ReadGroup(GetTagFieldNumber(tag), input, sub_message))
+ return false;
+ break;
}
- if (!ReadMessage(input, sub_message)) return false;
- break;
+ case FieldDescriptor::TYPE_MESSAGE: {
+ Message* sub_message;
+ if (field->is_repeated()) {
+ sub_message = message_reflection->AddMessage(message, field);
+ } else {
+ sub_message = message_reflection->MutableMessage(message, field);
+ }
+
+ if (!ReadMessage(input, sub_message)) return false;
+ break;
+ }
}
}
@@ -602,8 +664,53 @@ bool WireFormat::SerializeFieldWithCachedSizes(
count = 1;
}
+ const bool is_packed = field->options().packed();
+ if (is_packed && count > 0) {
+ if (!WriteTag(field->number(), WIRETYPE_LENGTH_DELIMITED, output))
+ return false;
+ const int data_size = FieldDataOnlyByteSize(field, message);
+ if (!output->WriteVarint32(data_size)) return false;
+ }
+
for (int j = 0; j < count; j++) {
switch (field->type()) {
+#define HANDLE_PRIMITIVE_TYPE(TYPE, CPPTYPE, TYPE_METHOD, CPPTYPE_METHOD) \
+ case FieldDescriptor::TYPE_##TYPE: { \
+ const CPPTYPE value = field->is_repeated() ? \
+ message_reflection->GetRepeated##CPPTYPE_METHOD( \
+ message, field, j) : \
+ message_reflection->Get##CPPTYPE_METHOD( \
+ message, field); \
+ if (is_packed) { \
+ if (!Write##TYPE_METHOD##NoTag(value, output)) { \
+ return false; \
+ } \
+ } else { \
+ if (!Write##TYPE_METHOD(field->number(), value, output)) { \
+ return false; \
+ } \
+ } \
+ break; \
+ }
+
+ HANDLE_PRIMITIVE_TYPE( INT32, int32, Int32, Int32)
+ HANDLE_PRIMITIVE_TYPE( INT64, int64, Int64, Int64)
+ HANDLE_PRIMITIVE_TYPE(SINT32, int32, SInt32, Int32)
+ HANDLE_PRIMITIVE_TYPE(SINT64, int64, SInt64, Int64)
+ HANDLE_PRIMITIVE_TYPE(UINT32, uint32, UInt32, UInt32)
+ HANDLE_PRIMITIVE_TYPE(UINT64, uint64, UInt64, UInt64)
+
+ HANDLE_PRIMITIVE_TYPE( FIXED32, uint32, Fixed32, UInt32)
+ HANDLE_PRIMITIVE_TYPE( FIXED64, uint64, Fixed64, UInt64)
+ HANDLE_PRIMITIVE_TYPE(SFIXED32, int32, SFixed32, Int32)
+ HANDLE_PRIMITIVE_TYPE(SFIXED64, int64, SFixed64, Int64)
+
+ HANDLE_PRIMITIVE_TYPE(FLOAT , float , Float , Float )
+ HANDLE_PRIMITIVE_TYPE(DOUBLE, double, Double, Double)
+
+ HANDLE_PRIMITIVE_TYPE(BOOL, bool, Bool, Bool)
+#undef HANDLE_PRIMITIVE_TYPE
+
#define HANDLE_TYPE(TYPE, TYPE_METHOD, CPPTYPE_METHOD) \
case FieldDescriptor::TYPE_##TYPE: \
if (!Write##TYPE_METHOD( \
@@ -617,23 +724,6 @@ bool WireFormat::SerializeFieldWithCachedSizes(
} \
break;
- HANDLE_TYPE( INT32, Int32, Int32)
- HANDLE_TYPE( INT64, Int64, Int64)
- HANDLE_TYPE(SINT32, SInt32, Int32)
- HANDLE_TYPE(SINT64, SInt64, Int64)
- HANDLE_TYPE(UINT32, UInt32, UInt32)
- HANDLE_TYPE(UINT64, UInt64, UInt64)
-
- HANDLE_TYPE( FIXED32, Fixed32, UInt32)
- HANDLE_TYPE( FIXED64, Fixed64, UInt64)
- HANDLE_TYPE(SFIXED32, SFixed32, Int32)
- HANDLE_TYPE(SFIXED64, SFixed64, Int64)
-
- HANDLE_TYPE(FLOAT , Float , Float )
- HANDLE_TYPE(DOUBLE, Double, Double)
-
- HANDLE_TYPE(BOOL, Bool, Bool)
-
HANDLE_TYPE(GROUP , Group , Message)
HANDLE_TYPE(MESSAGE, Message, Message)
#undef HANDLE_TYPE
@@ -642,7 +732,12 @@ bool WireFormat::SerializeFieldWithCachedSizes(
const EnumValueDescriptor* value = field->is_repeated() ?
message_reflection->GetRepeatedEnum(message, field, j) :
message_reflection->GetEnum(message, field);
- if (!WriteEnum(field->number(), value->number(), output)) return false;
+ if (is_packed) {
+ if (!WriteEnumNoTag(value->number(), output)) return false;
+ } else {
+ if (!WriteEnum(field->number(), value->number(), output))
+ return false;
+ }
break;
}
@@ -736,36 +831,60 @@ int WireFormat::FieldByteSize(
return MessageSetItemByteSize(field, message);
}
- int our_size = 0;
-
int count = 0;
-
if (field->is_repeated()) {
count = message_reflection->FieldSize(message, field);
} else if (message_reflection->HasField(message, field)) {
count = 1;
}
- our_size += count * TagSize(field->number(), field->type());
+ const int data_size = FieldDataOnlyByteSize(field, message);
+ int our_size = data_size;
+ if (field->options().packed()) {
+ if (data_size > 0) {
+ // Packed fields get serialized like a string, not their native type.
+ // Technically this doesn't really matter; the size only changes if it's
+ // a GROUP
+ our_size += TagSize(field->number(), FieldDescriptor::TYPE_STRING);
+ our_size += io::CodedOutputStream::VarintSize32(data_size);
+ }
+ } else {
+ our_size += count * TagSize(field->number(), field->type());
+ }
+ return our_size;
+}
+
+int WireFormat::FieldDataOnlyByteSize(
+ const FieldDescriptor* field,
+ const Message& message) {
+ const Reflection* message_reflection = message.GetReflection();
+
+ int count = 0;
+ if (field->is_repeated()) {
+ count = message_reflection->FieldSize(message, field);
+ } else if (message_reflection->HasField(message, field)) {
+ count = 1;
+ }
+ int data_size = 0;
switch (field->type()) {
#define HANDLE_TYPE(TYPE, TYPE_METHOD, CPPTYPE_METHOD) \
case FieldDescriptor::TYPE_##TYPE: \
if (field->is_repeated()) { \
for (int j = 0; j < count; j++) { \
- our_size += TYPE_METHOD##Size( \
+ data_size += TYPE_METHOD##Size( \
message_reflection->GetRepeated##CPPTYPE_METHOD( \
message, field, j)); \
} \
} else { \
- our_size += TYPE_METHOD##Size( \
+ data_size += TYPE_METHOD##Size( \
message_reflection->Get##CPPTYPE_METHOD(message, field)); \
} \
break;
#define HANDLE_FIXED_TYPE(TYPE, TYPE_METHOD) \
case FieldDescriptor::TYPE_##TYPE: \
- our_size += count * k##TYPE_METHOD##Size; \
+ data_size += count * k##TYPE_METHOD##Size; \
break;
HANDLE_TYPE( INT32, Int32, Int32)
@@ -793,11 +912,11 @@ int WireFormat::FieldByteSize(
case FieldDescriptor::TYPE_ENUM: {
if (field->is_repeated()) {
for (int j = 0; j < count; j++) {
- our_size += EnumSize(
+ data_size += EnumSize(
message_reflection->GetRepeatedEnum(message, field, j)->number());
}
} else {
- our_size += EnumSize(
+ data_size += EnumSize(
message_reflection->GetEnum(message, field)->number());
}
break;
@@ -813,13 +932,12 @@ int WireFormat::FieldByteSize(
message_reflection->GetRepeatedStringReference(
message, field, j, &scratch) :
message_reflection->GetStringReference(message, field, &scratch);
- our_size += StringSize(value);
+ data_size += StringSize(value);
}
break;
}
}
-
- return our_size;
+ return data_size;
}
int WireFormat::MessageSetItemByteSize(
diff --git a/src/google/protobuf/wire_format.h b/src/google/protobuf/wire_format.h
index 06f20d2a..9004caaa 100644
--- a/src/google/protobuf/wire_format.h
+++ b/src/google/protobuf/wire_format.h
@@ -163,13 +163,20 @@ class LIBPROTOBUF_EXPORT WireFormat {
static inline WireType WireTypeForFieldType(FieldDescriptor::Type type) {
return kWireTypeForFieldType[type];
}
+ // This is different from WireTypeForFieldType(field->type()) in the case of
+ // packed repeated fields.
+ static inline WireType WireTypeForField(const FieldDescriptor* field);
// Number of bits in a tag which identify the wire type.
static const int kTagTypeBits = 3;
// Mask for those bits.
static const uint32 kTagTypeMask = (1 << kTagTypeBits) - 1;
- // Helper functions for encoding and decoding tags. (Inlined below.)
+ // Helper functions for encoding and decoding tags. (Inlined below and in
+ // _inl.h)
+ //
+ // This is different from MakeTag(field->number(), field->type()) in the case
+ // of packed repeated fields.
static uint32 MakeTag(const FieldDescriptor* field);
static uint32 MakeTag(int field_number, WireType type);
static WireType GetTagWireType(uint32 tag);
@@ -258,10 +265,27 @@ class LIBPROTOBUF_EXPORT WireFormat {
template<typename MessageType>
static inline bool ReadMessageNoVirtual(input, MessageType* value);
- // Write a tag. The Write*() functions automatically include the tag, so
- // normally there's no need to call this.
+ // Write a tag. The Write*() functions typically include the tag, so
+ // normally there's no need to call this unless using the Write*NoTag()
+ // variants.
static inline bool WriteTag(field_number, WireType type, output) INL;
+ // Write fields, without tags.
+ static inline bool WriteInt32NoTag (int32 value, output) INL;
+ static inline bool WriteInt64NoTag (int64 value, output) INL;
+ static inline bool WriteUInt32NoTag (uint32 value, output) INL;
+ static inline bool WriteUInt64NoTag (uint64 value, output) INL;
+ static inline bool WriteSInt32NoTag (int32 value, output) INL;
+ static inline bool WriteSInt64NoTag (int64 value, output) INL;
+ static inline bool WriteFixed32NoTag (uint32 value, output) INL;
+ static inline bool WriteFixed64NoTag (uint64 value, output) INL;
+ static inline bool WriteSFixed32NoTag(int32 value, output) INL;
+ static inline bool WriteSFixed64NoTag(int64 value, output) INL;
+ static inline bool WriteFloatNoTag (float value, output) INL;
+ static inline bool WriteDoubleNoTag (double value, output) INL;
+ static inline bool WriteBoolNoTag (bool value, output) INL;
+ static inline bool WriteEnumNoTag (int value, output) INL;
+
// Write fields, including tags.
static inline bool WriteInt32 (field_number, int32 value, output) INL;
static inline bool WriteInt64 (field_number, int64 value, output) INL;
@@ -355,6 +379,14 @@ class LIBPROTOBUF_EXPORT WireFormat {
const FieldDescriptor* field,
const Message& message);
+ // Computes the byte size of a field, excluding tags. For packed fields, it
+ // only includes the size of the raw data, and not the size of the total
+ // length, but for other length-delimited types, the size of the length is
+ // included.
+ static int FieldDataOnlyByteSize(
+ const FieldDescriptor* field, // Cannot be NULL
+ const Message& message);
+
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(WireFormat);
};
@@ -368,10 +400,6 @@ class LIBPROTOBUF_EXPORT WireFormat {
static_cast<uint32>( \
((FIELD_NUMBER) << ::google::protobuf::internal::WireFormat::kTagTypeBits) | (TYPE))
-inline uint32 WireFormat::MakeTag(const FieldDescriptor* field) {
- return MakeTag(field->number(), WireTypeForFieldType(field->type()));
-}
-
inline uint32 WireFormat::MakeTag(int field_number, WireType type) {
return GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(field_number, type);
}
diff --git a/src/google/protobuf/wire_format_inl.h b/src/google/protobuf/wire_format_inl.h
index 539d8c67..451ac11c 100644
--- a/src/google/protobuf/wire_format_inl.h
+++ b/src/google/protobuf/wire_format_inl.h
@@ -38,6 +38,8 @@
#include <string>
#include <google/protobuf/stubs/common.h>
#include <google/protobuf/wire_format.h>
+#include <google/protobuf/descriptor.h>
+#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/io/coded_stream.h>
@@ -51,6 +53,19 @@ namespace google {
namespace protobuf {
namespace internal {
+inline WireFormat::WireType WireFormat::WireTypeForField(
+ const FieldDescriptor* field) {
+ if (field->options().packed()) {
+ return WIRETYPE_LENGTH_DELIMITED;
+ } else {
+ return WireTypeForFieldType(field->type());
+ }
+}
+
+inline uint32 WireFormat::MakeTag(const FieldDescriptor* field) {
+ return MakeTag(field->number(), WireTypeForField(field));
+}
+
inline bool WireFormat::ReadInt32(io::CodedInputStream* input, int32* value) {
uint32 temp;
if (!input->ReadVarint32(&temp)) return false;
@@ -210,75 +225,132 @@ inline bool WireFormat::WriteTag(int field_number, WireType type,
return output->WriteTag(MakeTag(field_number, type));
}
+inline bool WireFormat::WriteInt32NoTag(int32 value,
+ io::CodedOutputStream* output) {
+ return output->WriteVarint32SignExtended(value);
+}
+inline bool WireFormat::WriteInt64NoTag(int64 value,
+ io::CodedOutputStream* output) {
+ return output->WriteVarint64(static_cast<uint64>(value));
+}
+inline bool WireFormat::WriteUInt32NoTag(uint32 value,
+ io::CodedOutputStream* output) {
+ return output->WriteVarint32(value);
+}
+inline bool WireFormat::WriteUInt64NoTag(uint64 value,
+ io::CodedOutputStream* output) {
+ return output->WriteVarint64(value);
+}
+inline bool WireFormat::WriteSInt32NoTag(int32 value,
+ io::CodedOutputStream* output) {
+ return output->WriteVarint32(ZigZagEncode32(value));
+}
+inline bool WireFormat::WriteSInt64NoTag(int64 value,
+ io::CodedOutputStream* output) {
+ return output->WriteVarint64(ZigZagEncode64(value));
+}
+inline bool WireFormat::WriteFixed32NoTag(uint32 value,
+ io::CodedOutputStream* output) {
+ return output->WriteLittleEndian32(value);
+}
+inline bool WireFormat::WriteFixed64NoTag(uint64 value,
+ io::CodedOutputStream* output) {
+ return output->WriteLittleEndian64(value);
+}
+inline bool WireFormat::WriteSFixed32NoTag(int32 value,
+ io::CodedOutputStream* output) {
+ return output->WriteLittleEndian32(static_cast<uint32>(value));
+}
+inline bool WireFormat::WriteSFixed64NoTag(int64 value,
+ io::CodedOutputStream* output) {
+ return output->WriteLittleEndian64(static_cast<uint64>(value));
+}
+inline bool WireFormat::WriteFloatNoTag(float value,
+ io::CodedOutputStream* output) {
+ return output->WriteLittleEndian32(EncodeFloat(value));
+}
+inline bool WireFormat::WriteDoubleNoTag(double value,
+ io::CodedOutputStream* output) {
+ return output->WriteLittleEndian64(EncodeDouble(value));
+}
+inline bool WireFormat::WriteBoolNoTag(bool value,
+ io::CodedOutputStream* output) {
+ return output->WriteVarint32(value ? 1 : 0);
+}
+inline bool WireFormat::WriteEnumNoTag(int value,
+ io::CodedOutputStream* output) {
+ return output->WriteVarint32SignExtended(value);
+}
+
inline bool WireFormat::WriteInt32(int field_number, int32 value,
io::CodedOutputStream* output) {
return WriteTag(field_number, WIRETYPE_VARINT, output) &&
- output->WriteVarint32SignExtended(value);
+ WriteInt32NoTag(value, output);
}
inline bool WireFormat::WriteInt64(int field_number, int64 value,
io::CodedOutputStream* output) {
return WriteTag(field_number, WIRETYPE_VARINT, output) &&
- output->WriteVarint64(static_cast<uint64>(value));
+ WriteInt64NoTag(value, output);
}
inline bool WireFormat::WriteUInt32(int field_number, uint32 value,
io::CodedOutputStream* output) {
return WriteTag(field_number, WIRETYPE_VARINT, output) &&
- output->WriteVarint32(value);
+ WriteUInt32NoTag(value, output);
}
inline bool WireFormat::WriteUInt64(int field_number, uint64 value,
io::CodedOutputStream* output) {
return WriteTag(field_number, WIRETYPE_VARINT, output) &&
- output->WriteVarint64(value);
+ WriteUInt64NoTag(value, output);
}
inline bool WireFormat::WriteSInt32(int field_number, int32 value,
io::CodedOutputStream* output) {
return WriteTag(field_number, WIRETYPE_VARINT, output) &&
- output->WriteVarint32(ZigZagEncode32(value));
+ WriteSInt32NoTag(value, output);
}
inline bool WireFormat::WriteSInt64(int field_number, int64 value,
io::CodedOutputStream* output) {
return WriteTag(field_number, WIRETYPE_VARINT, output) &&
- output->WriteVarint64(ZigZagEncode64(value));
+ WriteSInt64NoTag(value, output);
}
inline bool WireFormat::WriteFixed32(int field_number, uint32 value,
io::CodedOutputStream* output) {
return WriteTag(field_number, WIRETYPE_FIXED32, output) &&
- output->WriteLittleEndian32(value);
+ WriteFixed32NoTag(value, output);
}
inline bool WireFormat::WriteFixed64(int field_number, uint64 value,
io::CodedOutputStream* output) {
return WriteTag(field_number, WIRETYPE_FIXED64, output) &&
- output->WriteLittleEndian64(value);
+ WriteFixed64NoTag(value, output);
}
inline bool WireFormat::WriteSFixed32(int field_number, int32 value,
io::CodedOutputStream* output) {
return WriteTag(field_number, WIRETYPE_FIXED32, output) &&
- output->WriteLittleEndian32(static_cast<uint32>(value));
+ WriteSFixed32NoTag(value, output);
}
inline bool WireFormat::WriteSFixed64(int field_number, int64 value,
io::CodedOutputStream* output) {
return WriteTag(field_number, WIRETYPE_FIXED64, output) &&
- output->WriteLittleEndian64(static_cast<uint64>(value));
+ WriteSFixed64NoTag(value, output);
}
inline bool WireFormat::WriteFloat(int field_number, float value,
io::CodedOutputStream* output) {
return WriteTag(field_number, WIRETYPE_FIXED32, output) &&
- output->WriteLittleEndian32(EncodeFloat(value));
+ WriteFloatNoTag(value, output);
}
inline bool WireFormat::WriteDouble(int field_number, double value,
io::CodedOutputStream* output) {
return WriteTag(field_number, WIRETYPE_FIXED64, output) &&
- output->WriteLittleEndian64(EncodeDouble(value));
+ WriteDoubleNoTag(value, output);
}
inline bool WireFormat::WriteBool(int field_number, bool value,
io::CodedOutputStream* output) {
return WriteTag(field_number, WIRETYPE_VARINT, output) &&
- output->WriteVarint32(value ? 1 : 0);
+ WriteBoolNoTag(value, output);
}
inline bool WireFormat::WriteEnum(int field_number, int value,
io::CodedOutputStream* output) {
return WriteTag(field_number, WIRETYPE_VARINT, output) &&
- output->WriteVarint32SignExtended(value);
+ WriteEnumNoTag(value, output);
}
inline bool WireFormat::WriteString(int field_number, const string& value,
diff --git a/src/google/protobuf/wire_format_unittest.cc b/src/google/protobuf/wire_format_unittest.cc
index 43dccd1a..5a7c6c23 100644
--- a/src/google/protobuf/wire_format_unittest.cc
+++ b/src/google/protobuf/wire_format_unittest.cc
@@ -90,6 +90,40 @@ TEST(WireFormatTest, ParseExtensions) {
TestUtil::ExpectAllExtensionsSet(dest);
}
+TEST(WireFormatTest, ParsePacked) {
+ unittest::TestPackedTypes source, dest;
+ string data;
+
+ // Serialize using the generated code.
+ TestUtil::SetPackedFields(&source);
+ source.SerializeToString(&data);
+
+ // Parse using WireFormat.
+ io::ArrayInputStream raw_input(data.data(), data.size());
+ io::CodedInputStream input(&raw_input);
+ WireFormat::ParseAndMergePartial(&input, &dest);
+
+ // Check.
+ TestUtil::ExpectPackedFieldsSet(dest);
+}
+
+TEST(WireFormatTest, ParsePackedExtensions) {
+ unittest::TestPackedExtensions source, dest;
+ string data;
+
+ // Serialize using the generated code.
+ TestUtil::SetPackedExtensions(&source);
+ source.SerializeToString(&data);
+
+ // Parse using WireFormat.
+ io::ArrayInputStream raw_input(data.data(), data.size());
+ io::CodedInputStream input(&raw_input);
+ WireFormat::ParseAndMergePartial(&input, &dest);
+
+ // Check.
+ TestUtil::ExpectPackedExtensionsSet(dest);
+}
+
TEST(WireFormatTest, ByteSize) {
unittest::TestAllTypes message;
TestUtil::SetAllFields(&message);
@@ -111,6 +145,27 @@ TEST(WireFormatTest, ByteSizeExtensions) {
EXPECT_EQ(0, WireFormat::ByteSize(message));
}
+TEST(WireFormatTest, ByteSizePacked) {
+ unittest::TestPackedTypes message;
+ TestUtil::SetPackedFields(&message);
+
+ EXPECT_EQ(message.ByteSize(), WireFormat::ByteSize(message));
+ message.Clear();
+ EXPECT_EQ(0, message.ByteSize());
+ EXPECT_EQ(0, WireFormat::ByteSize(message));
+}
+
+TEST(WireFormatTest, ByteSizePackedExtensions) {
+ unittest::TestPackedExtensions message;
+ TestUtil::SetPackedExtensions(&message);
+
+ EXPECT_EQ(message.ByteSize(),
+ WireFormat::ByteSize(message));
+ message.Clear();
+ EXPECT_EQ(0, message.ByteSize());
+ EXPECT_EQ(0, WireFormat::ByteSize(message));
+}
+
TEST(WireFormatTest, Serialize) {
unittest::TestAllTypes message;
string generated_data;