-BlockAllocator is no longer template
-Multithreaded IDManager.getNewID() *use implementation with free IDs stack (instead of classic pool) -support for multiple UpdatePasses. Passes are added by name, and must be called between begin() end() functions. -removed mutex from addEntity() -commit() function added. Used to commit all changes made while update() call. Called automatically by begin() end() functions.
This commit is contained in:
parent
430ce8074c
commit
d3f7593afc
6 changed files with 406 additions and 189 deletions
|
|
@ -1,8 +1,15 @@
|
|||
module ecs.id_manager;
|
||||
|
||||
import std.experimental.allocator;
|
||||
import std.experimental.allocator.mallocator : AlignedMallocator, Mallocator;
|
||||
|
||||
import ecs.entity;
|
||||
import ecs.vector;
|
||||
|
||||
import core.atomic;
|
||||
import core.stdc.string : memcpy;
|
||||
import core.sync.mutex;
|
||||
|
||||
/************************************************************************************************************************
|
||||
*IDManager is responsible for assignment and removing IDs. IDs are unique throughtout a whole duration of the program.
|
||||
*/
|
||||
|
|
@ -11,17 +18,62 @@ struct IDManager
|
|||
/************************************************************************************************************************
|
||||
*Get new ID.
|
||||
*/
|
||||
EntityID getNewID()
|
||||
pragma(inline, false) EntityID getNewID()
|
||||
{
|
||||
if (m_next_id >= m_ids_array.length)
|
||||
m_ids_array.add(Data());
|
||||
//uint current = m_next_id;
|
||||
//uint next;// = m_ids_array[m_next_id].next_id;
|
||||
begin:
|
||||
//if (current == uint.max)//> m_last_id)
|
||||
int current = m_stack_top.atomicOp!"-="(1) + 1;
|
||||
if(current < 0)
|
||||
{
|
||||
uint add_id = m_last_id.atomicOp!"+="(1) - 1;
|
||||
|
||||
if (add_id >= m_ids_array.length)
|
||||
{
|
||||
uint local_id = add_id - cast(uint) m_ids_array.length;
|
||||
uint block_id = local_id >> 16;
|
||||
if (block_id >= m_blocks_count)
|
||||
{
|
||||
add_mutex.lock();
|
||||
if(block_id >= m_blocks_count)
|
||||
{
|
||||
m_blocks[m_blocks_count].alloc();
|
||||
m_blocks_count++;
|
||||
}
|
||||
add_mutex.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
EntityID id;
|
||||
id.id = add_id;
|
||||
id.counter = 0;
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
//current += 1;
|
||||
uint index = m_free_stack[current];
|
||||
EntityID id;
|
||||
id.id = m_next_id;
|
||||
id.counter = /*++*/m_ids_array[m_next_id].counter;
|
||||
m_next_id = m_ids_array[m_next_id].next_id;
|
||||
if (m_next_id == uint.max)
|
||||
m_next_id = cast(uint) m_ids_array.length;
|
||||
id.id = index;
|
||||
id.counter = m_ids_array[index].counter;
|
||||
//current = m_ids_array[index].next_id;
|
||||
return id;
|
||||
|
||||
/*next = m_ids_array[current].next_id;
|
||||
if(cas(&m_next_id,current,next))
|
||||
{
|
||||
EntityID id;
|
||||
id.id = current;
|
||||
id.counter = m_ids_array[current].counter;
|
||||
m_next_id = m_ids_array[current].next_id;
|
||||
return id;
|
||||
}
|
||||
else
|
||||
{
|
||||
current = next;
|
||||
goto begin;
|
||||
}*/
|
||||
}
|
||||
|
||||
/************************************************************************************************************************
|
||||
|
|
@ -33,9 +85,12 @@ struct IDManager
|
|||
if (data.counter != id.counter)
|
||||
return;
|
||||
data.counter++;
|
||||
data.next_id = m_next_id;
|
||||
//data.next_id = m_next_id;
|
||||
data.entity = null;
|
||||
m_next_id = id.id;
|
||||
///m_next_id = id.id;
|
||||
|
||||
m_stack_top.atomicOp!"+="(1);
|
||||
m_free_stack[m_stack_top] = id.id;
|
||||
}
|
||||
|
||||
/************************************************************************************************************************
|
||||
|
|
@ -43,7 +98,15 @@ struct IDManager
|
|||
*/
|
||||
void update(ref Entity entity)
|
||||
{
|
||||
if(entity.id.counter == m_ids_array[entity.id.id].counter)m_ids_array[entity.id.id].entity = &entity;
|
||||
if (entity.id.id >= cast(uint) m_ids_array.length)
|
||||
{
|
||||
uint local_id = entity.id.id - cast(uint) m_ids_array.length;
|
||||
uint block_id = local_id >> 16;
|
||||
local_id -= block_id << 16;
|
||||
m_blocks[block_id].data[local_id].entity = &entity;
|
||||
}
|
||||
else //if (entity.id.counter == m_ids_array[entity.id.id].counter)
|
||||
m_ids_array[entity.id.id].entity = &entity;
|
||||
}
|
||||
|
||||
/************************************************************************************************************************
|
||||
|
|
@ -51,6 +114,19 @@ struct IDManager
|
|||
*/
|
||||
export Entity* getEntityPointer(EntityID id)
|
||||
{
|
||||
if (id.id >= m_ids_array.length)
|
||||
{
|
||||
uint local_id = id.id - cast(uint) m_ids_array.length;
|
||||
uint block_id = local_id >> 16;
|
||||
assert(block_id < m_blocks_count);
|
||||
if (block_id >= m_blocks_count)
|
||||
return null;
|
||||
local_id -= block_id << 16;
|
||||
if (m_blocks[block_id].data[local_id].counter != id.counter)
|
||||
return null;
|
||||
return m_blocks[block_id].data[local_id].entity;
|
||||
}
|
||||
|
||||
Data* data = &m_ids_array[id.id];
|
||||
if (data.counter != id.counter)
|
||||
return null;
|
||||
|
|
@ -67,16 +143,81 @@ struct IDManager
|
|||
return data.counter == id.counter;
|
||||
}
|
||||
|
||||
void initialize()
|
||||
{
|
||||
m_ids_array = Mallocator.instance.makeArray!Data(65536);
|
||||
m_free_stack = Mallocator.instance.makeArray!uint(65536);
|
||||
m_blocks = Mallocator.instance.makeArray!Block(64);
|
||||
m_blocks_count = 1;
|
||||
m_blocks[0].alloc();
|
||||
|
||||
add_mutex = Mallocator.instance.make!Mutex();
|
||||
}
|
||||
|
||||
void optimize()
|
||||
{
|
||||
if(m_stack_top < -1)m_stack_top = -1;
|
||||
if(m_last_id > m_ids_array.length)
|
||||
{
|
||||
uint begin = cast(uint)m_ids_array.length;
|
||||
Data[] new_array = Mallocator.instance.makeArray!Data(begin + (m_blocks_count << 16));
|
||||
memcpy(new_array.ptr, m_ids_array.ptr, m_ids_array.length * Data.sizeof);
|
||||
Mallocator.instance.dispose(m_ids_array);
|
||||
m_ids_array = new_array;
|
||||
|
||||
uint[] new_stack = Mallocator.instance.makeArray!uint(m_ids_array.length);
|
||||
memcpy(new_stack.ptr,m_free_stack.ptr,m_free_stack.length * uint.sizeof);
|
||||
Mallocator.instance.dispose(m_free_stack);
|
||||
m_free_stack = new_stack;
|
||||
|
||||
foreach(block;m_blocks[0..m_blocks_count-1])
|
||||
{
|
||||
memcpy(cast(void*)m_ids_array.ptr + begin * Data.sizeof, block.data.ptr, 65536 * Data.sizeof);
|
||||
begin += 65536;
|
||||
}
|
||||
memcpy(cast(void*)m_ids_array.ptr + begin * Data.sizeof, m_blocks[m_blocks_count-1].data.ptr, (m_last_id - begin) * Data.sizeof);
|
||||
foreach(block;m_blocks[1..m_blocks_count])block.free();
|
||||
m_blocks_count = 1;
|
||||
}
|
||||
}
|
||||
|
||||
private static struct Block
|
||||
{
|
||||
void alloc()
|
||||
{
|
||||
assert(data is null);
|
||||
data = Mallocator.instance.makeArray!Data(65536);
|
||||
}
|
||||
|
||||
void free()
|
||||
{
|
||||
assert(data !is null);
|
||||
Mallocator.instance.dispose(data);
|
||||
}
|
||||
|
||||
Data[] data; //65536
|
||||
}
|
||||
|
||||
private static struct Data
|
||||
{
|
||||
uint counter = 0;
|
||||
uint next_id = uint.max;
|
||||
//uint next_id = uint.max;
|
||||
Entity* entity = null;
|
||||
}
|
||||
|
||||
private:
|
||||
uint m_next_id;
|
||||
Vector!Data m_ids_array;
|
||||
Mutex add_mutex;
|
||||
//shared uint m_next_id = 0;
|
||||
|
||||
//shared uint m_last_id = 0;
|
||||
Data[] m_ids_array = null;
|
||||
uint m_blocks_count = 0;
|
||||
Block[] m_blocks;
|
||||
//shared int m_stack_top = -1;
|
||||
uint[] m_free_stack = null;
|
||||
|
||||
align(64) shared uint m_last_id = 0;
|
||||
align(64) shared int m_stack_top = -1;
|
||||
}
|
||||
|
||||
unittest
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue