static_assert( __cplusplus > 2020'99 ); #pragma once #include #include #include namespace Alepha::Hydrogen::Memory ::detail:: ThreadSlab_m { inline namespace exports { template< typename T > class ThreadSlab; using ThreadSlabString= std::basic_string< char, std::char_traits< char >, ThreadSlab< char > >; } namespace C { const std::size_t slabSize= 64 * 1024 * 1024; } template< typename T > class exports::ThreadSlab { public: inline static thread_local Blob slab; public: using value_type= T; using propagate_on_container_copy_assignment= std::true_type; using propagate_on_container_move_assignment= std::true_type; using propagate_on_container_swap= std::true_type; using is_always_equal= std::true_type; ThreadSlab select_on_container_copy_construction() { auto rv= ThreadSlab{}; } ThreadSlab()= default; ThreadSlab &operator= ( const ThreadSlab &other )= default; ThreadSlab( const ThreadSlab &other )= default; ThreadSlab( ThreadSlab &&other ) : ThreadSlab( std::as_const( other ) ) {} ~ThreadSlab() { std::cerr << "Reporting " << slab.reservation().use_count() << " living allocations when " << (void *) this << " is retired." << std::endl; } [[nodiscard]] T * allocate( const std::size_t amt ) { // TODO: Alignment? const std::size_t req= amt + sizeof( Blob::StorageReservation ); if( req > C::slabSize ) throw std::bad_alloc{}; //{ "Unable to allocate larger than the slab size." }; if( slab.size() < req ) slab.reset( std::max( req, C::slabSize ) ); std::cerr << "Reporting " << slab.reservation().use_count() << " living allocations when " << (void *) this << " made an allocation." << std::endl; auto next= slab.carveHead( req, Alignment{ sizeof( Blob::StorageReservation ) } ); const auto rv= reinterpret_cast< T * >( &next.template as< Blob::StorageReservation >() + 1 ); new ( &next.template as< Blob::StorageReservation >() ) Blob::StorageReservation{ std::move( next.reservation() ) }; std::cerr << "Reporting " << slab.reservation().use_count() << " living allocations when " << (void *) this << " made an allocation." << std::endl; return rv; } template< typename SP > static void destroy( SP *p ) { p->~SP(); } void deallocate( T *const p, const std::size_t /* ignored */ ) noexcept { std::cerr << "Reporting " << slab.reservation().use_count() << " living allocations when " << (void *) this << " made a deallocation." << std::endl; auto *const hidden= reinterpret_cast< Blob::StorageReservation * >( p ) - 1; destroy( hidden ); std::cerr << "Reporting " << slab.reservation().use_count() << " living allocations when " << (void *) this << " made a deallocation." << std::endl; } friend constexpr bool operator == ( const ThreadSlab &, const ThreadSlab & ) noexcept { return true; } }; } namespace Alepha::Hydrogen::Memory::inline exports::inline ThreadSlab_m { using namespace detail::ThreadSlab_m::exports; }