aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/google/protobuf/compiler/cpp/cpp_map_field.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/google/protobuf/compiler/cpp/cpp_map_field.cc')
-rw-r--r--src/google/protobuf/compiler/cpp/cpp_map_field.cc360
1 files changed, 193 insertions, 167 deletions
diff --git a/src/google/protobuf/compiler/cpp/cpp_map_field.cc b/src/google/protobuf/compiler/cpp/cpp_map_field.cc
index e5e2f07d..0e485cac 100644
--- a/src/google/protobuf/compiler/cpp/cpp_map_field.cc
+++ b/src/google/protobuf/compiler/cpp/cpp_map_field.cc
@@ -32,6 +32,7 @@
#include <google/protobuf/compiler/cpp/cpp_helpers.h>
#include <google/protobuf/io/printer.h>
#include <google/protobuf/wire_format.h>
+
#include <google/protobuf/stubs/strutil.h>
namespace google {
@@ -45,14 +46,17 @@ bool IsProto3Field(const FieldDescriptor* field_descriptor) {
}
void SetMessageVariables(const FieldDescriptor* descriptor,
- map<string, string>* variables,
+ std::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)["type"] = ClassName(descriptor->message_type(), false);
+ (*variables)["file_namespace"] =
+ FileLevelNamespace(descriptor->file()->name());
+ (*variables)["stream_writer"] =
+ (*variables)["declared_type"] +
+ (HasFastArraySerialization(descriptor->message_type()->file(), options)
+ ? "MaybeToArray"
+ : "");
(*variables)["full_name"] = descriptor->full_name();
const FieldDescriptor* key =
@@ -83,7 +87,7 @@ void SetMessageVariables(const FieldDescriptor* descriptor,
(*variables)["number"] = SimpleItoa(descriptor->number());
(*variables)["tag"] = SimpleItoa(internal::WireFormat::MakeTag(descriptor));
- if (HasDescriptorMethods(descriptor->file())) {
+ if (HasDescriptorMethods(descriptor->file(), options)) {
(*variables)["lite"] = "";
} else {
(*variables)["lite"] = "Lite";
@@ -98,11 +102,9 @@ void SetMessageVariables(const FieldDescriptor* descriptor,
}
}
-MapFieldGenerator::
-MapFieldGenerator(const FieldDescriptor* descriptor,
- const Options& options)
- : descriptor_(descriptor),
- dependent_field_(options.proto_h && IsFieldDependent(descriptor)) {
+MapFieldGenerator::MapFieldGenerator(const FieldDescriptor* descriptor,
+ const Options& options)
+ : FieldGenerator(options), descriptor_(descriptor) {
SetMessageVariables(descriptor, &variables_, options);
}
@@ -111,40 +113,36 @@ MapFieldGenerator::~MapFieldGenerator() {}
void MapFieldGenerator::
GeneratePrivateMembers(io::Printer* printer) const {
printer->Print(variables_,
- "typedef ::google::protobuf::internal::MapEntryLite<\n"
- " $key_cpp$, $val_cpp$,\n"
- " $key_wire_type$,\n"
- " $val_wire_type$,\n"
- " $default_enum_value$ >\n"
- " $map_classname$;\n"
- "::google::protobuf::internal::MapField$lite$<\n"
- " $key_cpp$, $val_cpp$,\n"
- " $key_wire_type$,\n"
- " $val_wire_type$,\n"
- " $default_enum_value$ > $name$_;\n");
+ "::google::protobuf::internal::MapField$lite$<\n"
+ " $map_classname$,\n"
+ " $key_cpp$, $val_cpp$,\n"
+ " $key_wire_type$,\n"
+ " $val_wire_type$,\n"
+ " $default_enum_value$ > $name$_;\n");
}
void MapFieldGenerator::
GenerateAccessorDeclarations(io::Printer* printer) const {
+ printer->Print(
+ variables_,
+ "$deprecated_attr$const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n"
+ " $name$() const;\n");
+ printer->Annotate("name", descriptor_);
printer->Print(variables_,
- "const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n"
- " $name$() const$deprecation$;\n"
- "::google::protobuf::Map< $key_cpp$, $val_cpp$ >*\n"
- " mutable_$name$()$deprecation$;\n");
+ "$deprecated_attr$::google::protobuf::Map< $key_cpp$, $val_cpp$ >*\n"
+ " ${$mutable_$name$$}$();\n");
+ printer->Annotate("{", "}", descriptor_);
}
void MapFieldGenerator::
-GenerateInlineAccessorDefinitions(io::Printer* printer,
- bool is_inline) const {
- map<string, string> variables(variables_);
- variables["inline"] = is_inline ? "inline" : "";
- printer->Print(variables,
- "$inline$ const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n"
+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"
+ "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"
@@ -153,9 +151,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer,
void MapFieldGenerator::
GenerateClearingCode(io::Printer* printer) const {
- map<string, string> variables(variables_);
- variables["this_message"] = dependent_field_ ? DependentBaseDownCast() : "";
- printer->Print(variables, "$this_message$$name$_.Clear();\n");
+ printer->Print(variables_, "$name$_.Clear();\n");
}
void MapFieldGenerator::
@@ -169,45 +165,42 @@ GenerateSwappingCode(io::Printer* printer) const {
}
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");
- }
+GenerateCopyConstructorCode(io::Printer* printer) const {
+ GenerateConstructorCode(printer);
+ GenerateMergingCode(printer);
}
void MapFieldGenerator::
GenerateMergeFromCodedStream(io::Printer* printer) const {
+ const FieldDescriptor* key_field =
+ descriptor_->message_type()->FindFieldByName("key");
const FieldDescriptor* value_field =
descriptor_->message_type()->FindFieldByName("value");
- printer->Print(variables_,
- "::google::protobuf::scoped_ptr<$map_classname$> entry($name$_.NewEntry());\n");
-
+ bool using_entry = false;
+ string key;
+ string value;
if (IsProto3Field(descriptor_) ||
value_field->type() != FieldDescriptor::TYPE_ENUM) {
- printer->Print(variables_,
+ printer->Print(
+ variables_,
+ "$map_classname$::Parser< ::google::protobuf::internal::MapField$lite$<\n"
+ " $map_classname$,\n"
+ " $key_cpp$, $val_cpp$,\n"
+ " $key_wire_type$,\n"
+ " $val_wire_type$,\n"
+ " $default_enum_value$ >,\n"
+ " ::google::protobuf::Map< $key_cpp$, $val_cpp$ > >"
+ " parser(&$name$_);\n"
"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;
- }
+ " input, &parser));\n");
+ key = "parser.key()";
+ value = "parser.value()";
} else {
+ using_entry = true;
+ key = "entry->key()";
+ value = "entry->value()";
+ printer->Print(variables_,
+ "::std::unique_ptr<$map_classname$> entry($name$_.NewEntry());\n");
printer->Print(variables_,
"{\n"
" ::std::string data;\n"
@@ -217,164 +210,197 @@ GenerateMergeFromCodedStream(io::Printer* printer) const {
" (*mutable_$name$())[entry->key()] =\n"
" static_cast< $val_cpp$ >(*entry->mutable_value());\n"
" } else {\n");
- if (HasDescriptorMethods(descriptor_->file())) {
+ if (HasDescriptorMethods(descriptor_->file(), options_)) {
printer->Print(variables_,
" mutable_unknown_fields()"
"->AddLengthDelimited($number$, data);\n");
} else {
printer->Print(variables_,
- " unknown_fields_stream.WriteVarint32($tag$);\n"
- " unknown_fields_stream.WriteVarint32(data.size());\n"
+ " unknown_fields_stream.WriteVarint32($tag$u);\n"
+ " unknown_fields_stream.WriteVarint32(\n"
+ " static_cast< ::google::protobuf::uint32>(data.size()));\n"
" unknown_fields_stream.WriteString(data);\n");
}
-
printer->Print(variables_,
" }\n"
"}\n");
}
- const FieldDescriptor* key_field =
- descriptor_->message_type()->FindFieldByName("key");
if (key_field->type() == FieldDescriptor::TYPE_STRING) {
GenerateUtf8CheckCodeForString(
- key_field, true, variables_,
- "entry->key().data(), entry->key().length(),\n", printer);
+ key_field, options_, true, variables_,
+ StrCat(key, ".data(), static_cast<int>(", key, ".length()),\n").data(),
+ printer);
}
if (value_field->type() == FieldDescriptor::TYPE_STRING) {
GenerateUtf8CheckCodeForString(
- value_field, true, variables_,
- "entry->mutable_value()->data(),\n"
- "entry->mutable_value()->length(),\n", printer);
+ value_field, options_, true, variables_,
+ StrCat(value, ".data(), static_cast<int>(", value, ".length()),\n")
+ .data(),
+ printer);
}
// If entry is allocated by arena, its desctructor should be avoided.
- if (SupportsArenas(descriptor_)) {
+ if (using_entry && SupportsArenas(descriptor_)) {
printer->Print(variables_,
"if (entry->GetArena() != NULL) entry.release();\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 = this->$name$().begin();\n"
- " it != this->$name$().end(); ++it) {\n");
+static void GenerateSerializationLoop(io::Printer* printer,
+ const std::map<string, string>& variables,
+ bool supports_arenas,
+ const string& utf8_check,
+ const string& loop_header,
+ const string& ptr,
+ bool loop_via_iterators) {
+ printer->Print(variables,
+ StrCat("::std::unique_ptr<$map_classname$> entry;\n",
+ loop_header, " {\n").c_str());
+ printer->Indent();
+
+ printer->Print(variables, StrCat(
+ "entry.reset($name$_.New$wrapper$(\n"
+ " ", ptr, "->first, ", ptr, "->second));\n"
+ "$write_entry$;\n").c_str());
// If entry is allocated by arena, its desctructor should be avoided.
- if (SupportsArenas(descriptor_)) {
- printer->Print(variables_,
- " if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
- " entry.release();\n"
- " }\n");
+ if (supports_arenas) {
+ printer->Print(
+ "if (entry->GetArena() != NULL) {\n"
+ " entry.release();\n"
+ "}\n");
}
- printer->Print(variables_,
- " entry.reset($name$_.New$wrapper$(it->first, it->second));\n"
- " ::google::protobuf::internal::WireFormatLite::Write$stream_writer$(\n"
- " $number$, *entry, output);\n");
-
- printer->Indent();
- printer->Indent();
-
- const FieldDescriptor* key_field =
- descriptor_->message_type()->FindFieldByName("key");
- const FieldDescriptor* value_field =
- descriptor_->message_type()->FindFieldByName("value");
- if (key_field->type() == FieldDescriptor::TYPE_STRING) {
- GenerateUtf8CheckCodeForString(
- key_field, false, variables_,
- "it->first.data(), it->first.length(),\n", printer);
- }
- if (value_field->type() == FieldDescriptor::TYPE_STRING) {
- GenerateUtf8CheckCodeForString(
- value_field, false, variables_,
- "it->second.data(), it->second.length(),\n", printer);
+ if (!utf8_check.empty()) {
+ // If loop_via_iterators is true then ptr is actually an iterator, and we
+ // create a pointer by prefixing it with "&*".
+ printer->Print(
+ StrCat(utf8_check, "(", (loop_via_iterators ? "&*" : ""), ptr, ");\n")
+ .c_str());
}
printer->Outdent();
- printer->Outdent();
-
printer->Print(
- " }\n");
-
- // If entry is allocated by arena, its desctructor should be avoided.
- if (SupportsArenas(descriptor_)) {
- printer->Print(variables_,
- " if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
- " entry.release();\n"
- " }\n");
- }
+ "}\n");
+}
- printer->Print("}\n");
+void MapFieldGenerator::
+GenerateSerializeWithCachedSizes(io::Printer* printer) const {
+ std::map<string, string> variables(variables_);
+ variables["write_entry"] = "::google::protobuf::internal::WireFormatLite::Write" +
+ variables["stream_writer"] + "(\n " +
+ variables["number"] + ", *entry, output)";
+ variables["deterministic"] = "output->IsSerializationDeterministic()";
+ GenerateSerializeWithCachedSizes(printer, variables);
}
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 = this->$name$().begin();\n"
- " it != this->$name$().end(); ++it) {\n");
-
- // If entry is allocated by arena, its desctructor should be avoided.
- if (SupportsArenas(descriptor_)) {
- printer->Print(variables_,
- " if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
- " entry.release();\n"
- " }\n");
- }
-
- printer->Print(variables_,
- " 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");
+ std::map<string, string> variables(variables_);
+ variables["write_entry"] =
+ "target = ::google::protobuf::internal::WireFormatLite::\n"
+ " InternalWrite" + variables["declared_type"] +
+ "NoVirtualToArray(\n " + variables["number"] +
+ ", *entry, deterministic, target);\n";
+ variables["deterministic"] = "deterministic";
+ GenerateSerializeWithCachedSizes(printer, variables);
+}
+void MapFieldGenerator::GenerateSerializeWithCachedSizes(
+ io::Printer* printer, const std::map<string, string>& variables) const {
+ printer->Print(variables,
+ "if (!this->$name$().empty()) {\n");
printer->Indent();
- printer->Indent();
-
const FieldDescriptor* key_field =
descriptor_->message_type()->FindFieldByName("key");
const FieldDescriptor* value_field =
descriptor_->message_type()->FindFieldByName("value");
- if (key_field->type() == FieldDescriptor::TYPE_STRING) {
- GenerateUtf8CheckCodeForString(
- key_field, false, variables_,
- "it->first.data(), it->first.length(),\n", printer);
+ const bool string_key = key_field->type() == FieldDescriptor::TYPE_STRING;
+ const bool string_value = value_field->type() == FieldDescriptor::TYPE_STRING;
+
+ printer->Print(variables,
+ "typedef ::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_pointer\n"
+ " ConstPtr;\n");
+ if (string_key) {
+ printer->Print(variables,
+ "typedef ConstPtr SortItem;\n"
+ "typedef ::google::protobuf::internal::"
+ "CompareByDerefFirst<SortItem> Less;\n");
+ } else {
+ printer->Print(variables,
+ "typedef ::google::protobuf::internal::SortItem< $key_cpp$, ConstPtr > "
+ "SortItem;\n"
+ "typedef ::google::protobuf::internal::CompareByFirstField<SortItem> Less;\n");
}
- if (value_field->type() == FieldDescriptor::TYPE_STRING) {
- GenerateUtf8CheckCodeForString(
- value_field, false, variables_,
- "it->second.data(), it->second.length(),\n", printer);
+ string utf8_check;
+ if (string_key || string_value) {
+ printer->Print(
+ "struct Utf8Check {\n"
+ " static void Check(ConstPtr p) {\n");
+ printer->Indent();
+ printer->Indent();
+ if (string_key) {
+ GenerateUtf8CheckCodeForString(
+ key_field, options_, false, variables,
+ "p->first.data(), static_cast<int>(p->first.length()),\n", printer);
+ }
+ if (string_value) {
+ GenerateUtf8CheckCodeForString(
+ value_field, options_, false, variables,
+ "p->second.data(), static_cast<int>(p->second.length()),\n", printer);
+ }
+ printer->Outdent();
+ printer->Outdent();
+ printer->Print(
+ " }\n"
+ "};\n");
+ utf8_check = "Utf8Check::Check";
}
- printer->Outdent();
+ printer->Print(variables,
+ "\n"
+ "if ($deterministic$ &&\n"
+ " this->$name$().size() > 1) {\n"
+ " ::std::unique_ptr<SortItem[]> items(\n"
+ " new SortItem[this->$name$().size()]);\n"
+ " typedef ::google::protobuf::Map< $key_cpp$, $val_cpp$ >::size_type size_type;\n"
+ " size_type n = 0;\n"
+ " for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
+ " it = this->$name$().begin();\n"
+ " it != this->$name$().end(); ++it, ++n) {\n"
+ " items[static_cast<ptrdiff_t>(n)] = SortItem(&*it);\n"
+ " }\n"
+ " ::std::sort(&items[0], &items[static_cast<ptrdiff_t>(n)], Less());\n");
+ printer->Indent();
+ GenerateSerializationLoop(printer, variables, SupportsArenas(descriptor_),
+ utf8_check, "for (size_type i = 0; i < n; i++)",
+ string_key ? "items[static_cast<ptrdiff_t>(i)]" :
+ "items[static_cast<ptrdiff_t>(i)].second", false);
printer->Outdent();
printer->Print(
- " }\n");
-
- // If entry is allocated by arena, its desctructor should be avoided.
- if (SupportsArenas(descriptor_)) {
- printer->Print(variables_,
- " if (entry.get() != NULL && entry->GetArena() != NULL) {\n"
- " entry.release();\n"
- " }\n");
- }
-
+ "} else {\n");
+ printer->Indent();
+ GenerateSerializationLoop(
+ printer, variables, SupportsArenas(descriptor_), utf8_check,
+ "for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
+ " it = this->$name$().begin();\n"
+ " it != this->$name$().end(); ++it)",
+ "it", true);
+ printer->Outdent();
+ printer->Print("}\n");
+ printer->Outdent();
printer->Print("}\n");
}
void MapFieldGenerator::
GenerateByteSize(io::Printer* printer) const {
printer->Print(variables_,
- "total_size += $tag_size$ * this->$name$_size();\n"
+ "total_size += $tag_size$ *\n"
+ " ::google::protobuf::internal::FromIntSize(this->$name$_size());\n"
"{\n"
- " ::google::protobuf::scoped_ptr<$map_classname$> entry;\n"
+ " ::std::unique_ptr<$map_classname$> entry;\n"
" for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n"
" it = this->$name$().begin();\n"
" it != this->$name$().end(); ++it) {\n");