From d73b4dbe0892d8cd5269a4fbc42affec95840d33 Mon Sep 17 00:00:00 2001 From: ADAM David Alan Martin Date: Sat, 11 May 2024 20:55:09 -0400 Subject: [PATCH] Slab strings via slots... --- Memory/Blob.h | 3 + Memory/ThreadSlab.h | 112 +++++++++++------------------------- Memory/ThreadSlab.test/0.cc | 10 +++- 3 files changed, 42 insertions(+), 83 deletions(-) diff --git a/Memory/Blob.h b/Memory/Blob.h index c24cd6b..ee8184a 100644 --- a/Memory/Blob.h +++ b/Memory/Blob.h @@ -94,6 +94,9 @@ namespace Alepha::Hydrogen ::detail:: Blob_m public: ~Blob() { reset(); } + using StorageReservation= IndirectStorage; + StorageReservation reservation() const { return storage; } + auto swap_lens() noexcept { diff --git a/Memory/ThreadSlab.h b/Memory/ThreadSlab.h index 21e943f..47be4a2 100644 --- a/Memory/ThreadSlab.h +++ b/Memory/ThreadSlab.h @@ -27,17 +27,18 @@ namespace Alepha::Hydrogen::Memory ::detail:: ThreadSlab_m class exports::ThreadSlab { private: - class Impl + inline static thread_local Blob slab; + using Slot= std::tuple< void *, Blob::StorageReservation >; + std::array< Slot, 16 > slots; + + std::size_t + freeSlots() const { - public: - std::vector< Blob > leases; + std::cerr << "Slot map for " << (void *) this << std::endl; + for( const auto &[ key, res ]: + return std::count( begin( slots ), end( slots ), Slot{ nullptr, nullptr } ); + } - inline static thread_local Blob slab; - - Impl() { leases.reserve( 8 ); } - }; - - std::shared_ptr< Impl > pimpl; public: using value_type= T; @@ -46,72 +47,31 @@ namespace Alepha::Hydrogen::Memory ::detail:: ThreadSlab_m using propagate_on_container_swap= std::true_type; using is_always_equal= std::false_type; - ThreadSlab select_on_container_copy_construction() { auto rv= ThreadSlab{}; std::cerr << "selection creation at " << (void *) &rv << std::endl; return rv; } + ThreadSlab select_on_container_copy_construction() { auto rv= ThreadSlab{}; } - ThreadSlab() - : pimpl( std::make_unique< Impl >() ) - { - std::cerr << (void *) this << " owns " << (void *) pimpl.get() << " (creation)" << std::endl; - } + ThreadSlab()= default; - ~ThreadSlab() { std::cerr << "Retired allocator external " << (void *) this << " which held " << (void *) pimpl.get() << std::endl; } - ThreadSlab & - operator= ( ThreadSlab &&other ) - { - std::cerr << "Allocator move assign from " << (void *) &other << " which owns " << (void *) other.pimpl.get() - << " to " << (void *) this << " which owns " << (void *) pimpl.get() << std::endl; + ThreadSlab &operator= ( const ThreadSlab &other )= default; - pimpl= std::move( other.pimpl ); - other.pimpl.reset(); - std::cerr << "After the move assign from " << (void *) &other << " it now owns " << (void *) other.pimpl.get() - << " and I'm still " << (void *) this << " which now owns " << (void *) pimpl.get() << std::endl; + ThreadSlab( const ThreadSlab &other )= default; - return *this; - } - - ThreadSlab & - operator= ( const ThreadSlab &other ) - { - std::cerr << "Allocator copy assign from " << (void *) &other << " which owns " << (void *) other.pimpl.get() - << " to " << (void *) this << " which owns " << (void *) pimpl.get() << std::endl; - - pimpl= other.pimpl; - std::cerr << "After the copy assign from " << (void *) &other << " it now owns " << (void *) other.pimpl.get() - << " and I'm still " << (void *) this << " which now owns " << (void *) pimpl.get() << std::endl; - - return *this; - } - - ThreadSlab( const ThreadSlab &other ) - : pimpl( other.pimpl ) - { - std::cerr << "Allocator copy construction created " << (void *) this << " (from " << (void *) &other << ") which held " << (void *) pimpl.get() << std::endl; - } - - ThreadSlab( ThreadSlab &&other ) - : pimpl( std::move( other.pimpl ) ) - { - std::cerr << "Allocator move construction created " << (void *) this << " (from " << (void *) &other << ") which held " << (void *) pimpl.get() << std::endl; - assert( pimpl ); - std::cerr << "Allocator move construction still holds " << pimpl.get() << std::endl; - } + ThreadSlab( ThreadSlab &&other ) : ThreadSlab( std::as_const( other ) ) {} [[nodiscard]] T * allocate( const std::size_t amt ) { - assert( pimpl ); - std::cerr << (void *) this << " owns " << (void *) pimpl.get() << " (alloc)" << std::endl; - if( pimpl->slab.size() < amt ) pimpl->slab.reset( std::max( amt, C::slabSize ) ); + std::cerr << "Pre allocation there are " << freeSlots() << " free slots" << std::endl; + if( slab.size() < amt ) slab.reset( std::max( amt, C::slabSize ) ); - auto next= pimpl->slab.carveHead( amt ); + const auto slot= std::find( begin( slots ), end( slots ), Slot{ nullptr, nullptr } ); + assert( slot != end( slots ) ); + + auto next= slab.carveHead( amt ); const auto rv= &next.template as< T >(); - std::cerr << "Carved off " << amt << " bytes to address " << (void *) rv << " as allocator at " << (void *) pimpl.get() << std::endl; + *slot= { rv, next.reservation() }; - pimpl->leases.push_back( std::move( next ) ); - - std::cerr << "The allocator at 0x" << (void *) pimpl.get() << " has " << pimpl->leases.size() << " leases. (alloc)" << std::endl; - assert( pimpl ); + std::cerr << "Post allocation there are " << freeSlots() << " free slots" << std::endl; return rv; } @@ -119,28 +79,20 @@ namespace Alepha::Hydrogen::Memory ::detail:: ThreadSlab_m void deallocate( T *const p, const std::size_t /* ignored */ ) noexcept { - assert( pimpl ); - std::cerr << (void *) this << " owns " << (void *) pimpl.get() << " (dealloc)" << std::endl; - std::cerr << "Deallocation attempt of " << (void *) p << " by " << (void *) pimpl.get() << " when there are " << pimpl->leases.size() << " leases left." << std::endl; - auto found= std::find_if( begin( pimpl->leases ), end( pimpl->leases ), [p]( const auto &x ) { return x.data() == p; } ); - if( found != end( pimpl->leases ) ) - { - pimpl->leases.erase( found ); - std::cerr << "The allocator at 0x" << (void *) pimpl.get() << " has " << pimpl->leases.size() << " leases. (dealloc)" << std::endl; - } - else - { - abort(); // Panic because it wasn't found in the list! - } - assert( pimpl ); + std::cerr << "Pre deallocation there are " << freeSlots() << " free slots" << std::endl; + const auto slot= std::find_if( begin( slots ), end( slots ), + [p]( const auto &slot ){ const auto &[ which, _ ]= slot; return which == p; } ); + assert( slot != end( slots ) ); + + *slot= { nullptr, nullptr }; + + std::cerr << "Post deallocation there are " << freeSlots() << " free slots" << std::endl; } friend constexpr bool operator == ( const ThreadSlab &a, const ThreadSlab &b ) noexcept { - assert( a.pimpl ); - assert( b.pimpl ); - return a.pimpl == b.pimpl; + return a.slots == b.slots; } }; } diff --git a/Memory/ThreadSlab.test/0.cc b/Memory/ThreadSlab.test/0.cc index 4edfc34..f29e03f 100644 --- a/Memory/ThreadSlab.test/0.cc +++ b/Memory/ThreadSlab.test/0.cc @@ -22,10 +22,14 @@ static auto init= Alepha::Utility::enroll <=[] std::cerr << "small hello world string." << std::endl; String s3= s2 + ": and bob"; - std::cerr << "appended..." << std::endl; - s3= s3 + s3 + s2; - s2= std::move( s3 ); + for( int i= 0; i < 10; ++i ) + { + std::cerr << "appended..." << std::endl; + s3= s3 + s3 + s2; + + s2= std::move( s3 ); + } std::cout << s3 << std::endl; };