Last active
October 19, 2020 07:27
-
-
Save mrtrizer/ad98f848aab0c21f9c1ec913430d0ff4 to your computer and use it in GitHub Desktop.
C language cache-friendly ECS
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <stdint.h> | |
#include <limits.h> | |
#include <assert.h> | |
#include <stdbool.h> | |
typedef uint32_t EId; | |
typedef struct | |
{ | |
EId* eIds; | |
uint8_t* data; | |
size_t itemSize; | |
size_t length; | |
size_t reserve; | |
size_t i; | |
size_t removedN; | |
void (*deinit)(void*); | |
void* (*realloc)(void *, size_t); | |
} ECDict; | |
size_t getCDataIndex(ECDict* dict, EId eId) | |
{ | |
for (size_t i = dict->i; i < dict->length; i++) | |
if (dict->eIds[i] == eId) | |
return i; | |
for (size_t i = 0; i < dict->i; i++) | |
if (dict->eIds[i] == eId) | |
return i; | |
return SIZE_MAX; | |
} | |
void* getCData(ECDict* dict, EId eId) | |
{ | |
size_t i = getCDataIndex(dict, eId); | |
if (i != SIZE_MAX) | |
{ | |
dict->i = i; | |
return dict->data + i * dict->itemSize; | |
} | |
return NULL; | |
} | |
void* addC(ECDict* dict, EId eId) | |
{ | |
if (dict->removedN > 0) | |
{ | |
size_t i = getCDataIndex(dict, 0); | |
assert(i != SIZE_MAX); | |
dict->eIds[i] = eId; | |
dict->removedN--; | |
return dict->data + i * dict->itemSize; | |
} | |
else | |
{ | |
if (dict->length == dict->reserve) | |
{ | |
dict->reserve += 1000; | |
dict->data = dict->realloc(dict->data, dict->reserve * dict->itemSize); | |
dict->eIds = dict->realloc(dict->eIds, dict->reserve * sizeof(*dict->eIds)); | |
} | |
dict->eIds[dict->length] = eId; | |
return dict->data + dict->itemSize * dict->length++; | |
} | |
} | |
bool removeC(ECDict* dict, EId eId) | |
{ | |
size_t i = getCDataIndex(dict, eId); | |
if (i != SIZE_MAX) | |
{ | |
dict->eIds[i] = 0; | |
if (dict->deinit) | |
dict->deinit(dict->data + dict->itemSize * i); | |
dict->removedN++; | |
return true; | |
} | |
return false; | |
} | |
typedef struct | |
{ | |
int x; | |
int y; | |
} TestComponent; | |
void initTestComponent(void* ref, int x, int y) | |
{ | |
TestComponent* c = ref; | |
c->x = x; | |
c->y = y; | |
} | |
void deinitTestComponent(void* ref) | |
{ | |
TestComponent* c = ref; | |
c->x = c->y = 0; | |
} | |
int main(void) | |
{ | |
ECDict test = { .itemSize = sizeof(TestComponent), .realloc = realloc, .deinit = deinitTestComponent }; | |
initTestComponent(addC(&test, 1), 10, 20); | |
initTestComponent(addC(&test, 2), 11, 21); | |
assert(test.length == 2); | |
assert(test.reserve == 1000); | |
removeC(&test, 1); | |
initTestComponent(addC(&test, 3), 12, 22); | |
initTestComponent(addC(&test, 4), 13, 23); | |
assert(test.length == 3); | |
for (EId* id = test.eIds; id != test.eIds + test.length; id++) | |
{ | |
TestComponent* c = getCData(&test, *id); | |
printf("%lu ( %u ) %d %d\n", id - test.eIds, *id, c->x, c->y); | |
} | |
return EXIT_SUCCESS; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment