File indexing completed on 2025-01-30 09:31:38
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
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
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, 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, 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
0297
0298
0299
0300
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
0306
0307
0308
0309
0310
0311 absl::conditional_t<IsMoveAssignOk<A>::value, ElementwiseAssignPolicy,
0312 ElementwiseConstructPolicy>>;
0313
0314
0315 using SwapInlinedElementsPolicy = absl::conditional_t<
0316
0317
0318
0319
0320
0321
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
0339
0340
0341 Storage() : metadata_(A(), 0u) {}
0342
0343 explicit Storage(const A& allocator)
0344 : metadata_(allocator, 0u) {}
0345
0346 ~Storage() {
0347
0348 if (GetSizeAndIsAllocated() == 0) {
0349 return;
0350 }
0351
0352
0353
0354
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
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
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
0395
0396
0397
0398
0399
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
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
0495
0496
0497
0498
0499
0500
0501
0502
0503
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
0512 absl::is_trivially_relocatable<V>::value ||
0513
0514 (absl::is_trivially_move_assignable<V>::value &&
0515 absl::is_trivially_destructible<V>::value) ||
0516
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
0543
0544
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);
0583 ConstPointer<A> src;
0584 Pointer<A> dst;
0585 if (!other.GetIsAllocated()) {
0586 dst = GetInlinedData();
0587 src = other.GetInlinedData();
0588 } else {
0589
0590
0591
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
0601
0602
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
0620 ABSL_HARDENING_ASSERT(!GetIsAllocated());
0621 ABSL_HARDENING_ASSERT(GetSize() == 0);
0622
0623 Pointer<A> construct_data;
0624 if (new_size > GetInlinedCapacity()) {
0625
0626
0627
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
0642
0643
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
0700 DestroyAdapter<A>::DestroyElements(alloc, base + new_size, size - new_size);
0701 } else if (new_size <= storage_view.capacity) {
0702
0703 ConstructElements<A>(alloc, base + size, values, new_size - size);
0704 } else {
0705
0706
0707
0708
0709
0710
0711
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
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
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
0855 AllocatorTraits<A>::construct(GetAllocator(), last_ptr,
0856 std::forward<Args>(args)...);
0857
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
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
0888
0889
0890
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
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
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
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
1072
1073
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
1097 #if !defined(__clang__) && defined(__GNUC__)
1098 #pragma GCC diagnostic pop
1099 #endif
1100
1101 }
1102 ABSL_NAMESPACE_END
1103 }
1104
1105 #endif