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/internal/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
#ifndef ABSL_CONTAINER_INTERNAL_INLINED_VECTOR_H_
16
#define ABSL_CONTAINER_INTERNAL_INLINED_VECTOR_H_
17
18
#include <algorithm>
19
#include <cstddef>
20
#include <cstring>
21
#include <iterator>
22
#include <limits>
23
#include <memory>
24
#include <new>
25
#include <type_traits>
26
#include <utility>
27
28
#include "absl/base/attributes.h"
29
#include "absl/base/config.h"
30
#include "absl/base/internal/hardening.h"
31
#include "absl/base/macros.h"
32
#include "absl/container/internal/compressed_tuple.h"
33
#include "absl/memory/memory.h"
34
#include "absl/meta/type_traits.h"
35
#include "absl/types/span.h"
36
37
namespace absl {
38
ABSL_NAMESPACE_BEGIN
39
namespace inlined_vector_internal {
40
41
// GCC does not deal very well with the below code
42
#if !defined(__clang__) && defined(__GNUC__)
43
#pragma GCC diagnostic push
44
#pragma GCC diagnostic ignored "-Warray-bounds"
45
#endif
46
47
template <typename A>
48
using AllocatorTraits = std::allocator_traits<A>;
49
template <typename A>
50
using ValueType = typename AllocatorTraits<A>::value_type;
51
template <typename A>
52
using SizeType = typename AllocatorTraits<A>::size_type;
53
template <typename A>
54
using Pointer = typename AllocatorTraits<A>::pointer;
55
template <typename A>
56
using ConstPointer = typename AllocatorTraits<A>::const_pointer;
57
template <typename A>
58
using SizeType = typename AllocatorTraits<A>::size_type;
59
template <typename A>
60
using DifferenceType = typename AllocatorTraits<A>::difference_type;
61
template <typename A>
62
using Reference = ValueType<A>&;
63
template <typename A>
64
using ConstReference = const ValueType<A>&;
65
template <typename A>
66
using Iterator = Pointer<A>;
67
template <typename A>
68
using ConstIterator = ConstPointer<A>;
69
template <typename A>
70
using ReverseIterator = typename std::reverse_iterator<Iterator<A>>;
71
template <typename A>
72
using ConstReverseIterator = typename std::reverse_iterator<ConstIterator<A>>;
73
template <typename A>
74
using MoveIterator = typename std::move_iterator<Iterator<A>>;
75
76
template <typename A>
77
using IsMoveAssignOk = std::is_move_assignable<ValueType<A>>;
78
template <typename A>
79
using IsSwapOk = absl::type_traits_internal::IsSwappable<ValueType<A>>;
80
81
template <typename A, bool IsTriviallyDestructible =
82
                          std::is_trivially_destructible_v<ValueType<A>> &&
83
                          std::is_same_v<A, std::allocator<ValueType<A>>>>
84
struct DestroyAdapter;
85
86
template <typename A>
87
struct DestroyAdapter<A, /* IsTriviallyDestructible */ false> {
88
  static void DestroyElements(A& allocator, Pointer<A> destroy_first,
89
                              SizeType<A> destroy_size) {
90
    for (SizeType<A> i = destroy_size; i != 0;) {
91
      --i;
92
      AllocatorTraits<A>::destroy(allocator, destroy_first + i);
93
    }
94
  }
95
};
96
97
template <typename A>
98
struct DestroyAdapter<A, /* IsTriviallyDestructible */ true> {
99
  static void DestroyElements(A& allocator, Pointer<A> destroy_first,
100
0
                              SizeType<A> destroy_size) {
101
0
    static_cast<void>(allocator);
102
0
    static_cast<void>(destroy_first);
103
0
    static_cast<void>(destroy_size);
104
0
  }
Unexecuted instantiation: absl::inlined_vector_internal::DestroyAdapter<std::__1::allocator<absl::LogSink*>, true>::DestroyElements(std::__1::allocator<absl::LogSink*>&, absl::LogSink**, unsigned long)
Unexecuted instantiation: absl::inlined_vector_internal::DestroyAdapter<std::__1::allocator<absl::str_format_internal::FormatArgImpl>, true>::DestroyElements(std::__1::allocator<absl::str_format_internal::FormatArgImpl>&, absl::str_format_internal::FormatArgImpl*, unsigned long)
105
};
106
107
template <typename A>
108
struct Allocation {
109
  Pointer<A> data = nullptr;
110
  SizeType<A> capacity = 0;
111
};
112
113
template <typename A,
114
          bool IsOverAligned =
115
              (alignof(ValueType<A>) > ABSL_INTERNAL_DEFAULT_NEW_ALIGNMENT)>
116
struct MallocAdapter {
117
0
  static Allocation<A> Allocate(A& allocator, SizeType<A> requested_capacity) {
118
0
    return {AllocatorTraits<A>::allocate(allocator, requested_capacity),
119
0
            requested_capacity};
120
0
  }
Unexecuted instantiation: absl::inlined_vector_internal::MallocAdapter<std::__1::allocator<absl::LogSink*>, false>::Allocate(std::__1::allocator<absl::LogSink*>&, unsigned long)
Unexecuted instantiation: absl::inlined_vector_internal::MallocAdapter<std::__1::allocator<absl::str_format_internal::FormatArgImpl>, false>::Allocate(std::__1::allocator<absl::str_format_internal::FormatArgImpl>&, unsigned long)
121
122
  static void Deallocate(A& allocator, Pointer<A> pointer,
123
0
                         SizeType<A> capacity) {
124
0
    AllocatorTraits<A>::deallocate(allocator, pointer, capacity);
125
0
  }
Unexecuted instantiation: absl::inlined_vector_internal::MallocAdapter<std::__1::allocator<absl::LogSink*>, false>::Deallocate(std::__1::allocator<absl::LogSink*>&, absl::LogSink**, unsigned long)
Unexecuted instantiation: absl::inlined_vector_internal::MallocAdapter<std::__1::allocator<absl::str_format_internal::FormatArgImpl>, false>::Deallocate(std::__1::allocator<absl::str_format_internal::FormatArgImpl>&, absl::str_format_internal::FormatArgImpl*, unsigned long)
126
};
127
128
template <typename A, typename ValueAdapter>
129
void ConstructElements(absl::type_identity_t<A>& allocator,
130
                       Pointer<A> construct_first, ValueAdapter& values,
131
0
                       SizeType<A> construct_size) {
132
0
  for (SizeType<A> i = 0; i < construct_size; ++i) {
133
0
    ABSL_INTERNAL_TRY { values.ConstructNext(allocator, construct_first + i); }
134
0
    ABSL_INTERNAL_CATCH_ANY {
135
0
      DestroyAdapter<A>::DestroyElements(allocator, construct_first, i);
136
0
      ABSL_INTERNAL_RETHROW;
137
0
    }
138
0
  }
139
0
}
Unexecuted instantiation: void absl::inlined_vector_internal::ConstructElements<std::__1::allocator<absl::LogSink*>, absl::inlined_vector_internal::IteratorValueAdapter<std::__1::allocator<absl::LogSink*>, std::__1::move_iterator<absl::LogSink**> > >(absl::type_identity<std::__1::allocator<absl::LogSink*> >::type&, std::__1::allocator_traits<std::__1::allocator<absl::LogSink*> >::pointer, absl::inlined_vector_internal::IteratorValueAdapter<std::__1::allocator<absl::LogSink*>, std::__1::move_iterator<absl::LogSink**> >&, std::__1::allocator_traits<std::__1::allocator<absl::LogSink*> >::size_type)
Unexecuted instantiation: void absl::inlined_vector_internal::ConstructElements<std::__1::allocator<absl::str_format_internal::FormatArgImpl>, absl::inlined_vector_internal::IteratorValueAdapter<std::__1::allocator<absl::str_format_internal::FormatArgImpl>, absl::str_format_internal::FormatArgImpl const*> >(absl::type_identity<std::__1::allocator<absl::str_format_internal::FormatArgImpl> >::type&, std::__1::allocator_traits<std::__1::allocator<absl::str_format_internal::FormatArgImpl> >::pointer, absl::inlined_vector_internal::IteratorValueAdapter<std::__1::allocator<absl::str_format_internal::FormatArgImpl>, absl::str_format_internal::FormatArgImpl const*>&, std::__1::allocator_traits<std::__1::allocator<absl::str_format_internal::FormatArgImpl> >::size_type)
140
141
template <typename A, typename ValueAdapter>
142
void AssignElements(Pointer<A> assign_first, ValueAdapter& values,
143
                    SizeType<A> assign_size) {
144
  for (SizeType<A> i = 0; i < assign_size; ++i) {
145
    values.AssignNext(assign_first + i);
146
  }
147
}
148
149
template <typename A>
150
struct StorageView {
151
  Pointer<A> data;
152
  SizeType<A> size;
153
  SizeType<A> capacity;
154
};
155
156
template <typename A, typename Iterator>
157
class IteratorValueAdapter {
158
 public:
159
0
  explicit IteratorValueAdapter(const Iterator& it) : it_(it) {}
160
161
0
  void ConstructNext(A& allocator, Pointer<A> construct_at) {
162
0
    AllocatorTraits<A>::construct(allocator, construct_at, *it_);
163
0
    ++it_;
164
0
  }
Unexecuted instantiation: absl::inlined_vector_internal::IteratorValueAdapter<std::__1::allocator<absl::LogSink*>, std::__1::move_iterator<absl::LogSink**> >::ConstructNext(std::__1::allocator<absl::LogSink*>&, absl::LogSink**)
Unexecuted instantiation: absl::inlined_vector_internal::IteratorValueAdapter<std::__1::allocator<absl::str_format_internal::FormatArgImpl>, absl::str_format_internal::FormatArgImpl const*>::ConstructNext(std::__1::allocator<absl::str_format_internal::FormatArgImpl>&, absl::str_format_internal::FormatArgImpl*)
165
166
  void AssignNext(Pointer<A> assign_at) {
167
    *assign_at = *it_;
168
    ++it_;
169
  }
170
171
 private:
172
  Iterator it_;
173
};
174
175
template <typename A>
176
class CopyValueAdapter {
177
 public:
178
  explicit CopyValueAdapter(ConstPointer<A> p) : ptr_(p) {}
179
180
  void ConstructNext(A& allocator, Pointer<A> construct_at) {
181
    AllocatorTraits<A>::construct(allocator, construct_at, *ptr_);
182
  }
183
184
  void AssignNext(Pointer<A> assign_at) { *assign_at = *ptr_; }
185
186
 private:
187
  ConstPointer<A> ptr_;
188
};
189
190
template <typename A>
191
class DefaultValueAdapter {
192
 public:
193
  explicit DefaultValueAdapter() {}
194
195
  void ConstructNext(A& allocator, Pointer<A> construct_at) {
196
    AllocatorTraits<A>::construct(allocator, construct_at);
197
  }
198
199
  void AssignNext(Pointer<A> assign_at) { *assign_at = ValueType<A>(); }
200
};
201
202
template <typename A>
203
class AllocationTransaction {
204
 public:
205
  explicit AllocationTransaction(A& allocator)
206
0
      : allocator_data_(allocator, nullptr), capacity_(0) {}
207
208
0
  ~AllocationTransaction() {
209
0
    if (DidAllocate()) {
210
0
      MallocAdapter<A>::Deallocate(GetAllocator(), GetData(), GetCapacity());
211
0
    }
212
0
  }
213
214
  AllocationTransaction(const AllocationTransaction&) = delete;
215
  void operator=(const AllocationTransaction&) = delete;
216
217
0
  A& GetAllocator() { return allocator_data_.template get<0>(); }
218
0
  Pointer<A>& GetData() { return allocator_data_.template get<1>(); }
219
0
  SizeType<A>& GetCapacity() { return capacity_; }
220
221
0
  bool DidAllocate() { return GetData() != nullptr; }
222
223
0
  Pointer<A> Allocate(SizeType<A> requested_capacity) {
224
0
    Allocation<A> result =
225
0
        MallocAdapter<A>::Allocate(GetAllocator(), requested_capacity);
226
0
    GetData() = result.data;
227
0
    GetCapacity() = result.capacity;
228
0
    return result.data;
229
0
  }
230
231
0
  [[nodiscard]] Allocation<A> Release() && {
232
0
    Allocation<A> result = {GetData(), GetCapacity()};
233
0
    Reset();
234
0
    return result;
235
0
  }
236
237
 private:
238
0
  void Reset() {
239
0
    GetData() = nullptr;
240
0
    GetCapacity() = 0;
241
0
  }
242
243
  container_internal::CompressedTuple<A, Pointer<A>> allocator_data_;
244
  SizeType<A> capacity_;
245
};
246
247
template <typename A>
248
class ConstructionTransaction {
249
 public:
250
  explicit ConstructionTransaction(A& allocator)
251
      : allocator_data_(allocator, nullptr), size_(0) {}
252
253
  ~ConstructionTransaction() {
254
    if (DidConstruct()) {
255
      DestroyAdapter<A>::DestroyElements(GetAllocator(), GetData(), GetSize());
256
    }
257
  }
258
259
  ConstructionTransaction(const ConstructionTransaction&) = delete;
260
  void operator=(const ConstructionTransaction&) = delete;
261
262
  A& GetAllocator() { return allocator_data_.template get<0>(); }
263
  Pointer<A>& GetData() { return allocator_data_.template get<1>(); }
264
  SizeType<A>& GetSize() { return size_; }
265
266
  bool DidConstruct() { return GetData() != nullptr; }
267
  template <typename ValueAdapter>
268
  void Construct(Pointer<A> data, ValueAdapter& values, SizeType<A> size) {
269
    ConstructElements<A>(GetAllocator(), data, values, size);
270
    GetData() = data;
271
    GetSize() = size;
272
  }
273
  void Commit() && {
274
    GetData() = nullptr;
275
    GetSize() = 0;
276
  }
277
278
 private:
279
  container_internal::CompressedTuple<A, Pointer<A>> allocator_data_;
280
  SizeType<A> size_;
281
};
282
283
template <typename T, size_t N, typename A>
284
class Storage {
285
 public:
286
  struct MemcpyPolicy {};
287
  struct ElementwiseAssignPolicy {};
288
  struct ElementwiseSwapPolicy {};
289
  struct ElementwiseConstructPolicy {};
290
291
  using MoveAssignmentPolicy = std::conditional_t<
292
      // Fast path: if the value type can be trivially move assigned and
293
      // destroyed, and we know the allocator doesn't do anything fancy, then
294
      // it's safe for us to simply adopt the contents of the storage for
295
      // `other` and remove its own reference to them. It's as if we had
296
      // individually move-assigned each value and then destroyed the original.
297
      std::conjunction_v<std::is_trivially_move_assignable<ValueType<A>>,
298
                         std::is_trivially_destructible<ValueType<A>>,
299
                         std::is_same<A, std::allocator<ValueType<A>>>>,
300
      MemcpyPolicy,
301
      // Otherwise we use move assignment if possible. If not, we simulate
302
      // move assignment using move construction.
303
      //
304
      // Note that this is in contrast to e.g. std::vector and std::optional,
305
      // which are themselves not move-assignable when their contained type is
306
      // not.
307
      std::conditional_t<IsMoveAssignOk<A>::value, ElementwiseAssignPolicy,
308
                         ElementwiseConstructPolicy>>;
309
310
  // The policy to be used specifically when swapping inlined elements.
311
  using SwapInlinedElementsPolicy = std::conditional_t<
312
      // Fast path: if the value type can be trivially relocated, and we
313
      // know the allocator doesn't do anything fancy, then it's safe for us
314
      // to simply swap the bytes in the inline storage. It's as if we had
315
      // relocated the first vector's elements into temporary storage,
316
      // relocated the second's elements into the (now-empty) first's,
317
      // and then relocated from temporary storage into the second.
318
      std::conjunction_v<absl::is_trivially_relocatable<ValueType<A>>,
319
                         std::is_same<A, std::allocator<ValueType<A>>>>,
320
      MemcpyPolicy,
321
      std::conditional_t<IsSwapOk<A>::value, ElementwiseSwapPolicy,
322
                         ElementwiseConstructPolicy>>;
323
324
0
  static SizeType<A> NextCapacity(SizeType<A> current_capacity) {
325
0
    return current_capacity * 2;
326
0
  }
Unexecuted instantiation: absl::inlined_vector_internal::Storage<absl::LogSink*, 16ul, std::__1::allocator<absl::LogSink*> >::NextCapacity(unsigned long)
Unexecuted instantiation: absl::inlined_vector_internal::Storage<absl::str_format_internal::FormatArgImpl, 4ul, std::__1::allocator<absl::str_format_internal::FormatArgImpl> >::NextCapacity(unsigned long)
327
328
  static SizeType<A> ComputeCapacity(SizeType<A> current_capacity,
329
0
                                     SizeType<A> requested_capacity) {
330
0
    return (std::max)(NextCapacity(current_capacity), requested_capacity);
331
0
  }
332
333
  // ---------------------------------------------------------------------------
334
  // Storage Constructors and Destructor
335
  // ---------------------------------------------------------------------------
336
337
0
  Storage() : metadata_(A(), /* size and is_allocated */ 0u) {}
338
339
  explicit Storage(const A& allocator)
340
0
      : metadata_(allocator, /* size and is_allocated */ 0u) {}
341
342
0
  ~Storage() {
343
    // Fast path: if we are empty and not allocated, there's nothing to do.
344
0
    if (GetSizeAndIsAllocated() == 0) {
345
0
      return;
346
0
    }
347
348
    // Fast path: if no destructors need to be run and we know the allocator
349
    // doesn't do anything fancy, then all we need to do is deallocate (and
350
    // maybe not even that).
351
0
    if (std::is_trivially_destructible_v<ValueType<A>> &&
352
0
        std::is_same_v<A, std::allocator<ValueType<A>>>) {
353
0
      DeallocateIfAllocated();
354
0
      return;
355
0
    }
356
357
0
    DestroyContents();
358
0
  }
Unexecuted instantiation: absl::inlined_vector_internal::Storage<absl::LogSink*, 16ul, std::__1::allocator<absl::LogSink*> >::~Storage()
Unexecuted instantiation: absl::inlined_vector_internal::Storage<absl::str_format_internal::FormatArgImpl, 4ul, std::__1::allocator<absl::str_format_internal::FormatArgImpl> >::~Storage()
359
360
  // ---------------------------------------------------------------------------
361
  // Storage Member Accessors
362
  // ---------------------------------------------------------------------------
363
364
0
  SizeType<A>& GetSizeAndIsAllocated() { return metadata_.template get<1>(); }
Unexecuted instantiation: absl::inlined_vector_internal::Storage<absl::LogSink*, 16ul, std::__1::allocator<absl::LogSink*> >::GetSizeAndIsAllocated()
Unexecuted instantiation: absl::inlined_vector_internal::Storage<absl::str_format_internal::FormatArgImpl, 4ul, std::__1::allocator<absl::str_format_internal::FormatArgImpl> >::GetSizeAndIsAllocated()
365
366
0
  const SizeType<A>& GetSizeAndIsAllocated() const {
367
0
    return metadata_.template get<1>();
368
0
  }
Unexecuted instantiation: absl::inlined_vector_internal::Storage<absl::LogSink*, 16ul, std::__1::allocator<absl::LogSink*> >::GetSizeAndIsAllocated() const
Unexecuted instantiation: absl::inlined_vector_internal::Storage<absl::str_format_internal::FormatArgImpl, 4ul, std::__1::allocator<absl::str_format_internal::FormatArgImpl> >::GetSizeAndIsAllocated() const
369
370
0
  SizeType<A> GetSize() const { return GetSizeAndIsAllocated() >> 1; }
Unexecuted instantiation: absl::inlined_vector_internal::Storage<absl::LogSink*, 16ul, std::__1::allocator<absl::LogSink*> >::GetSize() const
Unexecuted instantiation: absl::inlined_vector_internal::Storage<absl::str_format_internal::FormatArgImpl, 4ul, std::__1::allocator<absl::str_format_internal::FormatArgImpl> >::GetSize() const
371
372
0
  bool GetIsAllocated() const { return GetSizeAndIsAllocated() & 1; }
Unexecuted instantiation: absl::inlined_vector_internal::Storage<absl::LogSink*, 16ul, std::__1::allocator<absl::LogSink*> >::GetIsAllocated() const
Unexecuted instantiation: absl::inlined_vector_internal::Storage<absl::str_format_internal::FormatArgImpl, 4ul, std::__1::allocator<absl::str_format_internal::FormatArgImpl> >::GetIsAllocated() const
373
374
0
  Pointer<A> GetAllocatedData() {
375
    // GCC 12 has a false-positive -Wmaybe-uninitialized warning here.
376
#if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(12, 0)
377
#pragma GCC diagnostic push
378
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
379
#endif
380
0
    return data_.allocated.allocated_data;
381
#if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(12, 0)
382
#pragma GCC diagnostic pop
383
#endif
384
0
  }
Unexecuted instantiation: absl::inlined_vector_internal::Storage<absl::LogSink*, 16ul, std::__1::allocator<absl::LogSink*> >::GetAllocatedData()
Unexecuted instantiation: absl::inlined_vector_internal::Storage<absl::str_format_internal::FormatArgImpl, 4ul, std::__1::allocator<absl::str_format_internal::FormatArgImpl> >::GetAllocatedData()
385
386
0
  ConstPointer<A> GetAllocatedData() const {
387
0
    return data_.allocated.allocated_data;
388
0
  }
389
390
  // ABSL_ATTRIBUTE_NO_SANITIZE_CFI is used because the memory pointed to may be
391
  // uninitialized, a common pattern in allocate()+construct() APIs.
392
  // https://clang.llvm.org/docs/ControlFlowIntegrity.html#bad-cast-checking
393
  // NOTE: When this was written, LLVM documentation did not explicitly
394
  // mention that casting `char*` and using `reinterpret_cast` qualifies
395
  // as a bad cast.
396
0
  ABSL_ATTRIBUTE_NO_SANITIZE_CFI Pointer<A> GetInlinedData() {
397
0
    return reinterpret_cast<Pointer<A>>(data_.inlined.inlined_data);
398
0
  }
Unexecuted instantiation: absl::inlined_vector_internal::Storage<absl::LogSink*, 16ul, std::__1::allocator<absl::LogSink*> >::GetInlinedData()
Unexecuted instantiation: absl::inlined_vector_internal::Storage<absl::str_format_internal::FormatArgImpl, 4ul, std::__1::allocator<absl::str_format_internal::FormatArgImpl> >::GetInlinedData()
399
400
0
  ABSL_ATTRIBUTE_NO_SANITIZE_CFI ConstPointer<A> GetInlinedData() const {
401
0
    return reinterpret_cast<ConstPointer<A>>(data_.inlined.inlined_data);
402
0
  }
403
404
0
  SizeType<A> GetAllocatedCapacity() const {
405
0
    return data_.allocated.allocated_capacity;
406
0
  }
Unexecuted instantiation: absl::inlined_vector_internal::Storage<absl::LogSink*, 16ul, std::__1::allocator<absl::LogSink*> >::GetAllocatedCapacity() const
Unexecuted instantiation: absl::inlined_vector_internal::Storage<absl::str_format_internal::FormatArgImpl, 4ul, std::__1::allocator<absl::str_format_internal::FormatArgImpl> >::GetAllocatedCapacity() const
407
408
0
  SizeType<A> GetInlinedCapacity() const {
409
0
    return static_cast<SizeType<A>>(kOptimalInlinedSize);
410
0
  }
Unexecuted instantiation: absl::inlined_vector_internal::Storage<absl::LogSink*, 16ul, std::__1::allocator<absl::LogSink*> >::GetInlinedCapacity() const
Unexecuted instantiation: absl::inlined_vector_internal::Storage<absl::str_format_internal::FormatArgImpl, 4ul, std::__1::allocator<absl::str_format_internal::FormatArgImpl> >::GetInlinedCapacity() const
411
412
0
  StorageView<A> MakeStorageView() {
413
0
    return GetIsAllocated() ? StorageView<A>{GetAllocatedData(), GetSize(),
414
0
                                             GetAllocatedCapacity()}
415
0
                            : StorageView<A>{GetInlinedData(), GetSize(),
416
0
                                             GetInlinedCapacity()};
417
0
  }
418
419
0
  A& GetAllocator() { return metadata_.template get<0>(); }
Unexecuted instantiation: absl::inlined_vector_internal::Storage<absl::LogSink*, 16ul, std::__1::allocator<absl::LogSink*> >::GetAllocator()
Unexecuted instantiation: absl::inlined_vector_internal::Storage<absl::str_format_internal::FormatArgImpl, 4ul, std::__1::allocator<absl::str_format_internal::FormatArgImpl> >::GetAllocator()
420
421
0
  const A& GetAllocator() const { return metadata_.template get<0>(); }
Unexecuted instantiation: absl::inlined_vector_internal::Storage<absl::LogSink*, 16ul, std::__1::allocator<absl::LogSink*> >::GetAllocator() const
Unexecuted instantiation: absl::inlined_vector_internal::Storage<absl::str_format_internal::FormatArgImpl, 4ul, std::__1::allocator<absl::str_format_internal::FormatArgImpl> >::GetAllocator() const
422
423
  // ---------------------------------------------------------------------------
424
  // Storage Member Mutators
425
  // ---------------------------------------------------------------------------
426
427
  ABSL_ATTRIBUTE_NOINLINE void InitFrom(const Storage& other);
428
429
  template <typename ValueAdapter>
430
  void Initialize(ValueAdapter values, SizeType<A> new_size);
431
432
  template <typename ValueAdapter>
433
  void Assign(ValueAdapter values, SizeType<A> new_size);
434
435
  template <typename ValueAdapter>
436
  void Resize(ValueAdapter values, SizeType<A> new_size);
437
438
  template <typename ValueAdapter>
439
  Iterator<A> Insert(ConstIterator<A> pos, ValueAdapter values,
440
                     SizeType<A> insert_count);
441
442
  template <typename... Args>
443
  Reference<A> EmplaceBack(Args&&... args);
444
445
  Iterator<A> Erase(ConstIterator<A> from, ConstIterator<A> to);
446
447
  void Reserve(SizeType<A> requested_capacity);
448
449
  void ShrinkToFit();
450
451
  void Swap(Storage* other_storage_ptr);
452
453
0
  void SetIsAllocated() {
454
0
    GetSizeAndIsAllocated() |= static_cast<SizeType<A>>(1);
455
0
  }
Unexecuted instantiation: absl::inlined_vector_internal::Storage<absl::LogSink*, 16ul, std::__1::allocator<absl::LogSink*> >::SetIsAllocated()
Unexecuted instantiation: absl::inlined_vector_internal::Storage<absl::str_format_internal::FormatArgImpl, 4ul, std::__1::allocator<absl::str_format_internal::FormatArgImpl> >::SetIsAllocated()
456
457
  void UnsetIsAllocated() {
458
    GetSizeAndIsAllocated() &= ((std::numeric_limits<SizeType<A>>::max)() - 1);
459
  }
460
461
0
  void SetSize(SizeType<A> size) {
462
0
    GetSizeAndIsAllocated() =
463
0
        (size << 1) | static_cast<SizeType<A>>(GetIsAllocated());
464
0
  }
465
466
  void SetAllocatedSize(SizeType<A> size) {
467
    GetSizeAndIsAllocated() = (size << 1) | static_cast<SizeType<A>>(1);
468
  }
469
470
  void SetInlinedSize(SizeType<A> size) {
471
    GetSizeAndIsAllocated() = size << static_cast<SizeType<A>>(1);
472
  }
473
474
0
  void AddSize(SizeType<A> count) {
475
0
    GetSizeAndIsAllocated() += count << static_cast<SizeType<A>>(1);
476
0
  }
Unexecuted instantiation: absl::inlined_vector_internal::Storage<absl::LogSink*, 16ul, std::__1::allocator<absl::LogSink*> >::AddSize(unsigned long)
Unexecuted instantiation: absl::inlined_vector_internal::Storage<absl::str_format_internal::FormatArgImpl, 4ul, std::__1::allocator<absl::str_format_internal::FormatArgImpl> >::AddSize(unsigned long)
477
478
  void SubtractSize(SizeType<A> count) {
479
    absl::base_internal::HardeningAssertLE(count, GetSize());
480
481
    GetSizeAndIsAllocated() -= count << static_cast<SizeType<A>>(1);
482
  }
483
484
0
  void SetAllocation(Allocation<A> allocation) {
485
0
    data_.allocated.allocated_data = allocation.data;
486
0
    data_.allocated.allocated_capacity = allocation.capacity;
487
0
  }
Unexecuted instantiation: absl::inlined_vector_internal::Storage<absl::LogSink*, 16ul, std::__1::allocator<absl::LogSink*> >::SetAllocation(absl::inlined_vector_internal::Allocation<std::__1::allocator<absl::LogSink*> >)
Unexecuted instantiation: absl::inlined_vector_internal::Storage<absl::str_format_internal::FormatArgImpl, 4ul, std::__1::allocator<absl::str_format_internal::FormatArgImpl> >::SetAllocation(absl::inlined_vector_internal::Allocation<std::__1::allocator<absl::str_format_internal::FormatArgImpl> >)
488
489
  void MemcpyFrom(const Storage& other_storage) {
490
    // Assumption check: it doesn't make sense to memcpy inlined elements unless
491
    // we know the allocator doesn't do anything fancy, and one of the following
492
    // holds:
493
    //
494
    //  *  The elements are trivially relocatable.
495
    //
496
    //  *  It's possible to trivially assign the elements and then destroy the
497
    //     source.
498
    //
499
    //  *  It's possible to trivially copy construct/assign the elements.
500
    //
501
    {
502
      using V = ValueType<A>;
503
      ABSL_ASSERT(other_storage.GetIsAllocated() ||
504
                  (std::is_same_v<A, std::allocator<V>> &&
505
                   (
506
                       // First case above
507
                       absl::is_trivially_relocatable<V>::value ||
508
                       // Second case above
509
                       (std::is_trivially_move_assignable_v<V> &&
510
                        std::is_trivially_destructible_v<V>) ||
511
                       // Third case above
512
                       (std::is_trivially_copy_constructible_v<V> ||
513
                        std::is_trivially_copy_assignable_v<V>))));
514
    }
515
516
    GetSizeAndIsAllocated() = other_storage.GetSizeAndIsAllocated();
517
    data_ = other_storage.data_;
518
  }
519
520
0
  void DeallocateIfAllocated() {
521
0
    if (GetIsAllocated()) {
522
0
      MallocAdapter<A>::Deallocate(GetAllocator(), GetAllocatedData(),
523
0
                                   GetAllocatedCapacity());
524
0
    }
525
0
  }
Unexecuted instantiation: absl::inlined_vector_internal::Storage<absl::LogSink*, 16ul, std::__1::allocator<absl::LogSink*> >::DeallocateIfAllocated()
Unexecuted instantiation: absl::inlined_vector_internal::Storage<absl::str_format_internal::FormatArgImpl, 4ul, std::__1::allocator<absl::str_format_internal::FormatArgImpl> >::DeallocateIfAllocated()
526
527
 private:
528
  ABSL_ATTRIBUTE_NOINLINE void DestroyContents();
529
530
  using Metadata = container_internal::CompressedTuple<A, SizeType<A>>;
531
532
  struct Allocated {
533
    Pointer<A> allocated_data;
534
    SizeType<A> allocated_capacity;
535
  };
536
537
  // `kOptimalInlinedSize` is an automatically adjusted inlined capacity of the
538
  // `InlinedVector`. Sometimes, it is possible to increase the capacity (from
539
  // the user requested `N`) without increasing the size of the `InlinedVector`.
540
  static constexpr size_t kOptimalInlinedSize =
541
      (std::max)(N, sizeof(Allocated) / sizeof(ValueType<A>));
542
543
  struct Inlined {
544
    alignas(ValueType<A>) unsigned char inlined_data[sizeof(
545
        ValueType<A>[kOptimalInlinedSize])];
546
  };
547
548
  union Data {
549
    Allocated allocated;
550
    Inlined inlined;
551
  };
552
553
  void SwapN(ElementwiseSwapPolicy, Storage* other, SizeType<A> n);
554
  void SwapN(ElementwiseConstructPolicy, Storage* other, SizeType<A> n);
555
556
  void SwapInlinedElements(MemcpyPolicy, Storage* other);
557
  template <typename NotMemcpyPolicy>
558
  void SwapInlinedElements(NotMemcpyPolicy, Storage* other);
559
560
  template <typename... Args>
561
  ABSL_ATTRIBUTE_NOINLINE Reference<A> EmplaceBackSlow(Args&&... args);
562
563
  Metadata metadata_;
564
  Data data_;
565
};
566
567
template <typename T, size_t N, typename A>
568
0
void Storage<T, N, A>::DestroyContents() {
569
0
  Pointer<A> data = GetIsAllocated() ? GetAllocatedData() : GetInlinedData();
570
0
  DestroyAdapter<A>::DestroyElements(GetAllocator(), data, GetSize());
571
0
  DeallocateIfAllocated();
572
0
}
Unexecuted instantiation: absl::inlined_vector_internal::Storage<absl::LogSink*, 16ul, std::__1::allocator<absl::LogSink*> >::DestroyContents()
Unexecuted instantiation: absl::inlined_vector_internal::Storage<absl::str_format_internal::FormatArgImpl, 4ul, std::__1::allocator<absl::str_format_internal::FormatArgImpl> >::DestroyContents()
573
574
template <typename T, size_t N, typename A>
575
void Storage<T, N, A>::InitFrom(const Storage& other) {
576
  const SizeType<A> n = other.GetSize();
577
  ABSL_ASSERT(n > 0);  // Empty sources handled in caller.
578
  ConstPointer<A> src;
579
  Pointer<A> dst;
580
  if (!other.GetIsAllocated()) {
581
    dst = GetInlinedData();
582
    src = other.GetInlinedData();
583
  } else {
584
    // Because this is only called from the `InlinedVector` constructors, it's
585
    // safe to take on the allocation with size `0`. If `ConstructElements(...)`
586
    // throws, deallocation will be automatically handled by `~Storage()`.
587
    SizeType<A> requested_capacity = ComputeCapacity(GetInlinedCapacity(), n);
588
    Allocation<A> allocation =
589
        MallocAdapter<A>::Allocate(GetAllocator(), requested_capacity);
590
    SetAllocation(allocation);
591
    dst = allocation.data;
592
    src = other.GetAllocatedData();
593
  }
594
595
  // Fast path: if the value type is trivially copy constructible and we know
596
  // the allocator doesn't do anything fancy, then we know it is legal for us to
597
  // simply memcpy the other vector's elements.
598
  if (std::is_trivially_copy_constructible_v<ValueType<A>> &&
599
      std::is_same_v<A, std::allocator<ValueType<A>>>) {
600
    std::memcpy(reinterpret_cast<char*>(dst),
601
                reinterpret_cast<const char*>(src), n * sizeof(ValueType<A>));
602
  } else {
603
    auto values = IteratorValueAdapter<A, ConstPointer<A>>(src);
604
    ConstructElements<A>(GetAllocator(), dst, values, n);
605
  }
606
607
  GetSizeAndIsAllocated() = other.GetSizeAndIsAllocated();
608
}
609
610
template <typename T, size_t N, typename A>
611
template <typename ValueAdapter>
612
auto Storage<T, N, A>::Initialize(ValueAdapter values,
613
0
                                  SizeType<A> new_size) -> void {
614
  // Only callable from constructors!
615
0
  ABSL_ASSERT(!GetIsAllocated());
616
0
  ABSL_ASSERT(GetSize() == 0);
617
618
0
  Pointer<A> construct_data;
619
0
  if (new_size > GetInlinedCapacity()) {
620
    // Because this is only called from the `InlinedVector` constructors, it's
621
    // safe to take on the allocation with size `0`. If `ConstructElements(...)`
622
    // throws, deallocation will be automatically handled by `~Storage()`.
623
0
    SizeType<A> requested_capacity =
624
0
        ComputeCapacity(GetInlinedCapacity(), new_size);
625
0
    Allocation<A> allocation =
626
0
        MallocAdapter<A>::Allocate(GetAllocator(), requested_capacity);
627
0
    construct_data = allocation.data;
628
0
    SetAllocation(allocation);
629
0
    SetIsAllocated();
630
0
  } else {
631
0
    construct_data = GetInlinedData();
632
0
  }
633
634
0
  ConstructElements<A>(GetAllocator(), construct_data, values, new_size);
635
636
  // Since the initial size was guaranteed to be `0` and the allocated bit is
637
  // already correct for either case, *adding* `new_size` gives us the correct
638
  // result faster than setting it directly.
639
0
  AddSize(new_size);
640
0
}
641
642
template <typename T, size_t N, typename A>
643
template <typename ValueAdapter>
644
auto Storage<T, N, A>::Assign(ValueAdapter values,
645
                              SizeType<A> new_size) -> void {
646
  StorageView<A> storage_view = MakeStorageView();
647
648
  AllocationTransaction<A> allocation_tx(GetAllocator());
649
650
  absl::Span<ValueType<A>> assign_loop;
651
  absl::Span<ValueType<A>> construct_loop;
652
  absl::Span<ValueType<A>> destroy_loop;
653
654
  if (new_size > storage_view.capacity) {
655
    SizeType<A> requested_capacity =
656
        ComputeCapacity(storage_view.capacity, new_size);
657
    construct_loop = {allocation_tx.Allocate(requested_capacity), new_size};
658
    destroy_loop = {storage_view.data, storage_view.size};
659
  } else if (new_size > storage_view.size) {
660
    assign_loop = {storage_view.data, storage_view.size};
661
    construct_loop = {storage_view.data + storage_view.size,
662
                      new_size - storage_view.size};
663
  } else {
664
    assign_loop = {storage_view.data, new_size};
665
    destroy_loop = {storage_view.data + new_size, storage_view.size - new_size};
666
  }
667
668
  AssignElements<A>(assign_loop.data(), values, assign_loop.size());
669
670
  ConstructElements<A>(GetAllocator(), construct_loop.data(), values,
671
                       construct_loop.size());
672
673
  DestroyAdapter<A>::DestroyElements(GetAllocator(), destroy_loop.data(),
674
                                     destroy_loop.size());
675
676
  if (allocation_tx.DidAllocate()) {
677
    DeallocateIfAllocated();
678
    SetAllocation(std::move(allocation_tx).Release());
679
    SetIsAllocated();
680
  }
681
682
  SetSize(new_size);
683
}
684
685
template <typename T, size_t N, typename A>
686
template <typename ValueAdapter>
687
auto Storage<T, N, A>::Resize(ValueAdapter values,
688
                              SizeType<A> new_size) -> void {
689
  StorageView<A> storage_view = MakeStorageView();
690
  Pointer<A> const base = storage_view.data;
691
  const SizeType<A> size = storage_view.size;
692
  A& alloc = GetAllocator();
693
  if (new_size <= size) {
694
    // Destroy extra old elements.
695
    DestroyAdapter<A>::DestroyElements(alloc, base + new_size, size - new_size);
696
  } else if (new_size <= storage_view.capacity) {
697
    // Construct new elements in place.
698
    ConstructElements<A>(alloc, base + size, values, new_size - size);
699
  } else {
700
    // Steps:
701
    //  a. Allocate new backing store.
702
    //  b. Construct new elements in new backing store.
703
    //  c. Move existing elements from old backing store to new backing store.
704
    //  d. Destroy all elements in old backing store.
705
    // Use transactional wrappers for the first two steps so we can roll
706
    // back if necessary due to exceptions.
707
    AllocationTransaction<A> allocation_tx(alloc);
708
    SizeType<A> requested_capacity =
709
        ComputeCapacity(storage_view.capacity, new_size);
710
    Pointer<A> new_data = allocation_tx.Allocate(requested_capacity);
711
712
    ConstructionTransaction<A> construction_tx(alloc);
713
    construction_tx.Construct(new_data + size, values, new_size - size);
714
715
    IteratorValueAdapter<A, MoveIterator<A>> move_values(
716
        (MoveIterator<A>(base)));
717
    ConstructElements<A>(alloc, new_data, move_values, size);
718
719
    DestroyAdapter<A>::DestroyElements(alloc, base, size);
720
    std::move(construction_tx).Commit();
721
    DeallocateIfAllocated();
722
    SetAllocation(std::move(allocation_tx).Release());
723
    SetIsAllocated();
724
  }
725
  SetSize(new_size);
726
}
727
728
template <typename T, size_t N, typename A>
729
template <typename ValueAdapter>
730
auto Storage<T, N, A>::Insert(ConstIterator<A> pos, ValueAdapter values,
731
                              SizeType<A> insert_count) -> Iterator<A> {
732
  StorageView<A> storage_view = MakeStorageView();
733
734
  auto insert_index = static_cast<SizeType<A>>(
735
      std::distance(ConstIterator<A>(storage_view.data), pos));
736
  SizeType<A> insert_end_index = insert_index + insert_count;
737
  SizeType<A> new_size = storage_view.size + insert_count;
738
739
  if (new_size > storage_view.capacity) {
740
    AllocationTransaction<A> allocation_tx(GetAllocator());
741
    ConstructionTransaction<A> construction_tx(GetAllocator());
742
    ConstructionTransaction<A> move_construction_tx(GetAllocator());
743
744
    IteratorValueAdapter<A, MoveIterator<A>> move_values(
745
        MoveIterator<A>(storage_view.data));
746
747
    SizeType<A> requested_capacity =
748
        ComputeCapacity(storage_view.capacity, new_size);
749
    Pointer<A> new_data = allocation_tx.Allocate(requested_capacity);
750
751
    construction_tx.Construct(new_data + insert_index, values, insert_count);
752
753
    move_construction_tx.Construct(new_data, move_values, insert_index);
754
755
    ConstructElements<A>(GetAllocator(), new_data + insert_end_index,
756
                         move_values, storage_view.size - insert_index);
757
758
    DestroyAdapter<A>::DestroyElements(GetAllocator(), storage_view.data,
759
                                       storage_view.size);
760
761
    std::move(construction_tx).Commit();
762
    std::move(move_construction_tx).Commit();
763
    DeallocateIfAllocated();
764
    SetAllocation(std::move(allocation_tx).Release());
765
766
    SetAllocatedSize(new_size);
767
    return Iterator<A>(new_data + insert_index);
768
  } else {
769
    SizeType<A> move_construction_destination_index =
770
        (std::max)(insert_end_index, storage_view.size);
771
772
    ConstructionTransaction<A> move_construction_tx(GetAllocator());
773
774
    IteratorValueAdapter<A, MoveIterator<A>> move_construction_values(
775
        MoveIterator<A>(storage_view.data +
776
                        (move_construction_destination_index - insert_count)));
777
    absl::Span<ValueType<A>> move_construction = {
778
        storage_view.data + move_construction_destination_index,
779
        new_size - move_construction_destination_index};
780
781
    Pointer<A> move_assignment_values = storage_view.data + insert_index;
782
    absl::Span<ValueType<A>> move_assignment = {
783
        storage_view.data + insert_end_index,
784
        move_construction_destination_index - insert_end_index};
785
786
    absl::Span<ValueType<A>> insert_assignment = {move_assignment_values,
787
                                                  move_construction.size()};
788
789
    absl::Span<ValueType<A>> insert_construction = {
790
        insert_assignment.data() + insert_assignment.size(),
791
        insert_count - insert_assignment.size()};
792
793
    move_construction_tx.Construct(move_construction.data(),
794
                                   move_construction_values,
795
                                   move_construction.size());
796
797
    std::move_backward(move_assignment_values,
798
                       move_assignment_values + move_assignment.size(),
799
                       move_assignment.data() + move_assignment.size());
800
801
    AssignElements<A>(insert_assignment.data(), values,
802
                      insert_assignment.size());
803
804
    ConstructElements<A>(GetAllocator(), insert_construction.data(), values,
805
                         insert_construction.size());
806
807
    std::move(move_construction_tx).Commit();
808
809
    AddSize(insert_count);
810
    return Iterator<A>(storage_view.data + insert_index);
811
  }
812
}
813
814
template <typename T, size_t N, typename A>
815
template <typename... Args>
816
0
auto Storage<T, N, A>::EmplaceBack(Args&&... args) -> Reference<A> {
817
0
  StorageView<A> storage_view = MakeStorageView();
818
0
  const SizeType<A> n = storage_view.size;
819
0
  if (ABSL_PREDICT_TRUE(n != storage_view.capacity)) {
820
    // Fast path; new element fits.
821
0
    Pointer<A> last_ptr = storage_view.data + n;
822
0
    AllocatorTraits<A>::construct(GetAllocator(), last_ptr,
823
0
                                  std::forward<Args>(args)...);
824
0
    AddSize(1);
825
0
    return *last_ptr;
826
0
  }
827
  // TODO(b/173712035): Annotate with musttail attribute to prevent regression.
828
0
  return EmplaceBackSlow(std::forward<Args>(args)...);
829
0
}
830
831
template <typename T, size_t N, typename A>
832
template <typename... Args>
833
0
auto Storage<T, N, A>::EmplaceBackSlow(Args&&... args) -> Reference<A> {
834
0
  StorageView<A> storage_view = MakeStorageView();
835
0
  AllocationTransaction<A> allocation_tx(GetAllocator());
836
0
  IteratorValueAdapter<A, MoveIterator<A>> move_values(
837
0
      MoveIterator<A>(storage_view.data));
838
0
  SizeType<A> requested_capacity = NextCapacity(storage_view.capacity);
839
0
  Pointer<A> construct_data = allocation_tx.Allocate(requested_capacity);
840
0
  Pointer<A> last_ptr = construct_data + storage_view.size;
841
842
  // Construct new element.
843
0
  AllocatorTraits<A>::construct(GetAllocator(), last_ptr,
844
0
                                std::forward<Args>(args)...);
845
  // Move elements from old backing store to new backing store.
846
0
  ABSL_INTERNAL_TRY {
847
0
    ConstructElements<A>(GetAllocator(), allocation_tx.GetData(), move_values,
848
0
                         storage_view.size);
849
0
  }
850
0
  ABSL_INTERNAL_CATCH_ANY {
851
0
    AllocatorTraits<A>::destroy(GetAllocator(), last_ptr);
852
0
    ABSL_INTERNAL_RETHROW;
853
0
  }
854
  // Destroy elements in old backing store.
855
0
  DestroyAdapter<A>::DestroyElements(GetAllocator(), storage_view.data,
856
0
                                     storage_view.size);
857
858
0
  DeallocateIfAllocated();
859
0
  SetAllocation(std::move(allocation_tx).Release());
860
0
  SetIsAllocated();
861
0
  AddSize(1);
862
0
  return *last_ptr;
863
0
}
864
865
template <typename T, size_t N, typename A>
866
auto Storage<T, N, A>::Erase(ConstIterator<A> from,
867
                             ConstIterator<A> to) -> Iterator<A> {
868
  StorageView<A> storage_view = MakeStorageView();
869
870
  auto erase_size = static_cast<SizeType<A>>(std::distance(from, to));
871
  auto erase_index = static_cast<SizeType<A>>(
872
      std::distance(ConstIterator<A>(storage_view.data), from));
873
  SizeType<A> erase_end_index = erase_index + erase_size;
874
875
  // Fast path: if the value type is trivially relocatable and we know
876
  // the allocator doesn't do anything fancy, then we know it is legal for us to
877
  // simply destroy the elements in the "erasure window" (which cannot throw)
878
  // and then memcpy downward to close the window.
879
  if (absl::is_trivially_relocatable<ValueType<A>>::value &&
880
      std::is_nothrow_destructible_v<ValueType<A>> &&
881
      std::is_same_v<A, std::allocator<ValueType<A>>>) {
882
    DestroyAdapter<A>::DestroyElements(
883
        GetAllocator(), storage_view.data + erase_index, erase_size);
884
    std::memmove(
885
        reinterpret_cast<char*>(storage_view.data + erase_index),
886
        reinterpret_cast<const char*>(storage_view.data + erase_end_index),
887
        (storage_view.size - erase_end_index) * sizeof(ValueType<A>));
888
  } else {
889
    IteratorValueAdapter<A, MoveIterator<A>> move_values(
890
        MoveIterator<A>(storage_view.data + erase_end_index));
891
892
    AssignElements<A>(storage_view.data + erase_index, move_values,
893
                      storage_view.size - erase_end_index);
894
895
    DestroyAdapter<A>::DestroyElements(
896
        GetAllocator(), storage_view.data + (storage_view.size - erase_size),
897
        erase_size);
898
  }
899
  SubtractSize(erase_size);
900
  return Iterator<A>(storage_view.data + erase_index);
901
}
902
903
template <typename T, size_t N, typename A>
904
auto Storage<T, N, A>::Reserve(SizeType<A> requested_capacity) -> void {
905
  StorageView<A> storage_view = MakeStorageView();
906
907
  if (ABSL_PREDICT_FALSE(requested_capacity <= storage_view.capacity)) return;
908
909
  AllocationTransaction<A> allocation_tx(GetAllocator());
910
911
  IteratorValueAdapter<A, MoveIterator<A>> move_values(
912
      MoveIterator<A>(storage_view.data));
913
914
  SizeType<A> new_requested_capacity =
915
      ComputeCapacity(storage_view.capacity, requested_capacity);
916
  Pointer<A> new_data = allocation_tx.Allocate(new_requested_capacity);
917
918
  ConstructElements<A>(GetAllocator(), new_data, move_values,
919
                       storage_view.size);
920
921
  DestroyAdapter<A>::DestroyElements(GetAllocator(), storage_view.data,
922
                                     storage_view.size);
923
924
  DeallocateIfAllocated();
925
  SetAllocation(std::move(allocation_tx).Release());
926
  SetIsAllocated();
927
}
928
929
template <typename T, size_t N, typename A>
930
auto Storage<T, N, A>::ShrinkToFit() -> void {
931
  // May only be called on allocated instances!
932
  ABSL_ASSERT(GetIsAllocated());
933
934
  StorageView<A> storage_view{GetAllocatedData(), GetSize(),
935
                              GetAllocatedCapacity()};
936
937
  if (ABSL_PREDICT_FALSE(storage_view.size == storage_view.capacity)) return;
938
939
  AllocationTransaction<A> allocation_tx(GetAllocator());
940
941
  IteratorValueAdapter<A, MoveIterator<A>> move_values(
942
      MoveIterator<A>(storage_view.data));
943
944
  Pointer<A> construct_data;
945
  if (storage_view.size > GetInlinedCapacity()) {
946
    SizeType<A> requested_capacity = storage_view.size;
947
    construct_data = allocation_tx.Allocate(requested_capacity);
948
    if (allocation_tx.GetCapacity() >= storage_view.capacity) {
949
      // Already using the smallest available heap allocation.
950
      return;
951
    }
952
  } else {
953
    construct_data = GetInlinedData();
954
  }
955
956
  ABSL_INTERNAL_TRY {
957
    ConstructElements<A>(GetAllocator(), construct_data, move_values,
958
                         storage_view.size);
959
  }
960
  ABSL_INTERNAL_CATCH_ANY {
961
    SetAllocation({storage_view.data, storage_view.capacity});
962
    ABSL_INTERNAL_RETHROW;
963
  }
964
965
  DestroyAdapter<A>::DestroyElements(GetAllocator(), storage_view.data,
966
                                     storage_view.size);
967
968
  MallocAdapter<A>::Deallocate(GetAllocator(), storage_view.data,
969
                               storage_view.capacity);
970
971
  if (allocation_tx.DidAllocate()) {
972
    SetAllocation(std::move(allocation_tx).Release());
973
  } else {
974
    UnsetIsAllocated();
975
  }
976
}
977
978
template <typename T, size_t N, typename A>
979
auto Storage<T, N, A>::Swap(Storage* other_storage_ptr) -> void {
980
  using std::swap;
981
  ABSL_ASSERT(this != other_storage_ptr);
982
983
  if (GetIsAllocated() && other_storage_ptr->GetIsAllocated()) {
984
    swap(data_.allocated, other_storage_ptr->data_.allocated);
985
  } else if (!GetIsAllocated() && !other_storage_ptr->GetIsAllocated()) {
986
    SwapInlinedElements(SwapInlinedElementsPolicy{}, other_storage_ptr);
987
  } else {
988
    Storage* allocated_ptr = this;
989
    Storage* inlined_ptr = other_storage_ptr;
990
    if (!allocated_ptr->GetIsAllocated()) swap(allocated_ptr, inlined_ptr);
991
992
    StorageView<A> allocated_storage_view{
993
        allocated_ptr->GetAllocatedData(), allocated_ptr->GetSize(),
994
        allocated_ptr->GetAllocatedCapacity()};
995
996
    IteratorValueAdapter<A, MoveIterator<A>> move_values(
997
        MoveIterator<A>(inlined_ptr->GetInlinedData()));
998
999
    ABSL_INTERNAL_TRY {
1000
      ConstructElements<A>(inlined_ptr->GetAllocator(),
1001
                           allocated_ptr->GetInlinedData(), move_values,
1002
                           inlined_ptr->GetSize());
1003
    }
1004
    ABSL_INTERNAL_CATCH_ANY {
1005
      allocated_ptr->SetAllocation(Allocation<A>{
1006
          allocated_storage_view.data, allocated_storage_view.capacity});
1007
      ABSL_INTERNAL_RETHROW;
1008
    }
1009
1010
    DestroyAdapter<A>::DestroyElements(inlined_ptr->GetAllocator(),
1011
                                       inlined_ptr->GetInlinedData(),
1012
                                       inlined_ptr->GetSize());
1013
1014
    inlined_ptr->SetAllocation(Allocation<A>{allocated_storage_view.data,
1015
                                             allocated_storage_view.capacity});
1016
  }
1017
1018
  swap(GetSizeAndIsAllocated(), other_storage_ptr->GetSizeAndIsAllocated());
1019
  swap(GetAllocator(), other_storage_ptr->GetAllocator());
1020
}
1021
1022
template <typename T, size_t N, typename A>
1023
void Storage<T, N, A>::SwapN(ElementwiseSwapPolicy, Storage* other,
1024
                             SizeType<A> n) {
1025
  std::swap_ranges(GetInlinedData(), GetInlinedData() + n,
1026
                   other->GetInlinedData());
1027
}
1028
1029
template <typename T, size_t N, typename A>
1030
void Storage<T, N, A>::SwapN(ElementwiseConstructPolicy, Storage* other,
1031
                             SizeType<A> n) {
1032
  Pointer<A> a = GetInlinedData();
1033
  Pointer<A> b = other->GetInlinedData();
1034
  // see note on allocators in `SwapInlinedElements`.
1035
  A& allocator_a = GetAllocator();
1036
  A& allocator_b = other->GetAllocator();
1037
  for (SizeType<A> i = 0; i < n; ++i, ++a, ++b) {
1038
    ValueType<A> tmp(std::move(*a));
1039
1040
    AllocatorTraits<A>::destroy(allocator_a, a);
1041
    ABSL_INTERNAL_TRY {
1042
      AllocatorTraits<A>::construct(allocator_b, a, std::move(*b));
1043
    }
1044
    ABSL_INTERNAL_CATCH_ANY {
1045
      AllocatorTraits<A>::construct(allocator_a, a, std::move(tmp));
1046
      ABSL_INTERNAL_RETHROW;
1047
    }
1048
1049
    AllocatorTraits<A>::destroy(allocator_b, b);
1050
    ABSL_INTERNAL_TRY {
1051
      AllocatorTraits<A>::construct(allocator_a, b, std::move(tmp));
1052
    }
1053
    ABSL_INTERNAL_CATCH_ANY {
1054
      AllocatorTraits<A>::construct(allocator_b, b, std::move(*a));
1055
      ABSL_INTERNAL_RETHROW;
1056
    }
1057
  }
1058
}
1059
1060
template <typename T, size_t N, typename A>
1061
void Storage<T, N, A>::SwapInlinedElements(MemcpyPolicy, Storage* other) {
1062
  Data tmp = data_;
1063
  data_ = other->data_;
1064
  other->data_ = tmp;
1065
}
1066
1067
template <typename T, size_t N, typename A>
1068
template <typename NotMemcpyPolicy>
1069
void Storage<T, N, A>::SwapInlinedElements(NotMemcpyPolicy policy,
1070
                                           Storage* other) {
1071
  // Note: `destroy` needs to use pre-swap allocator while `construct` -
1072
  // post-swap allocator. Allocators will be swapped later on outside of
1073
  // `SwapInlinedElements`.
1074
  Storage* small_ptr = this;
1075
  Storage* large_ptr = other;
1076
  if (small_ptr->GetSize() > large_ptr->GetSize()) {
1077
    std::swap(small_ptr, large_ptr);
1078
  }
1079
1080
  auto small_size = small_ptr->GetSize();
1081
  auto diff = large_ptr->GetSize() - small_size;
1082
  SwapN(policy, other, small_size);
1083
1084
  IteratorValueAdapter<A, MoveIterator<A>> move_values(
1085
      MoveIterator<A>(large_ptr->GetInlinedData() + small_size));
1086
1087
  ConstructElements<A>(large_ptr->GetAllocator(),
1088
                       small_ptr->GetInlinedData() + small_size, move_values,
1089
                       diff);
1090
1091
  DestroyAdapter<A>::DestroyElements(large_ptr->GetAllocator(),
1092
                                     large_ptr->GetInlinedData() + small_size,
1093
                                     diff);
1094
}
1095
1096
// End ignore "array-bounds"
1097
#if !defined(__clang__) && defined(__GNUC__)
1098
#pragma GCC diagnostic pop
1099
#endif
1100
1101
}  // namespace inlined_vector_internal
1102
ABSL_NAMESPACE_END
1103
}  // namespace absl
1104
1105
#endif  // ABSL_CONTAINER_INTERNAL_INLINED_VECTOR_H_