aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/google/protobuf/compiler/cpp
diff options
context:
space:
mode:
authorGravatar Feng Xiao <xfxyjwf@gmail.com>2014-11-14 11:50:31 -0800
committerGravatar Feng Xiao <xfxyjwf@gmail.com>2014-11-14 11:50:31 -0800
commitf157a5651c79a7a36e242af216a5d5b383ba8af2 (patch)
tree368bb0ca0e89ab7514302e4df00435a4ef461a28 /src/google/protobuf/compiler/cpp
parentfaf581d20866ad5e586b3e515f6c547d2dcec2c1 (diff)
Down-integrate from internal code base (C++ maps support).
Diffstat (limited to 'src/google/protobuf/compiler/cpp')
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_field.cc20
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_field.h2
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_file.cc26
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_file.h8
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_generator.cc4
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_helpers.cc19
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_helpers.h10
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_map_field.cc255
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_map_field.h75
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message.cc148
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message.h6
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_message_field.cc14
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc2
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_string_field.cc9
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_unittest.cc16
15 files changed, 553 insertions, 61 deletions
diff --git a/src/google/protobuf/compiler/cpp/cpp_field.cc b/src/google/protobuf/compiler/cpp/cpp_field.cc
index 85838ac3..43df1d88 100644
--- a/src/google/protobuf/compiler/cpp/cpp_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_field.cc
@@ -42,6 +42,7 @@
#include <google/protobuf/compiler/cpp/cpp_primitive_field.h>
#include <google/protobuf/compiler/cpp/cpp_string_field.h>
#include <google/protobuf/compiler/cpp/cpp_enum_field.h>
+#include <google/protobuf/compiler/cpp/cpp_map_field.h>
#include <google/protobuf/compiler/cpp/cpp_message_field.h>
#include <google/protobuf/descriptor.pb.h>
#include <google/protobuf/wire_format.h>
@@ -65,6 +66,12 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor,
(*variables)["classname"] = ClassName(FieldScope(descriptor), false);
(*variables)["declared_type"] = DeclaredTypeMethodName(descriptor->type());
+ // non_null_ptr_to_name is usable only if has_$name$ is true. It yields a
+ // pointer that will not be NULL. Subclasses of FieldGenerator may set
+ // (*variables)["non_null_ptr_to_name"] differently.
+ (*variables)["non_null_ptr_to_name"] =
+ StrCat("&this->", FieldName(descriptor), "()");
+
(*variables)["tag_size"] = SimpleItoa(
WireFormat::TagSize(descriptor->number(), descriptor->type()));
(*variables)["deprecation"] = descriptor->options().deprecated()
@@ -89,8 +96,11 @@ void SetCommonFieldVariables(const FieldDescriptor* descriptor,
void SetCommonOneofFieldVariables(const FieldDescriptor* descriptor,
map<string, string>* variables) {
- (*variables)["oneof_prefix"] = descriptor->containing_oneof()->name() + "_.";
+ const string prefix = descriptor->containing_oneof()->name() + "_.";
+ (*variables)["oneof_prefix"] = prefix;
(*variables)["oneof_name"] = descriptor->containing_oneof()->name();
+ (*variables)["non_null_ptr_to_name"] =
+ StrCat(prefix, (*variables)["name"], "_");
}
FieldGenerator::~FieldGenerator() {}
@@ -111,7 +121,7 @@ FieldGeneratorMap::FieldGeneratorMap(const Descriptor* descriptor,
const Options& options)
: descriptor_(descriptor),
field_generators_(
- new scoped_ptr<FieldGenerator>[descriptor->field_count()]) {
+ new google::protobuf::scoped_ptr<FieldGenerator>[descriptor->field_count()]) {
// Construct all the FieldGenerators.
for (int i = 0; i < descriptor->field_count(); i++) {
field_generators_[i].reset(MakeGenerator(descriptor->field(i), options));
@@ -123,7 +133,11 @@ FieldGenerator* FieldGeneratorMap::MakeGenerator(const FieldDescriptor* field,
if (field->is_repeated()) {
switch (field->cpp_type()) {
case FieldDescriptor::CPPTYPE_MESSAGE:
- return new RepeatedMessageFieldGenerator(field, options);
+ if (field->is_map()) {
+ return new MapFieldGenerator(field, options);
+ } else {
+ return new RepeatedMessageFieldGenerator(field, options);
+ }
case FieldDescriptor::CPPTYPE_STRING:
switch (field->options().ctype()) {
default: // RepeatedStringFieldGenerator handles unknown ctypes.
diff --git a/src/google/protobuf/compiler/cpp/cpp_field.h b/src/google/protobuf/compiler/cpp/cpp_field.h
index 088e5063..c37fe0be 100644
--- a/src/google/protobuf/compiler/cpp/cpp_field.h
+++ b/src/google/protobuf/compiler/cpp/cpp_field.h
@@ -182,7 +182,7 @@ class FieldGeneratorMap {
private:
const Descriptor* descriptor_;
- scoped_array<scoped_ptr<FieldGenerator> > field_generators_;
+ google::protobuf::scoped_array<google::protobuf::scoped_ptr<FieldGenerator> > field_generators_;
static FieldGenerator* MakeGenerator(const FieldDescriptor* field,
const Options& options);
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.cc b/src/google/protobuf/compiler/cpp/cpp_file.cc
index dc8bf613..8745577f 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_file.cc
@@ -59,13 +59,13 @@ namespace cpp {
FileGenerator::FileGenerator(const FileDescriptor* file, const Options& options)
: file_(file),
message_generators_(
- new scoped_ptr<MessageGenerator>[file->message_type_count()]),
+ new google::protobuf::scoped_ptr<MessageGenerator>[file->message_type_count()]),
enum_generators_(
- new scoped_ptr<EnumGenerator>[file->enum_type_count()]),
+ new google::protobuf::scoped_ptr<EnumGenerator>[file->enum_type_count()]),
service_generators_(
- new scoped_ptr<ServiceGenerator>[file->service_count()]),
+ new google::protobuf::scoped_ptr<ServiceGenerator>[file->service_count()]),
extension_generators_(
- new scoped_ptr<ExtensionGenerator>[file->extension_count()]),
+ new google::protobuf::scoped_ptr<ExtensionGenerator>[file->extension_count()]),
options_(options) {
for (int i = 0; i < file->message_type_count(); i++) {
@@ -151,6 +151,11 @@ void FileGenerator::GenerateHeader(io::Printer* printer) {
printer->Print(
"#include <google/protobuf/repeated_field.h>\n"
"#include <google/protobuf/extension_set.h>\n");
+ if (HasMapFields(file_)) {
+ printer->Print(
+ "#include <google/protobuf/map.h>\n"
+ "#include <google/protobuf/map_field_inl.h>\n");
+ }
if (HasDescriptorMethods(file_) && HasEnumDefinitions(file_)) {
printer->Print(
@@ -396,6 +401,19 @@ void FileGenerator::GenerateSource(io::Printer* printer) {
// Generate classes.
for (int i = 0; i < file_->message_type_count(); i++) {
+ if (i == 0 && HasGeneratedMethods(file_)) {
+ printer->Print(
+ "\n"
+ "namespace {\n"
+ "\n"
+ "static void MergeFromFail(int line) GOOGLE_ATTRIBUTE_COLD;\n"
+ "static void MergeFromFail(int line) {\n"
+ " GOOGLE_CHECK(false) << __FILE__ << \":\" << line;\n"
+ "}\n"
+ "\n"
+ "} // namespace\n"
+ "\n");
+ }
printer->Print("\n");
printer->Print(kThickSeparator);
printer->Print("\n");
diff --git a/src/google/protobuf/compiler/cpp/cpp_file.h b/src/google/protobuf/compiler/cpp/cpp_file.h
index 13d06f98..0e06547d 100644
--- a/src/google/protobuf/compiler/cpp/cpp_file.h
+++ b/src/google/protobuf/compiler/cpp/cpp_file.h
@@ -82,10 +82,10 @@ class FileGenerator {
const FileDescriptor* file_;
- scoped_array<scoped_ptr<MessageGenerator> > message_generators_;
- scoped_array<scoped_ptr<EnumGenerator> > enum_generators_;
- scoped_array<scoped_ptr<ServiceGenerator> > service_generators_;
- scoped_array<scoped_ptr<ExtensionGenerator> > extension_generators_;
+ google::protobuf::scoped_array<google::protobuf::scoped_ptr<MessageGenerator> > message_generators_;
+ google::protobuf::scoped_array<google::protobuf::scoped_ptr<EnumGenerator> > enum_generators_;
+ google::protobuf::scoped_array<google::protobuf::scoped_ptr<ServiceGenerator> > service_generators_;
+ google::protobuf::scoped_array<google::protobuf::scoped_ptr<ExtensionGenerator> > extension_generators_;
// E.g. if the package is foo.bar, package_parts_ is {"foo", "bar"}.
vector<string> package_parts_;
diff --git a/src/google/protobuf/compiler/cpp/cpp_generator.cc b/src/google/protobuf/compiler/cpp/cpp_generator.cc
index a2fb7162..c999b93f 100644
--- a/src/google/protobuf/compiler/cpp/cpp_generator.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_generator.cc
@@ -105,7 +105,7 @@ bool CppGenerator::Generate(const FileDescriptor* file,
// Generate header.
{
- scoped_ptr<io::ZeroCopyOutputStream> output(
+ google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
generator_context->Open(basename + ".h"));
io::Printer printer(output.get(), '$');
file_generator.GenerateHeader(&printer);
@@ -113,7 +113,7 @@ bool CppGenerator::Generate(const FileDescriptor* file,
// Generate cc file.
{
- scoped_ptr<io::ZeroCopyOutputStream> output(
+ google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
generator_context->Open(basename + ".cc"));
io::Printer printer(output.get(), '$');
file_generator.GenerateSource(&printer);
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.cc b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
index 63b0265e..28c4dd54 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.cc
@@ -453,6 +453,25 @@ void PrintHandlingOptionalStaticInitializers(
}
+static bool HasMapFields(const Descriptor* descriptor) {
+ for (int i = 0; i < descriptor->field_count(); ++i) {
+ if (descriptor->field(i)->is_map()) {
+ return true;
+ }
+ }
+ for (int i = 0; i < descriptor->nested_type_count(); ++i) {
+ if (HasMapFields(descriptor->nested_type(i))) return true;
+ }
+ return false;
+}
+
+bool HasMapFields(const FileDescriptor* file) {
+ for (int i = 0; i < file->message_type_count(); ++i) {
+ if (HasMapFields(file->message_type(i))) return true;
+ }
+ return false;
+}
+
static bool HasEnumDefinitions(const Descriptor* message_type) {
if (message_type->enum_type_count() > 0) return true;
for (int i = 0; i < message_type->nested_type_count(); ++i) {
diff --git a/src/google/protobuf/compiler/cpp/cpp_helpers.h b/src/google/protobuf/compiler/cpp/cpp_helpers.h
index 1cff17c8..e60fa7c2 100644
--- a/src/google/protobuf/compiler/cpp/cpp_helpers.h
+++ b/src/google/protobuf/compiler/cpp/cpp_helpers.h
@@ -149,6 +149,10 @@ inline bool UseUnknownFieldSet(const FileDescriptor* file) {
}
+// Does the file have any map fields, necessitating the file to include
+// map_field_inl.h and map.h.
+bool HasMapFields(const FileDescriptor* file);
+
// Does this file have any enum type definitions?
bool HasEnumDefinitions(const FileDescriptor* file);
@@ -200,6 +204,10 @@ void PrintHandlingOptionalStaticInitializers(
const char* without_static_init);
+inline bool IsMapEntryMessage(const Descriptor* descriptor) {
+ return descriptor->options().map_entry();
+}
+
// Returns true if the field's CPPTYPE is string or message.
bool IsStringOrMessage(const FieldDescriptor* field);
@@ -216,7 +224,7 @@ inline bool HasPreservingUnknownEnumSemantics(const FileDescriptor* file) {
}
inline bool SupportsArenas(const FileDescriptor* file) {
- return true;
+ return file->options().cc_enable_arenas();
}
inline bool SupportsArenas(const Descriptor* desc) {
diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.cc b/src/google/protobuf/compiler/cpp/cpp_map_field.cc
new file mode 100644
index 00000000..0154eeb8
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_map_field.cc
@@ -0,0 +1,255 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include <google/protobuf/compiler/cpp/cpp_map_field.h>
+#include <google/protobuf/compiler/cpp/cpp_helpers.h>
+#include <google/protobuf/io/printer.h>
+#include <google/protobuf/stubs/strutil.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+bool IsProto3Field(const FieldDescriptor* field_descriptor) {
+ const FileDescriptor* file_descriptor = field_descriptor->file();
+ return file_descriptor->syntax() == FileDescriptor::SYNTAX_PROTO3;
+}
+
+void SetMessageVariables(const FieldDescriptor* descriptor,
+ map<string, string>* variables,
+ const Options& options) {
+ SetCommonFieldVariables(descriptor, variables, options);
+ (*variables)["type"] = FieldMessageTypeName(descriptor);
+ (*variables)["stream_writer"] = (*variables)["declared_type"] +
+ (HasFastArraySerialization(descriptor->message_type()->file()) ?
+ "MaybeToArray" :
+ "");
+ (*variables)["full_name"] = descriptor->full_name();
+
+ const FieldDescriptor* key =
+ descriptor->message_type()->FindFieldByName("key");
+ const FieldDescriptor* val =
+ descriptor->message_type()->FindFieldByName("value");
+ (*variables)["key_cpp"] = PrimitiveTypeName(key->cpp_type());
+ switch (val->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ (*variables)["val_cpp"] = FieldMessageTypeName(val);
+ (*variables)["wrapper"] = "EntryWrapper";
+ break;
+ case FieldDescriptor::CPPTYPE_ENUM:
+ (*variables)["val_cpp"] = ClassName(val->enum_type(), false);
+ (*variables)["wrapper"] = "EnumEntryWrapper";
+ break;
+ default:
+ (*variables)["val_cpp"] = PrimitiveTypeName(val->cpp_type());
+ (*variables)["wrapper"] = "EntryWrapper";
+ }
+ (*variables)["key_type"] =
+ "::google::protobuf::FieldDescriptor::TYPE_" +
+ ToUpper(DeclaredTypeMethodName(key->type()));
+ (*variables)["val_type"] =
+ "::google::protobuf::FieldDescriptor::TYPE_" +
+ ToUpper(DeclaredTypeMethodName(val->type()));
+ (*variables)["map_classname"] = ClassName(descriptor->message_type(), false);
+ (*variables)["number"] = Int32ToString(descriptor->number());
+
+ if (!IsProto3Field(descriptor) &&
+ val->type() == FieldDescriptor::TYPE_ENUM) {
+ const EnumValueDescriptor* default_value = val->default_value_enum();
+ (*variables)["default_enum_value"] = Int32ToString(default_value->number());
+ } else {
+ (*variables)["default_enum_value"] = "0";
+ }
+}
+
+MapFieldGenerator::
+MapFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options)
+ : descriptor_(descriptor) {
+ SetMessageVariables(descriptor, &variables_, options);
+}
+
+MapFieldGenerator::~MapFieldGenerator() {}
+
+void MapFieldGenerator::
+GeneratePrivateMembers(io::Printer* printer) const {
+ printer->Print(variables_,
+ "typedef ::google::protobuf::internal::MapEntry<\n"
+ " $key_cpp$, $val_cpp$,\n"
+ " $key_type$,\n"
+ " $val_type$, $default_enum_value$>\n"
+ " $map_classname$;\n"
+ "::google::protobuf::internal::MapField< $key_cpp$, $val_cpp$,"
+ "$key_type$, $val_type$, $default_enum_value$ > $name$_;\n");
+}
+
+void MapFieldGenerator::
+GenerateAccessorDeclarations(io::Printer* printer) const {
+ printer->Print(variables_,
+ "inline const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n"
+ " $name$() const$deprecation$;\n"
+ "inline ::google::protobuf::Map< $key_cpp$, $val_cpp$ >*\n"
+ " mutable_$name$()$deprecation$;\n");
+}
+
+void MapFieldGenerator::
+GenerateInlineAccessorDefinitions(io::Printer* printer) const {
+ printer->Print(variables_,
+ "inline const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n"
+ "$classname$::$name$() const {\n"
+ " // @@protoc_insertion_point(field_map:$full_name$)\n"
+ " return $name$_.GetMap();\n"
+ "}\n"
+ "inline ::google::protobuf::Map< $key_cpp$, $val_cpp$ >*\n"
+ "$classname$::mutable_$name$() {\n"
+ " // @@protoc_insertion_point(field_mutable_map:$full_name$)\n"
+ " return $name$_.MutableMap();\n"
+ "}\n");
+}
+
+void MapFieldGenerator::
+GenerateClearingCode(io::Printer* printer) const {
+ printer->Print(variables_, "$name$_.Clear();\n");
+}
+
+void MapFieldGenerator::
+GenerateMergingCode(io::Printer* printer) const {
+ printer->Print(variables_, "$name$_.MergeFrom(from.$name$_);\n");
+}
+
+void MapFieldGenerator::
+GenerateSwappingCode(io::Printer* printer) const {
+ printer->Print(variables_, "$name$_.Swap(&other->$name$_);\n");
+}
+
+void MapFieldGenerator::
+GenerateConstructorCode(io::Printer* printer) const {
+ if (HasDescriptorMethods(descriptor_->file())) {
+ printer->Print(variables_,
+ "$name$_.SetAssignDescriptorCallback(\n"
+ " protobuf_AssignDescriptorsOnce);\n"
+ "$name$_.SetEntryDescriptor(\n"
+ " &$type$_descriptor_);\n");
+ }
+}
+
+void MapFieldGenerator::
+GenerateMergeFromCodedStream(io::Printer* printer) const {
+ const FieldDescriptor* value_field =
+ descriptor_->message_type()->FindFieldByName("value");
+ printer->Print(variables_,
+ "::google::protobuf::scoped_ptr<$map_classname$> entry($name$_.NewEntry());\n");
+
+ if (IsProto3Field(descriptor_) ||
+ value_field->type() != FieldDescriptor::TYPE_ENUM) {
+ printer->Print(variables_,
+ "DO_(::google::protobuf::internal::WireFormatLite::ReadMessageNoVirtual(\n"
+ " input, entry.get()));\n");
+ switch (value_field->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ printer->Print(variables_,
+ "(*mutable_$name$())[entry->key()].Swap("
+ "entry->mutable_value());\n");
+ break;
+ case FieldDescriptor::CPPTYPE_ENUM:
+ printer->Print(variables_,
+ "(*mutable_$name$())[entry->key()] =\n"
+ " static_cast<$val_cpp$>(*entry->mutable_value());\n");
+ break;
+ default:
+ printer->Print(variables_,
+ "(*mutable_$name$())[entry->key()] = *entry->mutable_value();\n");
+ break;
+ }
+ } else {
+ printer->Print(variables_,
+ "{\n"
+ " ::std::string data;\n"
+ " DO_(::google::protobuf::internal::WireFormatLite::ReadString(input, &data));\n"
+ " DO_(entry->ParseFromString(data));\n"
+ " if ($val_cpp$_IsValid(*entry->mutable_value())) {\n"
+ " (*mutable_$name$())[entry->key()] =\n"
+ " static_cast<$val_cpp$>(*entry->mutable_value());\n"
+ " } else {\n"
+ " mutable_unknown_fields()->AddLengthDelimited($number$, data);\n"
+ " }\n"
+ "}\n");
+ }
+}
+
+void MapFieldGenerator::
+GenerateSerializeWithCachedSizes(io::Printer* printer) const {
+ printer->Print(variables_,
+ "{\n"
+ " ::google::protobuf::scoped_ptr<$map_classname$> entry;\n"
+ " for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
+ " it = $name$().begin(); it != $name$().end(); ++it) {\n"
+ " entry.reset($name$_.New$wrapper$(it->first, it->second));\n"
+ " ::google::protobuf::internal::WireFormatLite::Write$stream_writer$(\n"
+ " $number$, *entry, output);\n"
+ " }\n"
+ "}\n");
+}
+
+void MapFieldGenerator::
+GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
+ printer->Print(variables_,
+ "{\n"
+ " ::google::protobuf::scoped_ptr<$map_classname$> entry;\n"
+ " for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
+ " it = $name$().begin(); it != $name$().end(); ++it) {\n"
+ " entry.reset($name$_.New$wrapper$(it->first, it->second));\n"
+ " target = ::google::protobuf::internal::WireFormatLite::\n"
+ " Write$declared_type$NoVirtualToArray(\n"
+ " $number$, *entry, target);\n"
+ " }\n"
+ "}\n");
+}
+
+void MapFieldGenerator::
+GenerateByteSize(io::Printer* printer) const {
+ printer->Print(variables_,
+ "total_size += $tag_size$ * this->$name$_size();\n"
+ "{\n"
+ " ::google::protobuf::scoped_ptr<$map_classname$> entry;\n"
+ " for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
+ " it = $name$().begin(); it != $name$().end(); ++it) {\n"
+ " entry.reset($name$_.New$wrapper$(it->first, it->second));\n"
+ " total_size += ::google::protobuf::internal::WireFormatLite::\n"
+ " $declared_type$SizeNoVirtual(*entry);\n"
+ " }\n"
+ "}\n");
+}
+
+} // namespace cpp
+} // namespace compiler
+} // namespace protobuf
+} // namespace google
diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.h b/src/google/protobuf/compiler/cpp/cpp_map_field.h
new file mode 100644
index 00000000..0ff032fd
--- /dev/null
+++ b/src/google/protobuf/compiler/cpp/cpp_map_field.h
@@ -0,0 +1,75 @@
+// Protocol Buffers - Google's data interchange format
+// Copyright 2008 Google Inc. All rights reserved.
+// https://developers.google.com/protocol-buffers/
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_MAP_FIELD_H__
+#define GOOGLE_PROTOBUF_COMPILER_CPP_MAP_FIELD_H__
+
+#include <map>
+#include <string>
+
+#include <google/protobuf/compiler/cpp/cpp_message_field.h>
+
+namespace google {
+namespace protobuf {
+namespace compiler {
+namespace cpp {
+
+class MapFieldGenerator : public FieldGenerator {
+ public:
+ explicit MapFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options);
+ ~MapFieldGenerator();
+
+ // implements FieldGenerator ---------------------------------------
+ void GeneratePrivateMembers(io::Printer* printer) const;
+ void GenerateAccessorDeclarations(io::Printer* printer) const;
+ 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 GenerateConstructorCode(io::Printer* printer) const;
+ void GenerateMergeFromCodedStream(io::Printer* printer) const;
+ void GenerateSerializeWithCachedSizes(io::Printer* printer) const;
+ void GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const;
+ void GenerateByteSize(io::Printer* printer) const;
+
+ private:
+ const FieldDescriptor* descriptor_;
+ map<string, string> variables_;
+
+ GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapFieldGenerator);
+};
+
+} // namespace cpp
+} // namespace compiler
+} // namespace protobuf
+
+} // namespace google
+#endif // GOOGLE_PROTOBUF_COMPILER_CPP_MAP_FIELD_H__
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.cc b/src/google/protobuf/compiler/cpp/cpp_message.cc
index 54a92ae4..28ee3a9d 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message.cc
@@ -334,6 +334,31 @@ bool HasHasMethod(const FieldDescriptor* field) {
return field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE;
}
+// Collects map entry message type information.
+void CollectMapInfo(const Descriptor* descriptor,
+ map<string, string>* variables) {
+ GOOGLE_CHECK(IsMapEntryMessage(descriptor));
+ const FieldDescriptor* key = descriptor->FindFieldByName("key");
+ const FieldDescriptor* val = descriptor->FindFieldByName("value");
+ (*variables)["key"] = PrimitiveTypeName(key->cpp_type());
+ switch (val->cpp_type()) {
+ case FieldDescriptor::CPPTYPE_MESSAGE:
+ (*variables)["val"] = FieldMessageTypeName(val);
+ break;
+ case FieldDescriptor::CPPTYPE_ENUM:
+ (*variables)["val"] = ClassName(val->enum_type(), false);
+ break;
+ default:
+ (*variables)["val"] = PrimitiveTypeName(val->cpp_type());
+ }
+ (*variables)["key_type"] =
+ "::google::protobuf::FieldDescriptor::TYPE_" +
+ ToUpper(DeclaredTypeMethodName(key->type()));
+ (*variables)["val_type"] =
+ "::google::protobuf::FieldDescriptor::TYPE_" +
+ ToUpper(DeclaredTypeMethodName(val->type()));
+}
+
// Does the given field have a private (internal helper only) has_$name$()
// method?
bool HasPrivateHasMethod(const FieldDescriptor* field) {
@@ -353,11 +378,11 @@ MessageGenerator::MessageGenerator(const Descriptor* descriptor,
classname_(ClassName(descriptor, false)),
options_(options),
field_generators_(descriptor, options),
- nested_generators_(new scoped_ptr<
+ nested_generators_(new google::protobuf::scoped_ptr<
MessageGenerator>[descriptor->nested_type_count()]),
enum_generators_(
- new scoped_ptr<EnumGenerator>[descriptor->enum_type_count()]),
- extension_generators_(new scoped_ptr<
+ new google::protobuf::scoped_ptr<EnumGenerator>[descriptor->enum_type_count()]),
+ extension_generators_(new google::protobuf::scoped_ptr<
ExtensionGenerator>[descriptor->extension_count()]) {
for (int i = 0; i < descriptor->nested_type_count(); i++) {
@@ -391,6 +416,10 @@ GenerateForwardDeclaration(io::Printer* printer) {
"classname", classname_);
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ // map entry message doesn't need forward declaration. Since map entry
+ // message cannot be a top level class, we just need to avoid calling
+ // GenerateForwardDeclaration here.
+ if (IsMapEntryMessage(descriptor_->nested_type(i))) continue;
nested_generators_[i]->GenerateForwardDeclaration(printer);
}
}
@@ -622,6 +651,10 @@ static bool CanClearByZeroing(const FieldDescriptor* field) {
void MessageGenerator::
GenerateClassDefinition(io::Printer* printer) {
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ // map entry message doesn't need class definition. Since map entry message
+ // cannot be a top level class, we just need to avoid calling
+ // GenerateClassDefinition here.
+ if (IsMapEntryMessage(descriptor_->nested_type(i))) continue;
nested_generators_[i]->GenerateClassDefinition(printer);
printer->Print("\n");
printer->Print(kThinSeparator);
@@ -876,9 +909,11 @@ GenerateClassDefinition(io::Printer* printer) {
// Import all nested message classes into this class's scope with typedefs.
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
const Descriptor* nested_type = descriptor_->nested_type(i);
- printer->Print("typedef $nested_full_name$ $nested_name$;\n",
- "nested_name", nested_type->name(),
- "nested_full_name", ClassName(nested_type, false));
+ if (!IsMapEntryMessage(nested_type)) {
+ printer->Print("typedef $nested_full_name$ $nested_name$;\n",
+ "nested_name", nested_type->name(),
+ "nested_full_name", ClassName(nested_type, false));
+ }
}
if (descriptor_->nested_type_count() > 0) {
@@ -1124,6 +1159,10 @@ GenerateClassDefinition(io::Printer* printer) {
void MessageGenerator::
GenerateInlineMethods(io::Printer* printer) {
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ // map entry message doesn't need inline methods. Since map entry message
+ // cannot be a top level class, we just need to avoid calling
+ // GenerateInlineMethods here.
+ if (IsMapEntryMessage(descriptor_->nested_type(i))) continue;
nested_generators_[i]->GenerateInlineMethods(printer);
printer->Print(kThinSeparator);
printer->Print("\n");
@@ -1151,11 +1190,17 @@ GenerateInlineMethods(io::Printer* printer) {
void MessageGenerator::
GenerateDescriptorDeclarations(io::Printer* printer) {
- printer->Print(
- "const ::google::protobuf::Descriptor* $name$_descriptor_ = NULL;\n"
- "const ::google::protobuf::internal::GeneratedMessageReflection*\n"
- " $name$_reflection_ = NULL;\n",
- "name", classname_);
+ if (!IsMapEntryMessage(descriptor_)) {
+ printer->Print(
+ "const ::google::protobuf::Descriptor* $name$_descriptor_ = NULL;\n"
+ "const ::google::protobuf::internal::GeneratedMessageReflection*\n"
+ " $name$_reflection_ = NULL;\n",
+ "name", classname_);
+ } else {
+ printer->Print(
+ "const ::google::protobuf::Descriptor* $name$_descriptor_ = NULL;\n",
+ "name", classname_);
+ }
// Generate oneof default instance for reflection usage.
if (descriptor_->oneof_decl_count() > 0) {
@@ -1206,13 +1251,20 @@ GenerateDescriptorInitializer(io::Printer* printer, int index) {
"$parent$_descriptor_->nested_type($index$);\n");
}
+ if (IsMapEntryMessage(descriptor_)) return;
+
// Generate the offsets.
GenerateOffsets(printer);
+ const bool pass_pool_and_factory = false;
+ vars["fn"] = pass_pool_and_factory ?
+ "new ::google::protobuf::internal::GeneratedMessageReflection" :
+ "::google::protobuf::internal::GeneratedMessageReflection"
+ "::NewGeneratedMessageReflection";
// Construct the reflection object.
printer->Print(vars,
"$classname$_reflection_ =\n"
- " new ::google::protobuf::internal::GeneratedMessageReflection(\n"
+ " $fn$(\n"
" $classname$_descriptor_,\n"
" $classname$::default_instance_,\n"
" $classname$_offsets_,\n");
@@ -1254,10 +1306,12 @@ GenerateDescriptorInitializer(io::Printer* printer, int index) {
"$classname$, _oneof_case_[0]),\n");
}
- printer->Print(
- " ::google::protobuf::DescriptorPool::generated_pool(),\n");
- printer->Print(vars,
- " ::google::protobuf::MessageFactory::generated_factory(),\n");
+ if (pass_pool_and_factory) {
+ printer->Print(
+ " ::google::protobuf::DescriptorPool::generated_pool(),\n");
+ printer->Print(vars,
+ " ::google::protobuf::MessageFactory::generated_factory(),\n");
+ }
printer->Print(vars,
" sizeof($classname$),\n");
@@ -1289,10 +1343,37 @@ GenerateDescriptorInitializer(io::Printer* printer, int index) {
void MessageGenerator::
GenerateTypeRegistrations(io::Printer* printer) {
// Register this message type with the message factory.
- printer->Print(
- "::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(\n"
- " $classname$_descriptor_, &$classname$::default_instance());\n",
- "classname", classname_);
+ if (!IsMapEntryMessage(descriptor_)) {
+ printer->Print(
+ "::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(\n"
+ " $classname$_descriptor_, &$classname$::default_instance());\n",
+ "classname", classname_);
+ }
+ else {
+ map<string, string> vars;
+ CollectMapInfo(descriptor_, &vars);
+ vars["classname"] = classname_;
+
+ const FieldDescriptor* val = descriptor_->FindFieldByName("value");
+ if (descriptor_->file()->syntax() == FileDescriptor::SYNTAX_PROTO2 &&
+ val->type() == FieldDescriptor::TYPE_ENUM) {
+ const EnumValueDescriptor* default_value = val->default_value_enum();
+ vars["default_enum_value"] = Int32ToString(default_value->number());
+ } else {
+ vars["default_enum_value"] = "0";
+ }
+
+ printer->Print(vars,
+ "::google::protobuf::MessageFactory::InternalRegisterGeneratedMessage(\n"
+ " $classname$_descriptor_,\n"
+ " ::google::protobuf::internal::MapEntry<\n"
+ " $key$,\n"
+ " $val$,\n"
+ " $key_type$,\n"
+ " $val_type$,\n"
+ " $default_enum_value$>::CreateDefaultInstance(\n"
+ " $classname$_descriptor_));\n");
+ }
// Handle nested types.
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
@@ -1309,6 +1390,8 @@ GenerateDefaultInstanceAllocator(io::Printer* printer) {
.GenerateDefaultInstanceAllocator(printer);
}
+ if (IsMapEntryMessage(descriptor_)) return;
+
// Construct the default instance. We can't call InitAsDefaultInstance() yet
// because we need to make sure all default instances that this one might
// depend on are constructed first.
@@ -1343,6 +1426,10 @@ GenerateDefaultInstanceInitializer(io::Printer* printer) {
// Handle nested types.
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ // map entry message doesn't need to initialize default instance manually.
+ // Since map entry message cannot be a top level class, we just need to
+ // avoid calling DefaultInstanceInitializer here.
+ if (IsMapEntryMessage(descriptor_->nested_type(i))) continue;
nested_generators_[i]->GenerateDefaultInstanceInitializer(printer);
}
}
@@ -1372,6 +1459,7 @@ GenerateShutdownCode(io::Printer* printer) {
// Handle nested types.
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ if (IsMapEntryMessage(descriptor_->nested_type(i))) continue;
nested_generators_[i]->GenerateShutdownCode(printer);
}
}
@@ -1383,6 +1471,10 @@ GenerateClassMethods(io::Printer* printer) {
}
for (int i = 0; i < descriptor_->nested_type_count(); i++) {
+ // map entry message doesn't need class methods. Since map entry message
+ // cannot be a top level class, we just need to avoid calling
+ // GenerateClassMethods here.
+ if (IsMapEntryMessage(descriptor_->nested_type(i))) continue;
nested_generators_[i]->GenerateClassMethods(printer);
printer->Print("\n");
printer->Print(kThinSeparator);
@@ -2195,7 +2287,7 @@ GenerateMergeFrom(io::Printer* printer) {
// base class as a parameter).
printer->Print(
"void $classname$::MergeFrom(const ::google::protobuf::Message& from) {\n"
- " GOOGLE_CHECK_NE(&from, this);\n",
+ " if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);\n",
"classname", classname_);
printer->Indent();
@@ -2230,7 +2322,7 @@ GenerateMergeFrom(io::Printer* printer) {
// Generate the class-specific MergeFrom, which avoids the GOOGLE_CHECK and cast.
printer->Print(
"void $classname$::MergeFrom(const $classname$& from) {\n"
- " GOOGLE_CHECK_NE(&from, this);\n",
+ " if (GOOGLE_PREDICT_FALSE(&from == this)) MergeFromFail(__LINE__);\n",
"classname", classname_);
printer->Indent();
@@ -2429,7 +2521,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) {
printer->Print("for (;;) {\n");
printer->Indent();
- scoped_array<const FieldDescriptor*> ordered_fields(
+ google::protobuf::scoped_array<const FieldDescriptor * > ordered_fields(
SortFieldsByNumber(descriptor_));
uint32 maxtag = descriptor_->field_count() == 0 ? 0 :
WireFormat::MakeTag(ordered_fields[descriptor_->field_count() - 1]);
@@ -2788,7 +2880,7 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) {
void MessageGenerator::
GenerateSerializeWithCachedSizesBody(io::Printer* printer, bool to_array) {
- scoped_array<const FieldDescriptor*> ordered_fields(
+ google::protobuf::scoped_array<const FieldDescriptor * > ordered_fields(
SortFieldsByNumber(descriptor_));
vector<const Descriptor::ExtensionRange*> sorted_extensions;
@@ -3186,14 +3278,14 @@ GenerateIsInitialized(io::Printer* printer) {
" return false;\n",
"name", FieldName(field));
} else {
- if (field->options().weak()) {
+ if (field->options().weak() || !field->containing_oneof()) {
// For weak fields, use the data member (::google::protobuf::Message*) instead
// of the getter to avoid a link dependency on the weak message type
// which is only forward declared.
printer->Print(
- "if (has_$name$()) {\n"
- " if (!this->$name$_->IsInitialized()) return false;\n"
- "}\n",
+ "if (has_$name$()) {\n"
+ " if (!this->$name$_->IsInitialized()) return false;\n"
+ "}\n",
"name", FieldName(field));
} else {
printer->Print(
diff --git a/src/google/protobuf/compiler/cpp/cpp_message.h b/src/google/protobuf/compiler/cpp/cpp_message.h
index a781c234..dfbc9af5 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message.h
+++ b/src/google/protobuf/compiler/cpp/cpp_message.h
@@ -163,9 +163,9 @@ class MessageGenerator {
Options options_;
FieldGeneratorMap field_generators_;
vector< vector<string> > runs_of_fields_; // that might be trivially cleared
- scoped_array<scoped_ptr<MessageGenerator> > nested_generators_;
- scoped_array<scoped_ptr<EnumGenerator> > enum_generators_;
- scoped_array<scoped_ptr<ExtensionGenerator> > extension_generators_;
+ google::protobuf::scoped_array<google::protobuf::scoped_ptr<MessageGenerator> > nested_generators_;
+ google::protobuf::scoped_array<google::protobuf::scoped_ptr<EnumGenerator> > enum_generators_;
+ google::protobuf::scoped_array<google::protobuf::scoped_ptr<ExtensionGenerator> > extension_generators_;
int num_required_fields_;
bool uses_string_;
diff --git a/src/google/protobuf/compiler/cpp/cpp_message_field.cc b/src/google/protobuf/compiler/cpp/cpp_message_field.cc
index da1ec60b..b3cd0ba1 100644
--- a/src/google/protobuf/compiler/cpp/cpp_message_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_message_field.cc
@@ -49,6 +49,10 @@ void SetMessageVariables(const FieldDescriptor* descriptor,
const Options& options) {
SetCommonFieldVariables(descriptor, variables, options);
(*variables)["type"] = FieldMessageTypeName(descriptor);
+ if (descriptor->options().weak() || !descriptor->containing_oneof()) {
+ (*variables)["non_null_ptr_to_name"] =
+ StrCat("this->", (*variables)["name"], "_");
+ }
(*variables)["stream_writer"] = (*variables)["declared_type"] +
(HasFastArraySerialization(descriptor->message_type()->file()) ?
"MaybeToArray" :
@@ -293,7 +297,7 @@ void MessageFieldGenerator::
GenerateSerializeWithCachedSizes(io::Printer* printer) const {
printer->Print(variables_,
"::google::protobuf::internal::WireFormatLite::Write$stream_writer$(\n"
- " $number$, this->$name$(), output);\n");
+ " $number$, *$non_null_ptr_to_name$, output);\n");
}
void MessageFieldGenerator::
@@ -301,7 +305,7 @@ GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
printer->Print(variables_,
"target = ::google::protobuf::internal::WireFormatLite::\n"
" Write$declared_type$NoVirtualToArray(\n"
- " $number$, this->$name$(), target);\n");
+ " $number$, *$non_null_ptr_to_name$, target);\n");
}
void MessageFieldGenerator::
@@ -309,7 +313,7 @@ GenerateByteSize(io::Printer* printer) const {
printer->Print(variables_,
"total_size += $tag_size$ +\n"
" ::google::protobuf::internal::WireFormatLite::$declared_type$SizeNoVirtual(\n"
- " this->$name$());\n");
+ " *$non_null_ptr_to_name$);\n");
}
// ===================================================================
@@ -591,7 +595,7 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
void RepeatedMessageFieldGenerator::
GenerateSerializeWithCachedSizes(io::Printer* printer) const {
printer->Print(variables_,
- "for (int i = 0; i < this->$name$_size(); i++) {\n"
+ "for (unsigned int i = 0, n = this->$name$_size(); i < n; i++) {\n"
" ::google::protobuf::internal::WireFormatLite::Write$stream_writer$(\n"
" $number$, this->$name$(i), output);\n"
"}\n");
@@ -600,7 +604,7 @@ GenerateSerializeWithCachedSizes(io::Printer* printer) const {
void RepeatedMessageFieldGenerator::
GenerateSerializeWithCachedSizesToArray(io::Printer* printer) const {
printer->Print(variables_,
- "for (int i = 0; i < this->$name$_size(); i++) {\n"
+ "for (unsigned int i = 0, n = this->$name$_size(); i < n; i++) {\n"
" target = ::google::protobuf::internal::WireFormatLite::\n"
" Write$declared_type$NoVirtualToArray(\n"
" $number$, this->$name$(i), target);\n"
diff --git a/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc
index 26cefb2e..d1efbfe6 100644
--- a/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_plugin_unittest.cc
@@ -171,7 +171,7 @@ class TestGenerator : public CodeGenerator {
void TryInsert(const string& filename, const string& insertion_point,
GeneratorContext* context) const {
- scoped_ptr<io::ZeroCopyOutputStream> output(
+ google::protobuf::scoped_ptr<io::ZeroCopyOutputStream> output(
context->OpenForInsert(filename, insertion_point));
io::Printer printer(output.get(), '$');
printer.Print("// inserted $name$\n", "name", insertion_point);
diff --git a/src/google/protobuf/compiler/cpp/cpp_string_field.cc b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
index a2a8c81c..a7f95044 100644
--- a/src/google/protobuf/compiler/cpp/cpp_string_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_string_field.cc
@@ -306,7 +306,14 @@ GenerateClearingCode(io::Printer* printer) const {
void StringFieldGenerator::
GenerateMergingCode(io::Printer* printer) const {
- printer->Print(variables_, "set_$name$(from.$name$());\n");
+ if (SupportsArenas(descriptor_) || descriptor_->containing_oneof() != NULL) {
+ // TODO(gpike): improve this
+ printer->Print(variables_, "set_$name$(from.$name$());\n");
+ } else {
+ printer->Print(variables_,
+ "$set_hasbit$\n"
+ "$name$_.AssignWithDefault($default_variable$, from.$name$_);\n");
+ }
}
void StringFieldGenerator::
diff --git a/src/google/protobuf/compiler/cpp/cpp_unittest.cc b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
index 74a277e0..20fcfa62 100644
--- a/src/google/protobuf/compiler/cpp/cpp_unittest.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_unittest.cc
@@ -251,7 +251,7 @@ TEST(GeneratedMessageTest, ReleaseString) {
message.set_default_string("blah");
EXPECT_TRUE(message.has_default_string());
- scoped_ptr<string> str(message.release_default_string());
+ google::protobuf::scoped_ptr<string> str(message.release_default_string());
EXPECT_FALSE(message.has_default_string());
ASSERT_TRUE(str != NULL);
EXPECT_EQ("blah", *str);
@@ -270,7 +270,7 @@ TEST(GeneratedMessageTest, ReleaseMessage) {
EXPECT_FALSE(message.has_optional_nested_message());
message.mutable_optional_nested_message()->set_bb(1);
- scoped_ptr<unittest::TestAllTypes::NestedMessage> nest(
+ google::protobuf::scoped_ptr<unittest::TestAllTypes::NestedMessage> nest(
message.release_optional_nested_message());
EXPECT_FALSE(message.has_optional_nested_message());
ASSERT_TRUE(nest != NULL);
@@ -534,7 +534,7 @@ TEST(GeneratedMessageTest, DynamicMessageCopyFrom) {
// Construct a new version of the dynamic message via the factory.
DynamicMessageFactory factory;
- scoped_ptr<Message> message1;
+ google::protobuf::scoped_ptr<Message> message1;
message1.reset(factory.GetPrototype(
unittest::TestAllTypes::descriptor())->New());
@@ -581,9 +581,9 @@ TEST(GeneratedMessageTest, NonEmptyMergeFrom) {
TEST(GeneratedMessageTest, MergeFromSelf) {
unittest::TestAllTypes message;
- EXPECT_DEATH(message.MergeFrom(message), "&from");
+ EXPECT_DEATH(message.MergeFrom(message), "Check failed:.*pb[.]cc");
EXPECT_DEATH(message.MergeFrom(implicit_cast<const Message&>(message)),
- "&from");
+ "Check failed:.*pb[.]cc");
}
#endif // PROTOBUF_HAS_DEATH_TEST
@@ -1221,7 +1221,7 @@ class GeneratedServiceTest : public testing::Test {
unittest::FooResponse foo_response_;
unittest::BarRequest bar_request_;
unittest::BarResponse bar_response_;
- scoped_ptr<Closure> done_;
+ google::protobuf::scoped_ptr<Closure> done_;
};
TEST_F(GeneratedServiceTest, GetDescriptor) {
@@ -1519,7 +1519,7 @@ TEST_F(OneofTest, ReleaseString) {
message.set_foo_string("blah");
EXPECT_TRUE(message.has_foo_string());
- scoped_ptr<string> str(message.release_foo_string());
+ google::protobuf::scoped_ptr<string> str(message.release_foo_string());
EXPECT_FALSE(message.has_foo_string());
ASSERT_TRUE(str != NULL);
EXPECT_EQ("blah", *str);
@@ -1573,7 +1573,7 @@ TEST_F(OneofTest, ReleaseMessage) {
message.mutable_foo_message()->set_qux_int(1);
EXPECT_TRUE(message.has_foo_message());
- scoped_ptr<unittest::TestOneof2_NestedMessage> mes(
+ google::protobuf::scoped_ptr<unittest::TestOneof2_NestedMessage> mes(
message.release_foo_message());
EXPECT_FALSE(message.has_foo_message());
ASSERT_TRUE(mes != NULL);