333 lines
7.3 KiB
C++
333 lines
7.3 KiB
C++
|
#include <lw/lib/Alloc.hh>
|
||
|
#include <lw/lib/Pointers.hh>
|
||
|
#include <cppunit/extensions/HelperMacros.h>
|
||
|
using namespace lw;
|
||
|
|
||
|
|
||
|
class AllocPoolTest : public CppUnit::TestFixture
|
||
|
{
|
||
|
CPPUNIT_TEST_SUITE( AllocPoolTest );
|
||
|
CPPUNIT_TEST( testUnused );
|
||
|
|
||
|
CPPUNIT_TEST( testAllocPartial );
|
||
|
CPPUNIT_TEST( testAllocFull );
|
||
|
CPPUNIT_TEST( testAllocNewList );
|
||
|
|
||
|
CPPUNIT_TEST( testFreePartialToFree );
|
||
|
CPPUNIT_TEST( testFreePartialToPartial );
|
||
|
CPPUNIT_TEST( testFreeFullToPartial );
|
||
|
|
||
|
CPPUNIT_TEST( testFreeLists );
|
||
|
CPPUNIT_TEST( testFreeFragmented );
|
||
|
CPPUNIT_TEST( testFreeMaxLists );
|
||
|
|
||
|
CPPUNIT_TEST( testReallocation );
|
||
|
CPPUNIT_TEST_SUITE_END( );
|
||
|
|
||
|
public:
|
||
|
void setUp( ) override;
|
||
|
|
||
|
void testUnused( );
|
||
|
|
||
|
void testAllocPartial( );
|
||
|
void testAllocFull( );
|
||
|
void testAllocNewList( );
|
||
|
|
||
|
void testFreePartialToFree( );
|
||
|
void testFreePartialToPartial( );
|
||
|
void testFreeFullToPartial( );
|
||
|
|
||
|
void testFreeLists( );
|
||
|
void testFreeFragmented( );
|
||
|
void testFreeMaxLists( );
|
||
|
|
||
|
void testReallocation( );
|
||
|
};
|
||
|
CPPUNIT_TEST_SUITE_REGISTRATION( AllocPoolTest );
|
||
|
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
|
||
|
namespace {
|
||
|
|
||
|
class T_Test_
|
||
|
{
|
||
|
public:
|
||
|
static size_t counters[ 256 ];
|
||
|
uint8_t index;
|
||
|
|
||
|
T_Test_( ) = delete;
|
||
|
|
||
|
T_Test_( const uint8_t v ) noexcept
|
||
|
: index( v )
|
||
|
{ counters[ index ] ++; }
|
||
|
|
||
|
T_Test_( T_Test_ const& other ) noexcept
|
||
|
: index( other.index )
|
||
|
{ counters[ index ] ++; }
|
||
|
|
||
|
T_Test_( T_Test_&& other ) noexcept
|
||
|
: index( other.index )
|
||
|
{ counters[ index ] ++; }
|
||
|
|
||
|
~T_Test_( )
|
||
|
{ counters[ index ] --; }
|
||
|
|
||
|
void* operator new( size_t count ) noexcept;
|
||
|
void operator delete( void* object ) noexcept;
|
||
|
|
||
|
static size_t total( ) noexcept
|
||
|
{
|
||
|
size_t sum = 0;
|
||
|
for ( auto i = 0 ; i < 255 ; i ++ ) {
|
||
|
sum += counters[ i ];
|
||
|
}
|
||
|
return sum;
|
||
|
}
|
||
|
};
|
||
|
M_CLASS_POINTERS( Test_ );
|
||
|
|
||
|
size_t T_Test_::counters[ 256 ];
|
||
|
|
||
|
static constexpr size_t PerList_ = 15;
|
||
|
static constexpr size_t MaxFreeLists_ = 4;
|
||
|
static constexpr size_t MFLObjects_ = PerList_ * MaxFreeLists_;
|
||
|
using T_Pool_ = T_PoolAllocator<
|
||
|
sizeof( T_Test_ ) , alignof( T_Test_ ) ,
|
||
|
PerList_ , MaxFreeLists_ >;
|
||
|
|
||
|
static T_OwnPtr< T_Pool_ > Pool_;
|
||
|
|
||
|
void InitPool_( )
|
||
|
{
|
||
|
Pool_ = NewOwned< T_Pool_ >( );
|
||
|
}
|
||
|
|
||
|
void KillPool_( )
|
||
|
{
|
||
|
Pool_.clear( );
|
||
|
}
|
||
|
|
||
|
void* T_Test_::operator new(
|
||
|
const size_t count ) noexcept
|
||
|
{
|
||
|
assert( Pool_ );
|
||
|
return Pool_->allocate( count );
|
||
|
}
|
||
|
|
||
|
void T_Test_::operator delete(
|
||
|
void* object ) noexcept
|
||
|
{
|
||
|
assert( Pool_ );
|
||
|
Pool_->free( object );
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
#define M_CHECK_LISTS_( T , F , U ) \
|
||
|
do { \
|
||
|
CPPUNIT_ASSERT_EQUAL( size_t( T ) , Pool_->countFreeLists( ) ); \
|
||
|
CPPUNIT_ASSERT_EQUAL( size_t( F ) , Pool_->countPartialLists( ) ); \
|
||
|
CPPUNIT_ASSERT_EQUAL( size_t( U ) , Pool_->countFullLists( ) ); \
|
||
|
} while ( 0 )
|
||
|
|
||
|
#define M_CHECK_USAGE_( T , F , U ) \
|
||
|
do { \
|
||
|
size_t _t_ , _f_ , _u_; \
|
||
|
Pool_->getUsage( _t_ , _f_ , _u_ ); \
|
||
|
CPPUNIT_ASSERT_EQUAL( size_t( T ) , _t_ ); \
|
||
|
CPPUNIT_ASSERT_EQUAL( size_t( F ) , _f_ ); \
|
||
|
CPPUNIT_ASSERT_EQUAL( size_t( U ) , _u_ ); \
|
||
|
} while ( 0 )
|
||
|
|
||
|
#define M_CHECK_COUNT_( N ) \
|
||
|
CPPUNIT_ASSERT_EQUAL( size_t( N ) , T_Test_::total( ) )
|
||
|
|
||
|
void AllocPoolTest::setUp( )
|
||
|
{
|
||
|
memset( T_Test_::counters , 0 , sizeof( T_Test_::counters ) );
|
||
|
}
|
||
|
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
|
||
|
void AllocPoolTest::testUnused( )
|
||
|
{
|
||
|
InitPool_( );
|
||
|
M_CHECK_LISTS_( 1 , 0 , 0 );
|
||
|
M_CHECK_USAGE_( PerList_ , PerList_ , 0 );
|
||
|
KillPool_( );
|
||
|
M_CHECK_COUNT_( 0 );
|
||
|
}
|
||
|
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
|
||
|
void AllocPoolTest::testAllocPartial( )
|
||
|
{
|
||
|
InitPool_( );
|
||
|
{
|
||
|
OP_Test_ test( NewOwned< T_Test_ >( 0 ) );
|
||
|
M_CHECK_COUNT_( 1 );
|
||
|
M_CHECK_LISTS_( 0 , 1 , 0 );
|
||
|
M_CHECK_USAGE_( PerList_ , PerList_ - 1 , 1 );
|
||
|
}
|
||
|
KillPool_( );
|
||
|
M_CHECK_COUNT_( 0 );
|
||
|
}
|
||
|
|
||
|
void AllocPoolTest::testAllocFull( )
|
||
|
{
|
||
|
InitPool_( );
|
||
|
{
|
||
|
OP_Test_ test[ PerList_ ];
|
||
|
for ( auto i = 0u ; i < PerList_ ; i ++ ) {
|
||
|
test[ i ] = NewOwned< T_Test_ >( i );
|
||
|
}
|
||
|
M_CHECK_COUNT_( PerList_ );
|
||
|
M_CHECK_LISTS_( 0 , 0 , 1 );
|
||
|
M_CHECK_USAGE_( PerList_ , 0 , PerList_ );
|
||
|
}
|
||
|
KillPool_( );
|
||
|
M_CHECK_COUNT_( 0 );
|
||
|
}
|
||
|
|
||
|
void AllocPoolTest::testAllocNewList( )
|
||
|
{
|
||
|
InitPool_( );
|
||
|
{
|
||
|
OP_Test_ test[ PerList_ + 1 ];
|
||
|
for ( auto i = 0u ; i <= PerList_ ; i ++ ) {
|
||
|
test[ i ] = NewOwned< T_Test_ >( i );
|
||
|
}
|
||
|
M_CHECK_COUNT_( PerList_ + 1 );
|
||
|
M_CHECK_LISTS_( 0 , 1 , 1 );
|
||
|
M_CHECK_USAGE_( PerList_ * 2 , PerList_ - 1 , PerList_ + 1 );
|
||
|
}
|
||
|
KillPool_( );
|
||
|
M_CHECK_COUNT_( 0 );
|
||
|
}
|
||
|
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
|
||
|
void AllocPoolTest::testFreePartialToFree( )
|
||
|
{
|
||
|
InitPool_( );
|
||
|
{
|
||
|
OP_Test_ obj( NewOwned< T_Test_ >( 0 ) );
|
||
|
obj.clear( );
|
||
|
M_CHECK_COUNT_( 0 );
|
||
|
M_CHECK_LISTS_( 1 , 0 , 0 );
|
||
|
M_CHECK_USAGE_( PerList_ , PerList_ , 0 );
|
||
|
}
|
||
|
KillPool_( );
|
||
|
}
|
||
|
|
||
|
void AllocPoolTest::testFreePartialToPartial( )
|
||
|
{
|
||
|
InitPool_( );
|
||
|
{
|
||
|
OP_Test_ persist( NewOwned< T_Test_ >( 0 ) );
|
||
|
OP_Test_ test( NewOwned< T_Test_ >( 1 ) );
|
||
|
test.clear( );
|
||
|
M_CHECK_COUNT_( 1 );
|
||
|
M_CHECK_LISTS_( 0 , 1 , 0 );
|
||
|
M_CHECK_USAGE_( PerList_ , PerList_ - 1 , 1 );
|
||
|
}
|
||
|
KillPool_( );
|
||
|
}
|
||
|
|
||
|
void AllocPoolTest::testFreeFullToPartial( )
|
||
|
{
|
||
|
InitPool_( );
|
||
|
{
|
||
|
OP_Test_ objs[ PerList_ ];
|
||
|
for ( auto i = 0u ; i < PerList_ ; i ++ ) {
|
||
|
objs[ i ] = NewOwned< T_Test_ >( i );
|
||
|
}
|
||
|
objs[ PerList_ - 1 ].clear( );
|
||
|
M_CHECK_COUNT_( PerList_ - 1 );
|
||
|
M_CHECK_LISTS_( 0 , 1 , 0 );
|
||
|
M_CHECK_USAGE_( PerList_ , 1 , PerList_ - 1 );
|
||
|
}
|
||
|
KillPool_( );
|
||
|
}
|
||
|
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
|
||
|
void AllocPoolTest::testFreeLists( )
|
||
|
{
|
||
|
InitPool_( );
|
||
|
{
|
||
|
OP_Test_ obj[ MFLObjects_ ];
|
||
|
for ( auto i = 0u ; i < MFLObjects_ ; i ++ ) {
|
||
|
obj[ i ] = NewOwned< T_Test_ >( i );
|
||
|
}
|
||
|
for ( auto i = 0u ; i < MFLObjects_ ; i ++ ) {
|
||
|
obj[ i ].clear( );
|
||
|
}
|
||
|
M_CHECK_COUNT_( 0 );
|
||
|
M_CHECK_LISTS_( MaxFreeLists_ , 0 , 0 );
|
||
|
M_CHECK_USAGE_( MFLObjects_ , MFLObjects_ , 0 );
|
||
|
}
|
||
|
KillPool_( );
|
||
|
}
|
||
|
|
||
|
void AllocPoolTest::testFreeFragmented( )
|
||
|
{
|
||
|
InitPool_( );
|
||
|
{
|
||
|
OP_Test_ obj[ MFLObjects_ ];
|
||
|
for ( auto i = 0u ; i < MFLObjects_ ; i ++ ) {
|
||
|
obj[ i ] = NewOwned< T_Test_ >( i );
|
||
|
}
|
||
|
for ( auto i = 0u ; i < MaxFreeLists_ ; i ++ ) {
|
||
|
obj[ i * PerList_ ].clear( );
|
||
|
}
|
||
|
M_CHECK_COUNT_( MFLObjects_ - MaxFreeLists_ );
|
||
|
M_CHECK_LISTS_( 0 , MaxFreeLists_ , 0 );
|
||
|
M_CHECK_USAGE_( MFLObjects_ , MaxFreeLists_ , MFLObjects_ - MaxFreeLists_ );
|
||
|
}
|
||
|
KillPool_( );
|
||
|
}
|
||
|
|
||
|
void AllocPoolTest::testFreeMaxLists( )
|
||
|
{
|
||
|
InitPool_( );
|
||
|
{
|
||
|
OP_Test_ obj[ MFLObjects_ + PerList_ ];
|
||
|
for ( auto i = 0u ; i < MFLObjects_ + PerList_ ; i ++ ) {
|
||
|
obj[ i ] = NewOwned< T_Test_ >( i );
|
||
|
}
|
||
|
for ( auto i = 0u ; i < MFLObjects_ + PerList_ ; i ++ ) {
|
||
|
obj[ i ].clear( );
|
||
|
}
|
||
|
M_CHECK_COUNT_( 0 );
|
||
|
M_CHECK_LISTS_( MaxFreeLists_ , 0 , 0 );
|
||
|
M_CHECK_USAGE_( MFLObjects_ , MFLObjects_ , 0 );
|
||
|
}
|
||
|
KillPool_( );
|
||
|
}
|
||
|
|
||
|
/*----------------------------------------------------------------------------*/
|
||
|
|
||
|
void AllocPoolTest::testReallocation( )
|
||
|
{
|
||
|
InitPool_( );
|
||
|
{
|
||
|
OP_Test_ obj[ PerList_ ];
|
||
|
T_Test_* ptr[ PerList_ ];
|
||
|
for ( auto i = 0u ; i < PerList_ ; i ++ ) {
|
||
|
obj[ i ] = NewOwned< T_Test_ >( i );
|
||
|
ptr[ i ] = obj[ i ].get( );
|
||
|
}
|
||
|
for ( auto i = 1u ; i < PerList_ ; i += 2 ) {
|
||
|
obj[ i ].clear( );
|
||
|
}
|
||
|
for ( auto i = 1u ; i < PerList_ ; i += 2 ) {
|
||
|
obj[ i ] = NewOwned< T_Test_ >( i );
|
||
|
CPPUNIT_ASSERT( obj[ i ].get( ) == ptr[ i ] );
|
||
|
}
|
||
|
M_CHECK_LISTS_( 0 , 0 , 1 );
|
||
|
M_CHECK_USAGE_( PerList_ , 0 , PerList_ );
|
||
|
}
|
||
|
KillPool_( );
|
||
|
}
|