-fully working betterC for windows
*replaced array[..] = array[ .. ] sclice copy with mempcy *added own std library (allocator, alloca, Mutex) *changed tamplates for collecting components for systems -fixed issue with multiple optional components registering for system
This commit is contained in:
parent
ed99807871
commit
41f1c6474b
14 changed files with 722 additions and 868 deletions
|
|
@ -1,9 +1,10 @@
|
|||
module ecs.block_allocator;
|
||||
|
||||
import ecs.manager;
|
||||
|
||||
import ecs.std;
|
||||
/*
|
||||
import std.experimental.allocator;
|
||||
import std.experimental.allocator.mallocator : AlignedMallocator, Mallocator;
|
||||
import std.experimental.allocator.mallocator : AlignedMallocator, Mallocator;*/
|
||||
|
||||
struct BlockAllocator//(uint block_size, uint blocks_in_allocation)
|
||||
{
|
||||
|
|
@ -37,13 +38,13 @@ struct BlockAllocator//(uint block_size, uint blocks_in_allocation)
|
|||
|
||||
private void allocBlock() nothrow @nogc
|
||||
{
|
||||
next_block = cast(void*) AlignedMallocator.instance.alignedAllocate(
|
||||
next_block = cast(void*) Mallocator.alignAlloc(
|
||||
block_size * blocks_in_allocation, block_size);
|
||||
|
||||
if(pointers is null)pointers = Mallocator.instance.make!BlockPointers;
|
||||
if(pointers is null)pointers = Mallocator.make!BlockPointers;
|
||||
if(pointers.numberof >= 32)
|
||||
{
|
||||
BlockPointers* new_pointers = Mallocator.instance.make!BlockPointers;
|
||||
BlockPointers* new_pointers = Mallocator.make!BlockPointers;
|
||||
new_pointers.next_pointers = pointers;
|
||||
pointers = new_pointers;
|
||||
}
|
||||
|
|
@ -65,10 +66,10 @@ struct BlockAllocator//(uint block_size, uint blocks_in_allocation)
|
|||
{
|
||||
foreach(i;0..pointers.numberof)
|
||||
{
|
||||
AlignedMallocator.instance.dispose(pointers.blocks[i]);
|
||||
Mallocator.alignDispose(pointers.blocks[i]);
|
||||
}
|
||||
BlockPointers* next_pointers = pointers.next_pointers;
|
||||
Mallocator.instance.dispose(pointers);
|
||||
Mallocator.dispose(pointers);
|
||||
pointers = next_pointers;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,21 +9,6 @@ static struct ECS
|
|||
{
|
||||
__gshared ushort system_id;
|
||||
uint __ecs_jobs_count = jobs_count;
|
||||
/*EntityManager.Job[] _ecs_jobs;
|
||||
|
||||
void __ecsInitialize() nothrow @nogc
|
||||
{
|
||||
import std.experimental.allocator.mallocator;
|
||||
import std.experimental.allocator;
|
||||
_ecs_jobs = Mallocator.instance.makeArray!(EntityManager.Job)(jobs_count);
|
||||
}
|
||||
|
||||
void __ecsDeinitialize() nothrow @nogc
|
||||
{
|
||||
import std.experimental.allocator.mallocator;
|
||||
import std.experimental.allocator;
|
||||
Mallocator.instance.dispose(_ecs_jobs);
|
||||
}*/
|
||||
}
|
||||
|
||||
mixin template Component()
|
||||
|
|
|
|||
339
source/ecs/ecs.d
339
source/ecs/ecs.d
|
|
@ -1,339 +0,0 @@
|
|||
module ecs.ecs;
|
||||
|
||||
import std.stdio;
|
||||
|
||||
version(Design):
|
||||
|
||||
alias SytemFuncType = void function(ref SystemCallData data, void* componentsStart);
|
||||
|
||||
struct HasComponentsStore
|
||||
{
|
||||
ulong[4] bits; //256 components
|
||||
|
||||
bool has(HasComponentsStore components)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool notIn(HasComponentsStore components)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int length()
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
// Informacje o kompnencie
|
||||
struct ComponentInfo
|
||||
{
|
||||
int size;
|
||||
int aligment;
|
||||
SerializeJSON funsSerJ;
|
||||
SerializeBiN funcSerB;
|
||||
}
|
||||
|
||||
struct System
|
||||
{
|
||||
HasComponentsStore requiredComponents;
|
||||
HasComponentsStore absenComponents;
|
||||
HasComponentsStore maybeComponents;
|
||||
bool enabled;
|
||||
int priority;
|
||||
SytemFuncType func;
|
||||
}
|
||||
// Informacje o systemie dla konkretnego entitiesa
|
||||
struct SystemCallData
|
||||
{
|
||||
System* system;
|
||||
int[] componentsDt;
|
||||
}
|
||||
|
||||
// Informacje o entitiesie danego typu
|
||||
struct EntityTypeData
|
||||
{
|
||||
HasComponentsStore components;
|
||||
int[] deltas;
|
||||
int totalSize;
|
||||
int totalAligment = 8;
|
||||
SystemCallData[] systems;
|
||||
}
|
||||
|
||||
struct EntitiesBlock
|
||||
{
|
||||
EntityTypeData* typeData;
|
||||
Entity* freeEntitySlot;
|
||||
EntitiesBlock* nextBlock;
|
||||
}
|
||||
|
||||
struct EntityID
|
||||
{
|
||||
ulong id = ulong.max;
|
||||
static immutable notUsedValue = EntityID(ulong.max);
|
||||
}
|
||||
|
||||
// Dane konkretnego Entitiesa
|
||||
struct Entity
|
||||
{
|
||||
EntityID entityID = EntityID.notUsedValue;
|
||||
union
|
||||
{
|
||||
string name;
|
||||
Entity* nextFreeSlot;
|
||||
}
|
||||
|
||||
//string eventOnDestroy;
|
||||
uint group;
|
||||
EntityID entityID;
|
||||
//ubyte[XX] thereIsComponentsMemory;
|
||||
}
|
||||
|
||||
struct Template
|
||||
{
|
||||
HasComponentsStore hasComp;
|
||||
Entity* entity;
|
||||
}
|
||||
|
||||
struct Manager
|
||||
{
|
||||
EntityAllocator entityArrayAllcoator;
|
||||
|
||||
ComponentInfo[] components;
|
||||
System[] systems;
|
||||
HashMap!(HasComponentsStore, EntitiesBlock*) entitiesDatas;
|
||||
HashMapTwoWays!(string, Entity*) nameMap;
|
||||
HashMapTwoWays!(EntityID, Entity*) idMap;
|
||||
|
||||
EntitiesBlock* getEntitiesBlock(HasComponentsStore hasComponents)
|
||||
{
|
||||
EntitiesBlock* block = entitiesDatas.get(hasComponents, null);
|
||||
if (block is null)
|
||||
{
|
||||
// If such component combination was never present, add it
|
||||
block = addNewBlock(hasComponents, block);
|
||||
return block;
|
||||
}
|
||||
// Iterate over list of components until free slot is found or lists ends
|
||||
do
|
||||
{
|
||||
if (block.freeEntitySlot !is null)
|
||||
{
|
||||
return block;
|
||||
}
|
||||
if (block.nextBlock is null)
|
||||
{
|
||||
block = addNewBlock(hasComponents);
|
||||
return block;
|
||||
}
|
||||
block = block.nextBlock;
|
||||
}
|
||||
while (block.nextBlock !is null);
|
||||
|
||||
}
|
||||
|
||||
EntitiesBlock* addNewBlock(HasComponentsStore hasComponents, EntitiesBlock* firstBlock)
|
||||
{
|
||||
// Get last block so order of blocks is preserved, and first blocks are filled first
|
||||
EntitiesBlock* lastBlock = firstBlock;
|
||||
if (lastBlock !is null)
|
||||
{
|
||||
while (lastBlock.nextBlock !is null)
|
||||
{
|
||||
lastBlock = lastBlock.nextBlock;
|
||||
}
|
||||
}
|
||||
assert(lastBlock is null || lastBlock.nextBlock is null);
|
||||
|
||||
ubyte[] memory = new ubyte[](4096);
|
||||
EntitiesBlock* block = cast(EntitiesBlock*) memory.ptr;
|
||||
if (lastBlock is null)
|
||||
{
|
||||
EntityTypeData* entityTypeData = newEntityTypeData(hasComponents);
|
||||
block.typeData = entityTypeData;
|
||||
block.nextBlock = null;
|
||||
entitiesDatas.add(hasComponents, block);
|
||||
}
|
||||
else
|
||||
{
|
||||
lastBlock.nextBlock = block;
|
||||
block.typeData = lastBlock.typeData;
|
||||
block.nextBlock = null;
|
||||
}
|
||||
}
|
||||
|
||||
void alignNum(ref int num, int aligment)
|
||||
{
|
||||
int reminder = num % aligment;
|
||||
if (reminder != 0)
|
||||
{
|
||||
num += aligment - reminder;
|
||||
}
|
||||
}
|
||||
|
||||
EntityTypeData* newEntityTypeData(HasComponentsStore hasComponents)
|
||||
{
|
||||
EntityTypeData* typeData = new EntityTypeData();
|
||||
typeData.components = hasComponents;
|
||||
ComponentInfo[] components = getComponentsInfo(hasComponents);
|
||||
typeData.deltas.length = hasComponents.length;
|
||||
|
||||
foreach (i, comp; components)
|
||||
{
|
||||
typeData.deltas[i] = typeData.totalSize;
|
||||
typeData.totalAligment.max(comp.aligment);
|
||||
typeData.totalSize += comp.size;
|
||||
alignNum(typeData.totalSize, comp.aligment);
|
||||
}
|
||||
alignNum(typeData.totalSize, typeData.totalAligment);
|
||||
|
||||
foreach (sys; systems)
|
||||
{
|
||||
if (!typeData.hasComp.has(sys.requiredComponents)
|
||||
|| !typeData.hasComp.notIn(sys.absenComponents))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
entTypeData.systems ~= sys;
|
||||
}
|
||||
|
||||
return typeData;
|
||||
}
|
||||
|
||||
void addEntity(Template* templ)
|
||||
{
|
||||
EntitiesBlock* block = getEntitiesBlock(templ.hasComp);
|
||||
Entity* newEntity = block.freeEntitySlot;
|
||||
block.freeEntitySlot = newEntity.nextFreeSlot;
|
||||
// from to size
|
||||
memcpy(temp.entity, newEntity, block.typeData.totalSize);
|
||||
}
|
||||
|
||||
void addSystem(Func)(int priority)
|
||||
{
|
||||
HasComponentsStore requiredComponents;
|
||||
HasComponentsStore absenComponents;
|
||||
HasComponentsStore maybeComponents;
|
||||
|
||||
void systemCaller(ref SystemCallData data, void * componentsStart)
|
||||
{
|
||||
Func(cast(FUnc.par1Type)(componentsStart + data.componentsDt[0]),
|
||||
cast(FUnc.par1Type)(componentsStart + data.componentsDt[1])/*...*/);
|
||||
}
|
||||
System* system = new System(&systemCaller, entTypeData);
|
||||
systems ~= system;
|
||||
|
||||
foreach (ref entTypeData; entitiesDatas)
|
||||
{
|
||||
if (!entTypeData.hasComp.has(requiredComponents)
|
||||
|| !entTypeData.hasComp.notIn(absenComponents))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
entTypeData.systems ~= system;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void someSystem(CompA a, CompB b, CompC* c)
|
||||
{
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
writeln("Edit source/app.d to start your project.");
|
||||
}
|
||||
|
||||
class System
|
||||
{
|
||||
|
||||
void start()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void end()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void update(ref ObjRend a)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void useEvent(EventData evvv, ref ObjRend a)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
alias SerializeVector = ubyte[];
|
||||
|
||||
__gshared EntityManager gEntityManager;
|
||||
|
||||
unittest
|
||||
{
|
||||
struct ComponentA
|
||||
{
|
||||
__gshared static int component_id;
|
||||
int a;
|
||||
ulong b;
|
||||
|
||||
static void serializeComponent(ref ComponentA comp, SerializeVector output)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void deerializeComponent(ref ComponentA comp, ubyte[] data)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
gEM.addComponet!ComponentA();
|
||||
assert(ComponentA.component_id == 0);
|
||||
ComponentData* ccc = &gEM.componnets[ComponentA.component_id];
|
||||
assert(ccc.totalAligment == 8);
|
||||
assert(ccc.totalSize == 8);
|
||||
|
||||
HasComponentsStore hasComponents;
|
||||
hasComponents.addComponet(ComponentA.component_id);
|
||||
EntityTempalte* tmpl = gEM.allocateTemplate(hasComponents);
|
||||
|
||||
ComponentA* comp = tmpl.getComponent!ComponentA(ComponentA.component_id);
|
||||
comp.a = 111;
|
||||
comp.b = 222;
|
||||
|
||||
gEM.addEntity(tmpl);
|
||||
|
||||
struct SystemAdd
|
||||
{
|
||||
void update(ref ComponentA a)
|
||||
{
|
||||
a.a+=1000;
|
||||
b.b+=2000;
|
||||
|
||||
}
|
||||
|
||||
void handleEvent(EventData evvv, ref ComponentA a)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
int priority=10;
|
||||
gEM.registerSystem!(SystemAdd)(priority);
|
||||
gEM.updateStepAll();
|
||||
foreach(EntityID id; gEM.IterateByAllEntiteis){
|
||||
assert(id.getComponent(ComponentA.component_id));
|
||||
ComponentA* ccc=id.getComponent(ComponentA.component_id);
|
||||
assert(ccc.a==1111);
|
||||
assert(ccc.b==2222);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -3,12 +3,13 @@ module ecs.events;
|
|||
import ecs.manager;
|
||||
import ecs.block_allocator;
|
||||
import ecs.entity;
|
||||
|
||||
import ecs.std;
|
||||
/*
|
||||
import std.experimental.allocator;
|
||||
import std.experimental.allocator.mallocator : AlignedMallocator, Mallocator;
|
||||
import std.experimental.allocator.mallocator : AlignedMallocator, Mallocator;*/
|
||||
import std.algorithm.comparison : max;
|
||||
|
||||
import core.sync.mutex;
|
||||
//import core.sync.mutex;
|
||||
|
||||
/*struct Event
|
||||
{
|
||||
|
|
@ -20,67 +21,22 @@ import core.sync.mutex;
|
|||
struct EventManager
|
||||
{
|
||||
|
||||
//@disable this();
|
||||
|
||||
/*this(EntityManager m)
|
||||
{
|
||||
manager = m;
|
||||
}*/
|
||||
|
||||
/*void sendSelfEvent(Ev)(EntityID id, Ev event)
|
||||
{
|
||||
ushort size = cast(ushort)(Ev.sizeof); // + EntityID.sizeof + ushort.sizeof);
|
||||
ushort alignment = cast(ushort)(Ev.alignof);
|
||||
|
||||
EventList* list = &process_events;
|
||||
|
||||
if (list.current_block is null)
|
||||
{
|
||||
list.current_block = cast(EventBlock*) allocator.getBlock();
|
||||
list.first_block = list.current_block;
|
||||
list.current_block.index = cast(ushort)((void*).sizeof + ushort.sizeof);
|
||||
}
|
||||
|
||||
ushort index = cast(ushort)(
|
||||
list.current_block.index + ushort.sizeof + EntityID.sizeof + ushort.sizeof);
|
||||
|
||||
ushort aligned_index = index; //cast(ushort)(list.current_block.index);
|
||||
alignNum(aligned_index, alignment);
|
||||
|
||||
if (aligned_index + Ev.sizeof > events_block_size)
|
||||
{
|
||||
list.current_block.next = cast(EventBlock*) allocator.getBlock();
|
||||
list.current_block = list.current_block.next;
|
||||
list.current_block.index = cast(ushort)((void*).sizeof + ushort.sizeof);
|
||||
|
||||
index = cast(ushort)((void*)
|
||||
.sizeof + ushort.sizeof + ushort.sizeof + EntityID.sizeof + ushort.sizeof); // + EntityID.sizeof + ushort.sizeof;
|
||||
|
||||
aligned_index = index;
|
||||
alignNum(aligned_index, alignment);
|
||||
}
|
||||
|
||||
EventBlock* block = list.current_block;
|
||||
|
||||
ushort align_ = cast(ushort)(aligned_index - index);
|
||||
*cast(ushort*)&block.data[block.index] = align_;
|
||||
index = cast(ushort)(aligned_index - (EntityID.sizeof + ushort.sizeof));
|
||||
*cast(ushort*)&block.data[index] = Ev.event_id;
|
||||
*cast(EntityID*)&block.data[index + 2] = id;
|
||||
*cast(Ev*)&block.data[aligned_index] = event;
|
||||
block.index = cast(ushort)(aligned_index + Ev.sizeof);
|
||||
}*/
|
||||
|
||||
void initialize(EntityManager m) nothrow @nogc
|
||||
void initialize(EntityManager* m) nothrow @nogc
|
||||
{
|
||||
allocator = BlockAllocator(events_block_size, events_blocks_in_allocation);
|
||||
event_block_alloc_mutex = Mallocator.instance.make!Mutex;
|
||||
event_block_alloc_mutex = Mallocator.make!Mutex;
|
||||
event_block_alloc_mutex.initialize();
|
||||
manager = m;
|
||||
}
|
||||
|
||||
void destroy()
|
||||
void destroy() nothrow @nogc
|
||||
{
|
||||
Mallocator.instance.dispose(event_block_alloc_mutex);
|
||||
if(event_block_alloc_mutex)
|
||||
{
|
||||
event_block_alloc_mutex.destroy();
|
||||
Mallocator.dispose(event_block_alloc_mutex);
|
||||
event_block_alloc_mutex = null;
|
||||
}
|
||||
}
|
||||
|
||||
export void sendEvent(Ev)(EntityID id, Ev event, uint thread_id = 0) nothrow @nogc
|
||||
|
|
@ -94,9 +50,9 @@ struct EventManager
|
|||
|
||||
if(block is null)
|
||||
{
|
||||
event_block_alloc_mutex.lock_nothrow();
|
||||
event_block_alloc_mutex.lock();
|
||||
scope (exit)
|
||||
event_block_alloc_mutex.unlock_nothrow();
|
||||
event_block_alloc_mutex.unlock();
|
||||
|
||||
block = cast(EventBlock*) allocator.getBlock();
|
||||
*block = EventBlock();
|
||||
|
|
@ -106,9 +62,9 @@ struct EventManager
|
|||
|
||||
if(block.count >= data.max_events)
|
||||
{
|
||||
event_block_alloc_mutex.lock_nothrow();
|
||||
event_block_alloc_mutex.lock();
|
||||
scope (exit)
|
||||
event_block_alloc_mutex.unlock_nothrow();
|
||||
event_block_alloc_mutex.unlock();
|
||||
|
||||
EventBlock* new_block = cast(EventBlock*) allocator.getBlock();
|
||||
*new_block = EventBlock();
|
||||
|
|
@ -117,9 +73,6 @@ struct EventManager
|
|||
data.blocks[block_id] = block;
|
||||
}
|
||||
|
||||
/*void* start = cast(void*)block + data.data_offset + block.count * info.size;
|
||||
Ev* event_ptr = cast(Ev*)start;
|
||||
*event_ptr = event;*/
|
||||
Ev* event_array = cast(Ev*)(cast(void*)block + data.data_offset);
|
||||
event_array[block.count] = event;
|
||||
block.count++;
|
||||
|
|
@ -172,30 +125,16 @@ struct EventManager
|
|||
block = null;
|
||||
}
|
||||
}
|
||||
/*EventList tmp = current_events;
|
||||
current_events = process_events;
|
||||
process_events = tmp;
|
||||
|
||||
EventBlock* block = process_events.first_block;
|
||||
|
||||
while (block)
|
||||
{
|
||||
EventBlock* free = block;
|
||||
block = block.next;
|
||||
allocator.freeBlock(free);
|
||||
}
|
||||
process_events.first_block = null;
|
||||
process_events.current_block = null;*/
|
||||
}
|
||||
|
||||
void allocateData(uint threads_count) nothrow @nogc
|
||||
{
|
||||
disposeData();
|
||||
events = Mallocator.instance.makeArray!EventData(gEM.events.length);
|
||||
events = Mallocator.makeArray!EventData(gEM.events.length);
|
||||
foreach(i,ref event;events)
|
||||
{
|
||||
event.blocks = Mallocator.instance.makeArray!(EventBlock*)(threads_count*2);
|
||||
event.first_blocks = Mallocator.instance.makeArray!(EventBlock*)(threads_count*2);
|
||||
event.blocks = Mallocator.makeArray!(EventBlock*)(threads_count*2);
|
||||
event.first_blocks = Mallocator.makeArray!(EventBlock*)(threads_count*2);
|
||||
event.data_offset = EventBlock.sizeof;//gEM.events[i].
|
||||
gEM.alignNum(event.data_offset, gEM.events[i].alignment);
|
||||
|
||||
|
|
@ -216,16 +155,16 @@ struct EventManager
|
|||
if(block)next_block = first_block.next;
|
||||
while(block)
|
||||
{
|
||||
Mallocator.instance.dispose(block);
|
||||
Mallocator.dispose(block);
|
||||
block = next_block;
|
||||
if(block)next_block = block.next;
|
||||
}
|
||||
}
|
||||
|
||||
Mallocator.instance.dispose(event.blocks);
|
||||
Mallocator.instance.dispose(event.first_blocks);
|
||||
Mallocator.dispose(event.blocks);
|
||||
Mallocator.dispose(event.first_blocks);
|
||||
}
|
||||
Mallocator.instance.dispose(events);
|
||||
Mallocator.dispose(events);
|
||||
}
|
||||
allocator.freeMemory();
|
||||
}
|
||||
|
|
@ -233,10 +172,6 @@ struct EventManager
|
|||
~this() nothrow @nogc
|
||||
{
|
||||
disposeData();
|
||||
/*foreach(i,ref event;events)
|
||||
{
|
||||
EventBlock* block = event.first_blocks;
|
||||
}*/
|
||||
}
|
||||
|
||||
///Single page size. Must be power of two.
|
||||
|
|
@ -246,26 +181,10 @@ struct EventManager
|
|||
|
||||
struct EventBlock
|
||||
{
|
||||
/*union
|
||||
{
|
||||
struct
|
||||
{
|
||||
EventBlock* next;
|
||||
ushort index = 2;
|
||||
}
|
||||
|
||||
ubyte[events_block_size] data;
|
||||
}*/
|
||||
EventBlock* next;
|
||||
ushort count = 0;
|
||||
}
|
||||
|
||||
/*struct EventList
|
||||
{
|
||||
EventBlock* first_block;
|
||||
EventBlock* current_block;
|
||||
}*/
|
||||
|
||||
struct EventData
|
||||
{
|
||||
ushort data_offset;
|
||||
|
|
@ -276,12 +195,10 @@ struct EventManager
|
|||
//EventBlock*[] current_blocks;
|
||||
}
|
||||
|
||||
/*EventList current_events;
|
||||
EventList process_events;*/
|
||||
uint current_index = 0;
|
||||
EventData[] events;
|
||||
Mutex event_block_alloc_mutex;
|
||||
Mutex* event_block_alloc_mutex;
|
||||
|
||||
BlockAllocator/*!(events_block_size, events_blocks_in_allocation)*/ allocator;
|
||||
EntityManager manager;
|
||||
BlockAllocator allocator;
|
||||
EntityManager* manager;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ export ulong hashInt(ulong x) nothrow @nogc @safe {
|
|||
struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) {
|
||||
alias Key = KeyPar;
|
||||
alias Value = ValuePar;
|
||||
nothrow:
|
||||
|
||||
enum rehashFactor = 0.75;
|
||||
enum size_t getIndexEmptyValue = size_t.max;
|
||||
|
|
@ -262,7 +263,7 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) {
|
|||
return result;
|
||||
}
|
||||
|
||||
export int byKey(scope int delegate(Key k) dg) {
|
||||
export int byKey(scope int delegate(Key k) nothrow dg) {
|
||||
int result;
|
||||
foreach (ref Key k; this) {
|
||||
result = dg(k);
|
||||
|
|
@ -272,7 +273,7 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) {
|
|||
return result;
|
||||
}
|
||||
|
||||
export int byValue(scope int delegate(ref Value k) dg) {
|
||||
export int byValue(scope int delegate(ref Value k) nothrow dg) {
|
||||
int result;
|
||||
foreach (ref Value v; this) {
|
||||
result = dg(v);
|
||||
|
|
@ -282,7 +283,7 @@ struct HashMap(KeyPar, ValuePar, alias hashFunc = defaultHashFunc) {
|
|||
return result;
|
||||
}
|
||||
|
||||
export int byKeyValue(scope int delegate(ref Key k, ref Value v) dg) {
|
||||
export int byKeyValue(scope int delegate(ref Key k, ref Value v) nothrow dg) {
|
||||
int result;
|
||||
foreach (ref Key k, ref Value v; this) {
|
||||
result = dg(k, v);
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
module ecs.id_manager;
|
||||
|
||||
/*
|
||||
import std.experimental.allocator;
|
||||
import std.experimental.allocator.mallocator : AlignedMallocator, Mallocator;
|
||||
import std.experimental.allocator.mallocator : AlignedMallocator, Mallocator;*/
|
||||
|
||||
import ecs.entity;
|
||||
import ecs.vector;
|
||||
import ecs.std;
|
||||
|
||||
import core.atomic;
|
||||
import core.stdc.string : memcpy;
|
||||
import core.sync.mutex;
|
||||
//import core.sync.mutex;
|
||||
|
||||
/************************************************************************************************************************
|
||||
*IDManager is responsible for assignment and removing IDs. IDs are unique throughtout a whole duration of the program.
|
||||
|
|
@ -35,13 +36,13 @@ begin:
|
|||
uint block_id = local_id >> 16;
|
||||
if (block_id >= m_blocks_count)
|
||||
{
|
||||
add_mutex.lock_nothrow();
|
||||
add_mutex.lock();
|
||||
if(block_id >= m_blocks_count)
|
||||
{
|
||||
m_blocks[m_blocks_count].alloc();
|
||||
m_blocks_count++;
|
||||
}
|
||||
add_mutex.unlock_nothrow();
|
||||
add_mutex.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -145,30 +146,34 @@ begin:
|
|||
|
||||
void initialize() nothrow @nogc
|
||||
{
|
||||
m_ids_array = Mallocator.instance.makeArray!Data(65536);
|
||||
m_free_stack = Mallocator.instance.makeArray!uint(65536);
|
||||
m_blocks = Mallocator.instance.makeArray!Block(64);
|
||||
m_ids_array = Mallocator.makeArray!Data(65536);
|
||||
m_free_stack = Mallocator.makeArray!uint(65536);
|
||||
m_blocks = Mallocator.makeArray!Block(64);
|
||||
foreach(ref block;m_blocks)block = Block();
|
||||
m_blocks_count = 1;
|
||||
m_blocks[0].alloc();
|
||||
|
||||
add_mutex = Mallocator.instance.make!Mutex();
|
||||
add_mutex = Mallocator.make!Mutex();
|
||||
add_mutex.initialize();
|
||||
}
|
||||
|
||||
void deinitialize() @trusted @nogc
|
||||
void deinitialize() @trusted @nogc nothrow
|
||||
{
|
||||
if(m_ids_array)Mallocator.instance.dispose(m_ids_array);
|
||||
if(m_free_stack)Mallocator.instance.dispose(m_free_stack);
|
||||
if(m_ids_array)Mallocator.dispose(m_ids_array);
|
||||
if(m_free_stack)Mallocator.dispose(m_free_stack);
|
||||
if(m_blocks)
|
||||
{
|
||||
foreach(ref block;m_blocks)
|
||||
{
|
||||
if(block.data)block.free();
|
||||
}
|
||||
Mallocator.instance.dispose(m_blocks);
|
||||
Mallocator.dispose(m_blocks);
|
||||
}
|
||||
if(add_mutex)
|
||||
{
|
||||
Mallocator.instance.dispose(cast(void*)add_mutex); //workaround for compiler bug
|
||||
add_mutex.destroy();
|
||||
Mallocator.dispose(add_mutex);//cast(void*)add_mutex); //workaround for compiler bug
|
||||
add_mutex = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -178,14 +183,14 @@ begin:
|
|||
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));
|
||||
Data[] new_array = Mallocator.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);
|
||||
Mallocator.dispose(m_ids_array);
|
||||
m_ids_array = new_array;
|
||||
|
||||
uint[] new_stack = Mallocator.instance.makeArray!uint(m_ids_array.length);
|
||||
uint[] new_stack = Mallocator.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);
|
||||
Mallocator.dispose(m_free_stack);
|
||||
m_free_stack = new_stack;
|
||||
|
||||
foreach(block;m_blocks[0..m_blocks_count-1])
|
||||
|
|
@ -204,13 +209,13 @@ begin:
|
|||
void alloc() nothrow @nogc
|
||||
{
|
||||
assert(data is null);
|
||||
data = Mallocator.instance.makeArray!Data(65536);
|
||||
data = Mallocator.makeArray!Data(65536);
|
||||
}
|
||||
|
||||
void free() nothrow @nogc
|
||||
{
|
||||
assert(data !is null);
|
||||
Mallocator.instance.dispose(data);
|
||||
Mallocator.dispose(data);
|
||||
data = null;
|
||||
}
|
||||
|
||||
|
|
@ -225,7 +230,7 @@ begin:
|
|||
}
|
||||
|
||||
private:
|
||||
Mutex add_mutex;
|
||||
Mutex* add_mutex;
|
||||
//shared uint m_next_id = 0;
|
||||
|
||||
//shared uint m_last_id = 0;
|
||||
|
|
@ -261,5 +266,4 @@ unittest
|
|||
assert(id3 == EntityID(2, 1));
|
||||
assert(manager.isExist(id3));
|
||||
assert(!manager.isExist(EntityID(0, 1)));
|
||||
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,7 +1,9 @@
|
|||
module ecs.simple_vector;
|
||||
|
||||
/*
|
||||
import std.experimental.allocator;
|
||||
import std.experimental.allocator.mallocator;
|
||||
import std.experimental.allocator.mallocator;*/
|
||||
|
||||
import ecs.std;
|
||||
|
||||
import core.stdc.string;
|
||||
|
||||
|
|
@ -14,8 +16,8 @@ struct SimpleVector
|
|||
{
|
||||
while(used >= data.length)
|
||||
{
|
||||
if(data is null)data = Mallocator.instance.makeArray!ubyte(1024);
|
||||
else Mallocator.instance.expandArray(data,data.length);
|
||||
if(data is null)data = Mallocator.makeArray!ubyte(1024);
|
||||
else data = Mallocator.expandArray(data,data.length);
|
||||
}
|
||||
data[used++] = el;
|
||||
}
|
||||
|
|
@ -24,8 +26,8 @@ struct SimpleVector
|
|||
{
|
||||
while(used + el.length >= data.length)
|
||||
{
|
||||
if(data is null)data = Mallocator.instance.makeArray!ubyte(1024);
|
||||
else Mallocator.instance.expandArray(data,data.length);
|
||||
if(data is null)data = Mallocator.makeArray!ubyte(1024);
|
||||
else data = Mallocator.expandArray(data,data.length);
|
||||
}
|
||||
memcpy(data.ptr + used, el.ptr, el.length);
|
||||
used += el.length;
|
||||
|
|
|
|||
227
source/ecs/std.d
Normal file
227
source/ecs/std.d
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
module ecs.std;
|
||||
|
||||
import core.stdc.stdlib : malloc, free, realloc;
|
||||
import core.stdc.string : memcpy;
|
||||
import std.traits;
|
||||
import core.time;
|
||||
|
||||
version (Windows)
|
||||
{
|
||||
import core.sys.windows.windows;
|
||||
extern(Windows) void* _aligned_malloc(size_t size,size_t alignment) @nogc nothrow @system;
|
||||
extern(Windows) void _aligned_free(void* ptr) @nogc nothrow @system;
|
||||
|
||||
version(LDC)
|
||||
{
|
||||
/*extern(Windows) void* __alloca(size_t size) @nogc nothrow @system;
|
||||
alias alloca = __alloca;*/
|
||||
|
||||
private const uint max_alloca = 10000;
|
||||
private char[max_alloca] alloca_array;
|
||||
private uint alloca_pos = 0;
|
||||
void* alloca(size_t length) @nogc nothrow
|
||||
{
|
||||
if(alloca_pos + length > max_alloca)alloca_pos = 0;
|
||||
void* ret = &alloca_array[alloca_pos];
|
||||
alloca_pos += length;
|
||||
return ret;
|
||||
}
|
||||
|
||||
extern(Windows) void ___chkstk_ms() @nogc nothrow @system;
|
||||
|
||||
extern(Windows) void __chkstk()
|
||||
{
|
||||
___chkstk_ms();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
private const uint max_alloca = 10000;
|
||||
private char[max_alloca] alloca_array;
|
||||
private uint alloca_pos = 0;
|
||||
void* alloca(size_t length) @nogc nothrow
|
||||
{
|
||||
if(alloca_pos + length > max_alloca)alloca_pos = 0;
|
||||
void* ret = &alloca_array[alloca_pos];
|
||||
alloca_pos += length;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
else version (Posix)
|
||||
{
|
||||
import core.sys.posix.pthread;
|
||||
import core.sys.posix.stdlib;
|
||||
public import core.stdc.stdlib : alloca;
|
||||
}
|
||||
|
||||
static struct Mallocator
|
||||
{
|
||||
static T[] makeArray(T)(size_t length) nothrow @nogc
|
||||
{
|
||||
T[] ret = (cast(T*)malloc(T.sizeof * length))[0 .. length];
|
||||
|
||||
/*static if(__traits(isPOD, T))
|
||||
{
|
||||
static immutable T init = T.init;
|
||||
|
||||
foreach(i;0..ret.length)
|
||||
{
|
||||
memcpy(&ret[i], &init, T.sizeof);
|
||||
}
|
||||
}
|
||||
else
|
||||
{*/
|
||||
static import std.conv;
|
||||
foreach(i;0..ret.length)
|
||||
{
|
||||
std.conv.emplace(&ret[i]);
|
||||
}
|
||||
// }
|
||||
|
||||
//static if(is(T == struct))std.conv.emplace(ret);
|
||||
//static import std.conv;
|
||||
//emplace
|
||||
/*foreach(i;0..ret.length)
|
||||
{
|
||||
memcpy(ret);
|
||||
}*/
|
||||
return ret;
|
||||
}
|
||||
|
||||
static T[] makeArray(T)(size_t length, T initializer) nothrow @nogc
|
||||
{
|
||||
T[] ret = (cast(T*)malloc(T.sizeof * length))[0 .. length];
|
||||
foreach(ref v; ret)v = initializer;
|
||||
return ret;
|
||||
//return (cast(T*)ret)[0 .. length];
|
||||
}
|
||||
|
||||
static T[] expandArray(T)(T[] array, size_t length) nothrow @nogc
|
||||
{
|
||||
size_t new_length = array.length + length;
|
||||
return (cast(T*)realloc(array.ptr, T.sizeof * new_length))[0 .. new_length];
|
||||
}
|
||||
|
||||
static T[] makeArray(T)(T[] array) nothrow @nogc
|
||||
{
|
||||
T[] ret = (cast(T*)malloc(T.sizeof * array.length))[0 .. array.length];//Mallocator.makeArray!(T)(array.length);
|
||||
foreach(i, ref v;ret)v = array[i];
|
||||
//ret[0 .. $] = array;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static T* make(T, Args...)(Args args)
|
||||
{
|
||||
T* ret = cast(T*)malloc(T.sizeof);
|
||||
//*ret = T.init;
|
||||
//static immutable T init = T();
|
||||
//memcpy(ret, &init, T.sizeof);
|
||||
//static if(__traits(hasMember, T, "__ctor"))ret.__ctor(args);
|
||||
static import std.conv;
|
||||
static if(__traits(isPOD, T))
|
||||
{
|
||||
static immutable T init = T.init;
|
||||
memcpy(ret, &init, T.sizeof);
|
||||
}
|
||||
else static if(is(T == struct))std.conv.emplace(ret, args);
|
||||
//else std.conv.emplace(ret, args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void* alignAlloc(size_t length, size_t alignment) nothrow @nogc
|
||||
{
|
||||
|
||||
void* ret;
|
||||
version(Posix)ret = aligned_alloc(alignment, length);
|
||||
else version(Windows)ret = _aligned_malloc(length, alignment);
|
||||
else static assert(0, "Unimplemented platform!");
|
||||
//posix_memalign(&ret, alignment, length);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void dispose(T)(T object) nothrow @nogc
|
||||
{
|
||||
static if(__traits(hasMember, T, "__dtor"))object.__dtor();
|
||||
free(cast(void*)object);
|
||||
}
|
||||
|
||||
static void alignDispose(T)(T object)
|
||||
{
|
||||
static if(__traits(hasMember, T, "__dtor"))object.__dtor();
|
||||
version(Posix)aligned_free(cast(void*)object);
|
||||
else version(Windows)_aligned_free(cast(void*)object);
|
||||
else static assert(0, "Unimplemented platform!");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
struct Mutex
|
||||
{
|
||||
|
||||
version (Windows)
|
||||
{
|
||||
void initialize() nothrow @nogc
|
||||
{
|
||||
InitializeCriticalSection(cast(CRITICAL_SECTION*) &m_handle);
|
||||
}
|
||||
|
||||
void destroy() nothrow @nogc
|
||||
{
|
||||
DeleteCriticalSection(&m_handle);
|
||||
}
|
||||
|
||||
void lock() nothrow @nogc
|
||||
{
|
||||
EnterCriticalSection(&m_handle);
|
||||
}
|
||||
|
||||
void unlock() nothrow @nogc
|
||||
{
|
||||
LeaveCriticalSection(&m_handle);
|
||||
}
|
||||
|
||||
int tryLock() nothrow @nogc
|
||||
{
|
||||
return TryEnterCriticalSection(&m_handle) != 0;
|
||||
}
|
||||
|
||||
CRITICAL_SECTION m_handle;
|
||||
}
|
||||
else version (Posix)
|
||||
{
|
||||
void initialize() nothrow @nogc
|
||||
{
|
||||
pthread_mutexattr_t attr = void;
|
||||
|
||||
pthread_mutexattr_init(&attr);
|
||||
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
||||
pthread_mutex_init(cast(pthread_mutex_t*) &m_handle, &attr);
|
||||
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
}
|
||||
|
||||
void destroy() nothrow @nogc
|
||||
{
|
||||
pthread_mutex_destroy(&m_handle);
|
||||
}
|
||||
|
||||
void lock() nothrow @nogc
|
||||
{
|
||||
pthread_mutex_lock(&m_handle);
|
||||
}
|
||||
|
||||
void unlock() nothrow @nogc
|
||||
{
|
||||
pthread_mutex_unlock(&m_handle);
|
||||
}
|
||||
|
||||
int tryLock() nothrow @nogc
|
||||
{
|
||||
return pthread_mutex_trylock(&m_handle) == 0;
|
||||
}
|
||||
|
||||
private pthread_mutex_t m_handle;
|
||||
}
|
||||
}
|
||||
|
|
@ -125,14 +125,14 @@ package:
|
|||
//void function(ref EntityManager.CallData data) m_update;
|
||||
void* m_update; ///workaroud for DMD bug with upper line
|
||||
|
||||
/*void function(void* system_pointer) m_enable;
|
||||
void function(void* system_pointer) m_disable;
|
||||
//void function(void* system_pointer) m_enable;
|
||||
//void function(void* system_pointer) m_disable;
|
||||
|
||||
void function(void* system_pointer) m_create;
|
||||
void function(void* system_pointer) m_destroy;
|
||||
//void function(void* system_pointer) m_create;
|
||||
//void function(void* system_pointer) m_destroy;
|
||||
|
||||
void function(void* system_pointer) m_begin;
|
||||
void function(void* system_pointer) m_end;*/
|
||||
//void function(void* system_pointer) m_begin;
|
||||
//void function(void* system_pointer) m_end;
|
||||
|
||||
void* m_enable;
|
||||
void* m_disable;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ module ecs.vector;
|
|||
import core.bitop;
|
||||
import core.stdc.stdlib : free, malloc;
|
||||
import core.stdc.string : memcpy, memset;
|
||||
import std.algorithm : swap;
|
||||
//import std.algorithm : swap;
|
||||
import std.conv : emplace;
|
||||
import std.traits : hasMember, isCopyable, TemplateOf, Unqual;
|
||||
|
||||
|
|
@ -28,7 +28,7 @@ public:
|
|||
|
||||
}
|
||||
|
||||
static if (isCopyable!T) {
|
||||
/*static if (isCopyable!T) {
|
||||
export this(this) {
|
||||
T[] tmp = array[0 .. used];
|
||||
array = null;
|
||||
|
|
@ -37,7 +37,9 @@ public:
|
|||
}
|
||||
} else {
|
||||
@disable this(this);
|
||||
}
|
||||
}*/
|
||||
|
||||
@disable this(this);
|
||||
|
||||
export ~this() {
|
||||
clear();
|
||||
|
|
@ -167,7 +169,8 @@ public:
|
|||
|
||||
export void remove(size_t elemNum) {
|
||||
destroy(array[elemNum]);
|
||||
swap(array[elemNum], array[used - 1]);
|
||||
//swap(array[elemNum], array[used - 1]);
|
||||
array[elemNum] = array[used - 1];
|
||||
used--;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue