Automated rollback of commit 17e06c108d.

PiperOrigin-RevId: 571014062
pull/14304/head
Martijn Vels 1 year ago committed by Copybara-Service
parent 34f5364d3c
commit 6cc34ca5aa
  1. 3
      src/google/protobuf/implicit_weak_message.h
  2. 91
      src/google/protobuf/repeated_ptr_field.cc
  3. 127
      src/google/protobuf/repeated_ptr_field.h

@ -186,7 +186,8 @@ struct WeakRepeatedPtrField {
T* Add() { return weak.Add(); }
void Clear() { base().template Clear<TypeHandler>(); }
void MergeFrom(const WeakRepeatedPtrField& other) {
base().template MergeFrom<TypeHandler>(other.base());
if (other.empty()) return;
base().template MergeFrom<MessageLite>(other.base());
}
void InternalSwap(WeakRepeatedPtrField* PROTOBUF_RESTRICT other) {
base().InternalSwap(&other->base());

@ -9,10 +9,12 @@
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <limits>
#include <string>
#include "absl/log/absl_check.h"
#include "google/protobuf/arena.h"
@ -28,7 +30,7 @@ namespace protobuf {
namespace internal {
void RepeatedPtrFieldBase::InternalExtend(int extend_amount) {
void** RepeatedPtrFieldBase::InternalExtend(int extend_amount) {
ABSL_DCHECK(extend_amount > 0);
constexpr size_t ptr_size = sizeof(rep()->elements[0]);
int new_capacity = total_size_ + extend_amount;
@ -74,6 +76,7 @@ void RepeatedPtrFieldBase::InternalExtend(int extend_amount) {
tagged_rep_or_elem_ =
reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(new_rep) + 1);
total_size_ = new_capacity;
return &new_rep->elements[current_size_];
}
void RepeatedPtrFieldBase::Reserve(int capacity) {
@ -151,8 +154,92 @@ template PROTOBUF_EXPORT_TEMPLATE_DEFINE void
memswap<ArenaOffsetHelper<RepeatedPtrFieldBase>::value>(
char* PROTOBUF_RESTRICT, char* PROTOBUF_RESTRICT);
} // namespace internal
template <>
void RepeatedPtrFieldBase::MergeFrom<std::string>(
const RepeatedPtrFieldBase& from) {
ABSL_DCHECK_NE(&from, this);
int new_size = current_size_ + from.current_size_;
auto dst = reinterpret_cast<std::string**>(InternalReserve(new_size));
auto src = reinterpret_cast<std::string* const*>(from.elements());
auto end = src + from.current_size_;
auto end_assign = src + std::min(ClearedCount(), from.current_size_);
for (; src < end_assign; ++dst, ++src) {
(*dst)->assign(**src);
}
if (Arena* const arena = arena_) {
for (; src < end; ++dst, ++src) {
*dst = Arena::Create<std::string>(arena, **src);
}
} else {
for (; src < end; ++dst, ++src) {
*dst = new std::string(**src);
}
}
ExchangeCurrentSize(new_size);
if (new_size > allocated_size()) {
rep()->allocated_size = new_size;
}
}
int RepeatedPtrFieldBase::MergeIntoClearedMessages(
const RepeatedPtrFieldBase& from) {
auto dst = reinterpret_cast<MessageLite**>(elements() + current_size_);
auto src = reinterpret_cast<MessageLite* const*>(from.elements());
int count = std::min(ClearedCount(), from.current_size_);
for (int i = 0; i < count; ++i) {
dst[i]->CheckTypeAndMergeFrom(*src[i]);
}
return count;
}
void RepeatedPtrFieldBase::MergeFromConcreteMessage(
const RepeatedPtrFieldBase& from, CopyFn copy_fn) {
ABSL_DCHECK_NE(&from, this);
int new_size = current_size_ + from.current_size_;
auto dst = reinterpret_cast<MessageLite**>(InternalReserve(new_size));
auto src = reinterpret_cast<MessageLite const* const*>(from.elements());
auto end = src + from.current_size_;
if (PROTOBUF_PREDICT_FALSE(ClearedCount() > 0)) {
int recycled = MergeIntoClearedMessages(from);
dst += recycled;
src += recycled;
}
Arena* arena = GetOwningArena();
for (; src < end; ++src, ++dst) {
*dst = copy_fn(arena, **src);
}
ExchangeCurrentSize(new_size);
if (new_size > allocated_size()) {
rep()->allocated_size = new_size;
}
}
template <>
void RepeatedPtrFieldBase::MergeFrom<MessageLite>(
const RepeatedPtrFieldBase& from) {
ABSL_DCHECK_NE(&from, this);
int new_size = current_size_ + from.current_size_;
auto dst = reinterpret_cast<MessageLite**>(InternalReserve(new_size));
auto src = reinterpret_cast<MessageLite const* const*>(from.elements());
auto end = src + from.current_size_;
if (PROTOBUF_PREDICT_FALSE(ClearedCount() > 0)) {
int recycled = MergeIntoClearedMessages(from);
dst += recycled;
src += recycled;
}
Arena* arena = GetOwningArena();
for (; src < end; ++src, ++dst) {
*dst = (*src)->New(arena);
(*dst)->CheckTypeAndMergeFrom(**src);
}
ExchangeCurrentSize(new_size);
if (new_size > allocated_size()) {
rep()->allocated_size = new_size;
}
}
} // namespace internal
} // namespace protobuf
} // namespace google

@ -296,18 +296,19 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
}
}
template <typename TypeHandler>
void MergeFrom(const RepeatedPtrFieldBase& other) {
// To avoid unnecessary code duplication and reduce binary size, we use a
// layered approach to implementing MergeFrom(). The toplevel method is
// templated, so we get a small thunk per concrete message type in the
// binary. This calls a shared implementation with most of the logic,
// passing a function pointer to another type-specific piece of code that
// calls the object-allocate and merge handlers.
ABSL_DCHECK_NE(&other, this);
if (other.current_size_ == 0) return;
using H = CommonHandler<TypeHandler>;
MergeFromInternal(other, &RepeatedPtrFieldBase::MergeFromInnerLoop<H>);
// Message creating functor: used in MergeFrom<T>()
template <typename T>
static MessageLite* CopyMessage(Arena* arena, const MessageLite& src) {
T* msg = Arena::CreateMaybeMessage<T>(arena);
msg->MergeFrom(static_cast<const T&>(src));
return msg;
}
// Appends all message values from `from` to this instance.
template <typename T>
void MergeFrom(const RepeatedPtrFieldBase& from) {
static_assert(std::is_base_of<MessageLite, T>::value, "");
MergeFromConcreteMessage(from, CopyMessage<T>);
}
inline void InternalSwap(RepeatedPtrFieldBase* PROTOBUF_RESTRICT rhs) {
@ -348,7 +349,8 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
void CopyFrom(const RepeatedPtrFieldBase& other) {
if (&other == this) return;
RepeatedPtrFieldBase::Clear<TypeHandler>();
RepeatedPtrFieldBase::MergeFrom<TypeHandler>(other);
if (other.empty()) return;
RepeatedPtrFieldBase::MergeFrom<typename TypeHandler::Type>(other);
}
void CloseGap(int start, int num);
@ -629,9 +631,10 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
// temporary on |other|'s arena so that messages are copied twice rather
// than three times.
RepeatedPtrFieldBase temp(other->GetOwningArena());
temp.MergeFrom<TypeHandler>(*this);
this->Clear<TypeHandler>();
this->MergeFrom<TypeHandler>(*other);
if (!this->empty()) {
temp.MergeFrom<typename TypeHandler::Type>(*this);
}
this->CopyFrom<TypeHandler>(*other);
other->InternalSwap(&temp);
temp.Destroy<TypeHandler>(); // Frees rep_ if `other` had no arena.
}
@ -683,6 +686,12 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
friend class google::protobuf::Reflection;
friend class internal::SwapFieldHelper;
// Concrete Arena enabled copy function used to copy messages instances.
// This follows the `Arena::CreateMaybeMessage` signature so that the compiler
// can have the inlined call into the out of line copy function(s) simply pass
// the address of `Arena::CreateMaybeMessage` 'as is'.
using CopyFn = MessageLite* (*)(Arena*, const MessageLite&);
struct Rep {
int allocated_size;
// Here we declare a huge array as a way of approximating C's "flexible
@ -763,52 +772,24 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
ExchangeCurrentSize(0);
}
// Non-templated inner function to avoid code duplication. Takes a function
// pointer to the type-specific (templated) inner allocate/merge loop.
PROTOBUF_NOINLINE void MergeFromInternal(
const RepeatedPtrFieldBase& other,
void (RepeatedPtrFieldBase::*inner_loop)(void**, void* const*, int,
int)) {
// Note: wrapper has already guaranteed that `other_size` > 0.
int other_size = other.current_size_;
Reserve(current_size_ + other_size);
void* const* other_elements = other.elements();
void** new_elements = elements() + current_size_;
int allocated_elems = allocated_size() - current_size_;
(this->*inner_loop)(new_elements, other_elements, other_size,
allocated_elems);
ExchangeCurrentSize(current_size_ + other_size);
if (allocated_size() < current_size_) {
rep()->allocated_size = current_size_;
}
}
// Merges messages from `from` into available, cleared messages sitting in the
// range `[size(), allocated_size())`. Returns the number of message merged
// which is `ClearedCount(), from.size())`.
// Note that this function does explicitly NOT update `current_size_`.
// This function is out of line as it should be the slow path: this scenario
// only happens when a caller constructs and fills a repeated field, then
// shrinks it, and then merges additional messages into it.
int MergeIntoClearedMessages(const RepeatedPtrFieldBase& from);
// Merges other_elems to our_elems.
template <typename TypeHandler>
PROTOBUF_NOINLINE void MergeFromInnerLoop(void** our_elems,
void* const* other_elems,
int length, int already_allocated) {
if (already_allocated < length) {
Arena* arena = GetOwningArena();
auto* elem_prototype = cast<TypeHandler>(other_elems[0]);
for (int i = already_allocated; i < length; i++) {
// Allocate a new empty element that we'll merge into below
our_elems[i] = TypeHandler::NewFromPrototype(elem_prototype, arena);
}
}
// Main loop that does the actual merging
for (int i = 0; i < length; i++) {
// Already allocated: use existing element.
auto* other_elem = cast<TypeHandler>(other_elems[i]);
auto* new_elem = cast<TypeHandler>(our_elems[i]);
TypeHandler::Merge(*other_elem, new_elem);
}
}
// Appends all messages from `from` to this instance, using the
// provided `copy_fn` copy function to copy existing messages.
void MergeFromConcreteMessage(const RepeatedPtrFieldBase& from,
CopyFn copy_fn);
// Extends capacity by at least |extend_amount|.
//
// Pre-condition: |extend_amount| must be > 0.
void InternalExtend(int extend_amount);
void** InternalExtend(int extend_amount);
// Ensures that capacity is big enough to store one more allocated element.
inline void MaybeExtend() {
@ -821,6 +802,16 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
}
}
// Ensures that capacity is at least `n` elements.
// Returns a pointer to the element directly beyond the last element.
inline void** InternalReserve(int n) {
if (n <= total_size_) {
void** elements = using_sso() ? &tagged_rep_or_elem_ : rep()->elements;
return elements + current_size_;
}
return InternalExtend(n - total_size_);
}
// Internal helper for Add: adds "obj" as the next element in the
// array, including potentially resizing the array with Reserve if
// needed
@ -843,6 +834,25 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
Arena* arena_;
};
// Appends all message values from `from` to this instance using the abstract
// message interface. This overload is used in places like reflection and
// other locations where the underlying type is unavailable
template <>
void RepeatedPtrFieldBase::MergeFrom<MessageLite>(
const RepeatedPtrFieldBase& from);
template <>
inline void RepeatedPtrFieldBase::MergeFrom<Message>(
const RepeatedPtrFieldBase& from) {
return MergeFrom<MessageLite>(from);
}
// Appends all `std::string` values from `from` to this instance.
template <>
void RepeatedPtrFieldBase::MergeFrom<std::string>(
const RepeatedPtrFieldBase& from);
void InternalOutOfLineDeleteMessageLite(MessageLite* message);
template <typename GenericType>
@ -1579,7 +1589,8 @@ inline void RepeatedPtrField<Element>::Clear() {
template <typename Element>
inline void RepeatedPtrField<Element>::MergeFrom(
const RepeatedPtrField& other) {
RepeatedPtrFieldBase::MergeFrom<TypeHandler>(other);
if (other.empty()) return;
RepeatedPtrFieldBase::MergeFrom<Element>(other);
}
template <typename Element>

Loading…
Cancel
Save