Index: third_party/protobuf/src/google/protobuf/compiler/cpp/cpp_map_field.cc |
diff --git a/third_party/protobuf/src/google/protobuf/compiler/cpp/cpp_map_field.cc b/third_party/protobuf/src/google/protobuf/compiler/cpp/cpp_map_field.cc |
index f585c31b4bf8ebfb9a2bb5d96968bf63f9c6d470..5c4b56f7eda2433385d66b9759a32d37400577b2 100644 |
--- a/third_party/protobuf/src/google/protobuf/compiler/cpp/cpp_map_field.cc |
+++ b/third_party/protobuf/src/google/protobuf/compiler/cpp/cpp_map_field.cc |
@@ -45,10 +45,10 @@ 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)["type"] = ClassName(descriptor->message_type(), false); |
(*variables)["stream_writer"] = |
(*variables)["declared_type"] + |
(HasFastArraySerialization(descriptor->message_type()->file(), options) |
@@ -137,7 +137,7 @@ GenerateAccessorDeclarations(io::Printer* printer) const { |
void MapFieldGenerator:: |
GenerateInlineAccessorDefinitions(io::Printer* printer, |
bool is_inline) const { |
- map<string, string> variables(variables_); |
+ std::map<string, string> variables(variables_); |
variables["inline"] = is_inline ? "inline" : ""; |
printer->Print(variables, |
"$inline$ const ::google::protobuf::Map< $key_cpp$, $val_cpp$ >&\n" |
@@ -154,7 +154,7 @@ GenerateInlineAccessorDefinitions(io::Printer* printer, |
void MapFieldGenerator:: |
GenerateClearingCode(io::Printer* printer) const { |
- map<string, string> variables(variables_); |
+ std::map<string, string> variables(variables_); |
variables["this_message"] = dependent_field_ ? DependentBaseDownCast() : ""; |
printer->Print(variables, "$this_message$$name$_.Clear();\n"); |
} |
@@ -173,42 +173,48 @@ void MapFieldGenerator:: |
GenerateConstructorCode(io::Printer* printer) const { |
if (HasDescriptorMethods(descriptor_->file(), options_)) { |
printer->Print(variables_, |
- "$name$_.SetAssignDescriptorCallback(\n" |
- " protobuf_AssignDescriptorsOnce);\n" |
- "$name$_.SetEntryDescriptor(\n" |
- " &$type$_descriptor_);\n"); |
+ "$name$_.SetAssignDescriptorCallback(\n" |
+ " protobuf_AssignDescriptorsOnce);\n" |
+ "$name$_.SetEntryDescriptor(\n" |
+ " &$type$_descriptor);\n"); |
} |
} |
void MapFieldGenerator:: |
+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_, |
+ "$map_classname$::Parser< ::google::protobuf::internal::MapField$lite$<\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_, |
+ "::google::protobuf::scoped_ptr<$map_classname$> entry($name$_.NewEntry());\n"); |
printer->Print(variables_, |
"{\n" |
" ::std::string data;\n" |
@@ -224,156 +230,183 @@ GenerateMergeFromCodedStream(io::Printer* printer) const { |
"->AddLengthDelimited($number$, data);\n"); |
} else { |
printer->Print(variables_, |
- " unknown_fields_stream.WriteVarint32($tag$);\n" |
+ " unknown_fields_stream.WriteVarint32($tag$u);\n" |
" unknown_fields_stream.WriteVarint32(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, options_, true, variables_, |
- "entry->key().data(), entry->key().length(),\n", printer); |
+ key_field, options_, true, variables_, |
+ StrCat(key, ".data(), ", key, ".length(),\n").data(), printer); |
} |
if (value_field->type() == FieldDescriptor::TYPE_STRING) { |
GenerateUtf8CheckCodeForString(value_field, options_, true, variables_, |
- "entry->mutable_value()->data(),\n" |
- "entry->mutable_value()->length(),\n", |
- printer); |
+ StrCat(value, ".data(), ", 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("::google::protobuf::scoped_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, options_, false, variables_, |
- "it->first.data(), it->first.length(),\n", |
- printer); |
- } |
- if (value_field->type() == FieldDescriptor::TYPE_STRING) { |
- GenerateUtf8CheckCodeForString(value_field, options_, 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, options_, 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, options_, 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(), p->first.length(),\n", |
+ printer); |
+ } |
+ if (string_value) { |
+ GenerateUtf8CheckCodeForString(value_field, options_, false, variables, |
+ "p->second.data(), 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" |
+ " ::google::protobuf::scoped_array<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[n] = SortItem(&*it);\n" |
+ " }\n" |
+ " ::std::sort(&items[0], &items[n], Less());\n"); |
+ printer->Indent(); |
+ GenerateSerializationLoop(printer, variables, SupportsArenas(descriptor_), |
+ utf8_check, "for (size_type i = 0; i < n; i++)", |
+ string_key ? "items[i]" : "items[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" |
" for (::google::protobuf::Map< $key_cpp$, $val_cpp$ >::const_iterator\n" |