|
|
|
@ -26,482 +26,546 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
|
#define __MEM_BLOCKALLOC_H__
|
|
|
|
|
|
|
|
|
|
#include "linklist.h"
|
|
|
|
|
|
|
|
|
|
#define MEM_BLOCKSIZE char[ 256 ]
|
|
|
|
|
#include "q_shared.h"
|
|
|
|
|
|
|
|
|
|
void *MEM_Alloc( int size );
|
|
|
|
|
void MEM_Free( void *ptr );
|
|
|
|
|
|
|
|
|
|
template< typename aclass, typename blocksize >
|
|
|
|
|
static constexpr size_t DefaultBlock = 256;
|
|
|
|
|
|
|
|
|
|
enum class alloc_source_e
|
|
|
|
|
{
|
|
|
|
|
SourceBlock = 174,
|
|
|
|
|
SourceMalloc
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template<typename aclass, size_t blocksize>
|
|
|
|
|
class MEM_BlockAlloc_enum;
|
|
|
|
|
|
|
|
|
|
template< typename aclass, typename blocksize >
|
|
|
|
|
template<typename aclass, size_t blocksize>
|
|
|
|
|
class block_s {
|
|
|
|
|
public:
|
|
|
|
|
#ifndef _DEBUG_MEMBLOCK
|
|
|
|
|
unsigned char data[ sizeof( blocksize ) ][ sizeof( aclass ) + 8 ];
|
|
|
|
|
unsigned char prev_data[ sizeof( blocksize ) ];
|
|
|
|
|
unsigned char next_data[ sizeof( blocksize ) ];
|
|
|
|
|
|
|
|
|
|
short int free_data;
|
|
|
|
|
short int used_data;
|
|
|
|
|
#else
|
|
|
|
|
unsigned char data[ sizeof( aclass ) ];
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
block_s< aclass, blocksize > *prev_block;
|
|
|
|
|
block_s< aclass, blocksize > *next_block;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template< typename aclass, typename blocksize >
|
|
|
|
|
class MEM_BlockAlloc {
|
|
|
|
|
friend class MEM_BlockAlloc_enum< aclass, blocksize >;
|
|
|
|
|
|
|
|
|
|
#ifndef _DEBUG_MEMBLOCK
|
|
|
|
|
// Free block list [not usable], avoid slow down by using gi.Free
|
|
|
|
|
block_s< aclass, blocksize > *m_FreeBlock;
|
|
|
|
|
|
|
|
|
|
// Starting block list that will be used for further memory allocation
|
|
|
|
|
block_s< aclass, blocksize > *m_StartUsedBlock;
|
|
|
|
|
|
|
|
|
|
// Full block list [not usable], no space available for further memory allocation
|
|
|
|
|
block_s< aclass, blocksize > *m_StartFullBlock;
|
|
|
|
|
#else
|
|
|
|
|
block_s< aclass, blocksize > *m_Block;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
unsigned int m_BlockCount;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
unsigned int Count( block_s< aclass, blocksize > *block );
|
|
|
|
|
static constexpr size_t bitsNeeded =
|
|
|
|
|
blocksize <= 0x80 ? 8 :
|
|
|
|
|
blocksize <= 0x8000 ? 16 :
|
|
|
|
|
blocksize <= 0x80000000 ? 32 :
|
|
|
|
|
64;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
MEM_BlockAlloc();
|
|
|
|
|
block_s();
|
|
|
|
|
|
|
|
|
|
void *Alloc( void );
|
|
|
|
|
void Free( void *ptr );
|
|
|
|
|
void FreeAll( void );
|
|
|
|
|
unsigned int Count( void );
|
|
|
|
|
unsigned int BlockCount( void );
|
|
|
|
|
unsigned int BlockMemory( void );
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template< typename aclass, typename blocksize >
|
|
|
|
|
class MEM_BlockAlloc_enum {
|
|
|
|
|
protected:
|
|
|
|
|
MEM_BlockAlloc< aclass, blocksize > *m_Owner;
|
|
|
|
|
block_s< aclass, blocksize > *m_CurrentBlock;
|
|
|
|
|
#ifndef _DEBUG_MEMBLOCK
|
|
|
|
|
unsigned char m_CurrentData;
|
|
|
|
|
int m_CurrentBlockType;
|
|
|
|
|
#if !_DEBUG_MEMBLOCK
|
|
|
|
|
bool usedDataAvailable() const;
|
|
|
|
|
bool freeDataAvailable() const;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
MEM_BlockAlloc_enum( MEM_BlockAlloc< aclass, blocksize >& owner );
|
|
|
|
|
template<size_t bits>
|
|
|
|
|
struct selectType_t;
|
|
|
|
|
|
|
|
|
|
aclass *NextElement( void );
|
|
|
|
|
aclass *CurrentElement( void );
|
|
|
|
|
};
|
|
|
|
|
template<> struct selectType_t<8> { using type = uint8_t; };
|
|
|
|
|
template<> struct selectType_t<16> { using type = uint16_t; };
|
|
|
|
|
template<> struct selectType_t<32> { using type = uint32_t; };
|
|
|
|
|
template<> struct selectType_t<64> { using type = uint64_t; };
|
|
|
|
|
|
|
|
|
|
template< typename a, typename b >
|
|
|
|
|
MEM_BlockAlloc< a, b >::MEM_BlockAlloc( void )
|
|
|
|
|
{
|
|
|
|
|
#ifndef _DEBUG_MEMBLOCK
|
|
|
|
|
m_FreeBlock = NULL;
|
|
|
|
|
m_StartUsedBlock = NULL;
|
|
|
|
|
m_StartFullBlock = NULL;
|
|
|
|
|
m_BlockCount = 0;
|
|
|
|
|
using offset_t = typename selectType_t<bitsNeeded>::type;
|
|
|
|
|
|
|
|
|
|
struct info_t {
|
|
|
|
|
offset_t index;
|
|
|
|
|
alloc_source_e source;
|
|
|
|
|
static constexpr uint16_t typeSize = sizeof(aclass);
|
|
|
|
|
alignas(alignof(aclass)) char data[sizeof(aclass)];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
#if !_DEBUG_MEMBLOCK
|
|
|
|
|
info_t data[blocksize];
|
|
|
|
|
offset_t prev_data[blocksize];
|
|
|
|
|
offset_t next_data[blocksize];
|
|
|
|
|
|
|
|
|
|
offset_t free_data;
|
|
|
|
|
offset_t used_data;
|
|
|
|
|
bool has_free_data : 1;
|
|
|
|
|
bool has_used_data : 1;
|
|
|
|
|
#else
|
|
|
|
|
m_Block = NULL;
|
|
|
|
|
offset_t data[sizeof(aclass)];
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
block_s<aclass, blocksize>* prev_block;
|
|
|
|
|
block_s<aclass, blocksize>* next_block;
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
static constexpr size_t headersize = offsetof(info_t, data);
|
|
|
|
|
static constexpr size_t dataoffset = 0;
|
|
|
|
|
static constexpr size_t datasize = sizeof(info_t);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template<typename aclass, size_t blocksize>
|
|
|
|
|
block_s<aclass, blocksize>::block_s()
|
|
|
|
|
#if !_DEBUG_MEMBLOCK
|
|
|
|
|
{
|
|
|
|
|
info_t* header;
|
|
|
|
|
offset_t curr;
|
|
|
|
|
for (curr = 0; curr < blocksize - 1; ++curr)
|
|
|
|
|
{
|
|
|
|
|
offset_t next = curr + 1;
|
|
|
|
|
header = &data[curr];
|
|
|
|
|
header->source = alloc_source_e::SourceBlock;
|
|
|
|
|
header->index = curr;
|
|
|
|
|
prev_data[next] = curr;
|
|
|
|
|
next_data[curr] = next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
header = &data[curr];
|
|
|
|
|
header->source = alloc_source_e::SourceBlock;
|
|
|
|
|
header->index = blocksize - 1;
|
|
|
|
|
prev_data[0] = blocksize - 1;
|
|
|
|
|
next_data[blocksize - 1] = 0;
|
|
|
|
|
free_data = 0;
|
|
|
|
|
prev_block = next_block = nullptr;
|
|
|
|
|
|
|
|
|
|
has_free_data = true;
|
|
|
|
|
has_used_data = false;
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
: prev_block(nullptr)
|
|
|
|
|
, next_block(nullptr)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if !_DEBUG_MEMBLOCK
|
|
|
|
|
template<typename aclass, size_t blocksize>
|
|
|
|
|
bool block_s<aclass, blocksize>::usedDataAvailable() const {
|
|
|
|
|
return has_used_data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template< typename a, typename b >
|
|
|
|
|
void *MEM_BlockAlloc< a, b >::Alloc( void )
|
|
|
|
|
{
|
|
|
|
|
#ifdef _DEBUG_MEMBLOCK
|
|
|
|
|
block_s<a, b> *block = ( block_s<a, b> * )malloc( sizeof( block_s <a, b> ) );
|
|
|
|
|
template<typename aclass, size_t blocksize>
|
|
|
|
|
bool block_s<aclass, blocksize>::freeDataAvailable() const {
|
|
|
|
|
return has_free_data;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
LL_SafeAddFirst( m_Block, block, next_block, prev_block );
|
|
|
|
|
template<typename aclass, size_t blocksize = DefaultBlock>
|
|
|
|
|
class MEM_BlockAlloc
|
|
|
|
|
{
|
|
|
|
|
static_assert(blocksize >= 2, "Minimum 2x class preallocation required!!");
|
|
|
|
|
public:
|
|
|
|
|
MEM_BlockAlloc();
|
|
|
|
|
~MEM_BlockAlloc();
|
|
|
|
|
|
|
|
|
|
void* Alloc();
|
|
|
|
|
void Free(void* ptr) noexcept;
|
|
|
|
|
void FreeAll() noexcept;
|
|
|
|
|
size_t Count();
|
|
|
|
|
size_t BlockCount();
|
|
|
|
|
size_t BlockMemory();
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
friend class MEM_BlockAlloc_enum<aclass, blocksize>;
|
|
|
|
|
using block_t = block_s<aclass, blocksize>;
|
|
|
|
|
using block_offset_t = typename block_t::offset_t;
|
|
|
|
|
|
|
|
|
|
#if !_DEBUG_MEMBLOCK
|
|
|
|
|
block_t* m_FreeBlock;
|
|
|
|
|
block_t* m_StartUsedBlock;
|
|
|
|
|
block_t* m_StartFullBlock;
|
|
|
|
|
#else
|
|
|
|
|
block_t* m_Block;
|
|
|
|
|
#endif
|
|
|
|
|
size_t m_BlockCount;
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
void* TakeFree(block_t* block, uintptr_t free_data);
|
|
|
|
|
size_t Count(const block_t* block);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template<typename aclass, size_t blocksize = DefaultBlock>
|
|
|
|
|
class MEM_BlockAlloc_enum
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
MEM_BlockAlloc_enum(MEM_BlockAlloc<aclass, blocksize>& owner);
|
|
|
|
|
|
|
|
|
|
aclass* NextElement();
|
|
|
|
|
aclass* CurrentElement();
|
|
|
|
|
|
|
|
|
|
enum blockType_e {
|
|
|
|
|
used,
|
|
|
|
|
full
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
using block_t = block_s<aclass, blocksize>;
|
|
|
|
|
using offset_t = typename block_t::offset_t;
|
|
|
|
|
|
|
|
|
|
MEM_BlockAlloc<aclass, blocksize>* m_Owner;
|
|
|
|
|
block_t* m_CurrentBlock;
|
|
|
|
|
|
|
|
|
|
#if !_DEBUG_MEMBLOCK
|
|
|
|
|
offset_t m_CurrentData;
|
|
|
|
|
blockType_e m_CurrentBlockType;
|
|
|
|
|
#endif
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template<typename a, size_t b>
|
|
|
|
|
MEM_BlockAlloc<a, b>::MEM_BlockAlloc()
|
|
|
|
|
#if !_DEBUG_MEMBLOCK
|
|
|
|
|
: m_StartUsedBlock()
|
|
|
|
|
, m_StartFullBlock()
|
|
|
|
|
{
|
|
|
|
|
m_FreeBlock = nullptr;
|
|
|
|
|
m_BlockCount = 0;
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
: m_Block()
|
|
|
|
|
{
|
|
|
|
|
m_BlockCount = 0;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
template<typename a, size_t b>
|
|
|
|
|
MEM_BlockAlloc<a, b>::~MEM_BlockAlloc()
|
|
|
|
|
{
|
|
|
|
|
FreeAll();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename a, size_t b>
|
|
|
|
|
void* MEM_BlockAlloc<a, b>::Alloc()
|
|
|
|
|
{
|
|
|
|
|
#if _DEBUG_MEMBLOCK
|
|
|
|
|
block_t* block = new(MEM_Alloc(sizeof(block_t))) block_t();
|
|
|
|
|
|
|
|
|
|
m_Block.AddFirst(block);
|
|
|
|
|
|
|
|
|
|
m_BlockCount++;
|
|
|
|
|
return ( void * )block->data;
|
|
|
|
|
return (void*)block->data;
|
|
|
|
|
#else
|
|
|
|
|
unsigned char i;
|
|
|
|
|
block_s< a, b > *block;
|
|
|
|
|
block_s< a, b > *used_block;
|
|
|
|
|
short int free_data;
|
|
|
|
|
short int used_data;
|
|
|
|
|
unsigned char prev_data;
|
|
|
|
|
unsigned char next_data;
|
|
|
|
|
block_t* used_block;
|
|
|
|
|
block_offset_t free_data;
|
|
|
|
|
block_offset_t next_data;
|
|
|
|
|
|
|
|
|
|
block = m_StartUsedBlock;
|
|
|
|
|
if( block )
|
|
|
|
|
if (m_StartUsedBlock)
|
|
|
|
|
{
|
|
|
|
|
used_block = m_StartUsedBlock;
|
|
|
|
|
|
|
|
|
|
free_data = used_block->free_data;
|
|
|
|
|
next_data = used_block->next_data[ free_data ];
|
|
|
|
|
next_data = used_block->next_data[free_data];
|
|
|
|
|
|
|
|
|
|
if( next_data == free_data )
|
|
|
|
|
if (next_data == free_data)
|
|
|
|
|
{
|
|
|
|
|
// Move the block to the full block list as there is no space available
|
|
|
|
|
m_StartUsedBlock = block->next_block;
|
|
|
|
|
// Move the block to the next block list as there is no space available
|
|
|
|
|
m_StartUsedBlock = used_block->next_block;
|
|
|
|
|
|
|
|
|
|
LL_SafeRemove( block, next_block, prev_block );
|
|
|
|
|
LL_SafeAddFirst( m_StartFullBlock, used_block, next_block, prev_block );
|
|
|
|
|
LL_SafeRemoveRoot(m_StartUsedBlock, used_block, next_block, prev_block);
|
|
|
|
|
LL_SafeAddFirst(m_StartFullBlock, used_block, next_block, prev_block);
|
|
|
|
|
|
|
|
|
|
used_block->free_data = -1;
|
|
|
|
|
|
|
|
|
|
goto _ret;
|
|
|
|
|
used_block->has_free_data = false;
|
|
|
|
|
return TakeFree(used_block, free_data);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
block = m_FreeBlock;
|
|
|
|
|
if( block )
|
|
|
|
|
if (m_FreeBlock)
|
|
|
|
|
{
|
|
|
|
|
m_FreeBlock = NULL;
|
|
|
|
|
used_block = block;
|
|
|
|
|
free_data = block->free_data;
|
|
|
|
|
next_data = block->next_data[ free_data ];
|
|
|
|
|
// start from the free block
|
|
|
|
|
used_block = m_FreeBlock;
|
|
|
|
|
m_FreeBlock = nullptr;
|
|
|
|
|
free_data = used_block->free_data;
|
|
|
|
|
next_data = used_block->next_data[free_data];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
m_BlockCount++;
|
|
|
|
|
used_block = ( block_s< a, b > * )MEM_Alloc( sizeof( block_s< a, b > ) );
|
|
|
|
|
|
|
|
|
|
for( i = sizeof( b ) - 1; i; i-- )
|
|
|
|
|
{
|
|
|
|
|
unsigned char prev = i - 1;
|
|
|
|
|
unsigned char next = prev + 1;
|
|
|
|
|
used_block->data[ prev ][ 0 ] = -82;
|
|
|
|
|
used_block->data[ prev ][ 1 ] = prev;
|
|
|
|
|
*( short * )( &used_block->data[ prev ][ 2 ] ) = sizeof( a );
|
|
|
|
|
used_block->prev_data[ next ] = prev;
|
|
|
|
|
used_block->next_data[ prev ] = next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
used_block->data[ sizeof( b ) - 1 ][ 0 ] = -82;
|
|
|
|
|
used_block->data[ sizeof( b ) - 1 ][ 1 ] = -1;
|
|
|
|
|
*( short * )( &used_block->data[ sizeof( b ) - 1 ][ 2 ] ) = sizeof( a );
|
|
|
|
|
used_block->prev_data[ 0 ] = -1;
|
|
|
|
|
used_block->next_data[ sizeof( b ) - 1 ] = 0;
|
|
|
|
|
used_block->free_data = 0;
|
|
|
|
|
used_block->used_data = -1;
|
|
|
|
|
// allocate and construct a new block
|
|
|
|
|
used_block = new(MEM_Alloc(sizeof(block_t))) block_t();
|
|
|
|
|
|
|
|
|
|
free_data = 0;
|
|
|
|
|
next_data = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LL_SafeAddFirst( m_StartUsedBlock, used_block, next_block, prev_block );
|
|
|
|
|
LL_SafeAddFirst(m_StartUsedBlock, used_block, next_block, prev_block);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
prev_data = used_block->prev_data[ free_data ];
|
|
|
|
|
used_block->next_data[ prev_data ] = next_data;
|
|
|
|
|
used_block->prev_data[ next_data ] = prev_data;
|
|
|
|
|
used_block->free_data = next_data;
|
|
|
|
|
const block_offset_t prev_data = used_block->prev_data[free_data];
|
|
|
|
|
|
|
|
|
|
if( used_block->used_data < 0 )
|
|
|
|
|
used_block->next_data[prev_data] = next_data;
|
|
|
|
|
used_block->prev_data[next_data] = prev_data;
|
|
|
|
|
used_block->free_data = next_data;
|
|
|
|
|
used_block->has_free_data = true;
|
|
|
|
|
|
|
|
|
|
if (!used_block->usedDataAvailable())
|
|
|
|
|
{
|
|
|
|
|
used_block->used_data = free_data;
|
|
|
|
|
used_block->next_data[ free_data ] = free_data;
|
|
|
|
|
used_block->prev_data[ free_data ] = free_data;
|
|
|
|
|
return ( void * )&used_block->data[ free_data ][ 8 ];
|
|
|
|
|
used_block->has_used_data = true;
|
|
|
|
|
used_block->next_data[free_data] = free_data;
|
|
|
|
|
used_block->prev_data[free_data] = free_data;
|
|
|
|
|
return used_block->data[free_data].data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_ret:
|
|
|
|
|
used_data = used_block->used_data;
|
|
|
|
|
prev_data = used_block->prev_data[ used_data ];
|
|
|
|
|
used_block->prev_data[ used_data ] = free_data;
|
|
|
|
|
used_block->next_data[ prev_data ] = free_data;
|
|
|
|
|
used_block->prev_data[ free_data ] = prev_data;
|
|
|
|
|
used_block->next_data[ free_data ] = used_data;
|
|
|
|
|
return ( void * )&used_block->data[ free_data ][ 8 ];
|
|
|
|
|
return TakeFree(used_block, free_data);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template< typename a, typename b >
|
|
|
|
|
void MEM_BlockAlloc< a, b >::Free( void *ptr )
|
|
|
|
|
template< typename aclass, size_t blocksize>
|
|
|
|
|
void* MEM_BlockAlloc<aclass, blocksize>::TakeFree(block_t* block, uintptr_t free_data)
|
|
|
|
|
{
|
|
|
|
|
#ifdef _DEBUG_MEMBLOCK
|
|
|
|
|
block_s<a, b> *block = ( block_s<a, b> * )ptr;
|
|
|
|
|
const block_offset_t used_data = block->used_data;
|
|
|
|
|
const block_offset_t prev_data = block->prev_data[used_data];
|
|
|
|
|
|
|
|
|
|
assert( m_Block );
|
|
|
|
|
LL_SafeRemove( block, next_block, prev_block );
|
|
|
|
|
block->next_data[prev_data] = (block_offset_t)free_data;
|
|
|
|
|
block->prev_data[used_data] = (block_offset_t)free_data;
|
|
|
|
|
block->next_data[free_data] = used_data;
|
|
|
|
|
block->prev_data[free_data] = prev_data;
|
|
|
|
|
return block->data[free_data].data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( m_Block == block )
|
|
|
|
|
{
|
|
|
|
|
m_Block = block->next_block;
|
|
|
|
|
}
|
|
|
|
|
template<typename a, size_t b>
|
|
|
|
|
void MEM_BlockAlloc<a, b>::Free(void* ptr) noexcept
|
|
|
|
|
{
|
|
|
|
|
#if _DEBUG_MEMBLOCK
|
|
|
|
|
block_s<a, b>* block = (block_s<a, b> *)ptr;
|
|
|
|
|
|
|
|
|
|
m_Block.Remove(block);
|
|
|
|
|
|
|
|
|
|
m_BlockCount--;
|
|
|
|
|
free( block );
|
|
|
|
|
MEM::Free(block);
|
|
|
|
|
#else
|
|
|
|
|
block_s< a, b > *block;
|
|
|
|
|
short int free_data;
|
|
|
|
|
short int used_data;
|
|
|
|
|
unsigned char prev_data;
|
|
|
|
|
unsigned char next_data;
|
|
|
|
|
|
|
|
|
|
used_data = *( ( unsigned char * )ptr - 7 );
|
|
|
|
|
block = ( block_s< a, b > * )( ( unsigned char * )ptr + -( used_data * ( *( ( unsigned short * )ptr - 3 ) + 8 ) ) - 8 );
|
|
|
|
|
next_data = block->next_data[ used_data ];
|
|
|
|
|
if( next_data == used_data )
|
|
|
|
|
// get the header of the pointer
|
|
|
|
|
typename block_t::info_t* header = reinterpret_cast<typename block_t::info_t*>(static_cast<unsigned char*>(ptr) - block_t::headersize);
|
|
|
|
|
const block_offset_t used_data = header->index;
|
|
|
|
|
// get the block from the header
|
|
|
|
|
block_t* const block = (block_t*)((uint8_t*)header - used_data * block_t::datasize - block_t::dataoffset);
|
|
|
|
|
const block_offset_t next_data = block->next_data[used_data];
|
|
|
|
|
if (next_data == used_data)
|
|
|
|
|
{
|
|
|
|
|
if( m_StartUsedBlock == block )
|
|
|
|
|
{
|
|
|
|
|
m_StartUsedBlock = block->next_block;
|
|
|
|
|
}
|
|
|
|
|
LL_SafeRemoveRoot(m_StartUsedBlock, block, next_block, prev_block);
|
|
|
|
|
|
|
|
|
|
LL_SafeRemove( block, next_block, prev_block );
|
|
|
|
|
|
|
|
|
|
if( m_FreeBlock )
|
|
|
|
|
if (m_FreeBlock)
|
|
|
|
|
{
|
|
|
|
|
m_BlockCount--;
|
|
|
|
|
MEM_Free( m_FreeBlock );
|
|
|
|
|
m_FreeBlock = NULL;
|
|
|
|
|
// deallocate the free block because of another deallocation
|
|
|
|
|
--m_BlockCount;
|
|
|
|
|
MEM_Free(m_FreeBlock);
|
|
|
|
|
m_FreeBlock = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_FreeBlock = block;
|
|
|
|
|
block->used_data = -1;
|
|
|
|
|
block->has_used_data = false;
|
|
|
|
|
|
|
|
|
|
free_data = block->free_data;
|
|
|
|
|
prev_data = block->prev_data[ free_data ];
|
|
|
|
|
const block_offset_t free_data = block->free_data;
|
|
|
|
|
const block_offset_t prev_data = block->prev_data[free_data];
|
|
|
|
|
|
|
|
|
|
block->next_data[ prev_data ] = used_data;
|
|
|
|
|
block->prev_data[ free_data ] = used_data;
|
|
|
|
|
block->next_data[ used_data ] = free_data;
|
|
|
|
|
block->prev_data[ used_data ] = prev_data;
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
block->next_data[prev_data] = used_data;
|
|
|
|
|
block->prev_data[free_data] = used_data;
|
|
|
|
|
block->next_data[used_data] = free_data;
|
|
|
|
|
block->prev_data[used_data] = prev_data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
prev_data = block->prev_data[ used_data ];
|
|
|
|
|
|
|
|
|
|
block->next_data[ prev_data ] = next_data;
|
|
|
|
|
block->prev_data[ next_data ] = prev_data;
|
|
|
|
|
block->used_data = next_data;
|
|
|
|
|
|
|
|
|
|
if( block->free_data >= 0 )
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
free_data = block->free_data;
|
|
|
|
|
prev_data = block->prev_data[ free_data ];
|
|
|
|
|
const block_offset_t prev_data = block->prev_data[used_data];
|
|
|
|
|
|
|
|
|
|
block->next_data[ prev_data ] = used_data;
|
|
|
|
|
block->prev_data[ free_data ] = used_data;
|
|
|
|
|
block->next_data[ used_data ] = free_data;
|
|
|
|
|
block->prev_data[ used_data ] = prev_data;
|
|
|
|
|
return;
|
|
|
|
|
block->next_data[prev_data] = next_data;
|
|
|
|
|
block->prev_data[next_data] = prev_data;
|
|
|
|
|
block->used_data = next_data;
|
|
|
|
|
block->has_used_data = true;
|
|
|
|
|
|
|
|
|
|
if (block->freeDataAvailable())
|
|
|
|
|
{
|
|
|
|
|
const block_offset_t free_data = block->free_data;
|
|
|
|
|
const block_offset_t prev_data = block->prev_data[free_data];
|
|
|
|
|
|
|
|
|
|
block->next_data[prev_data] = used_data;
|
|
|
|
|
block->prev_data[free_data] = used_data;
|
|
|
|
|
block->next_data[used_data] = free_data;
|
|
|
|
|
block->prev_data[used_data] = prev_data;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_StartFullBlock == block)
|
|
|
|
|
{
|
|
|
|
|
m_StartFullBlock = block->next_block;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LL_SafeRemoveRoot(m_StartFullBlock, block, next_block, prev_block);
|
|
|
|
|
LL_SafeAddFirst(m_StartUsedBlock, block, next_block, prev_block);
|
|
|
|
|
|
|
|
|
|
block->free_data = used_data;
|
|
|
|
|
block->has_free_data = true;
|
|
|
|
|
block->prev_data[used_data] = used_data;
|
|
|
|
|
block->next_data[used_data] = used_data;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( m_StartFullBlock == block )
|
|
|
|
|
{
|
|
|
|
|
m_StartFullBlock = block->next_block;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LL_SafeRemove( block, next_block, prev_block );
|
|
|
|
|
LL_SafeAddFirst( m_StartUsedBlock, block, next_block, prev_block );
|
|
|
|
|
|
|
|
|
|
block->prev_data[ used_data ] = used_data;
|
|
|
|
|
block->next_data[ used_data ] = used_data;
|
|
|
|
|
block->free_data = used_data;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template< typename a, typename b >
|
|
|
|
|
void MEM_BlockAlloc< a, b >::FreeAll( void )
|
|
|
|
|
template<typename a, size_t b>
|
|
|
|
|
void MEM_BlockAlloc<a, b>::FreeAll() noexcept
|
|
|
|
|
{
|
|
|
|
|
#ifdef _DEBUG_MEMBLOCK
|
|
|
|
|
block_s<a, b> *block;
|
|
|
|
|
block_s<a, b> *next = m_Block;
|
|
|
|
|
for( block = m_Block; next != NULL; block = next )
|
|
|
|
|
#if _DEBUG_MEMBLOCK
|
|
|
|
|
block_t* block;
|
|
|
|
|
block_t* next = m_Block.Root();
|
|
|
|
|
for (block = next; block; block = next)
|
|
|
|
|
{
|
|
|
|
|
next = block->next_block;
|
|
|
|
|
m_BlockCount--;
|
|
|
|
|
a *ptr = ( a * )block->data;
|
|
|
|
|
a* ptr = (a*)block->data;
|
|
|
|
|
ptr->~a();
|
|
|
|
|
free( block );
|
|
|
|
|
MEM::Free(block);
|
|
|
|
|
}
|
|
|
|
|
m_Block = NULL;
|
|
|
|
|
m_Block.Reset();
|
|
|
|
|
#else
|
|
|
|
|
block_s< a, b > *block;
|
|
|
|
|
|
|
|
|
|
block = m_StartFullBlock;
|
|
|
|
|
while( block )
|
|
|
|
|
while(block_t* b = m_StartFullBlock)
|
|
|
|
|
{
|
|
|
|
|
if( block->used_data >= 0 )
|
|
|
|
|
if (b->usedDataAvailable())
|
|
|
|
|
{
|
|
|
|
|
a *ptr = ( a * )&block->data[ block->used_data ][ 8 ];
|
|
|
|
|
delete ptr;
|
|
|
|
|
block = m_StartFullBlock;
|
|
|
|
|
a* ptr = (a*)b->data[b->used_data].data;
|
|
|
|
|
ptr->~a();
|
|
|
|
|
Free(ptr);
|
|
|
|
|
b = m_StartFullBlock;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
block = m_StartUsedBlock;
|
|
|
|
|
while( block )
|
|
|
|
|
while (block_t* b = m_StartUsedBlock)
|
|
|
|
|
{
|
|
|
|
|
if( block->used_data >= 0 )
|
|
|
|
|
if (b->usedDataAvailable())
|
|
|
|
|
{
|
|
|
|
|
a *ptr = ( a * )&block->data[ block->used_data ][ 8 ];
|
|
|
|
|
delete ptr;
|
|
|
|
|
block = m_StartUsedBlock;
|
|
|
|
|
a* ptr = (a*)b->data[b->used_data].data;
|
|
|
|
|
ptr->~a();
|
|
|
|
|
Free(ptr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( m_FreeBlock )
|
|
|
|
|
if (m_FreeBlock)
|
|
|
|
|
{
|
|
|
|
|
m_BlockCount--;
|
|
|
|
|
MEM_Free( m_FreeBlock );
|
|
|
|
|
m_FreeBlock = NULL;
|
|
|
|
|
MEM_Free(m_FreeBlock);
|
|
|
|
|
m_FreeBlock = nullptr;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template< typename a, typename b >
|
|
|
|
|
unsigned int MEM_BlockAlloc< a, b >::Count( block_s< a, b > *block )
|
|
|
|
|
template<typename a, size_t b>
|
|
|
|
|
size_t MEM_BlockAlloc<a, b>::Count(const block_t* list)
|
|
|
|
|
{
|
|
|
|
|
int count = 0;
|
|
|
|
|
#ifdef _DEBUG_MEMBLOCK
|
|
|
|
|
for( ; block != NULL; block = block->next_block )
|
|
|
|
|
#if _DEBUG_MEMBLOCK
|
|
|
|
|
for (const block_t* block = list; block; block = block->next_block)
|
|
|
|
|
{
|
|
|
|
|
count++;
|
|
|
|
|
}
|
|
|
|
|
return count;
|
|
|
|
|
#else
|
|
|
|
|
unsigned char used_data;
|
|
|
|
|
unsigned char current_used_data;
|
|
|
|
|
|
|
|
|
|
for( ; block != NULL; block = block->next_block )
|
|
|
|
|
for (const block_t* block = list; block; block = block->next_block)
|
|
|
|
|
{
|
|
|
|
|
used_data = block->used_data;
|
|
|
|
|
|
|
|
|
|
if( used_data < 0 )
|
|
|
|
|
if (!block->usedDataAvailable())
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
current_used_data = used_data;
|
|
|
|
|
const block_offset_t used_data = block->used_data;
|
|
|
|
|
block_offset_t current_used_data = used_data;
|
|
|
|
|
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
count++;
|
|
|
|
|
current_used_data = block->next_data[ current_used_data ];
|
|
|
|
|
} while( current_used_data != used_data );
|
|
|
|
|
current_used_data = block->next_data[current_used_data];
|
|
|
|
|
} while (current_used_data != used_data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return count;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template< typename a, typename b >
|
|
|
|
|
unsigned int MEM_BlockAlloc< a, b >::Count( void )
|
|
|
|
|
template<typename a, size_t b>
|
|
|
|
|
size_t MEM_BlockAlloc<a, b>::Count()
|
|
|
|
|
{
|
|
|
|
|
#ifdef _DEBUG_MEMBLOCK
|
|
|
|
|
return Count( m_Block );
|
|
|
|
|
#if _DEBUG_MEMBLOCK
|
|
|
|
|
return Count(m_Block);
|
|
|
|
|
#else
|
|
|
|
|
return Count( m_StartFullBlock ) + Count( m_StartUsedBlock );
|
|
|
|
|
return Count(m_StartFullBlock) + Count(m_StartUsedBlock);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template< typename a, typename b >
|
|
|
|
|
unsigned int MEM_BlockAlloc< a, b >::BlockCount( void )
|
|
|
|
|
template<typename a, size_t b>
|
|
|
|
|
size_t MEM_BlockAlloc<a, b>::BlockCount()
|
|
|
|
|
{
|
|
|
|
|
return m_BlockCount;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template< typename a, typename b >
|
|
|
|
|
unsigned int MEM_BlockAlloc< a, b >::BlockMemory( void )
|
|
|
|
|
template<typename a, size_t b>
|
|
|
|
|
size_t MEM_BlockAlloc<a, b>::BlockMemory()
|
|
|
|
|
{
|
|
|
|
|
return sizeof( block_s< a, b > );
|
|
|
|
|
return sizeof(block_s<a, b>);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
template< typename a, typename b >
|
|
|
|
|
MEM_BlockAlloc_enum< a, b >::MEM_BlockAlloc_enum( MEM_BlockAlloc< a, b >& owner )
|
|
|
|
|
template<typename a, size_t b>
|
|
|
|
|
MEM_BlockAlloc_enum<a, b >::MEM_BlockAlloc_enum(MEM_BlockAlloc< a, b>& owner)
|
|
|
|
|
{
|
|
|
|
|
m_Owner = &owner;
|
|
|
|
|
m_CurrentBlock = NULL;
|
|
|
|
|
#ifndef _DEBUG_MEMBLOCK
|
|
|
|
|
m_CurrentBlockType = 0;
|
|
|
|
|
m_CurrentBlock = nullptr;
|
|
|
|
|
#if !_DEBUG_MEMBLOCK
|
|
|
|
|
m_CurrentBlockType = MEM_BlockAlloc_enum::used;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template< typename a, typename b >
|
|
|
|
|
a *MEM_BlockAlloc_enum< a, b >::NextElement( void )
|
|
|
|
|
template<typename a, size_t b>
|
|
|
|
|
a* MEM_BlockAlloc_enum<a, b>::NextElement()
|
|
|
|
|
{
|
|
|
|
|
#ifdef _DEBUG_MEMBLOCK
|
|
|
|
|
if( !m_CurrentBlock )
|
|
|
|
|
#if _DEBUG_MEMBLOCK
|
|
|
|
|
if (!m_CurrentBlock)
|
|
|
|
|
{
|
|
|
|
|
m_CurrentBlock = m_Owner->m_Block;
|
|
|
|
|
m_CurrentBlock = m_Owner->m_Block.Root();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
m_CurrentBlock = m_CurrentBlock->next_block;
|
|
|
|
|
}
|
|
|
|
|
return ( a * )m_CurrentBlock;
|
|
|
|
|
return (a*)m_CurrentBlock;
|
|
|
|
|
#else
|
|
|
|
|
block_s< a, b > *block;
|
|
|
|
|
block_s< a, b > *next;
|
|
|
|
|
|
|
|
|
|
block = m_CurrentBlock;
|
|
|
|
|
|
|
|
|
|
if( block )
|
|
|
|
|
// search for a valid block type
|
|
|
|
|
while (!m_CurrentBlock)
|
|
|
|
|
{
|
|
|
|
|
m_CurrentData = block->next_data[ m_CurrentData ];
|
|
|
|
|
if( m_CurrentData == block->used_data )
|
|
|
|
|
switch (m_CurrentBlockType)
|
|
|
|
|
{
|
|
|
|
|
block = m_CurrentBlock = block->next_block;
|
|
|
|
|
case blockType_e::used:
|
|
|
|
|
m_CurrentBlock = m_Owner->m_StartUsedBlock;
|
|
|
|
|
break;
|
|
|
|
|
case blockType_e::full:
|
|
|
|
|
m_CurrentBlock = m_Owner->m_StartFullBlock;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
reinterpret_cast<uint8_t&>(m_CurrentBlockType)++;
|
|
|
|
|
|
|
|
|
|
_label:
|
|
|
|
|
for (; m_CurrentBlock; m_CurrentBlock = m_CurrentBlock->next_block)
|
|
|
|
|
{
|
|
|
|
|
if (m_CurrentBlock->usedDataAvailable())
|
|
|
|
|
{
|
|
|
|
|
m_CurrentData = m_CurrentBlock->used_data;
|
|
|
|
|
return reinterpret_cast<a*>(m_CurrentBlock->data[m_CurrentData].data);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if( !block )
|
|
|
|
|
m_CurrentData = m_CurrentBlock->next_data[m_CurrentData];
|
|
|
|
|
|
|
|
|
|
if (m_CurrentData == m_CurrentBlock->used_data)
|
|
|
|
|
{
|
|
|
|
|
while( !block )
|
|
|
|
|
{
|
|
|
|
|
while( !block )
|
|
|
|
|
{
|
|
|
|
|
if( m_CurrentBlockType == 0 )
|
|
|
|
|
{
|
|
|
|
|
block = m_Owner->m_StartFullBlock;
|
|
|
|
|
}
|
|
|
|
|
else if( m_CurrentBlockType == 1 )
|
|
|
|
|
{
|
|
|
|
|
block = m_Owner->m_StartUsedBlock;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_CurrentBlock = block;
|
|
|
|
|
m_CurrentBlockType++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while( block->used_data < 0 )
|
|
|
|
|
{
|
|
|
|
|
next = block->next_block;
|
|
|
|
|
block = NULL;
|
|
|
|
|
m_CurrentBlock = next;
|
|
|
|
|
|
|
|
|
|
if( !next )
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
block = next;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_CurrentData = block->used_data;
|
|
|
|
|
// found an object
|
|
|
|
|
m_CurrentBlock = m_CurrentBlock->next_block;
|
|
|
|
|
goto _label;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ( a * )&block->data[ m_CurrentData ][ 8 ];
|
|
|
|
|
return reinterpret_cast<a*>(m_CurrentBlock->data[m_CurrentData].data);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template< typename a, typename b >
|
|
|
|
|
a *MEM_BlockAlloc_enum< a, b >::CurrentElement( void )
|
|
|
|
|
template<typename a, size_t b>
|
|
|
|
|
a* MEM_BlockAlloc_enum<a, b>::CurrentElement()
|
|
|
|
|
{
|
|
|
|
|
return m_CurrentBlock;
|
|
|
|
|
}
|
|
|
|
|