diff options
Diffstat (limited to 'src/google/protobuf/compiler/cpp/cpp_map_field.cc')
-rw-r--r-- | src/google/protobuf/compiler/cpp/cpp_map_field.cc | 360 |
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"); |