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