Add new public Map reflection API. The new API provides a map-like interface that can be accessed via `Reflection::GetMap` and `Reflection::MutableMap`. This API accesses the underlying Map type directly and avoid the fake repeated field we see today via the legacy reflection API. In a future breaking change, the repeated field based access for maps will be removed and the only valid reflection will be this new API. PiperOrigin-RevId: 987589348
diff --git a/python/google/protobuf/pyext/map_container.cc b/python/google/protobuf/pyext/map_container.cc index 207b952..ea9dddd 100644 --- a/python/google/protobuf/pyext/map_container.cc +++ b/python/google/protobuf/pyext/map_container.cc
@@ -17,6 +17,7 @@ #include <optional> #include <string> +#include "absl/status/statusor.h" #include "absl/strings/string_view.h" #include "google/protobuf/map.h" #include "google/protobuf/map_field.h" @@ -59,7 +60,7 @@ // clang-format off PyObject_HEAD - std::unique_ptr<::google::protobuf::ConstMapIterator> iter; + ::google::protobuf::GenericConstMapRef::const_iterator iter; // clang-format on // A pointer back to the container, so we can notice changes to the version. @@ -196,64 +197,64 @@ // CPPTYPE_MESSAGE case. static bool PythonToMapValueRef(MapContainer* self, PyObject* obj, bool allow_unknown_enum_values, - MapValueRef* value_ref) { + MapValueRef value_ref) { const FieldDescriptor* field_descriptor = self->parent_field_descriptor->message_type()->map_value(); switch (field_descriptor->cpp_type()) { case FieldDescriptor::CPPTYPE_INT32: { PROTOBUF_CHECK_GET_INT32(obj, value, false); - value_ref->SetInt32Value(value); + value_ref.SetInt32Value(value); return true; } case FieldDescriptor::CPPTYPE_INT64: { PROTOBUF_CHECK_GET_INT64(obj, value, false); - value_ref->SetInt64Value(value); + value_ref.SetInt64Value(value); return true; } case FieldDescriptor::CPPTYPE_UINT32: { PROTOBUF_CHECK_GET_UINT32(obj, value, false); - value_ref->SetUInt32Value(value); + value_ref.SetUInt32Value(value); return true; } case FieldDescriptor::CPPTYPE_UINT64: { PROTOBUF_CHECK_GET_UINT64(obj, value, false); - value_ref->SetUInt64Value(value); + value_ref.SetUInt64Value(value); return true; } case FieldDescriptor::CPPTYPE_FLOAT: { PROTOBUF_CHECK_GET_FLOAT(obj, value, false); - value_ref->SetFloatValue(value); + value_ref.SetFloatValue(value); return true; } case FieldDescriptor::CPPTYPE_DOUBLE: { PROTOBUF_CHECK_GET_DOUBLE(obj, value, false); - value_ref->SetDoubleValue(value); + value_ref.SetDoubleValue(value); return true; } case FieldDescriptor::CPPTYPE_BOOL: { PROTOBUF_CHECK_GET_BOOL(obj, value, false); - value_ref->SetBoolValue(value); + value_ref.SetBoolValue(value); return true; } case FieldDescriptor::CPPTYPE_STRING: { std::optional<absl::string_view> value = CheckString(obj, field_descriptor); if (value.has_value()) { - value_ref->SetStringValue(*value); + value_ref.SetStringValue(*value); } return value.has_value(); } case FieldDescriptor::CPPTYPE_ENUM: { PROTOBUF_CHECK_GET_INT32(obj, value, false); if (allow_unknown_enum_values) { - value_ref->SetEnumValue(value); + value_ref.SetEnumValue(value); return true; } else { const EnumDescriptor* enum_descriptor = field_descriptor->enum_type(); const EnumValueDescriptor* enum_value = enum_descriptor->FindValueByNumber(value); if (enum_value != nullptr) { - value_ref->SetEnumValue(value); + value_ref.SetEnumValue(value); return true; } else { PyErr_Format(PyExc_ValueError, "Unknown enum value: %d", value); @@ -270,6 +271,26 @@ } } +static std::optional<MapValueRef> TryEmplace(Message* message, + MapContainer* self, + MapKey map_key) { + auto map = message->GetReflection()->MutableMap( + message, self->parent_field_descriptor); + if (!map.ok()) { + PyErr_SetString(PyExc_SystemError, map.status().ToString().c_str()); + return std::nullopt; + } + auto res = map->try_emplace(map_key); + if (!res.ok()) { + PyErr_SetString(PyExc_SystemError, res.status().ToString().c_str()); + return std::nullopt; + } + if (res->inserted) { + self->version++; + } + return res->iter->value(); +} + // Map methods common to ScalarMap and MessageMap ////////////////////////////// static MapContainer* GetMap(PyObject* obj) { @@ -279,8 +300,9 @@ Py_ssize_t MapReflectionFriend::Length(PyObject* _self) { MapContainer* self = GetMap(_self); const google::protobuf::Message* message = self->parent->message; - return message->GetReflection()->MapSize(*message, - self->parent_field_descriptor); + auto map = + message->GetReflection()->GetMap(*message, self->parent_field_descriptor); + return map.ok() ? map->size() : 0; } PyObject* Clear(PyObject* _self) { @@ -337,8 +359,8 @@ return -1; } - if (reflection->ContainsMapKey(*message, self->parent_field_descriptor, - map_key)) { + auto map = reflection->GetMap(*message, self->parent_field_descriptor); + if (map.ok() && map->contains(map_key)) { return 1; } else { return 0; @@ -382,10 +404,11 @@ // 1. Read-only lookup without mutation if key exists. const Message* message = self->GetReadOnlyMessage(); const Reflection* reflection = message->GetReflection(); - MapValueConstRef value; - if (reflection->LookupMapValue(*message, self->parent_field_descriptor, - map_key, &value)) { - return MapValueRefToPython(self, value); + auto map = reflection->GetMap(*message, self->parent_field_descriptor); + if (map.ok()) { + if (auto it = map->find(map_key); it != map->end()) { + return MapValueRefToPython(self, it->value()); + } } // 2. Frozen path: read-only lookup failed and message is frozen. @@ -396,14 +419,9 @@ // 3. Mutable path: insert default value for missing key. if (Message* mutable_message = self->GetMutableMessage(); mutable_message != nullptr) { - MapValueRef mutable_value; - const Reflection* mutable_reflection = mutable_message->GetReflection(); - if (mutable_reflection->InsertOrLookupMapValue( - mutable_message, self->parent_field_descriptor, map_key, - &mutable_value)) { - self->version++; - } - return MapValueRefToPython(self, mutable_value); + auto value = TryEmplace(mutable_message, self, map_key); + if (!value.has_value()) return nullptr; + return MapValueRefToPython(self, *value); } return nullptr; @@ -417,31 +435,27 @@ if (message == nullptr) return -1; const Reflection* reflection = message->GetReflection(); MapKey map_key; - MapValueRef value; if (!PythonToMapKey(self, key, &map_key)) { return -1; } if (v) { + auto value = TryEmplace(message, self, map_key); + if (!value.has_value()) return -1; // Set item to v. - if (reflection->InsertOrLookupMapValue( - message, self->parent_field_descriptor, map_key, &value)) { - self->version++; - } - if (!PythonToMapValueRef(self, v, !self->parent_field_descriptor->message_type() ->map_value() ->legacy_enum_field_treated_as_closed(), - &value)) { + *value)) { return -1; } return 0; } else { // Delete key from map. - if (reflection->DeleteMapValue(message, self->parent_field_descriptor, - map_key)) { + auto map = reflection->MutableMap(message, self->parent_field_descriptor); + if (map.ok() && map->erase(map_key)) { self->version++; return 0; } else { @@ -519,20 +533,20 @@ MapContainer* self = GetMap(_self); const Message* message = self->GetReadOnlyMessage(); const Reflection* reflection = message->GetReflection(); - for (google::protobuf::ConstMapIterator it = - reflection->ConstMapBegin(message, self->parent_field_descriptor); - it != reflection->ConstMapEnd(message, self->parent_field_descriptor); - ++it) { - key.reset(MapKeyToPython(self, it.GetKey())); - if (key == nullptr) { - return nullptr; - } - value.reset(MapValueRefToPython(self, it.GetValueRef())); - if (value == nullptr) { - return nullptr; - } - if (PyDict_SetItem(dict.get(), key.get(), value.get()) < 0) { - return nullptr; + auto map = reflection->GetMap(*message, self->parent_field_descriptor); + if (map.ok()) { + for (auto entry : *map) { + key.reset(MapKeyToPython(self, entry.key())); + if (key == nullptr) { + return nullptr; + } + value.reset(MapValueRefToPython(self, entry.value())); + if (value == nullptr) { + return nullptr; + } + if (PyDict_SetItem(dict.get(), key.get(), value.get()) < 0) { + return nullptr; + } } } return PyObject_Repr(dict.get()); @@ -651,13 +665,14 @@ } // Delete key from map. - if (reflection->ContainsMapKey(*message, self->parent_field_descriptor, - map_key)) { + auto map = reflection->MutableMap(message, self->parent_field_descriptor); + if (!map.ok()) { + PyErr_Format(PyExc_KeyError, "Key not present in map"); + return -1; + } + if (auto it = map->find(map_key); it != map->end()) { // Delete key from CMessage dict. - MapValueRef value; - reflection->InsertOrLookupMapValue(message, self->parent_field_descriptor, - map_key, &value); - Message* sub_message = value.MutableMessageValue(); + Message* sub_message = it->value().MutableMessageValue(); // If there is a living weak reference to an item, we "Release" it, // otherwise we just discard the C++ value. if (CMessage* released = @@ -670,7 +685,7 @@ } // Delete key from map. - reflection->DeleteMapValue(message, self->parent_field_descriptor, map_key); + map->erase(map_key); return 0; } else { PyErr_Format(PyExc_KeyError, "Key not present in map"); @@ -696,13 +711,14 @@ // 1. Read-only lookup without mutation if key exists. const Message* message = self->GetReadOnlyMessage(); const Reflection* reflection = message->GetReflection(); - MapValueConstRef value; - if (reflection->LookupMapValue(*message, self->parent_field_descriptor, - map_key, &value)) { - MessageMutabilityState state = self->parent->state == MESSAGE_FROZEN - ? MESSAGE_FROZEN - : MESSAGE_UNPROMOTED; - return GetCMessage(self, &value.GetMessageValue(), state); + auto map = reflection->GetMap(*message, self->parent_field_descriptor); + if (map.ok()) { + if (auto it = map->find(map_key); it != map->end()) { + MessageMutabilityState state = self->parent->state == MESSAGE_FROZEN + ? MESSAGE_FROZEN + : MESSAGE_UNPROMOTED; + return GetCMessage(self, &it->value().GetMessageValue(), state); + } } // 2. Frozen path: read-only lookup failed and message is frozen. @@ -713,15 +729,9 @@ // 3. Mutable path: insert default submessage for missing key. if (Message* mutable_message = self->GetMutableMessage(); mutable_message != nullptr) { - const Reflection* mutable_reflection = mutable_message->GetReflection(); - MapValueRef mutable_value; - if (mutable_reflection->InsertOrLookupMapValue( - mutable_message, self->parent_field_descriptor, map_key, - &mutable_value)) { - self->version++; - } - return GetCMessage(self, mutable_value.MutableMessageValue(), - MESSAGE_MUTABLE); + auto value = TryEmplace(mutable_message, self, map_key); + if (!value.has_value()) return nullptr; + return GetCMessage(self, value->MutableMessageValue(), MESSAGE_MUTABLE); } return nullptr; @@ -744,20 +754,20 @@ MessageMutabilityState state = self->parent->state == MESSAGE_FROZEN ? MESSAGE_FROZEN : MESSAGE_UNPROMOTED; - for (google::protobuf::ConstMapIterator it = - reflection->ConstMapBegin(message, self->parent_field_descriptor); - it != reflection->ConstMapEnd(message, self->parent_field_descriptor); - ++it) { - key.reset(MapKeyToPython(self, it.GetKey())); - if (key == nullptr) { - return nullptr; - } - value.reset(GetCMessage(self, &it.GetValueRef().GetMessageValue(), state)); - if (value == nullptr) { - return nullptr; - } - if (PyDict_SetItem(dict.get(), key.get(), value.get()) < 0) { - return nullptr; + auto map = reflection->GetMap(*message, self->parent_field_descriptor); + if (map.ok()) { + for (auto entry : *map) { + key.reset(MapKeyToPython(self, entry.key())); + if (key == nullptr) { + return nullptr; + } + value.reset(GetCMessage(self, &entry.value().GetMessageValue(), state)); + if (value == nullptr) { + return nullptr; + } + if (PyDict_SetItem(dict.get(), key.get(), value.get()) < 0) { + return nullptr; + } } } return PyObject_Repr(dict.get()); @@ -889,13 +899,12 @@ Py_INCREF(self->parent); iter->parent = self->parent; - if (MapReflectionFriend::Length(_self) > 0) { - const Message* message = self->GetReadOnlyMessage(); - const Reflection* reflection = message->GetReflection(); + const Message* message = self->GetReadOnlyMessage(); + const Reflection* reflection = message->GetReflection(); - iter->iter = std::make_unique<::google::protobuf::ConstMapIterator>( - reflection->ConstMapBegin(message, self->parent_field_descriptor)); - } + iter->iter = reflection->GetMap(*message, self->parent_field_descriptor) + .value() + .begin(); return obj.release(); } @@ -910,28 +919,29 @@ return PyErr_Format(PyExc_RuntimeError, "Map cleared during iteration."); } - if (self->iter == nullptr) { + if (self->iter == ::google::protobuf::GenericConstMapRef::const_iterator{}) { return nullptr; } const Message* message = self->container->GetReadOnlyMessage(); const Reflection* reflection = message->GetReflection(); - if (*self->iter == reflection->ConstMapEnd( - message, self->container->parent_field_descriptor)) { + if (self->iter == + reflection->GetMap(*message, self->container->parent_field_descriptor) + .value() + .end()) { return nullptr; } - PyObject* ret = MapKeyToPython(self->container, self->iter->GetKey()); + PyObject* ret = MapKeyToPython(self->container, self->iter->key()); - ++(*self->iter); + ++self->iter; return ret; } static void DeallocMapIterator(PyObject* _self) { MapIterator* self = GetIter(_self); - self->iter.reset(); Py_CLEAR(self->container); Py_CLEAR(self->parent); Py_TYPE(_self)->tp_free(_self);
diff --git a/python/google/protobuf/pyext/message.cc b/python/google/protobuf/pyext/message.cc index 06c5d6a..f14d61b 100644 --- a/python/google/protobuf/pyext/message.cc +++ b/python/google/protobuf/pyext/message.cc
@@ -91,12 +91,6 @@ const std::vector<const FieldDescriptor*>& fields) { lhs->GetReflection()->UnsafeShallowSwapFields(lhs, rhs, fields); } - static bool ContainsMapKey(const Reflection* reflection, - const Message& message, - const FieldDescriptor* field, - const MapKey& map_key) { - return reflection->ContainsMapKey(message, field, map_key); - } static void SetString(absl::string_view value, Message* message, const FieldDescriptor* descriptor, @@ -2716,8 +2710,8 @@ } map_key.SetStringValue(*key_string); - return PyBool_FromLong(MessageReflectionFriend::ContainsMapKey( - reflection, *message, map_field, map_key)); + auto map = reflection->GetMap(*message, map_field); + return PyBool_FromLong(map.ok() && map->contains(map_key)); } case Descriptor::WELLKNOWNTYPE_LISTVALUE: { // For WKT ListValue, check if the key is in the items.
diff --git a/src/google/protobuf/BUILD.bazel b/src/google/protobuf/BUILD.bazel index 3d74021..4bfbfe4 100644 --- a/src/google/protobuf/BUILD.bazel +++ b/src/google/protobuf/BUILD.bazel
@@ -1897,7 +1897,11 @@ "@abseil-cpp//absl/base:log_severity", "@abseil-cpp//absl/container:flat_hash_map", "@abseil-cpp//absl/flags:flag", + "@abseil-cpp//absl/functional:overload", "@abseil-cpp//absl/log:absl_check", + "@abseil-cpp//absl/log:absl_log", + "@abseil-cpp//absl/status:status_matchers", + "@abseil-cpp//absl/status:statusor", "@abseil-cpp//absl/strings", "@abseil-cpp//absl/time", "@abseil-cpp//absl/types:optional", @@ -2531,6 +2535,8 @@ "@abseil-cpp//absl/log:globals", "@abseil-cpp//absl/random", "@abseil-cpp//absl/random:distributions", + "@abseil-cpp//absl/status:status_matchers", + "@abseil-cpp//absl/status:statusor", "@abseil-cpp//absl/strings", "@abseil-cpp//absl/strings:str_format", "@abseil-cpp//absl/time",
diff --git a/src/google/protobuf/generated_message_reflection.cc b/src/google/protobuf/generated_message_reflection.cc index 9a6ff3a..bb4863c 100644 --- a/src/google/protobuf/generated_message_reflection.cc +++ b/src/google/protobuf/generated_message_reflection.cc
@@ -31,6 +31,8 @@ #include "absl/container/flat_hash_set.h" #include "absl/log/absl_check.h" #include "absl/log/absl_log.h" +#include "absl/status/status.h" +#include "absl/status/statusor.h" #include "absl/strings/ascii.h" #include "absl/strings/numbers.h" #include "absl/strings/str_cat.h" @@ -311,21 +313,40 @@ } } +absl::Status ReflectionUsageError(const Descriptor* descriptor, + const FieldDescriptor* field, + absl::string_view method, + absl::string_view description) { + return absl::InvalidArgumentError(absl::StrCat( + "Protocol Buffer reflection usage error:\n" + " Method : google::protobuf::Reflection::", + method, "\n", " Message type: ", + descriptor != nullptr ? descriptor->full_name() : "null", "\n", + " Field : ", field != nullptr ? field->full_name() : "null", "\n", + " Problem : ", description)); +} + void ReportReflectionUsageError(const Descriptor* descriptor, const FieldDescriptor* field, const char* method, const char* description) { - ABSL_LOG(FATAL) << "Protocol Buffer reflection usage error:\n" - " Method : google::protobuf::Reflection::" - << method - << "\n" - " Message type: " - << descriptor->full_name() - << "\n" - " Field : " - << field->full_name() - << "\n" - " Problem : " - << description; + ABSL_LOG(FATAL) << ReflectionUsageError(descriptor, field, method, + description); +} + +absl::Status ReflectionUsageMessageError(const Descriptor* expected, + const Descriptor* actual, + const FieldDescriptor* field, + absl::string_view method) { + return absl::InvalidArgumentError(absl::StrFormat( + "Protocol Buffer reflection usage error:\n" + " Method : google::protobuf::Reflection::%s\n" + " Expected type: %s\n" + " Actual type : %s\n" + " Field : %s\n" + " Problem : Message is not the right object for reflection", + method, expected != nullptr ? expected->full_name() : "null", + actual != nullptr ? actual->full_name() : "null", + field != nullptr ? field->full_name() : "n/a")); } #ifndef NDEBUG @@ -333,15 +354,8 @@ const Descriptor* actual, const FieldDescriptor* field, const char* method) { - ABSL_LOG(FATAL) << absl::StrFormat( - "Protocol Buffer reflection usage error:\n" - " Method : google::protobuf::Reflection::%s\n" - " Expected type: %s\n" - " Actual type : %s\n" - " Field : %s\n" - " Problem : Message is not the right object for reflection", - method, expected->full_name(), actual->full_name(), - (field != nullptr ? field->full_name() : "n/a")); + ABSL_LOG(FATAL) << ReflectionUsageMessageError(expected, actual, field, + method); } #endif @@ -1524,7 +1538,7 @@ } else { // No need to materialize the repeated field if it is out of sync: // its size will be the same as the map's size. - return map.size(); + return static_cast<int>(map.GetMap().size()); } } else { return GetRaw<RepeatedPtrFieldBase>(message, field).size(); @@ -2568,6 +2582,8 @@ const internal::ClassData* Reflection::GetMessageClassData( const FieldDescriptor* field) const { + ABSL_DCHECK_EQ(descriptor_, field->containing_type()) + << field->full_name() << " " << descriptor_->full_name(); // If we are using the generated factory, we cache the prototype in the field // descriptor for faster access. // The default instances of generated messages are not cross-linked, which @@ -2948,7 +2964,7 @@ } else { // No need to materialize the repeated field if it is out of sync: // its size will be the same as the map's size. - return map.size() == 0; + return map.GetMap().empty(); } } else { return GetRaw<RepeatedPtrFieldBase>(message, field).empty(); @@ -3033,77 +3049,150 @@ bool Reflection::ContainsMapKey(const Message& message, const FieldDescriptor* field, const MapKey& key) const { - USAGE_CHECK(IsMapFieldInApi(field), LookupMapValue, - "Field is not a map field."); - return GetRaw<MapFieldBase>(message, field).ContainsMapKey(key); + auto map = GetMap(message, field); + return map.ok() && map->contains(key); } bool Reflection::InsertOrLookupMapValue(Message* message, const FieldDescriptor* field, const MapKey& key, MapValueRef* val) const { - USAGE_CHECK(IsMapFieldInApi(field), InsertOrLookupMapValue, - "Field is not a map field."); - val->SetType(field->message_type()->map_value()->cpp_type()); - SetHasBit(message, field); - return MutableRaw<MapFieldBase>(message, field) - ->InsertOrLookupMapValue(key, val); + auto map = MutableMap(message, field); + if (!map.ok()) return false; + auto res = map->try_emplace(key); + if (!res.ok()) return false; + if (val != nullptr) *val = res->iter->value(); + return res->inserted; } bool Reflection::LookupMapValue(const Message& message, const FieldDescriptor* field, const MapKey& key, MapValueConstRef* val) const { - USAGE_CHECK(IsMapFieldInApi(field), LookupMapValue, - "Field is not a map field."); - val->SetType(field->message_type()->map_value()->cpp_type()); - return GetRaw<MapFieldBase>(message, field).LookupMapValue(key, val); + auto map = GetMap(message, field); + if (!map.ok()) return false; + auto it = map->find(key); + if (it != map->end()) { + if (val != nullptr) *val = it->value(); + return true; + } + return false; } bool Reflection::DeleteMapValue(Message* message, const FieldDescriptor* field, const MapKey& key) const { - USAGE_CHECK(IsMapFieldInApi(field), DeleteMapValue, - "Field is not a map field."); - return MutableRaw<MapFieldBase>(message, field) - ->DeleteMapValue(message->GetArena(), key); + auto map = MutableMap(message, field); + if (!map.ok()) return false; + return map->erase(key); } -MapIterator Reflection::MapBegin(Message* message, - const FieldDescriptor* field) const { - USAGE_CHECK(IsMapFieldInApi(field), MapBegin, "Field is not a map field."); - MapIterator iter(message, field); - GetRaw<MapFieldBase>(*message, field).MapBegin(&iter); - return iter; -} - -MapIterator Reflection::MapEnd(Message* message, - const FieldDescriptor* field) const { - USAGE_CHECK(IsMapFieldInApi(field), MapEnd, "Field is not a map field."); - MapIterator iter(message, field); - GetRaw<MapFieldBase>(*message, field).MapEnd(&iter); - return iter; -} - +PROTOBUF_IGNORE_DEPRECATION_START ConstMapIterator Reflection::ConstMapBegin(const Message* message, const FieldDescriptor* field) const { - USAGE_CHECK(IsMapFieldInApi(field), ConstMapBegin, - "Field is not a map field."); - ConstMapIterator iter(message, field); - GetRaw<MapFieldBase>(*message, field).ConstMapBegin(&iter); - return iter; + auto map = GetMap(*message, field); + if (!map.ok()) return ConstMapIterator(); + return map->begin(); } ConstMapIterator Reflection::ConstMapEnd(const Message* message, const FieldDescriptor* field) const { - USAGE_CHECK(IsMapFieldInApi(field), ConstMapEnd, "Field is not a map field."); - ConstMapIterator iter(message, field); - GetRaw<MapFieldBase>(*message, field).ConstMapEnd(&iter); - return iter; + auto map = GetMap(*message, field); + if (!map.ok()) return ConstMapIterator(); + return map->end(); +} +PROTOBUF_IGNORE_DEPRECATION_STOP + +static absl::Status CheckUsage(const Reflection* reflection, + const Descriptor* descriptor, + const Message* message, + const FieldDescriptor* field, + absl::string_view method) { + if (ABSL_PREDICT_FALSE(message == nullptr)) { + return ReflectionUsageError(descriptor, field, method, + "Message pointer is null."); + } + if (ABSL_PREDICT_FALSE(field == nullptr)) { + return ReflectionUsageError(descriptor, nullptr, method, + "FieldDescriptor is null."); + } + if (ABSL_PREDICT_FALSE(reflection != message->GetReflection())) { + return ReflectionUsageMessageError(descriptor, message->GetDescriptor(), + field, method); + } + if (ABSL_PREDICT_FALSE(field->containing_type() != descriptor)) { + return ReflectionUsageError(descriptor, field, method, + "Field does not match message type."); + } + return absl::OkStatus(); +} + +static absl::Status CheckMapUsage(const Reflection* reflection, + const Descriptor* descriptor, + const Message* message, + const FieldDescriptor* field, + absl::string_view method) { + if (auto usage = CheckUsage(reflection, descriptor, message, field, method); + !usage.ok()) { + return usage; + } + if (ABSL_PREDICT_FALSE(!field->is_map())) { + return ReflectionUsageError( + descriptor, field, method, + "Field is singular or repeated; the method requires a map field."); + } + return absl::OkStatus(); +} + +const internal::ClassData* Reflection::GetClassDataForMapMessageValueType( + const FieldDescriptor* field, const internal::UntypedMapBase& map) const { + if (field->message_type()->map_value()->message_type() == nullptr) { + return nullptr; + } + if (!map.empty()) { + // If the map has elements, use it to get the prototype. + return internal::GetClassData(*DownCastMessage<Message>( + map.GetValue<MessageLite>(map.begin().node_))); + } else { + // Otherwise, fall back to reflection get it which is a bit more work. + auto* map_entry_prototype = DownCastMessage<Message>( + GetMessageClassData(field)->default_instance()); + return map_entry_prototype->GetReflection()->GetMessageClassData( + map_entry_prototype->GetDescriptor()->map_value()); + } +} + +absl::StatusOr<GenericMapRef> Reflection::MutableMap( + Message* message, const FieldDescriptor* field) const { + if (auto status = + CheckMapUsage(this, descriptor_, message, field, "MutableMap"); + ABSL_PREDICT_FALSE(!status.ok())) { + return status; + } + GenericMapRef ref; + ref.key_type_ = field->message_type()->map_key()->cpp_type(); + ref.value_type_ = field->message_type()->map_value()->cpp_type(); + ref.map_ = MutableMapData(message, field)->MutableMap(); + ref.value_class_data_ = GetClassDataForMapMessageValueType(field, *ref.map_); + return ref; +} + +absl::StatusOr<GenericConstMapRef> Reflection::GetMap( + const Message& message, const FieldDescriptor* field) const { + if (auto status = CheckMapUsage(this, descriptor_, &message, field, "GetMap"); + ABSL_PREDICT_FALSE(!status.ok())) { + return status; + } + GenericConstMapRef ref; + ref.key_type_ = field->message_type()->map_key()->cpp_type(); + ref.value_type_ = field->message_type()->map_value()->cpp_type(); + ref.map_ = &GetMapData(message, field)->GetMap(); + ref.value_class_data_ = GetClassDataForMapMessageValueType(field, *ref.map_); + return ref; } int Reflection::MapSize(const Message& message, const FieldDescriptor* field) const { - USAGE_CHECK(IsMapFieldInApi(field), MapSize, "Field is not a map field."); - return GetRaw<MapFieldBase>(message, field).size(); + auto map = GetMap(message, field); + return map.ok() ? static_cast<int>(map->size()) : 0; } // ----------------------------------------------------------------------------- @@ -4136,12 +4225,14 @@ const auto& map = reflection->GetRaw<MapFieldBase>(root, field); if (map.IsMapValid()) { - const auto end = reflection->ConstMapEnd(&root, field); - for (auto iter = reflection->ConstMapBegin(&root, field); iter != end; - ++iter) { - const Message& sub_message = iter.GetValueRef().GetMessageValue(); - if (&sub_message == &message || IsDescendant(sub_message, message)) { - return true; + auto map_or = reflection->GetMap(root, field); + if (map_or.ok()) { + for (auto entry : *map_or) { + const Message& sub_message = entry.value().GetMessageValue(); + if (&sub_message == &message || + IsDescendant(sub_message, message)) { + return true; + } } }
diff --git a/src/google/protobuf/json/internal/unparser.cc b/src/google/protobuf/json/internal/unparser.cc index aef2359..0405904 100644 --- a/src/google/protobuf/json/internal/unparser.cc +++ b/src/google/protobuf/json/internal/unparser.cc
@@ -370,9 +370,9 @@ if (Traits::MapFieldUseMapReflection(field, msg)) { RETURN_IF_ERROR(Traits::ForEachMapEntry( - field, msg, [&](auto it, const auto& type) -> absl::Status { + field, msg, [&](auto entry, const auto& type) -> absl::Status { auto is_empty = - IsEmptyValue<Traits>(it.GetValueRef(), Traits::ValueField(type)); + IsEmptyValue<Traits>(entry.value(), Traits::ValueField(type)); RETURN_IF_ERROR(is_empty.status()); if (*is_empty) { // Empty google.protobuf.Values are silently discarded. @@ -382,11 +382,11 @@ writer.WriteComma(first); writer.NewLine(); RETURN_IF_ERROR( - WriteMapKey<Traits>(writer, it.GetKey(), Traits::KeyField(type))); + WriteMapKey<Traits>(writer, entry.key(), Traits::KeyField(type))); writer.Write(":"); writer.Whitespace(" "); RETURN_IF_ERROR(WriteSingular<Traits>( - writer, Traits::ValueField(type), it.GetValueRef())); + writer, Traits::ValueField(type), entry.value())); return absl::OkStatus(); })); } else {
diff --git a/src/google/protobuf/json/internal/unparser_traits.h b/src/google/protobuf/json/internal/unparser_traits.h index 290821b..408995f 100644 --- a/src/google/protobuf/json/internal/unparser_traits.h +++ b/src/google/protobuf/json/internal/unparser_traits.h
@@ -297,10 +297,9 @@ static absl::Status ForEachMapEntry(Field f, const Msg& msg, Func func) { ABSL_DCHECK(MapFieldUseMapReflection(f, msg)); const auto& type = *f->message_type(); - for (auto it = msg.GetReflection()->ConstMapBegin(&msg, f), - end = msg.GetReflection()->ConstMapEnd(&msg, f); - it != end; ++it) { - RETURN_IF_ERROR(func(it, type)); + ASSIGN_OR_RETURN(auto map, msg.GetReflection()->GetMap(msg, f)); + for (auto entry : map) { + RETURN_IF_ERROR(func(entry, type)); } return absl::OkStatus(); }
diff --git a/src/google/protobuf/map.h b/src/google/protobuf/map.h index f8090bd..5b7bead 100644 --- a/src/google/protobuf/map.h +++ b/src/google/protobuf/map.h
@@ -7,9 +7,9 @@ // This file defines the map container and its helpers to support protobuf maps. // -// The Map and MapIterator types are provided by this header file. +// The Map type is provided by this header file. // Please avoid using other types defined here, unless they are public -// types within Map or MapIterator, such as Map::value_type. +// types within Map, such as Map::value_type. #ifndef GOOGLE_PROTOBUF_MAP_H__ #define GOOGLE_PROTOBUF_MAP_H__ @@ -58,7 +58,8 @@ template <typename Key, typename T> class Map; -class MapIterator; +class ABSL_ATTRIBUTE_VIEW GenericMapRef; +class ABSL_ATTRIBUTE_VIEW GenericConstMapRef; template <typename Enum> struct is_proto_enum; @@ -413,6 +414,7 @@ friend struct MapBenchmarkPeer; friend class UntypedMapIterator; friend class RustMapHelper; + friend GenericMapRef; // Calls `f(type_t)` where `type_t` is an unspecified type that has a `::type` // typedef in it representing the dynamic type of key/value of the node. @@ -612,7 +614,7 @@ // code, since that would bring in Message too. class MapFieldBaseForParse { public: - const UntypedMapBase& GetMap() const { + const UntypedMapBase& GetMap() const ABSL_ATTRIBUTE_LIFETIME_BOUND { const void* p = globals_or_payload_.load(std::memory_order_acquire); // If this instance has a payload, then it might need sync'n. if (ABSL_PREDICT_FALSE(IsPayload(p))) { @@ -621,7 +623,7 @@ return GetMapRaw(); } - UntypedMapBase* MutableMap() { + UntypedMapBase* MutableMap() ABSL_ATTRIBUTE_LIFETIME_BOUND { const void* p = globals_or_payload_.load(std::memory_order_acquire); // If this instance has a payload, then it might need sync'n. if (ABSL_PREDICT_FALSE(IsPayload(p))) { @@ -734,6 +736,8 @@ friend struct MapTestPeer; friend struct MapBenchmarkPeer; friend class RustMapHelper; + friend GenericMapRef; + friend GenericConstMapRef; Key* GetKey(NodeBase* node) const { return UntypedMapBase::GetKey<Key>(node);
diff --git a/src/google/protobuf/map_field.cc b/src/google/protobuf/map_field.cc index b599b8f..e06b05d 100644 --- a/src/google/protobuf/map_field.cc +++ b/src/google/protobuf/map_field.cc
@@ -12,9 +12,12 @@ #include <cstdint> #include <string> #include <type_traits> +#include <utility> #include "absl/functional/overload.h" #include "absl/log/absl_check.h" +#include "absl/status/status.h" +#include "absl/status/statusor.h" #include "absl/synchronization/mutex.h" #include "google/protobuf/arena.h" #include "google/protobuf/descriptor.h" @@ -80,119 +83,10 @@ } } -bool MapFieldBase::InsertOrLookupMapValueNoSync(const MapKey& map_key, - MapValueRef* val) { - if (LookupMapValueNoSync(map_key, static_cast<MapValueConstRef*>(val))) { - return false; - } - - auto& map = GetMapRaw(); - Arena* arena = map.arena(); - - NodeBase* node = map.AllocNode(arena); - map.VisitValue(node, [&](auto* v) { InitializeKeyValue(v); }); - val->SetValue(map.GetVoidValue(node)); - - return VisitMapKey(map_key, map, [&](auto& map, const auto& key) { - InitializeKeyValue(map.GetKey(node), key); - map.InsertOrReplaceNode( - arena, - static_cast<typename std::decay_t<decltype(map)>::KeyNode*>(node)); - return true; - }); -} - -bool MapFieldBase::DeleteMapValue(Arena* arena, const MapKey& map_key) { - return VisitMapKey(map_key, *MutableMap(), - [arena](auto& map, const auto& key) { - return map.EraseImpl(arena, key); - }); -} - void MapFieldBase::ClearMapNoSync() { GetMapRaw().ClearTable(arena(), /*reset=*/true); } -template <bool kIsMutable> -void MapFieldBase::SetMapIteratorValue( - MapIteratorBase<kIsMutable>* map_iter) const { - if (map_iter->iter_.Equals(UntypedMapBase::EndIterator())) return; - - const UntypedMapBase& map = *map_iter->iter_.m_; - NodeBase* node = map_iter->iter_.node_; - auto& key = map_iter->key_; - map.VisitKey(node, - absl::Overload{ - [&](const std::string* v) { key.val_.string_value = *v; }, - [&](const auto* v) { - // Memcpy the scalar into the union. - memcpy(static_cast<void*>(&key.val_), v, sizeof(*v)); - }, - }); - map_iter->value_.SetValue(map.GetVoidValue(node)); -} - -bool MapFieldBase::LookupMapValueNoSync(const MapKey& map_key, - MapValueConstRef* val) const { - auto& map = GetMapRaw(); - if (map.empty()) return false; - - return VisitMapKey(map_key, map, [&](auto& map, const auto& key) { - auto res = map.FindHelper(key); - if (res.node == nullptr) { - return false; - } - if (val != nullptr) { - val->SetValue(map.GetVoidValue(res.node)); - } - return true; - }); -} - -void MapFieldBase::MapBegin(MapIterator* map_iter) const { - map_iter->iter_ = GetMap().begin(); - SetMapIteratorValue(map_iter); -} - -void MapFieldBase::MapEnd(MapIterator* map_iter) const { - map_iter->iter_ = UntypedMapBase::EndIterator(); -} - -void MapFieldBase::ConstMapBegin(ConstMapIterator* map_iter) const { - map_iter->iter_ = GetMap().begin(); - SetMapIteratorValue(map_iter); -} - -void MapFieldBase::ConstMapEnd(ConstMapIterator* map_iter) const { - map_iter->iter_ = UntypedMapBase::EndIterator(); -} - -template <bool kIsMutable> -bool MapFieldBase::EqualIterator(const MapIteratorBase<kIsMutable>& a, - const MapIteratorBase<kIsMutable>& b) const { - return a.iter_.Equals(b.iter_); -} - -template <bool kIsMutable> -void MapFieldBase::IncreaseIterator( - MapIteratorBase<kIsMutable>* map_iter) const { - map_iter->iter_.PlusPlus(); - SetMapIteratorValue(map_iter); -} - -template <bool kIsMutable> -void MapFieldBase::CopyIterator( - MapIteratorBase<kIsMutable>* this_iter, - const MapIteratorBase<kIsMutable>& that_iter) const { - this_iter->iter_ = that_iter.iter_; - this_iter->key_.SetType(that_iter.key_.type()); - // MapValueRef::type() fails when containing data is null. However, if - // this_iter points to MapEnd, data can be null. - this_iter->value_.SetType( - static_cast<FieldDescriptor::CppType>(that_iter.value_.type_)); - SetMapIteratorValue(this_iter); -} - const RepeatedPtrFieldBase& MapFieldBase::GetRepeatedField() const { ConstAccess(); return SyncRepeatedFieldWithMap(false); @@ -340,21 +234,22 @@ RepeatedPtrField<Message>& rep = payload().repeated_field(); rep.Clear(); - ConstMapIterator it(this, descriptor); - ConstMapIterator end(this, descriptor); - + GenericConstMapRef::iterator it; + it.key_type_ = descriptor->map_key()->cpp_type(); + it.value_type_ = descriptor->map_value()->cpp_type(); it.iter_ = GetMapRaw().begin(); - SetMapIteratorValue(&it); + + GenericConstMapRef::iterator end; end.iter_ = UntypedMapBase::EndIterator(); Arena* arena = this->arena(); - for (; !EqualIterator(it, end); IncreaseIterator(&it)) { + for (; it != end; ++it) { Message* new_entry = reinterpret_cast<Message*>( rep.AddInternal(arena, [prototype](Arena* arena, void*& ptr) { ptr = prototype->New(arena); })); - const MapKey& map_key = it.GetKey(); + MapKey map_key = it->key(); switch (key_des->cpp_type()) { case FieldDescriptor::CPPTYPE_STRING: reflection->SetString(new_entry, key_des, @@ -379,7 +274,7 @@ Unreachable(); } - const MapValueConstRef& map_val = it.GetValueRef(); + MapValueConstRef map_val = it->value(); switch (val_des->cpp_type()) { case FieldDescriptor::CPPTYPE_STRING: reflection->SetString(new_entry, val_des, @@ -450,6 +345,15 @@ const FieldDescriptor* key_des = descriptor->map_key(); const FieldDescriptor* val_des = descriptor->map_value(); + GenericMapRef map_ref; + map_ref.key_type_ = descriptor->map_key()->cpp_type(); + map_ref.value_type_ = descriptor->map_value()->cpp_type(); + map_ref.map_ = &GetMapRaw(); + if (descriptor->map_value()->message_type()) { + map_ref.value_class_data_ = + GetClassData(GetMapEntryValuePrototype(*prototype)); + } + for (const Message& elem : rep) { // MapKey type will be set later. Reflection::ScratchSpace map_key_scratch_space; @@ -478,9 +382,7 @@ Unreachable(); } - MapValueRef map_val; - map_val.SetType(val_des->cpp_type()); - InsertOrLookupMapValueNoSync(map_key, &map_val); + MapValueRef map_val = map_ref.try_emplace(map_key).value().iter->value(); switch (val_des->cpp_type()) { #define HANDLE_TYPE(CPPTYPE, METHOD) \ @@ -520,78 +422,212 @@ SetMapDirty(); } -int MapFieldBase::size() const { return GetMap().size(); } - -bool MapFieldBase::InsertOrLookupMapValue(const MapKey& map_key, - MapValueRef* val) { - SyncMapWithRepeatedField(); - SetMapDirty(); - return InsertOrLookupMapValueNoSync(map_key, val); -} - void MapFieldBase::ReflectionPayload::Swap(ReflectionPayload& other) { repeated_field().Swap(&other.repeated_field()); SwapRelaxed(state_, other.state_); } +MapKey MapIteratorEntry::key() const { + return MapConstIteratorEntry(*this).key(); +} + +MapValueRef MapIteratorEntry::value() const { + MapValueRef value; + value.SetType(static_cast<FieldDescriptor::CppType>(value_type_)); + value.SetValue(iter_.m_->GetVoidValue(iter_.node_)); + return value; +} + +MapKey MapConstIteratorEntry::key() const { + MapKey key; + key.SetType(static_cast<FieldDescriptor::CppType>(key_type_)); + iter_.m_->VisitKey( + iter_.node_, + absl::Overload{ + [&](const std::string* v) { key.val_.string_value = *v; }, + [&](const auto* v) { + // Memcpy the scalar into the union. + memcpy(static_cast<void*>(&key.val_), v, sizeof(*v)); + }, + }); + return key; +} + +MapValueConstRef MapConstIteratorEntry::value() const { + MapValueConstRef value; + value.SetType(static_cast<FieldDescriptor::CppType>(value_type_)); + value.SetValue(iter_.m_->GetVoidValue(iter_.node_)); + return value; +} + +static bool IsCompatibleKey(uint8_t expected_key_cpp_type, const MapKey& key) { + if (!key.is_initialized()) return false; + return key.type() == + static_cast<FieldDescriptor::CppType>(expected_key_cpp_type); +} + } // namespace internal -template <bool kIsMutable> -MapIteratorBase<kIsMutable>::MapIteratorBase(MessageT* message, - const FieldDescriptor* field) { - const Reflection* reflection = message->GetReflection(); - if constexpr (kIsMutable) { - map_ = reflection->MutableMapData(message, field); - } else { - map_ = reflection->GetMapData(*message, field); +GenericMapRef::iterator GenericMapRef::begin() const { + iterator iter; + iter.key_type_ = key_type_; + iter.value_type_ = value_type_; + iter.iter_ = map_->begin(); + return iter; +} + +GenericMapRef::iterator GenericMapRef::end() const { + iterator iter; + iter.iter_ = internal::UntypedMapBase::EndIterator(); + return iter; +} + +size_t GenericMapRef::size() const { return map_->size(); } + +bool GenericMapRef::empty() const { return size() == 0; } + +bool GenericMapRef::contains(const MapKey& key) const { + return find(key) != end(); +} + +GenericMapRef::iterator GenericMapRef::find(const MapKey& key) const { + auto it = GenericConstMapRef(*this).find(key); + iterator res; + res.key_type_ = key_type_; + res.value_type_ = value_type_; + res.iter_ = it.iter_; + return res; +} + +absl::Status GenericMapRef::assign(const GenericConstMapRef& other) const { + auto status = GenericConstMapRef::CheckSameType(*this, other); + if (!status.ok()) return status; + if (map_ == other.map_) return absl::OkStatus(); + clear(); + map_->UntypedMergeFrom(map_->arena(), *other.map_); + return absl::OkStatus(); +} + +absl::Status GenericMapRef::swap(const GenericMapRef& other) const { + auto status = GenericConstMapRef::CheckSameType(*this, other); + if (!status.ok()) return status; + map_->UntypedSwap(map_->arena(), *other.map_, other.map_->arena()); + return absl::OkStatus(); +} + +void GenericMapRef::clear() const { + map_->ClearTable(map_->arena(), /*reset=*/true); +} + +size_t GenericMapRef::erase(const MapKey& key) const { + if (!internal::IsCompatibleKey(key_type_, key)) return 0; + return internal::VisitMapKey(key, *map_, [](auto& map, const auto& key) { + return map.EraseImpl(map.arena(), key) ? 1 : 0; + }); +} + +absl::StatusOr<GenericMapRef::InsertResult> GenericMapRef::try_emplace( + const MapKey& key) const { + if (!internal::IsCompatibleKey(key_type_, key)) { + return absl::InvalidArgumentError( + "MapKey is uninitialized or key type mismatch."); } - key_.SetType(field->message_type()->map_key()->cpp_type()); - value_.SetType(field->message_type()->map_value()->cpp_type()); + + InsertResult res; + res.iter.key_type_ = key_type_; + res.iter.value_type_ = value_type_; + res.iter.iter_.m_ = map_; + + if (!map_->empty()) { + auto find_res = internal::VisitMapKey( + key, *map_, + [&](auto& map, const auto& key) { return map.FindHelper(key); }); + if (find_res.node != nullptr) { + res.iter.iter_.node_ = find_res.node; + res.iter.iter_.bucket_index_ = find_res.bucket; + res.inserted = false; + return res; + } + } + + Arena* arena = map_->arena(); + auto* node = map_->AllocNode(arena); + map_->VisitValue(node, [&](auto* v) { InitializeKeyValue(v); }); + res.inserted = true; + res.iter.iter_.node_ = node; + res.iter.iter_.bucket_index_ = 0; + + internal::VisitMapKey(key, *map_, [&](auto& map, const auto& key) { + InitializeKeyValue(map.GetKey(node), key); + // Note: If we see enough usage of this we might want to refactor to avoid a + // second lookup here. + map.InsertOrReplaceNode( + arena, + static_cast<typename std::decay_t<decltype(map)>::KeyNode*>(node)); + }); + + return res; } -template <bool kIsMutable> -MapIteratorBase<kIsMutable>& MapIteratorBase<kIsMutable>::operator=( - const MapIteratorBase& other) { - map_ = other.map_; - map_->CopyIterator(this, other); - return *this; +absl::Status GenericConstMapRef::CheckSameType(const GenericConstMapRef& a, + const GenericConstMapRef& b) { + if (a.key_type_ != b.key_type_ || a.value_type_ != b.value_type_) { + return absl::InvalidArgumentError("Map key or value CppType mismatch."); + } + if (a.value_class_data_ != b.value_class_data_) { + return absl::InvalidArgumentError("Map value message prototype mismatch."); + } + return absl::OkStatus(); } -template <bool kIsMutable> -bool MapIteratorBase<kIsMutable>::operator==( - const MapIteratorBase<kIsMutable>& other) const { - return map_->EqualIterator(*this, other); +GenericConstMapRef::iterator GenericConstMapRef::begin() const { + iterator iter; + iter.key_type_ = key_type_; + iter.value_type_ = value_type_; + iter.iter_ = map_->begin(); + return iter; } -template <bool kIsMutable> -typename MapIteratorBase<kIsMutable>::DerivedIterator& -MapIteratorBase<kIsMutable>::operator++() { - map_->IncreaseIterator(this); - return static_cast<DerivedIterator&>(*this); +GenericConstMapRef::iterator GenericConstMapRef::end() const { + iterator iter; + iter.iter_ = internal::UntypedMapBase::EndIterator(); + return iter; } -template <bool kIsMutable> -typename MapIteratorBase<kIsMutable>::DerivedIterator -MapIteratorBase<kIsMutable>::operator++(int) { - // iter_ is copied from Map<...>::iterator, no need to - // copy from its self again. Use the same implementation - // with operator++() - map_->IncreaseIterator(this); - return *static_cast<DerivedIterator*>(this); +size_t GenericConstMapRef::size() const { return map_->size(); } + +bool GenericConstMapRef::empty() const { return size() == 0; } + +bool GenericConstMapRef::contains(const MapKey& key) const { + return find(key) != end(); } -template <bool kIsMutable> -MapIteratorBase<kIsMutable>::MapIteratorBase(MapFieldBase* map, - const Descriptor* descriptor) { - map_ = map; - key_.SetType(descriptor->map_key()->cpp_type()); - value_.SetType(descriptor->map_value()->cpp_type()); -} +GenericConstMapRef::iterator GenericConstMapRef::find( + const MapKey& map_key) const { + iterator res; + res.key_type_ = key_type_; + res.value_type_ = value_type_; -template class PROTOBUF_EXPORT_TEMPLATE_DEFINE - MapIteratorBase</*kIsMutable=*/false>; -template class PROTOBUF_EXPORT_TEMPLATE_DEFINE - MapIteratorBase</*kIsMutable=*/true>; + if (map_->empty() || !internal::IsCompatibleKey(key_type_, map_key)) { + res.iter_ = internal::UntypedMapBase::EndIterator(); + return res; + } + + res.iter_ = + internal::VisitMapKey(map_key, *map_, [&](auto& map, const auto& key) { + auto res = map.FindHelper(key); + if (res.node == nullptr) { + return internal::UntypedMapBase::EndIterator(); + } + internal::UntypedMapIterator iter; + iter.node_ = res.node; + iter.bucket_index_ = res.bucket; + iter.m_ = ↦ + return iter; + }); + + return res; +} } // namespace protobuf } // namespace google
diff --git a/src/google/protobuf/map_field.h b/src/google/protobuf/map_field.h index cf8a1bb..f6d6db3 100644 --- a/src/google/protobuf/map_field.h +++ b/src/google/protobuf/map_field.h
@@ -11,12 +11,16 @@ #include <atomic> #include <cstddef> #include <cstdint> +#include <iterator> #include <string> #include <type_traits> #include <utility> +#include "absl/base/attributes.h" #include "absl/log/absl_check.h" #include "absl/log/absl_log.h" +#include "absl/status/status.h" +#include "absl/status/statusor.h" #include "absl/strings/string_view.h" #include "absl/synchronization/mutex.h" #include "google/protobuf/arena.h" @@ -45,12 +49,12 @@ namespace google { namespace protobuf { class DynamicMessage; -template <bool> -class MapIteratorBase; -class ConstMapIterator; -class MapIterator; namespace internal { +class ABSL_ATTRIBUTE_VIEW MapConstIterator; +class ABSL_ATTRIBUTE_VIEW MapConstIteratorEntry; +class ABSL_ATTRIBUTE_VIEW MapIterator; +class ABSL_ATTRIBUTE_VIEW MapIteratorEntry; class MapFieldBase; } @@ -74,12 +78,14 @@ // MapKey is an union type for representing any possible map key. For strings, // map key does not own the underlying data. It is up to the caller to ensure // any supplied strings outlive any instance of this class. -class PROTOBUF_EXPORT MapKey { +class PROTOBUF_EXPORT ABSL_ATTRIBUTE_VIEW MapKey { public: MapKey() = default; MapKey(const MapKey&) = default; MapKey& operator=(const MapKey&) = default; + bool is_initialized() const { return type_ != FieldDescriptor::CppType(); } + FieldDescriptor::CppType type() const { if (type_ == FieldDescriptor::CppType()) { ABSL_LOG(FATAL) << "Protocol Buffer map usage error:\n" @@ -233,8 +239,7 @@ template <typename K, typename V> friend class internal::TypeDefinedMapFieldBase; friend class internal::MapFieldBase; - template <bool> - friend class MapIteratorBase; + friend internal::MapConstIteratorEntry; template <typename H> friend auto AbslHashValue(H state, const MapKey& key) { @@ -279,13 +284,6 @@ namespace internal { -template <> -struct is_internal_map_key_type<MapKey> : std::true_type {}; - -} // namespace internal - -namespace internal { - class ContendedMapCleanTest; class GeneratedMessageReflection; class MapFieldAccessor; @@ -340,40 +338,14 @@ PROTOBUF_FUTURE_ADD_EARLY_NODISCARD RepeatedPtrFieldBase* MutableRepeatedField(); - PROTOBUF_FUTURE_ADD_EARLY_NODISCARD bool ContainsMapKey( - const MapKey& map_key) const { - return LookupMapValue(map_key, static_cast<MapValueConstRef*>(nullptr)); - } - PROTOBUF_FUTURE_ADD_EARLY_NODISCARD bool LookupMapValue( - const MapKey& map_key, MapValueConstRef* val) const { - SyncMapWithRepeatedField(); - return LookupMapValueNoSync(map_key, val); - } - bool LookupMapValue(const MapKey&, MapValueRef*) const = delete; - - bool InsertOrLookupMapValue(const MapKey& map_key, MapValueRef* val); - // Returns whether changes to the map are reflected in the repeated field. PROTOBUF_FUTURE_ADD_EARLY_NODISCARD bool IsRepeatedFieldValid() const; // Insures operations after won't get executed before calling this. PROTOBUF_FUTURE_ADD_EARLY_NODISCARD bool IsMapValid() const; - bool DeleteMapValue(Arena* arena, const MapKey& map_key); void MergeFrom(Arena* arena, const MapFieldBase& other); void Swap(Arena* arena, MapFieldBase* other, Arena* other_arena); void InternalSwap(MapFieldBase* other); - // Sync Map with repeated field and returns the size of map. - PROTOBUF_FUTURE_ADD_EARLY_NODISCARD int size() const; void Clear(); - template <bool kIsMutable> - void SetMapIteratorValue(MapIteratorBase<kIsMutable>* map_iter) const; - - void MapBegin(MapIterator* map_iter) const; - void MapEnd(MapIterator* map_iter) const; - void ConstMapBegin(ConstMapIterator* map_iter) const; - void ConstMapEnd(ConstMapIterator* map_iter) const; - template <bool kIsMutable> - bool EqualIterator(const MapIteratorBase<kIsMutable>& a, - const MapIteratorBase<kIsMutable>& b) const; // Returns the number of bytes used by the repeated field, excluding // sizeof(*this) @@ -416,8 +388,6 @@ // Provides derived class the access to repeated field. void* MutableRepeatedPtrField() const; - bool InsertOrLookupMapValueNoSync(const MapKey& map_key, MapValueRef* val); - // Support thread sanitizer (tsan) by making const / mutable races // more apparent. If one thread calls MutableAccess() while another // thread calls either ConstAccess() or MutableAccess(), on the same @@ -501,41 +471,6 @@ friend class google::protobuf::Reflection; friend class google::protobuf::DynamicMessage; - template <typename T, typename... U> - void InitializeKeyValue(T* v, const U&... init) { - ::new (static_cast<void*>(v)) T(init...); - if constexpr (std::is_same_v<std::string, T>) { - if (arena() != nullptr) { - arena()->OwnDestructor(v); - } - } - } - - void InitializeKeyValue(MessageLite* msg) { - GetClassData(GetMapEntryValuePrototype(*GetPrototype())) - ->PlacementNew(msg, arena()); - } - - // Virtual helper methods for MapIterator. MapIterator doesn't have the - // type helper for key and value. Call these help methods to deal with - // different types. Real helper methods are implemented in - // TypeDefinedMapFieldBase. - template <bool> - friend class google::protobuf::MapIteratorBase; - friend class google::protobuf::MapIterator; - - // Copy the map<...>::iterator from other_iterator to - // this_iterator. - template <bool kIsMutable> - void CopyIterator(MapIteratorBase<kIsMutable>* this_iter, - const MapIteratorBase<kIsMutable>& that_iter) const; - - // IncreaseIterator() is called by operator++() of MapIterator only. - // It implements the ++ operator of MapIterator. - template <bool kIsMutable> - void IncreaseIterator(MapIteratorBase<kIsMutable>* map_iter) const; - - bool LookupMapValueNoSync(const MapKey& map_key, MapValueConstRef* val) const; static ReflectionPayload* ToPayload(const void* p) { ABSL_DCHECK(IsPayload(p)); auto* res = reinterpret_cast<ReflectionPayload*>( @@ -687,7 +622,7 @@ // MapValueConstRef points to a map value. Users can NOT modify // the map value. -class PROTOBUF_EXPORT MapValueConstRef { +class PROTOBUF_EXPORT ABSL_ATTRIBUTE_VIEW MapValueConstRef { public: MapValueConstRef() : data_(nullptr), type_() {} @@ -751,37 +686,27 @@ } protected: + friend internal::MapConstIteratorEntry; + friend internal::MapIteratorEntry; + + void SetType(FieldDescriptor::CppType type) { type_ = type; } + void SetValue(const void* val) { + ABSL_DCHECK_NE(static_cast<int>(type_), 0); + data_ = const_cast<void*>(val); + } + // data_ point to a map value. MapValueConstRef does not // own this value. void* data_; // type_ is 0 or a valid FieldDescriptor::CppType. // Use "CppType()" to indicate zero. - FieldDescriptor::CppType type_; - - private: - template <auto* kGlobals, typename K, typename V> - friend class internal::MapField; - template <typename K, typename V> - friend class internal::TypeDefinedMapFieldBase; - template <bool> - friend class google::protobuf::MapIteratorBase; - friend class Reflection; - friend class internal::MapFieldBase; - - void SetValueOrCopy(const void* val) { SetValue(val); } - void SetValueOrCopy(const MapValueConstRef* val) { CopyFrom(*val); } - - void SetType(FieldDescriptor::CppType type) { type_ = type; } - void SetValue(const void* val) { data_ = const_cast<void*>(val); } - void CopyFrom(const MapValueConstRef& other) { - type_ = other.type_; - data_ = other.data_; - } + FieldDescriptor::CppType type_{}; }; // MapValueRef points to a map value. Users are able to modify // the map value. -class PROTOBUF_EXPORT MapValueRef final : public MapValueConstRef { +class PROTOBUF_EXPORT ABSL_ATTRIBUTE_VIEW MapValueRef final + : public MapValueConstRef { public: MapValueRef() = default; @@ -828,104 +753,326 @@ "MapValueRef::MutableMessageValue"); return reinterpret_cast<Message*>(data_); } + + private: + friend internal::MapIteratorEntry; }; #undef TYPE_CHECK -template <bool kIsMutable> -class MapIteratorBase { - using MessageT = - std::conditional_t<kIsMutable, google::protobuf::Message, const google::protobuf::Message>; - using MapFieldBase = std::conditional_t<kIsMutable, internal::MapFieldBase, - const internal::MapFieldBase>; - using ValueRef = - std::conditional_t<kIsMutable, MapValueRef, MapValueConstRef>; - using DerivedIterator = - std::conditional_t<kIsMutable, MapIterator, ConstMapIterator>; +namespace internal { +class PROTOBUF_EXPORT ABSL_ATTRIBUTE_VIEW MapIteratorEntry final { public: - MapIteratorBase(MessageT* message, const FieldDescriptor* field); - MapIteratorBase(const MapIteratorBase& other) { *this = other; } + using key_type = MapKey; + using mapped_type = MapValueRef; - MapIteratorBase& operator=(const MapIteratorBase& other); + MapIteratorEntry(const MapIteratorEntry&) = default; + MapIteratorEntry& operator=(const MapIteratorEntry&) = default; - bool operator==(const MapIteratorBase& other) const; - friend bool operator!=(const MapIteratorBase& a, const MapIteratorBase& b) { + MapKey key() const; + MapValueRef value() const; + + private: + friend MapIterator; + friend MapConstIteratorEntry; + + MapIteratorEntry() = default; + + uint8_t key_type_{}; + uint8_t value_type_{}; + internal::UntypedMapIterator iter_{}; +}; + +class PROTOBUF_EXPORT ABSL_ATTRIBUTE_VIEW MapIterator final { + public: + using iterator_category = std::input_iterator_tag; + using iterator_concept = std::forward_iterator_tag; + using value_type = MapIteratorEntry; + using difference_type = ptrdiff_t; + using pointer = const value_type*; + using reference = value_type; + using key_type = value_type::key_type; + using mapped_type = value_type::mapped_type; + + MapIterator() = default; + MapIterator(const MapIterator&) = default; + MapIterator& operator=(const MapIterator&) = default; + + value_type operator*() const { + ABSL_CHECK(!iter_.Equals(internal::UntypedMapBase::EndIterator())) + << "Can't deref the end iterator"; + + value_type res; + res.key_type_ = key_type_; + res.value_type_ = value_type_; + res.iter_ = iter_; + return res; + } + + auto operator->() const { + struct ABSL_ATTRIBUTE_VIEW ArrowProxy { + value_type value; + const value_type* operator->() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + return &value; + } + }; + return ArrowProxy{**this}; + } + + MapIterator& operator++() { + iter_.PlusPlus(); + return *this; + } + MapIterator operator++(int) { + auto copy = *this; + iter_.PlusPlus(); + return copy; + } + + friend bool operator==(MapIterator a, MapIterator b) { + return a.iter_.Equals(b.iter_); + } + friend bool operator!=(MapIterator a, MapIterator b) { return !(a == b); } + + private: + friend GenericMapRef; + friend MapConstIterator; + + uint8_t key_type_{}; + uint8_t value_type_{}; + internal::UntypedMapIterator iter_{}; +}; + +class PROTOBUF_EXPORT ABSL_ATTRIBUTE_VIEW MapConstIteratorEntry final { + public: + using key_type = MapKey; + using mapped_type = MapValueConstRef; + + MapConstIteratorEntry(const MapConstIteratorEntry&) = default; + MapConstIteratorEntry& operator=(const MapConstIteratorEntry&) = default; + MapConstIteratorEntry(const MapIteratorEntry& entry) // NOLINT + : key_type_(entry.key_type_), + value_type_(entry.value_type_), + iter_(entry.iter_) {} + + MapKey key() const; + MapValueConstRef value() const; + + private: + friend MapConstIterator; + + MapConstIteratorEntry() = default; + + uint8_t key_type_{}; + uint8_t value_type_{}; + internal::UntypedMapIterator iter_{}; +}; + +class PROTOBUF_EXPORT ABSL_ATTRIBUTE_VIEW MapConstIterator final { + public: + using iterator_category = std::input_iterator_tag; + using iterator_concept = std::forward_iterator_tag; + using value_type = MapConstIteratorEntry; + using difference_type = ptrdiff_t; + using pointer = const value_type*; + using reference = value_type; + using key_type = value_type::key_type; + using mapped_type = value_type::mapped_type; + + MapConstIterator() = default; + MapConstIterator(const MapConstIterator&) = default; + MapConstIterator& operator=(const MapConstIterator&) = default; + MapConstIterator(MapIterator it) // NOLINT + : key_type_(it.key_type_), value_type_(it.value_type_), iter_(it.iter_) {} + + value_type operator*() const { + ABSL_CHECK(!iter_.Equals(internal::UntypedMapBase::EndIterator())) + << "Can't deref the end iterator"; + + value_type res; + res.key_type_ = key_type_; + res.value_type_ = value_type_; + res.iter_ = iter_; + return res; + } + + auto operator->() const { + struct ABSL_ATTRIBUTE_VIEW ArrowProxy { + value_type value; + const value_type* operator->() const ABSL_ATTRIBUTE_LIFETIME_BOUND { + return &value; + } + }; + return ArrowProxy{**this}; + } + + MapConstIterator& operator++() { + iter_.PlusPlus(); + return *this; + } + MapConstIterator operator++(int) { + auto copy = *this; + iter_.PlusPlus(); + return copy; + } + + friend bool operator==(MapConstIterator a, MapConstIterator b) { + return a.iter_.Equals(b.iter_); + } + friend bool operator!=(MapConstIterator a, MapConstIterator b) { return !(a == b); } - DerivedIterator& operator++(); - DerivedIterator operator++(int); - - const MapKey& GetKey() { return key_; } - const ValueRef& GetValueRef() { return value_; } - - protected: - template <typename Key, typename T> - friend class internal::TypeDefinedMapFieldBase; - template <auto* kGlobals, typename Key, typename T> - friend class internal::MapField; - friend class internal::MapFieldBase; - - MapIteratorBase(MapFieldBase* map, const Descriptor* descriptor); - - internal::UntypedMapIterator iter_; - // Point to a MapField to call helper methods implemented in MapField. - // MapIterator does not own this object. - MapFieldBase* map_; - MapKey key_; - ValueRef value_; -}; - -extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE - MapIteratorBase</*kIsMutable=*/false>; -extern template class PROTOBUF_EXPORT_TEMPLATE_DECLARE - MapIteratorBase</*kIsMutable=*/true>; - -class PROTOBUF_EXPORT ConstMapIterator final - : public MapIteratorBase</*kIsMutable=*/false> { - friend class internal::MapFieldBase; - template <typename MessageT> - friend struct internal::MapDynamicFieldInfo; - - public: - ConstMapIterator(const google::protobuf::Message* message, const FieldDescriptor* field) - : MapIteratorBase(message, field) {} - private: - ConstMapIterator(const internal::MapFieldBase* map, - const Descriptor* descriptor) - : MapIteratorBase(map, descriptor) {} + friend GenericConstMapRef; + friend GenericMapRef; + friend internal::MapFieldBase; + + uint8_t key_type_{}; + uint8_t value_type_{}; + internal::UntypedMapIterator iter_{}; }; -class PROTOBUF_EXPORT MapIterator final - : public MapIteratorBase</*kIsMutable=*/true> { - friend class internal::MapFieldBase; - template <typename MessageT> - friend struct internal::MapDynamicFieldInfo; - - public: - MapIterator(google::protobuf::Message* message, const FieldDescriptor* field) - : MapIteratorBase(message, field) {} - - MapValueRef* MutableValueRef() { - map_->SetMapDirty(); - return &value_; - } - - private: - MapIterator(internal::MapFieldBase* map, const Descriptor* descriptor) - : MapIteratorBase(map, descriptor) {} -}; - -namespace internal { -template <> -struct is_internal_map_value_type<class MapValueConstRef> : std::true_type {}; -template <> -struct is_internal_map_value_type<class MapValueRef> : std::true_type {}; - } // namespace internal +class PROTOBUF_EXPORT ABSL_ATTRIBUTE_VIEW GenericMapRef final { + public: + using iterator = internal::MapIterator; + using const_iterator = internal::MapConstIterator; + using value_type = iterator::value_type; + using key_type = iterator::key_type; + using mapped_type = iterator::mapped_type; + + GenericMapRef(const GenericMapRef&) = default; + + // Deleted to prevent confusion as to whether the assignment is shallow or + // deep. + GenericMapRef& operator=(const GenericMapRef&) = delete; + + iterator begin() const; + iterator end() const; + size_t size() const; + bool empty() const; + bool contains(const MapKey& key) const; + iterator find(const MapKey& key) const; + + void clear() const; + size_t erase(const MapKey& key) const; + + // These perform the operation on the underlying instances. + // They do not alter the handles themselves. + absl::Status assign(const GenericConstMapRef& other) const; + absl::Status swap(const GenericMapRef& other) const; + + struct PROTOBUF_EXPORT ABSL_ATTRIBUTE_VIEW InsertResult { + internal::MapIterator iter; + bool inserted; + }; + absl::StatusOr<InsertResult> try_emplace(const MapKey& key) const; + + private: + friend Reflection; + friend internal::MapFieldBase; + friend GenericConstMapRef; + + GenericMapRef() = default; + + template <typename T, typename... U> + void InitializeKeyValue(T* v, const U&... init) const { + ::new (static_cast<void*>(v)) T(init...); + if constexpr (std::is_same_v<std::string, T>) { + if (auto* a = map_->arena()) { + a->OwnDestructor(v); + } + } + } + + void InitializeKeyValue(MessageLite* msg) const { + value_class_data_->PlacementNew(msg, map_->arena()); + } + + uint8_t key_type_{}; + uint8_t value_type_{}; + internal::UntypedMapBase* map_ = nullptr; + const internal::ClassData* value_class_data_ = nullptr; +}; + +class PROTOBUF_EXPORT ABSL_ATTRIBUTE_VIEW GenericConstMapRef final { + public: + using iterator = internal::MapConstIterator; + using const_iterator = iterator; + using value_type = iterator::value_type; + using key_type = iterator::key_type; + using mapped_type = iterator::mapped_type; + + GenericConstMapRef(const GenericConstMapRef&) = default; + GenericConstMapRef& operator=(const GenericConstMapRef&) = default; + GenericConstMapRef(const GenericMapRef& mut) // NOLINT + : key_type_(mut.key_type_), + value_type_(mut.value_type_), + map_(mut.map_), + value_class_data_(mut.value_class_data_) {} + + iterator begin() const; + iterator end() const; + size_t size() const; + bool empty() const; + bool contains(const MapKey& key) const; + iterator find(const MapKey& key) const; + + private: + friend Reflection; + friend GenericMapRef; + + GenericConstMapRef() = default; + + static absl::Status CheckSameType(const GenericConstMapRef& a, + const GenericConstMapRef& b); + + uint8_t key_type_{}; + uint8_t value_type_{}; + const internal::UntypedMapBase* map_ = nullptr; + const internal::ClassData* value_class_data_ = nullptr; +}; + +// This class was never part of any public API (even though it was mistakenly +// put in the public namespace). +// We are replacing the old internal map reflection API with the new public one +// and this class is going away. It is here for now to support the migration of +// a friend project that is using the internal API. +class [[deprecated( + "Legacy internal class. Use Reflection::GetMap instead.")]] PROTOBUF_EXPORT + ConstMapIterator final { + public: + MapKey GetKey() const { return it_->key(); } + MapValueConstRef GetValueRef() const { return it_->value(); } + + ConstMapIterator& operator++() { + ++it_; + return *this; + } + + PROTOBUF_IGNORE_DEPRECATION_START + friend bool operator==(ConstMapIterator a, ConstMapIterator b) { + return a.it_ == b.it_; + } + friend bool operator!=(ConstMapIterator a, ConstMapIterator b) { + return a.it_ != b.it_; + } + PROTOBUF_IGNORE_DEPRECATION_STOP + + private: + friend Reflection; + ConstMapIterator() = default; + ConstMapIterator(internal::MapConstIterator it) : it_(it) {} // NOLINT + internal::MapConstIterator it_; +}; + +// Expose this feature macro to users to let them know that the map reflection +// API exists. +#define PROTOBUF_HAS_MAP_REFLECTION_APIS 1 + } // namespace protobuf } // namespace google
diff --git a/src/google/protobuf/map_field_test.cc b/src/google/protobuf/map_field_test.cc index fc67c4f..922090a 100644 --- a/src/google/protobuf/map_field_test.cc +++ b/src/google/protobuf/map_field_test.cc
@@ -446,7 +446,7 @@ // This tests that `MapField` and all its base classes can be constant // initialized. PROTOBUF_CONSTINIT static MyMapField field; // NOLINT - EXPECT_EQ(field.size(), 0); + EXPECT_EQ(field.GetMap().size(), 0); } TEST(MapFieldTest, MutableMapDoesNotAllocatePayload) {
diff --git a/src/google/protobuf/map_test.cc b/src/google/protobuf/map_test.cc index 23ab064..4c8d297 100644 --- a/src/google/protobuf/map_test.cc +++ b/src/google/protobuf/map_test.cc
@@ -480,6 +480,13 @@ } +TEST(MapTest, MapReflection) { +#if !defined(PROTOBUF_HAS_MAP_REFLECTION_APIS) || \ + !PROTOBUF_HAS_MAP_REFLECTION_APIS + FAIL() << "Missing feature macro."; +#endif +} + } // namespace } // namespace internal
diff --git a/src/google/protobuf/map_test.inc b/src/google/protobuf/map_test.inc index e315221..947457f 100644 --- a/src/google/protobuf/map_test.inc +++ b/src/google/protobuf/map_test.inc
@@ -17,11 +17,13 @@ #include <algorithm> #include <cstddef> #include <cstdint> +#include <iterator> #include <limits> #include <memory> #include <ostream> #include <sstream> #include <string> +#include <type_traits> #include <utility> #include <vector> @@ -38,6 +40,7 @@ #include "absl/log/absl_check.h" #include "absl/log/absl_log.h" #include "absl/log/globals.h" +#include "absl/status/status_matchers.h" #include "absl/strings/str_cat.h" #include "absl/strings/str_format.h" #include "absl/strings/string_view.h" @@ -70,7 +73,9 @@ // Must be included last. #include "google/protobuf/port_def.inc" +using ::absl_testing::StatusIs; using ::testing::ElementsAre; +using ::testing::HasSubstr; using ::testing::IsEmpty; using ::testing::Pair; @@ -1083,7 +1088,29 @@ reflection_tester.ExpectMapFieldsSetViaReflection(rhs); - // Add an entry to make sure it is using the right arena. + (*rhs.mutable_map_int32_int32())[1234] = 1234; + } +} + +TEST_F(MapImplTest, SwapFieldArenaMapReflection) { + MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor()); + + { + TestMap rhs; + + { + Arena local_arena; + auto* lhs = Arena::Create<TestMap>(&local_arena); + + reflection_tester.SetMapFieldsViaMapReflection(lhs); + reflection_tester.SwapMapsViaMapReflection(lhs, &rhs); + + reflection_tester.ExpectClearViaReflection(*lhs); + + (*lhs->mutable_map_int32_int32())[1234] = 1234; + } + + reflection_tester.ExpectMapFieldsSetViaReflection(rhs); (*rhs.mutable_map_int32_int32())[1234] = 1234; } } @@ -1127,22 +1154,21 @@ auto* field = descriptor->field(i); if (!field->is_map()) continue; - ConstMapIterator it = - reflection_tester.ConstMapBegin(message, field->name()); - ConstMapIterator end = - reflection_tester.ConstMapEnd(message, field->name()); + GenericConstMapRef map_ref = + message->GetReflection()->GetMap(*message, field).value(); // It's unordered, so search for it. - if (it == end) continue; + if (map_ref.empty()) continue; + auto it = map_ref.begin(); auto next = it; ++next; - ASSERT_NE(next, end); - if (next.GetKey() < it.GetKey()) { + ASSERT_NE(next, map_ref.end()); + if (next->key() < it->key()) { it = next; } EXPECT_EQ(reflection_tester.MapSize(*message, field->name()), 2); - reflection_tester.DeleteMapValueViaMapReflection( - message, field->name(), it.GetKey()); + reflection_tester.DeleteMapValueViaMapReflection(message, field->name(), + it->key()); EXPECT_EQ(reflection_tester.MapSize(*message, field->name()), 1); } @@ -1179,16 +1205,14 @@ auto* field = descriptor->field(i); if (!field->is_map()) continue; - ConstMapIterator it = - reflection_tester.ConstMapBegin(message, field->name()); - ConstMapIterator end = - reflection_tester.ConstMapEnd(message, field->name()); + GenericConstMapRef map_ref = + message->GetReflection()->GetMap(*message, field).value(); - while (it != end) { + for (auto it = map_ref.begin(); it != map_ref.end();) { auto next = it; ++next; - reflection_tester.DeleteMapValueViaMapReflection( - message, field->name(), it.GetKey()); + reflection_tester.DeleteMapValueViaMapReflection(message, field->name(), + it->key()); it = next; } EXPECT_EQ(reflection_tester.MapSize(*message, field->name()), 0); @@ -1198,67 +1222,101 @@ TEST_F(MapImplTest, CopyAssignMapIterator) { TestMap message; - MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor()); + const auto* desc = message.descriptor(); + const auto* field = desc->FindFieldByName("map_int32_int32"); + MapReflectionTester reflection_tester(desc); reflection_tester.SetMapFieldsViaMapReflection(&message); - ConstMapIterator it1 = - reflection_tester.ConstMapBegin(&message, "map_int32_int32"); - ConstMapIterator it2 = - reflection_tester.ConstMapEnd(&message, "map_int32_int32"); + auto map = message.GetReflection()->GetMap(message, field).value(); + auto it1 = map.begin(); + auto it2 = map.end(); it2 = it1; - EXPECT_EQ(it1.GetKey().GetInt32Value(), it2.GetKey().GetInt32Value()); + EXPECT_EQ(it1->key().GetInt32Value(), it2->key().GetInt32Value()); } class MapTestWithParams - : public testing::TestWithParam<std::tuple<bool, bool, bool>> {}; + : public testing::TestWithParam<std::tuple<bool, bool, bool>> { + protected: + const Descriptor* descriptor_ = UNITTEST::TestMap::descriptor(); + DynamicMessageFactory factory_; + std::unique_ptr<const Message> dyn_message_{ + factory_.GetPrototype(descriptor_)->New()}; + TestMap gen_message_; + Arena arena_; + + Message* MakeMessage(bool in_arena) { + bool use_dynamic = std::get<0>(GetParam()); + auto* prototype = use_dynamic ? dyn_message_.get() : &gen_message_; + return in_arena ? prototype->New(&arena_) + : Arena::Create<std::unique_ptr<Message>>(&arena_, + prototype->New()) + ->get(); + } +}; INSTANTIATE_TEST_SUITE_P(MapTestWithParamsSuite, MapTestWithParams, testing::Combine(testing::Bool(), testing::Bool(), testing::Bool())); TEST_P(MapTestWithParams, SwapMapsFieldsViaReflection) { - auto* descriptor = UNITTEST::TestMap::descriptor(); auto [use_dynamic, lhs_arena, rhs_arena] = GetParam(); - - DynamicMessageFactory factory; - std::unique_ptr<const Message> dyn_message( - factory.GetPrototype(descriptor)->New()); - TestMap gen_message; - Arena arena; - - std::vector<const FieldDescriptor*> fields; - for (int i = 0; i < descriptor->field_count(); ++i) { - fields.push_back(descriptor->field(i)); - } - - const auto make = [&, use_dynamic = use_dynamic](bool in_arena) { - auto* prototype = use_dynamic ? dyn_message.get() : &gen_message; - return in_arena ? prototype->New(&arena) - : Arena::Create<std::unique_ptr<Message>>(&arena, - prototype->New()) - ->get(); - }; - - auto* lhs = make(lhs_arena); - auto* rhs = make(rhs_arena); - MapReflectionTester reflection_tester(descriptor); + auto* lhs = MakeMessage(lhs_arena); + auto* rhs = MakeMessage(rhs_arena); + MapReflectionTester reflection_tester(descriptor_); reflection_tester.SetMapFieldsViaMapReflection(lhs); - reflection_tester.ExpectMapFieldsSetViaReflectionIterator(lhs); - reflection_tester.ExpectClearViaReflectionIterator(rhs); + reflection_tester.ExpectMapFieldsSetViaReflectionIterator(*lhs); + reflection_tester.ExpectClearViaReflectionIterator(*rhs); + + std::vector<const FieldDescriptor*> fields; + for (int i = 0; i < descriptor_->field_count(); ++i) { + fields.push_back(descriptor_->field(i)); + } lhs->GetReflection()->SwapFields(lhs, rhs, fields); - reflection_tester.ExpectClearViaReflectionIterator(lhs); - reflection_tester.ExpectMapFieldsSetViaReflectionIterator(rhs); + reflection_tester.ExpectClearViaReflectionIterator(*lhs); + reflection_tester.ExpectMapFieldsSetViaReflectionIterator(*rhs); if (lhs_arena == rhs_arena) { // If they are the same arena, we can try the unsafe swap. lhs->GetReflection()->UnsafeArenaSwapFields(lhs, rhs, fields); - reflection_tester.ExpectClearViaReflectionIterator(rhs); - reflection_tester.ExpectMapFieldsSetViaReflectionIterator(lhs); + reflection_tester.ExpectClearViaReflectionIterator(*rhs); + reflection_tester.ExpectMapFieldsSetViaReflectionIterator(*lhs); } } +TEST_P(MapTestWithParams, SwapMapsViaMapReflection) { + auto [use_dynamic, lhs_arena, rhs_arena] = GetParam(); + auto* lhs = MakeMessage(lhs_arena); + auto* rhs = MakeMessage(rhs_arena); + MapReflectionTester reflection_tester(descriptor_); + reflection_tester.SetMapFieldsViaMapReflection(lhs); + + reflection_tester.ExpectMapFieldsSetViaReflectionIterator(*lhs); + reflection_tester.ExpectClearViaReflectionIterator(*rhs); + + reflection_tester.SwapMapsViaMapReflection(lhs, rhs); + + reflection_tester.ExpectClearViaReflectionIterator(*lhs); + reflection_tester.ExpectMapFieldsSetViaReflectionIterator(*rhs); +} + +TEST_P(MapTestWithParams, AssignMapsViaMapReflection) { + auto [use_dynamic, lhs_arena, rhs_arena] = GetParam(); + auto* src = MakeMessage(lhs_arena); + auto* dst = MakeMessage(rhs_arena); + MapReflectionTester reflection_tester(descriptor_); + reflection_tester.SetMapFieldsViaMapReflection(src); + + reflection_tester.ExpectMapFieldsSetViaReflectionIterator(*src); + reflection_tester.ExpectClearViaReflectionIterator(*dst); + + reflection_tester.AssignMapsViaMapReflection(dst, src); + + reflection_tester.ExpectMapFieldsSetViaReflectionIterator(*src); + reflection_tester.ExpectMapFieldsSetViaReflectionIterator(*dst); +} + class MapTestCodegenOrDynamic : public testing::TestWithParam<bool> {}; INSTANTIATE_TEST_SUITE_P(MapTestCodegenOrDynamicSuite, MapTestCodegenOrDynamic, @@ -1550,22 +1608,7 @@ return result; } -} // namespace - -// This class is a friend, so no anonymous namespace. -class MapFieldReflectionTest : public testing::Test { - protected: - typedef FieldDescriptor FD; - - int MapSize(const Reflection* reflection, const FieldDescriptor* field, - const Message& message) { - return reflection->MapSize(message, field); - } -}; - -namespace { - -TEST_F(MapFieldReflectionTest, RegularFields) { +TEST(MapFieldReflectionTest, RegularFields) { TestMap message; const Reflection* refl = message.GetReflection(); const Descriptor* desc = message.GetDescriptor(); @@ -1757,7 +1800,7 @@ } } -TEST_F(MapFieldReflectionTest, RepeatedFieldRefForRegularFields) { +TEST(MapFieldReflectionTest, RepeatedFieldRefForRegularFields) { TestMap message; const Reflection* refl = message.GetReflection(); const Descriptor* desc = message.GetDescriptor(); @@ -2249,7 +2292,7 @@ } } -TEST_F(MapFieldReflectionTest, RepeatedFieldRefMergeFromAndSwap) { +TEST(MapFieldReflectionTest, RepeatedFieldRefMergeFromAndSwap) { // Set-up message content. TestMap m0, m1, m2; for (int i = 0; i < 10; ++i) { @@ -2355,7 +2398,7 @@ // TODO: add test for duplicated key } -TEST_F(MapFieldReflectionTest, MapSizeWithDuplicatedKey) { +TEST(MapFieldReflectionTest, MapSizeWithDuplicatedKey) { // Dynamic Message { DynamicMessageFactory factory; @@ -2374,7 +2417,7 @@ entry_reflection->SetInt32(entry2, key_field, 1); EXPECT_EQ(2, reflection->FieldSize(*message, field)); - EXPECT_EQ(1, MapSize(reflection, field, *message)); + EXPECT_EQ(1, reflection->GetMap(*message, field).value().size()); EXPECT_EQ(2, reflection->FieldSize(*message, field)); } @@ -2394,11 +2437,11 @@ entry_reflection->SetInt32(entry2, key_field, 1); EXPECT_EQ(2, reflection->FieldSize(message, field)); - EXPECT_EQ(1, MapSize(reflection, field, message)); + EXPECT_EQ(1, reflection->GetMap(message, field).value().size()); } } -TEST_F(MapFieldReflectionTest, UninitializedEntry) { +TEST(MapFieldReflectionTest, UninitializedEntry) { UNITTEST::TestRequiredMessageMap message; const Reflection* reflection = message.GetReflection(); const FieldDescriptor* field = @@ -3508,7 +3551,91 @@ MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor()); reflection_tester.SetMapFieldsViaMapReflection(&message); reflection_tester.ExpectMapFieldsSetViaReflection(message); - reflection_tester.ExpectMapFieldsSetViaReflectionIterator(&message); + reflection_tester.ExpectMapFieldsSetViaReflectionIterator(message); +} + +TEST(GeneratedMapFieldReflectionTest, ClearViaMapReflection) { + UNITTEST::TestMap message; + MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor()); + reflection_tester.SetMapFieldsViaMapReflection(&message); + reflection_tester.ExpectMapFieldsSetViaReflection(message); + reflection_tester.ClearMapFieldsViaMapReflection(&message); + reflection_tester.ExpectClearViaReflection(message); + reflection_tester.ExpectClearViaReflectionIterator(message); +} + +TEST(GeneratedMapFieldReflectionTest, ModifyViaMapReflection) { + UNITTEST::TestMap message; + MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor()); + reflection_tester.SetMapFieldsViaMapReflection(&message); + reflection_tester.ModifyMapFieldsViaReflection(&message); +} + +TEST(GeneratedMapFieldReflectionTest, SwapMapsViaMapReflection) { + UNITTEST::TestMap message1; + UNITTEST::TestMap message2; + MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor()); + reflection_tester.SetMapFieldsViaMapReflection(&message1); + + reflection_tester.ExpectMapFieldsSetViaReflectionIterator(message1); + reflection_tester.ExpectClearViaReflectionIterator(message2); + + reflection_tester.SwapMapsViaMapReflection(&message1, &message2); + + reflection_tester.ExpectClearViaReflectionIterator(message1); + reflection_tester.ExpectMapFieldsSetViaReflectionIterator(message2); +} + +TEST(GeneratedMapFieldReflectionTest, AssignMapsViaMapReflection) { + UNITTEST::TestMap src; + UNITTEST::TestMap dst; + MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor()); + reflection_tester.SetMapFieldsViaMapReflection(&src); + + reflection_tester.ExpectMapFieldsSetViaReflectionIterator(src); + reflection_tester.ExpectClearViaReflectionIterator(dst); + + reflection_tester.AssignMapsViaMapReflection(&dst, &src); + + reflection_tester.ExpectMapFieldsSetViaReflectionIterator(src); + reflection_tester.ExpectMapFieldsSetViaReflectionIterator(dst); +} + +TEST(GeneratedMapFieldReflectionTest, EraseMapValuesViaMapReflectionIterator) { + UNITTEST::TestMap message; + MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor()); + reflection_tester.SetMapFieldsViaMapReflection(&message); + reflection_tester.ExpectMapFieldsSetViaReflectionIterator(message); + + reflection_tester.EraseMapValuesViaMapReflectionIterator(&message); + reflection_tester.ExpectClearViaReflection(message); + reflection_tester.ExpectClearViaReflectionIterator(message); +} + +TEST(GeneratedMapFieldReflectionTest, InsertOrLookupMapValue) { + UNITTEST::TestMap message; + MapReflectionTester reflection_tester(UNITTEST::TestMap::descriptor()); + + MapKey key; + key.SetInt32Value(42); + MapValueRef val_ref; + EXPECT_TRUE(reflection_tester.InsertOrLookupMapValue( + &message, "map_int32_int32", key, &val_ref)); + val_ref.SetInt32Value(100); + + EXPECT_FALSE(reflection_tester.InsertOrLookupMapValue( + &message, "map_int32_int32", key, &val_ref)); + EXPECT_EQ(val_ref.GetInt32Value(), 100); + + MapValueConstRef const_val_ref; + EXPECT_TRUE(reflection_tester.LookupMapValue(message, "map_int32_int32", key, + &const_val_ref)); + EXPECT_EQ(const_val_ref.GetInt32Value(), 100); + + MapKey non_exist_key; + non_exist_key.SetInt32Value(999); + EXPECT_FALSE(reflection_tester.LookupMapValue(message, "map_int32_int32", + non_exist_key, &const_val_ref)); } // Dynamic Message Test ============================================= @@ -3554,6 +3681,59 @@ MapReflectionTester reflection_tester(map_descriptor_); reflection_tester.SetMapFieldsViaMapReflection(message.get()); reflection_tester.ExpectMapFieldsSetViaReflection(*message); + reflection_tester.ExpectMapFieldsSetViaReflectionIterator(*message); +} + +TEST_F(MapFieldInDynamicMessageTest, ClearViaMapReflection) { + std::unique_ptr<Message> message(map_prototype_->New()); + MapReflectionTester reflection_tester(map_descriptor_); + reflection_tester.SetMapFieldsViaMapReflection(message.get()); + reflection_tester.ExpectMapFieldsSetViaReflection(*message); + + reflection_tester.ClearMapFieldsViaMapReflection(message.get()); + reflection_tester.ExpectClearViaReflection(*message); + reflection_tester.ExpectClearViaReflectionIterator(*message); +} + +TEST_F(MapFieldInDynamicMessageTest, SwapMapsViaMapReflection) { + std::unique_ptr<Message> message1(map_prototype_->New()); + std::unique_ptr<Message> message2(map_prototype_->New()); + MapReflectionTester reflection_tester(map_descriptor_); + reflection_tester.SetMapFieldsViaMapReflection(message1.get()); + + reflection_tester.ExpectMapFieldsSetViaReflectionIterator(*message1); + reflection_tester.ExpectClearViaReflectionIterator(*message2); + + reflection_tester.SwapMapsViaMapReflection(message1.get(), message2.get()); + + reflection_tester.ExpectClearViaReflectionIterator(*message1); + reflection_tester.ExpectMapFieldsSetViaReflectionIterator(*message2); +} + +TEST_F(MapFieldInDynamicMessageTest, AssignMapsViaMapReflection) { + std::unique_ptr<Message> src(map_prototype_->New()); + std::unique_ptr<Message> dst(map_prototype_->New()); + MapReflectionTester reflection_tester(map_descriptor_); + reflection_tester.SetMapFieldsViaMapReflection(src.get()); + + reflection_tester.ExpectMapFieldsSetViaReflectionIterator(*src); + reflection_tester.ExpectClearViaReflectionIterator(*dst); + + reflection_tester.AssignMapsViaMapReflection(dst.get(), src.get()); + + reflection_tester.ExpectMapFieldsSetViaReflectionIterator(*src); + reflection_tester.ExpectMapFieldsSetViaReflectionIterator(*dst); +} + +TEST_F(MapFieldInDynamicMessageTest, EraseMapValuesViaMapReflectionIterator) { + std::unique_ptr<Message> message(map_prototype_->New()); + MapReflectionTester reflection_tester(map_descriptor_); + reflection_tester.SetMapFieldsViaMapReflection(message.get()); + reflection_tester.ExpectMapFieldsSetViaReflectionIterator(*message); + + reflection_tester.EraseMapValuesViaMapReflectionIterator(message.get()); + reflection_tester.ExpectClearViaReflection(*message); + reflection_tester.ExpectClearViaReflectionIterator(*message); } TEST_F(MapFieldInDynamicMessageTest, MapSpaceUsed) { @@ -3588,10 +3768,15 @@ // Get value reference before serialization, so that we know the value is from // map. MapKey map_key; - MapValueRef map_val; map_key.SetInt32Value(0); - reflection_tester.GetMapValueViaMapReflection( - message.get(), "map_int32_foreign_message", map_key, &map_val); + auto insert_res = + message->GetReflection() + ->MutableMap(message.get(), message->GetDescriptor()->FindFieldByName( + "map_int32_foreign_message")) + .value() + .try_emplace(map_key) + .value(); + MapValueRef map_val = insert_res.iter->value(); Message* submsg = map_val.MutableMessageValue(); // In previous implementation, calling SerializeToString will cause syncing @@ -4434,6 +4619,196 @@ EXPECT_EQ((*message.mutable_map_bytes())[1], "\xFF"); } +TEST_F(MapImplTest, FallibleMapReflectionApi) { + TestMap message; + const auto* desc = message.descriptor(); + const auto* reflection = message.GetReflection(); + const auto* map_i32_field = desc->FindFieldByName("map_int32_int32"); + const auto* map_i64_field = desc->FindFieldByName("map_int64_int64"); + TestAllTypes other_msg; + const auto* non_map_field = + other_msg.descriptor()->FindFieldByName("optional_int32"); + + // 1. GetMap / MutableMap with invalid arguments (replacing USAGE_CHECK + // crashes) Null field + EXPECT_THAT(reflection->GetMap(message, nullptr), + StatusIs(absl::StatusCode::kInvalidArgument, + HasSubstr("FieldDescriptor is null"))); + EXPECT_THAT(reflection->MutableMap(&message, nullptr), + StatusIs(absl::StatusCode::kInvalidArgument, + HasSubstr("FieldDescriptor is null"))); + + // Null message pointer + EXPECT_THAT(reflection->MutableMap(nullptr, map_i32_field), + StatusIs(absl::StatusCode::kInvalidArgument, + HasSubstr("Message pointer is null"))); + + // Field is singular/repeated (not a map) + EXPECT_THAT(other_msg.GetReflection()->GetMap(other_msg, non_map_field), + StatusIs(absl::StatusCode::kInvalidArgument, + HasSubstr("requires a map field"))); + EXPECT_THAT(other_msg.GetReflection()->MutableMap(&other_msg, non_map_field), + StatusIs(absl::StatusCode::kInvalidArgument, + HasSubstr("requires a map field"))); + + // Mismatched field from another descriptor + EXPECT_THAT(reflection->GetMap(message, non_map_field), + StatusIs(absl::StatusCode::kInvalidArgument, + HasSubstr("Field does not match message type"))); + EXPECT_THAT(reflection->MutableMap(&message, non_map_field), + StatusIs(absl::StatusCode::kInvalidArgument, + HasSubstr("Field does not match message type"))); + + // Mismatched message reflection + EXPECT_THAT(reflection->GetMap(other_msg, map_i32_field), + StatusIs(absl::StatusCode::kInvalidArgument, + HasSubstr("not the right object for reflection"))); + + ASSERT_TRUE(reflection->GetMap(message, map_i32_field).ok()); + ASSERT_TRUE(reflection->MutableMap(&message, map_i32_field).ok()); + + auto map = reflection->MutableMap(&message, map_i32_field).value(); + + // 2. MapKey type mismatch or uninitialized key + MapKey uninit_key; + MapKey int64_key; + int64_key.SetInt64Value(42); + MapKey int32_key; + int32_key.SetInt32Value(42); + + EXPECT_FALSE(map.contains(uninit_key)); + EXPECT_FALSE(map.contains(int64_key)); + EXPECT_EQ(map.find(uninit_key), map.end()); + EXPECT_EQ(map.find(int64_key), map.end()); + + EXPECT_FALSE(map.erase(uninit_key)); + EXPECT_FALSE(map.erase(int64_key)); + + EXPECT_THAT( + map.try_emplace(uninit_key), + StatusIs(absl::StatusCode::kInvalidArgument, HasSubstr("uninitialized"))); + EXPECT_THAT( + map.try_emplace(int64_key), + StatusIs(absl::StatusCode::kInvalidArgument, HasSubstr("type mismatch"))); + + // Valid try_emplace + auto res = map.try_emplace(int32_key); + ASSERT_TRUE(res.ok()); + EXPECT_TRUE(res->inserted); + EXPECT_EQ(res->iter->key().GetInt32Value(), 42); + + // 3. assign and swap between incompatible map handles + auto map_i64 = reflection->MutableMap(&message, map_i64_field).value(); + EXPECT_THAT(map.assign(map_i64), + StatusIs(absl::StatusCode::kInvalidArgument, + HasSubstr("Map key or value CppType mismatch"))); + EXPECT_THAT(map.swap(map_i64), + StatusIs(absl::StatusCode::kInvalidArgument, + HasSubstr("Map key or value CppType mismatch"))); + + // Same key/value CppType (int32 -> message), different message prototypes + // (when empty, when one is non-empty, and via GetMap) + auto map_foreign = + reflection + ->MutableMap(&message, + desc->FindFieldByName("map_int32_foreign_message")) + .value(); + const auto* all_types_field = desc->FindFieldByName("map_int32_all_types"); + auto map_all_types = + reflection->MutableMap(&message, all_types_field).value(); + auto const_map_all_types_empty = + reflection->GetMap(message, all_types_field).value(); + EXPECT_THAT(map_foreign.assign(map_all_types), + StatusIs(absl::StatusCode::kInvalidArgument, + HasSubstr("Map value message prototype mismatch"))); + EXPECT_THAT(map_foreign.assign(const_map_all_types_empty), + StatusIs(absl::StatusCode::kInvalidArgument, + HasSubstr("Map value message prototype mismatch"))); + EXPECT_THAT(map_foreign.swap(map_all_types), + StatusIs(absl::StatusCode::kInvalidArgument, + HasSubstr("Map value message prototype mismatch"))); + + ASSERT_TRUE(map_all_types.try_emplace(int32_key).ok()); + auto const_map_all_types_nonempty = + reflection->GetMap(message, all_types_field).value(); + EXPECT_THAT(map_foreign.assign(map_all_types), + StatusIs(absl::StatusCode::kInvalidArgument, + HasSubstr("Map value message prototype mismatch"))); + EXPECT_THAT(map_foreign.assign(const_map_all_types_nonempty), + StatusIs(absl::StatusCode::kInvalidArgument, + HasSubstr("Map value message prototype mismatch"))); + EXPECT_THAT(map_foreign.swap(map_all_types), + StatusIs(absl::StatusCode::kInvalidArgument, + HasSubstr("Map value message prototype mismatch"))); +} + +TEST_F(MapImplTest, GenericMapRefIteratorAndContainerTraits) { + using MutIterTraits = std::iterator_traits<GenericMapRef::iterator>; + static_assert(std::is_same_v<MutIterTraits::iterator_category, + std::input_iterator_tag>); + static_assert(std::is_same_v<GenericMapRef::iterator::iterator_concept, + std::forward_iterator_tag>); + static_assert(std::is_same_v<MutIterTraits::value_type, MapIteratorEntry>); + static_assert(std::is_same_v<MutIterTraits::difference_type, ptrdiff_t>); + static_assert( + std::is_same_v<MutIterTraits::pointer, const MapIteratorEntry*>); + static_assert(std::is_same_v<MutIterTraits::reference, MapIteratorEntry>); + + using ConstIterTraits = std::iterator_traits<GenericConstMapRef::iterator>; + static_assert(std::is_same_v<ConstIterTraits::iterator_category, + std::input_iterator_tag>); + static_assert(std::is_same_v<GenericConstMapRef::iterator::iterator_concept, + std::forward_iterator_tag>); + static_assert( + std::is_same_v<ConstIterTraits::value_type, MapConstIteratorEntry>); + static_assert(std::is_same_v<ConstIterTraits::difference_type, ptrdiff_t>); + static_assert( + std::is_same_v<ConstIterTraits::pointer, const MapConstIteratorEntry*>); + static_assert( + std::is_same_v<ConstIterTraits::reference, MapConstIteratorEntry>); + + static_assert(std::is_same_v<GenericMapRef::const_iterator, + GenericConstMapRef::iterator>); + static_assert(std::is_same_v<GenericConstMapRef::const_iterator, + GenericConstMapRef::iterator>); + + + TestMap message; + const auto* desc = message.descriptor(); + const auto* reflection = message.GetReflection(); + const auto* map_i32_field = desc->FindFieldByName("map_int32_int32"); + + GenericMapRef map = reflection->MutableMap(&message, map_i32_field).value(); + GenericConstMapRef const_map = + reflection->GetMap(message, map_i32_field).value(); + + EXPECT_EQ(GenericMapRef::iterator{}, GenericMapRef::iterator{}); + EXPECT_EQ(GenericConstMapRef::iterator{}, GenericConstMapRef::iterator{}); + EXPECT_EQ(std::distance(map.begin(), map.end()), 0); + EXPECT_EQ(std::distance(const_map.begin(), const_map.end()), 0); + EXPECT_THAT(map, IsEmpty()); + EXPECT_THAT(const_map, IsEmpty()); + EXPECT_THAT(map, ::testing::BeginEndDistanceIs(0)); + EXPECT_THAT(const_map, ::testing::BeginEndDistanceIs(0)); + + MapKey key; + key.SetInt32Value(7); + auto res = map.try_emplace(key); + ASSERT_TRUE(res.ok()); + res->iter->value().SetInt32Value(99); + + EXPECT_EQ(std::distance(map.begin(), map.end()), 1); + EXPECT_EQ(std::distance(const_map.begin(), const_map.end()), 1); + EXPECT_THAT(map, ::testing::SizeIs(1)); + EXPECT_THAT(const_map, ::testing::SizeIs(1)); + EXPECT_THAT(map, ::testing::BeginEndDistanceIs(1)); + EXPECT_THAT(const_map, ::testing::BeginEndDistanceIs(1)); + EXPECT_THAT(map, ::testing::UnorderedElementsAre(::testing::Property( + &GenericMapRef::value_type::key, key))); + EXPECT_THAT(const_map, ::testing::UnorderedElementsAre(::testing::Property( + &GenericConstMapRef::value_type::key, key))); +} + } // namespace } // namespace internal } // namespace protobuf
diff --git a/src/google/protobuf/message.h b/src/google/protobuf/message.h index 47f67b3..44b255f 100644 --- a/src/google/protobuf/message.h +++ b/src/google/protobuf/message.h
@@ -107,6 +107,8 @@ #include "absl/base/optimization.h" #include "absl/log/absl_check.h" #include "absl/memory/memory.h" +#include "absl/status/status.h" +#include "absl/status/statusor.h" #include "absl/strings/cord.h" #include "absl/strings/string_view.h" #include "absl/types/optional.h" @@ -137,13 +139,14 @@ // Defined in other files. class AssignDescriptorsHelper; -class ConstMapIterator; +class ABSL_ATTRIBUTE_VIEW ConstMapIterator; class DynamicMessageFactory; class GeneratedMessageReflectionTestHelper; -class MapKey; -class MapValueConstRef; -class MapValueRef; -class MapIterator; +class ABSL_ATTRIBUTE_VIEW MapKey; +class ABSL_ATTRIBUTE_VIEW MapValueConstRef; +class ABSL_ATTRIBUTE_VIEW MapValueRef; +class ABSL_ATTRIBUTE_VIEW GenericMapRef; +class ABSL_ATTRIBUTE_VIEW GenericConstMapRef; class MapReflectionTester; class TextFormat; @@ -213,7 +216,6 @@ class ReflectionOps; // reflection_ops.h class MapKeySorter; // wire_format.cc class WireFormat; // wire_format.h -class MapFieldReflectionTest; // map_test.cc } // namespace internal template <typename T> @@ -972,6 +974,77 @@ MutableRepeatedFieldRef<T> GetMutableRepeatedFieldRef( Message* message, const FieldDescriptor* field) const; + // Get a map field as a generic read-only handle. + // The generic key and value types give the relevant type information needed + // ot access them. + // + // Class synopsis: + // + // class GenericConstMapRef { + // public: + // using iterator = ...; + // using const_iterator = ...; + // using value_type = ...; + // using key_type = MapKey; + // using mapped_type = MapValueConstRef; + // + // iterator begin() const; + // iterator end() const; + // size_t size() const; + // bool empty() const; + // bool contains(const MapKey& key) const; + // iterator find(const MapKey& key) const; + // }; + // + // The `value_type` differs from standard map types in that the key and value + // are accessed as `elem.key()` and `elem.value()` instead of `elem.first` and + // `elem.second`. The accessors return `MapKey` and `MapValueConstRef`. + // + // Example usage: + // + // ASSIGN_OR_RETURN(auto map, reflection->GetMap(message, field)); + // for (auto entry : map) { + // MapKey key = entry.key(); + // MapValueConstRef value = entry.value(); + // ... + // } + absl::StatusOr<GenericConstMapRef> GetMap(const Message& message + ABSL_ATTRIBUTE_LIFETIME_BOUND, + const FieldDescriptor* field) const; + + // Get a map field as a generic mutable handle. + // `GenericMapRef` is similar to `GenericConstMapRef` but adds the following + // mutating operations: + // + // void clear() const; + // size_t erase(const MapKey& key) const; + // absl::StatusOr<InsertResult> try_emplace(const MapKey& key) const; + // + // // Deep container operations + // absl::Status assign(const GenericMapRef& other) const; + // absl::Status swap(const GenericMapRef& other) const; + // + // `try_emplace` behaves like a standard one, except that does not allow + // passing an initial value. The `mapped_type` will always be default + // initialized if the operation results in an insertion. + // + // In addition, the `value()` you get from the iterator returns a + // `MapValueRef`, which allows for mutable access to the value. + // + // Example usage: + // + // // Increase value for the key + // MapKey key = ...; + // ASSIGN_OR_RETURN(auto map, reflection->MutableMap(message, field)); + // auto it = map.find(key); + // if (it != map.end()) { + // it->value()->SetInt64Value(it->value()->GetInt64Value() + 1); + // } + // + absl::StatusOr<GenericMapRef> MutableMap(Message* message + ABSL_ATTRIBUTE_LIFETIME_BOUND, + const FieldDescriptor* field) const; + // DEPRECATED. Please use Get(Mutable)RepeatedFieldRef() for repeated field // access. The following repeated field accessors will be removed in the // future. @@ -1237,7 +1310,6 @@ friend class util::MessageDifferencer; #define GOOGLE_PROTOBUF_HAS_CEL_MAP_REFLECTION_FRIEND friend class expr::CelMapReflectionFriend; - friend class internal::MapFieldReflectionTest; friend class internal::MapKeySorter; friend class internal::MessageUtil; friend class internal::WireFormat; @@ -1266,60 +1338,35 @@ friend class MapReflectionTester; - // Returns true if key is in map. Returns false if key is not in map field. + // TODO: We keep these legacy functions temporarily. + // We have friend projects that are using the internal API. + // Once they are updated to use the public API we can clean this up. + [[deprecated("Legacy internal function. Use GetMap instead.")]] bool ContainsMapKey(const Message& message, const FieldDescriptor* field, const MapKey& key) const; - - // If key is in map field: Saves the value pointer to val and returns - // false. If key in not in map field: Insert the key into map, saves - // value pointer to val and returns true. Users are able to modify the - // map value by MapValueRef. + [[deprecated("Legacy internal function. Use MutableMap instead.")]] bool InsertOrLookupMapValue(Message* message, const FieldDescriptor* field, const MapKey& key, MapValueRef* val) const; - - // If key is in map field: Saves the value pointer to val and returns true. - // Returns false if key is not in map field. Users are NOT able to modify - // the value by MapValueConstRef. + [[deprecated("Legacy internal function. Use GetMap instead.")]] bool LookupMapValue(const Message& message, const FieldDescriptor* field, const MapKey& key, MapValueConstRef* val) const; - bool LookupMapValue(const Message&, const FieldDescriptor*, const MapKey&, - MapValueRef*) const = delete; - - // Delete and returns true if key is in the map field. Returns false - // otherwise. + [[deprecated("Legacy internal function. Use MutableMap instead.")]] bool DeleteMapValue(Message* message, const FieldDescriptor* field, const MapKey& key) const; - - // Returns a MapIterator referring to the first element in the map field. - // If the map field is empty, this function returns the same as - // reflection::MapEnd. Mutation to the field may invalidate the iterator. - MapIterator MapBegin(Message* message, const FieldDescriptor* field) const; - - // Returns a MapIterator referring to the theoretical element that would - // follow the last element in the map field. It does not point to any - // real element. Mutation to the field may invalidate the iterator. - MapIterator MapEnd(Message* message, const FieldDescriptor* field) const; - - // Returns a ConstMapIterator referring to the first element in the map field. - // If the map field is empty, this function returns the same as - // reflection::ConstMapEnd. Mutation to the field may invalidate the iterator. + PROTOBUF_IGNORE_DEPRECATION_START + [[deprecated("Legacy internal function. Use GetMap instead.")]] ConstMapIterator ConstMapBegin(const Message* message, const FieldDescriptor* field) const; - - // Returns a ConstMapIterator referring to the theoretical element that would - // follow the last element in the map field. It does not point to any - // real element. Mutation to the field may invalidate the iterator. + [[deprecated("Legacy internal function. Use GetMap instead.")]] ConstMapIterator ConstMapEnd(const Message* message, const FieldDescriptor* field) const; - - // Get the number of <key, value> pair of a map field. The result may be - // different from FieldSize which can have duplicate keys. + PROTOBUF_IGNORE_DEPRECATION_STOP + [[deprecated("Legacy internal function. Use GetMap instead.")]] int MapSize(const Message& message, const FieldDescriptor* field) const; - // Help method for MapIterator. - template <bool> - friend class MapIteratorBase; friend class WireFormatForMapFieldTest; + const internal::ClassData* GetClassDataForMapMessageValueType( + const FieldDescriptor* field, const internal::UntypedMapBase& map) const; internal::MapFieldBase* MutableMapData(Message* message, const FieldDescriptor* field) const;
diff --git a/src/google/protobuf/reflection_ops.cc b/src/google/protobuf/reflection_ops.cc index ba44721..cdd1a71 100644 --- a/src/google/protobuf/reflection_ops.cc +++ b/src/google/protobuf/reflection_ops.cc
@@ -201,12 +201,10 @@ const MapFieldBase* map_field = reflection->GetMapData(message, field); if (map_field->IsMapValid()) { - ConstMapIterator it(&message, field); - ConstMapIterator end_map(&message, field); - for (map_field->ConstMapBegin(&it), - map_field->ConstMapEnd(&end_map); - it != end_map; ++it) { - if (!it.GetValueRef().GetMessageValue().IsInitialized()) { + auto map = reflection->GetMap(message, field); + ABSL_DCHECK(map.ok()); + for (auto entry : *map) { + if (!entry.value().GetMessageValue().IsInitialized()) { return false; } } @@ -283,11 +281,10 @@ const MapFieldBase* map_field = reflection->GetMapData(message, field); if (map_field->IsMapValid()) { - ConstMapIterator iter(&message, field); - ConstMapIterator end(&message, field); - for (map_field->ConstMapBegin(&iter), map_field->ConstMapEnd(&end); - iter != end; ++iter) { - if (!iter.GetValueRef().GetMessageValue().IsInitialized()) { + auto map = reflection->GetMap(message, field); + ABSL_DCHECK(map.ok()); + for (auto entry : *map) { + if (!entry.value().GetMessageValue().IsInitialized()) { return false; } } @@ -344,11 +341,10 @@ field->is_map() ? reflection->MutableMapData(message, field) : nullptr; if (map_field != nullptr && map_field->IsMapValid()) { if (IsMapValueMessageTyped(field)) { - MapIterator iter(message, field); - MapIterator end(message, field); - for (map_field->MapBegin(&iter), map_field->MapEnd(&end); iter != end; - ++iter) { - iter.MutableValueRef()->MutableMessageValue()->DiscardUnknownFields(); + auto map = reflection->MutableMap(message, field); + ABSL_DCHECK(map.ok()); + for (auto entry : *map) { + entry.value().MutableMessageValue()->DiscardUnknownFields(); } } // Discard every unknown field inside messages in a repeated field.
diff --git a/src/google/protobuf/reflection_tester.cc b/src/google/protobuf/reflection_tester.cc index 8934cf5..54a3392 100644 --- a/src/google/protobuf/reflection_tester.cc +++ b/src/google/protobuf/reflection_tester.cc
@@ -10,10 +10,14 @@ #include <cstddef> #include <cstdint> #include <string> +#include <variant> #include <vector> #include <gtest/gtest.h> #include "absl/container/flat_hash_map.h" +#include "absl/functional/overload.h" +#include "absl/log/absl_log.h" +#include "absl/status/statusor.h" #include "absl/strings/string_view.h" #include "google/protobuf/descriptor.h" #include "google/protobuf/map_field.h" @@ -400,226 +404,432 @@ foreign_c_, 1); } +namespace { + +constexpr absl::string_view kMapFields[] = { + "map_int32_int32", + "map_int64_int64", + "map_uint32_uint32", + "map_uint64_uint64", + "map_sint32_sint32", + "map_sint64_sint64", + "map_fixed32_fixed32", + "map_fixed64_fixed64", + "map_sfixed32_sfixed32", + "map_sfixed64_sfixed64", + "map_int32_float", + "map_int32_double", + "map_bool_bool", + "map_string_string", + "map_int32_bytes", + "map_int32_enum", + "map_int32_foreign_message", +}; + +struct EnumVal { + int value = 0; + friend bool operator==(EnumVal a, EnumVal b) { return a.value == b.value; } +}; + +using KeyVariant = + std::variant<int32_t, int64_t, uint32_t, uint64_t, bool, std::string>; +using ValueVariant = std::variant<int32_t, int64_t, uint32_t, uint64_t, float, + double, bool, std::string, EnumVal>; + +inline KeyVariant GetKeyVariant(const MapKey& key) { + switch (key.type()) { + case FieldDescriptor::CPPTYPE_INT32: + return key.GetInt32Value(); + case FieldDescriptor::CPPTYPE_INT64: + return key.GetInt64Value(); + case FieldDescriptor::CPPTYPE_UINT32: + return key.GetUInt32Value(); + case FieldDescriptor::CPPTYPE_UINT64: + return key.GetUInt64Value(); + case FieldDescriptor::CPPTYPE_BOOL: + return key.GetBoolValue(); + case FieldDescriptor::CPPTYPE_STRING: + return std::string(key.GetStringValue()); + default: + ABSL_LOG(FATAL) << "Unsupported key type: " << key.type(); + } +} + +template <typename T> +inline ValueVariant GetValueVariant(const T& ref) { + switch (ref.type()) { + case FieldDescriptor::CPPTYPE_INT32: + return ref.GetInt32Value(); + case FieldDescriptor::CPPTYPE_INT64: + return ref.GetInt64Value(); + case FieldDescriptor::CPPTYPE_UINT32: + return ref.GetUInt32Value(); + case FieldDescriptor::CPPTYPE_UINT64: + return ref.GetUInt64Value(); + case FieldDescriptor::CPPTYPE_FLOAT: + return ref.GetFloatValue(); + case FieldDescriptor::CPPTYPE_DOUBLE: + return ref.GetDoubleValue(); + case FieldDescriptor::CPPTYPE_BOOL: + return ref.GetBoolValue(); + case FieldDescriptor::CPPTYPE_STRING: + return std::string(ref.GetStringValue()); + case FieldDescriptor::CPPTYPE_ENUM: + return EnumVal{ref.GetEnumValue()}; + default: + ABSL_LOG(FATAL) << "Unsupported value type: " << ref.type(); + } +} + +inline void SetMapKey(MapKey& key, const KeyVariant& val) { + std::visit(absl::Overload{ + [&](int32_t v) { key.SetInt32Value(v); }, + [&](int64_t v) { key.SetInt64Value(v); }, + [&](uint32_t v) { key.SetUInt32Value(v); }, + [&](uint64_t v) { key.SetUInt64Value(v); }, + [&](bool v) { key.SetBoolValue(v); }, + [&](const std::string& v) { key.SetStringValue(v); }, + }, + val); +} + +inline MapKey MakeMapKey(const KeyVariant& val) { + MapKey key; + SetMapKey(key, val); + return key; +} + +inline void SetMapValue(MapValueRef ref, const ValueVariant& val) { + std::visit(absl::Overload{ + [&](int32_t v) { ref.SetInt32Value(v); }, + [&](int64_t v) { ref.SetInt64Value(v); }, + [&](uint32_t v) { ref.SetUInt32Value(v); }, + [&](uint64_t v) { ref.SetUInt64Value(v); }, + [&](float v) { ref.SetFloatValue(v); }, + [&](double v) { ref.SetDoubleValue(v); }, + [&](bool v) { ref.SetBoolValue(v); }, + [&](const std::string& v) { ref.SetStringValue(v); }, + [&](EnumVal v) { ref.SetEnumValue(v.value); }, + }, + val); +} + +void SetMapFieldHelper(absl::StatusOr<GenericMapRef> map_ref, + const KeyVariant& k0_val, const ValueVariant& val0, + const KeyVariant& k1_val, const ValueVariant& val1) { + GenericMapRef map = map_ref.value(); + MapKey key0 = MakeMapKey(k0_val); + MapKey key1 = MakeMapKey(k1_val); + + GenericConstMapRef cmap = map; + + EXPECT_TRUE(map.empty()); + EXPECT_TRUE(cmap.empty()); + EXPECT_EQ(map.size(), 0); + EXPECT_EQ(cmap.size(), 0); + EXPECT_FALSE(map.contains(key0)); + EXPECT_FALSE(cmap.contains(key0)); + EXPECT_EQ(map.find(key0), map.end()); + EXPECT_EQ(cmap.find(key0), cmap.end()); + + auto res0 = map.try_emplace(key0).value(); + EXPECT_TRUE(res0.inserted); + EXPECT_NE(res0.iter, map.end()); + EXPECT_EQ(res0.iter->key(), key0); + SetMapValue(res0.iter->value(), val0); + + EXPECT_FALSE(map.empty()); + EXPECT_FALSE(cmap.empty()); + EXPECT_EQ(map.size(), 1); + EXPECT_EQ(cmap.size(), 1); + EXPECT_TRUE(map.contains(key0)); + EXPECT_TRUE(cmap.contains(key0)); + EXPECT_NE(map.find(key0), map.end()); + EXPECT_NE(cmap.find(key0), cmap.end()); + EXPECT_EQ(GetValueVariant(map.find(key0)->value()), val0); + EXPECT_EQ(GetValueVariant(cmap.find(key0)->value()), val0); + + EXPECT_FALSE(map.contains(key1)); + EXPECT_FALSE(cmap.contains(key1)); + + auto res1 = map.try_emplace(key1).value(); + EXPECT_TRUE(res1.inserted); + EXPECT_EQ(map.size(), 2); + EXPECT_EQ(cmap.size(), 2); + EXPECT_TRUE(map.contains(key1)); + EXPECT_TRUE(cmap.contains(key1)); + + // Set the value for key1. + SetMapValue(res1.iter->value(), val1); + + // Duplicate insertion via try_emplace should return false and not overwrite. + auto dup = map.try_emplace(key1).value(); + EXPECT_FALSE(dup.inserted); + EXPECT_EQ(GetValueVariant(dup.iter->value()), val1); + + EXPECT_EQ(map.size(), 2); + EXPECT_EQ(cmap.size(), 2); + EXPECT_TRUE(map.contains(key0)); + EXPECT_TRUE(cmap.contains(key0)); + EXPECT_TRUE(map.contains(key1)); + EXPECT_TRUE(cmap.contains(key1)); + EXPECT_EQ(GetValueVariant(map.find(key1)->value()), val1); + EXPECT_EQ(GetValueVariant(cmap.find(key1)->value()), val1); + + // Clear and populate standard map elements for downstream tests. + map.clear(); + EXPECT_TRUE(map.empty()); + EXPECT_TRUE(cmap.empty()); + + KeyVariant std_k0, std_k1; + std::visit(absl::Overload{ + [&](int32_t) { + std_k0 = int32_t{0}; + std_k1 = int32_t{1}; + }, + [&](int64_t) { + std_k0 = int64_t{0}; + std_k1 = int64_t{1}; + }, + [&](uint32_t) { + std_k0 = uint32_t{0}; + std_k1 = uint32_t{1}; + }, + [&](uint64_t) { + std_k0 = uint64_t{0}; + std_k1 = uint64_t{1}; + }, + [&](bool) { + std_k0 = false; + std_k1 = true; + }, + [&](const std::string&) { + std_k0 = MapReflectionTester::long_string(); + std_k1 = MapReflectionTester::long_string_2(); + }, + }, + k0_val); + + ValueVariant std_v0, std_v1; + std::visit(absl::Overload{ + [&](int32_t) { + std_v0 = int32_t{0}; + std_v1 = int32_t{1}; + }, + [&](int64_t) { + std_v0 = int64_t{0}; + std_v1 = int64_t{1}; + }, + [&](uint32_t) { + std_v0 = uint32_t{0}; + std_v1 = uint32_t{1}; + }, + [&](uint64_t) { + std_v0 = uint64_t{0}; + std_v1 = uint64_t{1}; + }, + [&](float) { + std_v0 = 0.0f; + std_v1 = 1.0f; + }, + [&](double) { + std_v0 = 0.0; + std_v1 = 1.0; + }, + [&](bool) { + std_v0 = false; + std_v1 = true; + }, + [&](const std::string&) { + std_v0 = MapReflectionTester::long_string(); + std_v1 = MapReflectionTester::long_string_2(); + }, + [&](EnumVal) { + std_v0 = val0; + std_v1 = val1; + }, + }, + val0); + + SetMapValue(map.try_emplace(MakeMapKey(std_k0)).value().iter->value(), + std_v0); + SetMapValue(map.try_emplace(MakeMapKey(std_k1)).value().iter->value(), + std_v1); + EXPECT_EQ(map.size(), 2); + EXPECT_EQ(cmap.size(), 2); +} + +void ModifyMapFieldHelper(absl::StatusOr<GenericMapRef> map_ref, + const KeyVariant& k_val, + const ValueVariant& new_val) { + GenericMapRef map = map_ref.value(); + MapKey key = MakeMapKey(k_val); + EXPECT_EQ(map.size(), 2); + EXPECT_TRUE(map.contains(key)); + auto dup = map.try_emplace(key).value(); + EXPECT_FALSE(dup.inserted); + SetMapValue(map.find(key)->value(), new_val); + EXPECT_EQ(GetValueVariant(map.find(key)->value()), new_val); + EXPECT_EQ(map.size(), 2); +} + +template <typename MapRef, typename StdMap> +void ExpectMapIteratorHelper(MapRef map_ref, const StdMap& map) { + using KeyT = typename StdMap::key_type; + using ValT = typename StdMap::mapped_type; + EXPECT_EQ(map_ref.size(), map.size()); + EXPECT_FALSE(map_ref.empty()); + + size_t count = 0; + for (auto entry : map_ref) { + auto key = std::get<KeyT>(GetKeyVariant(entry.key())); + auto val = std::get<ValT>(GetValueVariant(entry.value())); + auto it = map.find(key); + ASSERT_NE(it, map.end()); + EXPECT_EQ(it->second, val); + ++count; + } + EXPECT_EQ(count, map.size()); + + // Iterator prefix/postfix ++ and arrow operator + auto it = map_ref.begin(); + ASSERT_NE(it, map_ref.end()); + EXPECT_EQ(GetValueVariant((*it).value()), GetValueVariant(it->value())); + EXPECT_EQ(GetKeyVariant((*it).key()), GetKeyVariant(it->key())); + auto it_copy = it++; + EXPECT_NE(it, it_copy); + EXPECT_EQ(it_copy, map_ref.begin()); +} + +} // namespace + void MapReflectionTester::SetMapFieldsViaMapReflection(Message* message) { const Reflection* reflection = message->GetReflection(); - Message* sub_foreign_message = nullptr; - MapValueRef map_val; - MapValueConstRef map_val_const; + SetMapFieldHelper(reflection->MutableMap(message, F("map_int32_int32")), + int32_t{10}, int32_t{11}, int32_t{20}, int32_t{21}); + SetMapFieldHelper(reflection->MutableMap(message, F("map_int64_int64")), + int64_t{10}, int64_t{11}, int64_t{20}, int64_t{21}); + SetMapFieldHelper(reflection->MutableMap(message, F("map_uint32_uint32")), + uint32_t{10}, uint32_t{11}, uint32_t{20}, uint32_t{21}); + SetMapFieldHelper(reflection->MutableMap(message, F("map_uint64_uint64")), + uint64_t{10}, uint64_t{11}, uint64_t{20}, uint64_t{21}); + SetMapFieldHelper(reflection->MutableMap(message, F("map_sint32_sint32")), + int32_t{10}, int32_t{11}, int32_t{20}, int32_t{21}); + SetMapFieldHelper(reflection->MutableMap(message, F("map_sint64_sint64")), + int64_t{10}, int64_t{11}, int64_t{20}, int64_t{21}); + SetMapFieldHelper(reflection->MutableMap(message, F("map_fixed32_fixed32")), + uint32_t{10}, uint32_t{11}, uint32_t{20}, uint32_t{21}); + SetMapFieldHelper(reflection->MutableMap(message, F("map_fixed64_fixed64")), + uint64_t{10}, uint64_t{11}, uint64_t{20}, uint64_t{21}); + SetMapFieldHelper(reflection->MutableMap(message, F("map_sfixed32_sfixed32")), + int32_t{10}, int32_t{11}, int32_t{20}, int32_t{21}); + SetMapFieldHelper(reflection->MutableMap(message, F("map_sfixed64_sfixed64")), + int64_t{10}, int64_t{11}, int64_t{20}, int64_t{21}); + SetMapFieldHelper(reflection->MutableMap(message, F("map_int32_float")), + int32_t{10}, 11.0f, int32_t{20}, 21.0f); + SetMapFieldHelper(reflection->MutableMap(message, F("map_int32_double")), + int32_t{10}, 11.0, int32_t{20}, 21.0); + SetMapFieldHelper(reflection->MutableMap(message, F("map_bool_bool")), false, + true, true, false); + SetMapFieldHelper(reflection->MutableMap(message, F("map_string_string")), + std::string("key_a"), std::string("val_a"), + std::string("key_b"), std::string("val_b")); + SetMapFieldHelper(reflection->MutableMap(message, F("map_int32_bytes")), + int32_t{10}, std::string("bytes_a"), int32_t{20}, + std::string("bytes_b")); + SetMapFieldHelper(reflection->MutableMap(message, F("map_int32_enum")), + int32_t{10}, EnumVal{map_enum_bar_->number()}, int32_t{20}, + EnumVal{map_enum_baz_->number()}); - // Add first element. - std::string map_key_string; - MapKey map_key; - map_key.SetInt32Value(0); - EXPECT_FALSE(reflection->LookupMapValue(*message, F("map_int32_int32"), - map_key, &map_val_const)); - EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int32_int32"), - map_key, &map_val)); - map_val.SetInt32Value(0); + // 17. map_int32_foreign_message + { + auto map = + reflection->MutableMap(message, F("map_int32_foreign_message")).value(); + EXPECT_TRUE(map.empty()); + EXPECT_EQ(map.size(), 0); - map_key.SetInt64Value(0); - EXPECT_FALSE(reflection->LookupMapValue(*message, F("map_int64_int64"), - map_key, &map_val_const)); - EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int64_int64"), - map_key, &map_val)); - map_val.SetInt64Value(0); + MapKey k0 = MakeMapKey(int32_t{10}); + MapKey k1 = MakeMapKey(int32_t{20}); - map_key.SetUInt32Value(0); - EXPECT_FALSE(reflection->LookupMapValue(*message, F("map_uint32_uint32"), - map_key, &map_val_const)); - EXPECT_TRUE(reflection->InsertOrLookupMapValue( - message, F("map_uint32_uint32"), map_key, &map_val)); - map_val.SetUInt32Value(0); + EXPECT_FALSE(map.contains(k0)); + EXPECT_EQ(map.find(k0), map.end()); - map_key.SetUInt64Value(0); - EXPECT_TRUE(reflection->InsertOrLookupMapValue( - message, F("map_uint64_uint64"), map_key, &map_val)); - map_val.SetUInt64Value(0); + auto res0 = map.try_emplace(k0).value(); + EXPECT_TRUE(res0.inserted); + EXPECT_NE(res0.iter, map.end()); + EXPECT_EQ(res0.iter->key(), k0); + Message* sub0 = res0.iter->value().MutableMessageValue(); + sub0->GetReflection()->SetInt32(sub0, foreign_c_, 11); - map_key.SetInt32Value(0); - EXPECT_TRUE(reflection->InsertOrLookupMapValue( - message, F("map_sint32_sint32"), map_key, &map_val)); - map_val.SetInt32Value(0); + EXPECT_FALSE(map.empty()); + EXPECT_EQ(map.size(), 1); + EXPECT_TRUE(map.contains(k0)); + const Message& read_sub0 = map.find(k0)->value().GetMessageValue(); + EXPECT_EQ(read_sub0.GetReflection()->GetInt32(read_sub0, foreign_c_), 11); - map_key.SetInt64Value(0); - EXPECT_TRUE(reflection->InsertOrLookupMapValue( - message, F("map_sint64_sint64"), map_key, &map_val)); - map_val.SetInt64Value(0); + EXPECT_FALSE(map.contains(k1)); - map_key.SetUInt32Value(0); - EXPECT_TRUE(reflection->InsertOrLookupMapValue( - message, F("map_fixed32_fixed32"), map_key, &map_val)); - map_val.SetUInt32Value(0); + auto res1 = map.try_emplace(k1).value(); + EXPECT_TRUE(res1.inserted); + Message* sub1 = res1.iter->value().MutableMessageValue(); + EXPECT_EQ(map.size(), 2); + EXPECT_TRUE(map.contains(k1)); + EXPECT_EQ(sub1->GetReflection()->GetInt32(*sub1, foreign_c_), 0); - map_key.SetUInt64Value(0); - EXPECT_TRUE(reflection->InsertOrLookupMapValue( - message, F("map_fixed64_fixed64"), map_key, &map_val)); - map_val.SetUInt64Value(0); + // Set the value for k1. + sub1->GetReflection()->SetInt32(sub1, foreign_c_, 21); - map_key.SetInt32Value(0); - EXPECT_TRUE(reflection->InsertOrLookupMapValue( - message, F("map_sfixed32_sfixed32"), map_key, &map_val)); - map_val.SetInt32Value(0); + auto dup = map.try_emplace(k1).value(); + EXPECT_FALSE(dup.inserted); - map_key.SetInt64Value(0); - EXPECT_TRUE(reflection->InsertOrLookupMapValue( - message, F("map_sfixed64_sfixed64"), map_key, &map_val)); - map_val.SetInt64Value(0); + EXPECT_EQ(map.size(), 2); + EXPECT_TRUE(map.contains(k0)); + EXPECT_TRUE(map.contains(k1)); + EXPECT_EQ(map.find(k1)->value().GetMessageValue().GetReflection()->GetInt32( + map.find(k1)->value().GetMessageValue(), foreign_c_), + 21); - map_key.SetInt32Value(0); - EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int32_float"), - map_key, &map_val)); - map_val.SetFloatValue(0.0); + GenericConstMapRef const_map = map; + EXPECT_EQ(const_map.size(), 2); + EXPECT_FALSE(const_map.empty()); + EXPECT_TRUE(const_map.contains(k0)); + EXPECT_TRUE(const_map.contains(k1)); + const Message& c_sub0 = const_map.find(k0)->value().GetMessageValue(); + EXPECT_EQ(c_sub0.GetReflection()->GetInt32(c_sub0, foreign_c_), 11); + const Message& c_sub1 = const_map.find(k1)->value().GetMessageValue(); + EXPECT_EQ(c_sub1.GetReflection()->GetInt32(c_sub1, foreign_c_), 21); - map_key.SetInt32Value(0); - EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int32_double"), - map_key, &map_val)); - map_val.SetDoubleValue(0.0); - - map_key.SetBoolValue(false); - EXPECT_FALSE(reflection->LookupMapValue(*message, F("map_bool_bool"), map_key, - &map_val_const)); - EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_bool_bool"), - map_key, &map_val)); - map_val.SetBoolValue(false); - - map_key_string = long_string(); - map_key.SetStringValue(map_key_string); - EXPECT_FALSE(reflection->LookupMapValue(*message, F("map_string_string"), - map_key, &map_val_const)); - EXPECT_TRUE(reflection->InsertOrLookupMapValue( - message, F("map_string_string"), map_key, &map_val)); - map_val.SetStringValue(long_string()); - - map_key.SetInt32Value(0); - EXPECT_FALSE(reflection->LookupMapValue(*message, F("map_int32_bytes"), - map_key, &map_val_const)); - EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int32_bytes"), - map_key, &map_val)); - map_val.SetStringValue(long_string()); - - map_key.SetInt32Value(0); - EXPECT_FALSE(reflection->LookupMapValue(*message, F("map_int32_enum"), - map_key, &map_val_const)); - EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int32_enum"), - map_key, &map_val)); - map_val.SetEnumValue(map_enum_bar_->number()); - - map_key.SetInt32Value(0); - EXPECT_FALSE(reflection->LookupMapValue( - *message, F("map_int32_foreign_message"), map_key, &map_val_const)); - EXPECT_TRUE(reflection->InsertOrLookupMapValue( - message, F("map_int32_foreign_message"), map_key, &map_val)); - sub_foreign_message = map_val.MutableMessageValue(); - sub_foreign_message->GetReflection()->SetInt32(sub_foreign_message, - foreign_c_, 0); - - // Add second element - map_key.SetInt32Value(1); - EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int32_int32"), - map_key, &map_val)); - map_val.SetInt32Value(1); - EXPECT_FALSE(reflection->InsertOrLookupMapValue(message, F("map_int32_int32"), - map_key, &map_val)); - - map_key.SetInt64Value(1); - EXPECT_TRUE(reflection->InsertOrLookupMapValue(message, F("map_int64_int64"), - map_key, &map_val)); - map_val.SetInt64Value(1); - EXPECT_FALSE(reflection->InsertOrLookupMapValue(message, F("map_int64_int64"), - map_key, &map_val)); - - map_key.SetUInt32Value(1); - reflection->InsertOrLookupMapValue(message, F("map_uint32_uint32"), map_key, - &map_val); - map_val.SetUInt32Value(1); - - map_key.SetUInt64Value(1); - reflection->InsertOrLookupMapValue(message, F("map_uint64_uint64"), map_key, - &map_val); - map_val.SetUInt64Value(1); - - map_key.SetInt32Value(1); - reflection->InsertOrLookupMapValue(message, F("map_sint32_sint32"), map_key, - &map_val); - map_val.SetInt32Value(1); - - map_key.SetInt64Value(1); - reflection->InsertOrLookupMapValue(message, F("map_sint64_sint64"), map_key, - &map_val); - map_val.SetInt64Value(1); - - map_key.SetUInt32Value(1); - reflection->InsertOrLookupMapValue(message, F("map_fixed32_fixed32"), map_key, - &map_val); - map_val.SetUInt32Value(1); - - map_key.SetUInt64Value(1); - reflection->InsertOrLookupMapValue(message, F("map_fixed64_fixed64"), map_key, - &map_val); - map_val.SetUInt64Value(1); - - map_key.SetInt32Value(1); - reflection->InsertOrLookupMapValue(message, F("map_sfixed32_sfixed32"), - map_key, &map_val); - map_val.SetInt32Value(1); - - map_key.SetInt64Value(1); - reflection->InsertOrLookupMapValue(message, F("map_sfixed64_sfixed64"), - map_key, &map_val); - map_val.SetInt64Value(1); - - map_key.SetInt32Value(1); - reflection->InsertOrLookupMapValue(message, F("map_int32_float"), map_key, - &map_val); - map_val.SetFloatValue(1.0); - - map_key.SetInt32Value(1); - reflection->InsertOrLookupMapValue(message, F("map_int32_double"), map_key, - &map_val); - map_val.SetDoubleValue(1.0); - - map_key.SetBoolValue(true); - reflection->InsertOrLookupMapValue(message, F("map_bool_bool"), map_key, - &map_val); - map_val.SetBoolValue(true); - - map_key_string = long_string_2(); - map_key.SetStringValue(map_key_string); - reflection->InsertOrLookupMapValue(message, F("map_string_string"), map_key, - &map_val); - map_val.SetStringValue(long_string_2()); - - map_key.SetInt32Value(1); - reflection->InsertOrLookupMapValue(message, F("map_int32_bytes"), map_key, - &map_val); - map_val.SetStringValue(long_string_2()); - - map_key.SetInt32Value(1); - reflection->InsertOrLookupMapValue(message, F("map_int32_enum"), map_key, - &map_val); - map_val.SetEnumValue(map_enum_baz_->number()); - - map_key.SetInt32Value(1); - EXPECT_TRUE(reflection->InsertOrLookupMapValue( - message, F("map_int32_foreign_message"), map_key, &map_val)); - sub_foreign_message = map_val.MutableMessageValue(); - sub_foreign_message->GetReflection()->SetInt32(sub_foreign_message, - foreign_c_, 1); -} - -void MapReflectionTester::GetMapValueViaMapReflection( - Message* message, absl::string_view field_name, const MapKey& map_key, - MapValueRef* map_val) { - const Reflection* reflection = message->GetReflection(); - EXPECT_FALSE(reflection->InsertOrLookupMapValue(message, F(field_name), - map_key, map_val)); + // Clear and set standard elements (k0=0 with c=0, k1=1 with c=1) + map.clear(); + EXPECT_TRUE(map.empty()); + MapKey final_k0 = MakeMapKey(int32_t{0}); + MapKey final_k1 = MakeMapKey(int32_t{1}); + Message* final_sub0 = + map.try_emplace(final_k0).value().iter->value().MutableMessageValue(); + final_sub0->GetReflection()->SetInt32(final_sub0, foreign_c_, 0); + Message* final_sub1 = + map.try_emplace(final_k1).value().iter->value().MutableMessageValue(); + final_sub1->GetReflection()->SetInt32(final_sub1, foreign_c_, 1); + EXPECT_EQ(map.size(), 2); + } } void MapReflectionTester::DeleteMapValueViaMapReflection( - Message* message, absl::string_view field_name, const MapKey& map_key) { + Message* message, absl::string_view field_name, MapKey map_key) { const Reflection* reflection = message->GetReflection(); - reflection->DeleteMapValue(message, F(field_name), map_key); + auto map = reflection->MutableMap(message, F(field_name)).value(); + + // We want to use the key once more after the first erase, so let's make sure + // string keys outlive the erase. + std::string str; + if (map_key.type() == FieldDescriptor::CPPTYPE_STRING) { + str = std::string(map_key.GetStringValue()); + map_key.SetStringValue(str); + } + + EXPECT_TRUE(map.erase(map_key)); + EXPECT_FALSE(map.erase(map_key)); } Message* MapReflectionTester::GetMapEntryViaReflection( @@ -628,34 +838,10 @@ return reflection->MutableRepeatedMessage(message, F(field_name), index); } -MapIterator MapReflectionTester::MapBegin(Message* message, - absl::string_view field_name) { - const Reflection* reflection = message->GetReflection(); - return reflection->MapBegin(message, F(field_name)); -} - -MapIterator MapReflectionTester::MapEnd(Message* message, - absl::string_view field_name) { - const Reflection* reflection = message->GetReflection(); - return reflection->MapEnd(message, F(field_name)); -} - -ConstMapIterator MapReflectionTester::ConstMapBegin( - const Message* message, absl::string_view field_name) { - const Reflection* reflection = message->GetReflection(); - return reflection->ConstMapBegin(message, F(field_name)); -} - -ConstMapIterator MapReflectionTester::ConstMapEnd( - const Message* message, absl::string_view field_name) { - const Reflection* reflection = message->GetReflection(); - return reflection->ConstMapEnd(message, F(field_name)); -} - int MapReflectionTester::MapSize(const Message& message, absl::string_view field_name) { - const Reflection* reflection = message.GetReflection(); - return reflection->MapSize(message, F(field_name)); + return static_cast<int>( + message.GetReflection()->GetMap(message, F(field_name)).value().size()); } void MapReflectionTester::ClearMapFieldsViaReflection(Message* message) { @@ -680,101 +866,72 @@ reflection->ClearField(message, F("map_int32_foreign_message")); } +void MapReflectionTester::ClearMapFieldsViaMapReflection(Message* message) { + const Reflection* reflection = message->GetReflection(); + for (absl::string_view name : kMapFields) { + auto map = reflection->MutableMap(message, F(name)).value(); + map.clear(); + EXPECT_TRUE(map.empty()); + EXPECT_EQ(map.size(), 0); + EXPECT_EQ(map.begin(), map.end()); + } +} + void MapReflectionTester::ModifyMapFieldsViaReflection(Message* message) { const Reflection* reflection = message->GetReflection(); - MapValueRef map_val; - Message* sub_foreign_message; - // Modify the second element - std::string map_key_string; - MapKey map_key; - map_key.SetInt32Value(1); - EXPECT_FALSE(reflection->InsertOrLookupMapValue(message, F("map_int32_int32"), - map_key, &map_val)); - map_val.SetInt32Value(2); + ModifyMapFieldHelper(reflection->MutableMap(message, F("map_int32_int32")), + int32_t{1}, int32_t{2}); + ModifyMapFieldHelper(reflection->MutableMap(message, F("map_int64_int64")), + int64_t{1}, int64_t{2}); + ModifyMapFieldHelper(reflection->MutableMap(message, F("map_uint32_uint32")), + uint32_t{1}, uint32_t{2}); + ModifyMapFieldHelper(reflection->MutableMap(message, F("map_uint64_uint64")), + uint64_t{1}, uint64_t{2}); + ModifyMapFieldHelper(reflection->MutableMap(message, F("map_sint32_sint32")), + int32_t{1}, int32_t{2}); + ModifyMapFieldHelper(reflection->MutableMap(message, F("map_sint64_sint64")), + int64_t{1}, int64_t{2}); + ModifyMapFieldHelper( + reflection->MutableMap(message, F("map_fixed32_fixed32")), uint32_t{1}, + uint32_t{2}); + ModifyMapFieldHelper( + reflection->MutableMap(message, F("map_fixed64_fixed64")), uint64_t{1}, + uint64_t{2}); + ModifyMapFieldHelper( + reflection->MutableMap(message, F("map_sfixed32_sfixed32")), int32_t{1}, + int32_t{2}); + ModifyMapFieldHelper( + reflection->MutableMap(message, F("map_sfixed64_sfixed64")), int64_t{1}, + int64_t{2}); + ModifyMapFieldHelper(reflection->MutableMap(message, F("map_int32_float")), + int32_t{1}, 2.0f); + ModifyMapFieldHelper(reflection->MutableMap(message, F("map_int32_double")), + int32_t{1}, 2.0); + ModifyMapFieldHelper(reflection->MutableMap(message, F("map_bool_bool")), + true, false); + ModifyMapFieldHelper(reflection->MutableMap(message, F("map_string_string")), + long_string_2(), std::string("2")); + ModifyMapFieldHelper(reflection->MutableMap(message, F("map_int32_bytes")), + int32_t{1}, std::string("2")); + ModifyMapFieldHelper(reflection->MutableMap(message, F("map_int32_enum")), + int32_t{1}, EnumVal{map_enum_foo_->number()}); - map_key.SetInt64Value(1); - EXPECT_FALSE(reflection->InsertOrLookupMapValue(message, F("map_int64_int64"), - map_key, &map_val)); - map_val.SetInt64Value(2); - - map_key.SetUInt32Value(1); - EXPECT_FALSE(reflection->InsertOrLookupMapValue( - message, F("map_uint32_uint32"), map_key, &map_val)); - map_val.SetUInt32Value(2); - - map_key.SetUInt64Value(1); - reflection->InsertOrLookupMapValue(message, F("map_uint64_uint64"), map_key, - &map_val); - map_val.SetUInt64Value(2); - - map_key.SetInt32Value(1); - reflection->InsertOrLookupMapValue(message, F("map_sint32_sint32"), map_key, - &map_val); - map_val.SetInt32Value(2); - - map_key.SetInt64Value(1); - reflection->InsertOrLookupMapValue(message, F("map_sint64_sint64"), map_key, - &map_val); - map_val.SetInt64Value(2); - - map_key.SetUInt32Value(1); - reflection->InsertOrLookupMapValue(message, F("map_fixed32_fixed32"), map_key, - &map_val); - map_val.SetUInt32Value(2); - - map_key.SetUInt64Value(1); - reflection->InsertOrLookupMapValue(message, F("map_fixed64_fixed64"), map_key, - &map_val); - map_val.SetUInt64Value(2); - - map_key.SetInt32Value(1); - reflection->InsertOrLookupMapValue(message, F("map_sfixed32_sfixed32"), - map_key, &map_val); - map_val.SetInt32Value(2); - - map_key.SetInt64Value(1); - reflection->InsertOrLookupMapValue(message, F("map_sfixed64_sfixed64"), - map_key, &map_val); - map_val.SetInt64Value(2); - - map_key.SetInt32Value(1); - reflection->InsertOrLookupMapValue(message, F("map_int32_float"), map_key, - &map_val); - map_val.SetFloatValue(2.0); - - map_key.SetInt32Value(1); - reflection->InsertOrLookupMapValue(message, F("map_int32_double"), map_key, - &map_val); - map_val.SetDoubleValue(2.0); - - map_key.SetBoolValue(true); - reflection->InsertOrLookupMapValue(message, F("map_bool_bool"), map_key, - &map_val); - map_val.SetBoolValue(false); - - map_key_string = long_string_2(); - map_key.SetStringValue(map_key_string); - reflection->InsertOrLookupMapValue(message, F("map_string_string"), map_key, - &map_val); - map_val.SetStringValue("2"); - - map_key.SetInt32Value(1); - reflection->InsertOrLookupMapValue(message, F("map_int32_bytes"), map_key, - &map_val); - map_val.SetStringValue("2"); - - map_key.SetInt32Value(1); - reflection->InsertOrLookupMapValue(message, F("map_int32_enum"), map_key, - &map_val); - map_val.SetEnumValue(map_enum_foo_->number()); - - map_key.SetInt32Value(1); - EXPECT_FALSE(reflection->InsertOrLookupMapValue( - message, F("map_int32_foreign_message"), map_key, &map_val)); - sub_foreign_message = map_val.MutableMessageValue(); - sub_foreign_message->GetReflection()->SetInt32(sub_foreign_message, - foreign_c_, 2); + { + MapKey k_int32 = MakeMapKey(int32_t{1}); + auto map = + reflection->MutableMap(message, F("map_int32_foreign_message")).value(); + EXPECT_EQ(map.size(), 2); + EXPECT_TRUE(map.contains(k_int32)); + auto dup = map.try_emplace(k_int32).value(); + EXPECT_FALSE(dup.inserted); + Message* sub = dup.iter->value().MutableMessageValue(); + sub->GetReflection()->SetInt32(sub, foreign_c_, 2); + EXPECT_EQ(sub->GetReflection()->GetInt32( + dup.iter->value().GetMessageValue(), foreign_c_), + 2); + EXPECT_EQ(map.size(), 2); + } } void MapReflectionTester::RemoveLastMapsViaReflection(Message* message) { @@ -817,6 +974,39 @@ } } +void MapReflectionTester::SwapMapsViaMapReflection(Message* message1, + Message* message2) { + const Reflection* reflection1 = message1->GetReflection(); + const Reflection* reflection2 = message2->GetReflection(); + for (absl::string_view name : kMapFields) { + auto map1 = reflection1->MutableMap(message1, F(name)).value(); + auto map2 = reflection2->MutableMap(message2, F(name)).value(); + EXPECT_TRUE(map1.swap(map2).ok()); + } +} + +void MapReflectionTester::AssignMapsViaMapReflection(Message* dst, + Message* src) { + const Reflection* dst_reflection = dst->GetReflection(); + const Reflection* src_reflection = src->GetReflection(); + for (absl::string_view name : kMapFields) { + auto dst_map = dst_reflection->MutableMap(dst, F(name)).value(); + auto src_map = src_reflection->MutableMap(src, F(name)).value(); + EXPECT_TRUE(dst_map.assign(src_map).ok()); + } +} + +void MapReflectionTester::EraseMapValuesViaMapReflectionIterator( + Message* message) { + const Reflection* reflection = message->GetReflection(); + for (absl::string_view name : kMapFields) { + auto map = reflection->MutableMap(message, F(name)).value(); + while (!map.empty()) { + map.erase(map.begin()->key()); + } + } +} + void MapReflectionTester::MutableUnknownFieldsOfMapFieldsViaReflection( Message* message) { const Reflection* reflection = message->GetReflection(); @@ -877,13 +1067,436 @@ void MapReflectionTester::ExpectMapFieldsSetViaReflection( const Message& message) { - std::string scratch; const Reflection* reflection = message.GetReflection(); const Message* sub_message; MapKey map_key; - MapValueConstRef map_value_const_ref; - // ----------------------------------------------------------------- + for (auto f : kMapFields) { + ASSERT_EQ(2, reflection->FieldSize(message, F(f))) << f; + ASSERT_EQ(2, reflection->GetMap(message, F(f)).value().size()) << f; + } + + { + absl::flat_hash_map<int32_t, int32_t> map = {{0, 0}, {1, 1}}; + for (int i = 0; i < 2; i++) { + if (IsRepeatedFieldValid(message, "map_int32_int32")) { + sub_message = + &reflection->GetRepeatedMessage(message, F("map_int32_int32"), i); + int32_t key = sub_message->GetReflection()->GetInt32( + *sub_message, map_int32_int32_key_); + int32_t val = sub_message->GetReflection()->GetInt32( + *sub_message, map_int32_int32_val_); + EXPECT_EQ(map[key], val); + } else { + map_key.SetInt32Value(i); + GenericConstMapRef map_ref = + reflection->GetMap(message, F("map_int32_int32")).value(); + ASSERT_TRUE(map_ref.contains(map_key)); + auto it = map_ref.find(map_key); + EXPECT_EQ(it->key().GetInt32Value(), i); + EXPECT_EQ(it->value().GetInt32Value(), map[i]); + } + } + } + { + absl::flat_hash_map<int64_t, int64_t> map = {{0, 0}, {1, 1}}; + for (int i = 0; i < 2; i++) { + if (IsRepeatedFieldValid(message, "map_int64_int64")) { + sub_message = + &reflection->GetRepeatedMessage(message, F("map_int64_int64"), i); + int64_t key = sub_message->GetReflection()->GetInt64( + *sub_message, map_int64_int64_key_); + int64_t val = sub_message->GetReflection()->GetInt64( + *sub_message, map_int64_int64_val_); + EXPECT_EQ(map[key], val); + } else { + map_key.SetInt64Value(i); + GenericConstMapRef map_ref = + reflection->GetMap(message, F("map_int64_int64")).value(); + ASSERT_TRUE(map_ref.contains(map_key)); + auto it = map_ref.find(map_key); + EXPECT_EQ(it->key().GetInt64Value(), i); + EXPECT_EQ(it->value().GetInt64Value(), map[i]); + } + } + } + { + absl::flat_hash_map<uint32_t, uint32_t> map = {{0, 0}, {1, 1}}; + for (int i = 0; i < 2; i++) { + if (IsRepeatedFieldValid(message, "map_uint32_uint32")) { + sub_message = + &reflection->GetRepeatedMessage(message, F("map_uint32_uint32"), i); + uint32_t key = sub_message->GetReflection()->GetUInt32( + *sub_message, map_uint32_uint32_key_); + uint32_t val = sub_message->GetReflection()->GetUInt32( + *sub_message, map_uint32_uint32_val_); + EXPECT_EQ(map[key], val); + } else { + map_key.SetUInt32Value(i); + GenericConstMapRef map_ref = + reflection->GetMap(message, F("map_uint32_uint32")).value(); + ASSERT_TRUE(map_ref.contains(map_key)); + auto it = map_ref.find(map_key); + EXPECT_EQ(it->key().GetUInt32Value(), i); + EXPECT_EQ(it->value().GetUInt32Value(), map[i]); + } + } + } + { + absl::flat_hash_map<uint64_t, uint64_t> map = {{0, 0}, {1, 1}}; + for (int i = 0; i < 2; i++) { + if (IsRepeatedFieldValid(message, "map_uint64_uint64")) { + sub_message = + &reflection->GetRepeatedMessage(message, F("map_uint64_uint64"), i); + uint64_t key = sub_message->GetReflection()->GetUInt64( + *sub_message, map_uint64_uint64_key_); + uint64_t val = sub_message->GetReflection()->GetUInt64( + *sub_message, map_uint64_uint64_val_); + EXPECT_EQ(map[key], val); + } else { + map_key.SetUInt64Value(i); + GenericConstMapRef map_ref = + reflection->GetMap(message, F("map_uint64_uint64")).value(); + ASSERT_TRUE(map_ref.contains(map_key)); + auto it = map_ref.find(map_key); + EXPECT_EQ(it->key().GetUInt64Value(), i); + EXPECT_EQ(it->value().GetUInt64Value(), map[i]); + } + } + } + { + absl::flat_hash_map<int32_t, int32_t> map = {{0, 0}, {1, 1}}; + for (int i = 0; i < 2; i++) { + if (IsRepeatedFieldValid(message, "map_sint32_sint32")) { + sub_message = + &reflection->GetRepeatedMessage(message, F("map_sint32_sint32"), i); + int32_t key = sub_message->GetReflection()->GetInt32( + *sub_message, map_sint32_sint32_key_); + int32_t val = sub_message->GetReflection()->GetInt32( + *sub_message, map_sint32_sint32_val_); + EXPECT_EQ(map[key], val); + } else { + map_key.SetInt32Value(i); + GenericConstMapRef map_ref = + reflection->GetMap(message, F("map_sint32_sint32")).value(); + ASSERT_TRUE(map_ref.contains(map_key)); + auto it = map_ref.find(map_key); + EXPECT_EQ(it->key().GetInt32Value(), i); + EXPECT_EQ(it->value().GetInt32Value(), map[i]); + } + } + } + { + absl::flat_hash_map<int64_t, int64_t> map = {{0, 0}, {1, 1}}; + for (int i = 0; i < 2; i++) { + if (IsRepeatedFieldValid(message, "map_sint64_sint64")) { + sub_message = + &reflection->GetRepeatedMessage(message, F("map_sint64_sint64"), i); + int64_t key = sub_message->GetReflection()->GetInt64( + *sub_message, map_sint64_sint64_key_); + int64_t val = sub_message->GetReflection()->GetInt64( + *sub_message, map_sint64_sint64_val_); + EXPECT_EQ(map[key], val); + } else { + map_key.SetInt64Value(i); + GenericConstMapRef map_ref = + reflection->GetMap(message, F("map_sint64_sint64")).value(); + ASSERT_TRUE(map_ref.contains(map_key)); + auto it = map_ref.find(map_key); + EXPECT_EQ(it->key().GetInt64Value(), i); + EXPECT_EQ(it->value().GetInt64Value(), map[i]); + } + } + } + { + absl::flat_hash_map<uint32_t, uint32_t> map = {{0, 0}, {1, 1}}; + for (int i = 0; i < 2; i++) { + if (IsRepeatedFieldValid(message, "map_fixed32_fixed32")) { + sub_message = &reflection->GetRepeatedMessage( + message, F("map_fixed32_fixed32"), i); + uint32_t key = sub_message->GetReflection()->GetUInt32( + *sub_message, map_fixed32_fixed32_key_); + uint32_t val = sub_message->GetReflection()->GetUInt32( + *sub_message, map_fixed32_fixed32_val_); + EXPECT_EQ(map[key], val); + } else { + map_key.SetUInt32Value(i); + GenericConstMapRef map_ref = + reflection->GetMap(message, F("map_fixed32_fixed32")).value(); + ASSERT_TRUE(map_ref.contains(map_key)); + auto it = map_ref.find(map_key); + EXPECT_EQ(it->key().GetUInt32Value(), i); + EXPECT_EQ(it->value().GetUInt32Value(), map[i]); + } + } + } + { + absl::flat_hash_map<uint64_t, uint64_t> map = {{0, 0}, {1, 1}}; + for (int i = 0; i < 2; i++) { + if (IsRepeatedFieldValid(message, "map_fixed64_fixed64")) { + sub_message = &reflection->GetRepeatedMessage( + message, F("map_fixed64_fixed64"), i); + uint64_t key = sub_message->GetReflection()->GetUInt64( + *sub_message, map_fixed64_fixed64_key_); + uint64_t val = sub_message->GetReflection()->GetUInt64( + *sub_message, map_fixed64_fixed64_val_); + EXPECT_EQ(map[key], val); + } else { + map_key.SetUInt64Value(i); + GenericConstMapRef map_ref = + reflection->GetMap(message, F("map_fixed64_fixed64")).value(); + ASSERT_TRUE(map_ref.contains(map_key)); + auto it = map_ref.find(map_key); + EXPECT_EQ(it->key().GetUInt64Value(), i); + EXPECT_EQ(it->value().GetUInt64Value(), map[i]); + } + } + } + { + absl::flat_hash_map<int32_t, int32_t> map = {{0, 0}, {1, 1}}; + for (int i = 0; i < 2; i++) { + if (IsRepeatedFieldValid(message, "map_sfixed32_sfixed32")) { + sub_message = &reflection->GetRepeatedMessage( + message, F("map_sfixed32_sfixed32"), i); + int32_t key = sub_message->GetReflection()->GetInt32( + *sub_message, map_sfixed32_sfixed32_key_); + int32_t val = sub_message->GetReflection()->GetInt32( + *sub_message, map_sfixed32_sfixed32_val_); + EXPECT_EQ(map[key], val); + } else { + map_key.SetInt32Value(i); + GenericConstMapRef map_ref = + reflection->GetMap(message, F("map_sfixed32_sfixed32")).value(); + ASSERT_TRUE(map_ref.contains(map_key)); + auto it = map_ref.find(map_key); + EXPECT_EQ(it->key().GetInt32Value(), i); + EXPECT_EQ(it->value().GetInt32Value(), map[i]); + } + } + } + { + absl::flat_hash_map<int64_t, int64_t> map = {{0, 0}, {1, 1}}; + for (int i = 0; i < 2; i++) { + if (IsRepeatedFieldValid(message, "map_sfixed64_sfixed64")) { + sub_message = &reflection->GetRepeatedMessage( + message, F("map_sfixed64_sfixed64"), i); + int64_t key = sub_message->GetReflection()->GetInt64( + *sub_message, map_sfixed64_sfixed64_key_); + int64_t val = sub_message->GetReflection()->GetInt64( + *sub_message, map_sfixed64_sfixed64_val_); + EXPECT_EQ(map[key], val); + } else { + map_key.SetInt64Value(i); + GenericConstMapRef map_ref = + reflection->GetMap(message, F("map_sfixed64_sfixed64")).value(); + ASSERT_TRUE(map_ref.contains(map_key)); + auto it = map_ref.find(map_key); + EXPECT_EQ(it->key().GetInt64Value(), i); + EXPECT_EQ(it->value().GetInt64Value(), map[i]); + } + } + } + { + absl::flat_hash_map<int32_t, float> map = {{0, 0.0f}, {1, 1.0f}}; + for (int i = 0; i < 2; i++) { + if (IsRepeatedFieldValid(message, "map_int32_float")) { + sub_message = + &reflection->GetRepeatedMessage(message, F("map_int32_float"), i); + int32_t key = sub_message->GetReflection()->GetInt32( + *sub_message, map_int32_float_key_); + float val = sub_message->GetReflection()->GetFloat( + *sub_message, map_int32_float_val_); + EXPECT_EQ(map[key], val); + } else { + map_key.SetInt32Value(i); + GenericConstMapRef map_ref = + reflection->GetMap(message, F("map_int32_float")).value(); + ASSERT_TRUE(map_ref.contains(map_key)); + auto it = map_ref.find(map_key); + EXPECT_EQ(it->key().GetInt32Value(), i); + EXPECT_EQ(it->value().GetFloatValue(), map[i]); + } + } + } + { + absl::flat_hash_map<int32_t, double> map = {{0, 0.0}, {1, 1.0}}; + for (int i = 0; i < 2; i++) { + if (IsRepeatedFieldValid(message, "map_int32_double")) { + sub_message = + &reflection->GetRepeatedMessage(message, F("map_int32_double"), i); + int32_t key = sub_message->GetReflection()->GetInt32( + *sub_message, map_int32_double_key_); + double val = sub_message->GetReflection()->GetDouble( + *sub_message, map_int32_double_val_); + EXPECT_EQ(map[key], val); + } else { + map_key.SetInt32Value(i); + GenericConstMapRef map_ref = + reflection->GetMap(message, F("map_int32_double")).value(); + ASSERT_TRUE(map_ref.contains(map_key)); + auto it = map_ref.find(map_key); + EXPECT_EQ(it->key().GetInt32Value(), i); + EXPECT_EQ(it->value().GetDoubleValue(), map[i]); + } + } + } + { + std::array<bool, 2> map = {false, true}; + std::vector<bool> keys = {false, true}; + std::vector<bool> vals = {false, true}; + for (int i = 0; i < 2; i++) { + if (IsRepeatedFieldValid(message, "map_bool_bool")) { + sub_message = + &reflection->GetRepeatedMessage(message, F("map_bool_bool"), i); + bool key = sub_message->GetReflection()->GetBool(*sub_message, + map_bool_bool_key_); + bool val = sub_message->GetReflection()->GetBool(*sub_message, + map_bool_bool_val_); + EXPECT_EQ(map[key ? 1 : 0], val); + } else { + map_key.SetBoolValue(keys[i]); + GenericConstMapRef map_ref = + reflection->GetMap(message, F("map_bool_bool")).value(); + ASSERT_TRUE(map_ref.contains(map_key)); + auto it = map_ref.find(map_key); + EXPECT_EQ(it->key().GetBoolValue(), keys[i]); + EXPECT_EQ(it->value().GetBoolValue(), vals[i]); + } + } + } + { + absl::flat_hash_map<std::string, std::string> map = { + {long_string(), long_string()}, {long_string_2(), long_string_2()}}; + std::vector<std::string> keys = {long_string(), long_string_2()}; + std::vector<std::string> vals = {long_string(), long_string_2()}; + for (int i = 0; i < 2; i++) { + if (IsRepeatedFieldValid(message, "map_string_string")) { + sub_message = + &reflection->GetRepeatedMessage(message, F("map_string_string"), i); + std::string key = sub_message->GetReflection()->GetString( + *sub_message, map_string_string_key_); + std::string val = sub_message->GetReflection()->GetString( + *sub_message, map_string_string_val_); + EXPECT_EQ(map[key], val); + } else { + map_key.SetStringValue(keys[i]); + GenericConstMapRef map_ref = + reflection->GetMap(message, F("map_string_string")).value(); + ASSERT_TRUE(map_ref.contains(map_key)); + auto it = map_ref.find(map_key); + EXPECT_EQ(it->key().GetStringValue(), keys[i]); + EXPECT_EQ(it->value().GetStringValue(), vals[i]); + } + } + } + { + absl::flat_hash_map<int32_t, std::string> map = {{0, long_string()}, + {1, long_string_2()}}; + for (int i = 0; i < 2; i++) { + if (IsRepeatedFieldValid(message, "map_int32_bytes")) { + sub_message = + &reflection->GetRepeatedMessage(message, F("map_int32_bytes"), i); + int32_t key = sub_message->GetReflection()->GetInt32( + *sub_message, map_int32_bytes_key_); + std::string val = sub_message->GetReflection()->GetString( + *sub_message, map_int32_bytes_val_); + EXPECT_EQ(map[key], val); + } else { + map_key.SetInt32Value(i); + GenericConstMapRef map_ref = + reflection->GetMap(message, F("map_int32_bytes")).value(); + ASSERT_TRUE(map_ref.contains(map_key)); + auto it = map_ref.find(map_key); + EXPECT_EQ(it->key().GetInt32Value(), i); + EXPECT_EQ(it->value().GetStringValue(), map[i]); + } + } + } + { + absl::flat_hash_map<int32_t, const EnumValueDescriptor*> map = { + {0, map_enum_bar_}, {1, map_enum_baz_}}; + for (int i = 0; i < 2; i++) { + if (IsRepeatedFieldValid(message, "map_int32_enum")) { + sub_message = + &reflection->GetRepeatedMessage(message, F("map_int32_enum"), i); + int32_t key = sub_message->GetReflection()->GetInt32( + *sub_message, map_int32_enum_key_); + PROTOBUF_IGNORE_DEPRECATION_START + const EnumValueDescriptor* val = sub_message->GetReflection()->GetEnum( + *sub_message, map_int32_enum_val_); + PROTOBUF_IGNORE_DEPRECATION_STOP + EXPECT_EQ(map[key], val); + } else { + map_key.SetInt32Value(i); + GenericConstMapRef map_ref = + reflection->GetMap(message, F("map_int32_enum")).value(); + ASSERT_TRUE(map_ref.contains(map_key)); + auto it = map_ref.find(map_key); + EXPECT_EQ(it->key().GetInt32Value(), i); + EXPECT_EQ(it->value().GetEnumValue(), map[i]->number()); + } + } + } + { + absl::flat_hash_map<int32_t, int32_t> map = {{0, 0}, {1, 1}}; + for (int i = 0; i < 2; i++) { + if (IsRepeatedFieldValid(message, "map_int32_foreign_message")) { + sub_message = &reflection->GetRepeatedMessage( + message, F("map_int32_foreign_message"), i); + int32_t key = sub_message->GetReflection()->GetInt32( + *sub_message, map_int32_foreign_message_key_); + const Message& foreign_message = + sub_message->GetReflection()->GetMessage( + *sub_message, map_int32_foreign_message_val_); + int32_t val = foreign_message.GetReflection()->GetInt32(foreign_message, + foreign_c_); + EXPECT_EQ(map[key], val); + } else { + map_key.SetInt32Value(i); + GenericConstMapRef map_ref = + reflection->GetMap(message, F("map_int32_foreign_message")).value(); + ASSERT_TRUE(map_ref.contains(map_key)); + auto it = map_ref.find(map_key); + EXPECT_EQ(it->key().GetInt32Value(), i); + const Message& foreign_message = it->value().GetMessageValue(); + EXPECT_EQ(foreign_message.GetReflection()->GetInt32(foreign_message, + foreign_c_), + map[i]); + } + } + } +} + +void MapReflectionTester::ExpectMapFieldsSetViaReflectionIterator( + Message* message) { + ExpectMapFieldsSetViaReflectionIterator(*message); + + // Also test mutable iteration, operator[], and at() on Message* + const Reflection* reflection = message->GetReflection(); + for (absl::string_view name : kMapFields) { + GenericMapRef mut_map = reflection->MutableMap(message, F(name)).value(); + EXPECT_EQ(mut_map.size(), 2); + EXPECT_FALSE(mut_map.empty()); + + size_t count = 0; + for (auto entry : mut_map) { + EXPECT_NE(entry.key().type(), FieldDescriptor::CPPTYPE_MESSAGE); + ++count; + } + EXPECT_EQ(count, 2); + + // Test conversion from MapIterator to MapConstIterator + GenericConstMapRef::iterator cit = mut_map.begin(); + EXPECT_TRUE(cit == mut_map.begin()); + EXPECT_FALSE(cit != mut_map.begin()); + EXPECT_EQ(cit->key(), mut_map.begin()->key()); + } +} + +void MapReflectionTester::ExpectMapFieldsSetViaReflectionIterator( + const Message& message) { + std::string serialized; + const Reflection* reflection = message.GetReflection(); ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_int32"))); ASSERT_EQ(2, reflection->FieldSize(message, F("map_int64_int64"))); @@ -903,737 +1516,137 @@ ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_enum"))); ASSERT_EQ(2, reflection->FieldSize(message, F("map_int32_foreign_message"))); + // Const methods do not invalidate map. + (void)message.DebugString(); + (void)message.ShortDebugString(); + EXPECT_TRUE(message.SerializeToString(&serialized)); + (void)message.SpaceUsedLong(); + (void)message.ByteSizeLong(); + { absl::flat_hash_map<int32_t, int32_t> map; map[0] = 0; map[1] = 1; - for (int i = 0; i < 2; i++) { - const internal::MapFieldBase& map_field = - reflection->GetRaw<internal::MapFieldBase>(message, - F("map_int32_int32")); - if (map_field.IsRepeatedFieldValid()) { - // Check with RepeatedField Reflection - sub_message = - &reflection->GetRepeatedMessage(message, F("map_int32_int32"), i); - int32_t key = sub_message->GetReflection()->GetInt32( - *sub_message, map_int32_int32_key_); - int32_t val = sub_message->GetReflection()->GetInt32( - *sub_message, map_int32_int32_val_); - EXPECT_EQ(map[key], val); - } else { - // Check with Map Reflection - map_key.SetInt32Value(i); - EXPECT_TRUE( - reflection->ContainsMapKey(message, F("map_int32_int32"), map_key)); - EXPECT_TRUE(reflection->LookupMapValue(message, F("map_int32_int32"), - map_key, &map_value_const_ref)); - EXPECT_EQ(map_value_const_ref.GetInt32Value(), map[i]); - } - } + ExpectMapIteratorHelper( + reflection->GetMap(message, F("map_int32_int32")).value(), map); } { absl::flat_hash_map<int64_t, int64_t> map; map[0] = 0; map[1] = 1; - for (int i = 0; i < 2; i++) { - const internal::MapFieldBase& map_field = - reflection->GetRaw<internal::MapFieldBase>(message, - F("map_int64_int64")); - if (map_field.IsRepeatedFieldValid()) { - // Check with RepeatedField Reflection - sub_message = - &reflection->GetRepeatedMessage(message, F("map_int64_int64"), i); - int64_t key = sub_message->GetReflection()->GetInt64( - *sub_message, map_int64_int64_key_); - int64_t val = sub_message->GetReflection()->GetInt64( - *sub_message, map_int64_int64_val_); - EXPECT_EQ(map[key], val); - } else { - // Check with Map Reflection - map_key.SetInt64Value(i); - EXPECT_TRUE( - reflection->ContainsMapKey(message, F("map_int64_int64"), map_key)); - EXPECT_TRUE(reflection->LookupMapValue(message, F("map_int64_int64"), - map_key, &map_value_const_ref)); - EXPECT_EQ(map_value_const_ref.GetInt64Value(), map[i]); - } - } + ExpectMapIteratorHelper( + reflection->GetMap(message, F("map_int64_int64")).value(), map); } { absl::flat_hash_map<uint32_t, uint32_t> map; map[0] = 0; map[1] = 1; - for (int i = 0; i < 2; i++) { - const internal::MapFieldBase& map_field = - reflection->GetRaw<internal::MapFieldBase>(message, - F("map_uint32_uint32")); - if (map_field.IsRepeatedFieldValid()) { - // Check with RepeatedField Reflection - sub_message = - &reflection->GetRepeatedMessage(message, F("map_uint32_uint32"), i); - uint32_t key = sub_message->GetReflection()->GetUInt32( - *sub_message, map_uint32_uint32_key_); - uint32_t val = sub_message->GetReflection()->GetUInt32( - *sub_message, map_uint32_uint32_val_); - EXPECT_EQ(map[key], val); - } else { - // Check with Map Reflection - map_key.SetUInt32Value(i); - EXPECT_TRUE(reflection->ContainsMapKey(message, F("map_uint32_uint32"), - map_key)); - EXPECT_TRUE(reflection->LookupMapValue(message, F("map_uint32_uint32"), - map_key, &map_value_const_ref)); - EXPECT_EQ(map_value_const_ref.GetUInt32Value(), map[i]); - } - } + ExpectMapIteratorHelper( + reflection->GetMap(message, F("map_uint32_uint32")).value(), map); } { absl::flat_hash_map<uint64_t, uint64_t> map; map[0] = 0; map[1] = 1; - for (int i = 0; i < 2; i++) { - const internal::MapFieldBase& map_field = - reflection->GetRaw<internal::MapFieldBase>(message, - F("map_uint64_uint64")); - if (map_field.IsRepeatedFieldValid()) { - // Check with RepeatedField Reflection - sub_message = - &reflection->GetRepeatedMessage(message, F("map_uint64_uint64"), i); - uint64_t key = sub_message->GetReflection()->GetUInt64( - *sub_message, map_uint64_uint64_key_); - uint64_t val = sub_message->GetReflection()->GetUInt64( - *sub_message, map_uint64_uint64_val_); - EXPECT_EQ(map[key], val); - } else { - // Check with Map Reflection - map_key.SetUInt64Value(i); - EXPECT_TRUE(reflection->ContainsMapKey(message, F("map_uint64_uint64"), - map_key)); - EXPECT_TRUE(reflection->LookupMapValue(message, F("map_uint64_uint64"), - map_key, &map_value_const_ref)); - EXPECT_EQ(map_value_const_ref.GetUInt64Value(), map[i]); - } - } + ExpectMapIteratorHelper( + reflection->GetMap(message, F("map_uint64_uint64")).value(), map); } { absl::flat_hash_map<int32_t, int32_t> map; map[0] = 0; map[1] = 1; - for (int i = 0; i < 2; i++) { - const internal::MapFieldBase& map_field = - reflection->GetRaw<internal::MapFieldBase>(message, - F("map_sint32_sint32")); - if (map_field.IsRepeatedFieldValid()) { - // Check with RepeatedField Reflection - sub_message = - &reflection->GetRepeatedMessage(message, F("map_sint32_sint32"), i); - int32_t key = sub_message->GetReflection()->GetInt32( - *sub_message, map_sint32_sint32_key_); - int32_t val = sub_message->GetReflection()->GetInt32( - *sub_message, map_sint32_sint32_val_); - EXPECT_EQ(map[key], val); - } else { - // Check with Map Reflection - map_key.SetInt32Value(i); - EXPECT_EQ(true, reflection->ContainsMapKey( - message, F("map_sint32_sint32"), map_key)); - EXPECT_TRUE(reflection->LookupMapValue(message, F("map_sint32_sint32"), - map_key, &map_value_const_ref)); - EXPECT_EQ(map_value_const_ref.GetInt32Value(), map[i]); - } - } + ExpectMapIteratorHelper( + reflection->GetMap(message, F("map_sint32_sint32")).value(), map); } { absl::flat_hash_map<int64_t, int64_t> map; map[0] = 0; map[1] = 1; - for (int i = 0; i < 2; i++) { - const internal::MapFieldBase& map_field = - reflection->GetRaw<internal::MapFieldBase>(message, - F("map_sint64_sint64")); - if (map_field.IsRepeatedFieldValid()) { - // Check with RepeatedField Reflection - sub_message = - &reflection->GetRepeatedMessage(message, F("map_sint64_sint64"), i); - int64_t key = sub_message->GetReflection()->GetInt64( - *sub_message, map_sint64_sint64_key_); - int64_t val = sub_message->GetReflection()->GetInt64( - *sub_message, map_sint64_sint64_val_); - EXPECT_EQ(map[key], val); - } else { - // Check with Map Reflection - map_key.SetInt64Value(i); - EXPECT_EQ(true, reflection->ContainsMapKey( - message, F("map_sint64_sint64"), map_key)); - EXPECT_TRUE(reflection->LookupMapValue(message, F("map_sint64_sint64"), - map_key, &map_value_const_ref)); - EXPECT_EQ(map_value_const_ref.GetInt64Value(), map[i]); - } - } + ExpectMapIteratorHelper( + reflection->GetMap(message, F("map_sint64_sint64")).value(), map); } { absl::flat_hash_map<uint32_t, uint32_t> map; map[0] = 0; map[1] = 1; - for (int i = 0; i < 2; i++) { - const internal::MapFieldBase& map_field = - reflection->GetRaw<internal::MapFieldBase>(message, - F("map_fixed32_fixed32")); - if (map_field.IsRepeatedFieldValid()) { - // Check with RepeatedField Reflection - sub_message = &reflection->GetRepeatedMessage( - message, F("map_fixed32_fixed32"), i); - uint32_t key = sub_message->GetReflection()->GetUInt32( - *sub_message, map_fixed32_fixed32_key_); - uint32_t val = sub_message->GetReflection()->GetUInt32( - *sub_message, map_fixed32_fixed32_val_); - EXPECT_EQ(map[key], val); - } else { - // Check with Map Reflection - map_key.SetUInt32Value(i); - EXPECT_EQ(true, reflection->ContainsMapKey( - message, F("map_fixed32_fixed32"), map_key)); - EXPECT_TRUE(reflection->LookupMapValue( - message, F("map_fixed32_fixed32"), map_key, &map_value_const_ref)); - EXPECT_EQ(map_value_const_ref.GetUInt32Value(), map[i]); - } - } + ExpectMapIteratorHelper( + reflection->GetMap(message, F("map_fixed32_fixed32")).value(), map); } { absl::flat_hash_map<uint64_t, uint64_t> map; map[0] = 0; map[1] = 1; - for (int i = 0; i < 2; i++) { - const internal::MapFieldBase& map_field = - reflection->GetRaw<internal::MapFieldBase>(message, - F("map_fixed64_fixed64")); - if (map_field.IsRepeatedFieldValid()) { - // Check with RepeatedField Reflection - sub_message = &reflection->GetRepeatedMessage( - message, F("map_fixed64_fixed64"), i); - uint64_t key = sub_message->GetReflection()->GetUInt64( - *sub_message, map_fixed64_fixed64_key_); - uint64_t val = sub_message->GetReflection()->GetUInt64( - *sub_message, map_fixed64_fixed64_val_); - EXPECT_EQ(map[key], val); - } else { - // Check with Map Reflection - map_key.SetUInt64Value(i); - EXPECT_EQ(true, reflection->ContainsMapKey( - message, F("map_fixed64_fixed64"), map_key)); - EXPECT_TRUE(reflection->LookupMapValue( - message, F("map_fixed64_fixed64"), map_key, &map_value_const_ref)); - EXPECT_EQ(map_value_const_ref.GetUInt64Value(), map[i]); - } - } + ExpectMapIteratorHelper( + reflection->GetMap(message, F("map_fixed64_fixed64")).value(), map); } { absl::flat_hash_map<int32_t, int32_t> map; map[0] = 0; map[1] = 1; - for (int i = 0; i < 2; i++) { - const internal::MapFieldBase& map_field = - reflection->GetRaw<internal::MapFieldBase>( - message, F("map_sfixed32_sfixed32")); - if (map_field.IsRepeatedFieldValid()) { - // Check with RepeatedField Reflection - sub_message = &reflection->GetRepeatedMessage( - message, F("map_sfixed32_sfixed32"), i); - int32_t key = sub_message->GetReflection()->GetInt32( - *sub_message, map_sfixed32_sfixed32_key_); - int32_t val = sub_message->GetReflection()->GetInt32( - *sub_message, map_sfixed32_sfixed32_val_); - EXPECT_EQ(map[key], val); - } else { - // Check with Map Reflection - map_key.SetInt32Value(i); - EXPECT_EQ(true, reflection->ContainsMapKey( - message, F("map_sfixed32_sfixed32"), map_key)); - EXPECT_TRUE(reflection->LookupMapValue(message, - F("map_sfixed32_sfixed32"), - map_key, &map_value_const_ref)); - EXPECT_EQ(map_value_const_ref.GetInt32Value(), map[i]); - } - } + ExpectMapIteratorHelper( + reflection->GetMap(message, F("map_sfixed32_sfixed32")).value(), map); } { absl::flat_hash_map<int64_t, int64_t> map; map[0] = 0; map[1] = 1; - for (int i = 0; i < 2; i++) { - const internal::MapFieldBase& map_field = - reflection->GetRaw<internal::MapFieldBase>( - message, F("map_sfixed64_sfixed64")); - if (map_field.IsRepeatedFieldValid()) { - // Check with RepeatedField Reflection - sub_message = &reflection->GetRepeatedMessage( - message, F("map_sfixed64_sfixed64"), i); - int64_t key = sub_message->GetReflection()->GetInt64( - *sub_message, map_sfixed64_sfixed64_key_); - int64_t val = sub_message->GetReflection()->GetInt64( - *sub_message, map_sfixed64_sfixed64_val_); - EXPECT_EQ(map[key], val); - } else { - // Check with Map Reflection - map_key.SetInt64Value(i); - EXPECT_EQ(true, reflection->ContainsMapKey( - message, F("map_sfixed64_sfixed64"), map_key)); - EXPECT_TRUE(reflection->LookupMapValue(message, - F("map_sfixed64_sfixed64"), - map_key, &map_value_const_ref)); - EXPECT_EQ(map_value_const_ref.GetInt64Value(), map[i]); - } - } + ExpectMapIteratorHelper( + reflection->GetMap(message, F("map_sfixed64_sfixed64")).value(), map); } { absl::flat_hash_map<int32_t, float> map; - map[0] = 0.0; - map[1] = 1.0; - for (int i = 0; i < 2; i++) { - const internal::MapFieldBase& map_field = - reflection->GetRaw<internal::MapFieldBase>(message, - F("map_int32_float")); - if (map_field.IsRepeatedFieldValid()) { - // Check with RepeatedField Reflection - sub_message = - &reflection->GetRepeatedMessage(message, F("map_int32_float"), i); - int32_t key = sub_message->GetReflection()->GetInt32( - *sub_message, map_int32_float_key_); - float val = sub_message->GetReflection()->GetFloat( - *sub_message, map_int32_float_val_); - EXPECT_EQ(map[key], val); - } else { - // Check with Map Reflection - map_key.SetInt32Value(i); - EXPECT_EQ(true, reflection->ContainsMapKey( - message, F("map_int32_float"), map_key)); - EXPECT_TRUE(reflection->LookupMapValue(message, F("map_int32_float"), - map_key, &map_value_const_ref)); - EXPECT_EQ(map_value_const_ref.GetFloatValue(), map[i]); - } - } + map[0] = 0.0f; + map[1] = 1.0f; + ExpectMapIteratorHelper( + reflection->GetMap(message, F("map_int32_float")).value(), map); } { absl::flat_hash_map<int32_t, double> map; map[0] = 0.0; map[1] = 1.0; - for (int i = 0; i < 2; i++) { - const internal::MapFieldBase& map_field = - reflection->GetRaw<internal::MapFieldBase>(message, - F("map_int32_double")); - if (map_field.IsRepeatedFieldValid()) { - // Check with RepeatedField Reflection - sub_message = - &reflection->GetRepeatedMessage(message, F("map_int32_double"), i); - int32_t key = sub_message->GetReflection()->GetInt32( - *sub_message, map_int32_double_key_); - double val = sub_message->GetReflection()->GetDouble( - *sub_message, map_int32_double_val_); - EXPECT_EQ(map[key], val); - } else { - // Check with Map Reflection - map_key.SetInt32Value(i); - EXPECT_EQ(true, reflection->ContainsMapKey( - message, F("map_int32_double"), map_key)); - EXPECT_TRUE(reflection->LookupMapValue(message, F("map_int32_double"), - map_key, &map_value_const_ref)); - EXPECT_EQ(map_value_const_ref.GetDoubleValue(), map[i]); - } - } + ExpectMapIteratorHelper( + reflection->GetMap(message, F("map_int32_double")).value(), map); } { - std::array<bool, 2> map; - map[0] = false; - map[1] = true; - std::vector<bool> keys = {false, true}; - std::vector<bool> vals = {false, true}; - for (int i = 0; i < 2; i++) { - const internal::MapFieldBase& map_field = - reflection->GetRaw<internal::MapFieldBase>(message, - F("map_bool_bool")); - if (map_field.IsRepeatedFieldValid()) { - // Check with RepeatedField Reflection - sub_message = - &reflection->GetRepeatedMessage(message, F("map_bool_bool"), i); - bool key = sub_message->GetReflection()->GetBool(*sub_message, - map_bool_bool_key_); - bool val = sub_message->GetReflection()->GetBool(*sub_message, - map_bool_bool_val_); - EXPECT_EQ(map[key ? 1 : 0], val); - } else { - // Check with Map Reflection - map_key.SetBoolValue(keys[i]); - EXPECT_EQ(true, reflection->ContainsMapKey(message, F("map_bool_bool"), - map_key)); - EXPECT_TRUE(reflection->LookupMapValue(message, F("map_bool_bool"), - map_key, &map_value_const_ref)); - EXPECT_EQ(map_value_const_ref.GetBoolValue(), vals[i]); - } - } + absl::flat_hash_map<bool, bool> map; + map[false] = false; + map[true] = true; + ExpectMapIteratorHelper( + reflection->GetMap(message, F("map_bool_bool")).value(), map); } { absl::flat_hash_map<std::string, std::string> map; map[long_string()] = long_string(); map[long_string_2()] = long_string_2(); - std::vector<std::string> keys = {long_string(), long_string_2()}; - std::vector<std::string> vals = {long_string(), long_string_2()}; - for (int i = 0; i < 2; i++) { - const internal::MapFieldBase& map_field = - reflection->GetRaw<internal::MapFieldBase>(message, - F("map_string_string")); - if (map_field.IsRepeatedFieldValid()) { - // Check with RepeatedField Reflection - sub_message = - &reflection->GetRepeatedMessage(message, F("map_string_string"), i); - std::string key = sub_message->GetReflection()->GetString( - *sub_message, map_string_string_key_); - std::string val = sub_message->GetReflection()->GetString( - *sub_message, map_string_string_val_); - EXPECT_EQ(map[key], val); - } else { - // Check with Map Reflection - map_key.SetStringValue(keys[i]); - EXPECT_EQ(true, reflection->ContainsMapKey( - message, F("map_string_string"), map_key)); - EXPECT_TRUE(reflection->LookupMapValue(message, F("map_string_string"), - map_key, &map_value_const_ref)); - EXPECT_EQ(map_value_const_ref.GetStringValue(), vals[i]); - } - } + ExpectMapIteratorHelper( + reflection->GetMap(message, F("map_string_string")).value(), map); } { absl::flat_hash_map<int32_t, std::string> map; map[0] = long_string(); map[1] = long_string_2(); - for (int i = 0; i < 2; i++) { - const internal::MapFieldBase& map_field = - reflection->GetRaw<internal::MapFieldBase>(message, - F("map_int32_bytes")); - if (map_field.IsRepeatedFieldValid()) { - // Check with RepeatedField Reflection - sub_message = - &reflection->GetRepeatedMessage(message, F("map_int32_bytes"), i); - int32_t key = sub_message->GetReflection()->GetInt32( - *sub_message, map_int32_bytes_key_); - std::string val = sub_message->GetReflection()->GetString( - *sub_message, map_int32_bytes_val_); - EXPECT_EQ(map[key], val); - } else { - // Check with Map Reflection - map_key.SetInt32Value(i); - EXPECT_EQ(true, reflection->ContainsMapKey( - message, F("map_int32_bytes"), map_key)); - EXPECT_TRUE(reflection->LookupMapValue(message, F("map_int32_bytes"), - map_key, &map_value_const_ref)); - EXPECT_EQ(map_value_const_ref.GetStringValue(), map[i]); - } - } + ExpectMapIteratorHelper( + reflection->GetMap(message, F("map_int32_bytes")).value(), map); } { - absl::flat_hash_map<int32_t, const EnumValueDescriptor*> map; - map[0] = map_enum_bar_; - map[1] = map_enum_baz_; - for (int i = 0; i < 2; i++) { - const internal::MapFieldBase& map_field = - reflection->GetRaw<internal::MapFieldBase>(message, - F("map_int32_enum")); - if (map_field.IsRepeatedFieldValid()) { - // Check with RepeatedField Reflection - sub_message = - &reflection->GetRepeatedMessage(message, F("map_int32_enum"), i); - int32_t key = sub_message->GetReflection()->GetInt32( - *sub_message, map_int32_enum_key_); - PROTOBUF_IGNORE_DEPRECATION_START - const EnumValueDescriptor* val = sub_message->GetReflection()->GetEnum( - *sub_message, map_int32_enum_val_); - PROTOBUF_IGNORE_DEPRECATION_STOP - EXPECT_EQ(map[key], val); - } else { - // Check with Map Reflection - map_key.SetInt32Value(i); - EXPECT_EQ(true, reflection->ContainsMapKey(message, F("map_int32_enum"), - map_key)); - EXPECT_TRUE(reflection->LookupMapValue(message, F("map_int32_enum"), - map_key, &map_value_const_ref)); - EXPECT_EQ(map_value_const_ref.GetEnumValue(), map[i]->number()); - } - } + absl::flat_hash_map<int32_t, EnumVal> map; + map[0] = EnumVal{map_enum_bar_->number()}; + map[1] = EnumVal{map_enum_baz_->number()}; + ExpectMapIteratorHelper( + reflection->GetMap(message, F("map_int32_enum")).value(), map); } { absl::flat_hash_map<int32_t, int32_t> map; map[0] = 0; map[1] = 1; - for (int i = 0; i < 2; i++) { - const internal::MapFieldBase& map_field = - reflection->GetRaw<internal::MapFieldBase>( - message, F("map_int32_foreign_message")); - if (map_field.IsRepeatedFieldValid()) { - // Check with RepeatedField Reflection - sub_message = &reflection->GetRepeatedMessage( - message, F("map_int32_foreign_message"), i); - int32_t key = sub_message->GetReflection()->GetInt32( - *sub_message, map_int32_foreign_message_key_); - const Message& foreign_message = - sub_message->GetReflection()->GetMessage( - *sub_message, map_int32_foreign_message_val_); - int32_t val = foreign_message.GetReflection()->GetInt32(foreign_message, - foreign_c_); - EXPECT_EQ(map[key], val); - } else { - // Check with Map Reflection - map_key.SetInt32Value(i); - EXPECT_EQ(true, reflection->ContainsMapKey( - message, F("map_int32_foreign_message"), map_key)); - EXPECT_TRUE(reflection->LookupMapValue(message, - F("map_int32_foreign_message"), - map_key, &map_value_const_ref)); - const Message& foreign_message = map_value_const_ref.GetMessageValue(); - EXPECT_EQ(foreign_message.GetReflection()->GetInt32(foreign_message, - foreign_c_), - map[i]); - } - } - } -} - -void MapReflectionTester::ExpectMapFieldsSetViaReflectionIterator( - Message* message) { - std::string scratch; - std::string serialized; - const Reflection* reflection = message->GetReflection(); - - ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_int32"))); - ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int64_int64"))); - ASSERT_EQ(2, reflection->FieldSize(*message, F("map_uint32_uint32"))); - ASSERT_EQ(2, reflection->FieldSize(*message, F("map_uint64_uint64"))); - ASSERT_EQ(2, reflection->FieldSize(*message, F("map_sint32_sint32"))); - ASSERT_EQ(2, reflection->FieldSize(*message, F("map_sint64_sint64"))); - ASSERT_EQ(2, reflection->FieldSize(*message, F("map_fixed32_fixed32"))); - ASSERT_EQ(2, reflection->FieldSize(*message, F("map_fixed64_fixed64"))); - ASSERT_EQ(2, reflection->FieldSize(*message, F("map_sfixed32_sfixed32"))); - ASSERT_EQ(2, reflection->FieldSize(*message, F("map_sfixed64_sfixed64"))); - ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_float"))); - ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_double"))); - ASSERT_EQ(2, reflection->FieldSize(*message, F("map_bool_bool"))); - ASSERT_EQ(2, reflection->FieldSize(*message, F("map_string_string"))); - ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_bytes"))); - ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_enum"))); - ASSERT_EQ(2, reflection->FieldSize(*message, F("map_int32_foreign_message"))); - - { - absl::flat_hash_map<int32_t, int32_t> map; - map[0] = 0; - map[1] = 1; + GenericConstMapRef map_ref = + reflection->GetMap(message, F("map_int32_foreign_message")).value(); + EXPECT_EQ(map_ref.size(), 2); int size = 0; - for (ConstMapIterator iter = - reflection->ConstMapBegin(message, F("map_int32_int32")); - iter != reflection->ConstMapEnd(message, F("map_int32_int32")); - ++iter, ++size) { - // Check const methods do not invalidate map. - (void)message->DebugString(); - (void)message->ShortDebugString(); - EXPECT_TRUE(message->SerializeToString(&serialized)); - (void)message->SpaceUsedLong(); - (void)message->ByteSizeLong(); - EXPECT_EQ(map[iter.GetKey().GetInt32Value()], - iter.GetValueRef().GetInt32Value()); - } - EXPECT_EQ(size, 2); - } - { - absl::flat_hash_map<int64_t, int64_t> map; - map[0] = 0; - map[1] = 1; - for (ConstMapIterator iter = - reflection->ConstMapBegin(message, F("map_int64_int64")); - iter != reflection->ConstMapEnd(message, F("map_int64_int64")); - ++iter) { - EXPECT_EQ(map[iter.GetKey().GetInt64Value()], - iter.GetValueRef().GetInt64Value()); - } - } - { - absl::flat_hash_map<uint32_t, uint32_t> map; - map[0] = 0; - map[1] = 1; - for (ConstMapIterator iter = - reflection->ConstMapBegin(message, F("map_uint32_uint32")); - iter != reflection->ConstMapEnd(message, F("map_uint32_uint32")); - ++iter) { - EXPECT_EQ(map[iter.GetKey().GetUInt32Value()], - iter.GetValueRef().GetUInt32Value()); - } - } - { - absl::flat_hash_map<uint64_t, uint64_t> map; - map[0] = 0; - map[1] = 1; - for (ConstMapIterator iter = - reflection->ConstMapBegin(message, F("map_uint64_uint64")); - iter != reflection->ConstMapEnd(message, F("map_uint64_uint64")); - ++iter) { - EXPECT_EQ(map[iter.GetKey().GetUInt64Value()], - iter.GetValueRef().GetUInt64Value()); - } - } - { - absl::flat_hash_map<int32_t, int32_t> map; - map[0] = 0; - map[1] = 1; - for (ConstMapIterator iter = - reflection->ConstMapBegin(message, F("map_sint32_sint32")); - iter != reflection->ConstMapEnd(message, F("map_sint32_sint32")); - ++iter) { - EXPECT_EQ(map[iter.GetKey().GetInt32Value()], - iter.GetValueRef().GetInt32Value()); - } - } - { - absl::flat_hash_map<int64_t, int64_t> map; - map[0] = 0; - map[1] = 1; - for (ConstMapIterator iter = - reflection->ConstMapBegin(message, F("map_sint64_sint64")); - iter != reflection->ConstMapEnd(message, F("map_sint64_sint64")); - ++iter) { - EXPECT_EQ(map[iter.GetKey().GetInt64Value()], - iter.GetValueRef().GetInt64Value()); - } - } - { - absl::flat_hash_map<uint32_t, uint32_t> map; - map[0] = 0; - map[1] = 1; - for (ConstMapIterator iter = - reflection->ConstMapBegin(message, F("map_fixed32_fixed32")); - iter != reflection->ConstMapEnd(message, F("map_fixed32_fixed32")); - ++iter) { - EXPECT_EQ(map[iter.GetKey().GetUInt32Value()], - iter.GetValueRef().GetUInt32Value()); - } - } - { - absl::flat_hash_map<uint64_t, uint64_t> map; - map[0] = 0; - map[1] = 1; - for (ConstMapIterator iter = - reflection->ConstMapBegin(message, F("map_fixed64_fixed64")); - iter != reflection->ConstMapEnd(message, F("map_fixed64_fixed64")); - ++iter) { - EXPECT_EQ(map[iter.GetKey().GetUInt64Value()], - iter.GetValueRef().GetUInt64Value()); - } - } - { - absl::flat_hash_map<int32_t, int32_t> map; - map[0] = 0; - map[1] = 1; - for (ConstMapIterator iter = - reflection->ConstMapBegin(message, F("map_sfixed32_sfixed32")); - iter != reflection->ConstMapEnd(message, F("map_sfixed32_sfixed32")); - ++iter) { - EXPECT_EQ(map[iter.GetKey().GetInt32Value()], - iter.GetValueRef().GetInt32Value()); - } - } - { - absl::flat_hash_map<int32_t, float> map; - map[0] = 0.0; - map[1] = 1.0; - for (ConstMapIterator iter = - reflection->ConstMapBegin(message, F("map_int32_float")); - iter != reflection->ConstMapEnd(message, F("map_int32_float")); - ++iter) { - EXPECT_EQ(map[iter.GetKey().GetInt32Value()], - iter.GetValueRef().GetFloatValue()); - } - } - { - absl::flat_hash_map<int32_t, double> map; - map[0] = 0.0; - map[1] = 1.0; - for (ConstMapIterator iter = - reflection->ConstMapBegin(message, F("map_int32_double")); - iter != reflection->ConstMapEnd(message, F("map_int32_double")); - ++iter) { - EXPECT_EQ(map[iter.GetKey().GetInt32Value()], - iter.GetValueRef().GetDoubleValue()); - } - } - { - std::array<bool, 2> map; - map[0] = false; - map[1] = true; - for (ConstMapIterator iter = - reflection->ConstMapBegin(message, F("map_bool_bool")); - iter != reflection->ConstMapEnd(message, F("map_bool_bool")); ++iter) { - EXPECT_EQ(map[iter.GetKey().GetBoolValue() ? 1 : 0], - iter.GetValueRef().GetBoolValue()); - } - } - { - absl::flat_hash_map<std::string, std::string> map; - map[long_string()] = long_string(); - map[long_string_2()] = long_string_2(); - int size = 0; - for (ConstMapIterator iter = - reflection->ConstMapBegin(message, F("map_string_string")); - iter != reflection->ConstMapEnd(message, F("map_string_string")); - ++iter, ++size) { - // Check const methods do not invalidate map. - (void)message->DebugString(); - (void)message->ShortDebugString(); - EXPECT_TRUE(message->SerializeToString(&serialized)); - (void)message->SpaceUsedLong(); - (void)message->ByteSizeLong(); - EXPECT_EQ(map[iter.GetKey().GetStringValue()], - iter.GetValueRef().GetStringValue()); - } - EXPECT_EQ(size, 2); - } - { - absl::flat_hash_map<int32_t, std::string> map; - map[0] = long_string(); - map[1] = long_string_2(); - for (ConstMapIterator iter = - reflection->ConstMapBegin(message, F("map_int32_bytes")); - iter != reflection->ConstMapEnd(message, F("map_int32_bytes")); - ++iter) { - EXPECT_EQ(map[iter.GetKey().GetInt32Value()], - iter.GetValueRef().GetStringValue()); - } - } - { - absl::flat_hash_map<int32_t, const EnumValueDescriptor*> map; - map[0] = map_enum_bar_; - map[1] = map_enum_baz_; - for (ConstMapIterator iter = - reflection->ConstMapBegin(message, F("map_int32_enum")); - iter != reflection->ConstMapEnd(message, F("map_int32_enum")); - ++iter) { - EXPECT_EQ(map[iter.GetKey().GetInt32Value()]->number(), - iter.GetValueRef().GetEnumValue()); - } - } - { - absl::flat_hash_map<int32_t, int32_t> map; - map[0] = 0; - map[1] = 1; - int size = 0; - for (ConstMapIterator iter = - reflection->ConstMapBegin(message, F("map_int32_foreign_message")); - iter != - reflection->ConstMapEnd(message, F("map_int32_foreign_message")); - ++iter, ++size) { - // Check const methods do not invalidate map. - (void)message->DebugString(); - (void)message->ShortDebugString(); - EXPECT_TRUE(message->SerializeToString(&serialized)); - (void)message->SpaceUsedLong(); - (void)message->ByteSizeLong(); - const Message& sub_message = iter.GetValueRef().GetMessageValue(); - EXPECT_EQ(map[iter.GetKey().GetInt32Value()], - sub_message.GetReflection()->GetInt32(sub_message, foreign_c_)); + for (auto iter = map_ref.begin(); iter != map_ref.end(); ++iter, ++size) { + const Message& sub = iter->value().GetMessageValue(); + EXPECT_EQ(map[iter->key().GetInt32Value()], + sub.GetReflection()->GetInt32(sub, foreign_c_)); } EXPECT_EQ(size, 2); } @@ -1641,65 +1654,39 @@ void MapReflectionTester::ExpectClearViaReflection(const Message& message) { const Reflection* reflection = message.GetReflection(); - // Map fields are empty. - EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_int32"))); - EXPECT_EQ(0, reflection->FieldSize(message, F("map_int64_int64"))); - EXPECT_EQ(0, reflection->FieldSize(message, F("map_uint32_uint32"))); - EXPECT_EQ(0, reflection->FieldSize(message, F("map_uint64_uint64"))); - EXPECT_EQ(0, reflection->FieldSize(message, F("map_sint32_sint32"))); - EXPECT_EQ(0, reflection->FieldSize(message, F("map_sint64_sint64"))); - EXPECT_EQ(0, reflection->FieldSize(message, F("map_fixed32_fixed32"))); - EXPECT_EQ(0, reflection->FieldSize(message, F("map_fixed64_fixed64"))); - EXPECT_EQ(0, reflection->FieldSize(message, F("map_sfixed32_sfixed32"))); - EXPECT_EQ(0, reflection->FieldSize(message, F("map_sfixed64_sfixed64"))); - EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_float"))); - EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_double"))); - EXPECT_EQ(0, reflection->FieldSize(message, F("map_bool_bool"))); - EXPECT_EQ(0, reflection->FieldSize(message, F("map_string_string"))); - EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_bytes"))); - EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_enum"))); - EXPECT_EQ(0, reflection->FieldSize(message, F("map_int32_foreign_message"))); + for (absl::string_view name : kMapFields) { + const FieldDescriptor* field = F(name); + auto map = reflection->GetMap(message, field).value(); + EXPECT_EQ(0, reflection->FieldSize(message, field)); + EXPECT_TRUE(map.empty()); + EXPECT_EQ(0, map.size()); + EXPECT_EQ(map.begin(), map.end()); + } EXPECT_TRUE(reflection->GetMapData(message, F("map_int32_foreign_message")) ->IsMapValid()); } +void MapReflectionTester::ExpectClearViaReflectionIterator( + const Message& message) { + const Reflection* reflection = message.GetReflection(); + for (absl::string_view name : kMapFields) { + const FieldDescriptor* field = F(name); + GenericConstMapRef map = reflection->GetMap(message, field).value(); + EXPECT_TRUE(map.empty()); + EXPECT_EQ(map.size(), 0); + EXPECT_EQ(map.begin(), map.end()); + + int count = 0; + for (auto entry : map) { + (void)entry; + ++count; + } + EXPECT_EQ(count, 0); + } +} + void MapReflectionTester::ExpectClearViaReflectionIterator(Message* message) { - const Reflection* reflection = message->GetReflection(); - EXPECT_TRUE(reflection->ConstMapBegin(message, F("map_int32_int32")) == - reflection->ConstMapEnd(message, F("map_int32_int32"))); - EXPECT_TRUE(reflection->ConstMapBegin(message, F("map_int64_int64")) == - reflection->ConstMapEnd(message, F("map_int64_int64"))); - EXPECT_TRUE(reflection->ConstMapBegin(message, F("map_uint32_uint32")) == - reflection->ConstMapEnd(message, F("map_uint32_uint32"))); - EXPECT_TRUE(reflection->ConstMapBegin(message, F("map_uint64_uint64")) == - reflection->ConstMapEnd(message, F("map_uint64_uint64"))); - EXPECT_TRUE(reflection->ConstMapBegin(message, F("map_sint32_sint32")) == - reflection->ConstMapEnd(message, F("map_sint32_sint32"))); - EXPECT_TRUE(reflection->ConstMapBegin(message, F("map_sint64_sint64")) == - reflection->ConstMapEnd(message, F("map_sint64_sint64"))); - EXPECT_TRUE(reflection->ConstMapBegin(message, F("map_fixed32_fixed32")) == - reflection->ConstMapEnd(message, F("map_fixed32_fixed32"))); - EXPECT_TRUE(reflection->ConstMapBegin(message, F("map_fixed64_fixed64")) == - reflection->ConstMapEnd(message, F("map_fixed64_fixed64"))); - EXPECT_TRUE(reflection->ConstMapBegin(message, F("map_sfixed32_sfixed32")) == - reflection->ConstMapEnd(message, F("map_sfixed32_sfixed32"))); - EXPECT_TRUE(reflection->ConstMapBegin(message, F("map_sfixed64_sfixed64")) == - reflection->ConstMapEnd(message, F("map_sfixed64_sfixed64"))); - EXPECT_TRUE(reflection->ConstMapBegin(message, F("map_int32_float")) == - reflection->ConstMapEnd(message, F("map_int32_float"))); - EXPECT_TRUE(reflection->ConstMapBegin(message, F("map_int32_double")) == - reflection->ConstMapEnd(message, F("map_int32_double"))); - EXPECT_TRUE(reflection->ConstMapBegin(message, F("map_bool_bool")) == - reflection->ConstMapEnd(message, F("map_bool_bool"))); - EXPECT_TRUE(reflection->ConstMapBegin(message, F("map_string_string")) == - reflection->ConstMapEnd(message, F("map_string_string"))); - EXPECT_TRUE(reflection->ConstMapBegin(message, F("map_int32_bytes")) == - reflection->ConstMapEnd(message, F("map_int32_bytes"))); - EXPECT_TRUE(reflection->ConstMapBegin(message, F("map_int32_enum")) == - reflection->ConstMapEnd(message, F("map_int32_enum"))); - EXPECT_TRUE( - reflection->ConstMapBegin(message, F("map_int32_foreign_message")) == - reflection->ConstMapEnd(message, F("map_int32_foreign_message"))); + ExpectClearViaReflectionIterator(*message); } } // namespace protobuf
diff --git a/src/google/protobuf/reflection_tester.h b/src/google/protobuf/reflection_tester.h index bcd2445..0312ab7 100644 --- a/src/google/protobuf/reflection_tester.h +++ b/src/google/protobuf/reflection_tester.h
@@ -30,40 +30,75 @@ void SetMapFieldsViaReflection(Message* message); void SetMapFieldsViaMapReflection(Message* message); void ClearMapFieldsViaReflection(Message* message); + void ClearMapFieldsViaMapReflection(Message* message); void ModifyMapFieldsViaReflection(Message* message); void RemoveLastMapsViaReflection(Message* message); void ReleaseLastMapsViaReflection(Message* message); void SwapMapsViaReflection(Message* message); + void SwapMapsViaMapReflection(Message* message1, Message* message2); + void AssignMapsViaMapReflection(Message* dst, Message* src); + void EraseMapValuesViaMapReflectionIterator(Message* message); void MutableUnknownFieldsOfMapFieldsViaReflection(Message* message); void ExpectMapFieldsSetViaReflection(const Message& message); void ExpectMapFieldsSetViaReflectionIterator(Message* message); + void ExpectMapFieldsSetViaReflectionIterator(const Message& message); void ExpectClearViaReflection(const Message& message); void ExpectClearViaReflectionIterator(Message* message); - void GetMapValueViaMapReflection(Message* message, - absl::string_view field_name, - const MapKey& map_key, MapValueRef* map_val); + void ExpectClearViaReflectionIterator(const Message& message); void DeleteMapValueViaMapReflection(Message* message, absl::string_view field_name, - const MapKey& map_key); + MapKey map_key); Message* GetMapEntryViaReflection(Message* message, absl::string_view field_name, int index); - MapIterator MapBegin(Message* message, absl::string_view field_name); - MapIterator MapEnd(Message* message, absl::string_view field_name); - ConstMapIterator ConstMapBegin(const Message* message, - absl::string_view field_name); - ConstMapIterator ConstMapEnd(const Message* message, - absl::string_view field_name); + + bool InsertOrLookupMapValue(Message* message, absl::string_view field_name, + const MapKey& map_key, MapValueRef* map_val) { + auto res = message->GetReflection() + ->MutableMap(message, F(field_name)) + .value() + .try_emplace(map_key); + if (!res.ok()) return false; + *map_val = res->iter->value(); + return res->inserted; + } + + bool LookupMapValue(Message* message, absl::string_view field_name, + const MapKey& map_key, + MapValueConstRef* map_value_const_ref) { + return LookupMapValue(*message, field_name, map_key, map_value_const_ref); + } + + bool LookupMapValue(const Message& message, absl::string_view field_name, + const MapKey& map_key, + MapValueConstRef* map_value_const_ref) { + auto map = message.GetReflection()->GetMap(message, F(field_name)); + if (!map.ok()) return false; + auto it = map->find(map_key); + if (it == map->end()) return false; + *map_value_const_ref = it->value(); + return true; + } + + bool IsRepeatedFieldValid(const Message& message, + absl::string_view field_name) { + const internal::MapFieldBase& map_field = + message.GetReflection()->GetRaw<internal::MapFieldBase>(message, + F(field_name)); + return map_field.IsRepeatedFieldValid(); + } + int MapSize(const Message& message, absl::string_view field_name); static absl::optional<MapValueConstRef> LookupMapValue( const Reflection& reflection, const Message& message, const FieldDescriptor& descriptor, const MapKey& map_key) { - MapValueConstRef map_val_const; - if (reflection.LookupMapValue(message, &descriptor, map_key, - &map_val_const)) { - return map_val_const; + auto map = reflection.GetMap(message, &descriptor); + if (!map.ok()) return absl::nullopt; + auto it = map->find(map_key); + if (it == map->end()) { + return absl::nullopt; } - return absl::nullopt; + return it->value(); } static std::string long_string() {
diff --git a/src/google/protobuf/reflection_visit_field_info.h b/src/google/protobuf/reflection_visit_field_info.h index c0da446..cf74a6e 100644 --- a/src/google/protobuf/reflection_visit_field_info.h +++ b/src/google/protobuf/reflection_visit_field_info.h
@@ -9,6 +9,7 @@ #include <utility> #include "absl/log/absl_check.h" +#include "absl/status/statusor.h" #include "absl/strings/cord.h" #include "absl/strings/string_view.h" #include "google/protobuf/arenastring.h" @@ -1252,7 +1253,7 @@ // Dispatches based on key type to instantiate a right KeyInfo, then calls // MapDynamicFieldVisitValue to dispatch on the value type. template <typename MapValueRefT, typename MapFieldCallback> -void MapDynamicFieldVisitKey(const MapKey& key, MapValueRefT& value, +void MapDynamicFieldVisitKey(const MapKey& key, MapValueRefT value, const MapFieldCallback& user_cb) { switch (key.type()) { #define PROTOBUF_HANDLE_MAP_KEY_CASE(NAME, CPPTYPE) \ @@ -1284,14 +1285,8 @@ constexpr MapDynamicFieldInfo(const Reflection* r, MessageT& m, const FieldDescriptor* f, const FieldDescriptor* key_f, - const FieldDescriptor* val_f, - const MapFieldBase& map_field) - : reflection(r), - message(m), - field(f), - key(key_f), - value(val_f), - const_map_field(map_field) { + const FieldDescriptor* val_f) + : reflection(r), message(m), field(f), key(key_f), value(val_f) { ABSL_DCHECK(f->is_map()); ABSL_DCHECK_NE(key_f, nullptr); ABSL_DCHECK_NE(val_f, nullptr); @@ -1300,7 +1295,9 @@ int number() const { return field->number(); } FieldDescriptor::Type key_type() const { return key->type(); } FieldDescriptor::Type value_type() const { return value->type(); } - int size() const { return const_map_field.size(); } + int size() const { + return static_cast<int>(reflection->GetMap(message, field).value().size()); + } // go/ranked-overloads for the rationale. struct Rank0 {}; @@ -1310,40 +1307,30 @@ template <typename T, typename Callback, typename = std::enable_if_t<!std::is_const_v<T>>> static void VisitElementsImpl(T& msg, const Reflection* reflection, - const FieldDescriptor* field, - const MapFieldBase&, Callback&& cb, Rank1) { - auto& map_field = - DynamicFieldInfoHelper<false>::template Mutable<MapFieldBase>( - reflection, msg, field); - const Descriptor* descriptor = field->message_type(); - MapIterator begin(&map_field, descriptor), end(&map_field, descriptor); - map_field.MapBegin(&begin); - map_field.MapEnd(&end); - - for (auto it = begin; it != end; ++it) { - MapDynamicFieldVisitKey(it.GetKey(), *it.MutableValueRef(), cb); + const FieldDescriptor* field, Callback&& cb, + Rank1) { + auto map = reflection->MutableMap(&msg, field); + ABSL_DCHECK(map.ok()); + for (auto entry : *map) { + MapDynamicFieldVisitKey(entry.key(), entry.value(), cb); } } // Fallback version otherwise. template <typename T, typename Callback> - static void VisitElementsImpl(T& msg, const Reflection*, - const FieldDescriptor* field, - const MapFieldBase& map_field, Callback&& cb, + static void VisitElementsImpl(T& msg, const Reflection* ref, + const FieldDescriptor* field, Callback&& cb, Rank0) { - const Descriptor* descriptor = field->message_type(); - ConstMapIterator begin(&map_field, descriptor), end(&map_field, descriptor); - map_field.ConstMapBegin(&begin); - map_field.ConstMapEnd(&end); - - for (auto it = begin; it != end; ++it) { - MapDynamicFieldVisitKey(it.GetKey(), it.GetValueRef(), cb); + auto map = ref->GetMap(msg, field); + ABSL_DCHECK(map.ok()); + for (auto entry : *map) { + MapDynamicFieldVisitKey(entry.key(), entry.value(), cb); } } template <typename MapFieldCallback> void VisitElements(MapFieldCallback&& cb) const { - VisitElementsImpl(message, reflection, field, const_map_field, + VisitElementsImpl(message, reflection, field, static_cast<MapFieldCallback&&>(cb), Rank1{}); } @@ -1367,7 +1354,6 @@ const FieldDescriptor* field; const FieldDescriptor* key; const FieldDescriptor* value; - const MapFieldBase& const_map_field; }; } // namespace internal
diff --git a/src/google/protobuf/reflection_visit_fields.h b/src/google/protobuf/reflection_visit_fields.h index 6eb2f52..8084e1f 100644 --- a/src/google/protobuf/reflection_visit_fields.h +++ b/src/google/protobuf/reflection_visit_fields.h
@@ -8,6 +8,7 @@ #include "absl/base/attributes.h" #include "absl/base/optimization.h" #include "absl/log/absl_check.h" +#include "absl/status/statusor.h" #include "absl/strings/cord.h" #include "google/protobuf/descriptor.h" #include "google/protobuf/descriptor.pb.h" @@ -135,25 +136,23 @@ PROTOBUF_HANDLE_REPEATED_CASE(SINT32, int32_t, SInt32); PROTOBUF_HANDLE_REPEATED_CASE(SINT64, int64_t, SInt64); -#define PROTOBUF_HANDLE_REPEATED_PTR_CASE(TYPE, CPPTYPE, NAME) \ - case FieldDescriptor::TYPE_##TYPE: { \ - if (ABSL_PREDICT_TRUE(!field->is_map())) { \ - /* Handle repeated fields. */ \ - const auto& rep = \ - reflection->GetRaw<RepeatedPtrField<CPPTYPE>>(message, field); \ - if (rep.size() == 0) continue; \ - func(internal::Repeated##NAME##DynamicFieldInfo<MessageT>{ \ - reflection, message, field, rep}); \ - } else { \ - /* Handle map fields. */ \ - const auto& map = reflection->GetRaw<MapFieldBase>(message, field); \ - if (map.size() == 0) continue; /* NOLINT */ \ - const Descriptor* desc = field->message_type(); \ - func(internal::MapDynamicFieldInfo<MessageT>{reflection, message, field, \ - desc->map_key(), \ - desc->map_value(), map}); \ - } \ - break; \ +#define PROTOBUF_HANDLE_REPEATED_PTR_CASE(TYPE, CPPTYPE, NAME) \ + case FieldDescriptor::TYPE_##TYPE: { \ + if (ABSL_PREDICT_TRUE(!field->is_map())) { \ + /* Handle repeated fields. */ \ + const auto& rep = \ + reflection->GetRaw<RepeatedPtrField<CPPTYPE>>(message, field); \ + if (rep.size() == 0) continue; \ + func(internal::Repeated##NAME##DynamicFieldInfo<MessageT>{ \ + reflection, message, field, rep}); \ + } else { \ + /* Handle map fields. */ \ + if (reflection->GetMap(message, field)->empty()) continue; \ + const Descriptor* desc = field->message_type(); \ + func(internal::MapDynamicFieldInfo<MessageT>{ \ + reflection, message, field, desc->map_key(), desc->map_value()}); \ + } \ + break; \ } PROTOBUF_HANDLE_REPEATED_PTR_CASE(MESSAGE, Message, Message);
diff --git a/src/google/protobuf/text_format.cc b/src/google/protobuf/text_format.cc index 5d267dd..f1d170d 100644 --- a/src/google/protobuf/text_format.cc +++ b/src/google/protobuf/text_format.cc
@@ -2747,14 +2747,14 @@ 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 (ConstMapIterator iter = reflection->ConstMapBegin(&message, field); - iter != reflection->ConstMapEnd(&message, field); ++iter) { + auto map = *reflection->GetMap(message, field); + all_entries.reserve(map.size()); + owned_entries.reserve(map.size()); + for (auto entry : map) { std::unique_ptr<Message> 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(), + CopyKey(entry.key(), map_entry_message.get(), map_entry_desc->field(0)); + CopyValue(entry.value(), map_entry_message.get(), map_entry_desc->field(1)); all_entries.push_back(map_entry_message.get()); owned_entries.push_back(std::move(map_entry_message));
diff --git a/src/google/protobuf/util/message_differencer.cc b/src/google/protobuf/util/message_differencer.cc index ae685a4..8f8333e 100644 --- a/src/google/protobuf/util/message_differencer.cc +++ b/src/google/protobuf/util/message_differencer.cc
@@ -1081,21 +1081,19 @@ ABSL_DCHECK_EQ(repeated_field_comparison_, AS_LIST); const Reflection* reflection1 = message1.GetReflection(); const Reflection* reflection2 = message2.GetReflection(); - const int count1 = reflection1->MapSize(message1, map_field); - const int count2 = reflection2->MapSize(message2, map_field); + GenericConstMapRef map1 = *reflection1->GetMap(message1, map_field); + GenericConstMapRef map2 = *reflection2->GetMap(message2, map_field); const bool treated_as_subset = IsTreatedAsSubset(map_field); - if (count1 != count2 && !treated_as_subset) { + if (map1.size() != map2.size() && !treated_as_subset) { return false; } - if (count1 > count2) { + if (map1.size() > map2.size()) { return false; } // First pass: check whether the same keys are present. - for (ConstMapIterator it = reflection1->ConstMapBegin(&message1, map_field), - it_end = reflection1->ConstMapEnd(&message1, map_field); - it != it_end; ++it) { - if (!reflection2->ContainsMapKey(message2, map_field, it.GetKey())) { + for (auto entry1 : map1) { + if (!map2.contains(entry1.key())) { return false; } } @@ -1103,21 +1101,16 @@ // Second pass: compare values for matching keys. const FieldDescriptor* val_des = map_field->message_type()->map_value(); switch (val_des->cpp_type()) { -#define HANDLE_TYPE(CPPTYPE, METHOD, COMPAREMETHOD) \ - case FieldDescriptor::CPPTYPE_##CPPTYPE: { \ - for (ConstMapIterator \ - it = reflection1->ConstMapBegin(&message1, map_field), \ - it_end = reflection1->ConstMapEnd(&message1, map_field); \ - it != it_end; ++it) { \ - MapValueConstRef value2; \ - reflection2->LookupMapValue(message2, map_field, it.GetKey(), &value2); \ - if (!comparator->Compare##COMPAREMETHOD(*val_des, \ - it.GetValueRef().Get##METHOD(), \ - value2.Get##METHOD())) { \ - return false; \ - } \ - } \ - break; \ +#define HANDLE_TYPE(CPPTYPE, METHOD, COMPAREMETHOD) \ + case FieldDescriptor::CPPTYPE_##CPPTYPE: { \ + for (auto entry1 : map1) { \ + MapValueConstRef value2 = map2.find(entry1.key())->value(); \ + if (!comparator->Compare##COMPAREMETHOD( \ + *val_des, entry1.value().Get##METHOD(), value2.Get##METHOD())) { \ + return false; \ + } \ + } \ + break; \ } HANDLE_TYPE(INT32, Int32Value, Int32); HANDLE_TYPE(INT64, Int64Value, Int64); @@ -1130,15 +1123,12 @@ HANDLE_TYPE(ENUM, EnumValue, Int32); #undef HANDLE_TYPE case FieldDescriptor::CPPTYPE_MESSAGE: { - for (ConstMapIterator it = - reflection1->ConstMapBegin(&message1, map_field); - it != reflection1->ConstMapEnd(&message1, map_field); ++it) { - if (!reflection2->ContainsMapKey(message2, map_field, it.GetKey())) { + for (auto entry1 : map1) { + auto it2 = map2.find(entry1.key()); + if (it2 == map2.end()) { return false; } bool compare_result; - MapValueConstRef value2; - reflection2->LookupMapValue(message2, map_field, it.GetKey(), &value2); // Append currently compared field to the end of parent_fields. SpecificField specific_value_field; specific_value_field.message1 = &message1; @@ -1147,8 +1137,8 @@ specific_value_field.field = val_des; parent_fields->push_back(specific_value_field); compare_result = - Compare(it.GetValueRef().GetMessageValue(), - value2.GetMessageValue(), false, parent_fields); + Compare(entry1.value().GetMessageValue(), + it2->value().GetMessageValue(), false, parent_fields); parent_fields->pop_back(); if (!compare_result) { return false;
diff --git a/src/google/protobuf/wire_format.cc b/src/google/protobuf/wire_format.cc index 7cb447c..d78ee57 100644 --- a/src/google/protobuf/wire_format.cc +++ b/src/google/protobuf/wire_format.cc
@@ -22,6 +22,7 @@ #include "absl/base/optimization.h" #include "absl/log/absl_check.h" #include "absl/log/absl_log.h" +#include "absl/status/statusor.h" #include "absl/strings/cord.h" #include "absl/strings/string_view.h" #include "google/protobuf/class_data.h" @@ -1141,9 +1142,9 @@ const Reflection* reflection, const FieldDescriptor* field) { std::vector<MapKey> sorted_key_list; - for (ConstMapIterator it = reflection->ConstMapBegin(&message, field); - it != reflection->ConstMapEnd(&message, field); ++it) { - sorted_key_list.push_back(it.GetKey()); + auto map = *reflection->GetMap(message, field); + for (auto entry : map) { + sorted_key_list.push_back(entry.key()); } MapKeyComparator comparator; std::sort(sorted_key_list.begin(), sorted_key_list.end(), comparator); @@ -1229,22 +1230,20 @@ const MapFieldBase* map_field = message_reflection->GetMapData(message, field); if (map_field->IsMapValid()) { + GenericConstMapRef map = *message_reflection->GetMap(message, field); if (stream->IsSerializationDeterministic()) { std::vector<MapKey> sorted_key_list = MapKeySorter::SortKey(message, message_reflection, field); for (std::vector<MapKey>::iterator it = sorted_key_list.begin(); it != sorted_key_list.end(); ++it) { - MapValueConstRef map_value; - message_reflection->LookupMapValue(message, field, *it, &map_value); + MapValueConstRef map_value = map.find(*it)->value(); target = InternalSerializeMapEntry(field, *it, map_value, target, stream); } } else { - for (ConstMapIterator it = - message_reflection->ConstMapBegin(&message, field); - it != message_reflection->ConstMapEnd(&message, field); ++it) { - target = InternalSerializeMapEntry(field, it.GetKey(), - it.GetValueRef(), target, stream); + for (auto entry : map) { + target = InternalSerializeMapEntry(field, entry.key(), entry.value(), + target, stream); } } @@ -1500,7 +1499,7 @@ const MapFieldBase* map_field = message_reflection->GetMapData(message, field); if (map_field->IsMapValid()) { - count = FromIntSize(map_field->size()); + count = map_field->GetMap().size(); } else { count = FromIntSize(message_reflection->FieldSize(message, field)); } @@ -1621,15 +1620,13 @@ const MapFieldBase* map_field = message_reflection->GetMapData(message, field); if (map_field->IsMapValid()) { - ConstMapIterator iter(&message, field); - ConstMapIterator end(&message, field); const FieldDescriptor* key_field = field->message_type()->field(0); const FieldDescriptor* value_field = field->message_type()->field(1); - for (map_field->ConstMapBegin(&iter), map_field->ConstMapEnd(&end); - iter != end; ++iter) { + auto map = *message_reflection->GetMap(message, field); + for (auto entry : map) { size_t size = kMapEntryTagByteSize; - size += MapKeyDataOnlyByteSize(key_field, iter.GetKey()); - size += MapValueRefDataOnlyByteSize(value_field, iter.GetValueRef()); + size += MapKeyDataOnlyByteSize(key_field, entry.key()); + size += MapValueRefDataOnlyByteSize(value_field, entry.value()); data_size += WireFormatLite::LengthDelimitedSize(size); } return data_size;