Coverage Report

Created: 2026-07-16 06:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/abseil-cpp/absl/container/inlined_vector.h
Line
Count
Source
1
// Copyright 2019 The Abseil 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
//      https://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
// -----------------------------------------------------------------------------
16
// File: inlined_vector.h
17
// -----------------------------------------------------------------------------
18
//
19
// This header file contains the declaration and definition of an "inlined
20
// vector" which behaves in an equivalent fashion to a `std::vector`, except
21
// that storage for small sequences of the vector are provided inline without
22
// requiring any heap allocation.
23
//
24
// An `absl::InlinedVector<T, N>` specifies the default capacity `N` as one of
25
// its template parameters. Instances where `size() <= N` hold contained
26
// elements in inline space. Typically `N` is very small so that sequences that
27
// are expected to be short do not require allocations.
28
//
29
// An `absl::InlinedVector` does not usually require a specific allocator. If
30
// the inlined vector grows beyond its initial constraints, it will need to
31
// allocate (as any normal `std::vector` would). This is usually performed with
32
// the default allocator (defined as `std::allocator<T>`). Optionally, a custom
33
// allocator type may be specified as `A` in `absl::InlinedVector<T, N, A>`.
34
35
#ifndef ABSL_CONTAINER_INLINED_VECTOR_H_
36
#define ABSL_CONTAINER_INLINED_VECTOR_H_
37
38
#include <algorithm>
39
#include <cstddef>
40
#include <cstdlib>
41
#include <cstring>
42
#include <initializer_list>
43
#include <iterator>
44
#include <memory>
45
#include <type_traits>
46
#include <utility>
47
48
#include "absl/algorithm/algorithm.h"
49
#include "absl/base/attributes.h"
50
#include "absl/base/internal/hardening.h"
51
#include "absl/base/internal/iterator_traits.h"
52
#include "absl/base/macros.h"
53
#include "absl/base/optimization.h"
54
#include "absl/base/port.h"
55
#include "absl/base/throw_delegate.h"
56
#include "absl/container/internal/inlined_vector.h"
57
#include "absl/hash/internal/weakly_mixed_integer.h"
58
#include "absl/memory/memory.h"
59
#include "absl/meta/type_traits.h"
60
61
namespace absl {
62
ABSL_NAMESPACE_BEGIN
63
// -----------------------------------------------------------------------------
64
// InlinedVector
65
// -----------------------------------------------------------------------------
66
//
67
// An `absl::InlinedVector` is designed to be a drop-in replacement for
68
// `std::vector` for use cases where the vector's size is sufficiently small
69
// that it can be inlined. If the inlined vector does grow beyond its estimated
70
// capacity, it will trigger an initial allocation on the heap, and will behave
71
// as a `std::vector`. The API of the `absl::InlinedVector` within this file is
72
// designed to cover the same API footprint as covered by `std::vector`.
73
template <typename T, size_t N, typename A = std::allocator<T>>
74
class ABSL_ATTRIBUTE_WARN_UNUSED InlinedVector {
75
  static_assert(N > 0, "absl::InlinedVector requires an inlined capacity.");
76
77
  using Storage = inlined_vector_internal::Storage<T, N, A>;
78
79
  template <typename TheA>
80
  using AllocatorTraits = inlined_vector_internal::AllocatorTraits<TheA>;
81
  template <typename TheA>
82
  using MoveIterator = inlined_vector_internal::MoveIterator<TheA>;
83
  template <typename TheA>
84
  using IsMoveAssignOk = inlined_vector_internal::IsMoveAssignOk<TheA>;
85
86
  template <typename TheA, typename Iterator>
87
  using IteratorValueAdapter =
88
      inlined_vector_internal::IteratorValueAdapter<TheA, Iterator>;
89
  template <typename TheA>
90
  using CopyValueAdapter = inlined_vector_internal::CopyValueAdapter<TheA>;
91
  template <typename TheA>
92
  using DefaultValueAdapter =
93
      inlined_vector_internal::DefaultValueAdapter<TheA>;
94
95
  template <typename Iterator>
96
  using EnableIfAtLeastForwardIterator = std::enable_if_t<
97
      base_internal::IsAtLeastForwardIterator<Iterator>::value, int>;
98
  template <typename Iterator>
99
  using DisableIfAtLeastForwardIterator = std::enable_if_t<
100
      !base_internal::IsAtLeastForwardIterator<Iterator>::value, int>;
101
102
  using MemcpyPolicy = typename Storage::MemcpyPolicy;
103
  using ElementwiseAssignPolicy = typename Storage::ElementwiseAssignPolicy;
104
  using ElementwiseConstructPolicy =
105
      typename Storage::ElementwiseConstructPolicy;
106
  using MoveAssignmentPolicy = typename Storage::MoveAssignmentPolicy;
107
108
 public:
109
  using allocator_type = A;
110
  using value_type = inlined_vector_internal::ValueType<A>;
111
  using pointer = inlined_vector_internal::Pointer<A>;
112
  using const_pointer = inlined_vector_internal::ConstPointer<A>;
113
  using size_type = inlined_vector_internal::SizeType<A>;
114
  using difference_type = inlined_vector_internal::DifferenceType<A>;
115
  using reference = inlined_vector_internal::Reference<A>;
116
  using const_reference = inlined_vector_internal::ConstReference<A>;
117
  using iterator = inlined_vector_internal::Iterator<A>;
118
  using const_iterator = inlined_vector_internal::ConstIterator<A>;
119
  using reverse_iterator = inlined_vector_internal::ReverseIterator<A>;
120
  using const_reverse_iterator =
121
      inlined_vector_internal::ConstReverseIterator<A>;
122
123
  // ---------------------------------------------------------------------------
124
  // InlinedVector Constructors and Destructor
125
  // ---------------------------------------------------------------------------
126
127
  // Creates an empty inlined vector with a value-initialized allocator.
128
0
  InlinedVector() noexcept(noexcept(allocator_type())) : storage_() {}
129
130
  // Creates an empty inlined vector with a copy of `allocator`.
131
  explicit InlinedVector(const allocator_type& allocator) noexcept
132
      : storage_(allocator) {}
133
134
  // Creates an inlined vector with `n` copies of `value_type()`.
135
  explicit InlinedVector(size_type n,
136
                         const allocator_type& allocator = allocator_type())
137
      : storage_(allocator) {
138
    if (ABSL_PREDICT_FALSE(n > max_size())) {
139
      ThrowStdLengthError("InlinedVector::InlinedVector failed length check");
140
    }
141
    storage_.Initialize(DefaultValueAdapter<A>(), n);
142
  }
143
144
  // Creates an inlined vector with `n` copies of `v`.
145
  InlinedVector(size_type n, const_reference v,
146
                const allocator_type& allocator = allocator_type())
147
      : storage_(allocator) {
148
    if (ABSL_PREDICT_FALSE(n > max_size())) {
149
      ThrowStdLengthError("InlinedVector::InlinedVector failed length check");
150
    }
151
    storage_.Initialize(CopyValueAdapter<A>(std::addressof(v)), n);
152
  }
153
154
  // Creates an inlined vector with copies of the elements of `list`.
155
  InlinedVector(std::initializer_list<value_type> list,
156
                const allocator_type& allocator = allocator_type())
157
      : InlinedVector(list.begin(), list.end(), allocator) {}
158
159
  // Creates an inlined vector with elements constructed from the provided
160
  // forward iterator range [`first`, `last`).
161
  //
162
  // NOTE: the `enable_if` prevents ambiguous interpretation between a call to
163
  // this constructor with two integral arguments and a call to the above
164
  // `InlinedVector(size_type, const_reference)` constructor.
165
  template <typename ForwardIterator,
166
            EnableIfAtLeastForwardIterator<ForwardIterator> = 0>
167
  InlinedVector(ForwardIterator first, ForwardIterator last,
168
                const allocator_type& allocator = allocator_type())
169
0
      : storage_(allocator) {
170
0
    const size_type s = static_cast<size_type>(std::distance(first, last));
171
0
    if (ABSL_PREDICT_FALSE(s > max_size())) {
172
0
      ThrowStdLengthError("InlinedVector::InlinedVector failed length check");
173
0
    }
174
0
    storage_.Initialize(IteratorValueAdapter<A, ForwardIterator>(first), s);
175
0
  }
176
177
  // Creates an inlined vector with elements constructed from the provided input
178
  // iterator range [`first`, `last`).
179
  template <typename InputIterator,
180
            DisableIfAtLeastForwardIterator<InputIterator> = 0>
181
  InlinedVector(InputIterator first, InputIterator last,
182
                const allocator_type& allocator = allocator_type())
183
      : storage_(allocator) {
184
    std::copy(first, last, std::back_inserter(*this));
185
  }
186
187
  // Creates an inlined vector by copying the contents of `other` using
188
  // `other`'s allocator.
189
  InlinedVector(const InlinedVector& other)
190
      : InlinedVector(other, other.storage_.GetAllocator()) {}
191
192
  // Creates an inlined vector by copying the contents of `other` using the
193
  // provided `allocator`.
194
  InlinedVector(const InlinedVector& other, const allocator_type& allocator)
195
      : storage_(allocator) {
196
    // Fast path: if the other vector is empty, there's nothing for us to do.
197
    if (other.empty()) {
198
      return;
199
    }
200
201
    // Fast path: if the value type is trivially copy constructible, we know the
202
    // allocator doesn't do anything fancy, and there is nothing on the heap
203
    // then we know it is legal for us to simply memcpy the other vector's
204
    // inlined bytes to form our copy of its elements.
205
    if (std::is_trivially_copy_constructible_v<value_type> &&
206
        std::is_same_v<A, std::allocator<value_type>> &&
207
        !other.storage_.GetIsAllocated()) {
208
      storage_.MemcpyFrom(other.storage_);
209
      return;
210
    }
211
212
    storage_.InitFrom(other.storage_);
213
  }
214
215
  // Creates an inlined vector by moving in the contents of `other` without
216
  // allocating. If `other` contains allocated memory, the newly-created inlined
217
  // vector will take ownership of that memory. However, if `other` does not
218
  // contain allocated memory, the newly-created inlined vector will perform
219
  // element-wise move construction of the contents of `other`.
220
  //
221
  // NOTE: since no allocation is performed for the inlined vector in either
222
  // case, the `noexcept(...)` specification depends on whether moving the
223
  // underlying objects can throw. It is assumed assumed that...
224
  //  a) move constructors should only throw due to allocation failure.
225
  //  b) if `value_type`'s move constructor allocates, it uses the same
226
  //     allocation function as the inlined vector's allocator.
227
  // Thus, the move constructor is non-throwing if the allocator is non-throwing
228
  // or `value_type`'s move constructor is specified as `noexcept`.
229
  InlinedVector(InlinedVector&& other) noexcept(
230
      absl::allocator_is_nothrow<allocator_type>::value ||
231
      std::is_nothrow_move_constructible_v<value_type>)
232
      : storage_(other.storage_.GetAllocator()) {
233
    // Fast path: if the value type can be trivially relocated (i.e. moved from
234
    // and destroyed), and we know the allocator doesn't do anything fancy, then
235
    // it's safe for us to simply adopt the contents of the storage for `other`
236
    // and remove its own reference to them. It's as if we had individually
237
    // move-constructed each value and then destroyed the original.
238
    if (absl::is_trivially_relocatable<value_type>::value &&
239
        std::is_same_v<A, std::allocator<value_type>>) {
240
      storage_.MemcpyFrom(other.storage_);
241
      other.storage_.SetInlinedSize(0);
242
      return;
243
    }
244
245
    // Fast path: if the other vector is on the heap, we can simply take over
246
    // its allocation.
247
    if (other.storage_.GetIsAllocated()) {
248
      storage_.SetAllocation({other.storage_.GetAllocatedData(),
249
                              other.storage_.GetAllocatedCapacity()});
250
      storage_.SetAllocatedSize(other.storage_.GetSize());
251
252
      other.storage_.SetInlinedSize(0);
253
      return;
254
    }
255
256
    // Otherwise we must move each element individually.
257
    IteratorValueAdapter<A, MoveIterator<A>> other_values(
258
        MoveIterator<A>(other.storage_.GetInlinedData()));
259
260
    inlined_vector_internal::ConstructElements<A>(
261
        storage_.GetAllocator(), storage_.GetInlinedData(), other_values,
262
        other.storage_.GetSize());
263
264
    storage_.SetInlinedSize(other.storage_.GetSize());
265
  }
266
267
  // Creates an inlined vector by moving in the contents of `other` with a copy
268
  // of `allocator`.
269
  //
270
  // NOTE: if `other`'s allocator is not equal to `allocator`, even if `other`
271
  // contains allocated memory, this move constructor will still allocate. Since
272
  // allocation is performed, this constructor can only be `noexcept` if the
273
  // specified allocator is also `noexcept`.
274
  InlinedVector(
275
      InlinedVector&& other,
276
      const allocator_type&
277
          allocator) noexcept(absl::allocator_is_nothrow<allocator_type>::value)
278
      : storage_(allocator) {
279
    // Fast path: if the value type can be trivially relocated (i.e. moved from
280
    // and destroyed), and we know the allocator doesn't do anything fancy, then
281
    // it's safe for us to simply adopt the contents of the storage for `other`
282
    // and remove its own reference to them. It's as if we had individually
283
    // move-constructed each value and then destroyed the original.
284
    if (absl::is_trivially_relocatable<value_type>::value &&
285
        std::is_same_v<A, std::allocator<value_type>>) {
286
      storage_.MemcpyFrom(other.storage_);
287
      other.storage_.SetInlinedSize(0);
288
      return;
289
    }
290
291
    // Fast path: if the other vector is on the heap and shared the same
292
    // allocator, we can simply take over its allocation.
293
    if ((storage_.GetAllocator() == other.storage_.GetAllocator()) &&
294
        other.storage_.GetIsAllocated()) {
295
      storage_.SetAllocation({other.storage_.GetAllocatedData(),
296
                              other.storage_.GetAllocatedCapacity()});
297
      storage_.SetAllocatedSize(other.storage_.GetSize());
298
299
      other.storage_.SetInlinedSize(0);
300
      return;
301
    }
302
303
    // Otherwise we must move each element individually.
304
    storage_.Initialize(
305
        IteratorValueAdapter<A, MoveIterator<A>>(MoveIterator<A>(other.data())),
306
        other.size());
307
  }
308
309
0
  ~InlinedVector() {}
Unexecuted instantiation: absl::InlinedVector<absl::LogSink*, 16ul, std::__1::allocator<absl::LogSink*> >::~InlinedVector()
Unexecuted instantiation: absl::InlinedVector<absl::str_format_internal::FormatArgImpl, 4ul, std::__1::allocator<absl::str_format_internal::FormatArgImpl> >::~InlinedVector()
310
311
  // ---------------------------------------------------------------------------
312
  // InlinedVector Member Accessors
313
  // ---------------------------------------------------------------------------
314
315
  // `InlinedVector::empty()`
316
  //
317
  // Returns whether the inlined vector contains no elements.
318
  bool empty() const noexcept { return !size(); }
319
320
  // `InlinedVector::size()`
321
  //
322
  // Returns the number of elements in the inlined vector.
323
0
  size_type size() const noexcept { return storage_.GetSize(); }
Unexecuted instantiation: absl::InlinedVector<absl::LogSink*, 16ul, std::__1::allocator<absl::LogSink*> >::size() const
Unexecuted instantiation: absl::InlinedVector<absl::str_format_internal::FormatArgImpl, 4ul, std::__1::allocator<absl::str_format_internal::FormatArgImpl> >::size() const
324
325
  // `InlinedVector::max_size()`
326
  //
327
  // Returns the maximum number of elements the inlined vector can hold.
328
0
  size_type max_size() const noexcept {
329
    // One bit of the size storage is used to indicate whether the inlined
330
    // vector contains allocated memory. As a result, the maximum size that the
331
    // inlined vector can express is the minimum of the limit of how many
332
    // objects we can allocate and std::numeric_limits<size_type>::max() / 2.
333
0
    return (std::min)(AllocatorTraits<A>::max_size(storage_.GetAllocator()),
334
0
                      (std::numeric_limits<size_type>::max)() / 2);
335
0
  }
Unexecuted instantiation: absl::InlinedVector<absl::LogSink*, 16ul, std::__1::allocator<absl::LogSink*> >::max_size() const
Unexecuted instantiation: absl::InlinedVector<absl::str_format_internal::FormatArgImpl, 4ul, std::__1::allocator<absl::str_format_internal::FormatArgImpl> >::max_size() const
336
337
  // `InlinedVector::capacity()`
338
  //
339
  // Returns the number of elements that could be stored in the inlined vector
340
  // without requiring a reallocation.
341
  //
342
  // NOTE: for most inlined vectors, `capacity()` should be equal to the
343
  // template parameter `N`. For inlined vectors which exceed this capacity,
344
  // they will no longer be inlined and `capacity()` will equal the capactity of
345
  // the allocated memory.
346
  size_type capacity() const noexcept {
347
    return storage_.GetIsAllocated() ? storage_.GetAllocatedCapacity()
348
                                     : storage_.GetInlinedCapacity();
349
  }
350
351
  // `InlinedVector::data()`
352
  //
353
  // Returns a `pointer` to the elements of the inlined vector. This pointer
354
  // can be used to access and modify the contained elements.
355
  //
356
  // NOTE: only elements within [`data()`, `data() + size()`) are valid.
357
0
  pointer data() noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
358
0
    return storage_.GetIsAllocated() ? storage_.GetAllocatedData()
359
0
                                     : storage_.GetInlinedData();
360
0
  }
361
362
  // Overload of `InlinedVector::data()` that returns a `const_pointer` to the
363
  // elements of the inlined vector. This pointer can be used to access but not
364
  // modify the contained elements.
365
  //
366
  // NOTE: only elements within [`data()`, `data() + size()`) are valid.
367
0
  const_pointer data() const noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
368
0
    return storage_.GetIsAllocated() ? storage_.GetAllocatedData()
369
0
                                     : storage_.GetInlinedData();
370
0
  }
371
372
  // `InlinedVector::operator[](...)`
373
  //
374
  // Returns a `reference` to the `i`th element of the inlined vector.
375
  reference operator[](size_type i) ABSL_ATTRIBUTE_LIFETIME_BOUND {
376
    absl::base_internal::HardeningAssertLT(i, size());
377
    return data()[i];
378
  }
379
380
  // Overload of `InlinedVector::operator[](...)` that returns a
381
  // `const_reference` to the `i`th element of the inlined vector.
382
  const_reference operator[](size_type i) const ABSL_ATTRIBUTE_LIFETIME_BOUND {
383
    absl::base_internal::HardeningAssertLT(i, size());
384
    return data()[i];
385
  }
386
387
  // `InlinedVector::at(...)`
388
  //
389
  // Returns a `reference` to the `i`th element of the inlined vector.
390
  //
391
  // NOTE: if `i` is not within the required range of `InlinedVector::at(...)`,
392
  // in both debug and non-debug builds, `std::out_of_range` will be thrown.
393
  reference at(size_type i) ABSL_ATTRIBUTE_LIFETIME_BOUND {
394
    if (ABSL_PREDICT_FALSE(i >= size())) {
395
      ThrowStdOutOfRange("InlinedVector::at(size_type) failed bounds check");
396
    }
397
    return data()[i];
398
  }
399
400
  // Overload of `InlinedVector::at(...)` that returns a `const_reference` to
401
  // the `i`th element of the inlined vector.
402
  //
403
  // NOTE: if `i` is not within the required range of `InlinedVector::at(...)`,
404
  // in both debug and non-debug builds, `std::out_of_range` will be thrown.
405
  const_reference at(size_type i) const ABSL_ATTRIBUTE_LIFETIME_BOUND {
406
    if (ABSL_PREDICT_FALSE(i >= size())) {
407
      ThrowStdOutOfRange("InlinedVector::at(size_type) failed bounds check");
408
    }
409
    return data()[i];
410
  }
411
412
  // `InlinedVector::front()`
413
  //
414
  // Returns a `reference` to the first element of the inlined vector.
415
  reference front() ABSL_ATTRIBUTE_LIFETIME_BOUND {
416
    absl::base_internal::HardeningAssertNonEmpty(*this);
417
    return data()[0];
418
  }
419
420
  // Overload of `InlinedVector::front()` that returns a `const_reference` to
421
  // the first element of the inlined vector.
422
  const_reference front() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
423
    absl::base_internal::HardeningAssertNonEmpty(*this);
424
    return data()[0];
425
  }
426
427
  // `InlinedVector::back()`
428
  //
429
  // Returns a `reference` to the last element of the inlined vector.
430
  reference back() ABSL_ATTRIBUTE_LIFETIME_BOUND {
431
    absl::base_internal::HardeningAssertNonEmpty(*this);
432
    return data()[size() - 1];
433
  }
434
435
  // Overload of `InlinedVector::back()` that returns a `const_reference` to the
436
  // last element of the inlined vector.
437
  const_reference back() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
438
    absl::base_internal::HardeningAssertNonEmpty(*this);
439
    return data()[size() - 1];
440
  }
441
442
  // `InlinedVector::begin()`
443
  //
444
  // Returns an `iterator` to the beginning of the inlined vector.
445
  iterator begin() noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND { return data(); }
446
447
  // Overload of `InlinedVector::begin()` that returns a `const_iterator` to
448
  // the beginning of the inlined vector.
449
  const_iterator begin() const noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
450
    return data();
451
  }
452
453
  // `InlinedVector::end()`
454
  //
455
  // Returns an `iterator` to the end of the inlined vector.
456
  iterator end() noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
457
    return data() + size();
458
  }
459
460
  // Overload of `InlinedVector::end()` that returns a `const_iterator` to the
461
  // end of the inlined vector.
462
  const_iterator end() const noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
463
    return data() + size();
464
  }
465
466
  // `InlinedVector::cbegin()`
467
  //
468
  // Returns a `const_iterator` to the beginning of the inlined vector.
469
  const_iterator cbegin() const noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
470
    return begin();
471
  }
472
473
  // `InlinedVector::cend()`
474
  //
475
  // Returns a `const_iterator` to the end of the inlined vector.
476
  const_iterator cend() const noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
477
    return end();
478
  }
479
480
  // `InlinedVector::rbegin()`
481
  //
482
  // Returns a `reverse_iterator` from the end of the inlined vector.
483
  reverse_iterator rbegin() noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
484
    return reverse_iterator(end());
485
  }
486
487
  // Overload of `InlinedVector::rbegin()` that returns a
488
  // `const_reverse_iterator` from the end of the inlined vector.
489
  const_reverse_iterator rbegin() const noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
490
    return const_reverse_iterator(end());
491
  }
492
493
  // `InlinedVector::rend()`
494
  //
495
  // Returns a `reverse_iterator` from the beginning of the inlined vector.
496
  reverse_iterator rend() noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
497
    return reverse_iterator(begin());
498
  }
499
500
  // Overload of `InlinedVector::rend()` that returns a `const_reverse_iterator`
501
  // from the beginning of the inlined vector.
502
  const_reverse_iterator rend() const noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
503
    return const_reverse_iterator(begin());
504
  }
505
506
  // `InlinedVector::crbegin()`
507
  //
508
  // Returns a `const_reverse_iterator` from the end of the inlined vector.
509
  const_reverse_iterator crbegin() const noexcept
510
      ABSL_ATTRIBUTE_LIFETIME_BOUND {
511
    return rbegin();
512
  }
513
514
  // `InlinedVector::crend()`
515
  //
516
  // Returns a `const_reverse_iterator` from the beginning of the inlined
517
  // vector.
518
  const_reverse_iterator crend() const noexcept ABSL_ATTRIBUTE_LIFETIME_BOUND {
519
    return rend();
520
  }
521
522
  // `InlinedVector::get_allocator()`
523
  //
524
  // Returns a copy of the inlined vector's allocator.
525
  allocator_type get_allocator() const { return storage_.GetAllocator(); }
526
527
  // ---------------------------------------------------------------------------
528
  // InlinedVector Member Mutators
529
  // ---------------------------------------------------------------------------
530
531
  // `InlinedVector::operator=(...)`
532
  //
533
  // Replaces the elements of the inlined vector with copies of the elements of
534
  // `list`.
535
  InlinedVector& operator=(std::initializer_list<value_type> list) {
536
    assign(list.begin(), list.end());
537
538
    return *this;
539
  }
540
541
  // Overload of `InlinedVector::operator=(...)` that replaces the elements of
542
  // the inlined vector with copies of the elements of `other`.
543
  InlinedVector& operator=(const InlinedVector& other) {
544
    if (ABSL_PREDICT_TRUE(this != std::addressof(other))) {
545
      const_pointer other_data = other.data();
546
      assign(other_data, other_data + other.size());
547
    }
548
549
    return *this;
550
  }
551
552
  // Overload of `InlinedVector::operator=(...)` that moves the elements of
553
  // `other` into the inlined vector.
554
  //
555
  // NOTE: as a result of calling this overload, `other` is left in a valid but
556
  // unspecified state.
557
  InlinedVector& operator=(InlinedVector&& other) {
558
    if (ABSL_PREDICT_TRUE(this != std::addressof(other))) {
559
      MoveAssignment(MoveAssignmentPolicy{}, std::move(other));
560
    }
561
562
    return *this;
563
  }
564
565
  // `InlinedVector::assign(...)`
566
  //
567
  // Replaces the contents of the inlined vector with `n` copies of `v`.
568
  void assign(size_type n, const_reference v) {
569
    if (ABSL_PREDICT_FALSE(n > max_size())) {
570
      ThrowStdLengthError("InlinedVector::assign failed length check");
571
    }
572
    storage_.Assign(CopyValueAdapter<A>(std::addressof(v)), n);
573
  }
574
575
  // Overload of `InlinedVector::assign(...)` that replaces the contents of the
576
  // inlined vector with copies of the elements of `list`.
577
  void assign(std::initializer_list<value_type> list) {
578
    assign(list.begin(), list.end());
579
  }
580
581
  // Overload of `InlinedVector::assign(...)` to replace the contents of the
582
  // inlined vector with the range [`first`, `last`).
583
  //
584
  // NOTE: this overload is for iterators that are "forward" category or better.
585
  template <typename ForwardIterator,
586
            EnableIfAtLeastForwardIterator<ForwardIterator> = 0>
587
  void assign(ForwardIterator first, ForwardIterator last) {
588
    const size_type s = static_cast<size_type>(std::distance(first, last));
589
    if (ABSL_PREDICT_FALSE(s > max_size())) {
590
      ThrowStdLengthError("InlinedVector::assign failed length check");
591
    }
592
    storage_.Assign(IteratorValueAdapter<A, ForwardIterator>(first), s);
593
  }
594
595
  // Overload of `InlinedVector::assign(...)` to replace the contents of the
596
  // inlined vector with the range [`first`, `last`).
597
  //
598
  // NOTE: this overload is for iterators that are "input" category.
599
  template <typename InputIterator,
600
            DisableIfAtLeastForwardIterator<InputIterator> = 0>
601
  void assign(InputIterator first, InputIterator last) {
602
    size_type i = 0;
603
    for (; i < size() && first != last; ++i, static_cast<void>(++first)) {
604
      data()[i] = *first;
605
    }
606
607
    erase(data() + i, data() + size());
608
    std::copy(first, last, std::back_inserter(*this));
609
  }
610
611
  // `InlinedVector::resize(...)`
612
  //
613
  // Resizes the inlined vector to contain `n` elements.
614
  //
615
  // NOTE: If `n` is smaller than `size()`, extra elements are destroyed. If `n`
616
  // is larger than `size()`, new elements are value-initialized.
617
  void resize(size_type n) {
618
    if (ABSL_PREDICT_FALSE(n > max_size())) {
619
      ThrowStdLengthError("InlinedVector::resize failed length check");
620
    }
621
    storage_.Resize(DefaultValueAdapter<A>(), n);
622
  }
623
624
  // Overload of `InlinedVector::resize(...)` that resizes the inlined vector to
625
  // contain `n` elements.
626
  //
627
  // NOTE: if `n` is smaller than `size()`, extra elements are destroyed. If `n`
628
  // is larger than `size()`, new elements are copied-constructed from `v`.
629
  void resize(size_type n, const_reference v) {
630
    if (ABSL_PREDICT_FALSE(n > max_size())) {
631
      ThrowStdLengthError("InlinedVector::resize failed length check");
632
    }
633
    storage_.Resize(CopyValueAdapter<A>(std::addressof(v)), n);
634
  }
635
636
  // `InlinedVector::insert(...)`
637
  //
638
  // Inserts a copy of `v` at `pos`, returning an `iterator` to the newly
639
  // inserted element.
640
  iterator insert(const_iterator pos,
641
                  const_reference v) ABSL_ATTRIBUTE_LIFETIME_BOUND {
642
    return emplace(pos, v);
643
  }
644
645
  // Overload of `InlinedVector::insert(...)` that inserts `v` at `pos` using
646
  // move semantics, returning an `iterator` to the newly inserted element.
647
  iterator insert(const_iterator pos,
648
                  value_type&& v) ABSL_ATTRIBUTE_LIFETIME_BOUND {
649
    return emplace(pos, std::move(v));
650
  }
651
652
  // Overload of `InlinedVector::insert(...)` that inserts `n` contiguous copies
653
  // of `v` starting at `pos`, returning an `iterator` pointing to the first of
654
  // the newly inserted elements.
655
  iterator insert(const_iterator pos, size_type n,
656
                  const_reference v) ABSL_ATTRIBUTE_LIFETIME_BOUND {
657
    absl::base_internal::HardeningAssertGE(pos, cbegin());
658
    absl::base_internal::HardeningAssertLE(pos, cend());
659
    if (ABSL_PREDICT_FALSE(n > max_size() - size())) {
660
      ThrowStdLengthError("InlinedVector::insert failed length check");
661
    }
662
663
    if (ABSL_PREDICT_TRUE(n != 0)) {
664
      value_type dealias = v;
665
      // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102329#c2
666
      // It appears that GCC thinks that since `pos` is a const pointer and may
667
      // point to uninitialized memory at this point, a warning should be
668
      // issued. But `pos` is actually only used to compute an array index to
669
      // write to.
670
#if !defined(__clang__) && defined(__GNUC__)
671
#pragma GCC diagnostic push
672
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
673
#endif
674
      return storage_.Insert(pos, CopyValueAdapter<A>(std::addressof(dealias)),
675
                             n);
676
#if !defined(__clang__) && defined(__GNUC__)
677
#pragma GCC diagnostic pop
678
#endif
679
    } else {
680
      return const_cast<iterator>(pos);
681
    }
682
  }
683
684
  // Overload of `InlinedVector::insert(...)` that inserts copies of the
685
  // elements of `list` starting at `pos`, returning an `iterator` pointing to
686
  // the first of the newly inserted elements.
687
  iterator insert(const_iterator pos, std::initializer_list<value_type> list)
688
      ABSL_ATTRIBUTE_LIFETIME_BOUND {
689
    return insert(pos, list.begin(), list.end());
690
  }
691
692
  // Overload of `InlinedVector::insert(...)` that inserts the range [`first`,
693
  // `last`) starting at `pos`, returning an `iterator` pointing to the first
694
  // of the newly inserted elements.
695
  //
696
  // NOTE: this overload is for iterators that are "forward" category or better.
697
  template <typename ForwardIterator,
698
            EnableIfAtLeastForwardIterator<ForwardIterator> = 0>
699
  iterator insert(const_iterator pos, ForwardIterator first,
700
                  ForwardIterator last) ABSL_ATTRIBUTE_LIFETIME_BOUND {
701
    absl::base_internal::HardeningAssertGE(pos, cbegin());
702
    absl::base_internal::HardeningAssertLE(pos, cend());
703
    const size_type s = static_cast<size_type>(std::distance(first, last));
704
    if (ABSL_PREDICT_FALSE(s > max_size() - size())) {
705
      ThrowStdLengthError("InlinedVector::insert failed length check");
706
    }
707
708
    if (ABSL_PREDICT_TRUE(first != last)) {
709
      return storage_.Insert(
710
          pos, IteratorValueAdapter<A, ForwardIterator>(first), s);
711
    } else {
712
      return const_cast<iterator>(pos);
713
    }
714
  }
715
716
  // Overload of `InlinedVector::insert(...)` that inserts the range [`first`,
717
  // `last`) starting at `pos`, returning an `iterator` pointing to the first
718
  // of the newly inserted elements.
719
  //
720
  // NOTE: this overload is for iterators that are "input" category.
721
  template <typename InputIterator,
722
            DisableIfAtLeastForwardIterator<InputIterator> = 0>
723
  iterator insert(const_iterator pos, InputIterator first,
724
                  InputIterator last) ABSL_ATTRIBUTE_LIFETIME_BOUND {
725
    absl::base_internal::HardeningAssertGE(pos, cbegin());
726
    absl::base_internal::HardeningAssertLE(pos, cend());
727
728
    size_type index = static_cast<size_type>(std::distance(cbegin(), pos));
729
    for (size_type i = index; first != last; ++i, static_cast<void>(++first)) {
730
      insert(data() + i, *first);
731
    }
732
733
    return iterator(data() + index);
734
  }
735
736
  // `InlinedVector::emplace(...)`
737
  //
738
  // Constructs and inserts an element using `args...` in the inlined vector at
739
  // `pos`, returning an `iterator` pointing to the newly emplaced element.
740
  template <typename... Args>
741
  iterator emplace(const_iterator pos,
742
                   Args&&... args) ABSL_ATTRIBUTE_LIFETIME_BOUND {
743
    absl::base_internal::HardeningAssertGE(pos, cbegin());
744
    absl::base_internal::HardeningAssertLE(pos, cend());
745
    if (ABSL_PREDICT_FALSE(size() == max_size())) {
746
      ThrowStdLengthError("InlinedVector::emplace failed length check");
747
    }
748
749
    value_type dealias(std::forward<Args>(args)...);
750
    // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102329#c2
751
    // It appears that GCC thinks that since `pos` is a const pointer and may
752
    // point to uninitialized memory at this point, a warning should be
753
    // issued. But `pos` is actually only used to compute an array index to
754
    // write to.
755
#if !defined(__clang__) && defined(__GNUC__)
756
#pragma GCC diagnostic push
757
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
758
#endif
759
    return storage_.Insert(pos,
760
                           IteratorValueAdapter<A, MoveIterator<A>>(
761
                               MoveIterator<A>(std::addressof(dealias))),
762
                           1);
763
#if !defined(__clang__) && defined(__GNUC__)
764
#pragma GCC diagnostic pop
765
#endif
766
  }
767
768
  // `InlinedVector::emplace_back(...)`
769
  //
770
  // Constructs and inserts an element using `args...` in the inlined vector at
771
  // `end()`, returning a `reference` to the newly emplaced element.
772
  template <typename... Args>
773
0
  reference emplace_back(Args&&... args) ABSL_ATTRIBUTE_LIFETIME_BOUND {
774
0
    if (ABSL_PREDICT_FALSE(size() == max_size())) {
775
0
      ThrowStdLengthError("InlinedVector::emplace_back failed length check");
776
0
    }
777
0
    return storage_.EmplaceBack(std::forward<Args>(args)...);
778
0
  }
779
780
  // `InlinedVector::push_back(...)`
781
  //
782
  // Inserts a copy of `v` in the inlined vector at `end()`.
783
0
  void push_back(const_reference v) { static_cast<void>(emplace_back(v)); }
784
785
  // Overload of `InlinedVector::push_back(...)` for inserting `v` at `end()`
786
  // using move semantics.
787
  void push_back(value_type&& v) {
788
    static_cast<void>(emplace_back(std::move(v)));
789
  }
790
791
  // `InlinedVector::pop_back()`
792
  //
793
  // Destroys the element at `back()`, reducing the size by `1`.
794
  void pop_back() noexcept {
795
    absl::base_internal::HardeningAssertNonEmpty(*this);
796
797
    AllocatorTraits<A>::destroy(storage_.GetAllocator(), data() + (size() - 1));
798
    storage_.SubtractSize(1);
799
  }
800
801
  // `InlinedVector::erase(...)`
802
  //
803
  // Erases the element at `pos`, returning an `iterator` pointing to where the
804
  // erased element was located.
805
  //
806
  // NOTE: may return `end()`, which is not dereferenceable.
807
  iterator erase(const_iterator pos) ABSL_ATTRIBUTE_LIFETIME_BOUND {
808
    absl::base_internal::HardeningAssertGE(pos, cbegin());
809
    absl::base_internal::HardeningAssertLT(pos, cend());
810
811
    // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102329#c2
812
    // It appears that GCC thinks that since `pos` is a const pointer and may
813
    // point to uninitialized memory at this point, a warning should be
814
    // issued. But `pos` is actually only used to compute an array index to
815
    // write to.
816
#if !defined(__clang__) && defined(__GNUC__)
817
#pragma GCC diagnostic push
818
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
819
#pragma GCC diagnostic ignored "-Wuninitialized"
820
#endif
821
    return storage_.Erase(pos, pos + 1);
822
#if !defined(__clang__) && defined(__GNUC__)
823
#pragma GCC diagnostic pop
824
#endif
825
  }
826
827
  // Overload of `InlinedVector::erase(...)` that erases every element in the
828
  // range [`from`, `to`), returning an `iterator` pointing to where the first
829
  // erased element was located.
830
  //
831
  // NOTE: may return `end()`, which is not dereferenceable.
832
  iterator erase(const_iterator from,
833
                 const_iterator to) ABSL_ATTRIBUTE_LIFETIME_BOUND {
834
    absl::base_internal::HardeningAssertGE(from, cbegin());
835
    absl::base_internal::HardeningAssertLE(from, to);
836
    absl::base_internal::HardeningAssertLE(to, cend());
837
838
    if (ABSL_PREDICT_TRUE(from != to)) {
839
      return storage_.Erase(from, to);
840
    } else {
841
      return const_cast<iterator>(from);
842
    }
843
  }
844
845
  // `InlinedVector::clear()`
846
  //
847
  // Destroys all elements in the inlined vector, setting the size to `0` and
848
  // preserving capacity.
849
0
  void clear() noexcept {
850
0
    inlined_vector_internal::DestroyAdapter<A>::DestroyElements(
851
0
        storage_.GetAllocator(), data(), size());
852
0
    storage_.SetSize(0);
853
0
  }
854
855
  // `InlinedVector::reserve(...)`
856
  //
857
  // Ensures that there is enough room for at least `n` elements.
858
  void reserve(size_type n) {
859
    if (ABSL_PREDICT_FALSE(n > max_size())) {
860
      ThrowStdLengthError("InlinedVector::reserve failed length check");
861
    }
862
    storage_.Reserve(n);
863
  }
864
865
  // `InlinedVector::shrink_to_fit()`
866
  //
867
  // Attempts to reduce memory usage by moving elements to (or keeping elements
868
  // in) the smallest available buffer sufficient for containing `size()`
869
  // elements.
870
  //
871
  // If `size()` is sufficiently small, the elements will be moved into (or kept
872
  // in) the inlined space.
873
  void shrink_to_fit() {
874
    if (storage_.GetIsAllocated()) {
875
      storage_.ShrinkToFit();
876
    }
877
  }
878
879
  // `InlinedVector::swap(...)`
880
  //
881
  // Swaps the contents of the inlined vector with `other`.
882
  void swap(InlinedVector& other) {
883
    if (ABSL_PREDICT_TRUE(this != std::addressof(other))) {
884
      storage_.Swap(std::addressof(other.storage_));
885
    }
886
  }
887
888
 private:
889
  template <typename H, typename TheT, size_t TheN, typename TheA>
890
  friend H AbslHashValue(H h, const absl::InlinedVector<TheT, TheN, TheA>& a);
891
892
  void MoveAssignment(MemcpyPolicy, InlinedVector&& other) {
893
    // Assumption check: we shouldn't be told to use memcpy to implement move
894
    // assignment unless we have trivially destructible elements and an
895
    // allocator that does nothing fancy.
896
    static_assert(std::is_trivially_destructible_v<value_type>, "");
897
    static_assert(std::is_same_v<A, std::allocator<value_type>>, "");
898
899
    // Throw away our existing heap allocation, if any. There is no need to
900
    // destroy the existing elements one by one because we know they are
901
    // trivially destructible.
902
    storage_.DeallocateIfAllocated();
903
904
    // Adopt the other vector's inline elements or heap allocation.
905
    storage_.MemcpyFrom(other.storage_);
906
    other.storage_.SetInlinedSize(0);
907
  }
908
909
  // Destroy our existing elements, if any, and adopt the heap-allocated
910
  // elements of the other vector.
911
  //
912
  // REQUIRES: other.storage_.GetIsAllocated()
913
  void DestroyExistingAndAdopt(InlinedVector&& other) {
914
    absl::base_internal::HardeningAssert(other.storage_.GetIsAllocated());
915
916
    inlined_vector_internal::DestroyAdapter<A>::DestroyElements(
917
        storage_.GetAllocator(), data(), size());
918
    storage_.DeallocateIfAllocated();
919
920
    storage_.MemcpyFrom(other.storage_);
921
    other.storage_.SetInlinedSize(0);
922
  }
923
924
  void MoveAssignment(ElementwiseAssignPolicy, InlinedVector&& other) {
925
    // Fast path: if the other vector is on the heap then we don't worry about
926
    // actually move-assigning each element. Instead we only throw away our own
927
    // existing elements and adopt the heap allocation of the other vector.
928
    if (other.storage_.GetIsAllocated()) {
929
      DestroyExistingAndAdopt(std::move(other));
930
      return;
931
    }
932
933
    storage_.Assign(IteratorValueAdapter<A, MoveIterator<A>>(
934
                        MoveIterator<A>(other.storage_.GetInlinedData())),
935
                    other.size());
936
  }
937
938
  void MoveAssignment(ElementwiseConstructPolicy, InlinedVector&& other) {
939
    // Fast path: if the other vector is on the heap then we don't worry about
940
    // actually move-assigning each element. Instead we only throw away our own
941
    // existing elements and adopt the heap allocation of the other vector.
942
    if (other.storage_.GetIsAllocated()) {
943
      DestroyExistingAndAdopt(std::move(other));
944
      return;
945
    }
946
947
    inlined_vector_internal::DestroyAdapter<A>::DestroyElements(
948
        storage_.GetAllocator(), data(), size());
949
    storage_.DeallocateIfAllocated();
950
951
    if constexpr (!std::is_nothrow_move_constructible_v<value_type>) {
952
      // Reset the size to zero before moving to avoid leaking freed memory if
953
      // an exception is thrown.
954
      storage_.SetInlinedSize(0);
955
    }
956
957
    IteratorValueAdapter<A, MoveIterator<A>> other_values(
958
        MoveIterator<A>(other.storage_.GetInlinedData()));
959
    inlined_vector_internal::ConstructElements<A>(
960
        storage_.GetAllocator(), storage_.GetInlinedData(), other_values,
961
        other.storage_.GetSize());
962
    storage_.SetInlinedSize(other.storage_.GetSize());
963
  }
964
965
  Storage storage_;
966
};
967
968
// -----------------------------------------------------------------------------
969
// InlinedVector Non-Member Functions
970
// -----------------------------------------------------------------------------
971
972
// `swap(...)`
973
//
974
// Swaps the contents of two inlined vectors.
975
template <typename T, size_t N, typename A>
976
void swap(absl::InlinedVector<T, N, A>& a,
977
          absl::InlinedVector<T, N, A>& b) noexcept(noexcept(a.swap(b))) {
978
  a.swap(b);
979
}
980
981
// `operator==(...)`
982
//
983
// Tests for value-equality of two inlined vectors.
984
template <typename T, size_t N, typename A>
985
bool operator==(const absl::InlinedVector<T, N, A>& a,
986
                const absl::InlinedVector<T, N, A>& b) {
987
  auto a_data = a.data();
988
  auto b_data = b.data();
989
  return std::equal(a_data, a_data + a.size(), b_data, b_data + b.size());
990
}
991
992
// `operator!=(...)`
993
//
994
// Tests for value-inequality of two inlined vectors.
995
template <typename T, size_t N, typename A>
996
bool operator!=(const absl::InlinedVector<T, N, A>& a,
997
                const absl::InlinedVector<T, N, A>& b) {
998
  return !(a == b);
999
}
1000
1001
// `operator<(...)`
1002
//
1003
// Tests whether the value of an inlined vector is less than the value of
1004
// another inlined vector using a lexicographical comparison algorithm.
1005
template <typename T, size_t N, typename A>
1006
bool operator<(const absl::InlinedVector<T, N, A>& a,
1007
               const absl::InlinedVector<T, N, A>& b) {
1008
  auto a_data = a.data();
1009
  auto b_data = b.data();
1010
  return std::lexicographical_compare(a_data, a_data + a.size(), b_data,
1011
                                      b_data + b.size());
1012
}
1013
1014
// `operator>(...)`
1015
//
1016
// Tests whether the value of an inlined vector is greater than the value of
1017
// another inlined vector using a lexicographical comparison algorithm.
1018
template <typename T, size_t N, typename A>
1019
bool operator>(const absl::InlinedVector<T, N, A>& a,
1020
               const absl::InlinedVector<T, N, A>& b) {
1021
  return b < a;
1022
}
1023
1024
// `operator<=(...)`
1025
//
1026
// Tests whether the value of an inlined vector is less than or equal to the
1027
// value of another inlined vector using a lexicographical comparison algorithm.
1028
template <typename T, size_t N, typename A>
1029
bool operator<=(const absl::InlinedVector<T, N, A>& a,
1030
                const absl::InlinedVector<T, N, A>& b) {
1031
  return !(b < a);
1032
}
1033
1034
// `operator>=(...)`
1035
//
1036
// Tests whether the value of an inlined vector is greater than or equal to the
1037
// value of another inlined vector using a lexicographical comparison algorithm.
1038
template <typename T, size_t N, typename A>
1039
bool operator>=(const absl::InlinedVector<T, N, A>& a,
1040
                const absl::InlinedVector<T, N, A>& b) {
1041
  return !(a < b);
1042
}
1043
1044
// `AbslHashValue(...)`
1045
//
1046
// Provides `absl::Hash` support for `absl::InlinedVector`. It is uncommon to
1047
// call this directly.
1048
template <typename H, typename T, size_t N, typename A>
1049
H AbslHashValue(H h, const absl::InlinedVector<T, N, A>& a) {
1050
  return H::combine_contiguous(std::move(h), a.data(), a.size());
1051
}
1052
1053
template <typename T, size_t N, typename A, typename Predicate>
1054
constexpr typename InlinedVector<T, N, A>::size_type erase_if(
1055
    InlinedVector<T, N, A>& v, Predicate pred) {
1056
  const auto it = std::remove_if(v.begin(), v.end(), std::move(pred));
1057
  const auto removed = static_cast<typename InlinedVector<T, N, A>::size_type>(
1058
      std::distance(it, v.end()));
1059
  v.erase(it, v.end());
1060
  return removed;
1061
}
1062
1063
ABSL_NAMESPACE_END
1064
}  // namespace absl
1065
1066
#endif  // ABSL_CONTAINER_INLINED_VECTOR_H_