2016-03-27 11:49:47 +02:00
|
|
|
/*
|
|
|
|
===========================================================================
|
|
|
|
Copyright (C) 2015 the OpenMoHAA team
|
|
|
|
|
|
|
|
This file is part of OpenMoHAA source code.
|
|
|
|
|
|
|
|
OpenMoHAA source code is free software; you can redistribute it
|
|
|
|
and/or modify it under the terms of the GNU General Public License as
|
|
|
|
published by the Free Software Foundation; either version 2 of the License,
|
|
|
|
or (at your option) any later version.
|
|
|
|
|
|
|
|
OpenMoHAA source code is distributed in the hope that it will be
|
|
|
|
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with OpenMoHAA source code; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
===========================================================================
|
|
|
|
*/
|
|
|
|
|
|
|
|
// mem_blockalloc.h: Fast block memory manager
|
|
|
|
|
2023-02-01 00:28:40 +01:00
|
|
|
#pragma once
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-02-01 19:29:13 +01:00
|
|
|
#include "Linklist.h"
|
2023-01-30 17:11:44 +01:00
|
|
|
#include "q_shared.h"
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-02-01 00:28:40 +01:00
|
|
|
#include <cstddef>
|
|
|
|
#include <type_traits>
|
|
|
|
#include <new>
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
void *MEM_Alloc(int size);
|
|
|
|
void MEM_Free(void *ptr);
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-08-19 15:24:12 +02:00
|
|
|
#ifdef _DEBUG_MEM
|
|
|
|
# define _DEBUG_MEMBLOCK 1
|
|
|
|
#endif
|
|
|
|
|
2023-01-30 17:11:44 +01:00
|
|
|
static constexpr size_t DefaultBlock = 256;
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
enum class alloc_source_e {
|
|
|
|
SourceBlock = 174,
|
|
|
|
SourceMalloc
|
|
|
|
};
|
2023-01-30 17:11:44 +01:00
|
|
|
|
|
|
|
template<typename aclass, size_t blocksize>
|
2016-03-27 11:49:47 +02:00
|
|
|
class MEM_BlockAlloc_enum;
|
|
|
|
|
2023-02-06 19:24:01 +01:00
|
|
|
template<size_t bits>
|
|
|
|
struct block_selectType_t;
|
|
|
|
|
|
|
|
template<>
|
|
|
|
struct block_selectType_t<8> {
|
2023-07-05 21:23:39 +02:00
|
|
|
using type = uint8_t;
|
2023-02-06 19:24:01 +01:00
|
|
|
};
|
2023-07-05 21:23:39 +02:00
|
|
|
|
2023-02-06 19:24:01 +01:00
|
|
|
template<>
|
|
|
|
struct block_selectType_t<16> {
|
2023-07-05 21:23:39 +02:00
|
|
|
using type = uint16_t;
|
2023-02-06 19:24:01 +01:00
|
|
|
};
|
2023-07-05 21:23:39 +02:00
|
|
|
|
2023-02-06 19:24:01 +01:00
|
|
|
template<>
|
|
|
|
struct block_selectType_t<32> {
|
2023-07-05 21:23:39 +02:00
|
|
|
using type = uint32_t;
|
2023-02-06 19:24:01 +01:00
|
|
|
};
|
2023-07-05 21:23:39 +02:00
|
|
|
|
2023-02-06 19:24:01 +01:00
|
|
|
template<>
|
|
|
|
struct block_selectType_t<64> {
|
2023-07-05 21:23:39 +02:00
|
|
|
using type = uint64_t;
|
2023-02-06 19:24:01 +01:00
|
|
|
};
|
|
|
|
|
2023-01-30 17:11:44 +01:00
|
|
|
template<typename aclass, size_t blocksize>
|
2023-02-04 19:56:06 +01:00
|
|
|
class block_s
|
|
|
|
{
|
2023-01-30 17:11:44 +01:00
|
|
|
private:
|
2023-07-05 21:23:39 +02:00
|
|
|
static constexpr size_t bitsNeeded = blocksize <= 0x80 ? 8
|
|
|
|
: blocksize <= 0x8000 ? 16
|
|
|
|
: blocksize <= 0x80000000 ? 32
|
|
|
|
: 64;
|
2023-01-30 17:11:44 +01:00
|
|
|
|
|
|
|
public:
|
2023-02-04 19:56:06 +01:00
|
|
|
block_s();
|
2023-01-30 17:11:44 +01:00
|
|
|
|
|
|
|
#if !_DEBUG_MEMBLOCK
|
2023-02-04 19:56:06 +01:00
|
|
|
bool usedDataAvailable() const;
|
|
|
|
bool freeDataAvailable() const;
|
2023-01-30 17:11:44 +01:00
|
|
|
#endif
|
|
|
|
|
2016-03-27 11:49:47 +02:00
|
|
|
public:
|
2023-02-06 19:24:01 +01:00
|
|
|
using offset_t = typename block_selectType_t<bitsNeeded>::type;
|
2023-02-04 19:56:06 +01:00
|
|
|
|
|
|
|
struct info_t {
|
2023-07-05 21:23:39 +02:00
|
|
|
offset_t index;
|
|
|
|
alloc_source_e source;
|
2023-02-04 19:56:06 +01:00
|
|
|
static constexpr uint16_t typeSize = sizeof(aclass);
|
|
|
|
alignas(alignof(aclass)) char data[sizeof(aclass)];
|
|
|
|
};
|
2023-01-30 17:11:44 +01:00
|
|
|
|
|
|
|
public:
|
|
|
|
#if !_DEBUG_MEMBLOCK
|
2023-07-05 21:23:39 +02:00
|
|
|
info_t data[blocksize];
|
2023-02-04 19:56:06 +01:00
|
|
|
offset_t prev_data[blocksize];
|
|
|
|
offset_t next_data[blocksize];
|
|
|
|
|
|
|
|
offset_t free_data;
|
|
|
|
offset_t used_data;
|
2023-07-05 21:23:39 +02:00
|
|
|
bool has_free_data : 1;
|
|
|
|
bool has_used_data : 1;
|
2017-02-19 21:14:27 +01:00
|
|
|
#else
|
2023-02-04 19:56:06 +01:00
|
|
|
offset_t data[sizeof(aclass)];
|
2017-02-19 21:14:27 +01:00
|
|
|
#endif
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
block_s<aclass, blocksize> *prev_block;
|
|
|
|
block_s<aclass, blocksize> *next_block;
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-01-30 17:11:44 +01:00
|
|
|
public:
|
2023-02-04 19:56:06 +01:00
|
|
|
static constexpr size_t headersize = offsetof(info_t, data);
|
|
|
|
static constexpr size_t dataoffset = 0;
|
2023-07-05 21:23:39 +02:00
|
|
|
static constexpr size_t datasize = sizeof(info_t);
|
2023-01-30 17:11:44 +01:00
|
|
|
};
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-01-30 17:11:44 +01:00
|
|
|
template<typename aclass, size_t blocksize>
|
|
|
|
block_s<aclass, blocksize>::block_s()
|
|
|
|
#if !_DEBUG_MEMBLOCK
|
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
info_t *header;
|
2023-02-04 19:56:06 +01:00
|
|
|
offset_t curr;
|
|
|
|
for (curr = 0; curr < blocksize - 1; ++curr) {
|
2023-07-05 21:23:39 +02:00
|
|
|
offset_t next = curr + 1;
|
|
|
|
header = &data[curr];
|
|
|
|
header->source = alloc_source_e::SourceBlock;
|
|
|
|
header->index = curr;
|
2023-02-04 19:56:06 +01:00
|
|
|
prev_data[next] = curr;
|
|
|
|
next_data[curr] = next;
|
|
|
|
}
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
header = &data[curr];
|
|
|
|
header->source = alloc_source_e::SourceBlock;
|
|
|
|
header->index = blocksize - 1;
|
|
|
|
prev_data[0] = blocksize - 1;
|
2023-02-04 19:56:06 +01:00
|
|
|
next_data[blocksize - 1] = 0;
|
2023-07-05 21:23:39 +02:00
|
|
|
free_data = 0;
|
2023-02-04 19:56:06 +01:00
|
|
|
prev_block = next_block = nullptr;
|
|
|
|
|
|
|
|
has_free_data = true;
|
|
|
|
has_used_data = false;
|
2023-01-30 17:11:44 +01:00
|
|
|
}
|
2017-02-19 21:14:27 +01:00
|
|
|
#else
|
2023-07-05 21:23:39 +02:00
|
|
|
: prev_block(nullptr)
|
|
|
|
, next_block(nullptr)
|
2023-02-04 19:56:06 +01:00
|
|
|
{}
|
2017-02-19 21:14:27 +01:00
|
|
|
#endif
|
|
|
|
|
2023-01-30 17:11:44 +01:00
|
|
|
#if !_DEBUG_MEMBLOCK
|
|
|
|
template<typename aclass, size_t blocksize>
|
2023-02-04 19:56:06 +01:00
|
|
|
bool block_s<aclass, blocksize>::usedDataAvailable() const
|
|
|
|
{
|
|
|
|
return has_used_data;
|
2023-01-30 17:11:44 +01:00
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-01-30 17:11:44 +01:00
|
|
|
template<typename aclass, size_t blocksize>
|
2023-02-04 19:56:06 +01:00
|
|
|
bool block_s<aclass, blocksize>::freeDataAvailable() const
|
|
|
|
{
|
|
|
|
return has_free_data;
|
2023-01-30 17:11:44 +01:00
|
|
|
}
|
|
|
|
#endif
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-01-30 17:11:44 +01:00
|
|
|
template<typename aclass, size_t blocksize = DefaultBlock>
|
|
|
|
class MEM_BlockAlloc
|
|
|
|
{
|
2023-02-04 19:56:06 +01:00
|
|
|
static_assert(blocksize >= 2, "Minimum 2x class preallocation required!!");
|
|
|
|
|
2016-03-27 11:49:47 +02:00
|
|
|
public:
|
2023-02-04 19:56:06 +01:00
|
|
|
MEM_BlockAlloc();
|
|
|
|
~MEM_BlockAlloc();
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
void *Alloc();
|
|
|
|
void Free(void *ptr) noexcept;
|
|
|
|
void FreeAll() noexcept;
|
2023-02-04 19:56:06 +01:00
|
|
|
size_t Count();
|
|
|
|
size_t BlockCount();
|
|
|
|
size_t BlockMemory();
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-01-30 17:11:44 +01:00
|
|
|
private:
|
2023-02-04 19:56:06 +01:00
|
|
|
friend class MEM_BlockAlloc_enum<aclass, blocksize>;
|
2023-07-05 21:23:39 +02:00
|
|
|
using block_t = block_s<aclass, blocksize>;
|
2023-02-04 19:56:06 +01:00
|
|
|
using block_offset_t = typename block_t::offset_t;
|
2023-01-30 17:11:44 +01:00
|
|
|
|
|
|
|
#if !_DEBUG_MEMBLOCK
|
2023-07-05 21:23:39 +02:00
|
|
|
block_t *m_FreeBlock;
|
|
|
|
block_t *m_StartUsedBlock;
|
|
|
|
block_t *m_StartFullBlock;
|
2023-01-30 17:11:44 +01:00
|
|
|
#else
|
2023-07-05 21:23:39 +02:00
|
|
|
block_t *m_Block;
|
2017-02-19 21:14:27 +01:00
|
|
|
#endif
|
2023-02-04 19:56:06 +01:00
|
|
|
size_t m_BlockCount;
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-01-30 17:11:44 +01:00
|
|
|
private:
|
2023-07-05 21:23:39 +02:00
|
|
|
void *TakeFree(block_t *block, uintptr_t free_data);
|
|
|
|
size_t Count(const block_t *block);
|
2023-01-30 17:11:44 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
template<typename aclass, size_t blocksize = DefaultBlock>
|
|
|
|
class MEM_BlockAlloc_enum
|
|
|
|
{
|
2016-03-27 11:49:47 +02:00
|
|
|
public:
|
2023-02-04 19:56:06 +01:00
|
|
|
MEM_BlockAlloc_enum(MEM_BlockAlloc<aclass, blocksize>& owner);
|
2023-01-30 17:11:44 +01:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
aclass *NextElement();
|
|
|
|
aclass *CurrentElement();
|
2023-01-30 17:11:44 +01:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
enum blockType_e {
|
|
|
|
used,
|
|
|
|
full
|
|
|
|
};
|
2023-01-30 17:11:44 +01:00
|
|
|
|
|
|
|
private:
|
2023-07-05 21:23:39 +02:00
|
|
|
using block_t = block_s<aclass, blocksize>;
|
2023-02-04 19:56:06 +01:00
|
|
|
using offset_t = typename block_t::offset_t;
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
MEM_BlockAlloc<aclass, blocksize> *m_Owner;
|
|
|
|
block_t *m_CurrentBlock;
|
2023-01-30 17:11:44 +01:00
|
|
|
|
|
|
|
#if !_DEBUG_MEMBLOCK
|
2023-07-05 21:23:39 +02:00
|
|
|
offset_t m_CurrentData;
|
2023-02-04 19:56:06 +01:00
|
|
|
blockType_e m_CurrentBlockType;
|
2023-01-30 17:11:44 +01:00
|
|
|
#endif
|
2016-03-27 11:49:47 +02:00
|
|
|
};
|
|
|
|
|
2023-01-30 17:11:44 +01:00
|
|
|
template<typename a, size_t b>
|
|
|
|
MEM_BlockAlloc<a, b>::MEM_BlockAlloc()
|
|
|
|
#if !_DEBUG_MEMBLOCK
|
2023-07-05 21:23:39 +02:00
|
|
|
: m_StartUsedBlock()
|
|
|
|
, m_StartFullBlock()
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
m_FreeBlock = nullptr;
|
2023-02-04 19:56:06 +01:00
|
|
|
m_BlockCount = 0;
|
2023-01-30 17:11:44 +01:00
|
|
|
}
|
2017-02-19 21:14:27 +01:00
|
|
|
#else
|
2023-02-04 19:56:06 +01:00
|
|
|
: m_Block()
|
2023-01-30 17:11:44 +01:00
|
|
|
{
|
2023-02-04 19:56:06 +01:00
|
|
|
m_BlockCount = 0;
|
2023-01-30 17:11:44 +01:00
|
|
|
}
|
2017-02-19 21:14:27 +01:00
|
|
|
#endif
|
2023-01-30 17:11:44 +01:00
|
|
|
|
|
|
|
template<typename a, size_t b>
|
|
|
|
MEM_BlockAlloc<a, b>::~MEM_BlockAlloc()
|
|
|
|
{
|
2023-08-19 15:24:12 +02:00
|
|
|
// due to the randomized order of initialization and destruction
|
|
|
|
// MEM_BlockAlloc shouldn't automatically free memory
|
|
|
|
// because con_set and other stuff could handle destruction
|
|
|
|
// after memory was freed
|
|
|
|
//FreeAll();
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-01-30 17:11:44 +01:00
|
|
|
template<typename a, size_t b>
|
2023-07-05 21:23:39 +02:00
|
|
|
void *MEM_BlockAlloc<a, b>::Alloc()
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-01-30 17:11:44 +01:00
|
|
|
#if _DEBUG_MEMBLOCK
|
2023-07-05 21:23:39 +02:00
|
|
|
block_t *block = new (MEM_Alloc(sizeof(block_t))) block_t();
|
2017-02-19 21:14:27 +01:00
|
|
|
|
2023-08-19 15:24:12 +02:00
|
|
|
LL_SafeAddFirst(m_Block, block, next_block, prev_block);
|
2017-02-19 21:14:27 +01:00
|
|
|
|
2023-02-04 19:56:06 +01:00
|
|
|
m_BlockCount++;
|
2023-07-05 21:23:39 +02:00
|
|
|
return (void *)block->data;
|
2017-02-19 21:14:27 +01:00
|
|
|
#else
|
2023-07-05 21:23:39 +02:00
|
|
|
block_t *used_block;
|
2023-02-04 19:56:06 +01:00
|
|
|
block_offset_t free_data;
|
|
|
|
block_offset_t next_data;
|
|
|
|
|
|
|
|
if (m_StartUsedBlock) {
|
|
|
|
used_block = m_StartUsedBlock;
|
|
|
|
|
|
|
|
free_data = used_block->free_data;
|
|
|
|
next_data = used_block->next_data[free_data];
|
|
|
|
|
|
|
|
if (next_data == free_data) {
|
|
|
|
// Move the block to the next block list as there is no space
|
|
|
|
// available
|
|
|
|
m_StartUsedBlock = used_block->next_block;
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
LL_SafeRemoveRoot(m_StartUsedBlock, used_block, next_block, prev_block);
|
|
|
|
LL_SafeAddFirst(m_StartFullBlock, used_block, next_block, prev_block);
|
2023-02-04 19:56:06 +01:00
|
|
|
|
|
|
|
used_block->has_free_data = false;
|
|
|
|
return TakeFree(used_block, free_data);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (m_FreeBlock) {
|
|
|
|
// start from the free block
|
2023-07-05 21:23:39 +02:00
|
|
|
used_block = m_FreeBlock;
|
2023-02-04 19:56:06 +01:00
|
|
|
m_FreeBlock = nullptr;
|
2023-07-05 21:23:39 +02:00
|
|
|
free_data = used_block->free_data;
|
|
|
|
next_data = used_block->next_data[free_data];
|
2023-02-04 19:56:06 +01:00
|
|
|
} else {
|
|
|
|
m_BlockCount++;
|
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
|
|
|
|
const block_offset_t prev_data = used_block->prev_data[free_data];
|
|
|
|
|
|
|
|
used_block->next_data[prev_data] = next_data;
|
|
|
|
used_block->prev_data[next_data] = prev_data;
|
2023-07-05 21:23:39 +02:00
|
|
|
used_block->free_data = next_data;
|
|
|
|
used_block->has_free_data = true;
|
2023-02-04 19:56:06 +01:00
|
|
|
|
|
|
|
if (!used_block->usedDataAvailable()) {
|
2023-07-05 21:23:39 +02:00
|
|
|
used_block->used_data = free_data;
|
|
|
|
used_block->has_used_data = true;
|
2023-02-04 19:56:06 +01:00
|
|
|
used_block->next_data[free_data] = free_data;
|
|
|
|
used_block->prev_data[free_data] = free_data;
|
|
|
|
return used_block->data[free_data].data;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TakeFree(used_block, free_data);
|
2017-02-19 21:14:27 +01:00
|
|
|
#endif
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-02-04 19:56:06 +01:00
|
|
|
template<typename aclass, size_t blocksize>
|
2023-07-05 21:23:39 +02:00
|
|
|
void *MEM_BlockAlloc<aclass, blocksize>::TakeFree(block_t *block, uintptr_t free_data)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-02-04 19:56:06 +01:00
|
|
|
const block_offset_t used_data = block->used_data;
|
|
|
|
const block_offset_t prev_data = block->prev_data[used_data];
|
|
|
|
|
|
|
|
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;
|
2023-01-30 17:11:44 +01:00
|
|
|
}
|
2017-02-19 21:14:27 +01:00
|
|
|
|
2023-01-30 17:11:44 +01:00
|
|
|
template<typename a, size_t b>
|
2023-07-05 21:23:39 +02:00
|
|
|
void MEM_BlockAlloc<a, b>::Free(void *ptr) noexcept
|
2023-01-30 17:11:44 +01:00
|
|
|
{
|
|
|
|
#if _DEBUG_MEMBLOCK
|
2023-09-07 19:31:17 +02:00
|
|
|
block_t *block = (block_t*)ptr - offsetof(block_t, data);
|
2017-02-19 21:14:27 +01:00
|
|
|
|
2023-08-19 15:24:12 +02:00
|
|
|
LL_SafeRemoveRoot(m_Block, block, next_block, prev_block);
|
2017-02-19 21:14:27 +01:00
|
|
|
|
2023-02-04 19:56:06 +01:00
|
|
|
m_BlockCount--;
|
2023-08-19 15:24:12 +02:00
|
|
|
MEM_Free(block);
|
2017-02-19 21:14:27 +01:00
|
|
|
#else
|
2023-02-04 19:56:06 +01:00
|
|
|
// get the header of the pointer
|
2023-07-05 21:23:39 +02:00
|
|
|
typename block_t::info_t *header =
|
|
|
|
reinterpret_cast<typename block_t::info_t *>(static_cast<unsigned char *>(ptr) - block_t::headersize);
|
2023-02-04 19:56:06 +01:00
|
|
|
const block_offset_t used_data = header->index;
|
|
|
|
// get the block from the header
|
2023-07-05 21:23:39 +02:00
|
|
|
block_t *const block = (block_t *)((uint8_t *)header - used_data * block_t::datasize - block_t::dataoffset);
|
2023-02-04 19:56:06 +01:00
|
|
|
const block_offset_t next_data = block->next_data[used_data];
|
|
|
|
if (next_data == used_data) {
|
|
|
|
LL_SafeRemoveRoot(m_StartUsedBlock, block, next_block, prev_block);
|
|
|
|
|
|
|
|
if (m_FreeBlock) {
|
|
|
|
// deallocate the free block because of another deallocation
|
|
|
|
--m_BlockCount;
|
|
|
|
MEM_Free(m_FreeBlock);
|
|
|
|
m_FreeBlock = nullptr;
|
|
|
|
}
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
m_FreeBlock = block;
|
2023-02-04 19:56:06 +01:00
|
|
|
block->has_used_data = false;
|
|
|
|
|
|
|
|
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;
|
|
|
|
} else {
|
|
|
|
const block_offset_t prev_data = block->prev_data[used_data];
|
|
|
|
|
|
|
|
block->next_data[prev_data] = next_data;
|
|
|
|
block->prev_data[next_data] = prev_data;
|
2023-07-05 21:23:39 +02:00
|
|
|
block->used_data = next_data;
|
|
|
|
block->has_used_data = true;
|
2023-02-04 19:56:06 +01:00
|
|
|
|
|
|
|
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);
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
block->free_data = used_data;
|
|
|
|
block->has_free_data = true;
|
2023-02-04 19:56:06 +01:00
|
|
|
block->prev_data[used_data] = used_data;
|
|
|
|
block->next_data[used_data] = used_data;
|
|
|
|
}
|
2017-02-19 21:14:27 +01:00
|
|
|
#endif
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-01-30 17:11:44 +01:00
|
|
|
template<typename a, size_t b>
|
|
|
|
void MEM_BlockAlloc<a, b>::FreeAll() noexcept
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
block_t *block;
|
2023-02-01 00:28:40 +01:00
|
|
|
#if _DEBUG_MEMBLOCK
|
2023-08-19 15:24:12 +02:00
|
|
|
block_t *next = m_Block;
|
2023-02-04 19:56:06 +01:00
|
|
|
for (block = next; block; block = next) {
|
|
|
|
next = block->next_block;
|
|
|
|
m_BlockCount--;
|
2023-07-05 21:23:39 +02:00
|
|
|
a *ptr = (a *)block->data;
|
2023-02-04 19:56:06 +01:00
|
|
|
ptr->~a();
|
2023-08-19 15:24:12 +02:00
|
|
|
MEM_Free(block);
|
2023-02-04 19:56:06 +01:00
|
|
|
}
|
2023-08-19 15:24:12 +02:00
|
|
|
|
|
|
|
m_Block = NULL;
|
2017-02-19 21:14:27 +01:00
|
|
|
#else
|
2023-02-04 19:56:06 +01:00
|
|
|
while ((block = m_StartFullBlock) != nullptr) {
|
|
|
|
if (block->usedDataAvailable()) {
|
2023-07-05 21:23:39 +02:00
|
|
|
a *ptr = (a *)block->data[block->used_data].data;
|
2023-02-04 19:56:06 +01:00
|
|
|
ptr->~a();
|
|
|
|
Free(ptr);
|
|
|
|
block = m_StartFullBlock;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
while ((block = m_StartUsedBlock) != nullptr) {
|
|
|
|
if (block->usedDataAvailable()) {
|
2023-07-05 21:23:39 +02:00
|
|
|
a *ptr = (a *)block->data[block->used_data].data;
|
2023-02-04 19:56:06 +01:00
|
|
|
ptr->~a();
|
|
|
|
Free(ptr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_FreeBlock) {
|
|
|
|
m_BlockCount--;
|
|
|
|
MEM_Free(m_FreeBlock);
|
|
|
|
m_FreeBlock = nullptr;
|
|
|
|
}
|
2017-02-19 21:14:27 +01:00
|
|
|
#endif
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-01-30 17:11:44 +01:00
|
|
|
template<typename a, size_t b>
|
2023-07-05 21:23:39 +02:00
|
|
|
size_t MEM_BlockAlloc<a, b>::Count(const block_t *list)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-02-04 19:56:06 +01:00
|
|
|
int count = 0;
|
2023-01-30 17:11:44 +01:00
|
|
|
#if _DEBUG_MEMBLOCK
|
2023-07-05 21:23:39 +02:00
|
|
|
for (const block_t *block = list; block; block = block->next_block) {
|
2023-02-04 19:56:06 +01:00
|
|
|
count++;
|
|
|
|
}
|
|
|
|
return count;
|
2017-02-19 21:14:27 +01:00
|
|
|
#else
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
for (const block_t *block = list; block; block = block->next_block) {
|
2023-02-04 19:56:06 +01:00
|
|
|
if (!block->usedDataAvailable()) {
|
|
|
|
continue;
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
const block_offset_t used_data = block->used_data;
|
|
|
|
block_offset_t current_used_data = used_data;
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-02-04 19:56:06 +01:00
|
|
|
do {
|
|
|
|
count++;
|
|
|
|
current_used_data = block->next_data[current_used_data];
|
|
|
|
} while (current_used_data != used_data);
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-02-04 19:56:06 +01:00
|
|
|
return count;
|
2017-02-19 21:14:27 +01:00
|
|
|
#endif
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-01-30 17:11:44 +01:00
|
|
|
template<typename a, size_t b>
|
|
|
|
size_t MEM_BlockAlloc<a, b>::Count()
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-01-30 17:11:44 +01:00
|
|
|
#if _DEBUG_MEMBLOCK
|
2023-02-04 19:56:06 +01:00
|
|
|
return Count(m_Block);
|
2017-02-19 21:14:27 +01:00
|
|
|
#else
|
2023-02-04 19:56:06 +01:00
|
|
|
return Count(m_StartFullBlock) + Count(m_StartUsedBlock);
|
2017-02-19 21:14:27 +01:00
|
|
|
#endif
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-01-30 17:11:44 +01:00
|
|
|
template<typename a, size_t b>
|
|
|
|
size_t MEM_BlockAlloc<a, b>::BlockCount()
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-02-04 19:56:06 +01:00
|
|
|
return m_BlockCount;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-01-30 17:11:44 +01:00
|
|
|
template<typename a, size_t b>
|
|
|
|
size_t MEM_BlockAlloc<a, b>::BlockMemory()
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-02-04 19:56:06 +01:00
|
|
|
return sizeof(block_s<a, b>);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-01-30 17:11:44 +01:00
|
|
|
template<typename a, size_t b>
|
2023-02-04 19:56:06 +01:00
|
|
|
MEM_BlockAlloc_enum<a, b>::MEM_BlockAlloc_enum(MEM_BlockAlloc<a, b>& owner)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-07-05 21:23:39 +02:00
|
|
|
m_Owner = &owner;
|
2023-02-04 19:56:06 +01:00
|
|
|
m_CurrentBlock = nullptr;
|
2023-01-30 17:11:44 +01:00
|
|
|
#if !_DEBUG_MEMBLOCK
|
2023-02-04 19:56:06 +01:00
|
|
|
m_CurrentBlockType = MEM_BlockAlloc_enum::used;
|
2017-02-19 21:14:27 +01:00
|
|
|
#endif
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-01-30 17:11:44 +01:00
|
|
|
template<typename a, size_t b>
|
2023-07-05 21:23:39 +02:00
|
|
|
a *MEM_BlockAlloc_enum<a, b>::NextElement()
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-01-30 17:11:44 +01:00
|
|
|
#if _DEBUG_MEMBLOCK
|
2023-02-04 19:56:06 +01:00
|
|
|
if (!m_CurrentBlock) {
|
2023-08-19 15:24:12 +02:00
|
|
|
m_CurrentBlock = m_Owner->m_Block;
|
2023-02-04 19:56:06 +01:00
|
|
|
} else {
|
|
|
|
m_CurrentBlock = m_CurrentBlock->next_block;
|
|
|
|
}
|
2023-07-05 21:23:39 +02:00
|
|
|
return (a *)m_CurrentBlock;
|
2017-02-19 21:14:27 +01:00
|
|
|
#else
|
2023-02-04 19:56:06 +01:00
|
|
|
// search for a valid block type
|
|
|
|
while (!m_CurrentBlock) {
|
|
|
|
switch (m_CurrentBlockType) {
|
|
|
|
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;
|
2023-07-05 21:23:39 +02:00
|
|
|
return reinterpret_cast<a *>(m_CurrentBlock->data[m_CurrentData].data);
|
2023-02-04 19:56:06 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_CurrentData = m_CurrentBlock->next_data[m_CurrentData];
|
|
|
|
|
|
|
|
if (m_CurrentData == m_CurrentBlock->used_data) {
|
|
|
|
// found an object
|
|
|
|
m_CurrentBlock = m_CurrentBlock->next_block;
|
|
|
|
goto _label;
|
|
|
|
}
|
|
|
|
|
2023-07-05 21:23:39 +02:00
|
|
|
return reinterpret_cast<a *>(m_CurrentBlock->data[m_CurrentData].data);
|
2017-02-19 21:14:27 +01:00
|
|
|
#endif
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-01-30 17:11:44 +01:00
|
|
|
template<typename a, size_t b>
|
2023-07-05 21:23:39 +02:00
|
|
|
a *MEM_BlockAlloc_enum<a, b>::CurrentElement()
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-02-04 19:56:06 +01:00
|
|
|
return m_CurrentBlock;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-02-01 00:28:40 +01:00
|
|
|
template<typename a, size_t b>
|
2023-07-05 21:23:39 +02:00
|
|
|
void *operator new(size_t, MEM_BlockAlloc<a, b>& allocator)
|
2023-02-01 00:28:40 +01:00
|
|
|
{
|
2023-02-04 19:56:06 +01:00
|
|
|
return allocator.Alloc();
|
2023-02-01 00:28:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
template<typename a, size_t b>
|
2023-07-05 21:23:39 +02:00
|
|
|
void operator delete(void *ptr, MEM_BlockAlloc<a, b>& allocator) noexcept
|
2023-02-01 00:28:40 +01:00
|
|
|
{
|
2023-02-04 19:56:06 +01:00
|
|
|
return allocator.Free(ptr);
|
2023-02-01 00:28:40 +01:00
|
|
|
}
|