#ifndef GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__
#define GOOGLE_PROTOBUF_MAP_ENTRY_LITE_H__
#include <assert.h>
#include <algorithm>
#include <string>
#include <utility>
#include <google/protobuf/stubs/casts.h>
#include <google/protobuf/io/coded_stream.h>
#include <google/protobuf/arena.h>
#include <google/protobuf/port.h>
#include <google/protobuf/arenastring.h>
#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/map.h>
#include <google/protobuf/map_type_handler.h>
#include <google/protobuf/parse_context.h>
#include <google/protobuf/wire_format_lite.h>
#include <google/protobuf/port_def.inc>
#ifdef SWIG
#error "You cannot SWIG proto headers"
#endif
namespace google {
namespace protobuf {
namespace internal {
template <typename Derived, typename Key, typename Value,
WireFormatLite::FieldType kKeyFieldType,
WireFormatLite::FieldType kValueFieldType>
class MapEntry;
template <typename Derived, typename Key, typename Value,
WireFormatLite::FieldType kKeyFieldType,
WireFormatLite::FieldType kValueFieldType>
class MapFieldLite;
} } }
namespace google {
namespace protobuf {
namespace internal {
template <bool is_enum, bool is_message, bool is_stringlike, typename T>
struct MoveHelper { static void Move(T* src, T* dest) { *dest = *src; }
};
template <bool is_message, bool is_stringlike, typename T>
struct MoveHelper<true, is_message, is_stringlike, T> { static void Move(T* src, T* dest) { *dest = *src; }
static void Move(T* src, int* dest) { *dest = static_cast<int>(*src); }
static void Move(int* src, T* dest) { *dest = static_cast<T>(*src); }
};
template <bool is_stringlike, typename T>
struct MoveHelper<false, true, is_stringlike, T> { static void Move(T* src, T* dest) { dest->Swap(src); }
};
template <typename T>
struct MoveHelper<false, false, true, T> { static void Move(T* src, T* dest) {
*dest = std::move(*src);
}
};
template <typename Derived, typename Base, typename Key, typename Value,
WireFormatLite::FieldType kKeyFieldType,
WireFormatLite::FieldType kValueFieldType>
class MapEntryImpl : public Base {
public:
typedef MapEntryFuncs<Key, Value, kKeyFieldType, kValueFieldType> Funcs;
protected:
typedef MapTypeHandler<kKeyFieldType, Key> KeyTypeHandler;
typedef MapTypeHandler<kValueFieldType, Value> ValueTypeHandler;
typedef typename KeyTypeHandler::TypeOnMemory KeyOnMemory;
typedef typename ValueTypeHandler::TypeOnMemory ValueOnMemory;
typedef typename KeyTypeHandler::MapEntryAccessorType KeyMapEntryAccessorType;
typedef
typename ValueTypeHandler::MapEntryAccessorType ValueMapEntryAccessorType;
static const int kKeyFieldNumber = 1;
static const int kValueFieldNumber = 2;
static const uint8_t kKeyTag =
GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(kKeyFieldNumber, KeyTypeHandler::kWireType);
static const uint8_t kValueTag = GOOGLE_PROTOBUF_WIRE_FORMAT_MAKE_TAG(
kValueFieldNumber, ValueTypeHandler::kWireType);
static const size_t kTagSize = 1;
public:
typedef void MapEntryHasMergeTypeTrait;
typedef Derived EntryType;
typedef Key EntryKeyType;
typedef Value EntryValueType;
static const WireFormatLite::FieldType kEntryKeyFieldType = kKeyFieldType;
static const WireFormatLite::FieldType kEntryValueFieldType = kValueFieldType;
constexpr MapEntryImpl()
: key_(KeyTypeHandler::Constinit()),
value_(ValueTypeHandler::Constinit()),
_has_bits_{} {}
explicit MapEntryImpl(Arena* arena)
: Base(arena),
key_(KeyTypeHandler::Constinit()),
value_(ValueTypeHandler::Constinit()),
_has_bits_{} {}
~MapEntryImpl() override {
if (Base::GetArenaForAllocation() != nullptr) return;
KeyTypeHandler::DeleteNoArena(key_);
ValueTypeHandler::DeleteNoArena(value_);
}
virtual inline const KeyMapEntryAccessorType& key() const {
return KeyTypeHandler::GetExternalReference(key_);
}
virtual inline const ValueMapEntryAccessorType& value() const {
return ValueTypeHandler::DefaultIfNotInitialized(value_);
}
inline KeyMapEntryAccessorType* mutable_key() {
set_has_key();
return KeyTypeHandler::EnsureMutable(&key_, Base::GetArenaForAllocation());
}
inline ValueMapEntryAccessorType* mutable_value() {
set_has_value();
return ValueTypeHandler::EnsureMutable(&value_,
Base::GetArenaForAllocation());
}
std::string GetTypeName() const override { return ""; }
void CheckTypeAndMergeFrom(const MessageLite& other) override {
MergeFromInternal(*::google::protobuf::internal::DownCast<const Derived*>(&other));
}
const char* _InternalParse(const char* ptr, ParseContext* ctx) final {
while (!ctx->Done(&ptr)) {
uint32_t tag;
ptr = ReadTag(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
if (tag == kKeyTag) {
set_has_key();
KeyMapEntryAccessorType* key = mutable_key();
ptr = KeyTypeHandler::Read(ptr, ctx, key);
if (!Derived::ValidateKey(key)) return nullptr;
} else if (tag == kValueTag) {
set_has_value();
ValueMapEntryAccessorType* value = mutable_value();
ptr = ValueTypeHandler::Read(ptr, ctx, value);
if (!Derived::ValidateValue(value)) return nullptr;
} else {
if (tag == 0 || WireFormatLite::GetTagWireType(tag) ==
WireFormatLite::WIRETYPE_END_GROUP) {
ctx->SetLastTag(tag);
return ptr;
}
ptr = UnknownFieldParse(tag, static_cast<std::string*>(nullptr), ptr,
ctx);
}
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
}
return ptr;
}
size_t ByteSizeLong() const override {
size_t size = 0;
size += kTagSize + static_cast<size_t>(KeyTypeHandler::ByteSize(key()));
size += kTagSize + static_cast<size_t>(ValueTypeHandler::ByteSize(value()));
return size;
}
::uint8_t* _InternalSerialize(
::uint8_t* ptr, io::EpsCopyOutputStream* stream) const override {
ptr = KeyTypeHandler::Write(kKeyFieldNumber, key(), ptr, stream);
return ValueTypeHandler::Write(kValueFieldNumber, value(), ptr, stream);
}
int GetCachedSize() const override {
int size = 0;
size += has_key() ? static_cast<int>(kTagSize) +
KeyTypeHandler::GetCachedSize(key())
: 0;
size += has_value() ? static_cast<int>(kTagSize) +
ValueTypeHandler::GetCachedSize(value())
: 0;
return size;
}
bool IsInitialized() const override {
return ValueTypeHandler::IsInitialized(value_);
}
Base* New(Arena* arena) const override {
Derived* entry = Arena::CreateMessage<Derived>(arena);
return entry;
}
protected:
void MergeFromInternal(const MapEntryImpl& from) {
if (from._has_bits_[0]) {
if (from.has_key()) {
KeyTypeHandler::EnsureMutable(&key_, Base::GetArenaForAllocation());
KeyTypeHandler::Merge(from.key(), &key_, Base::GetArenaForAllocation());
set_has_key();
}
if (from.has_value()) {
ValueTypeHandler::EnsureMutable(&value_, Base::GetArenaForAllocation());
ValueTypeHandler::Merge(from.value(), &value_,
Base::GetArenaForAllocation());
set_has_value();
}
}
}
public:
void Clear() override {
KeyTypeHandler::Clear(&key_, Base::GetArenaForAllocation());
ValueTypeHandler::Clear(&value_, Base::GetArenaForAllocation());
clear_has_key();
clear_has_value();
}
template <typename MapField, typename Map>
class Parser {
public:
explicit Parser(MapField* mf) : mf_(mf), map_(mf->MutableMap()) {}
~Parser() {
if (entry_ != nullptr && entry_->GetArenaForAllocation() == nullptr)
delete entry_;
}
const char* _InternalParse(const char* ptr, ParseContext* ctx) {
if (PROTOBUF_PREDICT_TRUE(!ctx->Done(&ptr) && *ptr == kKeyTag)) {
ptr = KeyTypeHandler::Read(ptr + 1, ctx, &key_);
if (PROTOBUF_PREDICT_FALSE(!ptr || !Derived::ValidateKey(&key_))) {
return nullptr;
}
if (PROTOBUF_PREDICT_TRUE(!ctx->Done(&ptr) && *ptr == kValueTag)) {
typename Map::size_type map_size = map_->size();
value_ptr_ = &(*map_)[key_];
if (PROTOBUF_PREDICT_TRUE(map_size != map_->size())) {
using T =
typename MapIf<ValueTypeHandler::kIsEnum, int*, Value*>::type;
ptr = ValueTypeHandler::Read(ptr + 1, ctx,
reinterpret_cast<T>(value_ptr_));
if (PROTOBUF_PREDICT_FALSE(!ptr ||
!Derived::ValidateValue(value_ptr_))) {
map_->erase(key_); return nullptr;
}
if (PROTOBUF_PREDICT_TRUE(ctx->Done(&ptr))) return ptr;
if (!ptr) return nullptr;
NewEntry();
ValueMover::Move(value_ptr_, entry_->mutable_value());
map_->erase(key_);
goto move_key;
}
} else {
if (!ptr) return nullptr;
}
NewEntry();
move_key:
KeyMover::Move(&key_, entry_->mutable_key());
} else {
if (!ptr) return nullptr;
NewEntry();
}
ptr = entry_->_InternalParse(ptr, ctx);
if (ptr) UseKeyAndValueFromEntry();
return ptr;
}
template <typename UnknownType>
const char* ParseWithEnumValidation(const char* ptr, ParseContext* ctx,
bool (*is_valid)(int),
uint32_t field_num,
InternalMetadata* metadata) {
auto entry = NewEntry();
ptr = entry->_InternalParse(ptr, ctx);
if (!ptr) return nullptr;
if (is_valid(entry->value())) {
UseKeyAndValueFromEntry();
} else {
WriteLengthDelimited(field_num, entry->SerializeAsString(),
metadata->mutable_unknown_fields<UnknownType>());
}
return ptr;
}
MapEntryImpl* NewEntry() { return entry_ = mf_->NewEntry(); }
const Key& key() const { return key_; }
const Value& value() const { return *value_ptr_; }
const Key& entry_key() const { return entry_->key(); }
const Value& entry_value() const { return entry_->value(); }
private:
void UseKeyAndValueFromEntry() {
key_ = entry_->key();
value_ptr_ = &(*map_)[key_];
ValueMover::Move(entry_->mutable_value(), value_ptr_);
}
bool ReadBeyondKeyValuePair(io::CodedInputStream* input) PROTOBUF_COLD {
NewEntry();
ValueMover::Move(value_ptr_, entry_->mutable_value());
map_->erase(key_);
KeyMover::Move(&key_, entry_->mutable_key());
const bool result = entry_->MergePartialFromCodedStream(input);
if (result) UseKeyAndValueFromEntry();
return result;
}
typedef MoveHelper<KeyTypeHandler::kIsEnum, KeyTypeHandler::kIsMessage,
KeyTypeHandler::kWireType ==
WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
Key>
KeyMover;
typedef MoveHelper<ValueTypeHandler::kIsEnum, ValueTypeHandler::kIsMessage,
ValueTypeHandler::kWireType ==
WireFormatLite::WIRETYPE_LENGTH_DELIMITED,
Value>
ValueMover;
MapField* const mf_;
Map* const map_;
Key key_;
Value* value_ptr_;
MapEntryImpl* entry_ = nullptr;
};
protected:
void set_has_key() { _has_bits_[0] |= 0x00000001u; }
bool has_key() const { return (_has_bits_[0] & 0x00000001u) != 0; }
void clear_has_key() { _has_bits_[0] &= ~0x00000001u; }
void set_has_value() { _has_bits_[0] |= 0x00000002u; }
bool has_value() const { return (_has_bits_[0] & 0x00000002u) != 0; }
void clear_has_value() { _has_bits_[0] &= ~0x00000002u; }
public:
inline Arena* GetArena() const { return Base::GetArena(); }
protected: KeyOnMemory key_;
ValueOnMemory value_;
uint32_t _has_bits_[1];
private:
friend class ::PROTOBUF_NAMESPACE_ID::Arena;
typedef void InternalArenaConstructable_;
typedef void DestructorSkippable_;
template <typename C, typename K, typename V, WireFormatLite::FieldType,
WireFormatLite::FieldType>
friend class internal::MapEntry;
template <typename C, typename K, typename V, WireFormatLite::FieldType,
WireFormatLite::FieldType>
friend class internal::MapFieldLite;
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapEntryImpl);
};
template <typename T, typename Key, typename Value,
WireFormatLite::FieldType kKeyFieldType,
WireFormatLite::FieldType kValueFieldType>
class MapEntryLite : public MapEntryImpl<T, MessageLite, Key, Value,
kKeyFieldType, kValueFieldType> {
public:
typedef MapEntryImpl<T, MessageLite, Key, Value, kKeyFieldType,
kValueFieldType>
SuperType;
constexpr MapEntryLite() {}
explicit MapEntryLite(Arena* arena) : SuperType(arena) {}
~MapEntryLite() override {
MessageLite::_internal_metadata_.template Delete<std::string>();
}
void MergeFrom(const MapEntryLite& other) { MergeFromInternal(other); }
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(MapEntryLite);
};
template <typename storage_type>
struct MapSorterIt {
storage_type* ptr;
MapSorterIt(storage_type* ptr) : ptr(ptr) {}
bool operator==(const MapSorterIt& other) const { return ptr == other.ptr; }
bool operator!=(const MapSorterIt& other) const { return !(*this == other); }
MapSorterIt& operator++() { ++ptr; return *this; }
MapSorterIt operator++(int) { auto other = *this; ++ptr; return other; }
MapSorterIt operator+(int v) { return MapSorterIt{ptr + v}; }
};
template <typename MapT>
class MapSorterFlat {
public:
using value_type = typename MapT::value_type;
using storage_type = std::pair<typename MapT::key_type, const value_type*>;
struct const_iterator : public MapSorterIt<storage_type> {
using pointer = const typename MapT::value_type*;
using reference = const typename MapT::value_type&;
using MapSorterIt<storage_type>::MapSorterIt;
pointer operator->() const { return this->ptr->second; }
reference operator*() const { return *this->operator->(); }
};
explicit MapSorterFlat(const MapT& m)
: size_(m.size()), items_(size_ ? new storage_type[size_] : nullptr) {
if (!size_) return;
storage_type* it = &items_[0];
for (const auto& entry : m) {
*it++ = {entry.first, &entry};
}
std::sort(&items_[0], &items_[size_],
[](const storage_type& a, const storage_type& b) {
return a.first < b.first;
});
}
size_t size() const { return size_; }
const_iterator begin() const { return {items_.get()}; }
const_iterator end() const { return {items_.get() + size_}; }
private:
size_t size_;
std::unique_ptr<storage_type[]> items_;
};
template <typename MapT>
class MapSorterPtr {
public:
using value_type = typename MapT::value_type;
using storage_type = const typename MapT::value_type*;
struct const_iterator : public MapSorterIt<storage_type> {
using pointer = const typename MapT::value_type*;
using reference = const typename MapT::value_type&;
using MapSorterIt<storage_type>::MapSorterIt;
pointer operator->() const { return *this->ptr; }
reference operator*() const { return *this->operator->(); }
};
explicit MapSorterPtr(const MapT& m)
: size_(m.size()), items_(size_ ? new storage_type[size_] : nullptr) {
if (!size_) return;
storage_type* it = &items_[0];
for (const auto& entry : m) {
*it++ = &entry;
}
std::sort(&items_[0], &items_[size_],
[](const storage_type& a, const storage_type& b) {
return a->first < b->first;
});
}
size_t size() const { return size_; }
const_iterator begin() const { return {items_.get()}; }
const_iterator end() const { return {items_.get() + size_}; }
private:
size_t size_;
std::unique_ptr<storage_type[]> items_;
};
} } }
#include <google/protobuf/port_undef.inc>
#endif