In RepeatedField, rename members and use member accessors.

Motivation: refactoring in preparation for small object optimization in RepeatedField.
PiperOrigin-RevId: 651446582
pull/17389/head
Protobuf Team Bot 5 months ago committed by Copybara-Service
parent 77047d9cda
commit 7fa8718467
  1. 6
      src/google/protobuf/repeated_field.cc
  2. 189
      src/google/protobuf/repeated_field.h
  3. 4
      src/google/protobuf/repeated_field_unittest.cc

@ -12,6 +12,8 @@
#include "google/protobuf/repeated_field.h"
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <string>
#include "absl/log/absl_check.h"
@ -28,8 +30,8 @@ namespace protobuf {
template <>
PROTOBUF_EXPORT_TEMPLATE_DEFINE size_t
RepeatedField<absl::Cord>::SpaceUsedExcludingSelfLong() const {
size_t result = current_size_ * sizeof(absl::Cord);
for (int i = 0; i < current_size_; i++) {
size_t result = size() * sizeof(absl::Cord);
for (int i = 0; i < size(); i++) {
// Estimate only.
result += Get(i).size();
}

@ -295,8 +295,8 @@ class RepeatedField final
// Note: this can be inaccurate for split default fields so we make this
// function non-const.
inline Arena* GetArena() {
return (total_size_ == 0) ? static_cast<Arena*>(arena_or_elements_)
: rep()->arena;
return Capacity() == 0 ? static_cast<Arena*>(arena_or_elements_)
: rep()->arena;
}
// For internal use only.
@ -333,6 +333,9 @@ class RepeatedField final
RepeatedField(Arena* arena, RepeatedField&& rhs);
void set_size(int s) { size_ = s; }
void set_capacity(int c) { capacity_ = c; }
// Swaps entire contents with "other". Should be called only if the caller can
// guarantee that both repeated fields are on the same arena or are on the
// heap. Swapping between different arenas is disallowed and caught by a
@ -373,9 +376,9 @@ class RepeatedField final
// Reserves space to expand the field to at least the given size.
// If the array is grown, it will always be at least doubled in size.
// If `annotate_size` is true (the default), then this function will annotate
// the old container from `current_size` to `total_size_` (unpoison memory)
// the old container from `current_size` to `capacity_` (unpoison memory)
// directly before it is being released, and annotate the new container from
// `total_size_` to `current_size` (poison unused memory).
// `capacity_` to `current_size` (poison unused memory).
void Grow(int current_size, int new_size);
void GrowNoAnnotate(int current_size, int new_size);
@ -386,7 +389,7 @@ class RepeatedField final
void AnnotateSize(int old_size, int new_size) const {
if (old_size != new_size) {
ABSL_ANNOTATE_CONTIGUOUS_CONTAINER(
unsafe_elements(), unsafe_elements() + total_size_,
unsafe_elements(), unsafe_elements() + Capacity(),
unsafe_elements() + old_size, unsafe_elements() + new_size);
if (new_size < old_size) {
ABSL_ANNOTATE_MEMORY_IS_UNINITIALIZED(
@ -396,21 +399,21 @@ class RepeatedField final
}
}
// Replaces current_size_ with new_size and returns the previous value of
// current_size_. This function is intended to be the only place where
// current_size_ is modified, with the exception of `AddInputIterator()`
// Replaces size_ with new_size and returns the previous value of
// size_. This function is intended to be the only place where
// size_ is modified, with the exception of `AddInputIterator()`
// where the size of added items is not known in advance.
inline int ExchangeCurrentSize(int new_size) {
const int prev_size = current_size_;
const int prev_size = size();
AnnotateSize(prev_size, new_size);
current_size_ = new_size;
set_size(new_size);
return prev_size;
}
// Returns a pointer to elements array.
// pre-condition: the array must have been allocated.
Element* elements() const {
ABSL_DCHECK_GT(total_size_, 0);
ABSL_DCHECK_GT(Capacity(), 0);
// Because of above pre-condition this cast is safe.
return unsafe_elements();
}
@ -432,7 +435,7 @@ class RepeatedField final
// Internal helper to delete all elements and deallocate the storage.
template <bool in_destructor = false>
void InternalDeallocate() {
const size_t bytes = total_size_ * sizeof(Element) + kRepHeaderSize;
const size_t bytes = Capacity() * sizeof(Element) + kRepHeaderSize;
if (rep()->arena == nullptr) {
internal::SizedDelete(rep(), bytes);
} else if (!in_destructor) {
@ -452,9 +455,9 @@ class RepeatedField final
// empty (common case), and add only an 8-byte header to the elements array
// when non-empty. We make sure to place the size fields directly in the
// RepeatedField class to avoid costly cache misses due to the indirection.
int current_size_;
int total_size_;
// If total_size_ == 0 this points to an Arena otherwise it points to the
int size_;
int capacity_;
// If capacity_ == 0 this points to an Arena otherwise it points to the
// elements member of a Rep struct. Using this invariant allows the storage of
// the arena pointer without an extra allocation in the constructor.
void* arena_or_elements_;
@ -464,22 +467,22 @@ class RepeatedField final
template <typename Element>
constexpr RepeatedField<Element>::RepeatedField()
: current_size_(0), total_size_(0), arena_or_elements_(nullptr) {
: size_(0), capacity_(0), arena_or_elements_(nullptr) {
StaticValidityCheck();
}
template <typename Element>
inline RepeatedField<Element>::RepeatedField(Arena* arena)
: current_size_(0), total_size_(0), arena_or_elements_(arena) {
: size_(0), capacity_(0), arena_or_elements_(arena) {
StaticValidityCheck();
}
template <typename Element>
inline RepeatedField<Element>::RepeatedField(Arena* arena,
const RepeatedField& rhs)
: current_size_(0), total_size_(0), arena_or_elements_(arena) {
: size_(0), capacity_(0), arena_or_elements_(arena) {
StaticValidityCheck();
if (auto size = rhs.current_size_) {
if (auto size = rhs.size()) {
Grow(0, size);
ExchangeCurrentSize(size);
UninitializedCopyN(rhs.elements(), size, unsafe_elements());
@ -489,7 +492,7 @@ inline RepeatedField<Element>::RepeatedField(Arena* arena,
template <typename Element>
template <typename Iter, typename>
RepeatedField<Element>::RepeatedField(Iter begin, Iter end)
: current_size_(0), total_size_(0), arena_or_elements_(nullptr) {
: size_(0), capacity_(0), arena_or_elements_(nullptr) {
StaticValidityCheck();
Add(begin, end);
}
@ -503,8 +506,8 @@ RepeatedField<Element>::~RepeatedField() {
auto arena = GetArena();
if (arena) (void)arena->SpaceAllocated();
#endif
if (total_size_ > 0) {
Destroy(unsafe_elements(), unsafe_elements() + current_size_);
if (Capacity() > 0) {
Destroy(unsafe_elements(), unsafe_elements() + size());
InternalDeallocate<true>();
}
}
@ -553,42 +556,41 @@ inline RepeatedField<Element>& RepeatedField<Element>::operator=(
template <typename Element>
inline bool RepeatedField<Element>::empty() const {
return current_size_ == 0;
return size() == 0;
}
template <typename Element>
inline int RepeatedField<Element>::size() const {
return current_size_;
return size_;
}
template <typename Element>
inline int RepeatedField<Element>::Capacity() const {
return total_size_;
return capacity_;
}
template <typename Element>
inline void RepeatedField<Element>::AddAlreadyReserved(Element value) {
ABSL_DCHECK_LT(current_size_, total_size_);
void* p = elements() + ExchangeCurrentSize(current_size_ + 1);
ABSL_DCHECK_LT(size(), Capacity());
void* p = elements() + ExchangeCurrentSize(size() + 1);
::new (p) Element(std::move(value));
}
template <typename Element>
inline Element* RepeatedField<Element>::AddAlreadyReserved()
ABSL_ATTRIBUTE_LIFETIME_BOUND {
ABSL_DCHECK_LT(current_size_, total_size_);
ABSL_DCHECK_LT(size(), Capacity());
// new (p) <TrivialType> compiles into nothing: this is intentional as this
// function is documented to return uninitialized data for trivial types.
void* p = elements() + ExchangeCurrentSize(current_size_ + 1);
void* p = elements() + ExchangeCurrentSize(size() + 1);
return ::new (p) Element;
}
template <typename Element>
inline Element* RepeatedField<Element>::AddNAlreadyReserved(int n)
ABSL_ATTRIBUTE_LIFETIME_BOUND {
ABSL_DCHECK_GE(total_size_ - current_size_, n)
<< total_size_ << ", " << current_size_;
Element* p = unsafe_elements() + ExchangeCurrentSize(current_size_ + n);
ABSL_DCHECK_GE(Capacity() - size(), n) << Capacity() << ", " << size();
Element* p = unsafe_elements() + ExchangeCurrentSize(size() + n);
for (Element *begin = p, *end = p + n; begin != end; ++begin) {
new (static_cast<void*>(begin)) Element;
}
@ -598,12 +600,12 @@ inline Element* RepeatedField<Element>::AddNAlreadyReserved(int n)
template <typename Element>
inline void RepeatedField<Element>::Resize(int new_size, const Element& value) {
ABSL_DCHECK_GE(new_size, 0);
if (new_size > current_size_) {
if (new_size > total_size_) Grow(current_size_, new_size);
if (new_size > size()) {
if (new_size > Capacity()) Grow(size(), new_size);
Element* first = elements() + ExchangeCurrentSize(new_size);
std::uninitialized_fill(first, elements() + current_size_, value);
} else if (new_size < current_size_) {
Destroy(unsafe_elements() + new_size, unsafe_elements() + current_size_);
std::uninitialized_fill(first, elements() + size(), value);
} else if (new_size < size()) {
Destroy(unsafe_elements() + new_size, unsafe_elements() + size());
ExchangeCurrentSize(new_size);
}
}
@ -612,7 +614,7 @@ template <typename Element>
inline const Element& RepeatedField<Element>::Get(int index) const
ABSL_ATTRIBUTE_LIFETIME_BOUND {
ABSL_DCHECK_GE(index, 0);
ABSL_DCHECK_LT(index, current_size_);
ABSL_DCHECK_LT(index, size());
return elements()[index];
}
@ -620,7 +622,7 @@ template <typename Element>
inline const Element& RepeatedField<Element>::at(int index) const
ABSL_ATTRIBUTE_LIFETIME_BOUND {
ABSL_CHECK_GE(index, 0);
ABSL_CHECK_LT(index, current_size_);
ABSL_CHECK_LT(index, size());
return elements()[index];
}
@ -628,7 +630,7 @@ template <typename Element>
inline Element& RepeatedField<Element>::at(int index)
ABSL_ATTRIBUTE_LIFETIME_BOUND {
ABSL_CHECK_GE(index, 0);
ABSL_CHECK_LT(index, current_size_);
ABSL_CHECK_LT(index, size());
return elements()[index];
}
@ -636,85 +638,85 @@ template <typename Element>
inline Element* RepeatedField<Element>::Mutable(int index)
ABSL_ATTRIBUTE_LIFETIME_BOUND {
ABSL_DCHECK_GE(index, 0);
ABSL_DCHECK_LT(index, current_size_);
ABSL_DCHECK_LT(index, size());
return &elements()[index];
}
template <typename Element>
inline void RepeatedField<Element>::Set(int index, const Element& value) {
ABSL_DCHECK_GE(index, 0);
ABSL_DCHECK_LT(index, current_size_);
ABSL_DCHECK_LT(index, size());
elements()[index] = value;
}
template <typename Element>
inline void RepeatedField<Element>::Add(Element value) {
int total_size = total_size_;
int capacity = Capacity();
Element* elem = unsafe_elements();
if (ABSL_PREDICT_FALSE(current_size_ == total_size)) {
Grow(current_size_, current_size_ + 1);
total_size = total_size_;
if (ABSL_PREDICT_FALSE(size() == capacity)) {
Grow(size(), size() + 1);
capacity = Capacity();
elem = unsafe_elements();
}
int new_size = current_size_ + 1;
int new_size = size() + 1;
void* p = elem + ExchangeCurrentSize(new_size);
::new (p) Element(std::move(value));
// The below helps the compiler optimize dense loops.
ABSL_ASSUME(new_size == current_size_);
ABSL_ASSUME(new_size == size_);
ABSL_ASSUME(elem == arena_or_elements_);
ABSL_ASSUME(total_size == total_size_);
ABSL_ASSUME(capacity == capacity_);
}
template <typename Element>
inline Element* RepeatedField<Element>::Add() ABSL_ATTRIBUTE_LIFETIME_BOUND {
if (ABSL_PREDICT_FALSE(current_size_ == total_size_)) {
Grow(current_size_, current_size_ + 1);
if (ABSL_PREDICT_FALSE(size() == Capacity())) {
Grow(size(), size() + 1);
}
void* p = unsafe_elements() + ExchangeCurrentSize(current_size_ + 1);
void* p = unsafe_elements() + ExchangeCurrentSize(size() + 1);
return ::new (p) Element;
}
template <typename Element>
template <typename Iter>
inline void RepeatedField<Element>::AddForwardIterator(Iter begin, Iter end) {
int total_size = total_size_;
int capacity = Capacity();
Element* elem = unsafe_elements();
int new_size = current_size_ + static_cast<int>(std::distance(begin, end));
if (ABSL_PREDICT_FALSE(new_size > total_size)) {
Grow(current_size_, new_size);
int new_size = size() + static_cast<int>(std::distance(begin, end));
if (ABSL_PREDICT_FALSE(new_size > capacity)) {
Grow(size(), new_size);
elem = unsafe_elements();
total_size = total_size_;
capacity = Capacity();
}
UninitializedCopy(begin, end, elem + ExchangeCurrentSize(new_size));
// The below helps the compiler optimize dense loops.
ABSL_ASSUME(new_size == current_size_);
ABSL_ASSUME(new_size == size_);
ABSL_ASSUME(elem == arena_or_elements_);
ABSL_ASSUME(total_size == total_size_);
ABSL_ASSUME(capacity == capacity_);
}
template <typename Element>
template <typename Iter>
inline void RepeatedField<Element>::AddInputIterator(Iter begin, Iter end) {
Element* first = unsafe_elements() + current_size_;
Element* last = unsafe_elements() + total_size_;
AnnotateSize(current_size_, total_size_);
Element* first = unsafe_elements() + size();
Element* last = unsafe_elements() + Capacity();
AnnotateSize(size(), Capacity());
while (begin != end) {
if (ABSL_PREDICT_FALSE(first == last)) {
int current_size = first - unsafe_elements();
GrowNoAnnotate(current_size, current_size + 1);
first = unsafe_elements() + current_size;
last = unsafe_elements() + total_size_;
last = unsafe_elements() + Capacity();
}
::new (static_cast<void*>(first)) Element(*begin);
++begin;
++first;
}
current_size_ = first - unsafe_elements();
AnnotateSize(total_size_, current_size_);
set_size(first - unsafe_elements());
AnnotateSize(Capacity(), size());
}
template <typename Element>
@ -731,9 +733,9 @@ inline void RepeatedField<Element>::Add(Iter begin, Iter end) {
template <typename Element>
inline void RepeatedField<Element>::RemoveLast() {
ABSL_DCHECK_GT(current_size_, 0);
elements()[current_size_ - 1].~Element();
ExchangeCurrentSize(current_size_ - 1);
ABSL_DCHECK_GT(size(), 0);
elements()[size() - 1].~Element();
ExchangeCurrentSize(size() - 1);
}
template <typename Element>
@ -741,33 +743,32 @@ void RepeatedField<Element>::ExtractSubrange(int start, int num,
Element* elements) {
ABSL_DCHECK_GE(start, 0);
ABSL_DCHECK_GE(num, 0);
ABSL_DCHECK_LE(start + num, this->current_size_);
ABSL_DCHECK_LE(start + num, size());
// Save the values of the removed elements if requested.
if (elements != nullptr) {
for (int i = 0; i < num; ++i) elements[i] = this->Get(i + start);
for (int i = 0; i < num; ++i) elements[i] = Get(i + start);
}
// Slide remaining elements down to fill the gap.
if (num > 0) {
for (int i = start + num; i < this->current_size_; ++i)
this->Set(i - num, this->Get(i));
this->Truncate(this->current_size_ - num);
for (int i = start + num; i < size(); ++i) Set(i - num, Get(i));
Truncate(size() - num);
}
}
template <typename Element>
inline void RepeatedField<Element>::Clear() {
Destroy(unsafe_elements(), unsafe_elements() + current_size_);
Destroy(unsafe_elements(), unsafe_elements() + size());
ExchangeCurrentSize(0);
}
template <typename Element>
inline void RepeatedField<Element>::MergeFrom(const RepeatedField& other) {
ABSL_DCHECK_NE(&other, this);
if (auto size = other.current_size_) {
Reserve(current_size_ + size);
Element* dst = elements() + ExchangeCurrentSize(current_size_ + size);
if (auto size = other.size()) {
Reserve(this->size() + size);
Element* dst = elements() + ExchangeCurrentSize(this->size() + size);
UninitializedCopyN(other.elements(), size, dst);
}
}
@ -822,7 +823,7 @@ inline void RepeatedField<Element>::InternalSwap(
// Swap all fields at once.
static_assert(std::is_standard_layout<RepeatedField<Element>>::value,
"offsetof() requires standard layout before c++17");
static constexpr size_t kOffset = offsetof(RepeatedField, current_size_);
static constexpr size_t kOffset = offsetof(RepeatedField, size_);
internal::memswap<offsetof(RepeatedField, arena_or_elements_) +
sizeof(this->arena_or_elements_) - kOffset>(
reinterpret_cast<char*>(this) + kOffset,
@ -877,22 +878,22 @@ RepeatedField<Element>::cbegin() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
template <typename Element>
inline typename RepeatedField<Element>::iterator RepeatedField<Element>::end()
ABSL_ATTRIBUTE_LIFETIME_BOUND {
return iterator(unsafe_elements() + current_size_);
return iterator(unsafe_elements() + size());
}
template <typename Element>
inline typename RepeatedField<Element>::const_iterator
RepeatedField<Element>::end() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
return const_iterator(unsafe_elements() + current_size_);
return const_iterator(unsafe_elements() + size());
}
template <typename Element>
inline typename RepeatedField<Element>::const_iterator
RepeatedField<Element>::cend() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
return const_iterator(unsafe_elements() + current_size_);
return const_iterator(unsafe_elements() + size());
}
template <typename Element>
inline size_t RepeatedField<Element>::SpaceUsedExcludingSelfLong() const {
return total_size_ > 0 ? (total_size_ * sizeof(Element) + kRepHeaderSize) : 0;
return Capacity() > 0 ? (Capacity() * sizeof(Element) + kRepHeaderSize) : 0;
}
namespace internal {
@ -926,8 +927,8 @@ inline int CalculateReserveSize(int total_size, int new_size) {
template <typename Element>
void RepeatedField<Element>::Reserve(int new_size) {
if (ABSL_PREDICT_FALSE(new_size > total_size_)) {
Grow(current_size_, new_size);
if (ABSL_PREDICT_FALSE(new_size > Capacity())) {
Grow(size(), new_size);
}
}
@ -936,12 +937,12 @@ void RepeatedField<Element>::Reserve(int new_size) {
template <typename Element>
PROTOBUF_NOINLINE void RepeatedField<Element>::GrowNoAnnotate(int current_size,
int new_size) {
ABSL_DCHECK_GT(new_size, total_size_);
ABSL_DCHECK_GT(new_size, Capacity());
Rep* new_rep;
Arena* arena = GetArena();
new_size = internal::CalculateReserveSize<Element, kRepHeaderSize>(
total_size_, new_size);
new_size = internal::CalculateReserveSize<Element, kRepHeaderSize>(Capacity(),
new_size);
ABSL_DCHECK_LE(
static_cast<size_t>(new_size),
@ -964,7 +965,7 @@ PROTOBUF_NOINLINE void RepeatedField<Element>::GrowNoAnnotate(int current_size,
}
new_rep->arena = arena;
if (total_size_ > 0) {
if (Capacity() > 0) {
if (current_size > 0) {
Element* pnew = new_rep->elements();
Element* pold = elements();
@ -981,7 +982,7 @@ PROTOBUF_NOINLINE void RepeatedField<Element>::GrowNoAnnotate(int current_size,
InternalDeallocate();
}
total_size_ = new_size;
set_capacity(new_size);
arena_or_elements_ = new_rep->elements();
}
@ -993,16 +994,16 @@ PROTOBUF_NOINLINE void RepeatedField<Element>::GrowNoAnnotate(int current_size,
template <typename Element>
PROTOBUF_NOINLINE void RepeatedField<Element>::Grow(int current_size,
int new_size) {
AnnotateSize(current_size, total_size_);
AnnotateSize(current_size, Capacity());
GrowNoAnnotate(current_size, new_size);
AnnotateSize(total_size_, current_size);
AnnotateSize(Capacity(), current_size);
}
template <typename Element>
inline void RepeatedField<Element>::Truncate(int new_size) {
ABSL_DCHECK_LE(new_size, current_size_);
if (new_size < current_size_) {
Destroy(unsafe_elements() + new_size, unsafe_elements() + current_size_);
ABSL_DCHECK_LE(new_size, size());
if (new_size < size()) {
Destroy(unsafe_elements() + new_size, unsafe_elements() + size());
ExchangeCurrentSize(new_size);
}
}

@ -1240,8 +1240,8 @@ TEST(RepeatedField, HardenAgainstBadTruncate) {
for (int size = 0; size < 10; ++size) {
field.Truncate(size);
#if GTEST_HAS_DEATH_TEST
EXPECT_DEBUG_DEATH(field.Truncate(size + 1), "new_size <= current_size_");
EXPECT_DEBUG_DEATH(field.Truncate(size + 2), "new_size <= current_size_");
EXPECT_DEBUG_DEATH(field.Truncate(size + 1), "new_size <= size");
EXPECT_DEBUG_DEATH(field.Truncate(size + 2), "new_size <= size");
#elif defined(NDEBUG)
field.Truncate(size + 1);
field.Truncate(size + 1);

Loading…
Cancel
Save