Reduced TypeHandler boilerplate.

PiperOrigin-RevId: 559752947
pull/13645/head
Protobuf Team Bot 2 years ago committed by Copybara-Service
parent 08bbb577e8
commit 45c6352ddd
  1. 129
      src/google/protobuf/repeated_ptr_field.h

@ -169,6 +169,9 @@ struct IsMovable
// static int SpaceUsedLong(const Type&);
// };
class PROTOBUF_EXPORT RepeatedPtrFieldBase {
template <typename Handler>
using Value = typename Handler::Type;
static constexpr int kSSOCapacity = 1;
protected:
@ -199,43 +202,40 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
int Capacity() const { return total_size_; }
template <typename TypeHandler>
const typename TypeHandler::Type& at(int index) const {
const Value<TypeHandler>& at(int index) const {
ABSL_CHECK_GE(index, 0);
ABSL_CHECK_LT(index, current_size_);
return *cast<TypeHandler>(element_at(index));
}
template <typename TypeHandler>
typename TypeHandler::Type& at(int index) {
Value<TypeHandler>& at(int index) {
ABSL_CHECK_GE(index, 0);
ABSL_CHECK_LT(index, current_size_);
return *cast<TypeHandler>(element_at(index));
}
template <typename TypeHandler>
typename TypeHandler::Type* Mutable(int index) {
Value<TypeHandler>* Mutable(int index) {
ABSL_DCHECK_GE(index, 0);
ABSL_DCHECK_LT(index, current_size_);
return cast<TypeHandler>(element_at(index));
}
template <typename TypeHandler>
typename TypeHandler::Type* Add(
const typename TypeHandler::Type* prototype = nullptr) {
Value<TypeHandler>* Add(const Value<TypeHandler>* prototype = nullptr) {
if (current_size_ < allocated_size()) {
return cast<TypeHandler>(
element_at(ExchangeCurrentSize(current_size_ + 1)));
}
typename TypeHandler::Type* result =
TypeHandler::NewFromPrototype(prototype, arena_);
return reinterpret_cast<typename TypeHandler::Type*>(
AddOutOfLineHelper(result));
auto* result = TypeHandler::NewFromPrototype(prototype, arena_);
return cast<TypeHandler>(AddOutOfLineHelper(result));
}
template <
typename TypeHandler,
typename std::enable_if<TypeHandler::Movable::value>::type* = nullptr>
inline void Add(typename TypeHandler::Type&& value) {
inline void Add(Value<TypeHandler>&& value) {
if (current_size_ < allocated_size()) {
*cast<TypeHandler>(element_at(ExchangeCurrentSize(current_size_ + 1))) =
std::move(value);
@ -245,8 +245,7 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
Reserve(total_size_ + 1);
}
if (!using_sso()) ++rep()->allocated_size;
typename TypeHandler::Type* result =
TypeHandler::New(arena_, std::move(value));
auto* result = TypeHandler::New(arena_, std::move(value));
element_at(ExchangeCurrentSize(current_size_ + 1)) = result;
}
@ -254,7 +253,7 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
void Delete(int index) {
ABSL_DCHECK_GE(index, 0);
ABSL_DCHECK_LT(index, current_size_);
TypeHandler::Delete(cast<TypeHandler>(element_at(index)), arena_);
Delete<TypeHandler>(element_at(index), arena_);
}
// Must be called from destructor.
@ -264,7 +263,7 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
if (using_sso()) {
if (tagged_rep_or_elem_ == nullptr) return;
TypeHandler::Delete(cast<TypeHandler>(tagged_rep_or_elem_), nullptr);
Delete<TypeHandler>(tagged_rep_or_elem_, nullptr);
return;
}
@ -272,7 +271,7 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
int n = r->allocated_size;
void* const* elems = r->elements;
for (int i = 0; i < n; i++) {
TypeHandler::Delete(cast<TypeHandler>(elems[i]), nullptr);
Delete<TypeHandler>(elems[i], nullptr);
}
internal::SizedDelete(r, total_size_ * sizeof(elems[0]) + kRepHeaderSize);
}
@ -288,7 +287,7 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
// application code.
template <typename TypeHandler>
const typename TypeHandler::Type& Get(int index) const {
const Value<TypeHandler>& Get(int index) const {
ABSL_DCHECK_GE(index, 0);
ABSL_DCHECK_LT(index, current_size_);
return *cast<TypeHandler>(element_at(index));
@ -341,7 +340,7 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
// Can only be invoked after a call to `PrepareForParse` that returned `true`,
// or other calls to `AddAllocatedForParse`.
template <typename TypeHandler>
void AddAllocatedForParse(typename TypeHandler::Type* value) {
void AddAllocatedForParse(Value<TypeHandler>* value) {
ABSL_DCHECK_EQ(current_size_, allocated_size());
if (current_size_ == total_size_) {
// The array is completely full with no cleared objects, so grow it.
@ -371,8 +370,7 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
void Reserve(int new_size); // implemented in the cc file
template <typename TypeHandler>
static inline typename TypeHandler::Type* copy(
typename TypeHandler::Type* value) {
static inline Value<TypeHandler>* copy(Value<TypeHandler>* value) {
auto* new_value = TypeHandler::NewFromPrototype(value, nullptr);
TypeHandler::Merge(*value, new_value);
return new_value;
@ -383,18 +381,17 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
void** raw_mutable_data() { return elements(); }
template <typename TypeHandler>
typename TypeHandler::Type** mutable_data() {
Value<TypeHandler>** mutable_data() {
// TODO(kenton): Breaks C++ aliasing rules. We should probably remove this
// method entirely.
return reinterpret_cast<typename TypeHandler::Type**>(raw_mutable_data());
return reinterpret_cast<Value<TypeHandler>**>(raw_mutable_data());
}
template <typename TypeHandler>
const typename TypeHandler::Type* const* data() const {
const Value<TypeHandler>* const* data() const {
// TODO(kenton): Breaks C++ aliasing rules. We should probably remove this
// method entirely.
return reinterpret_cast<const typename TypeHandler::Type* const*>(
raw_data());
return reinterpret_cast<const Value<TypeHandler>* const*>(raw_data());
}
template <typename TypeHandler>
@ -436,7 +433,7 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
// Like Add(), but if there are no cleared objects to use, returns nullptr.
template <typename TypeHandler>
typename TypeHandler::Type* AddFromCleared() {
Value<TypeHandler>* AddFromCleared() {
if (current_size_ < allocated_size()) {
return cast<TypeHandler>(
element_at(ExchangeCurrentSize(current_size_ + 1)));
@ -446,13 +443,13 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
}
template <typename TypeHandler>
void AddAllocated(typename TypeHandler::Type* value) {
typename TypeImplementsMergeBehavior<typename TypeHandler::Type>::type t;
void AddAllocated(Value<TypeHandler>* value) {
typename TypeImplementsMergeBehavior<Value<TypeHandler>>::type t;
AddAllocatedInternal<TypeHandler>(value, t);
}
template <typename TypeHandler>
void UnsafeArenaAddAllocated(typename TypeHandler::Type* value) {
void UnsafeArenaAddAllocated(Value<TypeHandler>* value) {
// Make room for the new pointer.
if (current_size_ == total_size_) {
// The array is completely full with no cleared objects, so grow it.
@ -463,7 +460,7 @@ 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.
TypeHandler::Delete(cast<TypeHandler>(element_at(current_size_)), arena_);
Delete<TypeHandler>(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.
@ -478,8 +475,8 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
}
template <typename TypeHandler>
PROTOBUF_NODISCARD typename TypeHandler::Type* ReleaseLast() {
typename TypeImplementsMergeBehavior<typename TypeHandler::Type>::type t;
PROTOBUF_NODISCARD Value<TypeHandler>* ReleaseLast() {
typename TypeImplementsMergeBehavior<Value<TypeHandler>>::type t;
return ReleaseLastInternal<TypeHandler>(t);
}
@ -487,11 +484,10 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
// Instead, just returns the raw pointer to the contained element in the
// arena.
template <typename TypeHandler>
typename TypeHandler::Type* UnsafeArenaReleaseLast() {
Value<TypeHandler>* UnsafeArenaReleaseLast() {
ABSL_DCHECK_GT(current_size_, 0);
ExchangeCurrentSize(current_size_ - 1);
typename TypeHandler::Type* result =
cast<TypeHandler>(element_at(current_size_));
auto* result = cast<TypeHandler>(element_at(current_size_));
if (using_sso()) {
tagged_rep_or_elem_ = nullptr;
} else {
@ -508,7 +504,7 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
int ClearedCount() const { return allocated_size() - current_size_; }
template <typename TypeHandler>
void AddCleared(typename TypeHandler::Type* value) {
void AddCleared(Value<TypeHandler>* value) {
ABSL_DCHECK(GetOwningArena() == nullptr)
<< "AddCleared() can only be used on a "
"RepeatedPtrField not on an arena.";
@ -525,15 +521,14 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
}
template <typename TypeHandler>
PROTOBUF_NODISCARD typename TypeHandler::Type* ReleaseCleared() {
PROTOBUF_NODISCARD Value<TypeHandler>* ReleaseCleared() {
ABSL_DCHECK(GetOwningArena() == nullptr)
<< "ReleaseCleared() can only be used on a RepeatedPtrField not on "
<< "an arena.";
ABSL_DCHECK(tagged_rep_or_elem_ != nullptr);
ABSL_DCHECK_GT(allocated_size(), current_size_);
if (using_sso()) {
auto* result =
reinterpret_cast<typename TypeHandler::Type*>(tagged_rep_or_elem_);
auto* result = cast<TypeHandler>(tagged_rep_or_elem_);
tagged_rep_or_elem_ = nullptr;
return result;
} else {
@ -541,11 +536,10 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
}
}
// AddAllocated version that implements arena-safe copying behavior.
template <typename TypeHandler>
void AddAllocatedInternal(typename TypeHandler::Type* value, std::true_type) {
// AddAllocated version that implements arena-safe copying behavior.
Arena* element_arena =
reinterpret_cast<Arena*>(TypeHandler::GetOwningArena(value));
void AddAllocatedInternal(Value<TypeHandler>* value, std::true_type) {
Arena* element_arena = TypeHandler::GetOwningArena(value);
Arena* arena = GetOwningArena();
if (arena == element_arena && allocated_size() < total_size_) {
// Fast path: underlying arena representation (tagged pointer) is equal to
@ -564,11 +558,9 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
}
}
// AddAllocated version that does not implement arena-safe copying behavior.
template <typename TypeHandler>
void AddAllocatedInternal(
// AddAllocated version that does not implement arena-safe copying
// behavior.
typename TypeHandler::Type* value, std::false_type) {
void AddAllocatedInternal(Value<TypeHandler>* value, std::false_type) {
if (allocated_size() < total_size_) {
// Fast path: underlying arena representation (tagged pointer) is equal to
// our arena pointer, and we can add to array without resizing it (at
@ -591,15 +583,14 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
PROTOBUF_NOINLINE void AddAllocatedSlowWithCopy(
// Pass value_arena and my_arena to avoid duplicate virtual call (value)
// or load (mine).
typename TypeHandler::Type* value, Arena* value_arena, Arena* my_arena) {
Value<TypeHandler>* value, Arena* value_arena, Arena* my_arena) {
// Ensure that either the value is in the same arena, or if not, we do the
// appropriate thing: Own() it (if it's on heap and we're in an arena) or
// copy it to our arena/heap (otherwise).
if (my_arena != nullptr && value_arena == nullptr) {
my_arena->Own(value);
} else if (my_arena != value_arena) {
typename TypeHandler::Type* new_value =
TypeHandler::NewFromPrototype(value, my_arena);
auto* new_value = TypeHandler::NewFromPrototype(value, my_arena);
TypeHandler::Merge(*value, new_value);
TypeHandler::Delete(value, value_arena);
value = new_value;
@ -609,25 +600,24 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
}
template <typename TypeHandler>
typename TypeHandler::Type* ReleaseLastInternal(std::true_type) {
Value<TypeHandler>* ReleaseLastInternal(std::true_type) {
// ReleaseLast() for types that implement merge/copy behavior.
// First, release an element.
typename TypeHandler::Type* result = UnsafeArenaReleaseLast<TypeHandler>();
Value<TypeHandler>* result = UnsafeArenaReleaseLast<TypeHandler>();
// Now perform a copy if we're on an arena.
Arena* arena = GetOwningArena();
typename TypeHandler::Type* new_result;
#ifdef PROTOBUF_FORCE_COPY_IN_RELEASE
new_result = copy<TypeHandler>(result);
auto* new_result = copy<TypeHandler>(result);
if (arena == nullptr) delete result;
#else // PROTOBUF_FORCE_COPY_IN_RELEASE
new_result = (arena == nullptr) ? result : copy<TypeHandler>(result);
auto* new_result = (arena == nullptr) ? result : copy<TypeHandler>(result);
#endif // !PROTOBUF_FORCE_COPY_IN_RELEASE
return new_result;
}
template <typename TypeHandler>
typename TypeHandler::Type* ReleaseLastInternal(std::false_type) {
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
@ -716,9 +706,7 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
// current_size_. This function is intended to be the only place where
// current_size_ is modified.
inline int ExchangeCurrentSize(int new_size) {
int prev_size = current_size_;
current_size_ = new_size;
return prev_size;
return std::exchange(current_size_, new_size);
}
void* const* elements() const {
@ -757,12 +745,16 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
}
template <typename TypeHandler>
static inline typename TypeHandler::Type* cast(void* element) {
return reinterpret_cast<typename TypeHandler::Type*>(element);
static inline Value<TypeHandler>* cast(void* element) {
return reinterpret_cast<Value<TypeHandler>*>(element);
}
template <typename TypeHandler>
static inline const Value<TypeHandler>* cast(const void* element) {
return reinterpret_cast<const Value<TypeHandler>*>(element);
}
template <typename TypeHandler>
static inline const typename TypeHandler::Type* cast(const void* element) {
return reinterpret_cast<const typename TypeHandler::Type*>(element);
static inline void Delete(void* obj, Arena* arena) {
TypeHandler::Delete(cast<TypeHandler>(obj), arena);
}
// Out-of-line helper routine for Clear() once the inlined check has
@ -807,22 +799,17 @@ class PROTOBUF_EXPORT RepeatedPtrFieldBase {
int length, int already_allocated) {
if (already_allocated < length) {
Arena* arena = GetOwningArena();
auto* elem_prototype =
reinterpret_cast<typename TypeHandler::Type*>(other_elems[0]);
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
typename TypeHandler::Type* new_elem =
TypeHandler::NewFromPrototype(elem_prototype, arena);
our_elems[i] = new_elem;
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.
typename TypeHandler::Type* other_elem =
reinterpret_cast<typename TypeHandler::Type*>(other_elems[i]);
typename TypeHandler::Type* new_elem =
reinterpret_cast<typename TypeHandler::Type*>(our_elems[i]);
auto* other_elem = cast<TypeHandler>(other_elems[i]);
auto* new_elem = cast<TypeHandler>(our_elems[i]);
TypeHandler::Merge(*other_elem, new_elem);
}
}

Loading…
Cancel
Save