forked from Alepha/Alepha
97 lines
2.4 KiB
C++
97 lines
2.4 KiB
C++
static_assert( __cplusplus > 2023'00 );
|
|
|
|
#include "ThreadSlab.h"
|
|
|
|
#include <Alepha/Exception.h>
|
|
|
|
namespace Alepha::Hydrogen::Memory ::detail:: ThreadSlab_m
|
|
{
|
|
namespace
|
|
{
|
|
namespace C
|
|
{
|
|
const std::size_t slabSize= 64 * 1024 * 1024;
|
|
|
|
const bool debug= false;
|
|
const bool debugLifecycle= false or C::debug;
|
|
const bool debugAllocation= false or C::debug;
|
|
const bool debugDeallocation= false or C::debug;
|
|
}
|
|
|
|
template< typename SP >
|
|
void
|
|
destroy( SP *p )
|
|
{
|
|
p->~SP();
|
|
}
|
|
|
|
namespace storage
|
|
{
|
|
thread_local Blob slab;
|
|
}
|
|
}
|
|
|
|
[[nodiscard]]
|
|
void *
|
|
shim::allocate( std::size_t amt )
|
|
{
|
|
// TODO: Alignment needs to be handled.
|
|
const std::size_t req= amt + sizeof( Blob::StorageReservation );
|
|
|
|
// TODO: Larger allocations may be worth bespoke allocations, if they're rare one-off cases
|
|
if( req > C::slabSize )
|
|
{
|
|
auto exc= build_exception< AllocationError >( "Unable to allocate larger than the slab size." );
|
|
//exc.setAllocationAmount( req );
|
|
throw exc;
|
|
}
|
|
if( slab().size() < req ) slab().reset( std::max( req, C::slabSize ) );
|
|
|
|
if( C::debugAllocation )
|
|
{
|
|
std::cerr << "Reporting " << slab().reservation().use_count() << " living allocations when "
|
|
<< (void *) &slab << " made an allocation." << std::endl;
|
|
}
|
|
|
|
auto next= slab().carveHead( req );
|
|
void *const rv= &next.as< Blob::StorageReservation >() + 1;
|
|
|
|
// FIXME: The placement new here is potentially unaligned -- this may significantly impact
|
|
// performance. It is also non-portable.
|
|
new ( &next.template as< Blob::StorageReservation >() ) Blob::StorageReservation{ std::move( next.reservation() ) };
|
|
|
|
if( C::debugAllocation )
|
|
{
|
|
std::cerr << "Reporting " << slab().reservation().use_count() << " living allocations when "
|
|
<< (void *) &slab() << " made an allocation." << std::endl;
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
void
|
|
shim::deallocate( void *p ) noexcept
|
|
{
|
|
if( C::debugDeallocation )
|
|
{
|
|
std::cerr << "Reporting " << slab().reservation().use_count() << " living allocations when "
|
|
<< (void *) &slab() << " made a deallocation." << std::endl;
|
|
}
|
|
|
|
auto *const hidden= reinterpret_cast< Blob::StorageReservation * >( p ) - 1;
|
|
destroy( hidden );
|
|
|
|
if( C::debugDeallocation )
|
|
{
|
|
std::cerr << "Reporting " << slab().reservation().use_count() << " living allocations when "
|
|
<< (void *) &slab() << " made a deallocation." << std::endl;
|
|
}
|
|
}
|
|
|
|
Blob &
|
|
shim::slab()
|
|
{
|
|
return storage::slab;
|
|
}
|
|
}
|