Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-30 09:31:38

0001 // Copyright 2019 The Abseil Authors.
0002 //
0003 // Licensed under the Apache License, Version 2.0 (the "License");
0004 // you may not use this file except in compliance with the License.
0005 // You may obtain a copy of the License at
0006 //
0007 //      https://www.apache.org/licenses/LICENSE-2.0
0008 //
0009 // Unless required by applicable law or agreed to in writing, software
0010 // distributed under the License is distributed on an "AS IS" BASIS,
0011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0012 // See the License for the specific language governing permissions and
0013 // limitations under the License.
0014 
0015 #ifndef ABSL_CONTAINER_INTERNAL_INLINED_VECTOR_H_
0016 #define ABSL_CONTAINER_INTERNAL_INLINED_VECTOR_H_
0017 
0018 #include <algorithm>
0019 #include <cstddef>
0020 #include <cstring>
0021 #include <iterator>
0022 #include <limits>
0023 #include <memory>
0024 #include <new>
0025 #include <type_traits>
0026 #include <utility>
0027 
0028 #include "absl/base/attributes.h"
0029 #include "absl/base/config.h"
0030 #include "absl/base/internal/identity.h"
0031 #include "absl/base/macros.h"
0032 #include "absl/container/internal/compressed_tuple.h"
0033 #include "absl/memory/memory.h"
0034 #include "absl/meta/type_traits.h"
0035 #include "absl/types/span.h"
0036 
0037 namespace absl {
0038 ABSL_NAMESPACE_BEGIN
0039 namespace inlined_vector_internal {
0040 
0041 // GCC does not deal very well with the below code
0042 #if !defined(__clang__) && defined(__GNUC__)
0043 #pragma GCC diagnostic push
0044 #pragma GCC diagnostic ignored "-Warray-bounds"
0045 #endif
0046 
0047 template <typename A>
0048 using AllocatorTraits = std::allocator_traits<A>;
0049 template <typename A>
0050 using ValueType = typename AllocatorTraits<A>::value_type;
0051 template <typename A>
0052 using SizeType = typename AllocatorTraits<A>::size_type;
0053 template <typename A>
0054 using Pointer = typename AllocatorTraits<A>::pointer;
0055 template <typename A>
0056 using ConstPointer = typename AllocatorTraits<A>::const_pointer;
0057 template <typename A>
0058 using SizeType = typename AllocatorTraits<A>::size_type;
0059 template <typename A>
0060 using DifferenceType = typename AllocatorTraits<A>::difference_type;
0061 template <typename A>
0062 using Reference = ValueType<A>&;
0063 template <typename A>
0064 using ConstReference = const ValueType<A>&;
0065 template <typename A>
0066 using Iterator = Pointer<A>;
0067 template <typename A>
0068 using ConstIterator = ConstPointer<A>;
0069 template <typename A>
0070 using ReverseIterator = typename std::reverse_iterator<Iterator<A>>;
0071 template <typename A>
0072 using ConstReverseIterator = typename std::reverse_iterator<ConstIterator<A>>;
0073 template <typename A>
0074 using MoveIterator = typename std::move_iterator<Iterator<A>>;
0075 
0076 template <typename Iterator>
0077 using IsAtLeastForwardIterator = std::is_convertible<
0078     typename std::iterator_traits<Iterator>::iterator_category,
0079     std::forward_iterator_tag>;
0080 
0081 template <typename A>
0082 using IsMoveAssignOk = std::is_move_assignable<ValueType<A>>;
0083 template <typename A>
0084 using IsSwapOk = absl::type_traits_internal::IsSwappable<ValueType<A>>;
0085 
0086 template <typename A, bool IsTriviallyDestructible =
0087                           absl::is_trivially_destructible<ValueType<A>>::value>
0088 struct DestroyAdapter;
0089 
0090 template <typename A>
0091 struct DestroyAdapter<A, /* IsTriviallyDestructible */ false> {
0092   static void DestroyElements(A& allocator, Pointer<A> destroy_first,
0093                               SizeType<A> destroy_size) {
0094     for (SizeType<A> i = destroy_size; i != 0;) {
0095       --i;
0096       AllocatorTraits<A>::destroy(allocator, destroy_first + i);
0097     }
0098   }
0099 };
0100 
0101 template <typename A>
0102 struct DestroyAdapter<A, /* IsTriviallyDestructible */ true> {
0103   static void DestroyElements(A& allocator, Pointer<A> destroy_first,
0104                               SizeType<A> destroy_size) {
0105     static_cast<void>(allocator);
0106     static_cast<void>(destroy_first);
0107     static_cast<void>(destroy_size);
0108   }
0109 };
0110 
0111 template <typename A>
0112 struct Allocation {
0113   Pointer<A> data = nullptr;
0114   SizeType<A> capacity = 0;
0115 };
0116 
0117 template <typename A,
0118           bool IsOverAligned =
0119               (alignof(ValueType<A>) > ABSL_INTERNAL_DEFAULT_NEW_ALIGNMENT)>
0120 struct MallocAdapter {
0121   static Allocation<A> Allocate(A& allocator, SizeType<A> requested_capacity) {
0122     return {AllocatorTraits<A>::allocate(allocator, requested_capacity),
0123             requested_capacity};
0124   }
0125 
0126   static void Deallocate(A& allocator, Pointer<A> pointer,
0127                          SizeType<A> capacity) {
0128     AllocatorTraits<A>::deallocate(allocator, pointer, capacity);
0129   }
0130 };
0131 
0132 template <typename A, typename ValueAdapter>
0133 void ConstructElements(absl::internal::type_identity_t<A>& allocator,
0134                        Pointer<A> construct_first, ValueAdapter& values,
0135                        SizeType<A> construct_size) {
0136   for (SizeType<A> i = 0; i < construct_size; ++i) {
0137     ABSL_INTERNAL_TRY { values.ConstructNext(allocator, construct_first + i); }
0138     ABSL_INTERNAL_CATCH_ANY {
0139       DestroyAdapter<A>::DestroyElements(allocator, construct_first, i);
0140       ABSL_INTERNAL_RETHROW;
0141     }
0142   }
0143 }
0144 
0145 template <typename A, typename ValueAdapter>
0146 void AssignElements(Pointer<A> assign_first, ValueAdapter& values,
0147                     SizeType<A> assign_size) {
0148   for (SizeType<A> i = 0; i < assign_size; ++i) {
0149     values.AssignNext(assign_first + i);
0150   }
0151 }
0152 
0153 template <typename A>
0154 struct StorageView {
0155   Pointer<A> data;
0156   SizeType<A> size;
0157   SizeType<A> capacity;
0158 };
0159 
0160 template <typename A, typename Iterator>
0161 class IteratorValueAdapter {
0162  public:
0163   explicit IteratorValueAdapter(const Iterator& it) : it_(it) {}
0164 
0165   void ConstructNext(A& allocator, Pointer<A> construct_at) {
0166     AllocatorTraits<A>::construct(allocator, construct_at, *it_);
0167     ++it_;
0168   }
0169 
0170   void AssignNext(Pointer<A> assign_at) {
0171     *assign_at = *it_;
0172     ++it_;
0173   }
0174 
0175  private:
0176   Iterator it_;
0177 };
0178 
0179 template <typename A>
0180 class CopyValueAdapter {
0181  public:
0182   explicit CopyValueAdapter(ConstPointer<A> p) : ptr_(p) {}
0183 
0184   void ConstructNext(A& allocator, Pointer<A> construct_at) {
0185     AllocatorTraits<A>::construct(allocator, construct_at, *ptr_);
0186   }
0187 
0188   void AssignNext(Pointer<A> assign_at) { *assign_at = *ptr_; }
0189 
0190  private:
0191   ConstPointer<A> ptr_;
0192 };
0193 
0194 template <typename A>
0195 class DefaultValueAdapter {
0196  public:
0197   explicit DefaultValueAdapter() {}
0198 
0199   void ConstructNext(A& allocator, Pointer<A> construct_at) {
0200     AllocatorTraits<A>::construct(allocator, construct_at);
0201   }
0202 
0203   void AssignNext(Pointer<A> assign_at) { *assign_at = ValueType<A>(); }
0204 };
0205 
0206 template <typename A>
0207 class AllocationTransaction {
0208  public:
0209   explicit AllocationTransaction(A& allocator)
0210       : allocator_data_(allocator, nullptr), capacity_(0) {}
0211 
0212   ~AllocationTransaction() {
0213     if (DidAllocate()) {
0214       MallocAdapter<A>::Deallocate(GetAllocator(), GetData(), GetCapacity());
0215     }
0216   }
0217 
0218   AllocationTransaction(const AllocationTransaction&) = delete;
0219   void operator=(const AllocationTransaction&) = delete;
0220 
0221   A& GetAllocator() { return allocator_data_.template get<0>(); }
0222   Pointer<A>& GetData() { return allocator_data_.template get<1>(); }
0223   SizeType<A>& GetCapacity() { return capacity_; }
0224 
0225   bool DidAllocate() { return GetData() != nullptr; }
0226 
0227   Pointer<A> Allocate(SizeType<A> requested_capacity) {
0228     Allocation<A> result =
0229         MallocAdapter<A>::Allocate(GetAllocator(), requested_capacity);
0230     GetData() = result.data;
0231     GetCapacity() = result.capacity;
0232     return result.data;
0233   }
0234 
0235   ABSL_MUST_USE_RESULT Allocation<A> Release() && {
0236     Allocation<A> result = {GetData(), GetCapacity()};
0237     Reset();
0238     return result;
0239   }
0240 
0241  private:
0242   void Reset() {
0243     GetData() = nullptr;
0244     GetCapacity() = 0;
0245   }
0246 
0247   container_internal::CompressedTuple<A, Pointer<A>> allocator_data_;
0248   SizeType<A> capacity_;
0249 };
0250 
0251 template <typename A>
0252 class ConstructionTransaction {
0253  public:
0254   explicit ConstructionTransaction(A& allocator)
0255       : allocator_data_(allocator, nullptr), size_(0) {}
0256 
0257   ~ConstructionTransaction() {
0258     if (DidConstruct()) {
0259       DestroyAdapter<A>::DestroyElements(GetAllocator(), GetData(), GetSize());
0260     }
0261   }
0262 
0263   ConstructionTransaction(const ConstructionTransaction&) = delete;
0264   void operator=(const ConstructionTransaction&) = delete;
0265 
0266   A& GetAllocator() { return allocator_data_.template get<0>(); }
0267   Pointer<A>& GetData() { return allocator_data_.template get<1>(); }
0268   SizeType<A>& GetSize() { return size_; }
0269 
0270   bool DidConstruct() { return GetData() != nullptr; }
0271   template <typename ValueAdapter>
0272   void Construct(Pointer<A> data, ValueAdapter& values, SizeType<A> size) {
0273     ConstructElements<A>(GetAllocator(), data, values, size);
0274     GetData() = data;
0275     GetSize() = size;
0276   }
0277   void Commit() && {
0278     GetData() = nullptr;
0279     GetSize() = 0;
0280   }
0281 
0282  private:
0283   container_internal::CompressedTuple<A, Pointer<A>> allocator_data_;
0284   SizeType<A> size_;
0285 };
0286 
0287 template <typename T, size_t N, typename A>
0288 class Storage {
0289  public:
0290   struct MemcpyPolicy {};
0291   struct ElementwiseAssignPolicy {};
0292   struct ElementwiseSwapPolicy {};
0293   struct ElementwiseConstructPolicy {};
0294 
0295   using MoveAssignmentPolicy = absl::conditional_t<
0296       // Fast path: if the value type can be trivially move assigned and
0297       // destroyed, and we know the allocator doesn't do anything fancy, then
0298       // it's safe for us to simply adopt the contents of the storage for
0299       // `other` and remove its own reference to them. It's as if we had
0300       // individually move-assigned each value and then destroyed the original.
0301       absl::conjunction<absl::is_trivially_move_assignable<ValueType<A>>,
0302                         absl::is_trivially_destructible<ValueType<A>>,
0303                         std::is_same<A, std::allocator<ValueType<A>>>>::value,
0304       MemcpyPolicy,
0305       // Otherwise we use move assignment if possible. If not, we simulate
0306       // move assignment using move construction.
0307       //
0308       // Note that this is in contrast to e.g. std::vector and std::optional,
0309       // which are themselves not move-assignable when their contained type is
0310       // not.
0311       absl::conditional_t<IsMoveAssignOk<A>::value, ElementwiseAssignPolicy,
0312                           ElementwiseConstructPolicy>>;
0313 
0314   // The policy to be used specifically when swapping inlined elements.
0315   using SwapInlinedElementsPolicy = absl::conditional_t<
0316       // Fast path: if the value type can be trivially relocated, and we
0317       // know the allocator doesn't do anything fancy, then it's safe for us
0318       // to simply swap the bytes in the inline storage. It's as if we had
0319       // relocated the first vector's elements into temporary storage,
0320       // relocated the second's elements into the (now-empty) first's,
0321       // and then relocated from temporary storage into the second.
0322       absl::conjunction<absl::is_trivially_relocatable<ValueType<A>>,
0323                         std::is_same<A, std::allocator<ValueType<A>>>>::value,
0324       MemcpyPolicy,
0325       absl::conditional_t<IsSwapOk<A>::value, ElementwiseSwapPolicy,
0326                           ElementwiseConstructPolicy>>;
0327 
0328   static SizeType<A> NextCapacity(SizeType<A> current_capacity) {
0329     return current_capacity * 2;
0330   }
0331 
0332   static SizeType<A> ComputeCapacity(SizeType<A> current_capacity,
0333                                      SizeType<A> requested_capacity) {
0334     return (std::max)(NextCapacity(current_capacity), requested_capacity);
0335   }
0336 
0337   // ---------------------------------------------------------------------------
0338   // Storage Constructors and Destructor
0339   // ---------------------------------------------------------------------------
0340 
0341   Storage() : metadata_(A(), /* size and is_allocated */ 0u) {}
0342 
0343   explicit Storage(const A& allocator)
0344       : metadata_(allocator, /* size and is_allocated */ 0u) {}
0345 
0346   ~Storage() {
0347     // Fast path: if we are empty and not allocated, there's nothing to do.
0348     if (GetSizeAndIsAllocated() == 0) {
0349       return;
0350     }
0351 
0352     // Fast path: if no destructors need to be run and we know the allocator
0353     // doesn't do anything fancy, then all we need to do is deallocate (and
0354     // maybe not even that).
0355     if (absl::is_trivially_destructible<ValueType<A>>::value &&
0356         std::is_same<A, std::allocator<ValueType<A>>>::value) {
0357       DeallocateIfAllocated();
0358       return;
0359     }
0360 
0361     DestroyContents();
0362   }
0363 
0364   // ---------------------------------------------------------------------------
0365   // Storage Member Accessors
0366   // ---------------------------------------------------------------------------
0367 
0368   SizeType<A>& GetSizeAndIsAllocated() { return metadata_.template get<1>(); }
0369 
0370   const SizeType<A>& GetSizeAndIsAllocated() const {
0371     return metadata_.template get<1>();
0372   }
0373 
0374   SizeType<A> GetSize() const { return GetSizeAndIsAllocated() >> 1; }
0375 
0376   bool GetIsAllocated() const { return GetSizeAndIsAllocated() & 1; }
0377 
0378   Pointer<A> GetAllocatedData() {
0379     // GCC 12 has a false-positive -Wmaybe-uninitialized warning here.
0380 #if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(12, 0)
0381 #pragma GCC diagnostic push
0382 #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
0383 #endif
0384     return data_.allocated.allocated_data;
0385 #if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(12, 0)
0386 #pragma GCC diagnostic pop
0387 #endif
0388   }
0389 
0390   ConstPointer<A> GetAllocatedData() const {
0391     return data_.allocated.allocated_data;
0392   }
0393 
0394   // ABSL_ATTRIBUTE_NO_SANITIZE_CFI is used because the memory pointed to may be
0395   // uninitialized, a common pattern in allocate()+construct() APIs.
0396   // https://clang.llvm.org/docs/ControlFlowIntegrity.html#bad-cast-checking
0397   // NOTE: When this was written, LLVM documentation did not explicitly
0398   // mention that casting `char*` and using `reinterpret_cast` qualifies
0399   // as a bad cast.
0400   ABSL_ATTRIBUTE_NO_SANITIZE_CFI Pointer<A> GetInlinedData() {
0401     return reinterpret_cast<Pointer<A>>(data_.inlined.inlined_data);
0402   }
0403 
0404   ABSL_ATTRIBUTE_NO_SANITIZE_CFI ConstPointer<A> GetInlinedData() const {
0405     return reinterpret_cast<ConstPointer<A>>(data_.inlined.inlined_data);
0406   }
0407 
0408   SizeType<A> GetAllocatedCapacity() const {
0409     return data_.allocated.allocated_capacity;
0410   }
0411 
0412   SizeType<A> GetInlinedCapacity() const {
0413     return static_cast<SizeType<A>>(kOptimalInlinedSize);
0414   }
0415 
0416   StorageView<A> MakeStorageView() {
0417     return GetIsAllocated() ? StorageView<A>{GetAllocatedData(), GetSize(),
0418                                              GetAllocatedCapacity()}
0419                             : StorageView<A>{GetInlinedData(), GetSize(),
0420                                              GetInlinedCapacity()};
0421   }
0422 
0423   A& GetAllocator() { return metadata_.template get<0>(); }
0424 
0425   const A& GetAllocator() const { return metadata_.template get<0>(); }
0426 
0427   // ---------------------------------------------------------------------------
0428   // Storage Member Mutators
0429   // ---------------------------------------------------------------------------
0430 
0431   ABSL_ATTRIBUTE_NOINLINE void InitFrom(const Storage& other);
0432 
0433   template <typename ValueAdapter>
0434   void Initialize(ValueAdapter values, SizeType<A> new_size);
0435 
0436   template <typename ValueAdapter>
0437   void Assign(ValueAdapter values, SizeType<A> new_size);
0438 
0439   template <typename ValueAdapter>
0440   void Resize(ValueAdapter values, SizeType<A> new_size);
0441 
0442   template <typename ValueAdapter>
0443   Iterator<A> Insert(ConstIterator<A> pos, ValueAdapter values,
0444                      SizeType<A> insert_count);
0445 
0446   template <typename... Args>
0447   Reference<A> EmplaceBack(Args&&... args);
0448 
0449   Iterator<A> Erase(ConstIterator<A> from, ConstIterator<A> to);
0450 
0451   void Reserve(SizeType<A> requested_capacity);
0452 
0453   void ShrinkToFit();
0454 
0455   void Swap(Storage* other_storage_ptr);
0456 
0457   void SetIsAllocated() {
0458     GetSizeAndIsAllocated() |= static_cast<SizeType<A>>(1);
0459   }
0460 
0461   void UnsetIsAllocated() {
0462     GetSizeAndIsAllocated() &= ((std::numeric_limits<SizeType<A>>::max)() - 1);
0463   }
0464 
0465   void SetSize(SizeType<A> size) {
0466     GetSizeAndIsAllocated() =
0467         (size << 1) | static_cast<SizeType<A>>(GetIsAllocated());
0468   }
0469 
0470   void SetAllocatedSize(SizeType<A> size) {
0471     GetSizeAndIsAllocated() = (size << 1) | static_cast<SizeType<A>>(1);
0472   }
0473 
0474   void SetInlinedSize(SizeType<A> size) {
0475     GetSizeAndIsAllocated() = size << static_cast<SizeType<A>>(1);
0476   }
0477 
0478   void AddSize(SizeType<A> count) {
0479     GetSizeAndIsAllocated() += count << static_cast<SizeType<A>>(1);
0480   }
0481 
0482   void SubtractSize(SizeType<A> count) {
0483     ABSL_HARDENING_ASSERT(count <= GetSize());
0484 
0485     GetSizeAndIsAllocated() -= count << static_cast<SizeType<A>>(1);
0486   }
0487 
0488   void SetAllocation(Allocation<A> allocation) {
0489     data_.allocated.allocated_data = allocation.data;
0490     data_.allocated.allocated_capacity = allocation.capacity;
0491   }
0492 
0493   void MemcpyFrom(const Storage& other_storage) {
0494     // Assumption check: it doesn't make sense to memcpy inlined elements unless
0495     // we know the allocator doesn't do anything fancy, and one of the following
0496     // holds:
0497     //
0498     //  *  The elements are trivially relocatable.
0499     //
0500     //  *  It's possible to trivially assign the elements and then destroy the
0501     //     source.
0502     //
0503     //  *  It's possible to trivially copy construct/assign the elements.
0504     //
0505     {
0506       using V = ValueType<A>;
0507       ABSL_HARDENING_ASSERT(
0508           other_storage.GetIsAllocated() ||
0509           (std::is_same<A, std::allocator<V>>::value &&
0510            (
0511                // First case above
0512                absl::is_trivially_relocatable<V>::value ||
0513                // Second case above
0514                (absl::is_trivially_move_assignable<V>::value &&
0515                 absl::is_trivially_destructible<V>::value) ||
0516                // Third case above
0517                (absl::is_trivially_copy_constructible<V>::value ||
0518                 absl::is_trivially_copy_assignable<V>::value))));
0519     }
0520 
0521     GetSizeAndIsAllocated() = other_storage.GetSizeAndIsAllocated();
0522     data_ = other_storage.data_;
0523   }
0524 
0525   void DeallocateIfAllocated() {
0526     if (GetIsAllocated()) {
0527       MallocAdapter<A>::Deallocate(GetAllocator(), GetAllocatedData(),
0528                                    GetAllocatedCapacity());
0529     }
0530   }
0531 
0532  private:
0533   ABSL_ATTRIBUTE_NOINLINE void DestroyContents();
0534 
0535   using Metadata = container_internal::CompressedTuple<A, SizeType<A>>;
0536 
0537   struct Allocated {
0538     Pointer<A> allocated_data;
0539     SizeType<A> allocated_capacity;
0540   };
0541 
0542   // `kOptimalInlinedSize` is an automatically adjusted inlined capacity of the
0543   // `InlinedVector`. Sometimes, it is possible to increase the capacity (from
0544   // the user requested `N`) without increasing the size of the `InlinedVector`.
0545   static constexpr size_t kOptimalInlinedSize =
0546       (std::max)(N, sizeof(Allocated) / sizeof(ValueType<A>));
0547 
0548   struct Inlined {
0549     alignas(ValueType<A>) char inlined_data[sizeof(
0550         ValueType<A>[kOptimalInlinedSize])];
0551   };
0552 
0553   union Data {
0554     Allocated allocated;
0555     Inlined inlined;
0556   };
0557 
0558   void SwapN(ElementwiseSwapPolicy, Storage* other, SizeType<A> n);
0559   void SwapN(ElementwiseConstructPolicy, Storage* other, SizeType<A> n);
0560 
0561   void SwapInlinedElements(MemcpyPolicy, Storage* other);
0562   template <typename NotMemcpyPolicy>
0563   void SwapInlinedElements(NotMemcpyPolicy, Storage* other);
0564 
0565   template <typename... Args>
0566   ABSL_ATTRIBUTE_NOINLINE Reference<A> EmplaceBackSlow(Args&&... args);
0567 
0568   Metadata metadata_;
0569   Data data_;
0570 };
0571 
0572 template <typename T, size_t N, typename A>
0573 void Storage<T, N, A>::DestroyContents() {
0574   Pointer<A> data = GetIsAllocated() ? GetAllocatedData() : GetInlinedData();
0575   DestroyAdapter<A>::DestroyElements(GetAllocator(), data, GetSize());
0576   DeallocateIfAllocated();
0577 }
0578 
0579 template <typename T, size_t N, typename A>
0580 void Storage<T, N, A>::InitFrom(const Storage& other) {
0581   const SizeType<A> n = other.GetSize();
0582   ABSL_HARDENING_ASSERT(n > 0);  // Empty sources handled handled in caller.
0583   ConstPointer<A> src;
0584   Pointer<A> dst;
0585   if (!other.GetIsAllocated()) {
0586     dst = GetInlinedData();
0587     src = other.GetInlinedData();
0588   } else {
0589     // Because this is only called from the `InlinedVector` constructors, it's
0590     // safe to take on the allocation with size `0`. If `ConstructElements(...)`
0591     // throws, deallocation will be automatically handled by `~Storage()`.
0592     SizeType<A> requested_capacity = ComputeCapacity(GetInlinedCapacity(), n);
0593     Allocation<A> allocation =
0594         MallocAdapter<A>::Allocate(GetAllocator(), requested_capacity);
0595     SetAllocation(allocation);
0596     dst = allocation.data;
0597     src = other.GetAllocatedData();
0598   }
0599 
0600   // Fast path: if the value type is trivially copy constructible and we know
0601   // the allocator doesn't do anything fancy, then we know it is legal for us to
0602   // simply memcpy the other vector's elements.
0603   if (absl::is_trivially_copy_constructible<ValueType<A>>::value &&
0604       std::is_same<A, std::allocator<ValueType<A>>>::value) {
0605     std::memcpy(reinterpret_cast<char*>(dst),
0606                 reinterpret_cast<const char*>(src), n * sizeof(ValueType<A>));
0607   } else {
0608     auto values = IteratorValueAdapter<A, ConstPointer<A>>(src);
0609     ConstructElements<A>(GetAllocator(), dst, values, n);
0610   }
0611 
0612   GetSizeAndIsAllocated() = other.GetSizeAndIsAllocated();
0613 }
0614 
0615 template <typename T, size_t N, typename A>
0616 template <typename ValueAdapter>
0617 auto Storage<T, N, A>::Initialize(ValueAdapter values,
0618                                   SizeType<A> new_size) -> void {
0619   // Only callable from constructors!
0620   ABSL_HARDENING_ASSERT(!GetIsAllocated());
0621   ABSL_HARDENING_ASSERT(GetSize() == 0);
0622 
0623   Pointer<A> construct_data;
0624   if (new_size > GetInlinedCapacity()) {
0625     // Because this is only called from the `InlinedVector` constructors, it's
0626     // safe to take on the allocation with size `0`. If `ConstructElements(...)`
0627     // throws, deallocation will be automatically handled by `~Storage()`.
0628     SizeType<A> requested_capacity =
0629         ComputeCapacity(GetInlinedCapacity(), new_size);
0630     Allocation<A> allocation =
0631         MallocAdapter<A>::Allocate(GetAllocator(), requested_capacity);
0632     construct_data = allocation.data;
0633     SetAllocation(allocation);
0634     SetIsAllocated();
0635   } else {
0636     construct_data = GetInlinedData();
0637   }
0638 
0639   ConstructElements<A>(GetAllocator(), construct_data, values, new_size);
0640 
0641   // Since the initial size was guaranteed to be `0` and the allocated bit is
0642   // already correct for either case, *adding* `new_size` gives us the correct
0643   // result faster than setting it directly.
0644   AddSize(new_size);
0645 }
0646 
0647 template <typename T, size_t N, typename A>
0648 template <typename ValueAdapter>
0649 auto Storage<T, N, A>::Assign(ValueAdapter values,
0650                               SizeType<A> new_size) -> void {
0651   StorageView<A> storage_view = MakeStorageView();
0652 
0653   AllocationTransaction<A> allocation_tx(GetAllocator());
0654 
0655   absl::Span<ValueType<A>> assign_loop;
0656   absl::Span<ValueType<A>> construct_loop;
0657   absl::Span<ValueType<A>> destroy_loop;
0658 
0659   if (new_size > storage_view.capacity) {
0660     SizeType<A> requested_capacity =
0661         ComputeCapacity(storage_view.capacity, new_size);
0662     construct_loop = {allocation_tx.Allocate(requested_capacity), new_size};
0663     destroy_loop = {storage_view.data, storage_view.size};
0664   } else if (new_size > storage_view.size) {
0665     assign_loop = {storage_view.data, storage_view.size};
0666     construct_loop = {storage_view.data + storage_view.size,
0667                       new_size - storage_view.size};
0668   } else {
0669     assign_loop = {storage_view.data, new_size};
0670     destroy_loop = {storage_view.data + new_size, storage_view.size - new_size};
0671   }
0672 
0673   AssignElements<A>(assign_loop.data(), values, assign_loop.size());
0674 
0675   ConstructElements<A>(GetAllocator(), construct_loop.data(), values,
0676                        construct_loop.size());
0677 
0678   DestroyAdapter<A>::DestroyElements(GetAllocator(), destroy_loop.data(),
0679                                      destroy_loop.size());
0680 
0681   if (allocation_tx.DidAllocate()) {
0682     DeallocateIfAllocated();
0683     SetAllocation(std::move(allocation_tx).Release());
0684     SetIsAllocated();
0685   }
0686 
0687   SetSize(new_size);
0688 }
0689 
0690 template <typename T, size_t N, typename A>
0691 template <typename ValueAdapter>
0692 auto Storage<T, N, A>::Resize(ValueAdapter values,
0693                               SizeType<A> new_size) -> void {
0694   StorageView<A> storage_view = MakeStorageView();
0695   Pointer<A> const base = storage_view.data;
0696   const SizeType<A> size = storage_view.size;
0697   A& alloc = GetAllocator();
0698   if (new_size <= size) {
0699     // Destroy extra old elements.
0700     DestroyAdapter<A>::DestroyElements(alloc, base + new_size, size - new_size);
0701   } else if (new_size <= storage_view.capacity) {
0702     // Construct new elements in place.
0703     ConstructElements<A>(alloc, base + size, values, new_size - size);
0704   } else {
0705     // Steps:
0706     //  a. Allocate new backing store.
0707     //  b. Construct new elements in new backing store.
0708     //  c. Move existing elements from old backing store to new backing store.
0709     //  d. Destroy all elements in old backing store.
0710     // Use transactional wrappers for the first two steps so we can roll
0711     // back if necessary due to exceptions.
0712     AllocationTransaction<A> allocation_tx(alloc);
0713     SizeType<A> requested_capacity =
0714         ComputeCapacity(storage_view.capacity, new_size);
0715     Pointer<A> new_data = allocation_tx.Allocate(requested_capacity);
0716 
0717     ConstructionTransaction<A> construction_tx(alloc);
0718     construction_tx.Construct(new_data + size, values, new_size - size);
0719 
0720     IteratorValueAdapter<A, MoveIterator<A>> move_values(
0721         (MoveIterator<A>(base)));
0722     ConstructElements<A>(alloc, new_data, move_values, size);
0723 
0724     DestroyAdapter<A>::DestroyElements(alloc, base, size);
0725     std::move(construction_tx).Commit();
0726     DeallocateIfAllocated();
0727     SetAllocation(std::move(allocation_tx).Release());
0728     SetIsAllocated();
0729   }
0730   SetSize(new_size);
0731 }
0732 
0733 template <typename T, size_t N, typename A>
0734 template <typename ValueAdapter>
0735 auto Storage<T, N, A>::Insert(ConstIterator<A> pos, ValueAdapter values,
0736                               SizeType<A> insert_count) -> Iterator<A> {
0737   StorageView<A> storage_view = MakeStorageView();
0738 
0739   auto insert_index = static_cast<SizeType<A>>(
0740       std::distance(ConstIterator<A>(storage_view.data), pos));
0741   SizeType<A> insert_end_index = insert_index + insert_count;
0742   SizeType<A> new_size = storage_view.size + insert_count;
0743 
0744   if (new_size > storage_view.capacity) {
0745     AllocationTransaction<A> allocation_tx(GetAllocator());
0746     ConstructionTransaction<A> construction_tx(GetAllocator());
0747     ConstructionTransaction<A> move_construction_tx(GetAllocator());
0748 
0749     IteratorValueAdapter<A, MoveIterator<A>> move_values(
0750         MoveIterator<A>(storage_view.data));
0751 
0752     SizeType<A> requested_capacity =
0753         ComputeCapacity(storage_view.capacity, new_size);
0754     Pointer<A> new_data = allocation_tx.Allocate(requested_capacity);
0755 
0756     construction_tx.Construct(new_data + insert_index, values, insert_count);
0757 
0758     move_construction_tx.Construct(new_data, move_values, insert_index);
0759 
0760     ConstructElements<A>(GetAllocator(), new_data + insert_end_index,
0761                          move_values, storage_view.size - insert_index);
0762 
0763     DestroyAdapter<A>::DestroyElements(GetAllocator(), storage_view.data,
0764                                        storage_view.size);
0765 
0766     std::move(construction_tx).Commit();
0767     std::move(move_construction_tx).Commit();
0768     DeallocateIfAllocated();
0769     SetAllocation(std::move(allocation_tx).Release());
0770 
0771     SetAllocatedSize(new_size);
0772     return Iterator<A>(new_data + insert_index);
0773   } else {
0774     SizeType<A> move_construction_destination_index =
0775         (std::max)(insert_end_index, storage_view.size);
0776 
0777     ConstructionTransaction<A> move_construction_tx(GetAllocator());
0778 
0779     IteratorValueAdapter<A, MoveIterator<A>> move_construction_values(
0780         MoveIterator<A>(storage_view.data +
0781                         (move_construction_destination_index - insert_count)));
0782     absl::Span<ValueType<A>> move_construction = {
0783         storage_view.data + move_construction_destination_index,
0784         new_size - move_construction_destination_index};
0785 
0786     Pointer<A> move_assignment_values = storage_view.data + insert_index;
0787     absl::Span<ValueType<A>> move_assignment = {
0788         storage_view.data + insert_end_index,
0789         move_construction_destination_index - insert_end_index};
0790 
0791     absl::Span<ValueType<A>> insert_assignment = {move_assignment_values,
0792                                                   move_construction.size()};
0793 
0794     absl::Span<ValueType<A>> insert_construction = {
0795         insert_assignment.data() + insert_assignment.size(),
0796         insert_count - insert_assignment.size()};
0797 
0798     move_construction_tx.Construct(move_construction.data(),
0799                                    move_construction_values,
0800                                    move_construction.size());
0801 
0802     for (Pointer<A>
0803              destination = move_assignment.data() + move_assignment.size(),
0804              last_destination = move_assignment.data(),
0805              source = move_assignment_values + move_assignment.size();
0806          ;) {
0807       --destination;
0808       --source;
0809       if (destination < last_destination) break;
0810       *destination = std::move(*source);
0811     }
0812 
0813     AssignElements<A>(insert_assignment.data(), values,
0814                       insert_assignment.size());
0815 
0816     ConstructElements<A>(GetAllocator(), insert_construction.data(), values,
0817                          insert_construction.size());
0818 
0819     std::move(move_construction_tx).Commit();
0820 
0821     AddSize(insert_count);
0822     return Iterator<A>(storage_view.data + insert_index);
0823   }
0824 }
0825 
0826 template <typename T, size_t N, typename A>
0827 template <typename... Args>
0828 auto Storage<T, N, A>::EmplaceBack(Args&&... args) -> Reference<A> {
0829   StorageView<A> storage_view = MakeStorageView();
0830   const SizeType<A> n = storage_view.size;
0831   if (ABSL_PREDICT_TRUE(n != storage_view.capacity)) {
0832     // Fast path; new element fits.
0833     Pointer<A> last_ptr = storage_view.data + n;
0834     AllocatorTraits<A>::construct(GetAllocator(), last_ptr,
0835                                   std::forward<Args>(args)...);
0836     AddSize(1);
0837     return *last_ptr;
0838   }
0839   // TODO(b/173712035): Annotate with musttail attribute to prevent regression.
0840   return EmplaceBackSlow(std::forward<Args>(args)...);
0841 }
0842 
0843 template <typename T, size_t N, typename A>
0844 template <typename... Args>
0845 auto Storage<T, N, A>::EmplaceBackSlow(Args&&... args) -> Reference<A> {
0846   StorageView<A> storage_view = MakeStorageView();
0847   AllocationTransaction<A> allocation_tx(GetAllocator());
0848   IteratorValueAdapter<A, MoveIterator<A>> move_values(
0849       MoveIterator<A>(storage_view.data));
0850   SizeType<A> requested_capacity = NextCapacity(storage_view.capacity);
0851   Pointer<A> construct_data = allocation_tx.Allocate(requested_capacity);
0852   Pointer<A> last_ptr = construct_data + storage_view.size;
0853 
0854   // Construct new element.
0855   AllocatorTraits<A>::construct(GetAllocator(), last_ptr,
0856                                 std::forward<Args>(args)...);
0857   // Move elements from old backing store to new backing store.
0858   ABSL_INTERNAL_TRY {
0859     ConstructElements<A>(GetAllocator(), allocation_tx.GetData(), move_values,
0860                          storage_view.size);
0861   }
0862   ABSL_INTERNAL_CATCH_ANY {
0863     AllocatorTraits<A>::destroy(GetAllocator(), last_ptr);
0864     ABSL_INTERNAL_RETHROW;
0865   }
0866   // Destroy elements in old backing store.
0867   DestroyAdapter<A>::DestroyElements(GetAllocator(), storage_view.data,
0868                                      storage_view.size);
0869 
0870   DeallocateIfAllocated();
0871   SetAllocation(std::move(allocation_tx).Release());
0872   SetIsAllocated();
0873   AddSize(1);
0874   return *last_ptr;
0875 }
0876 
0877 template <typename T, size_t N, typename A>
0878 auto Storage<T, N, A>::Erase(ConstIterator<A> from,
0879                              ConstIterator<A> to) -> Iterator<A> {
0880   StorageView<A> storage_view = MakeStorageView();
0881 
0882   auto erase_size = static_cast<SizeType<A>>(std::distance(from, to));
0883   auto erase_index = static_cast<SizeType<A>>(
0884       std::distance(ConstIterator<A>(storage_view.data), from));
0885   SizeType<A> erase_end_index = erase_index + erase_size;
0886 
0887   // Fast path: if the value type is trivially relocatable and we know
0888   // the allocator doesn't do anything fancy, then we know it is legal for us to
0889   // simply destroy the elements in the "erasure window" (which cannot throw)
0890   // and then memcpy downward to close the window.
0891   if (absl::is_trivially_relocatable<ValueType<A>>::value &&
0892       std::is_nothrow_destructible<ValueType<A>>::value &&
0893       std::is_same<A, std::allocator<ValueType<A>>>::value) {
0894     DestroyAdapter<A>::DestroyElements(
0895         GetAllocator(), storage_view.data + erase_index, erase_size);
0896     std::memmove(
0897         reinterpret_cast<char*>(storage_view.data + erase_index),
0898         reinterpret_cast<const char*>(storage_view.data + erase_end_index),
0899         (storage_view.size - erase_end_index) * sizeof(ValueType<A>));
0900   } else {
0901     IteratorValueAdapter<A, MoveIterator<A>> move_values(
0902         MoveIterator<A>(storage_view.data + erase_end_index));
0903 
0904     AssignElements<A>(storage_view.data + erase_index, move_values,
0905                       storage_view.size - erase_end_index);
0906 
0907     DestroyAdapter<A>::DestroyElements(
0908         GetAllocator(), storage_view.data + (storage_view.size - erase_size),
0909         erase_size);
0910   }
0911   SubtractSize(erase_size);
0912   return Iterator<A>(storage_view.data + erase_index);
0913 }
0914 
0915 template <typename T, size_t N, typename A>
0916 auto Storage<T, N, A>::Reserve(SizeType<A> requested_capacity) -> void {
0917   StorageView<A> storage_view = MakeStorageView();
0918 
0919   if (ABSL_PREDICT_FALSE(requested_capacity <= storage_view.capacity)) return;
0920 
0921   AllocationTransaction<A> allocation_tx(GetAllocator());
0922 
0923   IteratorValueAdapter<A, MoveIterator<A>> move_values(
0924       MoveIterator<A>(storage_view.data));
0925 
0926   SizeType<A> new_requested_capacity =
0927       ComputeCapacity(storage_view.capacity, requested_capacity);
0928   Pointer<A> new_data = allocation_tx.Allocate(new_requested_capacity);
0929 
0930   ConstructElements<A>(GetAllocator(), new_data, move_values,
0931                        storage_view.size);
0932 
0933   DestroyAdapter<A>::DestroyElements(GetAllocator(), storage_view.data,
0934                                      storage_view.size);
0935 
0936   DeallocateIfAllocated();
0937   SetAllocation(std::move(allocation_tx).Release());
0938   SetIsAllocated();
0939 }
0940 
0941 template <typename T, size_t N, typename A>
0942 auto Storage<T, N, A>::ShrinkToFit() -> void {
0943   // May only be called on allocated instances!
0944   ABSL_HARDENING_ASSERT(GetIsAllocated());
0945 
0946   StorageView<A> storage_view{GetAllocatedData(), GetSize(),
0947                               GetAllocatedCapacity()};
0948 
0949   if (ABSL_PREDICT_FALSE(storage_view.size == storage_view.capacity)) return;
0950 
0951   AllocationTransaction<A> allocation_tx(GetAllocator());
0952 
0953   IteratorValueAdapter<A, MoveIterator<A>> move_values(
0954       MoveIterator<A>(storage_view.data));
0955 
0956   Pointer<A> construct_data;
0957   if (storage_view.size > GetInlinedCapacity()) {
0958     SizeType<A> requested_capacity = storage_view.size;
0959     construct_data = allocation_tx.Allocate(requested_capacity);
0960     if (allocation_tx.GetCapacity() >= storage_view.capacity) {
0961       // Already using the smallest available heap allocation.
0962       return;
0963     }
0964   } else {
0965     construct_data = GetInlinedData();
0966   }
0967 
0968   ABSL_INTERNAL_TRY {
0969     ConstructElements<A>(GetAllocator(), construct_data, move_values,
0970                          storage_view.size);
0971   }
0972   ABSL_INTERNAL_CATCH_ANY {
0973     SetAllocation({storage_view.data, storage_view.capacity});
0974     ABSL_INTERNAL_RETHROW;
0975   }
0976 
0977   DestroyAdapter<A>::DestroyElements(GetAllocator(), storage_view.data,
0978                                      storage_view.size);
0979 
0980   MallocAdapter<A>::Deallocate(GetAllocator(), storage_view.data,
0981                                storage_view.capacity);
0982 
0983   if (allocation_tx.DidAllocate()) {
0984     SetAllocation(std::move(allocation_tx).Release());
0985   } else {
0986     UnsetIsAllocated();
0987   }
0988 }
0989 
0990 template <typename T, size_t N, typename A>
0991 auto Storage<T, N, A>::Swap(Storage* other_storage_ptr) -> void {
0992   using std::swap;
0993   ABSL_HARDENING_ASSERT(this != other_storage_ptr);
0994 
0995   if (GetIsAllocated() && other_storage_ptr->GetIsAllocated()) {
0996     swap(data_.allocated, other_storage_ptr->data_.allocated);
0997   } else if (!GetIsAllocated() && !other_storage_ptr->GetIsAllocated()) {
0998     SwapInlinedElements(SwapInlinedElementsPolicy{}, other_storage_ptr);
0999   } else {
1000     Storage* allocated_ptr = this;
1001     Storage* inlined_ptr = other_storage_ptr;
1002     if (!allocated_ptr->GetIsAllocated()) swap(allocated_ptr, inlined_ptr);
1003 
1004     StorageView<A> allocated_storage_view{
1005         allocated_ptr->GetAllocatedData(), allocated_ptr->GetSize(),
1006         allocated_ptr->GetAllocatedCapacity()};
1007 
1008     IteratorValueAdapter<A, MoveIterator<A>> move_values(
1009         MoveIterator<A>(inlined_ptr->GetInlinedData()));
1010 
1011     ABSL_INTERNAL_TRY {
1012       ConstructElements<A>(inlined_ptr->GetAllocator(),
1013                            allocated_ptr->GetInlinedData(), move_values,
1014                            inlined_ptr->GetSize());
1015     }
1016     ABSL_INTERNAL_CATCH_ANY {
1017       allocated_ptr->SetAllocation(Allocation<A>{
1018           allocated_storage_view.data, allocated_storage_view.capacity});
1019       ABSL_INTERNAL_RETHROW;
1020     }
1021 
1022     DestroyAdapter<A>::DestroyElements(inlined_ptr->GetAllocator(),
1023                                        inlined_ptr->GetInlinedData(),
1024                                        inlined_ptr->GetSize());
1025 
1026     inlined_ptr->SetAllocation(Allocation<A>{allocated_storage_view.data,
1027                                              allocated_storage_view.capacity});
1028   }
1029 
1030   swap(GetSizeAndIsAllocated(), other_storage_ptr->GetSizeAndIsAllocated());
1031   swap(GetAllocator(), other_storage_ptr->GetAllocator());
1032 }
1033 
1034 template <typename T, size_t N, typename A>
1035 void Storage<T, N, A>::SwapN(ElementwiseSwapPolicy, Storage* other,
1036                              SizeType<A> n) {
1037   std::swap_ranges(GetInlinedData(), GetInlinedData() + n,
1038                    other->GetInlinedData());
1039 }
1040 
1041 template <typename T, size_t N, typename A>
1042 void Storage<T, N, A>::SwapN(ElementwiseConstructPolicy, Storage* other,
1043                              SizeType<A> n) {
1044   Pointer<A> a = GetInlinedData();
1045   Pointer<A> b = other->GetInlinedData();
1046   // see note on allocators in `SwapInlinedElements`.
1047   A& allocator_a = GetAllocator();
1048   A& allocator_b = other->GetAllocator();
1049   for (SizeType<A> i = 0; i < n; ++i, ++a, ++b) {
1050     ValueType<A> tmp(std::move(*a));
1051 
1052     AllocatorTraits<A>::destroy(allocator_a, a);
1053     AllocatorTraits<A>::construct(allocator_b, a, std::move(*b));
1054 
1055     AllocatorTraits<A>::destroy(allocator_b, b);
1056     AllocatorTraits<A>::construct(allocator_a, b, std::move(tmp));
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_