blob: f6d6db3680b74c5360821aa1c712c1fdc4429fe1 [file] [edit]
// 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 <iterator>
#include <string>
#include <type_traits>
#include <utility>
#include "absl/base/attributes.h"
#include "absl/log/absl_check.h"
#include "absl/log/absl_log.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include "absl/synchronization/mutex.h"
#include "google/protobuf/arena.h"
#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;
namespace internal {
class ABSL_ATTRIBUTE_VIEW MapConstIterator;
class ABSL_ATTRIBUTE_VIEW MapConstIteratorEntry;
class ABSL_ATTRIBUTE_VIEW MapIterator;
class ABSL_ATTRIBUTE_VIEW MapIteratorEntry;
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 ABSL_ATTRIBUTE_VIEW MapKey {
public:
MapKey() = default;
MapKey(const MapKey&) = default;
MapKey& operator=(const MapKey&) = default;
bool is_initialized() const { return type_ != FieldDescriptor::CppType(); }
FieldDescriptor::CppType type() const {
if (type_ == FieldDescriptor::CppType()) {
ABSL_LOG(FATAL) << "Protocol Buffer map usage error:\n"
<< "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;
friend internal::MapConstIteratorEntry;
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());
case FieldDescriptor::CPPTYPE_DOUBLE:
case FieldDescriptor::CPPTYPE_FLOAT:
case FieldDescriptor::CPPTYPE_ENUM:
case FieldDescriptor::CPPTYPE_MESSAGE:
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 {
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* globals_as_void)
: MapFieldBaseForParse(globals_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:
// Same as the base class, but without the dynamic dispatch.
const UntypedMapBase& GetMap() const {
SyncMapWithRepeatedField();
return GetMapRaw();
}
UntypedMapBase* MutableMap() {
SyncMapWithRepeatedField();
SetMapDirty();
return &GetMapRaw();
}
// 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();
// 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;
void MergeFrom(Arena* arena, const MapFieldBase& other);
void Swap(Arena* arena, MapFieldBase* other, Arena* other_arena);
void InternalSwap(MapFieldBase* other);
void Clear();
// 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;
// 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 = globals_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;
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:
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_));
}
TypeDefinedMapFieldBase(const TypeDefinedMapFieldBase&) = delete;
TypeDefinedMapFieldBase& operator=(const TypeDefinedMapFieldBase&) = delete;
TypeDefinedMapFieldBase(const Message* prototype,
InternalMetadataOffset offset)
: MapFieldBase(prototype),
map_(offset.TranslateForMember<offsetof(TypeDefinedMapFieldBase,
map_)>()) {}
TypeDefinedMapFieldBase(const Message* prototype,
InternalMetadataOffset offset, Arena* arena,
const TypeDefinedMapFieldBase& from)
: MapFieldBase(prototype),
map_(offset
.TranslateForMember<offsetof(TypeDefinedMapFieldBase, map_)>(),
arena, from.GetMap()) {}
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());
}
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 <auto* kGlobals, typename Key, typename T>
class PROTOBUF_FUTURE_ADD_EARLY_WARN_UNUSED MapField final
: public TypeDefinedMapFieldBase<Key, T> {
public:
typedef Map<Key, T> MapType;
constexpr MapField() : MapField(InternalMetadataOffset()) {}
MapField(const MapField&) = delete;
MapField& operator=(const MapField&) = delete;
~MapField() = default;
constexpr MapField(ArenaInitialized, InternalMetadataOffset offset)
: MapField(offset) {}
constexpr MapField(InternalVisibility, InternalMetadataOffset offset)
: MapField(offset) {}
MapField(InternalVisibility, InternalMetadataOffset offset, Arena* arena,
const MapField& from)
: TypeDefinedMapFieldBase<Key, T>(
MessageGlobalsBase::ToDefaultInstance<Message>(kGlobals), offset,
arena, from) {}
private:
explicit constexpr MapField(InternalMetadataOffset offset)
: MapField::TypeDefinedMapFieldBase(kGlobals, offset) {}
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;
}
template <auto* kGlobals, typename Key, typename T>
using MapFieldWithArena = FieldWithArena<MapField<kGlobals, Key, T>>;
// We don't use `auto* globals` here because GCC fails to deduce the
// specialization.
template <typename Globals, const Globals* kGlobals, typename Key, typename T>
struct FieldArenaRep<MapField<kGlobals, Key, T>> {
using Type = MapFieldWithArena<kGlobals, Key, T>;
static MapField<kGlobals, Key, T>* Get(Type* arena_rep) {
return &arena_rep->field();
}
};
template <typename Globals, const Globals* kGlobals, typename Key, typename T>
struct FieldArenaRep<const MapField<kGlobals, Key, T>> {
using Type = const MapFieldWithArena<kGlobals, Key, T>;
static const MapField<kGlobals, Key, T>* Get(Type* arena_rep) {
return &arena_rep->field();
}
};
} // namespace internal
// MapValueConstRef points to a map value. Users can NOT modify
// the map value.
class PROTOBUF_EXPORT ABSL_ATTRIBUTE_VIEW 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:
friend internal::MapConstIteratorEntry;
friend internal::MapIteratorEntry;
void SetType(FieldDescriptor::CppType type) { type_ = type; }
void SetValue(const void* val) {
ABSL_DCHECK_NE(static_cast<int>(type_), 0);
data_ = const_cast<void*>(val);
}
// data_ point to a map value. MapValueConstRef does not
// own this value.
void* data_;
// type_ is 0 or a valid FieldDescriptor::CppType.
// Use "CppType()" to indicate zero.
FieldDescriptor::CppType type_{};
};
// MapValueRef points to a map value. Users are able to modify
// the map value.
class PROTOBUF_EXPORT ABSL_ATTRIBUTE_VIEW 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_);
}
private:
friend internal::MapIteratorEntry;
};
#undef TYPE_CHECK
namespace internal {
class PROTOBUF_EXPORT ABSL_ATTRIBUTE_VIEW MapIteratorEntry final {
public:
using key_type = MapKey;
using mapped_type = MapValueRef;
MapIteratorEntry(const MapIteratorEntry&) = default;
MapIteratorEntry& operator=(const MapIteratorEntry&) = default;
MapKey key() const;
MapValueRef value() const;
private:
friend MapIterator;
friend MapConstIteratorEntry;
MapIteratorEntry() = default;
uint8_t key_type_{};
uint8_t value_type_{};
internal::UntypedMapIterator iter_{};
};
class PROTOBUF_EXPORT ABSL_ATTRIBUTE_VIEW MapIterator final {
public:
using iterator_category = std::input_iterator_tag;
using iterator_concept = std::forward_iterator_tag;
using value_type = MapIteratorEntry;
using difference_type = ptrdiff_t;
using pointer = const value_type*;
using reference = value_type;
using key_type = value_type::key_type;
using mapped_type = value_type::mapped_type;
MapIterator() = default;
MapIterator(const MapIterator&) = default;
MapIterator& operator=(const MapIterator&) = default;
value_type operator*() const {
ABSL_CHECK(!iter_.Equals(internal::UntypedMapBase::EndIterator()))
<< "Can't deref the end iterator";
value_type res;
res.key_type_ = key_type_;
res.value_type_ = value_type_;
res.iter_ = iter_;
return res;
}
auto operator->() const {
struct ABSL_ATTRIBUTE_VIEW ArrowProxy {
value_type value;
const value_type* operator->() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
return &value;
}
};
return ArrowProxy{**this};
}
MapIterator& operator++() {
iter_.PlusPlus();
return *this;
}
MapIterator operator++(int) {
auto copy = *this;
iter_.PlusPlus();
return copy;
}
friend bool operator==(MapIterator a, MapIterator b) {
return a.iter_.Equals(b.iter_);
}
friend bool operator!=(MapIterator a, MapIterator b) { return !(a == b); }
private:
friend GenericMapRef;
friend MapConstIterator;
uint8_t key_type_{};
uint8_t value_type_{};
internal::UntypedMapIterator iter_{};
};
class PROTOBUF_EXPORT ABSL_ATTRIBUTE_VIEW MapConstIteratorEntry final {
public:
using key_type = MapKey;
using mapped_type = MapValueConstRef;
MapConstIteratorEntry(const MapConstIteratorEntry&) = default;
MapConstIteratorEntry& operator=(const MapConstIteratorEntry&) = default;
MapConstIteratorEntry(const MapIteratorEntry& entry) // NOLINT
: key_type_(entry.key_type_),
value_type_(entry.value_type_),
iter_(entry.iter_) {}
MapKey key() const;
MapValueConstRef value() const;
private:
friend MapConstIterator;
MapConstIteratorEntry() = default;
uint8_t key_type_{};
uint8_t value_type_{};
internal::UntypedMapIterator iter_{};
};
class PROTOBUF_EXPORT ABSL_ATTRIBUTE_VIEW MapConstIterator final {
public:
using iterator_category = std::input_iterator_tag;
using iterator_concept = std::forward_iterator_tag;
using value_type = MapConstIteratorEntry;
using difference_type = ptrdiff_t;
using pointer = const value_type*;
using reference = value_type;
using key_type = value_type::key_type;
using mapped_type = value_type::mapped_type;
MapConstIterator() = default;
MapConstIterator(const MapConstIterator&) = default;
MapConstIterator& operator=(const MapConstIterator&) = default;
MapConstIterator(MapIterator it) // NOLINT
: key_type_(it.key_type_), value_type_(it.value_type_), iter_(it.iter_) {}
value_type operator*() const {
ABSL_CHECK(!iter_.Equals(internal::UntypedMapBase::EndIterator()))
<< "Can't deref the end iterator";
value_type res;
res.key_type_ = key_type_;
res.value_type_ = value_type_;
res.iter_ = iter_;
return res;
}
auto operator->() const {
struct ABSL_ATTRIBUTE_VIEW ArrowProxy {
value_type value;
const value_type* operator->() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
return &value;
}
};
return ArrowProxy{**this};
}
MapConstIterator& operator++() {
iter_.PlusPlus();
return *this;
}
MapConstIterator operator++(int) {
auto copy = *this;
iter_.PlusPlus();
return copy;
}
friend bool operator==(MapConstIterator a, MapConstIterator b) {
return a.iter_.Equals(b.iter_);
}
friend bool operator!=(MapConstIterator a, MapConstIterator b) {
return !(a == b);
}
private:
friend GenericConstMapRef;
friend GenericMapRef;
friend internal::MapFieldBase;
uint8_t key_type_{};
uint8_t value_type_{};
internal::UntypedMapIterator iter_{};
};
} // namespace internal
class PROTOBUF_EXPORT ABSL_ATTRIBUTE_VIEW GenericMapRef final {
public:
using iterator = internal::MapIterator;
using const_iterator = internal::MapConstIterator;
using value_type = iterator::value_type;
using key_type = iterator::key_type;
using mapped_type = iterator::mapped_type;
GenericMapRef(const GenericMapRef&) = default;
// Deleted to prevent confusion as to whether the assignment is shallow or
// deep.
GenericMapRef& operator=(const GenericMapRef&) = delete;
iterator begin() const;
iterator end() const;
size_t size() const;
bool empty() const;
bool contains(const MapKey& key) const;
iterator find(const MapKey& key) const;
void clear() const;
size_t erase(const MapKey& key) const;
// These perform the operation on the underlying instances.
// They do not alter the handles themselves.
absl::Status assign(const GenericConstMapRef& other) const;
absl::Status swap(const GenericMapRef& other) const;
struct PROTOBUF_EXPORT ABSL_ATTRIBUTE_VIEW InsertResult {
internal::MapIterator iter;
bool inserted;
};
absl::StatusOr<InsertResult> try_emplace(const MapKey& key) const;
private:
friend Reflection;
friend internal::MapFieldBase;
friend GenericConstMapRef;
GenericMapRef() = default;
template <typename T, typename... U>
void InitializeKeyValue(T* v, const U&... init) const {
::new (static_cast<void*>(v)) T(init...);
if constexpr (std::is_same_v<std::string, T>) {
if (auto* a = map_->arena()) {
a->OwnDestructor(v);
}
}
}
void InitializeKeyValue(MessageLite* msg) const {
value_class_data_->PlacementNew(msg, map_->arena());
}
uint8_t key_type_{};
uint8_t value_type_{};
internal::UntypedMapBase* map_ = nullptr;
const internal::ClassData* value_class_data_ = nullptr;
};
class PROTOBUF_EXPORT ABSL_ATTRIBUTE_VIEW GenericConstMapRef final {
public:
using iterator = internal::MapConstIterator;
using const_iterator = iterator;
using value_type = iterator::value_type;
using key_type = iterator::key_type;
using mapped_type = iterator::mapped_type;
GenericConstMapRef(const GenericConstMapRef&) = default;
GenericConstMapRef& operator=(const GenericConstMapRef&) = default;
GenericConstMapRef(const GenericMapRef& mut) // NOLINT
: key_type_(mut.key_type_),
value_type_(mut.value_type_),
map_(mut.map_),
value_class_data_(mut.value_class_data_) {}
iterator begin() const;
iterator end() const;
size_t size() const;
bool empty() const;
bool contains(const MapKey& key) const;
iterator find(const MapKey& key) const;
private:
friend Reflection;
friend GenericMapRef;
GenericConstMapRef() = default;
static absl::Status CheckSameType(const GenericConstMapRef& a,
const GenericConstMapRef& b);
uint8_t key_type_{};
uint8_t value_type_{};
const internal::UntypedMapBase* map_ = nullptr;
const internal::ClassData* value_class_data_ = nullptr;
};
// This class was never part of any public API (even though it was mistakenly
// put in the public namespace).
// We are replacing the old internal map reflection API with the new public one
// and this class is going away. It is here for now to support the migration of
// a friend project that is using the internal API.
class [[deprecated(
"Legacy internal class. Use Reflection::GetMap instead.")]] PROTOBUF_EXPORT
ConstMapIterator final {
public:
MapKey GetKey() const { return it_->key(); }
MapValueConstRef GetValueRef() const { return it_->value(); }
ConstMapIterator& operator++() {
++it_;
return *this;
}
PROTOBUF_IGNORE_DEPRECATION_START
friend bool operator==(ConstMapIterator a, ConstMapIterator b) {
return a.it_ == b.it_;
}
friend bool operator!=(ConstMapIterator a, ConstMapIterator b) {
return a.it_ != b.it_;
}
PROTOBUF_IGNORE_DEPRECATION_STOP
private:
friend Reflection;
ConstMapIterator() = default;
ConstMapIterator(internal::MapConstIterator it) : it_(it) {} // NOLINT
internal::MapConstIterator it_;
};
// Expose this feature macro to users to let them know that the map reflection
// API exists.
#define PROTOBUF_HAS_MAP_REFLECTION_APIS 1
} // namespace protobuf
} // namespace google
#ifdef _MSC_VER
#pragma warning(pop) // restore warning C4265
#endif // _MSC_VER
#include "google/protobuf/port_undef.inc"
#endif // GOOGLE_PROTOBUF_MAP_FIELD_H__