Coverage Report

Created: 2026-05-12 06:37

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