// Protocol Buffers - Google's data interchange format // Copyright 2008 Google Inc. All rights reserved. // https://developers.google.com/protocol-buffers/ // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above // copyright notice, this list of conditions and the following disclaimer // in the documentation and/or other materials provided with the // distribution. // * Neither the name of Google Inc. nor the names of its // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "google/protobuf/map_field.h" #include #include #include "google/protobuf/port.h" #include "google/protobuf/map_field_inl.h" // Must be included last. #include "google/protobuf/port_def.inc" namespace google { namespace protobuf { namespace internal { using ::google::protobuf::internal::DownCast; VariantKey RealKeyToVariantKey::operator()(const MapKey& value) const { switch (value.type()) { case FieldDescriptor::CPPTYPE_STRING: return VariantKey(value.GetStringValue()); case FieldDescriptor::CPPTYPE_INT64: return VariantKey(value.GetInt64Value()); case FieldDescriptor::CPPTYPE_INT32: return VariantKey(value.GetInt32Value()); case FieldDescriptor::CPPTYPE_UINT64: return VariantKey(value.GetUInt64Value()); case FieldDescriptor::CPPTYPE_UINT32: return VariantKey(value.GetUInt32Value()); case FieldDescriptor::CPPTYPE_BOOL: return VariantKey(static_cast(value.GetBoolValue())); default: ABSL_ASSUME(false); return VariantKey(uint64_t{}); } } MapFieldBase::~MapFieldBase() { ABSL_DCHECK_EQ(arena(), nullptr); delete maybe_payload(); } const UntypedMapBase& MapFieldBase::GetMapImpl(bool is_mutable) const { SyncMapWithRepeatedField(); if (is_mutable) const_cast(this)->SetMapDirty(); return GetMapRaw(); } 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(); } bool MapFieldBase::EqualIterator(const MapIterator& a, const MapIterator& b) const { return a.iter_.Equals(b.iter_); } void MapFieldBase::IncreaseIterator(MapIterator* map_iter) const { map_iter->iter_.PlusPlus(); SetMapIteratorValue(map_iter); } void MapFieldBase::CopyIterator(MapIterator* this_iter, const MapIterator& 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(that_iter.value_.type_)); SetMapIteratorValue(this_iter); } const RepeatedPtrFieldBase& MapFieldBase::GetRepeatedField() const { ConstAccess(); SyncRepeatedFieldWithMap(); return reinterpret_cast(payload().repeated_field); } RepeatedPtrFieldBase* MapFieldBase::MutableRepeatedField() { MutableAccess(); SyncRepeatedFieldWithMap(); SetRepeatedDirty(); return reinterpret_cast(&payload().repeated_field); } template static void SwapRelaxed(std::atomic& a, std::atomic& b) { auto value_b = b.load(std::memory_order_relaxed); auto value_a = a.load(std::memory_order_relaxed); b.store(value_a, std::memory_order_relaxed); a.store(value_b, std::memory_order_relaxed); } MapFieldBase::ReflectionPayload& MapFieldBase::PayloadSlow() const { auto p = payload_.load(std::memory_order_acquire); if (!IsPayload(p)) { auto* arena = ToArena(p); auto* payload = Arena::Create(arena, arena); auto new_p = ToTaggedPtr(payload); if (payload_.compare_exchange_strong(p, new_p, std::memory_order_acq_rel)) { // We were able to store it. p = new_p; } else { // Someone beat us to it. Throw away the one we made. `p` already contains // the one we want. if (arena == nullptr) delete payload; } } return *ToPayload(p); } void MapFieldBase::Swap(MapFieldBase* other) { if (arena() == other->arena()) { InternalSwap(other); return; } auto* p1 = maybe_payload(); auto* p2 = other->maybe_payload(); if (p1 == nullptr && p2 == nullptr) return; if (p1 == nullptr) p1 = &payload(); if (p2 == nullptr) p2 = &other->payload(); p1->repeated_field.Swap(&p2->repeated_field); SwapRelaxed(p1->state, p2->state); } void MapFieldBase::UnsafeShallowSwap(MapFieldBase* other) { ABSL_DCHECK_EQ(arena(), other->arena()); InternalSwap(other); } void MapFieldBase::InternalSwap(MapFieldBase* other) { SwapRelaxed(payload_, other->payload_); } size_t MapFieldBase::SpaceUsedExcludingSelfLong() const { ConstAccess(); size_t size = 0; if (auto* p = maybe_payload()) { { absl::MutexLock lock(&p->mutex); size = SpaceUsedExcludingSelfNoLock(); } ConstAccess(); } return size; } size_t MapFieldBase::SpaceUsedExcludingSelfNoLock() const { if (auto* p = maybe_payload()) { return p->repeated_field.SpaceUsedExcludingSelfLong(); } else { return 0; } } bool MapFieldBase::IsMapValid() const { ConstAccess(); // "Acquire" insures the operation after SyncRepeatedFieldWithMap won't get // executed before state_ is checked. return state() != STATE_MODIFIED_REPEATED; } bool MapFieldBase::IsRepeatedFieldValid() const { ConstAccess(); return state() != STATE_MODIFIED_MAP; } void MapFieldBase::SetMapDirty() { MutableAccess(); // These are called by (non-const) mutator functions. So by our API it's the // callers responsibility to have these calls properly ordered. payload().state.store(STATE_MODIFIED_MAP, std::memory_order_relaxed); } void MapFieldBase::SetRepeatedDirty() { MutableAccess(); // These are called by (non-const) mutator functions. So by our API it's the // callers responsibility to have these calls properly ordered. payload().state.store(STATE_MODIFIED_REPEATED, std::memory_order_relaxed); } void MapFieldBase::SyncRepeatedFieldWithMap() const { ConstAccess(); if (state() == STATE_MODIFIED_MAP) { auto& p = payload(); { absl::MutexLock lock(&p.mutex); // 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) { const_cast(this)->SyncRepeatedFieldWithMapNoLock(); p.state.store(CLEAN, std::memory_order_release); } } ConstAccess(); } } 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& 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 // value of CLEAN after all previous changes have been synced. if (state() == STATE_MODIFIED_REPEATED) { auto& p = payload(); { absl::MutexLock lock(&p.mutex); // 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) { const_cast(this)->SyncMapWithRepeatedFieldNoLock(); p.state.store(CLEAN, std::memory_order_release); } } ConstAccess(); } } void MapFieldBase::SyncMapWithRepeatedFieldNoLock() { ClearMapNoSync(); RepeatedPtrField& 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) {} DynamicMapField::DynamicMapField(const Message* default_entry, Arena* arena) : TypeDefinedMapFieldBase(arena), default_entry_(default_entry) {} DynamicMapField::~DynamicMapField() { ABSL_DCHECK_EQ(arena(), nullptr); // DynamicMapField owns map values. Need to delete them before clearing the // map. for (auto& kv : map_) { kv.second.DeleteData(); } map_.clear(); } void DynamicMapField::ClearMapNoSync() { if (arena() == nullptr) { for (auto& elem : map_) { elem.second.DeleteData(); } } map_.clear(); } void DynamicMapField::AllocateMapValue(MapValueRef* map_val) { const FieldDescriptor* val_des = default_entry_->GetDescriptor()->map_value(); map_val->SetType(val_des->cpp_type()); // Allocate memory for the MapValueRef, and initialize to // default value. switch (val_des->cpp_type()) { #define HANDLE_TYPE(CPPTYPE, TYPE) \ case FieldDescriptor::CPPTYPE_##CPPTYPE: { \ auto* value = Arena::Create(arena()); \ map_val->SetValue(value); \ break; \ } HANDLE_TYPE(INT32, int32_t); HANDLE_TYPE(INT64, int64_t); HANDLE_TYPE(UINT32, uint32_t); HANDLE_TYPE(UINT64, uint64_t); HANDLE_TYPE(DOUBLE, double); HANDLE_TYPE(FLOAT, float); HANDLE_TYPE(BOOL, bool); HANDLE_TYPE(STRING, std::string); HANDLE_TYPE(ENUM, int32_t); #undef HANDLE_TYPE case FieldDescriptor::CPPTYPE_MESSAGE: { const Message& message = default_entry_->GetReflection()->GetMessage(*default_entry_, val_des); Message* value = message.New(arena()); map_val->SetValue(value); break; } } } bool DynamicMapField::InsertOrLookupMapValueNoSync(const MapKey& map_key, MapValueRef* val) { Map::iterator iter = map_.find(map_key); if (iter == map_.end()) { MapValueRef& map_val = map_[map_key]; AllocateMapValue(&map_val); val->CopyFrom(map_val); return true; } // map_key is already in the map. Make sure (*map)[map_key] is not called. // [] may reorder the map and iterators. val->CopyFrom(iter->second); return false; } void DynamicMapField::MergeFrom(const MapFieldBase& other) { ABSL_DCHECK(IsMapValid() && other.IsMapValid()); Map* map = MutableMap(); const DynamicMapField& other_field = reinterpret_cast(other); for (Map::const_iterator other_it = other_field.map_.begin(); other_it != other_field.map_.end(); ++other_it) { Map::iterator iter = map->find(other_it->first); MapValueRef* map_val; if (iter == map->end()) { map_val = &map_[other_it->first]; AllocateMapValue(map_val); } else { map_val = &iter->second; } // Copy map value const FieldDescriptor* field_descriptor = default_entry_->GetDescriptor()->map_value(); switch (field_descriptor->cpp_type()) { case FieldDescriptor::CPPTYPE_INT32: { map_val->SetInt32Value(other_it->second.GetInt32Value()); break; } case FieldDescriptor::CPPTYPE_INT64: { map_val->SetInt64Value(other_it->second.GetInt64Value()); break; } case FieldDescriptor::CPPTYPE_UINT32: { map_val->SetUInt32Value(other_it->second.GetUInt32Value()); break; } case FieldDescriptor::CPPTYPE_UINT64: { map_val->SetUInt64Value(other_it->second.GetUInt64Value()); break; } case FieldDescriptor::CPPTYPE_FLOAT: { map_val->SetFloatValue(other_it->second.GetFloatValue()); break; } case FieldDescriptor::CPPTYPE_DOUBLE: { map_val->SetDoubleValue(other_it->second.GetDoubleValue()); break; } case FieldDescriptor::CPPTYPE_BOOL: { map_val->SetBoolValue(other_it->second.GetBoolValue()); break; } case FieldDescriptor::CPPTYPE_STRING: { map_val->SetStringValue(other_it->second.GetStringValue()); break; } case FieldDescriptor::CPPTYPE_ENUM: { map_val->SetEnumValue(other_it->second.GetEnumValue()); break; } case FieldDescriptor::CPPTYPE_MESSAGE: { map_val->MutableMessageValue()->CopyFrom( other_it->second.GetMessageValue()); break; } } } } const Message* DynamicMapField::GetPrototype() const { return default_entry_; } size_t DynamicMapField::SpaceUsedExcludingSelfNoLock() const { size_t size = 0; if (auto* p = maybe_payload()) { size += p->repeated_field.SpaceUsedExcludingSelfLong(); } size += sizeof(map_); size_t map_size = map_.size(); if (map_size) { Map::const_iterator it = map_.begin(); size += sizeof(it->first) * map_size; size += sizeof(it->second) * map_size; // If key is string, add the allocated space. if (it->first.type() == FieldDescriptor::CPPTYPE_STRING) { size += sizeof(std::string) * map_size; } // Add the allocated space in MapValueRef. switch (it->second.type()) { #define HANDLE_TYPE(CPPTYPE, TYPE) \ case FieldDescriptor::CPPTYPE_##CPPTYPE: { \ size += sizeof(TYPE) * map_size; \ break; \ } HANDLE_TYPE(INT32, int32_t); HANDLE_TYPE(INT64, int64_t); HANDLE_TYPE(UINT32, uint32_t); HANDLE_TYPE(UINT64, uint64_t); HANDLE_TYPE(DOUBLE, double); HANDLE_TYPE(FLOAT, float); HANDLE_TYPE(BOOL, bool); HANDLE_TYPE(STRING, std::string); HANDLE_TYPE(ENUM, int32_t); #undef HANDLE_TYPE case FieldDescriptor::CPPTYPE_MESSAGE: { while (it != map_.end()) { const Message& message = it->second.GetMessageValue(); size += message.GetReflection()->SpaceUsedLong(message); ++it; } break; } } } return size; } } // namespace internal } // namespace protobuf } // namespace google #include "google/protobuf/port_undef.inc"