Skip to content

Instantly share code, notes, and snippets.

@darkuranium
Last active November 25, 2022 15:48
Show Gist options
  • Save darkuranium/5a789bab35e8524ab358120ad225c13c to your computer and use it in GitHub Desktop.
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
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)
#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