module tests.perf;

import tests.runner;

import bubel.ecs.core;
import bubel.ecs.manager;
import bubel.ecs.entity;

import std.array : staticArray;

import core.stdc.stdio;

struct CLong
{
    mixin ECS.Component;

    alias value this;

    long value = 10;
}

struct CShort
{
    mixin ECS.Component;

    alias value this;

    short value = 12;
}

struct CInt
{
    mixin ECS.Component;

    alias value this;

    int value = 10;
}

struct CUInt
{
    mixin ECS.Component;

    alias value this;

    uint value = 12;
}

struct CBig
{
    mixin ECS.Component;
    uint[32] data;
}

EntityTemplate* tmpl;

void beforeEveryTest()
{
    gEM.initialize(0);

    gEM.beginRegister();

    gEM.registerComponent!CLong;
    gEM.registerComponent!CShort;
    gEM.registerComponent!CInt;
    gEM.registerComponent!CUInt;
    gEM.registerComponent!CBig;

    gEM.endRegister();
    tmpl = null;
}

void afterEveryTest()
{
    if(tmpl)gEM.freeTemplate(tmpl);
    tmpl = null;
    gEM.destroy();
}

void smallTmpl()
{
    tmpl = gEM.allocateTemplate([CShort.component_id].staticArray);
}

void bigTmpl()
{
    tmpl = gEM.allocateTemplate([CBig.component_id].staticArray);
}

void multiSmallTmpl()
{
    tmpl = gEM.allocateTemplate([CShort.component_id, CLong.component_id, CInt.component_id, CUInt.component_id].staticArray);
}

void multiBigTmpl()
{
    tmpl = gEM.allocateTemplate([CLong.component_id, CInt.component_id, CUInt.component_id, CBig.component_id].staticArray);
}

@("AddEntities100k1comp2b")  @(before, &smallTmpl)
unittest
{
    foreach(i; 0..100_000)gEM.addEntity(tmpl);
}

@("AddEntities100k1comp128b")  @(before, &bigTmpl)
unittest
{
    foreach(i; 0..100_000)gEM.addEntity(tmpl);
}

@("AddEntities100k4comp18b")  @(before, &multiSmallTmpl)
unittest
{
    foreach(i; 0..100_000)gEM.addEntity(tmpl);
}

@("AddEntities100k4comp144b")  @(before, &multiBigTmpl)
unittest
{
    foreach(i; 0..100_000)gEM.addEntity(tmpl);
}

void allocDealloc100k()
{
    foreach(i; 0..100_000)gEM.addEntity(tmpl);
    gEM.commit();
    foreach(i; 0..100_000)gEM.removeEntity(EntityID(i + 1,0));
    gEM.commit();
}

void smallTmplPreAlloc()
{
    tmpl = gEM.allocateTemplate([CShort.component_id].staticArray);
    allocDealloc100k();
}

void bigTmplPreAlloc()
{
    tmpl = gEM.allocateTemplate([CBig.component_id].staticArray);
    allocDealloc100k();
}

void multiSmallTmplPreAlloc()
{
    tmpl = gEM.allocateTemplate([CShort.component_id, CLong.component_id, CInt.component_id, CUInt.component_id].staticArray);
    allocDealloc100k();
}

void multiBigTmplPreAlloc()
{
    tmpl = gEM.allocateTemplate([CLong.component_id, CInt.component_id, CUInt.component_id, CBig.component_id].staticArray);
    allocDealloc100k();
}

@("AddEntities100k1comp2bPreAlloc")  @(before, &smallTmplPreAlloc)
unittest
{
    foreach(i; 0..100_000)gEM.addEntity(tmpl);
}

@("AddEntities100k1comp128bPreAlloc")  @(before, &bigTmplPreAlloc)
unittest
{
    foreach(i; 0..100_000)gEM.addEntity(tmpl);
}

@("AddEntities100k4comp18bPreAlloc")  @(before, &multiSmallTmplPreAlloc)
unittest
{
    foreach(i; 0..100_000)gEM.addEntity(tmpl);
}

@("AddEntities100k4comp144bPreAlloc")  @(before, &multiBigTmplPreAlloc)
unittest
{
    foreach(i; 0..100_000)gEM.addEntity(tmpl);
}