| // Protocol Buffers - Google's data interchange format |
| // Copyright 2008 Google Inc. All rights reserved. |
| // |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file or at |
| // https://developers.google.com/open-source/licenses/bsd |
| |
| #ifndef GOOGLE_PROTOBUF_MAP_FIELD_H__ |
| #define GOOGLE_PROTOBUF_MAP_FIELD_H__ |
| |
| #include <atomic> |
| #include <cstddef> |
| #include <cstdint> |
| #include <string> |
| #include <type_traits> |
| #include <utility> |
| |
| #include "absl/log/absl_check.h" |
| #include "absl/log/absl_log.h" |
| #include "absl/strings/string_view.h" |
| #include "absl/synchronization/mutex.h" |
| #include "google/protobuf/arena.h" |
| #include "google/protobuf/descriptor.h" |
| #include "google/protobuf/field_with_arena.h" |
| #include "google/protobuf/generated_message_reflection.h" |
| #include "google/protobuf/generated_message_util.h" |
| #include "google/protobuf/internal_visibility.h" |
| #include "google/protobuf/map.h" |
| #include "google/protobuf/map_type_handler.h" |
| #include "google/protobuf/message.h" |
| #include "google/protobuf/message_lite.h" |
| #include "google/protobuf/port.h" |
| #include "google/protobuf/repeated_field.h" |
| #include "google/protobuf/repeated_ptr_field.h" |
| #include "google/protobuf/unknown_field_set.h" |
| |
| |
| // Must be included last. |
| #include "google/protobuf/port_def.inc" |
| |
| #ifdef SWIG |
| #error "You cannot SWIG proto headers" |
| #endif |
| |
| namespace google { |
| namespace protobuf { |
| class DynamicMessage; |
| template <bool> |
| class MapIteratorBase; |
| class ConstMapIterator; |
| class MapIterator; |
| |
| namespace internal { |
| class MapFieldBase; |
| } |
| |
| // Microsoft compiler complains about non-virtual destructor, |
| // even when the destructor is private. |
| #ifdef _MSC_VER |
| #pragma warning(push) |
| #pragma warning(disable : 4265) |
| #endif // _MSC_VER |
| |
| #define TYPE_CHECK(EXPECTEDTYPE, METHOD) \ |
| if (type() != EXPECTEDTYPE) { \ |
| ABSL_LOG(FATAL) << "Protocol Buffer map usage error:\n" \ |
| << METHOD << " type does not match\n" \ |
| << " Expected : " \ |
| << FieldDescriptor::CppTypeName(EXPECTEDTYPE) << "\n" \ |
| << " Actual : " \ |
| << FieldDescriptor::CppTypeName(type()); \ |
| } |
| |
| // 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 { |
| public: |
| MapKey() = default; |
| MapKey(const MapKey&) = default; |
| MapKey& operator=(const MapKey&) = default; |
| |
| FieldDescriptor::CppType type() const { |
| if (type_ == FieldDescriptor::CppType()) { |
| ABSL_LOG(FATAL) << "Protocol Buffer map usage error:\n" |
| << "MapKey::type MapKey is not initialized. " |
| << "Call set methods to initialize MapKey."; |
| } |
| return type_; |
| } |
| |
| void SetInt64Value(int64_t value) { |
| SetType(FieldDescriptor::CPPTYPE_INT64); |
| val_.int64_value = value; |
| } |
| void SetUInt64Value(uint64_t value) { |
| SetType(FieldDescriptor::CPPTYPE_UINT64); |
| val_.uint64_value = value; |
| } |
| void SetInt32Value(int32_t value) { |
| SetType(FieldDescriptor::CPPTYPE_INT32); |
| val_.int32_value = value; |
| } |
| void SetUInt32Value(uint32_t value) { |
| SetType(FieldDescriptor::CPPTYPE_UINT32); |
| val_.uint32_value = value; |
| } |
| void SetBoolValue(bool value) { |
| SetType(FieldDescriptor::CPPTYPE_BOOL); |
| val_.bool_value = value; |
| } |
| void SetStringValue(absl::string_view val) { |
| SetType(FieldDescriptor::CPPTYPE_STRING); |
| val_.string_value = val; |
| } |
| |
| PROTOBUF_FUTURE_ADD_EARLY_NODISCARD int64_t GetInt64Value() const { |
| TYPE_CHECK(FieldDescriptor::CPPTYPE_INT64, "MapKey::GetInt64Value"); |
| return val_.int64_value; |
| } |
| PROTOBUF_FUTURE_ADD_EARLY_NODISCARD uint64_t GetUInt64Value() const { |
| TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT64, "MapKey::GetUInt64Value"); |
| return val_.uint64_value; |
| } |
| PROTOBUF_FUTURE_ADD_EARLY_NODISCARD int32_t GetInt32Value() const { |
| TYPE_CHECK(FieldDescriptor::CPPTYPE_INT32, "MapKey::GetInt32Value"); |
| return val_.int32_value; |
| } |
| PROTOBUF_FUTURE_ADD_EARLY_NODISCARD uint32_t GetUInt32Value() const { |
| TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT32, "MapKey::GetUInt32Value"); |
| return val_.uint32_value; |
| } |
| PROTOBUF_FUTURE_ADD_EARLY_NODISCARD bool GetBoolValue() const { |
| TYPE_CHECK(FieldDescriptor::CPPTYPE_BOOL, "MapKey::GetBoolValue"); |
| return val_.bool_value; |
| } |
| PROTOBUF_FUTURE_ADD_EARLY_NODISCARD absl::string_view GetStringValue() const { |
| TYPE_CHECK(FieldDescriptor::CPPTYPE_STRING, "MapKey::GetStringValue"); |
| return val_.string_value; |
| } |
| |
| PROTOBUF_FUTURE_ADD_EARLY_NODISCARD bool operator<( |
| const MapKey& other) const { |
| if (type_ != other.type_) { |
| // We could define a total order that handles this case, but |
| // there currently no need. So, for now, fail. |
| ABSL_LOG(FATAL) << "Unsupported: type mismatch"; |
| } |
| switch (type()) { |
| case FieldDescriptor::CPPTYPE_DOUBLE: |
| case FieldDescriptor::CPPTYPE_FLOAT: |
| case FieldDescriptor::CPPTYPE_ENUM: |
| case FieldDescriptor::CPPTYPE_MESSAGE: |
| ABSL_LOG(FATAL) << "Unsupported"; |
| return false; |
| case FieldDescriptor::CPPTYPE_STRING: |
| return val_.string_value < other.val_.string_value; |
| case FieldDescriptor::CPPTYPE_INT64: |
| return val_.int64_value < other.val_.int64_value; |
| case FieldDescriptor::CPPTYPE_INT32: |
| return val_.int32_value < other.val_.int32_value; |
| case FieldDescriptor::CPPTYPE_UINT64: |
| return val_.uint64_value < other.val_.uint64_value; |
| case FieldDescriptor::CPPTYPE_UINT32: |
| return val_.uint32_value < other.val_.uint32_value; |
| case FieldDescriptor::CPPTYPE_BOOL: |
| return val_.bool_value < other.val_.bool_value; |
| } |
| return false; |
| } |
| |
| PROTOBUF_FUTURE_ADD_EARLY_NODISCARD bool operator==( |
| const MapKey& other) const { |
| if (type_ != other.type_) { |
| // To be consistent with operator<, we don't allow this either. |
| ABSL_LOG(FATAL) << "Unsupported: type mismatch"; |
| } |
| switch (type()) { |
| case FieldDescriptor::CPPTYPE_DOUBLE: |
| case FieldDescriptor::CPPTYPE_FLOAT: |
| case FieldDescriptor::CPPTYPE_ENUM: |
| case FieldDescriptor::CPPTYPE_MESSAGE: |
| ABSL_LOG(FATAL) << "Unsupported"; |
| break; |
| case FieldDescriptor::CPPTYPE_STRING: |
| return val_.string_value == other.val_.string_value; |
| case FieldDescriptor::CPPTYPE_INT64: |
| return val_.int64_value == other.val_.int64_value; |
| case FieldDescriptor::CPPTYPE_INT32: |
| return val_.int32_value == other.val_.int32_value; |
| case FieldDescriptor::CPPTYPE_UINT64: |
| return val_.uint64_value == other.val_.uint64_value; |
| case FieldDescriptor::CPPTYPE_UINT32: |
| return val_.uint32_value == other.val_.uint32_value; |
| case FieldDescriptor::CPPTYPE_BOOL: |
| return val_.bool_value == other.val_.bool_value; |
| } |
| ABSL_LOG(FATAL) << "Can't get here."; |
| return false; |
| } |
| |
| void CopyFrom(const MapKey& other) { |
| SetType(other.type()); |
| switch (type_) { |
| case FieldDescriptor::CPPTYPE_DOUBLE: |
| case FieldDescriptor::CPPTYPE_FLOAT: |
| case FieldDescriptor::CPPTYPE_ENUM: |
| case FieldDescriptor::CPPTYPE_MESSAGE: |
| ABSL_LOG(FATAL) << "Unsupported"; |
| break; |
| case FieldDescriptor::CPPTYPE_STRING: |
| val_.string_value = other.val_.string_value; |
| break; |
| case FieldDescriptor::CPPTYPE_INT64: |
| val_.int64_value = other.val_.int64_value; |
| break; |
| case FieldDescriptor::CPPTYPE_INT32: |
| val_.int32_value = other.val_.int32_value; |
| break; |
| case FieldDescriptor::CPPTYPE_UINT64: |
| val_.uint64_value = other.val_.uint64_value; |
| break; |
| case FieldDescriptor::CPPTYPE_UINT32: |
| val_.uint32_value = other.val_.uint32_value; |
| break; |
| case FieldDescriptor::CPPTYPE_BOOL: |
| val_.bool_value = other.val_.bool_value; |
| break; |
| } |
| } |
| |
| private: |
| template <typename K, typename V> |
| friend class internal::TypeDefinedMapFieldBase; |
| friend class internal::MapFieldBase; |
| template <bool> |
| friend class MapIteratorBase; |
| |
| template <typename H> |
| friend auto AbslHashValue(H state, const MapKey& key) { |
| switch (key.type()) { |
| case FieldDescriptor::CPPTYPE_STRING: |
| return H::combine(std::move(state), key.GetStringValue()); |
| case FieldDescriptor::CPPTYPE_INT64: |
| return H::combine(std::move(state), key.GetInt64Value()); |
| case FieldDescriptor::CPPTYPE_INT32: |
| return H::combine(std::move(state), key.GetInt32Value()); |
| case FieldDescriptor::CPPTYPE_UINT64: |
| return H::combine(std::move(state), key.GetUInt64Value()); |
| case FieldDescriptor::CPPTYPE_UINT32: |
| return H::combine(std::move(state), key.GetUInt32Value()); |
| case FieldDescriptor::CPPTYPE_BOOL: |
| return H::combine(std::move(state), key.GetBoolValue()); |
| default: |
| internal::Unreachable(); |
| } |
| } |
| |
| union KeyValue { |
| KeyValue() {} |
| absl::string_view string_value; |
| int64_t int64_value; |
| int32_t int32_value; |
| uint64_t uint64_value; |
| uint32_t uint32_value; |
| bool bool_value; |
| } val_; |
| |
| void SetType(FieldDescriptor::CppType type) { type_ = type; } |
| |
| // type_ is 0 or a valid FieldDescriptor::CppType. |
| // Use "CppType()" to indicate zero. |
| FieldDescriptor::CppType type_ = FieldDescriptor::CppType(); |
| }; |
| |
| namespace internal { |
| |
| template <> |
| struct is_internal_map_key_type<MapKey> : std::true_type {}; |
| |
| } // namespace internal |
| |
| namespace internal { |
| |
| class ContendedMapCleanTest; |
| class GeneratedMessageReflection; |
| class MapFieldAccessor; |
| |
| template <typename MessageT> |
| struct MapDynamicFieldInfo; |
| struct MapFieldTestPeer; |
| |
| // Return the prototype message for a Map entry. |
| // REQUIRES: `default_entry` is a map entry message. |
| // REQUIRES: mapped_type is of type message. |
| inline const Message& GetMapEntryValuePrototype(const Message& default_entry) { |
| return default_entry.GetReflection()->GetMessage( |
| default_entry, default_entry.GetDescriptor()->map_value()); |
| } |
| |
| // This class provides access to map field using reflection, which is the same |
| // as those provided for RepeatedPtrField<Message>. It is used for internal |
| // reflection implementation only. Users should never use this directly. |
| class PROTOBUF_EXPORT MapFieldBase : public MapFieldBaseForParse { |
| public: |
| explicit constexpr MapFieldBase(const void* prototype_as_void) |
| : MapFieldBaseForParse(prototype_as_void) {} |
| explicit MapFieldBase(const Message* prototype) |
| : MapFieldBaseForParse(prototype) {} |
| MapFieldBase(const MapFieldBase&) = delete; |
| MapFieldBase& operator=(const MapFieldBase&) = delete; |
| |
| protected: |
| // "protected" stops users from deleting a `MapFieldBase *` |
| ~MapFieldBase(); |
| |
| public: |
| // Returns reference to internal repeated field. Data written using |
| // Map's api prior to calling this function is guarantted to be |
| // included in repeated field. |
| PROTOBUF_FUTURE_ADD_EARLY_NODISCARD const RepeatedPtrFieldBase& |
| GetRepeatedField() const; |
| |
| // Like above. Returns mutable pointer to the internal repeated field. |
| 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) |
| size_t SpaceUsedExcludingSelfLong() const; |
| |
| int SpaceUsedExcludingSelf() const { |
| return internal::ToIntSize(SpaceUsedExcludingSelfLong()); |
| } |
| |
| protected: |
| const Message* GetPrototype() const; |
| void ClearMapNoSync(); |
| |
| // Synchronizes the content in Map to RepeatedPtrField if there is any change |
| // to Map after last synchronization. |
| const RepeatedPtrFieldBase& SyncRepeatedFieldWithMap(bool for_mutation) const; |
| void SyncRepeatedFieldWithMapNoLock(); |
| |
| // Synchronizes the content in RepeatedPtrField to Map if there is any change |
| // to RepeatedPtrField after last synchronization. |
| void SyncMapWithRepeatedField() const; |
| void SyncMapWithRepeatedFieldNoLock(); |
| |
| static void SwapPayload(MapFieldBase& lhs, MapFieldBase& rhs); |
| |
| // Tells MapFieldBase that there is new change to Map. |
| void 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. |
| if (auto* p = maybe_payload()) { |
| // If we don't have a payload, it is already assumed `STATE_MODIFIED_MAP`. |
| p->set_state_relaxed(STATE_MODIFIED_MAP); |
| } |
| } |
| |
| // Tells MapFieldBase that there is new change to RepeatedPtrField. |
| void SetRepeatedDirty(); |
| |
| // 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 |
| // MapFieldBase-derived object, and there is no synchronization going |
| // on between them, tsan will alert. |
| void ConstAccess() const { GetMapRaw().ConstAccess(); } |
| void MutableAccess() { GetMapRaw().MutableAccess(); } |
| enum State { |
| STATE_MODIFIED_MAP = 0, // map has newly added data that has not been |
| // synchronized to repeated field |
| STATE_MODIFIED_REPEATED = 1, // repeated field has newly added data that |
| // has not been synchronized to map |
| CLEAN = 2, // data in map and repeated field are same |
| }; |
| |
| class ReflectionPayload { |
| public: |
| explicit ReflectionPayload(Arena* arena, const Message* prototype) |
| : repeated_field_(Arena::Create<RepeatedPtrField<Message>>(arena)), |
| prototype_(prototype) {} |
| ~ReflectionPayload() { |
| if (repeated_field_->GetArena() == nullptr) { |
| delete repeated_field_; |
| } |
| } |
| |
| RepeatedPtrField<Message>& repeated_field() { return *repeated_field_; } |
| |
| const Message* prototype() const { return prototype_; } |
| |
| absl::Mutex& mutex() { return mutex_; } |
| |
| State load_state_relaxed() const { |
| return state_.load(std::memory_order_relaxed); |
| } |
| State load_state_acquire() const { |
| return state_.load(std::memory_order_acquire); |
| } |
| void set_state_relaxed(State state) { |
| state_.store(state, std::memory_order_relaxed); |
| } |
| void set_state_release(State state) { |
| state_.store(state, std::memory_order_release); |
| } |
| |
| void Swap(ReflectionPayload& other); |
| |
| private: |
| RepeatedPtrField<Message>* repeated_field_; |
| const Message* prototype_; |
| absl::Mutex mutex_; // The thread to synchronize map and repeated |
| // field needs to get lock first; |
| std::atomic<State> state_{STATE_MODIFIED_MAP}; |
| }; |
| |
| Arena* arena() const { return GetMapRaw().arena(); } |
| |
| // Returns the reflection payload. Returns null if it does not exist yet. |
| ReflectionPayload* maybe_payload() const { |
| auto p = prototype_or_payload_.load(std::memory_order_acquire); |
| return IsPayload(p) ? ToPayload(p) : nullptr; |
| } |
| // Returns the reflection payload, and constructs one if does not exist yet. |
| ReflectionPayload& payload() const { |
| auto* p = maybe_payload(); |
| return p != nullptr ? *p : PayloadSlow(); |
| } |
| ReflectionPayload& PayloadSlow() const; |
| |
| State state() const { |
| auto* p = maybe_payload(); |
| return p != nullptr ? p->load_state_acquire() |
| // The default |
| : STATE_MODIFIED_MAP; |
| } |
| |
| private: |
| friend class ContendedMapCleanTest; |
| friend class GeneratedMessageReflection; |
| friend class MapFieldAccessor; |
| 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*>( |
| reinterpret_cast<uintptr_t>(p) - kHasPayloadBit); |
| PROTOBUF_ASSUME(res != nullptr); |
| return res; |
| } |
| static const void* ToTaggedPtr(ReflectionPayload* p) { |
| return reinterpret_cast<const void*>(reinterpret_cast<uintptr_t>(p) + |
| kHasPayloadBit); |
| } |
| }; |
| |
| // This class provides common Map Reflection implementations for generated |
| // message and dynamic message. |
| template <typename Key, typename T> |
| class TypeDefinedMapFieldBase : public MapFieldBase { |
| public: |
| #ifdef PROTOBUF_INTERNAL_REMOVE_ARENA_PTRS_MAP_FIELD |
| explicit constexpr TypeDefinedMapFieldBase(const void* prototype_as_void, |
| InternalMetadataOffset offset) |
| : MapFieldBase(prototype_as_void), |
| map_(offset.TranslateForMember<offsetof(TypeDefinedMapFieldBase, |
| map_)>()) { |
| // This invariant is required by `GetMapRaw` to easily access the map |
| // member without paying for dynamic dispatch. |
| static_assert(MapFieldBaseForParse::MapOffset() == |
| PROTOBUF_FIELD_OFFSET(TypeDefinedMapFieldBase, map_)); |
| } |
| #else |
| explicit constexpr TypeDefinedMapFieldBase(const void* prototype_as_void) |
| : MapFieldBase(prototype_as_void), map_() { |
| // This invariant is required by `GetMapRaw` to easily access the map |
| // member without paying for dynamic dispatch. |
| static_assert(MapFieldBaseForParse::MapOffset() == |
| PROTOBUF_FIELD_OFFSET(TypeDefinedMapFieldBase, map_)); |
| } |
| #endif |
| TypeDefinedMapFieldBase(const TypeDefinedMapFieldBase&) = delete; |
| TypeDefinedMapFieldBase& operator=(const TypeDefinedMapFieldBase&) = delete; |
| |
| #ifdef PROTOBUF_INTERNAL_REMOVE_ARENA_PTRS_MAP_FIELD |
| TypeDefinedMapFieldBase(const Message* prototype, |
| InternalMetadataOffset offset) |
| : MapFieldBase(prototype), |
| map_(offset.TranslateForMember<offsetof(TypeDefinedMapFieldBase, |
| map_)>()) {} |
| |
| TypeDefinedMapFieldBase(const Message* prototype, |
| InternalMetadataOffset offset, |
| const TypeDefinedMapFieldBase& from) |
| : MapFieldBase(prototype), |
| map_(offset |
| .TranslateForMember<offsetof(TypeDefinedMapFieldBase, map_)>(), |
| from.GetMap()) {} |
| #else |
| TypeDefinedMapFieldBase(const Message* prototype, Arena* arena) |
| : MapFieldBase(prototype), map_(arena) {} |
| |
| TypeDefinedMapFieldBase(const Message* prototype, Arena* arena, |
| const TypeDefinedMapFieldBase& from) |
| : MapFieldBase(prototype), map_(arena, from.GetMap()) {} |
| #endif |
| |
| protected: |
| ~TypeDefinedMapFieldBase() { map_.~Map(); } |
| |
| public: |
| const Map<Key, T>& GetMap() const { |
| SyncMapWithRepeatedField(); |
| return map_; |
| } |
| |
| Map<Key, T>* MutableMap() { |
| SyncMapWithRepeatedField(); |
| SetMapDirty(); |
| return &map_; |
| } |
| |
| // This overload is called from codegen, so we use templates for speed. |
| // If there is no codegen (eg optimize_for=CODE_SIZE), then only the |
| // reflection based one above will be used. |
| void MergeFrom(const TypeDefinedMapFieldBase& other) { |
| internal::MapMergeFrom(*MutableMap(), other.GetMap()); |
| } |
| |
| #ifndef PROTOBUF_INTERNAL_REMOVE_ARENA_PTRS_MAP_FIELD |
| static constexpr size_t InternalGetArenaOffset( |
| internal::InternalVisibility access) { |
| return PROTOBUF_FIELD_OFFSET(TypeDefinedMapFieldBase, map_) + |
| decltype(map_)::InternalGetArenaOffset(access); |
| } |
| #endif |
| |
| protected: |
| friend struct MapFieldTestPeer; |
| |
| using Iter = typename Map<Key, T>::const_iterator; |
| |
| // map_ is inside an anonymous union so we can explicitly control its |
| // destruction |
| union { |
| Map<Key, T> map_; |
| }; |
| }; |
| |
| // This class provides access to map field using generated api. It is used for |
| // internal generated message implementation only. Users should never use this |
| // directly. |
| template <typename Derived, typename Key, typename T> |
| class PROTOBUF_FUTURE_ADD_EARLY_WARN_UNUSED MapField final |
| : public TypeDefinedMapFieldBase<Key, T> { |
| public: |
| typedef Map<Key, T> MapType; |
| |
| #ifdef PROTOBUF_INTERNAL_REMOVE_ARENA_PTRS_MAP_FIELD |
| constexpr MapField() : MapField(InternalMetadataOffset()) {} |
| #else |
| constexpr MapField() |
| : MapField::TypeDefinedMapFieldBase( |
| Derived::internal_default_instance()) {} |
| #endif |
| MapField(const MapField&) = delete; |
| MapField& operator=(const MapField&) = delete; |
| ~MapField() = default; |
| |
| #ifdef PROTOBUF_INTERNAL_REMOVE_ARENA_PTRS_MAP_FIELD |
| constexpr MapField(ArenaInitialized, InternalMetadataOffset offset) |
| : MapField(offset) {} |
| constexpr MapField(InternalVisibility, InternalMetadataOffset offset) |
| : MapField(offset) {} |
| MapField(InternalVisibility, InternalMetadataOffset offset, |
| const MapField& from) |
| : TypeDefinedMapFieldBase<Key, T>( |
| static_cast<const Message*>(Derived::internal_default_instance()), |
| offset, from) {} |
| #else |
| explicit MapField(Arena* arena) |
| : TypeDefinedMapFieldBase<Key, T>( |
| static_cast<const Message*>(Derived::internal_default_instance()), |
| arena) {} |
| MapField(ArenaInitialized, Arena* arena) : MapField(arena) {} |
| MapField(InternalVisibility, Arena* arena) : MapField(arena) {} |
| MapField(InternalVisibility, Arena* arena, const MapField& from) |
| : TypeDefinedMapFieldBase<Key, T>( |
| static_cast<const Message*>(Derived::internal_default_instance()), |
| arena, from) {} |
| #endif |
| |
| private: |
| #ifdef PROTOBUF_INTERNAL_REMOVE_ARENA_PTRS_MAP_FIELD |
| explicit constexpr MapField(InternalMetadataOffset offset) |
| : MapField::TypeDefinedMapFieldBase(Derived::internal_default_instance(), |
| offset) {} |
| #endif |
| |
| typedef void InternalArenaConstructable_; |
| typedef void DestructorSkippable_; |
| |
| friend class google::protobuf::Arena; |
| friend class google::protobuf::internal::FieldWithArena<MapField>; |
| friend class MapFieldBase; |
| friend class MapFieldStateTest; // For testing, it needs raw access to impl_ |
| }; |
| |
| template <typename Key, typename T> |
| bool AllAreInitialized(const TypeDefinedMapFieldBase<Key, T>& field) { |
| for (const auto& p : field.GetMap()) { |
| if (!p.second.IsInitialized()) return false; |
| } |
| return true; |
| } |
| |
| #ifdef PROTOBUF_INTERNAL_REMOVE_ARENA_PTRS_MAP_FIELD |
| template <typename Derived, typename Key, typename T> |
| using MapFieldWithArena = FieldWithArena<MapField<Derived, Key, T>>; |
| |
| template <typename Derived, typename Key, typename T> |
| struct FieldArenaRep<MapField<Derived, Key, T>> { |
| using Type = MapFieldWithArena<Derived, Key, T>; |
| |
| static inline MapField<Derived, Key, T>* Get(Type* arena_rep) { |
| return &arena_rep->field(); |
| } |
| }; |
| |
| template <typename Derived, typename Key, typename T> |
| struct FieldArenaRep<const MapField<Derived, Key, T>> { |
| using Type = const MapFieldWithArena<Derived, Key, T>; |
| |
| static inline const MapField<Derived, Key, T>* Get(Type* arena_rep) { |
| return &arena_rep->field(); |
| } |
| }; |
| #endif // PROTOBUF_INTERNAL_REMOVE_ARENA_PTRS_MAP_FIELD |
| |
| } // namespace internal |
| |
| // MapValueConstRef points to a map value. Users can NOT modify |
| // the map value. |
| class PROTOBUF_EXPORT MapValueConstRef { |
| public: |
| MapValueConstRef() : data_(nullptr), type_() {} |
| |
| int64_t GetInt64Value() const { |
| TYPE_CHECK(FieldDescriptor::CPPTYPE_INT64, |
| "MapValueConstRef::GetInt64Value"); |
| return *reinterpret_cast<int64_t*>(data_); |
| } |
| uint64_t GetUInt64Value() const { |
| TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT64, |
| "MapValueConstRef::GetUInt64Value"); |
| return *reinterpret_cast<uint64_t*>(data_); |
| } |
| int32_t GetInt32Value() const { |
| TYPE_CHECK(FieldDescriptor::CPPTYPE_INT32, |
| "MapValueConstRef::GetInt32Value"); |
| return *reinterpret_cast<int32_t*>(data_); |
| } |
| uint32_t GetUInt32Value() const { |
| TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT32, |
| "MapValueConstRef::GetUInt32Value"); |
| return *reinterpret_cast<uint32_t*>(data_); |
| } |
| bool GetBoolValue() const { |
| TYPE_CHECK(FieldDescriptor::CPPTYPE_BOOL, "MapValueConstRef::GetBoolValue"); |
| return *reinterpret_cast<bool*>(data_); |
| } |
| int GetEnumValue() const { |
| TYPE_CHECK(FieldDescriptor::CPPTYPE_ENUM, "MapValueConstRef::GetEnumValue"); |
| return *reinterpret_cast<int*>(data_); |
| } |
| absl::string_view GetStringValue() const { |
| TYPE_CHECK(FieldDescriptor::CPPTYPE_STRING, |
| "MapValueConstRef::GetStringValue"); |
| return absl::string_view(*reinterpret_cast<std::string*>(data_)); |
| } |
| float GetFloatValue() const { |
| TYPE_CHECK(FieldDescriptor::CPPTYPE_FLOAT, |
| "MapValueConstRef::GetFloatValue"); |
| return *reinterpret_cast<float*>(data_); |
| } |
| double GetDoubleValue() const { |
| TYPE_CHECK(FieldDescriptor::CPPTYPE_DOUBLE, |
| "MapValueConstRef::GetDoubleValue"); |
| return *reinterpret_cast<double*>(data_); |
| } |
| |
| const Message& GetMessageValue() const { |
| TYPE_CHECK(FieldDescriptor::CPPTYPE_MESSAGE, |
| "MapValueConstRef::GetMessageValue"); |
| return *reinterpret_cast<Message*>(data_); |
| } |
| |
| FieldDescriptor::CppType type() const { |
| if (type_ == FieldDescriptor::CppType() || data_ == nullptr) { |
| ABSL_LOG(FATAL) |
| << "Protocol Buffer map usage error:\n" |
| << "MapValueConstRef::type MapValueConstRef is not initialized."; |
| } |
| return type_; |
| } |
| |
| protected: |
| // 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 <typename Derived, 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_; |
| } |
| }; |
| |
| // MapValueRef points to a map value. Users are able to modify |
| // the map value. |
| class PROTOBUF_EXPORT MapValueRef final : public MapValueConstRef { |
| public: |
| MapValueRef() = default; |
| |
| void SetInt64Value(int64_t value) { |
| TYPE_CHECK(FieldDescriptor::CPPTYPE_INT64, "MapValueRef::SetInt64Value"); |
| *reinterpret_cast<int64_t*>(data_) = value; |
| } |
| void SetUInt64Value(uint64_t value) { |
| TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT64, "MapValueRef::SetUInt64Value"); |
| *reinterpret_cast<uint64_t*>(data_) = value; |
| } |
| void SetInt32Value(int32_t value) { |
| TYPE_CHECK(FieldDescriptor::CPPTYPE_INT32, "MapValueRef::SetInt32Value"); |
| *reinterpret_cast<int32_t*>(data_) = value; |
| } |
| void SetUInt32Value(uint32_t value) { |
| TYPE_CHECK(FieldDescriptor::CPPTYPE_UINT32, "MapValueRef::SetUInt32Value"); |
| *reinterpret_cast<uint32_t*>(data_) = value; |
| } |
| void SetBoolValue(bool value) { |
| TYPE_CHECK(FieldDescriptor::CPPTYPE_BOOL, "MapValueRef::SetBoolValue"); |
| *reinterpret_cast<bool*>(data_) = value; |
| } |
| // TODO - Checks that enum is member. |
| void SetEnumValue(int value) { |
| TYPE_CHECK(FieldDescriptor::CPPTYPE_ENUM, "MapValueRef::SetEnumValue"); |
| *reinterpret_cast<int*>(data_) = value; |
| } |
| void SetStringValue(absl::string_view value) { |
| TYPE_CHECK(FieldDescriptor::CPPTYPE_STRING, "MapValueRef::SetStringValue"); |
| reinterpret_cast<std::string*>(data_)->assign(value.data(), value.size()); |
| } |
| void SetFloatValue(float value) { |
| TYPE_CHECK(FieldDescriptor::CPPTYPE_FLOAT, "MapValueRef::SetFloatValue"); |
| *reinterpret_cast<float*>(data_) = value; |
| } |
| void SetDoubleValue(double value) { |
| TYPE_CHECK(FieldDescriptor::CPPTYPE_DOUBLE, "MapValueRef::SetDoubleValue"); |
| *reinterpret_cast<double*>(data_) = value; |
| } |
| |
| Message* MutableMessageValue() { |
| TYPE_CHECK(FieldDescriptor::CPPTYPE_MESSAGE, |
| "MapValueRef::MutableMessageValue"); |
| return reinterpret_cast<Message*>(data_); |
| } |
| }; |
| |
| #undef TYPE_CHECK |
| |
| template <bool kIsMutable> |
| class PROTOBUF_EXPORT 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>; |
| |
| public: |
| MapIteratorBase(MessageT* message, const FieldDescriptor* field); |
| MapIteratorBase(const MapIteratorBase& other) { *this = other; } |
| |
| MapIteratorBase& operator=(const MapIteratorBase& other); |
| |
| bool operator==(const MapIteratorBase& other) const; |
| friend bool operator!=(const MapIteratorBase& a, const MapIteratorBase& 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 <typename Derived, 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 MapIteratorBase</*kIsMutable=*/false>; |
| extern template class 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) {} |
| }; |
| |
| 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 |
| |
| } // namespace protobuf |
| } // namespace google |
| |
| #ifdef _MSC_VER |
| #pragma warning(pop) // restore warning C4265 |
| #endif // _MSC_VER |
| |
| #include "google/protobuf/port_undef.inc" |
| |
| #endif // GOOGLE_PROTOBUF_MAP_FIELD_H__ |