Reduce code bloat for messages - use virtual methods for Merge/Clear/Delete.

PiperOrigin-RevId: 564768912
pull/14030/head
Protobuf Team Bot 1 year ago committed by Copybara-Service
parent 2447882e04
commit 3ae5a079fc
  1. 77
      src/google/protobuf/repeated_ptr_field.h

@ -149,6 +149,13 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
template <typename Handler> template <typename Handler>
using Value = typename Handler::Type; using Value = typename Handler::Type;
// We use the same Handler for all Message types to deduplicate generated
// code.
template <typename Handler>
using CommonHandler = typename std::conditional<
std::is_base_of<MessageLite, Value<Handler>>::value,
internal::GenericTypeHandler<MessageLite>, Handler>::type;
static constexpr int kSSOCapacity = 1; static constexpr int kSSOCapacity = 1;
protected: protected:
@ -230,27 +237,24 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
void Delete(int index) { void Delete(int index) {
ABSL_DCHECK_GE(index, 0); ABSL_DCHECK_GE(index, 0);
ABSL_DCHECK_LT(index, current_size_); ABSL_DCHECK_LT(index, current_size_);
Delete<TypeHandler>(element_at(index), arena_); using H = CommonHandler<TypeHandler>;
Delete<H>(element_at(index), arena_);
} }
// Must be called from destructor. // Must be called from destructor.
template <typename TypeHandler> template <typename TypeHandler>
void Destroy() { void Destroy() {
using H = CommonHandler<TypeHandler>;
if (arena_ != nullptr) return; if (arena_ != nullptr) return;
int n = allocated_size();
if (using_sso()) { void** elems = elements();
if (tagged_rep_or_elem_ == nullptr) return;
Delete<TypeHandler>(tagged_rep_or_elem_, nullptr);
return;
}
Rep* r = rep();
int n = r->allocated_size;
void* const* elems = r->elements;
for (int i = 0; i < n; i++) { for (int i = 0; i < n; i++) {
Delete<TypeHandler>(elems[i], nullptr); Delete<H>(elems[i], nullptr);
}
if (!using_sso()) {
internal::SizedDelete(rep(),
total_size_ * sizeof(elems[0]) + kRepHeaderSize);
} }
internal::SizedDelete(r, total_size_ * sizeof(elems[0]) + kRepHeaderSize);
} }
bool NeedsDestroy() const { bool NeedsDestroy() const {
@ -281,7 +285,8 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
const int n = current_size_; const int n = current_size_;
ABSL_DCHECK_GE(n, 0); ABSL_DCHECK_GE(n, 0);
if (n > 0) { if (n > 0) {
ClearNonEmpty<TypeHandler>(); using H = CommonHandler<TypeHandler>;
ClearNonEmpty<H>();
} }
} }
@ -295,8 +300,8 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
// calls the object-allocate and merge handlers. // calls the object-allocate and merge handlers.
ABSL_DCHECK_NE(&other, this); ABSL_DCHECK_NE(&other, this);
if (other.current_size_ == 0) return; if (other.current_size_ == 0) return;
MergeFromInternal(other, using H = CommonHandler<TypeHandler>;
&RepeatedPtrFieldBase::MergeFromInnerLoop<TypeHandler>); MergeFromInternal(other, &RepeatedPtrFieldBase::MergeFromInnerLoop<H>);
} }
inline void InternalSwap(RepeatedPtrFieldBase* PROTOBUF_RESTRICT rhs) { inline void InternalSwap(RepeatedPtrFieldBase* PROTOBUF_RESTRICT rhs) {
@ -332,7 +337,8 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
void RemoveLast() { void RemoveLast() {
ABSL_DCHECK_GT(current_size_, 0); ABSL_DCHECK_GT(current_size_, 0);
ExchangeCurrentSize(current_size_ - 1); ExchangeCurrentSize(current_size_ - 1);
TypeHandler::Clear(cast<TypeHandler>(element_at(current_size_))); using H = CommonHandler<TypeHandler>;
H::Clear(cast<H>(element_at(current_size_)));
} }
template <typename TypeHandler> template <typename TypeHandler>
@ -348,9 +354,10 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
template <typename TypeHandler> template <typename TypeHandler>
static inline Value<TypeHandler>* copy(Value<TypeHandler>* value) { static inline Value<TypeHandler>* copy(Value<TypeHandler>* value) {
auto* new_value = TypeHandler::NewFromPrototype(value, nullptr); using H = CommonHandler<TypeHandler>;
TypeHandler::Merge(*value, new_value); auto* new_value = H::NewFromPrototype(value, nullptr);
return new_value; H::Merge(*value, new_value);
return cast<TypeHandler>(new_value);
} }
// Used for constructing iterators. // Used for constructing iterators.
@ -392,7 +399,7 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
} }
template <typename TypeHandler> template <typename TypeHandler>
size_t SpaceUsedExcludingSelfLong() const { PROTOBUF_NOINLINE size_t SpaceUsedExcludingSelfLong() const {
size_t allocated_bytes = size_t allocated_bytes =
using_sso() using_sso()
? 0 ? 0
@ -437,7 +444,8 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
// cleared objects awaiting reuse. We don't want to grow the array in // cleared objects awaiting reuse. We don't want to grow the array in
// this case because otherwise a loop calling AddAllocated() followed by // this case because otherwise a loop calling AddAllocated() followed by
// Clear() would leak memory. // Clear() would leak memory.
Delete<TypeHandler>(element_at(current_size_), arena_); using H = CommonHandler<TypeHandler>;
Delete<H>(element_at(current_size_), arena_);
} else if (current_size_ < allocated_size()) { } else if (current_size_ < allocated_size()) {
// We have some cleared objects. We don't care about their order, so we // We have some cleared objects. We don't care about their order, so we
// can just move the first one to the end to make space. // can just move the first one to the end to make space.
@ -568,8 +576,9 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
my_arena->Own(value); my_arena->Own(value);
} else if (my_arena != value_arena) { } else if (my_arena != value_arena) {
auto* new_value = TypeHandler::NewFromPrototype(value, my_arena); auto* new_value = TypeHandler::NewFromPrototype(value, my_arena);
TypeHandler::Merge(*value, new_value); using H = CommonHandler<TypeHandler>;
TypeHandler::Delete(value, value_arena); H::Merge(*value, new_value);
H::Delete(value, value_arena);
value = new_value; value = new_value;
} }
@ -741,9 +750,8 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
const int n = current_size_; const int n = current_size_;
void* const* elems = elements(); void* const* elems = elements();
int i = 0; int i = 0;
ABSL_DCHECK_GT( ABSL_DCHECK_GT(n, 0);
n, // do/while loop to avoid initial test because we know n > 0
0); // do/while loop to avoid initial test because we know n > 0
do { do {
TypeHandler::Clear(cast<TypeHandler>(elems[i++])); TypeHandler::Clear(cast<TypeHandler>(elems[i++]));
} while (i < n); } while (i < n);
@ -866,7 +874,8 @@ class GenericTypeHandler {
// NewFromPrototypeHelper() is not defined inline here, as we will need to do a // 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 // virtual function dispatch anyways to go from Message* to call New/Merge. (The
// additional helper is needed as a workaround for MSVC.) // additional helper is needed as a workaround for MSVC.)
MessageLite* NewFromPrototypeHelper(const MessageLite* prototype, Arena* arena); PROTOBUF_EXPORT MessageLite* NewFromPrototypeHelper(
const MessageLite* prototype, Arena* arena);
template <> template <>
inline MessageLite* GenericTypeHandler<MessageLite>::NewFromPrototype( inline MessageLite* GenericTypeHandler<MessageLite>::NewFromPrototype(
@ -885,8 +894,8 @@ PROTOBUF_NOINLINE inline void GenericTypeHandler<GenericType>::Merge(
to->MergeFrom(from); to->MergeFrom(from);
} }
template <> template <>
void GenericTypeHandler<MessageLite>::Merge(const MessageLite& from, PROTOBUF_EXPORT void GenericTypeHandler<MessageLite>::Merge(
MessageLite* to); const MessageLite& from, MessageLite* to);
template <> template <>
inline void GenericTypeHandler<std::string>::Clear(std::string* value) { inline void GenericTypeHandler<std::string>::Clear(std::string* value) {
@ -1642,7 +1651,13 @@ inline Arena* RepeatedPtrField<Element>::GetOwningArena() const {
template <typename Element> template <typename Element>
inline size_t RepeatedPtrField<Element>::SpaceUsedExcludingSelfLong() const { inline size_t RepeatedPtrField<Element>::SpaceUsedExcludingSelfLong() const {
return RepeatedPtrFieldBase::SpaceUsedExcludingSelfLong<TypeHandler>(); // `google::protobuf::Message` has a virtual method `SpaceUsedLong`, hence we can
// instantiate just one function for all protobuf messages.
// Note: std::is_base_of requires that `Element` is a concrete class.
using H = typename std::conditional<std::is_base_of<Message, Element>::value,
internal::GenericTypeHandler<Message>,
TypeHandler>::type;
return RepeatedPtrFieldBase::SpaceUsedExcludingSelfLong<H>();
} }
template <typename Element> template <typename Element>

Loading…
Cancel
Save