|
|
|
@ -81,43 +81,6 @@ inline void memswap(char* PROTOBUF_RESTRICT a, char* PROTOBUF_RESTRICT b) { |
|
|
|
|
std::swap_ranges(a, a + N, b); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// type-traits helper for RepeatedPtrFieldBase: we only want to invoke
|
|
|
|
|
// arena-related "copy if on different arena" behavior if the necessary methods
|
|
|
|
|
// exist on the contained type. In particular, we rely on MergeFrom() existing
|
|
|
|
|
// as a general proxy for the fact that a copy will work, and we also provide a
|
|
|
|
|
// specific override for std::string*.
|
|
|
|
|
template <typename T> |
|
|
|
|
struct TypeImplementsMergeBehaviorProbeForMergeFrom { |
|
|
|
|
typedef char HasMerge; |
|
|
|
|
typedef long HasNoMerge; |
|
|
|
|
|
|
|
|
|
// We accept either of:
|
|
|
|
|
// - void MergeFrom(const T& other)
|
|
|
|
|
// - bool MergeFrom(const T& other)
|
|
|
|
|
//
|
|
|
|
|
// We mangle these names a bit to avoid compatibility issues in 'unclean'
|
|
|
|
|
// include environments that may have, e.g., "#define test ..." (yes, this
|
|
|
|
|
// exists).
|
|
|
|
|
template <typename U, typename RetType, RetType (U::*)(const U& arg)> |
|
|
|
|
struct CheckType; |
|
|
|
|
template <typename U> |
|
|
|
|
static HasMerge Check(CheckType<U, void, &U::MergeFrom>*); |
|
|
|
|
template <typename U> |
|
|
|
|
static HasMerge Check(CheckType<U, bool, &U::MergeFrom>*); |
|
|
|
|
template <typename U> |
|
|
|
|
static HasNoMerge Check(...); |
|
|
|
|
|
|
|
|
|
// Resolves to either std::true_type or std::false_type.
|
|
|
|
|
typedef std::integral_constant<bool, |
|
|
|
|
(sizeof(Check<T>(0)) == sizeof(HasMerge))> |
|
|
|
|
type; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
template <typename T> |
|
|
|
|
using TypeImplementsMergeBehavior = |
|
|
|
|
absl::disjunction<std::is_same<T, std::string>, |
|
|
|
|
TypeImplementsMergeBehaviorProbeForMergeFrom<T>>; |
|
|
|
|
|
|
|
|
|
template <typename T> |
|
|
|
|
struct IsMovable |
|
|
|
|
: std::integral_constant<bool, std::is_move_constructible<T>::value && |
|
|
|
@ -420,9 +383,24 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase { |
|
|
|
|
|
|
|
|
|
template <typename TypeHandler> |
|
|
|
|
void AddAllocated(Value<TypeHandler>* value) { |
|
|
|
|
typename TypeImplementsMergeBehavior<Value<TypeHandler>>::type t; |
|
|
|
|
ABSL_DCHECK_NE(value, nullptr); |
|
|
|
|
AddAllocatedInternal<TypeHandler>(value, t); |
|
|
|
|
Arena* element_arena = TypeHandler::GetArena(value); |
|
|
|
|
Arena* arena = GetArena(); |
|
|
|
|
if (arena != element_arena || AllocatedSizeAtCapacity()) { |
|
|
|
|
AddAllocatedSlowWithCopy<TypeHandler>(value, element_arena, arena); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
// Fast path: underlying arena representation (tagged pointer) is equal to
|
|
|
|
|
// our arena pointer, and we can add to array without resizing it (at
|
|
|
|
|
// least one slot that is not allocated).
|
|
|
|
|
void** elems = elements(); |
|
|
|
|
if (current_size_ < allocated_size()) { |
|
|
|
|
// Make space at [current] by moving first allocated element to end of
|
|
|
|
|
// allocated list.
|
|
|
|
|
elems[allocated_size()] = elems[current_size_]; |
|
|
|
|
} |
|
|
|
|
elems[ExchangeCurrentSize(current_size_ + 1)] = value; |
|
|
|
|
if (!using_sso()) ++rep()->allocated_size; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
template <typename TypeHandler> |
|
|
|
@ -455,8 +433,17 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase { |
|
|
|
|
|
|
|
|
|
template <typename TypeHandler> |
|
|
|
|
PROTOBUF_NODISCARD Value<TypeHandler>* ReleaseLast() { |
|
|
|
|
typename TypeImplementsMergeBehavior<Value<TypeHandler>>::type t; |
|
|
|
|
return ReleaseLastInternal<TypeHandler>(t); |
|
|
|
|
Value<TypeHandler>* result = UnsafeArenaReleaseLast<TypeHandler>(); |
|
|
|
|
// Now perform a copy if we're on an arena.
|
|
|
|
|
Arena* arena = GetArena(); |
|
|
|
|
|
|
|
|
|
#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE |
|
|
|
|
auto* new_result = copy<TypeHandler>(result); |
|
|
|
|
if (arena == nullptr) delete result; |
|
|
|
|
#else // PROTOBUF_FORCE_COPY_IN_RELEASE
|
|
|
|
|
auto* new_result = (arena == nullptr) ? result : copy<TypeHandler>(result); |
|
|
|
|
#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE
|
|
|
|
|
return new_result; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Releases and returns the last element, but does not do out-of-arena copy.
|
|
|
|
@ -512,48 +499,6 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// AddAllocated version that implements arena-safe copying behavior.
|
|
|
|
|
template <typename TypeHandler> |
|
|
|
|
void AddAllocatedInternal(Value<TypeHandler>* value, std::true_type) { |
|
|
|
|
Arena* element_arena = TypeHandler::GetArena(value); |
|
|
|
|
Arena* arena = GetArena(); |
|
|
|
|
if (arena != element_arena || AllocatedSizeAtCapacity()) { |
|
|
|
|
AddAllocatedSlowWithCopy<TypeHandler>(value, element_arena, arena); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
// Fast path: underlying arena representation (tagged pointer) is equal to
|
|
|
|
|
// our arena pointer, and we can add to array without resizing it (at
|
|
|
|
|
// least one slot that is not allocated).
|
|
|
|
|
void** elems = elements(); |
|
|
|
|
if (current_size_ < allocated_size()) { |
|
|
|
|
// Make space at [current] by moving first allocated element to end of
|
|
|
|
|
// allocated list.
|
|
|
|
|
elems[allocated_size()] = elems[current_size_]; |
|
|
|
|
} |
|
|
|
|
elems[ExchangeCurrentSize(current_size_ + 1)] = value; |
|
|
|
|
if (!using_sso()) ++rep()->allocated_size; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// AddAllocated version that does not implement arena-safe copying behavior.
|
|
|
|
|
template <typename TypeHandler> |
|
|
|
|
void AddAllocatedInternal(Value<TypeHandler>* value, std::false_type) { |
|
|
|
|
if (AllocatedSizeAtCapacity()) { |
|
|
|
|
UnsafeArenaAddAllocated<TypeHandler>(value); |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
// Fast path: underlying arena representation (tagged pointer) is equal to
|
|
|
|
|
// our arena pointer, and we can add to array without resizing it (at
|
|
|
|
|
// least one slot that is not allocated).
|
|
|
|
|
void** elems = elements(); |
|
|
|
|
if (current_size_ < allocated_size()) { |
|
|
|
|
// Make space at [current] by moving first allocated element to end of
|
|
|
|
|
// allocated list.
|
|
|
|
|
elems[allocated_size()] = elems[current_size_]; |
|
|
|
|
} |
|
|
|
|
elems[ExchangeCurrentSize(current_size_ + 1)] = value; |
|
|
|
|
if (!using_sso()) ++rep()->allocated_size; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Slowpath handles all cases, copying if necessary.
|
|
|
|
|
template <typename TypeHandler> |
|
|
|
|
PROTOBUF_NOINLINE void AddAllocatedSlowWithCopy( |
|
|
|
@ -576,36 +521,6 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase { |
|
|
|
|
UnsafeArenaAddAllocated<TypeHandler>(value); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
template <typename TypeHandler> |
|
|
|
|
Value<TypeHandler>* ReleaseLastInternal(std::true_type) { |
|
|
|
|
// ReleaseLast() for types that implement merge/copy behavior.
|
|
|
|
|
// First, release an element.
|
|
|
|
|
Value<TypeHandler>* result = UnsafeArenaReleaseLast<TypeHandler>(); |
|
|
|
|
// Now perform a copy if we're on an arena.
|
|
|
|
|
Arena* arena = GetArena(); |
|
|
|
|
|
|
|
|
|
#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE |
|
|
|
|
auto* new_result = copy<TypeHandler>(result); |
|
|
|
|
if (arena == nullptr) delete result; |
|
|
|
|
#else // PROTOBUF_FORCE_COPY_IN_RELEASE
|
|
|
|
|
auto* new_result = (arena == nullptr) ? result : copy<TypeHandler>(result); |
|
|
|
|
#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE
|
|
|
|
|
return new_result; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
template <typename TypeHandler> |
|
|
|
|
Value<TypeHandler>* ReleaseLastInternal(std::false_type) { |
|
|
|
|
// ReleaseLast() for types that *do not* implement merge/copy behavior --
|
|
|
|
|
// this is the same as UnsafeArenaReleaseLast(). Note that we
|
|
|
|
|
// ABSL_DCHECK-fail if we're on an arena, since the user really should
|
|
|
|
|
// implement the copy operation in this case.
|
|
|
|
|
ABSL_DCHECK(GetArena() == nullptr) |
|
|
|
|
<< "ReleaseLast() called on a RepeatedPtrField that is on an arena, " |
|
|
|
|
<< "with a type that does not implement MergeFrom. This is unsafe; " |
|
|
|
|
<< "please implement MergeFrom for your type."; |
|
|
|
|
return UnsafeArenaReleaseLast<TypeHandler>(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
template <typename TypeHandler> |
|
|
|
|
PROTOBUF_NOINLINE void SwapFallback(RepeatedPtrFieldBase* other) { |
|
|
|
|
#ifdef PROTOBUF_FORCE_COPY_IN_SWAP |
|
|
|
@ -1323,15 +1238,6 @@ class RepeatedPtrField final : private internal::RepeatedPtrFieldBase { |
|
|
|
|
RepeatedPtrField(Arena* arena, RepeatedPtrField&& rhs); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Implementations for ExtractSubrange(). The copying behavior must be
|
|
|
|
|
// included only if the type supports the necessary operations (e.g.,
|
|
|
|
|
// MergeFrom()), so we must resolve this at compile time. ExtractSubrange()
|
|
|
|
|
// uses SFINAE to choose one of the below implementations.
|
|
|
|
|
void ExtractSubrangeInternal(int start, int num, Element** elements, |
|
|
|
|
std::true_type); |
|
|
|
|
void ExtractSubrangeInternal(int start, int num, Element** elements, |
|
|
|
|
std::false_type); |
|
|
|
|
|
|
|
|
|
void AddAllocatedForParse(Element* p) { |
|
|
|
|
return RepeatedPtrFieldBase::AddAllocatedForParse<TypeHandler>(p); |
|
|
|
|
} |
|
|
|
@ -1508,16 +1414,6 @@ inline void RepeatedPtrField<Element>::DeleteSubrange(int start, int num) { |
|
|
|
|
template <typename Element> |
|
|
|
|
inline void RepeatedPtrField<Element>::ExtractSubrange(int start, int num, |
|
|
|
|
Element** elements) { |
|
|
|
|
typename internal::TypeImplementsMergeBehavior< |
|
|
|
|
typename TypeHandler::Type>::type t; |
|
|
|
|
ExtractSubrangeInternal(start, num, elements, t); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// ExtractSubrange() implementation for types that implement merge/copy
|
|
|
|
|
// behavior.
|
|
|
|
|
template <typename Element> |
|
|
|
|
inline void RepeatedPtrField<Element>::ExtractSubrangeInternal( |
|
|
|
|
int start, int num, Element** elements, std::true_type) { |
|
|
|
|
ABSL_DCHECK_GE(start, 0); |
|
|
|
|
ABSL_DCHECK_GE(num, 0); |
|
|
|
|
ABSL_DCHECK_LE(start + num, size()); |
|
|
|
@ -1555,21 +1451,6 @@ inline void RepeatedPtrField<Element>::ExtractSubrangeInternal( |
|
|
|
|
CloseGap(start, num); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// ExtractSubrange() implementation for types that do not implement merge/copy
|
|
|
|
|
// behavior.
|
|
|
|
|
template <typename Element> |
|
|
|
|
inline void RepeatedPtrField<Element>::ExtractSubrangeInternal( |
|
|
|
|
int start, int num, Element** elements, std::false_type) { |
|
|
|
|
// This case is identical to UnsafeArenaExtractSubrange(). However, since
|
|
|
|
|
// ExtractSubrange() must return heap-allocated objects by contract, and we
|
|
|
|
|
// cannot fulfill this contract if we are an on arena, we must ABSL_DCHECK()
|
|
|
|
|
// that we are not on an arena.
|
|
|
|
|
ABSL_DCHECK(GetArena() == nullptr) |
|
|
|
|
<< "ExtractSubrange() when arena is non-nullptr is only supported when " |
|
|
|
|
<< "the Element type supplies a MergeFrom() operation to make copies."; |
|
|
|
|
UnsafeArenaExtractSubrange(start, num, elements); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
template <typename Element> |
|
|
|
|
inline void RepeatedPtrField<Element>::UnsafeArenaExtractSubrange( |
|
|
|
|
int start, int num, Element** elements) { |
|
|
|
|