chunked_vector.h
Go to the documentation of this file.
1 // Copyright 2021 gRPC authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef GRPC_CORE_LIB_GPRPP_CHUNKED_VECTOR_H
16 #define GRPC_CORE_LIB_GPRPP_CHUNKED_VECTOR_H
17 
19 
20 #include <cstddef>
21 #include <iterator>
22 #include <utility>
23 
24 #include <grpc/support/log.h>
25 
28 
29 namespace grpc_core {
30 
31 // Arena-friendly vector type.
32 // This "vector" allocates non-contiguous runs of kChunkSize T's at a time.
33 // Expectation is that most usage will fit in one chunk, sometimes two will be
34 // needed, and very rarely three. Appending is constant time, calculating the
35 // size is O(n_chunks).
36 template <typename T, size_t kChunkSize>
38  private:
39  // One chunk of allocated memory.
40  struct Chunk {
41  Chunk() = default;
42  Chunk* next = nullptr;
43  size_t count = 0;
45  };
46 
47  public:
49  template <class Iterator>
51  for (; begin != end; ++begin) {
53  }
54  }
56  : ChunkedVector(other.arena_, other.begin(), other.end()) {}
58  ChunkedVector tmp(other);
59  Swap(&tmp);
60  return *this;
61  }
62  ChunkedVector(ChunkedVector&& other) noexcept
63  : arena_(other.arena_), first_(other.first_), append_(other.append_) {
64  other.first_ = nullptr;
65  other.append_ = nullptr;
66  }
67  ChunkedVector& operator=(ChunkedVector&& other) noexcept {
68  Swap(&other);
69  return *this;
70  }
72  void Swap(ChunkedVector* other) {
73  std::swap(other->arena_, arena_);
74  std::swap(other->first_, first_);
75  std::swap(other->append_, append_);
76  }
77 
78  Arena* arena() const { return arena_; }
79 
80  // Append a new element to the end of the vector.
81  template <typename... Args>
83  auto* p = AppendSlot();
84  p->Init(std::forward<Args>(args)...);
85  return &**p;
86  }
87 
88  // Remove the last element and return it.
89  T PopBack() {
90  GPR_ASSERT(append_ != nullptr);
91  if (append_->count == 0) {
93  Chunk* chunk = first_;
94  while (chunk->next != append_) {
95  chunk = chunk->next;
96  }
97  append_ = chunk;
98  }
99  const auto last = append_->count - 1;
100  T result = std::move(*append_->data[last]);
101  append_->data[last].Destroy();
102  append_->count = last;
103  return result;
104  }
105 
106  void Clear() {
107  Chunk* chunk = first_;
108  while (chunk != nullptr && chunk->count != 0) {
109  for (size_t i = 0; i < chunk->count; i++) {
110  chunk->data[i].Destroy();
111  }
112  chunk->count = 0;
113  chunk = chunk->next;
114  }
115  append_ = first_;
116  }
117 
118  // Forward-only iterator.
120  public:
121  ForwardIterator(Chunk* chunk, size_t n) : chunk_(chunk), n_(n) {}
122 
123  using difference_type = std::ptrdiff_t;
124  using iterator_category = std::forward_iterator_tag;
125  using value_type = T;
126  using pointer = T*;
127  using reference = T&;
128 
129  T& operator*() const { return *chunk_->data[n_]; }
130  T* operator->() const { return &*chunk_->data[n_]; }
132  ++n_;
133  while (chunk_ != nullptr && n_ == chunk_->count) {
134  chunk_ = chunk_->next;
135  n_ = 0;
136  }
137  return *this;
138  }
140  ForwardIterator tmp = *this;
141  ++*this;
142  return tmp;
143  }
144  bool operator==(const ForwardIterator& other) const {
145  return chunk_ == other.chunk_ && n_ == other.n_;
146  }
147  bool operator!=(const ForwardIterator& other) const {
148  return !(*this == other);
149  }
150 
151  private:
152  friend class ChunkedVector;
153 
155  size_t n_;
156  };
157 
158  // Const Forward-only iterator.
160  public:
161  ConstForwardIterator(const Chunk* chunk, size_t n) : chunk_(chunk), n_(n) {}
162 
163  using iterator_category = std::forward_iterator_tag;
164 
165  const T& operator*() const { return *chunk_->data[n_]; }
166  const T* operator->() const { return &*chunk_->data[n_]; }
168  ++n_;
169  while (chunk_ != nullptr && n_ == chunk_->count) {
170  chunk_ = chunk_->next;
171  n_ = 0;
172  }
173  return *this;
174  }
176  ConstForwardIterator tmp = *this;
177  ++*this;
178  return tmp;
179  }
180  bool operator==(const ConstForwardIterator& other) const {
181  return chunk_ == other.chunk_ && n_ == other.n_;
182  }
183  bool operator!=(const ConstForwardIterator& other) const {
184  return !(*this == other);
185  }
186 
187  private:
188  const Chunk* chunk_;
189  size_t n_;
190  };
191 
192  ForwardIterator begin() {
193  if (first_ != nullptr && first_->count == 0) return end();
194  return ForwardIterator(first_, 0);
195  }
196  ForwardIterator end() { return ForwardIterator(nullptr, 0); }
197 
198  ConstForwardIterator begin() const {
199  if (first_ != nullptr && first_->count == 0) return cend();
200  return ConstForwardIterator(first_, 0);
201  }
202  ConstForwardIterator end() const { return ConstForwardIterator(nullptr, 0); }
203 
204  ConstForwardIterator cbegin() const { return begin(); }
205  ConstForwardIterator cend() const { return end(); }
206 
207  // Count the number of elements in the vector.
208  size_t size() const {
209  size_t n = 0;
210  for (const Chunk* chunk = first_; chunk != nullptr; chunk = chunk->next) {
211  n += chunk->count;
212  }
213  return n;
214  }
215 
216  // Return true if the vector is empty.
217  bool empty() const { return first_ == nullptr || first_->count == 0; }
218 
219  void SetEnd(ForwardIterator it) {
220  if (it == end()) return;
221  Chunk* chunk = it.chunk_;
222  for (size_t i = it.n_; i < chunk->count; i++) {
223  chunk->data[i].Destroy();
224  }
225  chunk->count = it.n_;
226  append_ = chunk;
227  while ((chunk = chunk->next) != nullptr) {
228  for (size_t i = 0; i < chunk->count; i++) {
229  chunk->data[i].Destroy();
230  }
231  chunk->count = 0;
232  }
233  }
234 
235  private:
237  if (append_ == nullptr) {
238  GPR_ASSERT(first_ == nullptr);
239  first_ = arena_->New<Chunk>();
240  append_ = first_;
241  } else if (append_->count == kChunkSize) {
242  if (append_->next == nullptr) {
243  append_->next = arena_->New<Chunk>();
244  }
245  append_ = append_->next;
246  }
247  return &append_->data[append_->count++];
248  }
249 
251  Chunk* first_ = nullptr;
252  Chunk* append_ = nullptr;
253 };
254 
255 } // namespace grpc_core
256 
257 #endif // GRPC_CORE_LIB_GPRPP_CHUNKED_VECTOR_H
grpc_core::ChunkedVector::ForwardIterator::operator->
T * operator->() const
Definition: chunked_vector.h:130
_gevent_test_main.result
result
Definition: _gevent_test_main.py:96
grpc_core::ChunkedVector::ForwardIterator::operator==
bool operator==(const ForwardIterator &other) const
Definition: chunked_vector.h:144
regen-readme.it
it
Definition: regen-readme.py:15
log.h
grpc_core::ChunkedVector::EmplaceBack
T * EmplaceBack(Args &&... args)
Definition: chunked_vector.h:82
grpc_core::ChunkedVector::ForwardIterator::n_
size_t n_
Definition: chunked_vector.h:155
grpc_core::ChunkedVector::SetEnd
void SetEnd(ForwardIterator it)
Definition: chunked_vector.h:219
grpc_core::ChunkedVector::Clear
void Clear()
Definition: chunked_vector.h:106
grpc_core::ChunkedVector::cbegin
ConstForwardIterator cbegin() const
Definition: chunked_vector.h:204
grpc_core::ChunkedVector::ConstForwardIterator::operator++
ConstForwardIterator & operator++(int)
Definition: chunked_vector.h:175
grpc_core::ChunkedVector::ForwardIterator::difference_type
std::ptrdiff_t difference_type
Definition: chunked_vector.h:123
grpc_core
Definition: call_metric_recorder.h:31
grpc_core::ChunkedVector::begin
ConstForwardIterator begin() const
Definition: chunked_vector.h:198
grpc_core::ChunkedVector::ForwardIterator
Definition: chunked_vector.h:119
grpc_core::ChunkedVector::ForwardIterator::operator!=
bool operator!=(const ForwardIterator &other) const
Definition: chunked_vector.h:147
grpc_core::ChunkedVector::ConstForwardIterator::chunk_
const Chunk * chunk_
Definition: chunked_vector.h:188
grpc_core::Arena::New
T * New(Args &&... args)
Definition: src/core/lib/resource_quota/arena.h:77
grpc_core::ChunkedVector::arena_
Arena * arena_
Definition: chunked_vector.h:250
arena.h
grpc_core::ChunkedVector::Chunk::data
ManualConstructor< T > data[kChunkSize]
Definition: chunked_vector.h:44
grpc_core::ChunkedVector::ConstForwardIterator::n_
size_t n_
Definition: chunked_vector.h:189
grpc_core::ChunkedVector::AppendSlot
ManualConstructor< T > * AppendSlot()
Definition: chunked_vector.h:236
kChunkSize
static constexpr size_t kChunkSize
Definition: chunked_vector_fuzzer.cc:29
grpc_core::ChunkedVector::ConstForwardIterator::operator++
ConstForwardIterator & operator++()
Definition: chunked_vector.h:167
grpc_core::ManualConstructor::Destroy
void Destroy()
Definition: manual_constructor.h:139
grpc_core::Arena
Definition: src/core/lib/resource_quota/arena.h:45
grpc_core::ChunkedVector::end
ConstForwardIterator end() const
Definition: chunked_vector.h:202
T
#define T(upbtypeconst, upbtype, ctype, default_value)
grpc_core::ChunkedVector::Swap
void Swap(ChunkedVector *other)
Definition: chunked_vector.h:72
grpc_core::ChunkedVector::ChunkedVector
ChunkedVector(Arena *arena)
Definition: chunked_vector.h:48
grpc_core::ChunkedVector::~ChunkedVector
~ChunkedVector()
Definition: chunked_vector.h:71
grpc_core::ChunkedVector::PopBack
T PopBack()
Definition: chunked_vector.h:89
grpc_core::ChunkedVector::end
ForwardIterator end()
Definition: chunked_vector.h:196
asyncio_get_stats.args
args
Definition: asyncio_get_stats.py:40
absl::move
constexpr absl::remove_reference_t< T > && move(T &&t) noexcept
Definition: abseil-cpp/absl/utility/utility.h:221
GPR_ASSERT
#define GPR_ASSERT(x)
Definition: include/grpc/impl/codegen/log.h:94
grpc_core::ChunkedVector::ConstForwardIterator::operator!=
bool operator!=(const ConstForwardIterator &other) const
Definition: chunked_vector.h:183
hpack_encoder_fixtures::Args
Args({0, 16384})
grpc_core::ChunkedVector::ChunkedVector
ChunkedVector(ChunkedVector &&other) noexcept
Definition: chunked_vector.h:62
grpc_core::ChunkedVector::ConstForwardIterator::operator->
const T * operator->() const
Definition: chunked_vector.h:166
grpc_core::ChunkedVector::append_
Chunk * append_
Definition: chunked_vector.h:252
grpc_core::ChunkedVector::ForwardIterator::reference
T & reference
Definition: chunked_vector.h:127
grpc_core::ChunkedVector::operator=
ChunkedVector & operator=(const ChunkedVector &other)
Definition: chunked_vector.h:57
grpc_core::ChunkedVector::ForwardIterator::operator++
ForwardIterator & operator++(int)
Definition: chunked_vector.h:139
grpc_core::ChunkedVector::ConstForwardIterator::ConstForwardIterator
ConstForwardIterator(const Chunk *chunk, size_t n)
Definition: chunked_vector.h:161
std::swap
void swap(Json::Value &a, Json::Value &b)
Specialize std::swap() for Json::Value.
Definition: third_party/bloaty/third_party/protobuf/conformance/third_party/jsoncpp/json.h:1226
grpc_core::ChunkedVector::arena
Arena * arena() const
Definition: chunked_vector.h:78
grpc_core::ChunkedVector
Definition: chunked_vector.h:37
n
int n
Definition: abseil-cpp/absl/container/btree_test.cc:1080
manual_constructor.h
grpc_core::ChunkedVector::ConstForwardIterator::operator==
bool operator==(const ConstForwardIterator &other) const
Definition: chunked_vector.h:180
grpc_core::ChunkedVector::Chunk::count
size_t count
Definition: chunked_vector.h:43
grpc_core::ChunkedVector::Chunk::next
Chunk * next
Definition: chunked_vector.h:42
grpc_core::ChunkedVector::Chunk
Definition: chunked_vector.h:40
grpc_core::ChunkedVector::ChunkedVector
ChunkedVector(const ChunkedVector &other)
Definition: chunked_vector.h:55
grpc_core::ChunkedVector::ForwardIterator::operator*
T & operator*() const
Definition: chunked_vector.h:129
count
int * count
Definition: bloaty/third_party/googletest/googlemock/test/gmock_stress_test.cc:96
grpc_core::ChunkedVector::ForwardIterator::value_type
T value_type
Definition: chunked_vector.h:125
grpc_core::ChunkedVector::ForwardIterator::ForwardIterator
ForwardIterator(Chunk *chunk, size_t n)
Definition: chunked_vector.h:121
grpc_core::ChunkedVector::ForwardIterator::iterator_category
std::forward_iterator_tag iterator_category
Definition: chunked_vector.h:124
grpc_core::ChunkedVector::first_
Chunk * first_
Definition: chunked_vector.h:251
grpc_core::ChunkedVector::ConstForwardIterator::operator*
const T & operator*() const
Definition: chunked_vector.h:165
absl::inlined_vector_internal::Iterator
Pointer< A > Iterator
Definition: abseil-cpp/absl/container/internal/inlined_vector.h:64
grpc_core::ChunkedVector::ForwardIterator::operator++
ForwardIterator & operator++()
Definition: chunked_vector.h:131
grpc_core::ChunkedVector::empty
bool empty() const
Definition: chunked_vector.h:217
grpc_core::ChunkedVector::ForwardIterator::chunk_
Chunk * chunk_
Definition: chunked_vector.h:154
grpc_core::ChunkedVector::Chunk::Chunk
Chunk()=default
grpc_core::ChunkedVector::ConstForwardIterator::iterator_category
std::forward_iterator_tag iterator_category
Definition: chunked_vector.h:163
grpc_core::ChunkedVector::ConstForwardIterator
Definition: chunked_vector.h:159
autogen_x86imm.tmp
tmp
Definition: autogen_x86imm.py:12
grpc_core::ChunkedVector::ForwardIterator::pointer
T * pointer
Definition: chunked_vector.h:126
grpc_core::ChunkedVector::cend
ConstForwardIterator cend() const
Definition: chunked_vector.h:205
grpc_core::ChunkedVector::begin
ForwardIterator begin()
Definition: chunked_vector.h:192
grpc_core::ChunkedVector::ChunkedVector
ChunkedVector(Arena *arena, Iterator begin, Iterator end)
Definition: chunked_vector.h:50
grpc_core::ChunkedVector::size
size_t size() const
Definition: chunked_vector.h:208
grpc_core::ChunkedVector::operator=
ChunkedVector & operator=(ChunkedVector &&other) noexcept
Definition: chunked_vector.h:67
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230
grpc_core::ManualConstructor< T >
port_platform.h


grpc
Author(s):
autogenerated on Fri May 16 2025 02:57:54