aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/google/protobuf/compiler
diff options
context:
space:
mode:
authorGravatar kenton@google.com <kenton@google.com@630680e5-0e50-0410-840e-4b1c322b438d>2008-11-21 00:06:27 +0000
committerGravatar kenton@google.com <kenton@google.com@630680e5-0e50-0410-840e-4b1c322b438d>2008-11-21 00:06:27 +0000
commit26bd9eee6ee6d116e1cc0dedeb660cd69d7aac45 (patch)
treed35cca89e0da44f136090a554ff9abc93a794fa8 /src/google/protobuf/compiler
parenta2a32c20434807e9966e3f48375f9419134d1b55 (diff)
Integrate changes from internal code.
protoc * Enum values may now have custom options, using syntax similar to field options. * Fixed bug where .proto files which use custom options but don't actually define them (i.e. they import another .proto file defining the options) had to explicitly import descriptor.proto. * Adjacent string literals in .proto files will now be concatenated, like in C. C++ * Generated message classes now have a Swap() method which efficiently swaps the contents of two objects. * All message classes now have a SpaceUsed() method which returns an estimate of the number of bytes of allocated memory currently owned by the object. This is particularly useful when you are reusing a single message object to improve performance but want to make sure it doesn't bloat up too large. * New method Message::SerializeAsString() returns a string containing the serialized data. May be more convenient than calling SerializeToString(string*). * In debug mode, log error messages when string-type fields are found to contain bytes that are not valid UTF-8. * Fixed bug where a message with multiple extension ranges couldn't parse extensions. * Fixed bug where MergeFrom(const Message&) didn't do anything if invoked on a message that contained no fields (but possibly contained extensions). * Fixed ShortDebugString() to not be O(n^2). Durr. * Fixed crash in TextFormat parsing if the first token in the input caused a tokenization error. Java * New overload of mergeFrom() which parses a slice of a byte array instead of the whole thing. * New method ByteString.asReadOnlyByteBuffer() does what it sounds like. * Improved performance of isInitialized() when optimizing for code size. Python * Corrected ListFields() signature in Message base class to match what subclasses actually implement. * Some minor refactoring.
Diffstat (limited to 'src/google/protobuf/compiler')
-rw-r--r--src/google/protobuf/compiler/command_line_interface.cc1
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_enum_field.cc10
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_enum_field.h2
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_field.h7
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message.cc72
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message.h1
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message_field.cc10
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message_field.h2
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_primitive_field.cc10
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_primitive_field.h2
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_string_field.cc28
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_string_field.h2
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_unittest.cc116
-rw-r--r--src/google/protobuf/compiler/parser.cc18
-rw-r--r--src/google/protobuf/compiler/parser.h4
-rw-r--r--src/google/protobuf/compiler/parser_unittest.cc38
16 files changed, 294 insertions, 29 deletions
diff --git a/src/google/protobuf/compiler/command_line_interface.cc b/src/google/protobuf/compiler/command_line_interface.cc
index a19d16d1..ea8c4ab2 100644
--- a/src/google/protobuf/compiler/command_line_interface.cc
+++ b/src/google/protobuf/compiler/command_line_interface.cc
@@ -32,6 +32,7 @@
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
+#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
index 6f0bc270..c998f20b 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.cc
@@ -111,6 +111,11 @@ GenerateMergingCode(io::Printer* printer) const {
}
void EnumFieldGenerator::
+GenerateSwappingCode(io::Printer* printer) const {
+ printer->Print(variables_, "std::swap($name$_, other->$name$_);\n");
+}
+
+void EnumFieldGenerator::
GenerateInitializer(io::Printer* printer) const {
printer->Print(variables_, ",\n$name$_($default$)");
}
@@ -201,6 +206,11 @@ GenerateMergingCode(io::Printer* printer) const {
}
void RepeatedEnumFieldGenerator::
+GenerateSwappingCode(io::Printer* printer) const {
+ printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n");
+}
+
+void RepeatedEnumFieldGenerator::
GenerateInitializer(io::Printer* printer) const {
// Not needed for repeated fields.
}
diff --git a/src/google/protobuf/compiler/cpp/cpp_enum_field.h b/src/google/protobuf/compiler/cpp/cpp_enum_field.h
index 6bcd0b1b..f67b7ac0 100644
--- a/src/google/protobuf/compiler/cpp/cpp_enum_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_enum_field.h
@@ -55,6 +55,7 @@ class EnumFieldGenerator : public FieldGenerator {
void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
void GenerateClearingCode(io::Printer* printer) const;
void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateSwappingCode(io::Printer* printer) const;
void GenerateInitializer(io::Printer* printer) const;
void GenerateMergeFromCodedStream(io::Printer* printer) const;
void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
@@ -78,6 +79,7 @@ class RepeatedEnumFieldGenerator : public FieldGenerator {
void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
void GenerateClearingCode(io::Printer* printer) const;
void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateSwappingCode(io::Printer* printer) const;
void GenerateInitializer(io::Printer* printer) const;
void GenerateMergeFromCodedStream(io::Printer* printer) const;
void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
diff --git a/src/google/protobuf/compiler/cpp/cpp_field.h b/src/google/protobuf/compiler/cpp/cpp_field.h
index 925483a7..e5f8258f 100644
--- a/src/google/protobuf/compiler/cpp/cpp_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_field.h
@@ -87,6 +87,13 @@ class FieldGenerator {
// GenerateMergeFrom method.
virtual void GenerateMergingCode(io::Printer* printer) const = 0;
+ // Generate lines of code (statements, not declarations) which swaps
+ // this field and the corresponding field of another message, which
+ // is stored in the generated code variable "other". This is used to
+ // define the Swap method. Details of usage can be found in
+ // message.cc under the GenerateSwap method.
+ virtual void GenerateSwappingCode(io::Printer* printer) const = 0;
+
// Generate any initializers needed for the private members declared by
// GeneratePrivateMembers(). These go into the message class's
// constructor's initializer list. For each initializer, this method
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc
index f3fd48d1..eacceeaf 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message.cc
@@ -416,7 +416,8 @@ GenerateClassDefinition(io::Printer* printer) {
"}\n"
"\n"
"static const ::google::protobuf::Descriptor* descriptor();\n"
- "static const $classname$& default_instance();"
+ "static const $classname$& default_instance();\n"
+ "void Swap($classname$* other);\n"
"\n"
"// implements Message ----------------------------------------------\n"
"\n"
@@ -617,7 +618,8 @@ GenerateDescriptorInitializer(io::Printer* printer, int index) {
" -1,\n");
}
printer->Print(vars,
- " ::google::protobuf::DescriptorPool::generated_pool());\n");
+ " ::google::protobuf::DescriptorPool::generated_pool(),\n"
+ " sizeof($classname$));\n");
// Handle nested types.
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
@@ -693,6 +695,9 @@ GenerateClassMethods(io::Printer* printer) {
GenerateCopyFrom(printer);
printer->Print("\n");
+ GenerateSwap(printer);
+ printer->Print("\n");
+
GenerateIsInitialized(printer);
printer->Print("\n");
}
@@ -947,6 +952,37 @@ GenerateClear(io::Printer* printer) {
}
void MessageGenerator::
+GenerateSwap(io::Printer* printer) {
+ // Generate the Swap member function.
+ printer->Print("void $classname$::Swap($classname$* other) {\n",
+ "classname", classname_);
+ printer->Indent();
+ printer->Print("if (other != this) {\n");
+ printer->Indent();
+
+ for (int i = 0; i < descriptor_->field_count(); i++) {
+ const FieldDescriptor* field = descriptor_->field(i);
+ field_generators_.get(field).GenerateSwappingCode(printer);
+ }
+
+ for (int i = 0; i < (descriptor_->field_count() + 31) / 32; ++i) {
+ printer->Print("std::swap(_has_bits_[$i$], other->_has_bits_[$i$]);\n",
+ "i", SimpleItoa(i));
+ }
+
+ printer->Print("_unknown_fields_.Swap(&other->_unknown_fields_);\n");
+ printer->Print("std::swap(_cached_size_, other->_cached_size_);\n");
+ if (descriptor_->extension_range_count() > 0) {
+ printer->Print("_extensions_.Swap(&other->_extensions_);\n");
+ }
+
+ printer->Outdent();
+ printer->Print("}\n");
+ printer->Outdent();
+ printer->Print("}\n");
+}
+
+void MessageGenerator::
GenerateMergeFrom(io::Printer* printer) {
// Generate the generalized MergeFrom (aka that which takes in the Message
// base class as a parameter).
@@ -956,22 +992,20 @@ GenerateMergeFrom(io::Printer* printer) {
"classname", classname_);
printer->Indent();
- if (descriptor_->field_count() > 0) {
- // Cast the message to the proper type. If we find that the message is
- // *not* of the proper type, we can still call Merge via the reflection
- // system, as the GOOGLE_CHECK above ensured that we have the same descriptor
- // for each message.
- printer->Print(
- "const $classname$* source =\n"
- " ::google::protobuf::internal::dynamic_cast_if_available<const $classname$*>(\n"
- " &from);\n"
- "if (source == NULL) {\n"
- " ::google::protobuf::internal::ReflectionOps::Merge(from, this);\n"
- "} else {\n"
- " MergeFrom(*source);\n"
- "}\n",
- "classname", classname_);
- }
+ // Cast the message to the proper type. If we find that the message is
+ // *not* of the proper type, we can still call Merge via the reflection
+ // system, as the GOOGLE_CHECK above ensured that we have the same descriptor
+ // for each message.
+ printer->Print(
+ "const $classname$* source =\n"
+ " ::google::protobuf::internal::dynamic_cast_if_available<const $classname$*>(\n"
+ " &from);\n"
+ "if (source == NULL) {\n"
+ " ::google::protobuf::internal::ReflectionOps::Merge(from, this);\n"
+ "} else {\n"
+ " MergeFrom(*source);\n"
+ "}\n",
+ "classname", classname_);
printer->Outdent();
printer->Print("}\n\n");
@@ -1199,7 +1233,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
for (int i = 0; i < descriptor_->extension_range_count(); i++) {
const Descriptor::ExtensionRange* range =
descriptor_->extension_range(i);
- if (i > 0) printer->Print(" &&\n ");
+ if (i > 0) printer->Print(" ||\n ");
uint32 start_tag = WireFormat::MakeTag(
range->start, static_cast<WireFormat::WireType>(0));
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.h b/src/google/protobuf/compiler/cpp/cpp_message.h
index 037ddd85..d6669a34 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.h
+++ b/src/google/protobuf/compiler/cpp/cpp_message.h
@@ -115,6 +115,7 @@ class MessageGenerator {
void GenerateByteSize(io::Printer* printer);
void GenerateMergeFrom(io::Printer* printer);
void GenerateCopyFrom(io::Printer* printer);
+ void GenerateSwap(io::Printer* printer);
void GenerateIsInitialized(io::Printer* printer);
// Helpers for GenerateSerializeWithCachedSizes().
diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.cc b/src/google/protobuf/compiler/cpp/cpp_message_field.cc
index 8904974f..d1c31067 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc
@@ -111,6 +111,11 @@ GenerateMergingCode(io::Printer* printer) const {
}
void MessageFieldGenerator::
+GenerateSwappingCode(io::Printer* printer) const {
+ printer->Print(variables_, "std::swap($name$_, other->$name$_);\n");
+}
+
+void MessageFieldGenerator::
GenerateInitializer(io::Printer* printer) const {
printer->Print(variables_, ",\n$name$_(NULL)");
}
@@ -202,6 +207,11 @@ GenerateMergingCode(io::Printer* printer) const {
}
void RepeatedMessageFieldGenerator::
+GenerateSwappingCode(io::Printer* printer) const {
+ printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n");
+}
+
+void RepeatedMessageFieldGenerator::
GenerateInitializer(io::Printer* printer) const {
// Not needed for repeated fields.
}
diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.h b/src/google/protobuf/compiler/cpp/cpp_message_field.h
index 0405cbc8..7ce4c32b 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_message_field.h
@@ -55,6 +55,7 @@ class MessageFieldGenerator : public FieldGenerator {
void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
void GenerateClearingCode(io::Printer* printer) const;
void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateSwappingCode(io::Printer* printer) const;
void GenerateInitializer(io::Printer* printer) const;
void GenerateMergeFromCodedStream(io::Printer* printer) const;
void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
@@ -78,6 +79,7 @@ class RepeatedMessageFieldGenerator : public FieldGenerator {
void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
void GenerateClearingCode(io::Printer* printer) const;
void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateSwappingCode(io::Printer* printer) const;
void GenerateInitializer(io::Printer* printer) const;
void GenerateMergeFromCodedStream(io::Printer* printer) const;
void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
index 0b437d68..ef4072f0 100644
--- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc
@@ -175,6 +175,11 @@ GenerateMergingCode(io::Printer* printer) const {
}
void PrimitiveFieldGenerator::
+GenerateSwappingCode(io::Printer* printer) const {
+ printer->Print(variables_, "std::swap($name$_, other->$name$_);\n");
+}
+
+void PrimitiveFieldGenerator::
GenerateInitializer(io::Printer* printer) const {
printer->Print(variables_, ",\n$name$_($default$)");
}
@@ -267,6 +272,11 @@ GenerateMergingCode(io::Printer* printer) const {
}
void RepeatedPrimitiveFieldGenerator::
+GenerateSwappingCode(io::Printer* printer) const {
+ printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n");
+}
+
+void RepeatedPrimitiveFieldGenerator::
GenerateInitializer(io::Printer* printer) const {
// Not needed for repeated fields.
}
diff --git a/src/google/protobuf/compiler/cpp/cpp_primitive_field.h b/src/google/protobuf/compiler/cpp/cpp_primitive_field.h
index 25b7fba4..c7f7f310 100644
--- a/src/google/protobuf/compiler/cpp/cpp_primitive_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_primitive_field.h
@@ -55,6 +55,7 @@ class PrimitiveFieldGenerator : public FieldGenerator {
void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
void GenerateClearingCode(io::Printer* printer) const;
void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateSwappingCode(io::Printer* printer) const;
void GenerateInitializer(io::Printer* printer) const;
void GenerateMergeFromCodedStream(io::Printer* printer) const;
void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
@@ -78,6 +79,7 @@ class RepeatedPrimitiveFieldGenerator : public FieldGenerator {
void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
void GenerateClearingCode(io::Printer* printer) const;
void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateSwappingCode(io::Printer* printer) const;
void GenerateInitializer(io::Printer* printer) const;
void GenerateMergeFromCodedStream(io::Printer* printer) const;
void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
index 66a0496c..3e694ab7 100644
--- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
@@ -163,12 +163,12 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
"inline ::std::string* $classname$::mutable_$name$() {\n"
" _set_bit($index$);\n"
" if ($name$_ == &_default_$name$_) {\n");
- if (descriptor_->has_default_value()) {
+ if (descriptor_->default_value_string().empty()) {
printer->Print(variables_,
- " $name$_ = new ::std::string(_default_$name$_);\n");
+ " $name$_ = new ::std::string;\n");
} else {
printer->Print(variables_,
- " $name$_ = new ::std::string;\n");
+ " $name$_ = new ::std::string(_default_$name$_);\n");
}
printer->Print(variables_,
" }\n"
@@ -178,26 +178,26 @@ GenerateInlineAccessorDefinitions(io::Printer* printer) const {
void StringFieldGenerator::
GenerateNonInlineAccessorDefinitions(io::Printer* printer) const {
- if (descriptor_->has_default_value()) {
+ if (descriptor_->default_value_string().empty()) {
printer->Print(variables_,
- "const ::std::string $classname$::_default_$name$_($default$);");
+ "const ::std::string $classname$::_default_$name$_;");
} else {
printer->Print(variables_,
- "const ::std::string $classname$::_default_$name$_;");
+ "const ::std::string $classname$::_default_$name$_($default$);");
}
}
void StringFieldGenerator::
GenerateClearingCode(io::Printer* printer) const {
- if (descriptor_->has_default_value()) {
+ if (descriptor_->default_value_string().empty()) {
printer->Print(variables_,
"if ($name$_ != &_default_$name$_) {\n"
- " $name$_->assign(_default_$name$_);\n"
+ " $name$_->clear();\n"
"}\n");
} else {
printer->Print(variables_,
"if ($name$_ != &_default_$name$_) {\n"
- " $name$_->clear();\n"
+ " $name$_->assign(_default_$name$_);\n"
"}\n");
}
}
@@ -208,6 +208,11 @@ GenerateMergingCode(io::Printer* printer) const {
}
void StringFieldGenerator::
+GenerateSwappingCode(io::Printer* printer) const {
+ printer->Print(variables_, "std::swap($name$_, other->$name$_);\n");
+}
+
+void StringFieldGenerator::
GenerateInitializer(io::Printer* printer) const {
printer->Print(variables_,
",\n$name$_(const_cast< ::std::string*>(&_default_$name$_))");
@@ -350,6 +355,11 @@ GenerateMergingCode(io::Printer* printer) const {
}
void RepeatedStringFieldGenerator::
+GenerateSwappingCode(io::Printer* printer) const {
+ printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n");
+}
+
+void RepeatedStringFieldGenerator::
GenerateInitializer(io::Printer* printer) const {
// Not needed for repeated fields.
}
diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.h b/src/google/protobuf/compiler/cpp/cpp_string_field.h
index a0e5dce9..2244bd77 100644
--- a/src/google/protobuf/compiler/cpp/cpp_string_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_string_field.h
@@ -56,6 +56,7 @@ class StringFieldGenerator : public FieldGenerator {
void GenerateNonInlineAccessorDefinitions(io::Printer* printer) const;
void GenerateClearingCode(io::Printer* printer) const;
void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateSwappingCode(io::Printer* printer) const;
void GenerateInitializer(io::Printer* printer) const;
void GenerateDestructorCode(io::Printer* printer) const;
void GenerateMergeFromCodedStream(io::Printer* printer) const;
@@ -80,6 +81,7 @@ class RepeatedStringFieldGenerator : public FieldGenerator {
void GenerateInlineAccessorDefinitions(io::Printer* printer) const;
void GenerateClearingCode(io::Printer* printer) const;
void GenerateMergingCode(io::Printer* printer) const;
+ void GenerateSwappingCode(io::Printer* printer) const;
void GenerateInitializer(io::Printer* printer) const;
void GenerateMergeFromCodedStream(io::Printer* printer) const;
void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
index ce7d0c88..393c923b 100644
--- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
@@ -236,6 +236,83 @@ TEST(GeneratedMessageTest, CopyFrom) {
TestUtil::ExpectAllFieldsSet(message2);
}
+TEST(GeneratedMessageTest, SwapWithEmpty) {
+ unittest::TestAllTypes message1, message2;
+ TestUtil::SetAllFields(&message1);
+
+ TestUtil::ExpectAllFieldsSet(message1);
+ TestUtil::ExpectClear(message2);
+ message1.Swap(&message2);
+ TestUtil::ExpectAllFieldsSet(message2);
+ TestUtil::ExpectClear(message1);
+}
+
+TEST(GeneratedMessageTest, SwapWithSelf) {
+ unittest::TestAllTypes message;
+ TestUtil::SetAllFields(&message);
+ TestUtil::ExpectAllFieldsSet(message);
+ message.Swap(&message);
+ TestUtil::ExpectAllFieldsSet(message);
+}
+
+TEST(GeneratedMessageTest, SwapWithOther) {
+ unittest::TestAllTypes message1, message2;
+
+ message1.set_optional_int32(123);
+ message1.set_optional_string("abc");
+ message1.mutable_optional_nested_message()->set_bb(1);
+ message1.set_optional_nested_enum(unittest::TestAllTypes::FOO);
+ message1.add_repeated_int32(1);
+ message1.add_repeated_int32(2);
+ message1.add_repeated_string("a");
+ message1.add_repeated_string("b");
+ message1.add_repeated_nested_message()->set_bb(7);
+ message1.add_repeated_nested_message()->set_bb(8);
+ message1.add_repeated_nested_enum(unittest::TestAllTypes::FOO);
+ message1.add_repeated_nested_enum(unittest::TestAllTypes::BAR);
+
+ message2.set_optional_int32(456);
+ message2.set_optional_string("def");
+ message2.mutable_optional_nested_message()->set_bb(2);
+ message2.set_optional_nested_enum(unittest::TestAllTypes::BAR);
+ message2.add_repeated_int32(3);
+ message2.add_repeated_string("c");
+ message2.add_repeated_nested_message()->set_bb(9);
+ message2.add_repeated_nested_enum(unittest::TestAllTypes::BAZ);
+
+ message1.Swap(&message2);
+
+ EXPECT_EQ(456, message1.optional_int32());
+ EXPECT_EQ("def", message1.optional_string());
+ EXPECT_EQ(2, message1.optional_nested_message().bb());
+ EXPECT_EQ(unittest::TestAllTypes::BAR, message1.optional_nested_enum());
+ ASSERT_EQ(1, message1.repeated_int32_size());
+ EXPECT_EQ(3, message1.repeated_int32(0));
+ ASSERT_EQ(1, message1.repeated_string_size());
+ EXPECT_EQ("c", message1.repeated_string(0));
+ ASSERT_EQ(1, message1.repeated_nested_message_size());
+ EXPECT_EQ(9, message1.repeated_nested_message(0).bb());
+ ASSERT_EQ(1, message1.repeated_nested_enum_size());
+ EXPECT_EQ(unittest::TestAllTypes::BAZ, message1.repeated_nested_enum(0));
+
+ EXPECT_EQ(123, message2.optional_int32());
+ EXPECT_EQ("abc", message2.optional_string());
+ EXPECT_EQ(1, message2.optional_nested_message().bb());
+ EXPECT_EQ(unittest::TestAllTypes::FOO, message2.optional_nested_enum());
+ ASSERT_EQ(2, message2.repeated_int32_size());
+ EXPECT_EQ(1, message2.repeated_int32(0));
+ EXPECT_EQ(2, message2.repeated_int32(1));
+ ASSERT_EQ(2, message2.repeated_string_size());
+ EXPECT_EQ("a", message2.repeated_string(0));
+ EXPECT_EQ("b", message2.repeated_string(1));
+ ASSERT_EQ(2, message2.repeated_nested_message_size());
+ EXPECT_EQ(7, message2.repeated_nested_message(0).bb());
+ EXPECT_EQ(8, message2.repeated_nested_message(1).bb());
+ ASSERT_EQ(2, message2.repeated_nested_enum_size());
+ EXPECT_EQ(unittest::TestAllTypes::FOO, message2.repeated_nested_enum(0));
+ EXPECT_EQ(unittest::TestAllTypes::BAR, message2.repeated_nested_enum(1));
+}
+
TEST(GeneratedMessageTest, CopyConstructor) {
unittest::TestAllTypes message1;
TestUtil::SetAllFields(&message1);
@@ -492,6 +569,45 @@ TEST(GeneratedMessageTest, TestEmbedOptimizedForSize) {
EXPECT_EQ(2, message2.repeated_message(0).msg().c());
}
+TEST(GeneratedMessageTest, TestSpaceUsed) {
+ unittest::TestAllTypes message1;
+ // sizeof provides a lower bound on SpaceUsed().
+ EXPECT_LE(sizeof(unittest::TestAllTypes), message1.SpaceUsed());
+ const int empty_message_size = message1.SpaceUsed();
+
+ // Setting primitive types shouldn't affect the space used.
+ message1.set_optional_int32(123);
+ message1.set_optional_int64(12345);
+ message1.set_optional_uint32(123);
+ message1.set_optional_uint64(12345);
+ EXPECT_EQ(empty_message_size, message1.SpaceUsed());
+
+ // On some STL implementations, setting the string to a small value should
+ // only increase SpaceUsed() by the size of a string object, though this is
+ // not true everywhere.
+ message1.set_optional_string("abc");
+ EXPECT_LE(empty_message_size + sizeof(string), message1.SpaceUsed());
+
+ // Setting a string to a value larger than the string object itself should
+ // increase SpaceUsed(), because it cannot store the value internally.
+ message1.set_optional_string(string(sizeof(string) + 1, 'x'));
+ int min_expected_increase = message1.optional_string().capacity() +
+ sizeof(string);
+ EXPECT_LE(empty_message_size + min_expected_increase,
+ message1.SpaceUsed());
+
+ int previous_size = message1.SpaceUsed();
+ // Adding an optional message should increase the size by the size of the
+ // nested message type. NestedMessage is simple enough (1 int field) that it
+ // is equal to sizeof(NestedMessage)
+ message1.mutable_optional_nested_message();
+ ASSERT_EQ(sizeof(unittest::TestAllTypes::NestedMessage),
+ message1.optional_nested_message().SpaceUsed());
+ EXPECT_EQ(previous_size +
+ sizeof(unittest::TestAllTypes::NestedMessage),
+ message1.SpaceUsed());
+}
+
// ===================================================================
TEST(GeneratedEnumTest, EnumValuesAsSwitchCases) {
diff --git a/src/google/protobuf/compiler/parser.cc b/src/google/protobuf/compiler/parser.cc
index 1144aab7..e1c0d0d1 100644
--- a/src/google/protobuf/compiler/parser.cc
+++ b/src/google/protobuf/compiler/parser.cc
@@ -215,6 +215,11 @@ bool Parser::ConsumeString(string* output, const char* error) {
if (LookingAtType(io::Tokenizer::TYPE_STRING)) {
io::Tokenizer::ParseString(input_->current().text, output);
input_->Next();
+ // Allow C++ like concatenation of adjacent string tokens.
+ while (LookingAtType(io::Tokenizer::TYPE_STRING)) {
+ io::Tokenizer::ParseStringAppend(input_->current().text, output);
+ input_->Next();
+ }
return true;
} else {
AddError(error);
@@ -864,13 +869,24 @@ bool Parser::ParseEnumConstant(EnumValueDescriptorProto* enum_value) {
if (is_negative) number *= -1;
enum_value->set_number(number);
- // TODO(kenton): Options for enum values?
+ DO(ParseEnumConstantOptions(enum_value));
DO(Consume(";"));
return true;
}
+bool Parser::ParseEnumConstantOptions(EnumValueDescriptorProto* value) {
+ if (!TryConsume("[")) return true;
+
+ do {
+ DO(ParseOptionAssignment(value->mutable_options()));
+ } while (TryConsume(","));
+
+ DO(Consume("]"));
+ return true;
+}
+
// -------------------------------------------------------------------
// Services
diff --git a/src/google/protobuf/compiler/parser.h b/src/google/protobuf/compiler/parser.h
index e963c062..b670f740 100644
--- a/src/google/protobuf/compiler/parser.h
+++ b/src/google/protobuf/compiler/parser.h
@@ -236,6 +236,10 @@ class LIBPROTOBUF_EXPORT Parser {
// Parse a single enum value within an enum block.
bool ParseEnumConstant(EnumValueDescriptorProto* enum_value);
+ // Parse enum constant options, i.e. the list in square brackets at the end
+ // of the enum constant value definition.
+ bool ParseEnumConstantOptions(EnumValueDescriptorProto* value);
+
// Parse a single method within a service definition.
bool ParseServiceMethod(MethodDescriptorProto* method);
diff --git a/src/google/protobuf/compiler/parser_unittest.cc b/src/google/protobuf/compiler/parser_unittest.cc
index 15cdd896..2d48c5ae 100644
--- a/src/google/protobuf/compiler/parser_unittest.cc
+++ b/src/google/protobuf/compiler/parser_unittest.cc
@@ -305,7 +305,9 @@ TEST_F(ParseMessageTest, FieldDefaults) {
" required double foo = 1 [default=-11.5];\n"
" required double foo = 1 [default= 12 ];\n"
" required string foo = 1 [default='13\\001'];\n"
+ " required string foo = 1 [default='a' \"b\" \n \"c\"];\n"
" required bytes foo = 1 [default='14\\002'];\n"
+ " required bytes foo = 1 [default='a' \"b\" \n 'c'];\n"
" required bool foo = 1 [default=true ];\n"
" required Foo foo = 1 [default=FOO ];\n"
@@ -334,7 +336,9 @@ TEST_F(ParseMessageTest, FieldDefaults) {
" field { type:TYPE_DOUBLE default_value:\"-11.5\" "ETC" }"
" field { type:TYPE_DOUBLE default_value:\"12\" "ETC" }"
" field { type:TYPE_STRING default_value:\"13\\001\" "ETC" }"
+ " field { type:TYPE_STRING default_value:\"abc\" "ETC" }"
" field { type:TYPE_BYTES default_value:\"14\\\\002\" "ETC" }"
+ " field { type:TYPE_BYTES default_value:\"abc\" "ETC" }"
" field { type:TYPE_BOOL default_value:\"true\" "ETC" }"
" field { type_name:\"Foo\" default_value:\"FOO\" "ETC" }"
@@ -534,6 +538,40 @@ TEST_F(ParseEnumTest, Values) {
"}");
}
+TEST_F(ParseEnumTest, ValueOptions) {
+ ExpectParsesTo(
+ "enum TestEnum {\n"
+ " FOO = 13;\n"
+ " BAR = -10 [ (something.text) = 'abc' ];\n"
+ " BAZ = 500 [ (something.text) = 'def', other = 1 ];\n"
+ "}\n",
+
+ "enum_type {"
+ " name: \"TestEnum\""
+ " value { name: \"FOO\" number: 13 }"
+ " value { name: \"BAR\" number: -10 "
+ " options { "
+ " uninterpreted_option { "
+ " name { name_part: \"something.text\" is_extension: true } "
+ " string_value: \"abc\" "
+ " } "
+ " } "
+ " } "
+ " value { name: \"BAZ\" number: 500 "
+ " options { "
+ " uninterpreted_option { "
+ " name { name_part: \"something.text\" is_extension: true } "
+ " string_value: \"def\" "
+ " } "
+ " uninterpreted_option { "
+ " name { name_part: \"other\" is_extension: false } "
+ " positive_int_value: 1 "
+ " } "
+ " } "
+ " } "
+ "}");
+}
+
// ===================================================================
typedef ParserTest ParseServiceTest;