diff --git a/src/google/protobuf/extension_set.cc b/src/google/protobuf/extension_set.cc index 34a13fe5039e..d2e69a666ac0 100644 --- a/src/google/protobuf/extension_set.cc +++ b/src/google/protobuf/extension_set.cc @@ -823,9 +823,7 @@ MessageLite* ExtensionSet::AddMessage(int number, FieldType type, ABSL_DCHECK_TYPE(*extension, REPEATED_FIELD, MESSAGE); } - return reinterpret_cast( - extension->ptr.repeated_message_value) - ->AddMessage(&prototype); + return extension->ptr.repeated_message_value->AddFromPrototype(&prototype); } // Defined in extension_set_heavy.cc. diff --git a/src/google/protobuf/lazy_repeated_field.h b/src/google/protobuf/lazy_repeated_field.h index ab573e58c081..40ec02e771aa 100644 --- a/src/google/protobuf/lazy_repeated_field.h +++ b/src/google/protobuf/lazy_repeated_field.h @@ -328,7 +328,8 @@ class LazyRepeatedPtrField { const char* ptr2 = ptr; TagType next_tag; do { - MessageLite* submsg = value->AddMessage(prototype); + MessageLite* submsg = + value->AddFromPrototype>(prototype); // ptr2 points to the start of the element's encoded length. ptr = ctx->ParseMessage(submsg, ptr2); if (PROTOBUF_PREDICT_FALSE(ptr == nullptr)) return nullptr; diff --git a/src/google/protobuf/message.cc b/src/google/protobuf/message.cc index f60818f424b1..40afaa6e63c1 100644 --- a/src/google/protobuf/message.cc +++ b/src/google/protobuf/message.cc @@ -495,28 +495,6 @@ const internal::RepeatedFieldAccessor* Reflection::RepeatedFieldAccessor( } 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::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::GetArena(Message* value) { - return value->GetArena(); -} - template void InternalMetadata::DoClear(); template void InternalMetadata::DoMergeFrom( const UnknownFieldSet& other); diff --git a/src/google/protobuf/message_lite.cc b/src/google/protobuf/message_lite.cc index 9b3debf11e85..acc985913093 100644 --- a/src/google/protobuf/message_lite.cc +++ b/src/google/protobuf/message_lite.cc @@ -703,16 +703,6 @@ absl::Cord MessageLite::SerializePartialAsCord() const { namespace internal { -MessageLite* NewFromPrototypeHelper(const MessageLite* prototype, - Arena* arena) { - return prototype->New(arena); -} -template <> -void GenericTypeHandler::Merge(const MessageLite& from, - MessageLite* to) { - to->CheckTypeAndMergeFrom(from); -} - // Non-inline variants of std::string specializations for // various InternalMetadata routines. template <> diff --git a/src/google/protobuf/message_lite.h b/src/google/protobuf/message_lite.h index c3ae2039b3d6..571e2f535bd9 100644 --- a/src/google/protobuf/message_lite.h +++ b/src/google/protobuf/message_lite.h @@ -225,9 +225,6 @@ class WireFormatLite; class WeakFieldMap; class RustMapHelper; -template -class GenericTypeHandler; // defined in repeated_field.h - // We compute sizes as size_t but cache them as int. This function converts a // computed size to a cached size. Since we don't proceed with serialization // if the total size was > INT_MAX, it is not important what this function @@ -963,8 +960,6 @@ class PROTOBUF_EXPORT MessageLite { template friend class Arena::InternalHelper; - template - friend class internal::GenericTypeHandler; friend auto internal::GetClassData(const MessageLite& msg); diff --git a/src/google/protobuf/repeated_field.h b/src/google/protobuf/repeated_field.h index 4c4ae30808ea..f885f49d594b 100644 --- a/src/google/protobuf/repeated_field.h +++ b/src/google/protobuf/repeated_field.h @@ -28,7 +28,6 @@ #include #include #include -#include #include #include @@ -36,7 +35,6 @@ #include "absl/base/dynamic_annotations.h" #include "absl/base/optimization.h" #include "absl/log/absl_check.h" -#include "absl/log/absl_log.h" #include "absl/meta/type_traits.h" #include "absl/strings/cord.h" #include "google/protobuf/arena.h" @@ -46,7 +44,6 @@ #include "google/protobuf/port.h" #include "google/protobuf/repeated_ptr_field.h" - // Must be included last. #include "google/protobuf/port_def.inc" @@ -79,7 +76,11 @@ constexpr int RepeatedFieldLowerClampLimit() { // overflows when multiplied by 2 (which is undefined behavior). Sizes above // this will clamp to the maximum int value instead of following exponential // growth when growing a repeated field. +#if defined(__cpp_inline_variables) +inline constexpr int kRepeatedFieldUpperClampLimit = +#else constexpr int kRepeatedFieldUpperClampLimit = +#endif (std::numeric_limits::max() / 2) + 1; template diff --git a/src/google/protobuf/repeated_field_unittest.cc b/src/google/protobuf/repeated_field_unittest.cc index 551b135811f7..328221b003f9 100644 --- a/src/google/protobuf/repeated_field_unittest.cc +++ b/src/google/protobuf/repeated_field_unittest.cc @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -34,7 +35,6 @@ #include #include "absl/log/absl_check.h" #include "absl/numeric/bits.h" -#include "absl/random/random.h" #include "absl/strings/cord.h" #include "absl/strings/str_cat.h" #include "absl/types/span.h" diff --git a/src/google/protobuf/repeated_ptr_field.cc b/src/google/protobuf/repeated_ptr_field.cc index 19992e454e97..4c847866cb4c 100644 --- a/src/google/protobuf/repeated_ptr_field.cc +++ b/src/google/protobuf/repeated_ptr_field.cc @@ -16,9 +16,9 @@ #include #include #include +#include #include -#include "absl/base/prefetch.h" #include "absl/log/absl_check.h" #include "google/protobuf/arena.h" #include "google/protobuf/message_lite.h" @@ -93,14 +93,6 @@ void RepeatedPtrFieldBase::DestroyProtos() { 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) { if (using_sso()) { if (start == 0 && num == 1) { @@ -116,11 +108,6 @@ void RepeatedPtrFieldBase::CloseGap(int start, int num) { ExchangeCurrentSize(current_size_ - num); } -MessageLite* RepeatedPtrFieldBase::AddMessage(const MessageLite* prototype) { - return static_cast( - AddInternal([prototype](Arena* a) { return prototype->New(a); })); -} - void InternalOutOfLineDeleteMessageLite(MessageLite* message) { delete message; } @@ -227,10 +214,6 @@ void RepeatedPtrFieldBase::MergeFrom( } } -void* NewStringElement(Arena* arena) { - return Arena::Create(arena); -} - } // namespace internal } // namespace protobuf } // namespace google diff --git a/src/google/protobuf/repeated_ptr_field.h b/src/google/protobuf/repeated_ptr_field.h index 12bfdd77a4c2..b2178c6bf1f3 100644 --- a/src/google/protobuf/repeated_ptr_field.h +++ b/src/google/protobuf/repeated_ptr_field.h @@ -26,8 +26,8 @@ #include #include #include +#include #include -#include #include #include @@ -40,7 +40,6 @@ #include "google/protobuf/message_lite.h" #include "google/protobuf/port.h" - // Must be included last. #include "google/protobuf/port_def.inc" @@ -92,9 +91,13 @@ struct IsMovable // Do not use this struct - it exists for internal use only. template struct ArenaOffsetHelper { - constexpr static size_t value = offsetof(T, arena_); + static constexpr size_t value = offsetof(T, arena_); }; +// Defined further below. +template +class GenericTypeHandler; + // This is the common base class for RepeatedPtrFields. It deals only in void* // pointers. Users should not use this interface directly. // @@ -102,11 +105,17 @@ struct ArenaOffsetHelper { // but may have a template argument called TypeHandler. Its signature is: // class TypeHandler { // public: -// typedef MyType Type; -// static Type* New(); -// static Type* NewFromPrototype(const Type* prototype, -// Arena* arena); -// static void Delete(Type*); +// using Type = MyType; +// using Movable = ...; +// +// static ElementFactory GetNewFunc(); +// static ElementFactory GetNewFromPrototypeFunc(const Type* prototype); +// static void GetArena(Type* value); +// +// static Type* New(Arena* arena); +// static Type* New(Arena* arena, Type&& value); +// static Type* NewFromPrototype(const Type* prototype, Arena* arena); +// static void Delete(Type*, Arena* arena); // static void Clear(Type*); // static void Merge(const Type& from, Type* to); // @@ -114,20 +123,18 @@ struct ArenaOffsetHelper { // static int SpaceUsedLong(const Type&); // }; class PROTOBUF_EXPORT RepeatedPtrFieldBase { - template - using Value = typename Handler::Type; + template + using Value = typename TypeHandler::Type; static constexpr int kSSOCapacity = 1; - using ElementFactory = void* (*)(Arena*); - protected: - // We use the same Handler for all Message types to deduplicate generated + // We use the same TypeHandler for all Message types to deduplicate generated // code. - template + template using CommonHandler = typename std::conditional< - std::is_base_of>::value, - internal::GenericTypeHandler, Handler>::type; + std::is_base_of>::value, + GenericTypeHandler, TypeHandler>::type; constexpr RepeatedPtrFieldBase() : tagged_rep_or_elem_(nullptr), @@ -145,7 +152,7 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase { ~RepeatedPtrFieldBase() { #ifndef NDEBUG - // Try to trigger segfault / asan failure in non-opt builds. If arena_ + // Try to trigger segfault / asan failure in non-opt builds if arena_ // lifetime has ended before the destructor. if (arena_) (void)arena_->SpaceAllocated(); #endif @@ -182,14 +189,18 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase { return cast(element_at(index)); } - template - Value* Add() { - if (std::is_same, std::string>{}) { - return cast(AddString()); - } - return cast(AddMessageLite(Handler::GetNewFunc())); + template + Value* Add() { + return cast(AddInternal(TypeHandler::GetNewFunc())); } + template + Value* AddFromPrototype(const Value* prototype) { + return cast( + AddInternal(TypeHandler::GetNewFromPrototypeFunc(prototype))); + } + + // TODO: Rework in terms of `AddInternal()`. template < typename TypeHandler, typename std::enable_if::type* = nullptr> @@ -247,12 +258,6 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase { return *cast(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 void Clear() { const int n = current_size_; @@ -318,9 +323,9 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase { template void CopyFrom(const RepeatedPtrFieldBase& other) { if (&other == this) return; - RepeatedPtrFieldBase::Clear(); + Clear(); if (other.empty()) return; - RepeatedPtrFieldBase::MergeFrom(other); + MergeFrom(other); } void CloseGap(int start, int num); @@ -717,10 +722,6 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase { 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 // used to construct a new element unless there are spare cleared elements // ready for reuse. Returns pointer to the new element. @@ -767,8 +768,8 @@ void RepeatedPtrFieldBase::MergeFrom( const RepeatedPtrFieldBase& from); -template -void* RepeatedPtrFieldBase::AddInternal(F factory) { +template +void* RepeatedPtrFieldBase::AddInternal(Factory factory) { Arena* const arena = GetArena(); if (tagged_rep_or_elem_ == nullptr) { ExchangeCurrentSize(1); @@ -808,27 +809,45 @@ PROTOBUF_EXPORT void InternalOutOfLineDeleteMessageLite(MessageLite* message); template class GenericTypeHandler { public: - typedef GenericType Type; - using Movable = IsMovable; + using Type = GenericType; + using Movable = IsMovable; static constexpr auto GetNewFunc() { return Arena::DefaultConstruct; } + static constexpr auto GetNewFromPrototypeFunc(const Type* prototype) { + return [prototype](Arena* arena) { + ABSL_DCHECK(prototype != nullptr); + return prototype->New(arena); + }; + } + static inline Arena* GetArena(Type* value) { + return Arena::InternalGetArena(value); + } - static inline GenericType* New(Arena* arena) { - return static_cast(Arena::DefaultConstruct(arena)); + static inline Type* New(Arena* arena) { + return static_cast(Arena::DefaultConstruct(arena)); } - static inline GenericType* New(Arena* arena, GenericType&& value) { - return Arena::Create(arena, std::move(value)); + static inline Type* New(Arena* arena, Type&& value) { + return Arena::Create(arena, std::move(value)); } - static inline GenericType* NewFromPrototype(const GenericType* /*prototype*/, - Arena* arena = nullptr) { - return New(arena); + static inline Type* NewFromPrototype(const Type* prototype, + Arena* arena = nullptr) { +#if __cpp_if_constexpr + if constexpr (std::is_base_of::value) { +#else + if (std::is_base_of::value) { +#endif + ABSL_DCHECK(prototype != nullptr); + return prototype->New(arena); + } else { + return New(arena); + } } - static inline void Delete(GenericType* value, Arena* arena) { + static inline void Delete(Type* value, Arena* arena) { if (arena != nullptr) return; #ifdef __cpp_if_constexpr - if constexpr (std::is_base_of::value) { + if constexpr (std::is_base_of::value) { // Using virtual destructor to reduce generated code size that would have - // happened otherwise due to inlined `~GenericType`. + // happened otherwise due to inlined `~Type()`. InternalOutOfLineDeleteMessageLite(value); } else { delete value; @@ -837,86 +856,56 @@ class GenericTypeHandler { delete value; #endif } - static inline Arena* GetArena(GenericType* value) { - return Arena::InternalGetArena(value); + static inline void Clear(Type* value) { value->Clear(); } + static inline void Merge(const Type& from, Type* to) { +#if __cpp_if_constexpr + if constexpr (std::is_base_of::value) { +#else + if (std::is_base_of::value) { +#endif + to->CheckTypeAndMergeFrom(from); + } else { + to->MergeFrom(from); + } } - - static inline void Clear(GenericType* value) { value->Clear(); } - static void Merge(const GenericType& from, GenericType* to); - static inline size_t SpaceUsedLong(const GenericType& value) { + static inline size_t SpaceUsedLong(const Type& value) { 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::NewFromPrototype( - const MessageLite* prototype, Arena* arena) { - return NewFromPrototypeHelper(prototype, arena); -} -template <> -inline Arena* GenericTypeHandler::GetArena(MessageLite* value) { - return value->GetArena(); -} - -template -PROTOBUF_NOINLINE inline void GenericTypeHandler::Merge( - const GenericType& from, GenericType* to) { - to->MergeFrom(from); -} -template <> -PROTOBUF_EXPORT void GenericTypeHandler::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::NewFromPrototype( - const Message* prototype, Arena* arena); -template <> -PROTOBUF_EXPORT Arena* GenericTypeHandler::GetArena(Message* value); - -PROTOBUF_EXPORT void* NewStringElement(Arena* arena); - template <> class GenericTypeHandler { public: - typedef std::string Type; + using Type = std::string; using Movable = IsMovable; - static constexpr auto GetNewFunc() { return NewStringElement; } - - static PROTOBUF_NOINLINE std::string* New(Arena* arena) { - return Arena::Create(arena); + static constexpr auto* GetNewFunc() { return Arena::Create; } + static constexpr auto GetNewFromPrototypeFunc(const Type* prototype) { + return GetNewFunc(); } - static PROTOBUF_NOINLINE std::string* New(Arena* arena, std::string&& value) { - return Arena::Create(arena, std::move(value)); + static PROTOBUF_NOINLINE Type* New(Arena* arena) { + return Arena::Create(arena); } - static inline std::string* NewFromPrototype(const std::string*, - Arena* arena) { + static PROTOBUF_NOINLINE Type* New(Arena* arena, Type&& value) { + return Arena::Create(arena, std::move(value)); + } + static inline Type* NewFromPrototype(const Type*, Arena* arena) { return New(arena); } - static inline Arena* GetArena(std::string*) { return nullptr; } - static inline void Delete(std::string* value, Arena* arena) { + static inline void Delete(Type* value, Arena* arena) { if (arena == nullptr) { delete value; } } - static inline void Clear(std::string* value) { value->clear(); } - static inline void Merge(const std::string& from, std::string* to) { - *to = from; - } - static size_t SpaceUsedLong(const std::string& value) { + static inline Arena* GetArena(Type*) { return nullptr; } + static inline void Clear(Type* value) { value->clear(); } + static inline void Merge(const Type& from, Type* to) { *to = from; } + static inline size_t SpaceUsedLong(const Type& value) { return sizeof(value) + StringSpaceUsedExcludingSelfLong(value); } }; + } // namespace internal // RepeatedPtrField is like RepeatedField, but used for repeated strings or @@ -1000,6 +989,12 @@ class RepeatedPtrField final : private internal::RepeatedPtrFieldBase { // fastest API for adding a new element. pointer Add() ABSL_ATTRIBUTE_LIFETIME_BOUND; + // Like `Add()`, but creates a new element from a provided prototype. For + // strings, this is equivalent to `Add()`. For messages, this is equivalent + // to `AddAllocated(new T(prototype))`. + pointer AddFromPrototype(const_pointer prototype) + ABSL_ATTRIBUTE_LIFETIME_BOUND; + // `Add(std::move(value));` is equivalent to `*Add() = std::move(value);` // It will either move-construct to the end of this field, or swap value // with the new-or-recycled element at the end of this field. Note that @@ -1375,6 +1370,12 @@ inline Element* RepeatedPtrField::Add() ABSL_ATTRIBUTE_LIFETIME_BOUND { return RepeatedPtrFieldBase::Add(); } +template +Element* RepeatedPtrField::AddFromPrototype(const Element* prototype) + ABSL_ATTRIBUTE_LIFETIME_BOUND { + return RepeatedPtrFieldBase::AddFromPrototype(prototype); +} + template inline void RepeatedPtrField::Add(Element&& value) { RepeatedPtrFieldBase::Add(std::move(value));