aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar kenton@google.com <kenton@google.com@630680e5-0e50-0410-840e-4b1c322b438d>2009-01-22 01:27:00 +0000
committerGravatar kenton@google.com <kenton@google.com@630680e5-0e50-0410-840e-4b1c322b438d>2009-01-22 01:27:00 +0000
commit2d6daa72ab5832bf4cab38df0d911f32df547021 (patch)
tree5f9304a6ff2c7c0cb7ed62eead92bf05411666f8 /src
parent87e64e1ceeff224043078e7e31fe0b1a119c8b1a (diff)
Push out changes from internal codebase.
All Languages * Repeated fields of primitive types (types other that string, group, and nested messages) may now use the option [packed = true] to get a more efficient encoding. In the new encoding, the entire list is written as a single byte blob using the "length-delimited" wire type. Within this blob, the individual values are encoded the same way they would be normally except without a tag before each value (thus, they are tightly "packed"). C++ * UnknownFieldSet now supports STL-like iteration. * Message interface has method ParseFromBoundedZeroCopyStream() which parses a limited number of bytes from an input stream rather than parsing until EOF. Java * Fixed bug where Message.mergeFrom(Message) failed to merge extensions. * Message interface has new method toBuilder() which is equivalent to newBuilderForType().mergeFrom(this). * All enums now implement the ProtocolMessageEnum interface. * Setting a field to null now throws NullPointerException. * Fixed tendency for TextFormat's parsing to overflow the stack when parsing large string values. The underlying problem is with Java's regex implementation (which unfortunately uses recursive backtracking rather than building an NFA). Worked around by making use of possesive quantifiers. Python * Updated RPC interfaces to allow for blocking operation. A client may now pass None for a callback when making an RPC, in which case the call will block until the response is received, and the response object will be returned directly to the caller. This interface change cannot be used in practice until RPC implementations are updated to implement it.
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;