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.algorithm.comparison : max; //import core.sync.mutex; /*struct Event { uint id; }*/ //mixin template EventManagerCode() struct EventManager { void initialize(EntityManager* m) nothrow @nogc { allocator = BlockAllocator(events_block_size, events_blocks_in_allocation); event_block_alloc_mutex = Mallocator.make!Mutex; event_block_alloc_mutex.initialize(); manager = m; } void destroy() nothrow @nogc { 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 { uint block_id = current_index+thread_id; EventData* data = &events[Ev.event_id]; EventBlock* block = data.blocks[block_id]; EntityManager.EventInfo* info = &gEM.events[Ev.event_id]; event.entity_id = id; if(block is null) { event_block_alloc_mutex.lock(); scope (exit) event_block_alloc_mutex.unlock(); block = cast(EventBlock*) allocator.getBlock(); *block = EventBlock(); data.first_blocks[block_id] = block; data.blocks[block_id] = block; } if(block.count >= data.max_events) { event_block_alloc_mutex.lock(); scope (exit) event_block_alloc_mutex.unlock(); EventBlock* new_block = cast(EventBlock*) allocator.getBlock(); *new_block = EventBlock(); block.next = new_block; block = new_block; data.blocks[block_id] = block; } Ev* event_array = cast(Ev*)(cast(void*)block + data.data_offset); event_array[block.count] = event; block.count++; } void swapCurrent() nothrow @nogc { uint threads_count = cast(uint)manager.threads.length; if(current_index == 0)current_index = threads_count; else current_index = 0; foreach(ref event;events) { foreach(ref first_block; event.first_blocks[current_index .. current_index + threads_count]) { EventBlock* block = first_block; while(block) { EventBlock* to_dispose = block; block = block.next; allocator.freeBlock(to_dispose); } first_block = null; } foreach(ref block; event.blocks[current_index .. current_index + threads_count]) { block = null; } } } void clearEvents() nothrow @nogc { uint threads_count = cast(uint)manager.threads.length; foreach(ref event;events) { foreach(ref first_block; event.first_blocks) { EventBlock* block = first_block; while(block) { EventBlock* to_dispose = block; block = block.next; allocator.freeBlock(to_dispose); } first_block = null; } foreach(ref block; event.blocks) { block = null; } } } void allocateData(uint threads_count) nothrow @nogc { disposeData(); events = Mallocator.makeArray!EventData(gEM.events.length); foreach(i,ref event;events) { 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); event.max_events = cast(ushort)((events_block_size - event.data_offset) / gEM.events[i].size); } } private void disposeData() nothrow @nogc { if(events) { foreach(ref event;events) { foreach(first_block; event.first_blocks) { EventBlock* block = first_block; EventBlock* next_block; if(block)next_block = first_block.next; while(block) { Mallocator.dispose(block); block = next_block; if(block)next_block = block.next; } } Mallocator.dispose(event.blocks); Mallocator.dispose(event.first_blocks); } Mallocator.dispose(events); } allocator.freeMemory(); } ~this() nothrow @nogc { disposeData(); } ///Single page size. Must be power of two. enum events_block_size = 1 << 14; ///Number of pages in block. enum events_blocks_in_allocation = 128; struct EventBlock { EventBlock* next; ushort count = 0; } struct EventData { ushort data_offset; ushort max_events; EventBlock*[] blocks; EventBlock*[] first_blocks; //EventBlock*[] current_blocks; } uint current_index = 0; EventData[] events; Mutex* event_block_alloc_mutex; BlockAllocator allocator; EntityManager* manager; }