Change .clang-format

This commit is contained in:
NukeBird 2025-02-16 21:18:39 +03:00
parent 26353e423b
commit 123aa2b7dc
3 changed files with 92 additions and 104 deletions

View file

@ -3,3 +3,12 @@ BreakBeforeBraces: Allman
AccessModifierOffset: -4 AccessModifierOffset: -4
IndentWidth: 4 IndentWidth: 4
AlwaysBreakTemplateDeclarations: Yes AlwaysBreakTemplateDeclarations: Yes
NamespaceIndentation: All
SpaceAfterTemplateKeyword: false
PointerAlignment: Left
ReferenceAlignment: Left
SpaceAfterControlStatementKeyword: false
AllowShortFunctionsOnASingleLine: false
SpaceBeforeCtorInitializerColon: false
SpaceBeforeInheritanceColon: false
SpaceBeforeRangeBasedForLoopColon: false

View file

@ -1,5 +1,4 @@
#include <catch2/catch_test_macros.hpp> #include <catch2/catch_test_macros.hpp>
#include <concepts>
#include <string> #include <string>
#define CATCH_CONFIG_MAIN #define CATCH_CONFIG_MAIN
#include <catch2/catch_all.hpp> #include <catch2/catch_all.hpp>
@ -11,26 +10,26 @@ using namespace zecsy;
TEST_CASE("Create a single entity and verify its existence") TEST_CASE("Create a single entity and verify its existence")
{ {
world w; world w;
auto e = w.make_entity(); auto e = w.make_entity();
REQUIRE(w.is_alive(e)); REQUIRE(w.is_alive(e));
} }
TEST_CASE("Destroy an entity and ensure it no longer exists in the world") TEST_CASE("Destroy an entity and ensure it no longer exists in the world")
{ {
world w; world w;
auto e = w.make_entity(); auto e = w.make_entity();
w.destroy_entity(e); w.destroy_entity(e);
REQUIRE_FALSE(w.is_alive(e)); REQUIRE_FALSE(w.is_alive(e));
} }
TEST_CASE("Entity #0 should be reserved and never used") TEST_CASE("Entity #0 should be reserved and never used")
{ {
world w; world w;
auto e = w.make_entity(); auto e = w.make_entity();
REQUIRE(e != 0); REQUIRE(e != 0);
@ -39,7 +38,6 @@ TEST_CASE("Entity #0 should be reserved and never used")
struct ChoosenOne struct ChoosenOne
{ {
}; };
TEST_CASE("Entity shouldn't have a component that wasn't attached to it") TEST_CASE("Entity shouldn't have a component that wasn't attached to it")
@ -60,7 +58,8 @@ TEST_CASE("Attempt of getting non-owned component should throw")
REQUIRE_THROWS(w.get<ChoosenOne>(e)); REQUIRE_THROWS(w.get<ChoosenOne>(e));
} }
TEST_CASE("Attach a simple component to an entity and verify it is correctly associated") TEST_CASE("Attach a simple component to an entity and verify it is correctly "
"associated")
{ {
world w; world w;
@ -74,13 +73,14 @@ TEST_CASE("Attach a simple component to an entity and verify it is correctly ass
REQUIRE(w.has<ChoosenOne>(e2)); REQUIRE(w.has<ChoosenOne>(e2));
} }
struct Name struct Name
{ {
std::string value; std::string value;
}; };
TEST_CASE("Retrieve a component from an entity and verify its data matches what was set") TEST_CASE("Retrieve a component from an entity and verify its data matches "
"what was set")
{ {
world w; world w;
@ -94,7 +94,8 @@ TEST_CASE("Retrieve a component from an entity and verify its data matches what
REQUIRE(w.get<Name>(e).value == "super-zecsy!"); REQUIRE(w.get<Name>(e).value == "super-zecsy!");
} }
TEST_CASE("Remove a component from an entity and verify it is no longer attached") TEST_CASE(
"Remove a component from an entity and verify it is no longer attached")
{ {
world w; world w;
@ -112,7 +113,7 @@ TEST_CASE("Remove a component from an entity and verify it is no longer attached
TEST_CASE("Addresses of removed components should be reused") TEST_CASE("Addresses of removed components should be reused")
{ {
world w; world w;
std::vector<entity_id> entities; std::vector<entity_id> entities;
std::vector<ChoosenOne*> addr; std::vector<ChoosenOne*> addr;
@ -133,7 +134,7 @@ TEST_CASE("Addresses of removed components should be reused")
addr.emplace_back(&w.get<ChoosenOne>(entities[j])); addr.emplace_back(&w.get<ChoosenOne>(entities[j]));
} }
} }
else else
{ {
for(int j = 0; j < N; ++j) for(int j = 0; j < N; ++j)
{ {
@ -149,7 +150,8 @@ TEST_CASE("Addresses of removed components should be reused")
} }
} }
TEST_CASE("Attach multiple components to an entity and verify all are correctly stored and retrievable") TEST_CASE("Attach multiple components to an entity and verify all are "
"correctly stored and retrievable")
{ {
world w; world w;
@ -165,9 +167,10 @@ TEST_CASE("Attach multiple components to an entity and verify all are correctly
REQUIRE_FALSE(w.has<Name>(e)); REQUIRE_FALSE(w.has<Name>(e));
} }
TEST_CASE("Create a simple system that processes entities with a specific component and verify it executes correctly") TEST_CASE("Create a simple system that processes entities with a specific "
"component and verify it executes correctly")
{ {
struct Component struct Component
{ {
int value = 0; int value = 0;
}; };
@ -175,28 +178,26 @@ TEST_CASE("Create a simple system that processes entities with a specific compon
world w; world w;
auto e0 = w.make_entity(), e1 = w.make_entity(); auto e0 = w.make_entity(), e1 = w.make_entity();
w.set<Component>(e0); //or e0.set(Component{}) w.set<Component>(e0); // or e0.set(Component{})
w.set(e1, Component{20}); w.set(e1, Component{20});
REQUIRE(w.get<Component>(e0).value == 0); REQUIRE(w.get<Component>(e0).value == 0);
REQUIRE(w.get<Component>(e1).value == 20); REQUIRE(w.get<Component>(e1).value == 20);
/* /*
* Really wanna deduce it to w.query([](Component&){}), * Really wanna deduce it to w.query([](Component&){}),
* but I have some troubles with it * but I have some troubles with it
*/ */
w.query<Component>([](Component& c) w.query<Component>([](Component& c) { c.value++; });
{
c.value++;
});
REQUIRE(w.get<Component>(e0).value == 1); REQUIRE(w.get<Component>(e0).value == 1);
REQUIRE(w.get<Component>(e1).value == 21); REQUIRE(w.get<Component>(e1).value == 21);
} }
TEST_CASE("Test a systems ability to query and process only entities with a specific combination of components") TEST_CASE("Test a systems ability to query and process only entities with a "
"specific combination of components")
{ {
struct C0 struct C0
{ {
int value = 0; int value = 0;
}; };
@ -250,25 +251,19 @@ TEST_CASE("Systems execute at correct frequencies")
int slow_count = 0; int slow_count = 0;
// Add a fast system (60 Hz) // Add a fast system (60 Hz)
scheduler.add_system(60, [&](float dt) scheduler.add_system(60, [&](float dt) { fast_count++; });
{
fast_count++;
});
// Add a slow system (1 Hz) // Add a slow system (1 Hz)
scheduler.add_system(1, [&](float dt) scheduler.add_system(1, [&](float dt) { slow_count++; });
{
slow_count++;
});
// Simulate 2 seconds of updates at 120 FPS // Simulate 2 seconds of updates at 120 FPS
for (int i = 0; i < 240; ++i) for(int i = 0; i < 240; ++i)
{ {
scheduler.update(1.0f / 120.0f); scheduler.update(1.0f / 120.0f);
} }
// Verify counts // Verify counts
REQUIRE(fast_count == 120); // 60 Hz system should execute 60 times REQUIRE(fast_count == 120); // 60 Hz system should execute 60 times
REQUIRE(slow_count == 2); // 1 Hz system should execute 1 time REQUIRE(slow_count == 2); // 1 Hz system should execute 1 time
} }
@ -280,13 +275,10 @@ TEST_CASE("Systems handle zero-frequency gracefully")
int zero_count = 0; int zero_count = 0;
// Add a zero-frequency system (should never execute) // Add a zero-frequency system (should never execute)
scheduler.add_system(0, [&](float dt) scheduler.add_system(0, [&](float dt) { zero_count++; });
{
zero_count++;
});
// Simulate 1 second of updates at 60 FPS // Simulate 1 second of updates at 60 FPS
for (int i = 0; i < 60; ++i) for(int i = 0; i < 60; ++i)
{ {
scheduler.update(1.0f / 60.0f); scheduler.update(1.0f / 60.0f);
} }
@ -303,13 +295,10 @@ TEST_CASE("Systems handle varying update rates")
int varying_count = 0; int varying_count = 0;
// Add a system with varying frequency (10 Hz) // Add a system with varying frequency (10 Hz)
scheduler.add_system(10, [&](float dt) scheduler.add_system(10, [&](float dt) { varying_count++; });
{
varying_count++;
});
// Simulate 1 second of updates at 30 FPS // Simulate 1 second of updates at 30 FPS
for (int i = 0; i < 30; ++i) for(int i = 0; i < 30; ++i)
{ {
scheduler.update(1.0f / 30.0f); scheduler.update(1.0f / 30.0f);
} }
@ -326,10 +315,7 @@ TEST_CASE("Systems handle large time steps")
int large_step_count = 0; int large_step_count = 0;
// Add a system (1 Hz) // Add a system (1 Hz)
scheduler.add_system(1, [&](float dt) scheduler.add_system(1, [&](float dt) { large_step_count++; });
{
large_step_count++;
});
// Simulate a large time step (2 seconds) // Simulate a large time step (2 seconds)
scheduler.update(2.0f); scheduler.update(2.0f);
@ -353,7 +339,7 @@ TEST_CASE("Systems handle multiple frequencies")
scheduler.add_system(1, [&](float dt) { slow_count++; }); scheduler.add_system(1, [&](float dt) { slow_count++; });
// Simulate 1 second of updates at 120 FPS // Simulate 1 second of updates at 120 FPS
for (int i = 0; i < 120; ++i) for(int i = 0; i < 120; ++i)
{ {
scheduler.update(1.0f / 120.0f); scheduler.update(1.0f / 120.0f);
} }
@ -372,18 +358,16 @@ TEST_CASE("Systems handle fractional frequencies")
int fractional_count = 0; int fractional_count = 0;
// Add a system with fractional frequency (0.5 Hz) // Add a system with fractional frequency (0.5 Hz)
scheduler.add_system(0.5f, [&](float dt) scheduler.add_system(0.5f, [&](float dt) { fractional_count++; });
{
fractional_count++;
});
// Simulate 4 seconds of updates at 60 FPS // Simulate 4 seconds of updates at 60 FPS
for (int i = 0; i < 240; ++i) for(int i = 0; i < 240; ++i)
{ {
scheduler.update(1.0f / 60.0f); scheduler.update(1.0f / 60.0f);
} }
// Verify fractional-frequency system executes twice (0.5 Hz = 2 times in 4 seconds) // Verify fractional-frequency system executes twice (0.5 Hz = 2 times in 4
// seconds)
REQUIRE(fractional_count == 2); REQUIRE(fractional_count == 2);
} }
@ -395,10 +379,7 @@ TEST_CASE("Systems handle zero delta time")
int zero_dt_count = 0; int zero_dt_count = 0;
// Add a system (1 Hz) // Add a system (1 Hz)
scheduler.add_system(1, [&](float dt) scheduler.add_system(1, [&](float dt) { zero_dt_count++; });
{
zero_dt_count++;
});
// Simulate zero delta time // Simulate zero delta time
scheduler.update(0.0f); scheduler.update(0.0f);
@ -415,10 +396,7 @@ TEST_CASE("Systems handle negative delta time")
int count = 0; int count = 0;
// Add a system (1 Hz) // Add a system (1 Hz)
scheduler.add_system(1, [&](float dt) scheduler.add_system(1, [&](float dt) { count++; });
{
count++;
});
// Simulate negative delta time // Simulate negative delta time
scheduler.update(-1.0f); scheduler.update(-1.0f);

View file

@ -5,23 +5,22 @@
#include <format> #include <format>
#include <functional> #include <functional>
#include <queue> #include <queue>
#include <set>
#include <stdexcept> #include <stdexcept>
#include <typeindex> #include <typeindex>
#include <unordered_map> #include <unordered_map>
#include <unordered_set>
#include <set>
namespace zecsy namespace zecsy
{ {
using entity_id = uint64_t; using entity_id = uint64_t;
/* /*
* unordered_set is also an option. But probably sorting ids may be * unordered_set is also an option. But probably sorting ids may be
* beneficial for queries, because it might increase the chance of reusing * beneficial for queries, because it might increase the chance of reusing
* cpu cache (aka "required components were close to each other"). Definitely * cpu cache (aka "required components were close to each other").
* should play around with it * Definitely should play around with it
*/ */
using entities_set = std::set<entity_id>; using entities_set = std::set<entity_id>;
class component_storage final class component_storage final
{ {
@ -37,38 +36,40 @@ namespace zecsy
template<typename T> template<typename T>
void set(entity_id e); void set(entity_id e);
template<typename T> template<typename T>
void set(entity_id e, const T& comp); void set(entity_id e, const T& comp);
template<typename First, typename Second, typename... Rest> template<typename First, typename Second, typename... Rest>
void set(entity_id e); void set(entity_id e);
template<typename First, typename Second, typename... Rest> template<typename First, typename Second, typename... Rest>
void set(entity_id e, const First& comp0, const Second& comp1, void set(entity_id e, const First& comp0, const Second& comp1,
const Rest&... rest_comps); const Rest&... rest_comps);
template<typename T> template<typename T>
void remove(entity_id e); void remove(entity_id e);
template<typename First, typename Second, typename... Rest> template<typename First, typename Second, typename... Rest>
void remove(entity_id e); void remove(entity_id e);
private: private:
using comp_index = std::type_index; using comp_index = std::type_index;
using comp_to_entities_set = std::unordered_map<comp_index, entities_set>; using comp_to_entities_set =
std::unordered_map<comp_index, entities_set>;
using entity_to_index = std::unordered_map<entity_id, size_t>; using entity_to_index = std::unordered_map<entity_id, size_t>;
using comp_to_entity_dict = std::unordered_map<comp_index, using comp_to_entity_dict =
entity_to_index>; std::unordered_map<comp_index, entity_to_index>;
using comp_to_storage = std::unordered_map<comp_index,
std::vector<uint8_t>>;
using comp_to_reusable_ids = std::unordered_map<comp_index, using comp_to_storage =
std::queue<size_t>>; std::unordered_map<comp_index, std::vector<uint8_t>>;
using comp_to_reusable_ids =
std::unordered_map<comp_index, std::queue<size_t>>;
comp_to_entities_set entities_dict; comp_to_entities_set entities_dict;
comp_to_entity_dict indices_dict; comp_to_entity_dict indices_dict;
comp_to_storage storage_dict; comp_to_storage storage_dict;
comp_to_reusable_ids reusable_id_queues; comp_to_reusable_ids reusable_id_queues;
}; };
@ -80,9 +81,10 @@ namespace zecsy
void add_system(int freq, auto&& func); void add_system(int freq, auto&& func);
void update(float dt); void update(float dt);
private: private:
struct system_handler struct system_handler
{ {
double interval; double interval;
double accumulator = 0.0f; double accumulator = 0.0f;
@ -97,7 +99,7 @@ namespace zecsy
public: public:
entity_id make_entity(); entity_id make_entity();
void destroy_entity(entity_id e); void destroy_entity(entity_id e);
bool is_alive(entity_id e) const; bool is_alive(entity_id e) const;
template<typename... T> template<typename... T>
bool has(entity_id e) const; bool has(entity_id e) const;
@ -107,7 +109,7 @@ namespace zecsy
template<typename... T> template<typename... T>
void set(entity_id e); void set(entity_id e);
template<typename... T> template<typename... T>
void set(entity_id e, const T&... comps); void set(entity_id e, const T&... comps);
@ -116,6 +118,7 @@ namespace zecsy
template<typename... T> template<typename... T>
void query(auto&& system); void query(auto&& system);
private: private:
entities_set alive_entities; entities_set alive_entities;
entity_id entity_counter = 0; entity_id entity_counter = 0;
@ -155,12 +158,12 @@ namespace zecsy
{ {
if(!has<T>(e)) if(!has<T>(e))
{ {
throw std::runtime_error(std::format("Entity #{} doesn't have {}", throw std::runtime_error(
e, typeid(T).name())); std::format("Entity #{} doesn't have {}", e, typeid(T).name()));
} }
auto index = indices_dict[typeid(T)].at(e); auto index = indices_dict[typeid(T)].at(e);
auto* ptr = reinterpret_cast<T*>(&storage_dict[typeid(T)][0]); auto* ptr = reinterpret_cast<T*>(&storage_dict[typeid(T)][0]);
ptr += index; ptr += index;
@ -203,7 +206,7 @@ namespace zecsy
indices_dict[typeid(T)][e] = index; indices_dict[typeid(T)][e] = index;
} }
template<typename T> template<typename T>
inline void component_storage::set(entity_id e) inline void component_storage::set(entity_id e)
{ {
@ -252,7 +255,7 @@ namespace zecsy
{ {
return has<First>(e) && has<Second>(e) && (has<Rest>(e) && ...); return has<First>(e) && has<Second>(e) && (has<Rest>(e) && ...);
} }
template<typename First, typename Second, typename... Rest> template<typename First, typename Second, typename... Rest>
inline void component_storage::set(entity_id e) inline void component_storage::set(entity_id e)
{ {
@ -262,8 +265,9 @@ namespace zecsy
} }
template<typename First, typename Second, typename... Rest> template<typename First, typename Second, typename... Rest>
inline void component_storage::set(entity_id e, const First& comp0, const Second& comp1, inline void component_storage::set(entity_id e, const First& comp0,
const Rest&... rest_comps) const Second& comp1,
const Rest&... rest_comps)
{ {
set(e, comp0); set(e, comp0);
set(e, comp1); set(e, comp1);
@ -292,11 +296,8 @@ namespace zecsy
inline void system_scheduler::add_system(float freq, auto&& func) inline void system_scheduler::add_system(float freq, auto&& func)
{ {
systems.push_back({ systems.emplace_back(1.0f / freq, 0.0f,
1.0f / freq, std::forward<decltype(func)>(func));
0.0f,
std::forward<decltype(func)>(func)
});
} }
inline void system_scheduler::add_system(int freq, auto&& func) inline void system_scheduler::add_system(int freq, auto&& func)
@ -318,4 +319,4 @@ namespace zecsy
} }
} }
} }
}; }; // namespace zecsy