Move more methods into MapFieldBase using the type-erased iteration functions.

This further reduces code duplication and binary size.

PiperOrigin-RevId: 536496189
pull/12928/head
Protobuf Team Bot 2 years ago committed by Copybara-Service
parent 472e8b40f6
commit 4b3615c332
  1. 4
      objectivec/GPBAny.pbobjc.m
  2. 12
      objectivec/GPBApi.pbobjc.m
  3. 4
      objectivec/GPBDuration.pbobjc.m
  4. 4
      objectivec/GPBEmpty.pbobjc.m
  5. 4
      objectivec/GPBFieldMask.pbobjc.m
  6. 4
      objectivec/GPBSourceContext.pbobjc.m
  7. 12
      objectivec/GPBStruct.pbobjc.m
  8. 4
      objectivec/GPBTimestamp.pbobjc.m
  9. 20
      objectivec/GPBType.pbobjc.m
  10. 36
      objectivec/GPBWrappers.pbobjc.m
  11. 366
      src/google/protobuf/map_field.cc
  12. 59
      src/google/protobuf/map_field.h
  13. 46
      src/google/protobuf/map_field_inl.h
  14. 37
      src/google/protobuf/map_field_test.cc

@ -91,9 +91,9 @@ typedef struct GPBAny__storage_ {
"\001\001\004\241!!\000";
[localDescriptor setupExtraTextInfo:extraTextFormatInfo];
#endif // !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS
#if defined(DEBUG) && DEBUG
#if defined(DEBUG) && DEBUG
NSAssert(descriptor == nil, @"Startup recursed!");
#endif // DEBUG
#endif // DEBUG
descriptor = localDescriptor;
}
return descriptor;

@ -145,9 +145,9 @@ typedef struct GPBApi__storage_ {
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBApi__storage_)
flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown | GPBDescriptorInitializationFlag_ClosedEnumSupportKnown)];
#if defined(DEBUG) && DEBUG
#if defined(DEBUG) && DEBUG
NSAssert(descriptor == nil, @"Startup recursed!");
#endif // DEBUG
#endif // DEBUG
descriptor = localDescriptor;
}
return descriptor;
@ -272,9 +272,9 @@ typedef struct GPBMethod__storage_ {
"\002\002\007\244\241!!\000\004\010\244\241!!\000";
[localDescriptor setupExtraTextInfo:extraTextFormatInfo];
#endif // !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS
#if defined(DEBUG) && DEBUG
#if defined(DEBUG) && DEBUG
NSAssert(descriptor == nil, @"Startup recursed!");
#endif // DEBUG
#endif // DEBUG
descriptor = localDescriptor;
}
return descriptor;
@ -341,9 +341,9 @@ typedef struct GPBMixin__storage_ {
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBMixin__storage_)
flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown | GPBDescriptorInitializationFlag_ClosedEnumSupportKnown)];
#if defined(DEBUG) && DEBUG
#if defined(DEBUG) && DEBUG
NSAssert(descriptor == nil, @"Startup recursed!");
#endif // DEBUG
#endif // DEBUG
descriptor = localDescriptor;
}
return descriptor;

@ -86,9 +86,9 @@ typedef struct GPBDuration__storage_ {
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBDuration__storage_)
flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown | GPBDescriptorInitializationFlag_ClosedEnumSupportKnown)];
#if defined(DEBUG) && DEBUG
#if defined(DEBUG) && DEBUG
NSAssert(descriptor == nil, @"Startup recursed!");
#endif // DEBUG
#endif // DEBUG
descriptor = localDescriptor;
}
return descriptor;

@ -62,9 +62,9 @@ typedef struct GPBEmpty__storage_ {
fieldCount:0
storageSize:sizeof(GPBEmpty__storage_)
flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown | GPBDescriptorInitializationFlag_ClosedEnumSupportKnown)];
#if defined(DEBUG) && DEBUG
#if defined(DEBUG) && DEBUG
NSAssert(descriptor == nil, @"Startup recursed!");
#endif // DEBUG
#endif // DEBUG
descriptor = localDescriptor;
}
return descriptor;

@ -75,9 +75,9 @@ typedef struct GPBFieldMask__storage_ {
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBFieldMask__storage_)
flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown | GPBDescriptorInitializationFlag_ClosedEnumSupportKnown)];
#if defined(DEBUG) && DEBUG
#if defined(DEBUG) && DEBUG
NSAssert(descriptor == nil, @"Startup recursed!");
#endif // DEBUG
#endif // DEBUG
descriptor = localDescriptor;
}
return descriptor;

@ -75,9 +75,9 @@ typedef struct GPBSourceContext__storage_ {
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBSourceContext__storage_)
flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown | GPBDescriptorInitializationFlag_ClosedEnumSupportKnown)];
#if defined(DEBUG) && DEBUG
#if defined(DEBUG) && DEBUG
NSAssert(descriptor == nil, @"Startup recursed!");
#endif // DEBUG
#endif // DEBUG
descriptor = localDescriptor;
}
return descriptor;

@ -115,9 +115,9 @@ typedef struct GPBStruct__storage_ {
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBStruct__storage_)
flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown | GPBDescriptorInitializationFlag_ClosedEnumSupportKnown)];
#if defined(DEBUG) && DEBUG
#if defined(DEBUG) && DEBUG
NSAssert(descriptor == nil, @"Startup recursed!");
#endif // DEBUG
#endif // DEBUG
descriptor = localDescriptor;
}
return descriptor;
@ -222,9 +222,9 @@ typedef struct GPBValue__storage_ {
[localDescriptor setupOneofs:oneofs
count:(uint32_t)(sizeof(oneofs) / sizeof(char*))
firstHasIndex:-1];
#if defined(DEBUG) && DEBUG
#if defined(DEBUG) && DEBUG
NSAssert(descriptor == nil, @"Startup recursed!");
#endif // DEBUG
#endif // DEBUG
descriptor = localDescriptor;
}
return descriptor;
@ -285,9 +285,9 @@ typedef struct GPBListValue__storage_ {
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBListValue__storage_)
flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown | GPBDescriptorInitializationFlag_ClosedEnumSupportKnown)];
#if defined(DEBUG) && DEBUG
#if defined(DEBUG) && DEBUG
NSAssert(descriptor == nil, @"Startup recursed!");
#endif // DEBUG
#endif // DEBUG
descriptor = localDescriptor;
}
return descriptor;

@ -86,9 +86,9 @@ typedef struct GPBTimestamp__storage_ {
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBTimestamp__storage_)
flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown | GPBDescriptorInitializationFlag_ClosedEnumSupportKnown)];
#if defined(DEBUG) && DEBUG
#if defined(DEBUG) && DEBUG
NSAssert(descriptor == nil, @"Startup recursed!");
#endif // DEBUG
#endif // DEBUG
descriptor = localDescriptor;
}
return descriptor;

@ -307,9 +307,9 @@ typedef struct GPBType__storage_ {
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBType__storage_)
flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown | GPBDescriptorInitializationFlag_ClosedEnumSupportKnown)];
#if defined(DEBUG) && DEBUG
#if defined(DEBUG) && DEBUG
NSAssert(descriptor == nil, @"Startup recursed!");
#endif // DEBUG
#endif // DEBUG
descriptor = localDescriptor;
}
return descriptor;
@ -468,9 +468,9 @@ typedef struct GPBField__storage_ {
"\001\006\004\241!!\000";
[localDescriptor setupExtraTextInfo:extraTextFormatInfo];
#endif // !GPBOBJC_SKIP_MESSAGE_TEXTFORMAT_EXTRAS
#if defined(DEBUG) && DEBUG
#if defined(DEBUG) && DEBUG
NSAssert(descriptor == nil, @"Startup recursed!");
#endif // DEBUG
#endif // DEBUG
descriptor = localDescriptor;
}
return descriptor;
@ -593,9 +593,9 @@ typedef struct GPBEnum__storage_ {
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBEnum__storage_)
flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown | GPBDescriptorInitializationFlag_ClosedEnumSupportKnown)];
#if defined(DEBUG) && DEBUG
#if defined(DEBUG) && DEBUG
NSAssert(descriptor == nil, @"Startup recursed!");
#endif // DEBUG
#endif // DEBUG
descriptor = localDescriptor;
}
return descriptor;
@ -673,9 +673,9 @@ typedef struct GPBEnumValue__storage_ {
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBEnumValue__storage_)
flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown | GPBDescriptorInitializationFlag_ClosedEnumSupportKnown)];
#if defined(DEBUG) && DEBUG
#if defined(DEBUG) && DEBUG
NSAssert(descriptor == nil, @"Startup recursed!");
#endif // DEBUG
#endif // DEBUG
descriptor = localDescriptor;
}
return descriptor;
@ -730,9 +730,9 @@ typedef struct GPBOption__storage_ {
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBOption__storage_)
flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown | GPBDescriptorInitializationFlag_ClosedEnumSupportKnown)];
#if defined(DEBUG) && DEBUG
#if defined(DEBUG) && DEBUG
NSAssert(descriptor == nil, @"Startup recursed!");
#endif // DEBUG
#endif // DEBUG
descriptor = localDescriptor;
}
return descriptor;

@ -83,9 +83,9 @@ typedef struct GPBDoubleValue__storage_ {
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBDoubleValue__storage_)
flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown | GPBDescriptorInitializationFlag_ClosedEnumSupportKnown)];
#if defined(DEBUG) && DEBUG
#if defined(DEBUG) && DEBUG
NSAssert(descriptor == nil, @"Startup recursed!");
#endif // DEBUG
#endif // DEBUG
descriptor = localDescriptor;
}
return descriptor;
@ -129,9 +129,9 @@ typedef struct GPBFloatValue__storage_ {
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBFloatValue__storage_)
flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown | GPBDescriptorInitializationFlag_ClosedEnumSupportKnown)];
#if defined(DEBUG) && DEBUG
#if defined(DEBUG) && DEBUG
NSAssert(descriptor == nil, @"Startup recursed!");
#endif // DEBUG
#endif // DEBUG
descriptor = localDescriptor;
}
return descriptor;
@ -175,9 +175,9 @@ typedef struct GPBInt64Value__storage_ {
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBInt64Value__storage_)
flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown | GPBDescriptorInitializationFlag_ClosedEnumSupportKnown)];
#if defined(DEBUG) && DEBUG
#if defined(DEBUG) && DEBUG
NSAssert(descriptor == nil, @"Startup recursed!");
#endif // DEBUG
#endif // DEBUG
descriptor = localDescriptor;
}
return descriptor;
@ -221,9 +221,9 @@ typedef struct GPBUInt64Value__storage_ {
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBUInt64Value__storage_)
flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown | GPBDescriptorInitializationFlag_ClosedEnumSupportKnown)];
#if defined(DEBUG) && DEBUG
#if defined(DEBUG) && DEBUG
NSAssert(descriptor == nil, @"Startup recursed!");
#endif // DEBUG
#endif // DEBUG
descriptor = localDescriptor;
}
return descriptor;
@ -267,9 +267,9 @@ typedef struct GPBInt32Value__storage_ {
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBInt32Value__storage_)
flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown | GPBDescriptorInitializationFlag_ClosedEnumSupportKnown)];
#if defined(DEBUG) && DEBUG
#if defined(DEBUG) && DEBUG
NSAssert(descriptor == nil, @"Startup recursed!");
#endif // DEBUG
#endif // DEBUG
descriptor = localDescriptor;
}
return descriptor;
@ -313,9 +313,9 @@ typedef struct GPBUInt32Value__storage_ {
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBUInt32Value__storage_)
flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown | GPBDescriptorInitializationFlag_ClosedEnumSupportKnown)];
#if defined(DEBUG) && DEBUG
#if defined(DEBUG) && DEBUG
NSAssert(descriptor == nil, @"Startup recursed!");
#endif // DEBUG
#endif // DEBUG
descriptor = localDescriptor;
}
return descriptor;
@ -358,9 +358,9 @@ typedef struct GPBBoolValue__storage_ {
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBBoolValue__storage_)
flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown | GPBDescriptorInitializationFlag_ClosedEnumSupportKnown)];
#if defined(DEBUG) && DEBUG
#if defined(DEBUG) && DEBUG
NSAssert(descriptor == nil, @"Startup recursed!");
#endif // DEBUG
#endif // DEBUG
descriptor = localDescriptor;
}
return descriptor;
@ -404,9 +404,9 @@ typedef struct GPBStringValue__storage_ {
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBStringValue__storage_)
flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown | GPBDescriptorInitializationFlag_ClosedEnumSupportKnown)];
#if defined(DEBUG) && DEBUG
#if defined(DEBUG) && DEBUG
NSAssert(descriptor == nil, @"Startup recursed!");
#endif // DEBUG
#endif // DEBUG
descriptor = localDescriptor;
}
return descriptor;
@ -450,9 +450,9 @@ typedef struct GPBBytesValue__storage_ {
fieldCount:(uint32_t)(sizeof(fields) / sizeof(GPBMessageFieldDescription))
storageSize:sizeof(GPBBytesValue__storage_)
flags:(GPBDescriptorInitializationFlags)(GPBDescriptorInitializationFlag_UsesClassRefs | GPBDescriptorInitializationFlag_Proto3OptionalKnown | GPBDescriptorInitializationFlag_ClosedEnumSupportKnown)];
#if defined(DEBUG) && DEBUG
#if defined(DEBUG) && DEBUG
NSAssert(descriptor == nil, @"Startup recursed!");
#endif // DEBUG
#endif // DEBUG
descriptor = localDescriptor;
}
return descriptor;

@ -224,7 +224,7 @@ void MapFieldBase::SyncRepeatedFieldWithMap() const {
// Double check state, because another thread may have seen the same
// state and done the synchronization before the current thread.
if (p.state.load(std::memory_order_relaxed) == STATE_MODIFIED_MAP) {
SyncRepeatedFieldWithMapNoLock();
const_cast<MapFieldBase*>(this)->SyncRepeatedFieldWithMapNoLock();
p.state.store(CLEAN, std::memory_order_release);
}
}
@ -232,6 +232,88 @@ void MapFieldBase::SyncRepeatedFieldWithMap() const {
}
}
void MapFieldBase::SyncRepeatedFieldWithMapNoLock() {
const Message* prototype = GetPrototype();
const Reflection* reflection = prototype->GetReflection();
const Descriptor* descriptor = prototype->GetDescriptor();
const FieldDescriptor* key_des = descriptor->map_key();
const FieldDescriptor* val_des = descriptor->map_value();
RepeatedPtrField<Message>& rep = payload().repeated_field;
rep.Clear();
MapIterator it(this, descriptor);
MapIterator end(this, descriptor);
it.iter_ = GetMapRaw().begin();
SetMapIteratorValue(&it);
end.iter_ = UntypedMapBase::EndIterator();
for (; !EqualIterator(it, end); IncreaseIterator(&it)) {
Message* new_entry = prototype->New(arena());
rep.AddAllocated(new_entry);
const MapKey& map_key = it.GetKey();
switch (key_des->cpp_type()) {
case FieldDescriptor::CPPTYPE_STRING:
reflection->SetString(new_entry, key_des, map_key.GetStringValue());
break;
case FieldDescriptor::CPPTYPE_INT64:
reflection->SetInt64(new_entry, key_des, map_key.GetInt64Value());
break;
case FieldDescriptor::CPPTYPE_INT32:
reflection->SetInt32(new_entry, key_des, map_key.GetInt32Value());
break;
case FieldDescriptor::CPPTYPE_UINT64:
reflection->SetUInt64(new_entry, key_des, map_key.GetUInt64Value());
break;
case FieldDescriptor::CPPTYPE_UINT32:
reflection->SetUInt32(new_entry, key_des, map_key.GetUInt32Value());
break;
case FieldDescriptor::CPPTYPE_BOOL:
reflection->SetBool(new_entry, key_des, map_key.GetBoolValue());
break;
default:
PROTOBUF_ASSUME(false);
}
const MapValueRef& map_val = it.GetValueRef();
switch (val_des->cpp_type()) {
case FieldDescriptor::CPPTYPE_STRING:
reflection->SetString(new_entry, val_des, map_val.GetStringValue());
break;
case FieldDescriptor::CPPTYPE_INT64:
reflection->SetInt64(new_entry, val_des, map_val.GetInt64Value());
break;
case FieldDescriptor::CPPTYPE_INT32:
reflection->SetInt32(new_entry, val_des, map_val.GetInt32Value());
break;
case FieldDescriptor::CPPTYPE_UINT64:
reflection->SetUInt64(new_entry, val_des, map_val.GetUInt64Value());
break;
case FieldDescriptor::CPPTYPE_UINT32:
reflection->SetUInt32(new_entry, val_des, map_val.GetUInt32Value());
break;
case FieldDescriptor::CPPTYPE_BOOL:
reflection->SetBool(new_entry, val_des, map_val.GetBoolValue());
break;
case FieldDescriptor::CPPTYPE_DOUBLE:
reflection->SetDouble(new_entry, val_des, map_val.GetDoubleValue());
break;
case FieldDescriptor::CPPTYPE_FLOAT:
reflection->SetFloat(new_entry, val_des, map_val.GetFloatValue());
break;
case FieldDescriptor::CPPTYPE_ENUM:
reflection->SetEnumValue(new_entry, val_des, map_val.GetEnumValue());
break;
case FieldDescriptor::CPPTYPE_MESSAGE: {
const Message& message = map_val.GetMessageValue();
reflection->MutableMessage(new_entry, val_des)->CopyFrom(message);
break;
}
}
}
}
void MapFieldBase::SyncMapWithRepeatedField() const {
ConstAccess();
// acquire here matches with release below to ensure that we can only see a
@ -243,7 +325,7 @@ void MapFieldBase::SyncMapWithRepeatedField() const {
// Double check state, because another thread may have seen the same state
// and done the synchronization before the current thread.
if (p.state.load(std::memory_order_relaxed) == STATE_MODIFIED_REPEATED) {
SyncMapWithRepeatedFieldNoLock();
const_cast<MapFieldBase*>(this)->SyncMapWithRepeatedFieldNoLock();
p.state.store(CLEAN, std::memory_order_release);
}
}
@ -251,6 +333,96 @@ void MapFieldBase::SyncMapWithRepeatedField() const {
}
}
void MapFieldBase::SyncMapWithRepeatedFieldNoLock() {
ClearMapNoSync();
RepeatedPtrField<Message>& rep = payload().repeated_field;
if (rep.empty()) return;
const Message* prototype = &rep[0];
const Reflection* reflection = prototype->GetReflection();
const Descriptor* descriptor = prototype->GetDescriptor();
const FieldDescriptor* key_des = descriptor->map_key();
const FieldDescriptor* val_des = descriptor->map_value();
for (const Message& elem : rep) {
// MapKey type will be set later.
MapKey map_key;
switch (key_des->cpp_type()) {
case FieldDescriptor::CPPTYPE_STRING:
map_key.SetStringValue(reflection->GetString(elem, key_des));
break;
case FieldDescriptor::CPPTYPE_INT64:
map_key.SetInt64Value(reflection->GetInt64(elem, key_des));
break;
case FieldDescriptor::CPPTYPE_INT32:
map_key.SetInt32Value(reflection->GetInt32(elem, key_des));
break;
case FieldDescriptor::CPPTYPE_UINT64:
map_key.SetUInt64Value(reflection->GetUInt64(elem, key_des));
break;
case FieldDescriptor::CPPTYPE_UINT32:
map_key.SetUInt32Value(reflection->GetUInt32(elem, key_des));
break;
case FieldDescriptor::CPPTYPE_BOOL:
map_key.SetBoolValue(reflection->GetBool(elem, key_des));
break;
default:
PROTOBUF_ASSUME(false);
}
MapValueRef map_val;
map_val.SetType(val_des->cpp_type());
InsertOrLookupMapValueNoSync(map_key, &map_val);
switch (val_des->cpp_type()) {
#define HANDLE_TYPE(CPPTYPE, METHOD) \
case FieldDescriptor::CPPTYPE_##CPPTYPE: \
map_val.Set##METHOD##Value(reflection->Get##METHOD(elem, val_des)); \
break;
HANDLE_TYPE(INT32, Int32);
HANDLE_TYPE(INT64, Int64);
HANDLE_TYPE(UINT32, UInt32);
HANDLE_TYPE(UINT64, UInt64);
HANDLE_TYPE(DOUBLE, Double);
HANDLE_TYPE(FLOAT, Float);
HANDLE_TYPE(BOOL, Bool);
HANDLE_TYPE(STRING, String);
#undef HANDLE_TYPE
case FieldDescriptor::CPPTYPE_ENUM:
map_val.SetEnumValue(reflection->GetEnumValue(elem, val_des));
break;
case FieldDescriptor::CPPTYPE_MESSAGE: {
map_val.MutableMessageValue()->CopyFrom(
reflection->GetMessage(elem, val_des));
break;
}
}
}
}
void MapFieldBase::Clear() {
if (ReflectionPayload* p = maybe_payload()) {
p->repeated_field.Clear();
}
ClearMapNoSync();
// Data in map and repeated field are both empty, but we can't set status
// CLEAN. Because clear is a generated API, we cannot invalidate previous
// reference to map.
SetMapDirty();
}
int MapFieldBase::size() const { return GetMap().size(); }
bool MapFieldBase::InsertOrLookupMapValue(const MapKey& map_key,
MapValueRef* val) {
SyncMapWithRepeatedField();
SetMapDirty();
return InsertOrLookupMapValueNoSync(map_key, val);
}
// ------------------DynamicMapField------------------
DynamicMapField::DynamicMapField(const Message* default_entry)
: default_entry_(default_entry) {}
@ -269,23 +441,14 @@ DynamicMapField::~DynamicMapField() {
map_.clear();
}
void DynamicMapField::Clear() {
Map<MapKey, MapValueRef>* map = &const_cast<DynamicMapField*>(this)->map_;
void DynamicMapField::ClearMapNoSync() {
if (arena() == nullptr) {
for (Map<MapKey, MapValueRef>::iterator iter = map->begin();
iter != map->end(); ++iter) {
iter->second.DeleteData();
for (auto& elem : map_) {
elem.second.DeleteData();
}
}
map->clear();
if (auto* p = maybe_payload()) {
p->repeated_field.Clear();
}
// Data in map and repeated field are both empty, but we can't set status
// CLEAN which will invalidate previous reference to map.
MapFieldBase::SetMapDirty();
map_.clear();
}
void DynamicMapField::AllocateMapValue(MapValueRef* map_val) {
@ -320,13 +483,10 @@ void DynamicMapField::AllocateMapValue(MapValueRef* map_val) {
}
}
bool DynamicMapField::InsertOrLookupMapValue(const MapKey& map_key,
MapValueRef* val) {
// Always use mutable map because users may change the map value by
// MapValueRef.
Map<MapKey, MapValueRef>* map = MutableMap();
Map<MapKey, MapValueRef>::iterator iter = map->find(map_key);
if (iter == map->end()) {
bool DynamicMapField::InsertOrLookupMapValueNoSync(const MapKey& map_key,
MapValueRef* val) {
Map<MapKey, MapValueRef>::iterator iter = map_.find(map_key);
if (iter == map_.end()) {
MapValueRef& map_val = map_[map_key];
AllocateMapValue(&map_val);
val->CopyFrom(map_val);
@ -404,167 +564,7 @@ void DynamicMapField::MergeFrom(const MapFieldBase& other) {
}
}
void DynamicMapField::SyncRepeatedFieldWithMapNoLock() const {
const Reflection* reflection = default_entry_->GetReflection();
const FieldDescriptor* key_des = default_entry_->GetDescriptor()->map_key();
const FieldDescriptor* val_des = default_entry_->GetDescriptor()->map_value();
auto& rep = payload().repeated_field;
rep.Clear();
for (Map<MapKey, MapValueRef>::const_iterator it = map_.begin();
it != map_.end(); ++it) {
Message* new_entry = default_entry_->New(arena());
rep.AddAllocated(new_entry);
const MapKey& map_key = it->first;
switch (key_des->cpp_type()) {
case FieldDescriptor::CPPTYPE_STRING:
reflection->SetString(new_entry, key_des, map_key.GetStringValue());
break;
case FieldDescriptor::CPPTYPE_INT64:
reflection->SetInt64(new_entry, key_des, map_key.GetInt64Value());
break;
case FieldDescriptor::CPPTYPE_INT32:
reflection->SetInt32(new_entry, key_des, map_key.GetInt32Value());
break;
case FieldDescriptor::CPPTYPE_UINT64:
reflection->SetUInt64(new_entry, key_des, map_key.GetUInt64Value());
break;
case FieldDescriptor::CPPTYPE_UINT32:
reflection->SetUInt32(new_entry, key_des, map_key.GetUInt32Value());
break;
case FieldDescriptor::CPPTYPE_BOOL:
reflection->SetBool(new_entry, key_des, map_key.GetBoolValue());
break;
case FieldDescriptor::CPPTYPE_DOUBLE:
case FieldDescriptor::CPPTYPE_FLOAT:
case FieldDescriptor::CPPTYPE_ENUM:
case FieldDescriptor::CPPTYPE_MESSAGE:
ABSL_LOG(FATAL) << "Can't get here.";
break;
}
const MapValueRef& map_val = it->second;
switch (val_des->cpp_type()) {
case FieldDescriptor::CPPTYPE_STRING:
reflection->SetString(new_entry, val_des, map_val.GetStringValue());
break;
case FieldDescriptor::CPPTYPE_INT64:
reflection->SetInt64(new_entry, val_des, map_val.GetInt64Value());
break;
case FieldDescriptor::CPPTYPE_INT32:
reflection->SetInt32(new_entry, val_des, map_val.GetInt32Value());
break;
case FieldDescriptor::CPPTYPE_UINT64:
reflection->SetUInt64(new_entry, val_des, map_val.GetUInt64Value());
break;
case FieldDescriptor::CPPTYPE_UINT32:
reflection->SetUInt32(new_entry, val_des, map_val.GetUInt32Value());
break;
case FieldDescriptor::CPPTYPE_BOOL:
reflection->SetBool(new_entry, val_des, map_val.GetBoolValue());
break;
case FieldDescriptor::CPPTYPE_DOUBLE:
reflection->SetDouble(new_entry, val_des, map_val.GetDoubleValue());
break;
case FieldDescriptor::CPPTYPE_FLOAT:
reflection->SetFloat(new_entry, val_des, map_val.GetFloatValue());
break;
case FieldDescriptor::CPPTYPE_ENUM:
reflection->SetEnumValue(new_entry, val_des, map_val.GetEnumValue());
break;
case FieldDescriptor::CPPTYPE_MESSAGE: {
const Message& message = map_val.GetMessageValue();
reflection->MutableMessage(new_entry, val_des)->CopyFrom(message);
break;
}
}
}
}
void DynamicMapField::SyncMapWithRepeatedFieldNoLock() const {
Map<MapKey, MapValueRef>* map = &const_cast<DynamicMapField*>(this)->map_;
const Reflection* reflection = default_entry_->GetReflection();
const FieldDescriptor* key_des = default_entry_->GetDescriptor()->map_key();
const FieldDescriptor* val_des = default_entry_->GetDescriptor()->map_value();
Arena* arena = this->arena();
// DynamicMapField owns map values. Need to delete them before clearing
// the map.
if (arena == nullptr) {
for (Map<MapKey, MapValueRef>::iterator iter = map->begin();
iter != map->end(); ++iter) {
iter->second.DeleteData();
}
}
map->clear();
auto& rep = payload().repeated_field;
for (const Message& elem : rep) {
// MapKey type will be set later.
MapKey map_key;
switch (key_des->cpp_type()) {
case FieldDescriptor::CPPTYPE_STRING:
map_key.SetStringValue(reflection->GetString(elem, key_des));
break;
case FieldDescriptor::CPPTYPE_INT64:
map_key.SetInt64Value(reflection->GetInt64(elem, key_des));
break;
case FieldDescriptor::CPPTYPE_INT32:
map_key.SetInt32Value(reflection->GetInt32(elem, key_des));
break;
case FieldDescriptor::CPPTYPE_UINT64:
map_key.SetUInt64Value(reflection->GetUInt64(elem, key_des));
break;
case FieldDescriptor::CPPTYPE_UINT32:
map_key.SetUInt32Value(reflection->GetUInt32(elem, key_des));
break;
case FieldDescriptor::CPPTYPE_BOOL:
map_key.SetBoolValue(reflection->GetBool(elem, key_des));
break;
case FieldDescriptor::CPPTYPE_DOUBLE:
case FieldDescriptor::CPPTYPE_FLOAT:
case FieldDescriptor::CPPTYPE_ENUM:
case FieldDescriptor::CPPTYPE_MESSAGE:
ABSL_LOG(FATAL) << "Can't get here.";
break;
}
if (arena == nullptr) {
// Remove existing map value with same key.
Map<MapKey, MapValueRef>::iterator iter = map->find(map_key);
if (iter != map->end()) {
iter->second.DeleteData();
}
}
MapValueRef& map_val = (*map)[map_key];
map_val.SetType(val_des->cpp_type());
switch (val_des->cpp_type()) {
#define HANDLE_TYPE(CPPTYPE, TYPE, METHOD) \
case FieldDescriptor::CPPTYPE_##CPPTYPE: { \
auto* value = Arena::Create<TYPE>(arena); \
*value = reflection->Get##METHOD(elem, val_des); \
map_val.SetValue(value); \
break; \
}
HANDLE_TYPE(INT32, int32_t, Int32);
HANDLE_TYPE(INT64, int64_t, Int64);
HANDLE_TYPE(UINT32, uint32_t, UInt32);
HANDLE_TYPE(UINT64, uint64_t, UInt64);
HANDLE_TYPE(DOUBLE, double, Double);
HANDLE_TYPE(FLOAT, float, Float);
HANDLE_TYPE(BOOL, bool, Bool);
HANDLE_TYPE(STRING, std::string, String);
HANDLE_TYPE(ENUM, int32_t, EnumValue);
#undef HANDLE_TYPE
case FieldDescriptor::CPPTYPE_MESSAGE: {
const Message& message = reflection->GetMessage(elem, val_des);
Message* value = message.New(arena);
value->CopyFrom(message);
map_val.SetValue(value);
break;
}
}
}
}
const Message* DynamicMapField::GetPrototype() const { return default_entry_; }
size_t DynamicMapField::SpaceUsedExcludingSelfNoLock() const {
size_t size = 0;

@ -337,12 +337,12 @@ class PROTOBUF_EXPORT MapFieldBase : public MapFieldBaseForParse {
// Pure virtual map APIs for Map Reflection.
virtual bool ContainsMapKey(const MapKey& map_key) const = 0;
virtual bool InsertOrLookupMapValue(const MapKey& map_key,
MapValueRef* val) = 0;
virtual bool LookupMapValue(const MapKey& map_key,
MapValueConstRef* val) const = 0;
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.
bool IsRepeatedFieldValid() const;
// Insures operations after won't get executed before calling this.
@ -352,8 +352,8 @@ class PROTOBUF_EXPORT MapFieldBase : public MapFieldBaseForParse {
virtual void Swap(MapFieldBase* other);
virtual void UnsafeShallowSwap(MapFieldBase* other);
// Sync Map with repeated field and returns the size of map.
virtual int size() const = 0;
virtual void Clear() = 0;
int size() const;
void Clear();
virtual void SetMapIteratorValue(MapIterator* map_iter) const = 0;
void MapBegin(MapIterator* map_iter) const;
@ -373,15 +373,18 @@ class PROTOBUF_EXPORT MapFieldBase : public MapFieldBaseForParse {
// Gets the size of space used by map field.
virtual size_t SpaceUsedExcludingSelfNoLock() const;
virtual const Message* GetPrototype() const = 0;
virtual void ClearMapNoSync() = 0;
// Synchronizes the content in Map to RepeatedPtrField if there is any change
// to Map after last synchronization.
void SyncRepeatedFieldWithMap() const;
virtual void SyncRepeatedFieldWithMapNoLock() const = 0;
void SyncRepeatedFieldWithMapNoLock();
// Synchronizes the content in RepeatedPtrField to Map if there is any change
// to RepeatedPtrField after last synchronization.
void SyncMapWithRepeatedField() const;
virtual void SyncMapWithRepeatedFieldNoLock() const = 0;
void SyncMapWithRepeatedFieldNoLock();
// Tells MapFieldBase that there is new change to Map.
void SetMapDirty();
@ -392,6 +395,9 @@ class PROTOBUF_EXPORT MapFieldBase : public MapFieldBaseForParse {
// Provides derived class the access to repeated field.
void* MutableRepeatedPtrField() const;
virtual bool InsertOrLookupMapValueNoSync(const MapKey& map_key,
MapValueRef* val) = 0;
void InternalSwap(MapFieldBase* other);
// Support thread sanitizer (tsan) by making const / mutable races
@ -551,19 +557,7 @@ class TypeDefinedMapFieldBase : public MapFieldBase {
return &map_;
}
void Clear() override {
if (auto* p = maybe_payload()) {
p->repeated_field.Clear();
}
MutableMap()->clear();
// Data in map and repeated field are both empty, but we can't set status
// CLEAN. Because clear is a generated API, we cannot invalidate previous
// reference to map.
SetMapDirty();
}
int size() const final { return GetMap().size(); }
void ClearMapNoSync() override { map_.clear(); }
void InternalSwap(TypeDefinedMapFieldBase* other);
@ -588,7 +582,8 @@ class TypeDefinedMapFieldBase : public MapFieldBase {
bool LookupMapValue(const MapKey& map_key, MapValueConstRef* val) const final;
bool LookupMapValue(const MapKey&, MapValueRef*) const = delete;
bool DeleteMapValue(const MapKey& map_key) final;
bool InsertOrLookupMapValue(const MapKey& map_key, MapValueRef* val) override;
bool InsertOrLookupMapValueNoSync(const MapKey& map_key,
MapValueRef* val) override;
};
// This class provides access to map field using generated api. It is used for
@ -610,13 +605,6 @@ class MapField final : public TypeDefinedMapFieldBase<Key, T> {
typedef MapFieldLite<Derived, Key, T, kKeyFieldType_, kValueFieldType_>
MapFieldLiteType;
// Enum needs to be handled differently from other types because it has
// different exposed type in Map's api and repeated field's api. For
// details see the comment in the implementation of
// SyncMapWithRepeatedFieldNoLock.
static constexpr bool kIsValueEnum = ValueTypeHandler::kIsEnum;
typedef typename MapIf<kIsValueEnum, T, const T&>::type CastValueType;
public:
typedef Map<Key, T> MapType;
static constexpr WireFormatLite::FieldType kKeyFieldType = kKeyFieldType_;
@ -654,8 +642,7 @@ class MapField final : public TypeDefinedMapFieldBase<Key, T> {
typedef void DestructorSkippable_;
// Implements MapFieldBase
void SyncRepeatedFieldWithMapNoLock() const final;
void SyncMapWithRepeatedFieldNoLock() const final;
const Message* GetPrototype() const final;
friend class google::protobuf::Arena;
friend class MapFieldStateTest; // For testing, it needs raw access to impl_
@ -687,11 +674,12 @@ class PROTOBUF_EXPORT DynamicMapField final
virtual ~DynamicMapField();
// Implement MapFieldBase
bool InsertOrLookupMapValue(const MapKey& map_key, MapValueRef* val) final;
bool InsertOrLookupMapValueNoSync(const MapKey& map_key,
MapValueRef* val) final;
void MergeFrom(const MapFieldBase& other) final;
void UnsafeShallowSwap(MapFieldBase* other) final { Swap(other); }
void Clear() final;
void ClearMapNoSync() final;
private:
const Message* default_entry_;
@ -699,8 +687,7 @@ class PROTOBUF_EXPORT DynamicMapField final
void AllocateMapValue(MapValueRef* map_val);
// Implements MapFieldBase
void SyncRepeatedFieldWithMapNoLock() const final;
void SyncMapWithRepeatedFieldNoLock() const final;
const Message* GetPrototype() const final;
size_t SpaceUsedExcludingSelfNoLock() const final;
};
@ -928,6 +915,12 @@ class PROTOBUF_EXPORT MapIterator {
friend class internal::MapField;
friend class internal::MapFieldBase;
MapIterator(internal::MapFieldBase* map, const Descriptor* descriptor) {
map_ = map;
key_.SetType(descriptor->map_key()->cpp_type());
value_.SetType(descriptor->map_value()->cpp_type());
}
internal::UntypedMapIterator iter_;
// Point to a MapField to call helper methods implemented in MapField.
// MapIterator does not own this object.

@ -124,12 +124,9 @@ bool TypeDefinedMapFieldBase<Key, T>::ContainsMapKey(
}
template <typename Key, typename T>
bool TypeDefinedMapFieldBase<Key, T>::InsertOrLookupMapValue(
bool TypeDefinedMapFieldBase<Key, T>::InsertOrLookupMapValueNoSync(
const MapKey& map_key, MapValueRef* val) {
// Always use mutable map because users may change the map value by
// MapValueRef.
auto& map = *MutableMap();
auto res = map.try_emplace(UnwrapMapKey<Key>(map_key));
auto res = map_.try_emplace(UnwrapMapKey<Key>(map_key));
val->SetValue(&res.first->second);
return res.second;
}
@ -200,44 +197,11 @@ void TypeDefinedMapFieldBase<Key, T>::InternalSwap(
template <typename Derived, typename Key, typename T,
WireFormatLite::FieldType kKeyFieldType,
WireFormatLite::FieldType kValueFieldType>
void MapField<Derived, Key, T, kKeyFieldType,
kValueFieldType>::SyncRepeatedFieldWithMapNoLock() const {
auto& repeated_field = this->payload().repeated_field;
repeated_field.Clear();
// The only way we can get at this point is through reflection and the
// only way we can get the reflection object is by having called GetReflection
// on the encompassing field. So that type must have existed and hence we
// know that this MapEntry default_type has also already been constructed.
// So it's safe to just call internal_default_instance().
auto* arena = this->arena();
const Message* default_entry = Derived::internal_default_instance();
for (auto& elem : this->map_) {
EntryType* new_entry = DownCast<EntryType*>(default_entry->New(arena));
repeated_field.AddAllocated(new_entry);
(*new_entry->mutable_key()) = elem.first;
(*new_entry->mutable_value()) = elem.second;
}
const Message* MapField<Derived, Key, T, kKeyFieldType,
kValueFieldType>::GetPrototype() const {
return Derived::internal_default_instance();
}
template <typename Derived, typename Key, typename T,
WireFormatLite::FieldType kKeyFieldType,
WireFormatLite::FieldType kValueFieldType>
void MapField<Derived, Key, T, kKeyFieldType,
kValueFieldType>::SyncMapWithRepeatedFieldNoLock() const {
Map<Key, T>& map = const_cast<MapField*>(this)->map_;
auto& repeated_field = this->payload().repeated_field;
map.clear();
for (const auto& generic_elem : repeated_field) {
// Cast is needed because Map's api and internal storage is different when
// value is enum. For enum, we cannot cast an int to enum. Thus, we have to
// copy value. For other types, they have same exposed api type and internal
// stored type. We should not introduce value copy for them. We achieve this
// by casting to value for enum while casting to reference for other types.
const EntryType& elem = DownCast<const EntryType&>(generic_elem);
map[elem.key()] = static_cast<CastValueType>(elem.value());
}
}
} // namespace internal
} // namespace protobuf
} // namespace google

@ -35,10 +35,14 @@
#include "google/protobuf/map_field_inl.h"
#include "google/protobuf/message.h"
#include "google/protobuf/repeated_field.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "absl/container/flat_hash_map.h"
#include "absl/log/absl_check.h"
#include "absl/strings/str_format.h"
#include "absl/synchronization/barrier.h"
#include "absl/synchronization/blocking_counter.h"
#include "absl/types/optional.h"
#include "google/protobuf/arena_test_util.h"
#include "google/protobuf/map_test_util.h"
#include "google/protobuf/map_unittest.pb.h"
@ -54,41 +58,26 @@ namespace internal {
using unittest::TestAllTypes;
class MapFieldBaseStub : public MapFieldBase {
class MapFieldBaseStub : public TypeDefinedMapFieldBase<int32_t, int32_t> {
public:
using InternalArenaConstructable_ = void;
typedef void DestructorSkippable_;
MapFieldBaseStub() {}
virtual ~MapFieldBaseStub() {}
explicit MapFieldBaseStub(Arena* arena) : MapFieldBase(arena) {}
void SetMapDirty() {
payload().state.store(STATE_MODIFIED_MAP, std::memory_order_relaxed);
}
void SetRepeatedDirty() {
payload().state.store(STATE_MODIFIED_REPEATED, std::memory_order_relaxed);
}
void SyncRepeatedFieldWithMapNoLock() const override {}
void SyncMapWithRepeatedFieldNoLock() const override {}
bool ContainsMapKey(const MapKey& map_key) const override { return false; }
bool InsertOrLookupMapValue(const MapKey& map_key,
MapValueRef* val) override {
return false;
}
bool LookupMapValue(const MapKey& map_key,
MapValueConstRef* val) const override {
return false;
explicit MapFieldBaseStub(Arena* arena)
: MapFieldBaseStub::TypeDefinedMapFieldBase(arena) {}
const Message* GetPrototype() const override {
return unittest::TestMap_MapInt32Int32Entry_DoNotUse::
internal_default_instance();
}
bool DeleteMapValue(const MapKey& map_key) override { return false; }
int size() const override { return 0; }
void Clear() override {}
void MergeFrom(const MapFieldBase& other) override {}
void Swap(MapFieldBase* other) override {}
void SetMapIteratorValue(MapIterator* map_iter) const override {}
Arena* GetArenaForInternalRepeatedField() {
auto* repeated_field = MutableRepeatedField();
return repeated_field->GetArena();
}
using MapFieldBaseStub::TypeDefinedMapFieldBase::map_;
};
class MapFieldBasePrimitiveTest : public testing::TestWithParam<bool> {

Loading…
Cancel
Save