Remove some function overrides from MapEntry and use the ones from Message.

This saves on binary size.
Plus, some other minor fixes to make the object more like normal codegen'd types.

PiperOrigin-RevId: 567705458
pull/14187/head
Protobuf Team Bot 1 year ago committed by Copybara-Service
parent c50e89217d
commit 996268a345
  1. 8
      src/google/protobuf/compiler/cpp/message.cc
  2. 94
      src/google/protobuf/map_entry.h
  3. 9
      src/google/protobuf/map_test.inc
  4. 172
      src/google/protobuf/map_type_handler.h
  5. 1
      src/google/protobuf/message_unittest.inc

@ -1157,7 +1157,6 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* p) {
explicit PROTOBUF_CONSTEXPR $classname$(
::$proto_ns$::internal::ConstantInitialized);
explicit $classname$(::$proto_ns$::Arena* arena);
void MergeFrom(const $classname$& other);
static const $classname$* internal_default_instance() {
return reinterpret_cast<const $classname$*>(
&_$classname$_default_instance_);
@ -1226,8 +1225,6 @@ void MessageGenerator::GenerateClassDefinition(io::Printer* p) {
}
if (HasDescriptorMethods(descriptor_->file(), options_)) {
format(
" using ::$proto_ns$::Message::MergeFrom;\n"
""
" ::$proto_ns$::Metadata GetMetadata() const final;\n");
}
format(
@ -1932,10 +1929,7 @@ void MessageGenerator::GenerateClassMethods(io::Printer* p) {
format(
"$classname$::$classname$() {}\n"
"$classname$::$classname$(::$proto_ns$::Arena* arena)\n"
" : SuperType(arena) {}\n"
"void $classname$::MergeFrom(const $classname$& other) {\n"
" MergeFromInternal(other);\n"
"}\n");
" : SuperType(arena) {}\n");
if (HasDescriptorMethods(descriptor_->file(), options_)) {
if (!descriptor_->options().map_entry()) {
format(

@ -13,12 +13,11 @@
#include <string>
#include "google/protobuf/generated_message_reflection.h"
#include "google/protobuf/has_bits.h"
#include "google/protobuf/map_type_handler.h"
#include "google/protobuf/message.h"
#include "google/protobuf/message_lite.h"
#include "google/protobuf/parse_context.h"
#include "google/protobuf/port.h"
#include "google/protobuf/reflection_ops.h"
#include "google/protobuf/unknown_field_set.h"
#include "google/protobuf/wire_format_lite.h"
@ -85,12 +84,6 @@ class MapEntry : public Message {
using KeyOnMemory = typename KeyTypeHandler::TypeOnMemory;
using ValueOnMemory = typename ValueTypeHandler::TypeOnMemory;
// Enum type cannot be used for MapTypeHandler::Read. Define a type
// which will replace Enum with int.
using KeyMapEntryAccessorType = typename KeyTypeHandler::MapEntryAccessorType;
using ValueMapEntryAccessorType =
typename ValueTypeHandler::MapEntryAccessorType;
// Constants for field number.
static const int kKeyFieldNumber = 1;
static const int kValueFieldNumber = 2;
@ -129,37 +122,26 @@ class MapEntry : public Message {
// accessors ======================================================
inline const KeyMapEntryAccessorType& key() const {
inline const auto& key() const {
return KeyTypeHandler::GetExternalReference(key_);
}
inline const ValueMapEntryAccessorType& value() const {
inline const auto& value() const {
return ValueTypeHandler::DefaultIfNotInitialized(value_);
}
inline KeyMapEntryAccessorType* mutable_key() {
set_has_key();
inline auto* mutable_key() {
_has_bits_[0] |= 0x00000001u;
return KeyTypeHandler::EnsureMutable(&key_, GetArenaForAllocation());
}
inline ValueMapEntryAccessorType* mutable_value() {
set_has_value();
inline auto* mutable_value() {
_has_bits_[0] |= 0x00000002u;
return ValueTypeHandler::EnsureMutable(&value_, GetArenaForAllocation());
}
// implements MessageLite =========================================
// MapEntry is for implementation only and this function isn't called
// anywhere. Just provide a fake implementation here for MessageLite.
std::string GetTypeName() const override { return ""; }
// TODO: These methods currently differ in behavior from the ones
// implemented via reflection. This means that a MapEntry does not behave the
// same as an equivalent object made via DynamicMessage.
size_t SpaceUsedLong() const final {
size_t size = sizeof(Derived);
size += KeyTypeHandler::SpaceUsedInMapEntryLong(this->key_);
size += ValueTypeHandler::SpaceUsedInMapEntryLong(this->value_);
return size;
}
void CheckTypeAndMergeFrom(const MessageLite& other) override {
MergeFromInternal(*::google::protobuf::internal::DownCast<const Derived*>(&other));
}
std::string GetTypeName() const final { return ""; }
const char* _InternalParse(const char* ptr, ParseContext* ctx) final {
while (!ctx->Done(&ptr)) {
@ -167,13 +149,11 @@ class MapEntry : public Message {
ptr = ReadTag(ptr, &tag);
GOOGLE_PROTOBUF_PARSER_ASSERT(ptr);
if (tag == kKeyTag) {
set_has_key();
KeyMapEntryAccessorType* key = mutable_key();
auto* 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();
auto* value = mutable_value();
ptr = ValueTypeHandler::Read(ptr, ctx, value);
if (!Derived::ValidateValue(value)) return nullptr;
} else {
@ -190,34 +170,29 @@ class MapEntry : public Message {
return ptr;
}
size_t ByteSizeLong() const override {
size_t ByteSizeLong() const final {
size_t size = 0;
size += kTagSize + static_cast<size_t>(KeyTypeHandler::ByteSize(key()));
size += kTagSize + static_cast<size_t>(ValueTypeHandler::ByteSize(value()));
_cached_size_.Set(ToCachedSize(size));
return size;
}
::uint8_t* _InternalSerialize(
::uint8_t* ptr, io::EpsCopyOutputStream* stream) const override {
::uint8_t* _InternalSerialize(::uint8_t* ptr,
io::EpsCopyOutputStream* stream) const final {
ptr = KeyTypeHandler::Write(kKeyFieldNumber, key(), ptr, stream);
return ValueTypeHandler::Write(kValueFieldNumber, value(), ptr, stream);
}
bool IsInitialized() const override {
bool IsInitialized() const final {
return ValueTypeHandler::IsInitialized(value_);
}
Message* New(Arena* arena) const override {
Derived* entry = Arena::CreateMessage<Derived>(arena);
return entry;
Message* New(Arena* arena) const final {
return Arena::CreateMessage<Derived>(arena);
}
void Clear() final {
KeyTypeHandler::Clear(&key_, GetArenaForAllocation());
ValueTypeHandler::Clear(&value_, GetArenaForAllocation());
clear_has_key();
clear_has_value();
}
CachedSize* AccessCachedSize() const final { return &_cached_size_; }
protected:
friend class google::protobuf::Arena;
@ -225,33 +200,10 @@ class MapEntry : public Message {
WireFormatLite::FieldType>
friend class MapField;
// We can't declare this function directly here as it would hide the other
// overload (const Message&).
void MergeFromInternal(const MapEntry& from) {
if (from._has_bits_[0]) {
if (from.has_key()) {
KeyTypeHandler::EnsureMutable(&key_, GetArenaForAllocation());
KeyTypeHandler::Merge(from.key(), &key_, GetArenaForAllocation());
set_has_key();
}
if (from.has_value()) {
ValueTypeHandler::EnsureMutable(&value_, GetArenaForAllocation());
ValueTypeHandler::Merge(from.value(), &value_, GetArenaForAllocation());
set_has_value();
}
}
}
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; }
KeyOnMemory key_;
ValueOnMemory value_;
uint32_t _has_bits_[1];
HasBits<1> _has_bits_;
mutable CachedSize _cached_size_;
};
} // namespace internal

@ -2351,17 +2351,18 @@ class MyMapEntry
internal::WireFormatLite::TYPE_INT32> {
public:
constexpr MyMapEntry() {}
MyMapEntry(Arena*) { ABSL_CHECK(false); }
using MyMapEntry::MapEntry::MapEntry;
Metadata GetMetadata() const override { ABSL_CHECK(false); }
static bool ValidateKey(void*) { return true; }
static bool ValidateValue(void*) { return true; }
};
TEST(MapEntryTest, ConstInit) {
// This verifies that `MapEntry`, `MapEntryLite` and `MapEntryImpl` can be
// constant initialized.
// This verifies that `MapEntry` can be constant initialized.
PROTOBUF_CONSTINIT static MyMapEntry entry{};
EXPECT_NE(entry.SpaceUsed(), 0);
// Use the object in some way to make sure the vtable is there.
const google::protobuf::Message* volatile m = &entry;
delete m->New();
}
// Generated Message Test ===========================================

@ -8,6 +8,9 @@
#ifndef GOOGLE_PROTOBUF_MAP_TYPE_HANDLER_H__
#define GOOGLE_PROTOBUF_MAP_TYPE_HANDLER_H__
#include <cstdint>
#include <type_traits>
#include "google/protobuf/arena.h"
#include "google/protobuf/arenastring.h"
#include "google/protobuf/io/coded_stream.h"
@ -22,81 +25,46 @@ namespace google {
namespace protobuf {
namespace internal {
// Used for compile time type selection. MapIf::type will be TrueType if Flag is
// true and FalseType otherwise.
template <bool Flag, typename TrueType, typename FalseType>
struct MapIf;
template <typename TrueType, typename FalseType>
struct MapIf<true, TrueType, FalseType> {
typedef TrueType type;
};
template <typename TrueType, typename FalseType>
struct MapIf<false, TrueType, FalseType> {
typedef FalseType type;
};
template <typename Type, bool is_arena_constructable>
class MapArenaMessageCreator {
public:
// Use arena to create message if Type is arena constructable. Otherwise,
// create the message on heap.
static inline Type* CreateMessage(Arena* arena);
};
template <typename Type>
class MapArenaMessageCreator<Type, true> {
public:
static inline Type* CreateMessage(Arena* arena) {
return Arena::CreateMessage<Type>(arena);
}
};
template <typename Type>
class MapArenaMessageCreator<Type, false> {
public:
static inline Type* CreateMessage(Arena* arena) {
return Arena::Create<Type>(arena);
}
};
// Define constants for given wire field type
template <WireFormatLite::FieldType field_type, typename Type>
class MapWireFieldTypeTraits {};
#define TYPE_TRAITS(FieldType, CType, WireFormatType, IsMessage, IsEnum) \
template <typename Type> \
class MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType, Type> { \
public: \
static const bool kIsMessage = IsMessage; \
static const bool kIsEnum = IsEnum; \
typedef typename MapIf<kIsMessage, Type*, CType>::type TypeOnMemory; \
typedef typename MapIf<kIsEnum, int, Type>::type MapEntryAccessorType; \
static const WireFormatLite::WireType kWireType = \
WireFormatLite::WIRETYPE_##WireFormatType; \
#define TYPE_TRAITS(FieldType, CType, WireFormatType) \
template <typename Type> \
class MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType, Type> { \
public: \
using TypeOnMemory = \
std::conditional_t<WireFormatLite::TYPE_##FieldType == \
WireFormatLite::TYPE_MESSAGE, \
Type*, CType>; \
using MapEntryAccessorType = \
std::conditional_t<std::is_enum<Type>::value, int, Type>; \
static const WireFormatLite::WireType kWireType = \
WireFormatLite::WIRETYPE_##WireFormatType; \
};
TYPE_TRAITS(MESSAGE, Type, LENGTH_DELIMITED, true, false)
TYPE_TRAITS(STRING, ArenaStringPtr, LENGTH_DELIMITED, false, false)
TYPE_TRAITS(BYTES, ArenaStringPtr, LENGTH_DELIMITED, false, false)
TYPE_TRAITS(INT64, int64_t, VARINT, false, false)
TYPE_TRAITS(UINT64, uint64_t, VARINT, false, false)
TYPE_TRAITS(INT32, int32_t, VARINT, false, false)
TYPE_TRAITS(UINT32, uint32_t, VARINT, false, false)
TYPE_TRAITS(SINT64, int64_t, VARINT, false, false)
TYPE_TRAITS(SINT32, int32_t, VARINT, false, false)
TYPE_TRAITS(ENUM, int, VARINT, false, true)
TYPE_TRAITS(DOUBLE, double, FIXED64, false, false)
TYPE_TRAITS(FLOAT, float, FIXED32, false, false)
TYPE_TRAITS(FIXED64, uint64_t, FIXED64, false, false)
TYPE_TRAITS(FIXED32, uint32_t, FIXED32, false, false)
TYPE_TRAITS(SFIXED64, int64_t, FIXED64, false, false)
TYPE_TRAITS(SFIXED32, int32_t, FIXED32, false, false)
TYPE_TRAITS(BOOL, bool, VARINT, false, false)
TYPE_TRAITS(MESSAGE, Type, LENGTH_DELIMITED)
TYPE_TRAITS(STRING, ArenaStringPtr, LENGTH_DELIMITED)
TYPE_TRAITS(BYTES, ArenaStringPtr, LENGTH_DELIMITED)
TYPE_TRAITS(INT64, int64_t, VARINT)
TYPE_TRAITS(UINT64, uint64_t, VARINT)
TYPE_TRAITS(INT32, int32_t, VARINT)
TYPE_TRAITS(UINT32, uint32_t, VARINT)
TYPE_TRAITS(SINT64, int64_t, VARINT)
TYPE_TRAITS(SINT32, int32_t, VARINT)
TYPE_TRAITS(ENUM, int, VARINT)
TYPE_TRAITS(DOUBLE, double, FIXED64)
TYPE_TRAITS(FLOAT, float, FIXED32)
TYPE_TRAITS(FIXED64, uint64_t, FIXED64)
TYPE_TRAITS(FIXED32, uint32_t, FIXED32)
TYPE_TRAITS(SFIXED64, int64_t, FIXED64)
TYPE_TRAITS(SFIXED32, int32_t, FIXED32)
TYPE_TRAITS(BOOL, bool, VARINT)
#undef TYPE_TRAITS
template <WireFormatLite::FieldType field_type, typename Type>
class MapTypeHandler {};
class MapTypeHandler;
template <typename Type>
class MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type> {
@ -112,12 +80,6 @@ class MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type> {
// Corresponding wire type for field type.
static constexpr WireFormatLite::WireType kWireType =
MapWireFieldTypeTraits<WireFormatLite::TYPE_MESSAGE, Type>::kWireType;
// Whether wire type is for message.
static constexpr bool kIsMessage =
MapWireFieldTypeTraits<WireFormatLite::TYPE_MESSAGE, Type>::kIsMessage;
// Whether wire type is for enum.
static constexpr bool kIsEnum =
MapWireFieldTypeTraits<WireFormatLite::TYPE_MESSAGE, Type>::kIsEnum;
// Functions used in parsing and serialization. ===================
static inline size_t ByteSize(const MapEntryAccessorType& value);
@ -133,14 +95,9 @@ class MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type> {
// Functions to manipulate data on memory. ========================
static inline const Type& GetExternalReference(const Type* value);
static inline void DeleteNoArena(const Type* x);
static inline void Merge(const Type& from, Type** to, Arena* arena);
static inline void Clear(Type** value, Arena* arena);
static constexpr TypeOnMemory Constinit();
static inline Type* EnsureMutable(Type** value, Arena* arena);
// SpaceUsedInMapEntry: Return bytes used by value in MapEntry, excluding
// those already calculate in sizeof(MapField).
static inline size_t SpaceUsedInMapEntryLong(const Type* value);
// Return default instance if value is not initialized when calling const
// reference accessor.
static inline const Type& DefaultIfNotInitialized(const Type* value);
@ -160,12 +117,6 @@ class MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type> {
static const WireFormatLite::WireType kWireType = \
MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType, \
Type>::kWireType; \
static const bool kIsMessage = \
MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType, \
Type>::kIsMessage; \
static const bool kIsEnum = \
MapWireFieldTypeTraits<WireFormatLite::TYPE_##FieldType, \
Type>::kIsEnum; \
static inline int ByteSize(const MapEntryAccessorType& value); \
static inline int GetCachedSize(const MapEntryAccessorType& value); \
static inline bool Read(io::CodedInputStream* input, \
@ -178,10 +129,6 @@ class MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type> {
static inline const MapEntryAccessorType& GetExternalReference( \
const TypeOnMemory& value); \
static inline void DeleteNoArena(const TypeOnMemory& x); \
static inline void Merge(const MapEntryAccessorType& from, \
TypeOnMemory* to, Arena* arena); \
static inline void Clear(TypeOnMemory* value, Arena* arena); \
static inline size_t SpaceUsedInMapEntryLong(const TypeOnMemory& value); \
static inline const MapEntryAccessorType& DefaultIfNotInitialized( \
const TypeOnMemory& value); \
static inline bool IsInitialized(const TypeOnMemory& value); \
@ -480,23 +427,6 @@ MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::GetExternalReference(
return *value;
}
template <typename Type>
inline size_t MapTypeHandler<WireFormatLite::TYPE_MESSAGE,
Type>::SpaceUsedInMapEntryLong(const Type* value) {
return value->SpaceUsedLong();
}
template <typename Type>
inline void MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::Clear(
Type** value, Arena* /* arena */) {
if (*value != nullptr) (*value)->Clear();
}
template <typename Type>
inline void MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::Merge(
const Type& from, Type** to, Arena* /* arena */) {
(*to)->MergeFrom(from);
}
template <typename Type>
void MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::DeleteNoArena(
const Type* ptr) {
@ -513,9 +443,7 @@ template <typename Type>
inline Type* MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::EnsureMutable(
Type** value, Arena* arena) {
if (*value == nullptr) {
*value = MapArenaMessageCreator<
Type,
Arena::is_arena_constructable<Type>::type::value>::CreateMessage(arena);
*value = Arena::CreateMessage<Type>(arena);
}
return *value;
}
@ -544,22 +472,6 @@ inline bool MapTypeHandler<WireFormatLite::TYPE_MESSAGE, Type>::IsInitialized(
return value.Get(); \
} \
template <typename Type> \
inline size_t \
MapTypeHandler<WireFormatLite::TYPE_##FieldType, \
Type>::SpaceUsedInMapEntryLong(const TypeOnMemory& value) { \
return sizeof(value); \
} \
template <typename Type> \
inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Clear( \
TypeOnMemory* value, Arena* /* arena */) { \
value->ClearToEmpty(); \
} \
template <typename Type> \
inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Merge( \
const MapEntryAccessorType& from, TypeOnMemory* to, Arena* arena) { \
to->Set(from, arena); \
} \
template <typename Type> \
void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::DeleteNoArena( \
TypeOnMemory& value) { \
value.Destroy(); \
@ -604,22 +516,6 @@ STRING_OR_BYTES_HANDLER_FUNCTIONS(BYTES)
return value; \
} \
template <typename Type> \
inline size_t MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>:: \
SpaceUsedInMapEntryLong(const TypeOnMemory& /* value */) { \
return 0; \
} \
template <typename Type> \
inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Clear( \
TypeOnMemory* value, Arena* /* arena */) { \
*value = 0; \
} \
template <typename Type> \
inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, Type>::Merge( \
const MapEntryAccessorType& from, TypeOnMemory* to, \
Arena* /* arena */) { \
*to = from; \
} \
template <typename Type> \
inline void MapTypeHandler<WireFormatLite::TYPE_##FieldType, \
Type>::DeleteNoArena(TypeOnMemory& /* x */) {} \
template <typename Type> \

@ -46,6 +46,7 @@
#include "google/protobuf/io/zero_copy_stream.h"
#include "google/protobuf/io/zero_copy_stream_impl.h"
#include "google/protobuf/message.h"
#include "google/protobuf/reflection_ops.h"
#include "google/protobuf/test_util2.h"

Loading…
Cancel
Save