diff --git a/src/google/protobuf/text_format.cc b/src/google/protobuf/text_format.cc index 5ae9899dab75b..0cb19685fdc87 100644 --- a/src/google/protobuf/text_format.cc +++ b/src/google/protobuf/text_format.cc @@ -29,6 +29,7 @@ #include "absl/base/macros.h" #include "absl/container/btree_set.h" #include "absl/log/absl_check.h" +#include "absl/memory/memory.h" #include "absl/strings/ascii.h" #include "absl/strings/cord.h" #include "absl/strings/escaping.h" @@ -44,6 +45,7 @@ #include "google/protobuf/descriptor.h" #include "google/protobuf/descriptor.pb.h" #include "google/protobuf/dynamic_message.h" +#include "google/protobuf/internal_visibility.h" #include "google/protobuf/io/coded_stream.h" #include "google/protobuf/io/strtod.h" #include "google/protobuf/io/tokenizer.h" @@ -2459,32 +2461,38 @@ class MapEntryMessageComparator { }; namespace internal { + +struct MapEntries { + std::vector> owned_entries; + std::vector all_entries; +}; + class MapFieldPrinterHelper { public: // DynamicMapSorter::Sort cannot be used because it enforces syncing with // repeated field. - static bool SortMap(const Message& message, const Reflection* reflection, - const FieldDescriptor* field, - std::vector* sorted_map_field); + static MapEntries SortMap(const Message& message, + const Reflection* reflection, + const FieldDescriptor* field); static void CopyKey(const MapKey& key, Message* message, const FieldDescriptor* field_desc); static void CopyValue(const MapValueRef& value, Message* message, const FieldDescriptor* field_desc); }; -// Returns true if elements contained in sorted_map_field need to be released. -bool MapFieldPrinterHelper::SortMap( - const Message& message, const Reflection* reflection, - const FieldDescriptor* field, - std::vector* sorted_map_field) { - bool need_release = false; +MapEntries MapFieldPrinterHelper::SortMap(const Message& message, + const Reflection* reflection, + const FieldDescriptor* field) { const MapFieldBase& base = *reflection->GetMapData(message, field); + std::vector all_entries; + std::vector> owned_entries; if (base.IsRepeatedFieldValid()) { const RepeatedPtrField& map_field = reflection->GetRepeatedPtrFieldInternal(message, field); + all_entries.reserve(map_field.size()); for (int i = 0; i < map_field.size(); ++i) { - sorted_map_field->push_back( + all_entries.push_back( const_cast*>(&map_field)->Mutable(i)); } } else { @@ -2493,23 +2501,25 @@ bool MapFieldPrinterHelper::SortMap( const Descriptor* map_entry_desc = field->message_type(); const Message* prototype = reflection->GetMessageFactory()->GetPrototype(map_entry_desc); + all_entries.reserve(reflection->MapSize(message, field)); + owned_entries.reserve(reflection->MapSize(message, field)); for (MapIterator iter = reflection->MapBegin(const_cast(&message), field); iter != reflection->MapEnd(const_cast(&message), field); ++iter) { - Message* map_entry_message = prototype->New(); - CopyKey(iter.GetKey(), map_entry_message, map_entry_desc->field(0)); - CopyValue(iter.GetValueRef(), map_entry_message, + std::unique_ptr map_entry_message = + absl::WrapUnique(prototype->New()); + CopyKey(iter.GetKey(), map_entry_message.get(), map_entry_desc->field(0)); + CopyValue(iter.GetValueRef(), map_entry_message.get(), map_entry_desc->field(1)); - sorted_map_field->push_back(map_entry_message); + all_entries.push_back(map_entry_message.get()); + owned_entries.push_back(std::move(map_entry_message)); } - need_release = true; } - MapEntryMessageComparator comparator(field->message_type()); - std::stable_sort(sorted_map_field->begin(), sorted_map_field->end(), - comparator); - return need_release; + std::stable_sort(all_entries.begin(), all_entries.end(), + MapEntryMessageComparator(field->message_type())); + return {std::move(owned_entries), std::move(all_entries)}; } void MapFieldPrinterHelper::CopyKey(const MapKey& key, Message* message, @@ -2607,13 +2617,11 @@ void TextFormat::Printer::PrintField(const Message& message, count = 1; } - std::vector sorted_map_field; - bool need_release = false; bool is_map = field->is_map(); - if (is_map) { - need_release = internal::MapFieldPrinterHelper::SortMap( - message, reflection, field, &sorted_map_field); - } + const internal::MapEntries map_entries = + is_map + ? internal::MapFieldPrinterHelper::SortMap(message, reflection, field) + : internal::MapEntries(); for (int j = 0; j < count; ++j) { const int field_index = field->is_repeated() ? j : -1; @@ -2628,7 +2636,7 @@ void TextFormat::Printer::PrintField(const Message& message, const FastFieldValuePrinter* printer = GetFieldPrinter(field); const Message& sub_message = field->is_repeated() - ? (is_map ? *sorted_map_field[j] + ? (is_map ? *map_entries.all_entries[j] : reflection->GetRepeatedMessage(message, field, j)) : reflection->GetMessage(message, field); printer->PrintMessageStart(sub_message, field_index, count, @@ -2652,12 +2660,6 @@ void TextFormat::Printer::PrintField(const Message& message, } } } - - if (need_release) { - for (const Message* message_to_delete : sorted_map_field) { - delete message_to_delete; - } - } } void TextFormat::Printer::PrintShortRepeatedField(