Last active
November 25, 2022 15:48
-
-
Save darkuranium/5a789bab35e8524ab358120ad225c13c to your computer and use it in GitHub Desktop.
MCVE for FLECS problem of EcsWith not working properly when used with singletons
This file contains hidden or 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
cmake_minimum_required(VERSION 3.2) | |
project(FlecsMCVE LANGUAGES C) | |
# NOTE: A clone of the FLECS repository (https://github.com/SanderMertens/flecs) is expected to exist in `flecs/` | |
add_subdirectory(flecs) | |
add_executable(mcve mcve.c) | |
target_link_libraries(mcve flecs_static) |
This file contains hidden or 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 <flecs.h> | |
#include <stdio.h> | |
// impromptu test framework | |
#define STREAM stdout | |
#define PREFIX " " | |
uint32_t pass; | |
uint32_t fail; | |
#define HEAD(...) do { \ | |
fprintf(STREAM, "==== [L:%3u]: ", __LINE__); \ | |
fprintf(STREAM, __VA_ARGS__); \ | |
fprintf(STREAM, " ====\n"); \ | |
fflush(STREAM); \ | |
} while(0) | |
#define INFO(...) do { \ | |
fprintf(STREAM, PREFIX "---- [L:%3u]: ", __LINE__); \ | |
fprintf(STREAM, __VA_ARGS__); \ | |
fprintf(STREAM, "\n"); \ | |
fflush(STREAM); \ | |
} while(0) | |
#define TEST(X, ...) do { \ | |
if((X)) { ++pass; fprintf(STREAM, PREFIX " ok "); } \ | |
else { ++fail; fprintf(STREAM, PREFIX "FAIL"); } \ | |
fprintf(STREAM, " [L:%3u]: %s (", __LINE__, #X); \ | |
fprintf(STREAM, __VA_ARGS__); \ | |
fprintf(STREAM, ")\n"); \ | |
fflush(STREAM); \ | |
} while(0) | |
// Two test components. | |
typedef struct Foo | |
{ | |
int foo; | |
} Foo; | |
ECS_COMPONENT_DECLARE(Foo); | |
typedef struct Bar | |
{ | |
int bar; | |
} Bar; | |
ECS_COMPONENT_DECLARE(Bar); | |
static void dump_ints(const int* vals, int32_t count) | |
{ | |
for(int32_t i = 0; i < count; i++) | |
fprintf(STREAM, " %d", vals[i]); | |
} | |
static void cb_ctor(void* ptr, int32_t count, const ecs_type_info_t* type_info) | |
{ | |
fprintf(STREAM, PREFIX " %s ctor[%d]\n", type_info->name, count); | |
fflush(STREAM); | |
memset(ptr, 0, count * type_info->size); | |
} | |
static void cb_dtor(void* ptr, int32_t count, const ecs_type_info_t* type_info) | |
{ | |
fprintf(STREAM, PREFIX " %s dtor[%d]:", type_info->name, count); | |
dump_ints(ptr, count); | |
fprintf(STREAM, "\n"); | |
fflush(STREAM); | |
} | |
static void cb_copy(void* dst_ptr, const void* src_ptr, int32_t count, const ecs_type_info_t* type_info) | |
{ | |
fprintf(STREAM, PREFIX " %s copy[%d]:", type_info->name, count); | |
dump_ints(src_ptr, count); | |
fprintf(STREAM, "\n"); | |
fflush(STREAM); | |
memcpy(dst_ptr, src_ptr, count * type_info->size); | |
} | |
static void cb_move(void* dst_ptr, void* src_ptr, int32_t count, const ecs_type_info_t* type_info) | |
{ | |
fprintf(STREAM, PREFIX " %s move[%d]:", type_info->name, count); | |
dump_ints(src_ptr, count); | |
fprintf(STREAM, "\n"); | |
fflush(STREAM); | |
memcpy(dst_ptr, src_ptr, count * type_info->size); | |
memset(src_ptr, 0, count * type_info->size); | |
} | |
static void Foo_on_add(ecs_iter_t* it) | |
{ | |
Foo* foo = ecs_field(it, Foo, 1); | |
fprintf(STREAM, PREFIX " Foo add[%d]:", it->count); | |
dump_ints((const int*)foo, it->count); | |
fprintf(STREAM, "\n"); | |
fflush(STREAM); | |
} | |
static void Foo_on_remove(ecs_iter_t* it) | |
{ | |
Foo* foo = ecs_field(it, Foo, 1); | |
fprintf(STREAM, PREFIX " Foo remove[%d]:", it->count); | |
dump_ints((const int*)foo, it->count); | |
fprintf(STREAM, "\n"); | |
fflush(STREAM); | |
} | |
static void Bar_on_add(ecs_iter_t* it) | |
{ | |
Foo* foo = ecs_field(it, Foo, 1); | |
fprintf(STREAM, PREFIX " Bar add[%d]:", it->count); | |
dump_ints((const int*)foo, it->count); | |
fprintf(STREAM, "\n"); | |
fflush(STREAM); | |
} | |
static void Bar_on_remove(ecs_iter_t* it) | |
{ | |
Foo* foo = ecs_field(it, Foo, 1); | |
fprintf(STREAM, PREFIX " Bar remove[%d]:", it->count); | |
dump_ints((const int*)foo, it->count); | |
fprintf(STREAM, "\n"); | |
fflush(STREAM); | |
} | |
// Module body; separate so that the module can be easily toggled (for testing purposes). | |
static void FooBarBody(ecs_world_t* world) | |
{ | |
INFO("Defining `Foo` and `Bar` components"); | |
ECS_COMPONENT_DEFINE(world, Foo); | |
ecs_set_hooks(world, Foo, { | |
.ctor = cb_ctor, | |
.dtor = cb_dtor, | |
.copy = cb_copy, | |
.move = cb_move, | |
.on_add = Foo_on_add, | |
.on_remove = Foo_on_remove, | |
}); | |
ECS_COMPONENT_DEFINE(world, Bar); | |
ecs_set_hooks(world, Bar, { | |
.ctor = cb_ctor, | |
.dtor = cb_dtor, | |
.copy = cb_copy, | |
.move = cb_move, | |
.on_add = Bar_on_add, | |
.on_remove = Bar_on_remove, | |
}); | |
INFO("Adding EcsWith(Foo,Bar) pair"); | |
ecs_add_pair(world, ecs_id(Foo), EcsWith, ecs_id(Bar)); | |
// Singleton tests. | |
HEAD("Singleton tests"); | |
{ | |
INFO("Adding `Foo` singleton"); | |
ecs_singleton_add(world, Foo); | |
INFO("Performing tests ..."); | |
TEST(ecs_singleton_get(world, Foo), "Check whether singleton `Foo` is present after adding `Foo`"); | |
TEST(ecs_singleton_get(world, Bar), "Check whether singleton `Bar` is present after adding `Foo`"); | |
INFO("CLEANUP: Removing `Foo` singleton"); | |
ecs_singleton_remove(world, Foo); | |
INFO("CLEANUP: Removing `Bar` singleton"); | |
ecs_singleton_remove(world, Bar); | |
INFO("Adding `Bar` singleton"); | |
ecs_singleton_add(world, Bar); | |
INFO("Performing tests ..."); | |
TEST(ecs_singleton_get(world, Foo), "Check whether singleton `Foo` is present after adding `Bar`"); | |
TEST(ecs_singleton_get(world, Bar), "Check whether singleton `Bar` is present after adding `Bar`"); | |
} | |
// Entity tests. | |
HEAD("Entity tests"); | |
{ | |
INFO("Creating new entity `TestEntity`"); | |
ecs_entity_t entity = ecs_new_entity(world, "TestEntity"); | |
INFO("Adding `Foo` to `TestEntity`"); | |
ecs_add(world, entity, Foo); | |
INFO("Performing tests ..."); | |
TEST(ecs_get(world, entity, Foo), "Check whether component `Foo` is present in `TestEntity` after adding `Foo`"); | |
TEST(ecs_get(world, entity, Bar), "Check whether component `Bar` is present in `TestEntity` after adding `Foo`"); | |
} | |
} | |
// The actual module to import. | |
void FooBarImport(ecs_world_t* world) | |
{ | |
INFO("Importing `FooBar` module"); | |
ECS_MODULE(world, FooBar); | |
FooBarBody(world); | |
} | |
int main(int argc, char** argv) | |
{ | |
fprintf(STREAM, "MCVE for FLECS problem of EcsWith not working properly when used with singletons.\n"); | |
fprintf(STREAM, "\n"); | |
fflush(STREAM); | |
ecs_world_t* world = ecs_init_w_args(argc, argv); | |
HEAD("Initialization"); | |
pass = fail = 0; | |
#if 1 // use module | |
ECS_IMPORT(world, FooBar); | |
#else // skip module | |
FooBarBody(world); | |
#endif | |
ecs_quit(world); | |
fprintf(STREAM, "\n"); | |
fprintf(STREAM, "DONE: pass=%u fail=%u\n", pass, fail); | |
fflush(STREAM); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment