tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

inlined_vector.h (39576B)


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