Streamline creation of new elements in `RepeatedPtrField`

The logic to create new elements in `RepeatedPtrField` was spread across an assorted collection of specializations of `GenericTypeHandler`, individual `GenericTypeHandler` static functions, and external member and non-member functions, all living in multiple sources. Now all that logic is concentrated in three symmetric `GenericTypeHandler` specializations.

PiperOrigin-RevId: 674064544
pull/18299/head
Protobuf Team Bot 6 months ago committed by Copybara-Service
parent 52544482bf
commit 91e3162240
  1. 2
      src/google/protobuf/extension_set.cc
  2. 2
      src/google/protobuf/lazy_repeated_field.h
  3. 22
      src/google/protobuf/message.cc
  4. 10
      src/google/protobuf/message_lite.cc
  5. 17
      src/google/protobuf/repeated_ptr_field.cc
  6. 133
      src/google/protobuf/repeated_ptr_field.h

@ -825,7 +825,7 @@ MessageLite* ExtensionSet::AddMessage(int number, FieldType type,
return reinterpret_cast<internal::RepeatedPtrFieldBase*>( return reinterpret_cast<internal::RepeatedPtrFieldBase*>(
extension->ptr.repeated_message_value) extension->ptr.repeated_message_value)
->AddMessage(&prototype); ->AddFromPrototype(&prototype);
} }
// Defined in extension_set_heavy.cc. // Defined in extension_set_heavy.cc.

@ -328,7 +328,7 @@ class LazyRepeatedPtrField {
const char* ptr2 = ptr; const char* ptr2 = ptr;
TagType next_tag; TagType next_tag;
do { do {
MessageLite* submsg = value->AddMessage(prototype); MessageLite* submsg = value->AddFromPrototype(prototype);
// ptr2 points to the start of the element's encoded length. // ptr2 points to the start of the element's encoded length.
ptr = ctx->ParseMessage(submsg, ptr2); ptr = ctx->ParseMessage(submsg, ptr2);
if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) return nullptr; if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) return nullptr;

@ -495,28 +495,6 @@ const internal::RepeatedFieldAccessor* Reflection::RepeatedFieldAccessor(
} }
namespace internal { namespace internal {
template <>
#if defined(_MSC_VER) && (_MSC_VER >= 1800)
// Note: force noinline to workaround MSVC compiler bug with /Zc:inline, issue
// #240
PROTOBUF_NOINLINE
#endif
Message*
GenericTypeHandler<Message>::NewFromPrototype(const Message* prototype,
Arena* arena) {
return prototype->New(arena);
}
template <>
#if defined(_MSC_VER) && (_MSC_VER >= 1800)
// Note: force noinline to workaround MSVC compiler bug with /Zc:inline, issue
// #240
PROTOBUF_NOINLINE
#endif
Arena*
GenericTypeHandler<Message>::GetArena(Message* value) {
return value->GetArena();
}
template void InternalMetadata::DoClear<UnknownFieldSet>(); template void InternalMetadata::DoClear<UnknownFieldSet>();
template void InternalMetadata::DoMergeFrom<UnknownFieldSet>( template void InternalMetadata::DoMergeFrom<UnknownFieldSet>(
const UnknownFieldSet& other); const UnknownFieldSet& other);

@ -711,16 +711,6 @@ absl::Cord MessageLite::SerializePartialAsCord() const {
namespace internal { namespace internal {
MessageLite* NewFromPrototypeHelper(const MessageLite* prototype,
Arena* arena) {
return prototype->New(arena);
}
template <>
void GenericTypeHandler<MessageLite>::Merge(const MessageLite& from,
MessageLite* to) {
to->CheckTypeAndMergeFrom(from);
}
// Non-inline variants of std::string specializations for // Non-inline variants of std::string specializations for
// various InternalMetadata routines. // various InternalMetadata routines.
template <> template <>

@ -93,14 +93,6 @@ void RepeatedPtrFieldBase::DestroyProtos() {
tagged_rep_or_elem_ = nullptr; tagged_rep_or_elem_ = nullptr;
} }
void* RepeatedPtrFieldBase::AddMessageLite(ElementFactory factory) {
return AddInternal(factory);
}
void* RepeatedPtrFieldBase::AddString() {
return AddInternal([](Arena* arena) { return NewStringElement(arena); });
}
void RepeatedPtrFieldBase::CloseGap(int start, int num) { void RepeatedPtrFieldBase::CloseGap(int start, int num) {
if (using_sso()) { if (using_sso()) {
if (start == 0 && num == 1) { if (start == 0 && num == 1) {
@ -116,11 +108,6 @@ void RepeatedPtrFieldBase::CloseGap(int start, int num) {
ExchangeCurrentSize(current_size_ - num); ExchangeCurrentSize(current_size_ - num);
} }
MessageLite* RepeatedPtrFieldBase::AddMessage(const MessageLite* prototype) {
return static_cast<MessageLite*>(
AddInternal([prototype](Arena* a) { return prototype->New(a); }));
}
void InternalOutOfLineDeleteMessageLite(MessageLite* message) { void InternalOutOfLineDeleteMessageLite(MessageLite* message) {
delete message; delete message;
} }
@ -227,10 +214,6 @@ void RepeatedPtrFieldBase::MergeFrom<MessageLite>(
} }
} }
void* NewStringElement(Arena* arena) {
return Arena::Create<std::string>(arena);
}
} // namespace internal } // namespace internal
} // namespace protobuf } // namespace protobuf
} // namespace google } // namespace google

@ -108,7 +108,8 @@ class GenericTypeHandler;
// using Type = MyType; // using Type = MyType;
// using Movable = ...; // using Movable = ...;
// //
// static Type*(*)(Arena*) GetNewFunc(); // static ElementFactory GetNewFunc();
// static ElementFactory GetNewFromPrototypeFunc(const Type* prototype);
// static void GetArena(Type* value); // static void GetArena(Type* value);
// //
// static Type* New(Arena* arena); // static Type* New(Arena* arena);
@ -127,8 +128,6 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
static constexpr int kSSOCapacity = 1; static constexpr int kSSOCapacity = 1;
using ElementFactory = void* (*)(Arena*);
protected: protected:
// We use the same TypeHandler for all Message types to deduplicate generated // We use the same TypeHandler for all Message types to deduplicate generated
// code. // code.
@ -192,15 +191,18 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
template <typename TypeHandler> template <typename TypeHandler>
Value<TypeHandler>* Add() { Value<TypeHandler>* Add() {
if (std::is_same<Value<TypeHandler>, std::string>{}) { return cast<TypeHandler>(AddInternal(TypeHandler::GetNewFunc()));
return cast<TypeHandler>(AddString());
}
return cast<TypeHandler>(AddMessageLite(TypeHandler::GetNewFunc()));
} }
template < template <typename Type>
typename TypeHandler, Type* AddFromPrototype(const Type* prototype) {
typename std::enable_if<TypeHandler::Movable::value>::type* = nullptr> using TypeHandler = GenericTypeHandler<Type>;
using H = CommonHandler<TypeHandler>;
return cast<TypeHandler>(
AddInternal(H::GetNewFromPrototypeFunc(prototype)));
}
template <typename TypeHandler>
inline void Add(Value<TypeHandler>&& value) { inline void Add(Value<TypeHandler>&& value) {
if (current_size_ < allocated_size()) { if (current_size_ < allocated_size()) {
*cast<TypeHandler>(element_at(ExchangeCurrentSize(current_size_ + 1))) = *cast<TypeHandler>(element_at(ExchangeCurrentSize(current_size_ + 1))) =
@ -255,12 +257,6 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
return *cast<TypeHandler>(element_at(index)); return *cast<TypeHandler>(element_at(index));
} }
// Creates and adds an element using the given prototype, without introducing
// a link-time dependency on the concrete message type.
//
// Pre-condition: prototype must not be nullptr.
MessageLite* AddMessage(const MessageLite* prototype);
template <typename TypeHandler> template <typename TypeHandler>
void Clear() { void Clear() {
const int n = current_size_; const int n = current_size_;
@ -725,10 +721,6 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
return InternalExtend(n - Capacity()); return InternalExtend(n - Capacity());
} }
// Internal helpers for Add that keep definition out-of-line.
void* AddMessageLite(ElementFactory factory);
void* AddString();
// Common implementation used by various Add* methods. `factory` is an object // Common implementation used by various Add* methods. `factory` is an object
// used to construct a new element unless there are spare cleared elements // used to construct a new element unless there are spare cleared elements
// ready for reuse. Returns pointer to the new element. // ready for reuse. Returns pointer to the new element.
@ -813,13 +805,32 @@ void* RepeatedPtrFieldBase::AddInternal(Factory factory) {
PROTOBUF_EXPORT void InternalOutOfLineDeleteMessageLite(MessageLite* message); PROTOBUF_EXPORT void InternalOutOfLineDeleteMessageLite(MessageLite* message);
// Encapsulates the minimally required subset of T's properties in a
// `RepeatedPtrField<T>` specialization so the type-agnostic
// `RepeatedPtrFieldBase` could do its job without knowing T.
//
// This generic definition is for types derived from `MessageLite`. That is
// statically asserted, but only where a non-conforming type would emit a
// compile-time diagnostic that lacks proper guidance for fixing. Asserting
// at the top level isn't possible, because some template argument types are not
// yet fully defined at the instantiation point.
//
// Explicit specializations are provided for `std::string` and
// `StringPieceField` further below.
template <typename GenericType> template <typename GenericType>
class GenericTypeHandler { class GenericTypeHandler {
public: public:
using Type = GenericType; using Type = GenericType;
using Movable = IsMovable<Type>; using Movable = IsMovable<Type>;
static constexpr auto GetNewFunc() { return Arena::DefaultConstruct<Type>; } static constexpr auto* GetNewFunc() { return Arena::DefaultConstruct<Type>; }
static constexpr auto GetNewFromPrototypeFunc(const Type* prototype) {
static_assert(std::is_base_of<MessageLite, Type>::value, "");
return [prototype](Arena* arena) {
ABSL_DCHECK(prototype != nullptr);
return prototype->New(arena);
};
}
static inline Arena* GetArena(Type* value) { static inline Arena* GetArena(Type* value) {
return Arena::InternalGetArena(value); return Arena::InternalGetArena(value);
} }
@ -830,76 +841,42 @@ class GenericTypeHandler {
static inline Type* New(Arena* arena, Type&& value) { static inline Type* New(Arena* arena, Type&& value) {
return Arena::Create<Type>(arena, std::move(value)); return Arena::Create<Type>(arena, std::move(value));
} }
static inline Type* NewFromPrototype(const Type* /*prototype*/, static inline Type* NewFromPrototype(const Type* prototype,
Arena* arena = nullptr) { Arena* arena = nullptr) {
return New(arena); static_assert(std::is_base_of<MessageLite, Type>::value, "");
ABSL_DCHECK(prototype != nullptr);
return prototype->New(arena);
} }
static inline void Delete(Type* value, Arena* arena) { static inline void Delete(Type* value, Arena* arena) {
if (arena != nullptr) return; if (arena != nullptr) return;
#ifdef __cpp_if_constexpr // Using virtual destructor to reduce generated code size that would have
if constexpr (std::is_base_of<MessageLite, Type>::value) { // happened otherwise due to inlined `~Type()`.
// Using virtual destructor to reduce generated code size that would have InternalOutOfLineDeleteMessageLite(value);
// happened otherwise due to inlined `~Type()`. }
InternalOutOfLineDeleteMessageLite(value); static inline void Clear(Type* value) {
} else { static_assert(std::is_base_of<MessageLite, Type>::value, "");
delete value; value->Clear();
} }
#else static inline void Merge(const Type& from, Type* to) {
delete value; static_assert(std::is_base_of<MessageLite, Type>::value, "");
#endif to->CheckTypeAndMergeFrom(from);
} }
static inline void Clear(Type* value) { value->Clear(); }
static void Merge(const Type& from, Type* to);
static inline size_t SpaceUsedLong(const Type& value) { static inline size_t SpaceUsedLong(const Type& value) {
static_assert(std::is_base_of<MessageLite, Type>::value, "");
return value.SpaceUsedLong(); return value.SpaceUsedLong();
} }
}; };
// NewFromPrototypeHelper() is not defined inline here, as we will need to do a
// virtual function dispatch anyways to go from Message* to call New/Merge. (The
// additional helper is needed as a workaround for MSVC.)
PROTOBUF_EXPORT MessageLite* NewFromPrototypeHelper(
const MessageLite* prototype, Arena* arena);
template <>
inline MessageLite* GenericTypeHandler<MessageLite>::NewFromPrototype(
const MessageLite* prototype, Arena* arena) {
return NewFromPrototypeHelper(prototype, arena);
}
template <>
inline Arena* GenericTypeHandler<MessageLite>::GetArena(MessageLite* value) {
return value->GetArena();
}
template <typename GenericType>
PROTOBUF_NOINLINE inline void GenericTypeHandler<GenericType>::Merge(
const GenericType& from, GenericType* to) {
to->MergeFrom(from);
}
template <>
PROTOBUF_EXPORT void GenericTypeHandler<MessageLite>::Merge(
const MessageLite& from, MessageLite* to);
// Message specialization bodies defined in message.cc. This split is necessary
// to allow proto2-lite (which includes this header) to be independent of
// Message.
template <>
PROTOBUF_EXPORT Message* GenericTypeHandler<Message>::NewFromPrototype(
const Message* prototype, Arena* arena);
template <>
PROTOBUF_EXPORT Arena* GenericTypeHandler<Message>::GetArena(Message* value);
PROTOBUF_EXPORT void* NewStringElement(Arena* arena);
template <> template <>
class GenericTypeHandler<std::string> { class GenericTypeHandler<std::string> {
public: public:
using Type = std::string; using Type = std::string;
using Movable = IsMovable<Type>; using Movable = IsMovable<Type>;
static constexpr auto GetNewFunc() { return NewStringElement; } static constexpr auto* GetNewFunc() { return Arena::Create<Type>; }
static inline Arena* GetArena(Type*) { return nullptr; } static constexpr auto* GetNewFromPrototypeFunc(const Type* prototype) {
return GetNewFunc();
}
static PROTOBUF_NOINLINE Type* New(Arena* arena) { static PROTOBUF_NOINLINE Type* New(Arena* arena) {
return Arena::Create<Type>(arena); return Arena::Create<Type>(arena);
} }
@ -914,13 +891,15 @@ class GenericTypeHandler<std::string> {
delete value; delete value;
} }
} }
static inline Arena* GetArena(Type*) { return nullptr; }
static inline void Clear(Type* value) { value->clear(); } static inline void Clear(Type* value) { value->clear(); }
static inline void Merge(const Type& from, Type* to) { *to = from; } static inline void Merge(const Type& from, Type* to) { *to = from; }
static size_t SpaceUsedLong(const Type& value) { static inline size_t SpaceUsedLong(const Type& value) {
return sizeof(value) + StringSpaceUsedExcludingSelfLong(value); return sizeof(value) + StringSpaceUsedExcludingSelfLong(value);
} }
}; };
} // namespace internal } // namespace internal
// RepeatedPtrField is like RepeatedField, but used for repeated strings or // RepeatedPtrField is like RepeatedField, but used for repeated strings or
@ -1246,7 +1225,7 @@ class RepeatedPtrField final : private internal::RepeatedPtrFieldBase {
void AddAllocatedForParse(Element* p) { void AddAllocatedForParse(Element* p) {
return RepeatedPtrFieldBase::AddAllocatedForParse(p); RepeatedPtrFieldBase::AddAllocatedForParse(p);
} }
}; };

Loading…
Cancel
Save