2121#include < iterator>
2222#include < limits>
2323#include < memory>
24+ #include < new>
25+ #include < type_traits>
2426#include < utility>
2527
28+ #include " absl/base/attributes.h"
2629#include " absl/base/macros.h"
2730#include " absl/container/internal/compressed_tuple.h"
2831#include " absl/memory/memory.h"
@@ -102,6 +105,27 @@ void DestroyElements(NoTypeDeduction<A>& allocator, Pointer<A> destroy_first,
102105 }
103106}
104107
108+ template <typename A>
109+ struct Allocation {
110+ Pointer<A> data;
111+ SizeType<A> capacity;
112+ };
113+
114+ template <typename A,
115+ bool IsOverAligned =
116+ (alignof (ValueType<A>) > ABSL_INTERNAL_DEFAULT_NEW_ALIGNMENT)>
117+ struct MallocAdapter {
118+ static Allocation<A> Allocate (A& allocator, SizeType<A> requested_capacity) {
119+ return {AllocatorTraits<A>::allocate (allocator, requested_capacity),
120+ requested_capacity};
121+ }
122+
123+ static void Deallocate (A& allocator, Pointer<A> pointer,
124+ SizeType<A> capacity) {
125+ AllocatorTraits<A>::deallocate (allocator, pointer, capacity);
126+ }
127+ };
128+
105129// If kUseMemcpy is true, memcpy(dst, src, n); else do nothing.
106130// Useful to avoid compiler warnings when memcpy() is used for T values
107131// that are not trivially copyable in non-reachable code.
@@ -201,7 +225,7 @@ class AllocationTransaction {
201225
202226 ~AllocationTransaction () {
203227 if (DidAllocate ()) {
204- AllocatorTraits <A>::deallocate (GetAllocator (), GetData (), GetCapacity ());
228+ MallocAdapter <A>::Deallocate (GetAllocator (), GetData (), GetCapacity ());
205229 }
206230 }
207231
@@ -213,18 +237,27 @@ class AllocationTransaction {
213237 SizeType<A>& GetCapacity () { return capacity_; }
214238
215239 bool DidAllocate () { return GetData () != nullptr ; }
216- Pointer<A> Allocate (SizeType<A> capacity) {
217- GetData () = AllocatorTraits<A>::allocate (GetAllocator (), capacity);
218- GetCapacity () = capacity;
219- return GetData ();
240+
241+ Pointer<A> Allocate (SizeType<A> requested_capacity) {
242+ Allocation<A> result =
243+ MallocAdapter<A>::Allocate (GetAllocator (), requested_capacity);
244+ GetData () = result.data ;
245+ GetCapacity () = result.capacity ;
246+ return result.data ;
247+ }
248+
249+ ABSL_MUST_USE_RESULT Allocation<A> Release () && {
250+ Allocation<A> result = {GetData (), GetCapacity ()};
251+ Reset ();
252+ return result;
220253 }
221254
255+ private:
222256 void Reset () {
223257 GetData () = nullptr ;
224258 GetCapacity () = 0 ;
225259 }
226260
227- private:
228261 container_internal::CompressedTuple<A, Pointer<A>> allocator_data_;
229262 SizeType<A> capacity_;
230263};
@@ -405,15 +438,9 @@ class Storage {
405438 GetSizeAndIsAllocated () -= count << static_cast <SizeType<A>>(1 );
406439 }
407440
408- void SetAllocatedData (Pointer<A> data, SizeType<A> capacity) {
409- data_.allocated .allocated_data = data;
410- data_.allocated .allocated_capacity = capacity;
411- }
412-
413- void AcquireAllocatedData (AllocationTransaction<A>& allocation_tx) {
414- SetAllocatedData (allocation_tx.GetData (), allocation_tx.GetCapacity ());
415-
416- allocation_tx.Reset ();
441+ void SetAllocation (Allocation<A> allocation) {
442+ data_.allocated .allocated_data = allocation.data ;
443+ data_.allocated .allocated_capacity = allocation.capacity ;
417444 }
418445
419446 void MemcpyFrom (const Storage& other_storage) {
@@ -425,8 +452,8 @@ class Storage {
425452
426453 void DeallocateIfAllocated () {
427454 if (GetIsAllocated ()) {
428- AllocatorTraits <A>::deallocate (GetAllocator (), GetAllocatedData (),
429- GetAllocatedCapacity ());
455+ MallocAdapter <A>::Deallocate (GetAllocator (), GetAllocatedData (),
456+ GetAllocatedCapacity ());
430457 }
431458 }
432459
@@ -476,9 +503,11 @@ void Storage<T, N, A>::InitFrom(const Storage& other) {
476503 // Because this is only called from the `InlinedVector` constructors, it's
477504 // safe to take on the allocation with size `0`. If `ConstructElements(...)`
478505 // throws, deallocation will be automatically handled by `~Storage()`.
479- SizeType<A> new_capacity = ComputeCapacity (GetInlinedCapacity (), n);
480- dst = AllocatorTraits<A>::allocate (GetAllocator (), new_capacity);
481- SetAllocatedData (dst, new_capacity);
506+ SizeType<A> requested_capacity = ComputeCapacity (GetInlinedCapacity (), n);
507+ Allocation<A> allocation =
508+ MallocAdapter<A>::Allocate (GetAllocator (), requested_capacity);
509+ SetAllocation (allocation);
510+ dst = allocation.data ;
482511 src = other.GetAllocatedData ();
483512 }
484513 if (IsMemcpyOk<A>::value) {
@@ -503,9 +532,12 @@ auto Storage<T, N, A>::Initialize(ValueAdapter values, SizeType<A> new_size)
503532 // Because this is only called from the `InlinedVector` constructors, it's
504533 // safe to take on the allocation with size `0`. If `ConstructElements(...)`
505534 // throws, deallocation will be automatically handled by `~Storage()`.
506- SizeType<A> new_capacity = ComputeCapacity (GetInlinedCapacity (), new_size);
507- construct_data = AllocatorTraits<A>::allocate (GetAllocator (), new_capacity);
508- SetAllocatedData (construct_data, new_capacity);
535+ SizeType<A> requested_capacity =
536+ ComputeCapacity (GetInlinedCapacity (), new_size);
537+ Allocation<A> allocation =
538+ MallocAdapter<A>::Allocate (GetAllocator (), requested_capacity);
539+ construct_data = allocation.data ;
540+ SetAllocation (allocation);
509541 SetIsAllocated ();
510542 } else {
511543 construct_data = GetInlinedData ();
@@ -532,8 +564,9 @@ auto Storage<T, N, A>::Assign(ValueAdapter values, SizeType<A> new_size)
532564 absl::Span<ValueType<A>> destroy_loop;
533565
534566 if (new_size > storage_view.capacity ) {
535- SizeType<A> new_capacity = ComputeCapacity (storage_view.capacity , new_size);
536- construct_loop = {allocation_tx.Allocate (new_capacity), new_size};
567+ SizeType<A> requested_capacity =
568+ ComputeCapacity (storage_view.capacity , new_size);
569+ construct_loop = {allocation_tx.Allocate (requested_capacity), new_size};
537570 destroy_loop = {storage_view.data , storage_view.size };
538571 } else if (new_size > storage_view.size ) {
539572 assign_loop = {storage_view.data , storage_view.size };
@@ -553,7 +586,7 @@ auto Storage<T, N, A>::Assign(ValueAdapter values, SizeType<A> new_size)
553586
554587 if (allocation_tx.DidAllocate ()) {
555588 DeallocateIfAllocated ();
556- AcquireAllocatedData ( allocation_tx);
589+ SetAllocation ( std::move ( allocation_tx). Release () );
557590 SetIsAllocated ();
558591 }
559592
@@ -583,8 +616,9 @@ auto Storage<T, N, A>::Resize(ValueAdapter values, SizeType<A> new_size)
583616 // Use transactional wrappers for the first two steps so we can roll
584617 // back if necessary due to exceptions.
585618 AllocationTransaction<A> allocation_tx (alloc);
586- SizeType<A> new_capacity = ComputeCapacity (storage_view.capacity , new_size);
587- Pointer<A> new_data = allocation_tx.Allocate (new_capacity);
619+ SizeType<A> requested_capacity =
620+ ComputeCapacity (storage_view.capacity , new_size);
621+ Pointer<A> new_data = allocation_tx.Allocate (requested_capacity);
588622
589623 ConstructionTransaction<A> construction_tx (alloc);
590624 construction_tx.Construct (new_data + size, values, new_size - size);
@@ -596,7 +630,7 @@ auto Storage<T, N, A>::Resize(ValueAdapter values, SizeType<A> new_size)
596630 DestroyElements<A>(alloc, base, size);
597631 construction_tx.Commit ();
598632 DeallocateIfAllocated ();
599- AcquireAllocatedData ( allocation_tx);
633+ SetAllocation ( std::move ( allocation_tx). Release () );
600634 SetIsAllocated ();
601635 }
602636 SetSize (new_size);
@@ -621,8 +655,9 @@ auto Storage<T, N, A>::Insert(ConstIterator<A> pos, ValueAdapter values,
621655 IteratorValueAdapter<A, MoveIterator<A>> move_values (
622656 MoveIterator<A>(storage_view.data ));
623657
624- SizeType<A> new_capacity = ComputeCapacity (storage_view.capacity , new_size);
625- Pointer<A> new_data = allocation_tx.Allocate (new_capacity);
658+ SizeType<A> requested_capacity =
659+ ComputeCapacity (storage_view.capacity , new_size);
660+ Pointer<A> new_data = allocation_tx.Allocate (requested_capacity);
626661
627662 construction_tx.Construct (new_data + insert_index, values, insert_count);
628663
@@ -636,7 +671,7 @@ auto Storage<T, N, A>::Insert(ConstIterator<A> pos, ValueAdapter values,
636671 construction_tx.Commit ();
637672 move_construction_tx.Commit ();
638673 DeallocateIfAllocated ();
639- AcquireAllocatedData ( allocation_tx);
674+ SetAllocation ( std::move ( allocation_tx). Release () );
640675
641676 SetAllocatedSize (new_size);
642677 return Iterator<A>(new_data + insert_index);
@@ -717,8 +752,8 @@ auto Storage<T, N, A>::EmplaceBackSlow(Args&&... args) -> Reference<A> {
717752 AllocationTransaction<A> allocation_tx (GetAllocator ());
718753 IteratorValueAdapter<A, MoveIterator<A>> move_values (
719754 MoveIterator<A>(storage_view.data ));
720- SizeType<A> new_capacity = NextCapacity (storage_view.capacity );
721- Pointer<A> construct_data = allocation_tx.Allocate (new_capacity );
755+ SizeType<A> requested_capacity = NextCapacity (storage_view.capacity );
756+ Pointer<A> construct_data = allocation_tx.Allocate (requested_capacity );
722757 Pointer<A> last_ptr = construct_data + storage_view.size ;
723758
724759 // Construct new element.
@@ -737,7 +772,7 @@ auto Storage<T, N, A>::EmplaceBackSlow(Args&&... args) -> Reference<A> {
737772 DestroyElements<A>(GetAllocator (), storage_view.data , storage_view.size );
738773
739774 DeallocateIfAllocated ();
740- AcquireAllocatedData ( allocation_tx);
775+ SetAllocation ( std::move ( allocation_tx). Release () );
741776 SetIsAllocated ();
742777 AddSize (1 );
743778 return *last_ptr;
@@ -778,17 +813,17 @@ auto Storage<T, N, A>::Reserve(SizeType<A> requested_capacity) -> void {
778813 IteratorValueAdapter<A, MoveIterator<A>> move_values (
779814 MoveIterator<A>(storage_view.data ));
780815
781- SizeType<A> new_capacity =
816+ SizeType<A> new_requested_capacity =
782817 ComputeCapacity (storage_view.capacity , requested_capacity);
783- Pointer<A> new_data = allocation_tx.Allocate (new_capacity );
818+ Pointer<A> new_data = allocation_tx.Allocate (new_requested_capacity );
784819
785820 ConstructElements<A>(GetAllocator (), new_data, move_values,
786821 storage_view.size );
787822
788823 DestroyElements<A>(GetAllocator (), storage_view.data , storage_view.size );
789824
790825 DeallocateIfAllocated ();
791- AcquireAllocatedData ( allocation_tx);
826+ SetAllocation ( std::move ( allocation_tx). Release () );
792827 SetIsAllocated ();
793828}
794829
@@ -809,8 +844,12 @@ auto Storage<T, N, A>::ShrinkToFit() -> void {
809844
810845 Pointer<A> construct_data;
811846 if (storage_view.size > GetInlinedCapacity ()) {
812- SizeType<A> new_capacity = storage_view.size ;
813- construct_data = allocation_tx.Allocate (new_capacity);
847+ SizeType<A> requested_capacity = storage_view.size ;
848+ construct_data = allocation_tx.Allocate (requested_capacity);
849+ if (allocation_tx.GetCapacity () >= storage_view.capacity ) {
850+ // Already using the smallest available heap allocation.
851+ return ;
852+ }
814853 } else {
815854 construct_data = GetInlinedData ();
816855 }
@@ -820,17 +859,17 @@ auto Storage<T, N, A>::ShrinkToFit() -> void {
820859 storage_view.size );
821860 }
822861 ABSL_INTERNAL_CATCH_ANY {
823- SetAllocatedData ( storage_view.data , storage_view.capacity );
862+ SetAllocation ({ storage_view.data , storage_view.capacity } );
824863 ABSL_INTERNAL_RETHROW;
825864 }
826865
827866 DestroyElements<A>(GetAllocator (), storage_view.data , storage_view.size );
828867
829- AllocatorTraits <A>::deallocate (GetAllocator (), storage_view.data ,
830- storage_view.capacity );
868+ MallocAdapter <A>::Deallocate (GetAllocator (), storage_view.data ,
869+ storage_view.capacity );
831870
832871 if (allocation_tx.DidAllocate ()) {
833- AcquireAllocatedData ( allocation_tx);
872+ SetAllocation ( std::move ( allocation_tx). Release () );
834873 } else {
835874 UnsetIsAllocated ();
836875 }
@@ -881,16 +920,16 @@ auto Storage<T, N, A>::Swap(Storage* other_storage_ptr) -> void {
881920 inlined_ptr->GetSize ());
882921 }
883922 ABSL_INTERNAL_CATCH_ANY {
884- allocated_ptr->SetAllocatedData (allocated_storage_view. data ,
885- allocated_storage_view.capacity );
923+ allocated_ptr->SetAllocation (
924+ {allocated_storage_view. data , allocated_storage_view.capacity } );
886925 ABSL_INTERNAL_RETHROW;
887926 }
888927
889928 DestroyElements<A>(inlined_ptr->GetAllocator (),
890929 inlined_ptr->GetInlinedData (), inlined_ptr->GetSize ());
891930
892- inlined_ptr->SetAllocatedData (allocated_storage_view. data ,
893- allocated_storage_view.capacity );
931+ inlined_ptr->SetAllocation (
932+ {allocated_storage_view. data , allocated_storage_view.capacity } );
894933 }
895934
896935 swap (GetSizeAndIsAllocated (), other_storage_ptr->GetSizeAndIsAllocated ());
0 commit comments