diff options
author | kenton@google.com <kenton@google.com@630680e5-0e50-0410-840e-4b1c322b438d> | 2008-11-21 00:06:27 +0000 |
---|---|---|
committer | kenton@google.com <kenton@google.com@630680e5-0e50-0410-840e-4b1c322b438d> | 2008-11-21 00:06:27 +0000 |
commit | 26bd9eee6ee6d116e1cc0dedeb660cd69d7aac45 (patch) | |
tree | d35cca89e0da44f136090a554ff9abc93a794fa8 /src/google/protobuf/compiler | |
parent | a2a32c20434807e9966e3f48375f9419134d1b55 (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.cc | 1 | ||||
-rw-r--r-- | src/google/protobuf/compiler/cpp/cpp_enum_field.cc | 10 | ||||
-rw-r--r-- | src/google/protobuf/compiler/cpp/cpp_enum_field.h | 2 | ||||
-rw-r--r-- | src/google/protobuf/compiler/cpp/cpp_field.h | 7 | ||||
-rw-r--r-- | src/google/protobuf/compiler/cpp/cpp_message.cc | 72 | ||||
-rw-r--r-- | src/google/protobuf/compiler/cpp/cpp_message.h | 1 | ||||
-rw-r--r-- | src/google/protobuf/compiler/cpp/cpp_message_field.cc | 10 | ||||
-rw-r--r-- | src/google/protobuf/compiler/cpp/cpp_message_field.h | 2 | ||||
-rw-r--r-- | src/google/protobuf/compiler/cpp/cpp_primitive_field.cc | 10 | ||||
-rw-r--r-- | src/google/protobuf/compiler/cpp/cpp_primitive_field.h | 2 | ||||
-rw-r--r-- | src/google/protobuf/compiler/cpp/cpp_string_field.cc | 28 | ||||
-rw-r--r-- | src/google/protobuf/compiler/cpp/cpp_string_field.h | 2 | ||||
-rw-r--r-- | src/google/protobuf/compiler/cpp/cpp_unittest.cc | 116 | ||||
-rw-r--r-- | src/google/protobuf/compiler/parser.cc | 18 | ||||
-rw-r--r-- | src/google/protobuf/compiler/parser.h | 4 | ||||
-rw-r--r-- | src/google/protobuf/compiler/parser_unittest.cc | 38 |
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; |