|
|
|
@ -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> |
|
|
|
|