@ -21,8 +21,11 @@
# include <iterator>
# include <limits>
# include <memory>
# include <new>
# include <type_traits>
# include <utility>
# include "absl/base/attributes.h"
# include "absl/base/macros.h"
# include "absl/container/internal/compressed_tuple.h"
# include "absl/memory/memory.h"
@ -102,6 +105,27 @@ void DestroyElements(NoTypeDeduction<A>& allocator, Pointer<A> destroy_first,
}
}
template < typename A >
struct Allocation {
Pointer < A > data ;
SizeType < A > capacity ;
} ;
template < typename A ,
bool IsOverAligned =
( alignof ( ValueType < A > ) > ABSL_INTERNAL_DEFAULT_NEW_ALIGNMENT ) >
struct MallocAdapter {
static Allocation < A > Allocate ( A & allocator , SizeType < A > requested_capacity ) {
return { AllocatorTraits < A > : : allocate ( allocator , requested_capacity ) ,
requested_capacity } ;
}
static void Deallocate ( A & allocator , Pointer < A > pointer ,
SizeType < A > capacity ) {
AllocatorTraits < A > : : deallocate ( allocator , pointer , capacity ) ;
}
} ;
// If kUseMemcpy is true, memcpy(dst, src, n); else do nothing.
// Useful to avoid compiler warnings when memcpy() is used for T values
// that are not trivially copyable in non-reachable code.
@ -201,7 +225,7 @@ class AllocationTransaction {
~ AllocationTransaction ( ) {
if ( DidAllocate ( ) ) {
AllocatorTraits < A > : : d eallocate( GetAllocator ( ) , GetData ( ) , GetCapacity ( ) ) ;
MallocAdapter < A > : : D eallocate( GetAllocator ( ) , GetData ( ) , GetCapacity ( ) ) ;
}
}
@ -213,18 +237,27 @@ class AllocationTransaction {
SizeType < A > & GetCapacity ( ) { return capacity_ ; }
bool DidAllocate ( ) { return GetData ( ) ! = nullptr ; }
Pointer < A > Allocate ( SizeType < A > capacity ) {
GetData ( ) = AllocatorTraits < A > : : allocate ( GetAllocator ( ) , capacity ) ;
GetCapacity ( ) = capacity ;
return GetData ( ) ;
Pointer < A > Allocate ( SizeType < A > requested_capacity ) {
Allocation < A > result =
MallocAdapter < A > : : Allocate ( GetAllocator ( ) , requested_capacity ) ;
GetData ( ) = result . data ;
GetCapacity ( ) = result . capacity ;
return result . data ;
}
ABSL_MUST_USE_RESULT Allocation < A > Release ( ) & & {
Allocation < A > result = { GetData ( ) , GetCapacity ( ) } ;
Reset ( ) ;
return result ;
}
private :
void Reset ( ) {
GetData ( ) = nullptr ;
GetCapacity ( ) = 0 ;
}
private :
container_internal : : CompressedTuple < A , Pointer < A > > allocator_data_ ;
SizeType < A > capacity_ ;
} ;
@ -405,15 +438,9 @@ class Storage {
GetSizeAndIsAllocated ( ) - = count < < static_cast < SizeType < A > > ( 1 ) ;
}
void SetAllocatedData ( Pointer < A > data , SizeType < A > capacity ) {
data_ . allocated . allocated_data = data ;
data_ . allocated . allocated_capacity = capacity ;
}
void AcquireAllocatedData ( AllocationTransaction < A > & allocation_tx ) {
SetAllocatedData ( allocation_tx . GetData ( ) , allocation_tx . GetCapacity ( ) ) ;
allocation_tx . Reset ( ) ;
void SetAllocation ( Allocation < A > allocation ) {
data_ . allocated . allocated_data = allocation . data ;
data_ . allocated . allocated_capacity = allocation . capacity ;
}
void MemcpyFrom ( const Storage & other_storage ) {
@ -425,8 +452,8 @@ class Storage {
void DeallocateIfAllocated ( ) {
if ( GetIsAllocated ( ) ) {
AllocatorTraits < A > : : d eallocate( GetAllocator ( ) , GetAllocatedData ( ) ,
GetAllocatedCapacity ( ) ) ;
MallocAdapter < A > : : D eallocate( GetAllocator ( ) , GetAllocatedData ( ) ,
GetAllocatedCapacity ( ) ) ;
}
}
@ -476,9 +503,11 @@ void Storage<T, N, A>::InitFrom(const Storage& other) {
// Because this is only called from the `InlinedVector` constructors, it's
// safe to take on the allocation with size `0`. If `ConstructElements(...)`
// throws, deallocation will be automatically handled by `~Storage()`.
SizeType < A > new_capacity = ComputeCapacity ( GetInlinedCapacity ( ) , n ) ;
dst = AllocatorTraits < A > : : allocate ( GetAllocator ( ) , new_capacity ) ;
SetAllocatedData ( dst , new_capacity ) ;
SizeType < A > requested_capacity = ComputeCapacity ( GetInlinedCapacity ( ) , n ) ;
Allocation < A > allocation =
MallocAdapter < A > : : Allocate ( GetAllocator ( ) , requested_capacity ) ;
SetAllocation ( allocation ) ;
dst = allocation . data ;
src = other . GetAllocatedData ( ) ;
}
if ( IsMemcpyOk < A > : : value ) {
@ -503,9 +532,12 @@ auto Storage<T, N, A>::Initialize(ValueAdapter values, SizeType<A> new_size)
// Because this is only called from the `InlinedVector` constructors, it's
// safe to take on the allocation with size `0`. If `ConstructElements(...)`
// throws, deallocation will be automatically handled by `~Storage()`.
SizeType < A > new_capacity = ComputeCapacity ( GetInlinedCapacity ( ) , new_size ) ;
construct_data = AllocatorTraits < A > : : allocate ( GetAllocator ( ) , new_capacity ) ;
SetAllocatedData ( construct_data , new_capacity ) ;
SizeType < A > requested_capacity =
ComputeCapacity ( GetInlinedCapacity ( ) , new_size ) ;
Allocation < A > allocation =
MallocAdapter < A > : : Allocate ( GetAllocator ( ) , requested_capacity ) ;
construct_data = allocation . data ;
SetAllocation ( allocation ) ;
SetIsAllocated ( ) ;
} else {
construct_data = GetInlinedData ( ) ;
@ -532,8 +564,9 @@ auto Storage<T, N, A>::Assign(ValueAdapter values, SizeType<A> new_size)
absl : : Span < ValueType < A > > destroy_loop ;
if ( new_size > storage_view . capacity ) {
SizeType < A > new_capacity = ComputeCapacity ( storage_view . capacity , new_size ) ;
construct_loop = { allocation_tx . Allocate ( new_capacity ) , new_size } ;
SizeType < A > requested_capacity =
ComputeCapacity ( storage_view . capacity , new_size ) ;
construct_loop = { allocation_tx . Allocate ( requested_capacity ) , new_size } ;
destroy_loop = { storage_view . data , storage_view . size } ;
} else if ( new_size > storage_view . size ) {
assign_loop = { storage_view . data , storage_view . size } ;
@ -553,7 +586,7 @@ auto Storage<T, N, A>::Assign(ValueAdapter values, SizeType<A> new_size)
if ( allocation_tx . DidAllocate ( ) ) {
DeallocateIfAllocated ( ) ;
AcquireAllocatedData ( allocation_tx ) ;
SetAllocation ( std : : move ( allocation_tx ) . Release ( ) ) ;
SetIsAllocated ( ) ;
}
@ -583,8 +616,9 @@ auto Storage<T, N, A>::Resize(ValueAdapter values, SizeType<A> new_size)
// Use transactional wrappers for the first two steps so we can roll
// back if necessary due to exceptions.
AllocationTransaction < A > allocation_tx ( alloc ) ;
SizeType < A > new_capacity = ComputeCapacity ( storage_view . capacity , new_size ) ;
Pointer < A > new_data = allocation_tx . Allocate ( new_capacity ) ;
SizeType < A > requested_capacity =
ComputeCapacity ( storage_view . capacity , new_size ) ;
Pointer < A > new_data = allocation_tx . Allocate ( requested_capacity ) ;
ConstructionTransaction < A > construction_tx ( alloc ) ;
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)
DestroyElements < A > ( alloc , base , size ) ;
construction_tx . Commit ( ) ;
DeallocateIfAllocated ( ) ;
AcquireAllocatedData ( allocation_tx ) ;
SetAllocation ( std : : move ( allocation_tx ) . Release ( ) ) ;
SetIsAllocated ( ) ;
}
SetSize ( new_size ) ;
@ -621,8 +655,9 @@ auto Storage<T, N, A>::Insert(ConstIterator<A> pos, ValueAdapter values,
IteratorValueAdapter < A , MoveIterator < A > > move_values (
MoveIterator < A > ( storage_view . data ) ) ;
SizeType < A > new_capacity = ComputeCapacity ( storage_view . capacity , new_size ) ;
Pointer < A > new_data = allocation_tx . Allocate ( new_capacity ) ;
SizeType < A > requested_capacity =
ComputeCapacity ( storage_view . capacity , new_size ) ;
Pointer < A > new_data = allocation_tx . Allocate ( requested_capacity ) ;
construction_tx . Construct ( new_data + insert_index , values , insert_count ) ;
@ -636,7 +671,7 @@ auto Storage<T, N, A>::Insert(ConstIterator<A> pos, ValueAdapter values,
construction_tx . Commit ( ) ;
move_construction_tx . Commit ( ) ;
DeallocateIfAllocated ( ) ;
AcquireAllocatedData ( allocation_tx ) ;
SetAllocation ( std : : move ( allocation_tx ) . Release ( ) ) ;
SetAllocatedSize ( new_size ) ;
return Iterator < A > ( new_data + insert_index ) ;
@ -717,8 +752,8 @@ auto Storage<T, N, A>::EmplaceBackSlow(Args&&... args) -> Reference<A> {
AllocationTransaction < A > allocation_tx ( GetAllocator ( ) ) ;
IteratorValueAdapter < A , MoveIterator < A > > move_values (
MoveIterator < A > ( storage_view . data ) ) ;
SizeType < A > new _capacity = NextCapacity ( storage_view . capacity ) ;
Pointer < A > construct_data = allocation_tx . Allocate ( new _capacity) ;
SizeType < A > requested _capacity = NextCapacity ( storage_view . capacity ) ;
Pointer < A > construct_data = allocation_tx . Allocate ( requested _capacity) ;
Pointer < A > last_ptr = construct_data + storage_view . size ;
// Construct new element.
@ -737,7 +772,7 @@ auto Storage<T, N, A>::EmplaceBackSlow(Args&&... args) -> Reference<A> {
DestroyElements < A > ( GetAllocator ( ) , storage_view . data , storage_view . size ) ;
DeallocateIfAllocated ( ) ;
AcquireAllocatedData ( allocation_tx ) ;
SetAllocation ( std : : move ( allocation_tx ) . Release ( ) ) ;
SetIsAllocated ( ) ;
AddSize ( 1 ) ;
return * last_ptr ;
@ -778,9 +813,9 @@ auto Storage<T, N, A>::Reserve(SizeType<A> requested_capacity) -> void {
IteratorValueAdapter < A , MoveIterator < A > > move_values (
MoveIterator < A > ( storage_view . data ) ) ;
SizeType < A > new_capacity =
SizeType < A > new_requested_ capacity =
ComputeCapacity ( storage_view . capacity , requested_capacity ) ;
Pointer < A > new_data = allocation_tx . Allocate ( new_capacity ) ;
Pointer < A > new_data = allocation_tx . Allocate ( new_requested_ capacity ) ;
ConstructElements < A > ( GetAllocator ( ) , new_data , move_values ,
storage_view . size ) ;
@ -788,7 +823,7 @@ auto Storage<T, N, A>::Reserve(SizeType<A> requested_capacity) -> void {
DestroyElements < A > ( GetAllocator ( ) , storage_view . data , storage_view . size ) ;
DeallocateIfAllocated ( ) ;
AcquireAllocatedData ( allocation_tx ) ;
SetAllocation ( std : : move ( allocation_tx ) . Release ( ) ) ;
SetIsAllocated ( ) ;
}
@ -809,8 +844,12 @@ auto Storage<T, N, A>::ShrinkToFit() -> void {
Pointer < A > construct_data ;
if ( storage_view . size > GetInlinedCapacity ( ) ) {
SizeType < A > new_capacity = storage_view . size ;
construct_data = allocation_tx . Allocate ( new_capacity ) ;
SizeType < A > requested_capacity = storage_view . size ;
construct_data = allocation_tx . Allocate ( requested_capacity ) ;
if ( allocation_tx . GetCapacity ( ) > = storage_view . capacity ) {
// Already using the smallest available heap allocation.
return ;
}
} else {
construct_data = GetInlinedData ( ) ;
}
@ -820,17 +859,17 @@ auto Storage<T, N, A>::ShrinkToFit() -> void {
storage_view . size ) ;
}
ABSL_INTERNAL_CATCH_ANY {
SetAllocatedData ( storage_view . data , storage_view . capacity ) ;
SetAllocation ( { storage_view . data , storage_view . capacity } ) ;
ABSL_INTERNAL_RETHROW ;
}
DestroyElements < A > ( GetAllocator ( ) , storage_view . data , storage_view . size ) ;
AllocatorTraits < A > : : d eallocate( GetAllocator ( ) , storage_view . data ,
storage_view . capacity ) ;
MallocAdapter < A > : : D eallocate( GetAllocator ( ) , storage_view . data ,
storage_view . capacity ) ;
if ( allocation_tx . DidAllocate ( ) ) {
AcquireAllocatedData ( allocation_tx ) ;
SetAllocation ( std : : move ( allocation_tx ) . Release ( ) ) ;
} else {
UnsetIsAllocated ( ) ;
}
@ -881,16 +920,16 @@ auto Storage<T, N, A>::Swap(Storage* other_storage_ptr) -> void {
inlined_ptr - > GetSize ( ) ) ;
}
ABSL_INTERNAL_CATCH_ANY {
allocated_ptr - > SetAllocatedData ( allocated_storage_view . data ,
allocated_storage_view . capacity ) ;
allocated_ptr - > SetAllocation (
{ allocated_storage_view . data , allocated_storage_view . capacity } ) ;
ABSL_INTERNAL_RETHROW ;
}
DestroyElements < A > ( inlined_ptr - > GetAllocator ( ) ,
inlined_ptr - > GetInlinedData ( ) , inlined_ptr - > GetSize ( ) ) ;
inlined_ptr - > SetAllocatedData ( allocated_storage_view . data ,
allocated_storage_view . capacity ) ;
inlined_ptr - > SetAllocation (
{ allocated_storage_view . data , allocated_storage_view . capacity } ) ;
}
swap ( GetSizeAndIsAllocated ( ) , other_storage_ptr - > GetSizeAndIsAllocated ( ) ) ;