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>
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;
protected:
@ -230,27 +237,24 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
void Delete(int index) {
ABSL_DCHECK_GE(index, 0);
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.
template <typename TypeHandler>
void Destroy() {
using H = CommonHandler<TypeHandler>;
if (arena_ != nullptr) return;
if (using_sso()) {
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;
int n = allocated_size();
void** elems = elements();
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 {
@ -281,7 +285,8 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
const int n = current_size_;
ABSL_DCHECK_GE(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.
ABSL_DCHECK_NE(&other, this);
if (other.current_size_ == 0) return;
MergeFromInternal(other,
&RepeatedPtrFieldBase::MergeFromInnerLoop<TypeHandler>);
using H = CommonHandler<TypeHandler>;
MergeFromInternal(other, &RepeatedPtrFieldBase::MergeFromInnerLoop<H>);
}
inline void InternalSwap(RepeatedPtrFieldBase* PROTOBUF_RESTRICT rhs) {
@ -332,7 +337,8 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
void RemoveLast() {
ABSL_DCHECK_GT(current_size_, 0);
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>
@ -348,9 +354,10 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
template <typename TypeHandler>
static inline Value<TypeHandler>* copy(Value<TypeHandler>* value) {
auto* new_value = TypeHandler::NewFromPrototype(value, nullptr);
TypeHandler::Merge(*value, new_value);
return new_value;
using H = CommonHandler<TypeHandler>;
auto* new_value = H::NewFromPrototype(value, nullptr);
H::Merge(*value, new_value);
return cast<TypeHandler>(new_value);
}
// Used for constructing iterators.
@ -392,7 +399,7 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
}
template <typename TypeHandler>
size_t SpaceUsedExcludingSelfLong() const {
PROTOBUF_NOINLINE size_t SpaceUsedExcludingSelfLong() const {
size_t allocated_bytes =
using_sso()
? 0
@ -437,7 +444,8 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
// cleared objects awaiting reuse. We don't want to grow the array in
// this case because otherwise a loop calling AddAllocated() followed by
// 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()) {
// 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.
@ -568,8 +576,9 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
my_arena->Own(value);
} else if (my_arena != value_arena) {
auto* new_value = TypeHandler::NewFromPrototype(value, my_arena);
TypeHandler::Merge(*value, new_value);
TypeHandler::Delete(value, value_arena);
using H = CommonHandler<TypeHandler>;
H::Merge(*value, new_value);
H::Delete(value, value_arena);
value = new_value;
}
@ -741,9 +750,8 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
const int n = current_size_;
void* const* elems = elements();
int i = 0;
ABSL_DCHECK_GT(
n,
0); // do/while loop to avoid initial test because we know n > 0
ABSL_DCHECK_GT(n, 0);
// do/while loop to avoid initial test because we know n > 0
do {
TypeHandler::Clear(cast<TypeHandler>(elems[i++]));
} while (i < n);
@ -866,7 +874,8 @@ class GenericTypeHandler {
// 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.)
MessageLite* NewFromPrototypeHelper(const MessageLite* prototype, Arena* arena);
PROTOBUF_EXPORT MessageLite* NewFromPrototypeHelper(
const MessageLite* prototype, Arena* arena);
template <>
inline MessageLite* GenericTypeHandler<MessageLite>::NewFromPrototype(
@ -885,8 +894,8 @@ PROTOBUF_NOINLINE inline void GenericTypeHandler<GenericType>::Merge(
to->MergeFrom(from);
}
template <>
void GenericTypeHandler<MessageLite>::Merge(const MessageLite& from,
MessageLite* to);
PROTOBUF_EXPORT void GenericTypeHandler<MessageLite>::Merge(
const MessageLite& from, MessageLite* to);
template <>
inline void GenericTypeHandler<std::string>::Clear(std::string* value) {
@ -1642,7 +1651,13 @@ inline Arena* RepeatedPtrField<Element>::GetOwningArena() const {
template <typename Element>
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>

Loading…
Cancel
Save