diff --git a/include/ecs.h b/include/ecs.h index 88fc0c1..2b09168 100644 --- a/include/ecs.h +++ b/include/ecs.h @@ -4,4 +4,5 @@ #include "./ecs/settings.h" #include "./ecs/signature_list.h" #include "./ecs/signature.h" +#include "./ecs/system_execution_adapter.h" #include "./ecs/tag.h" \ No newline at end of file diff --git a/include/ecs/config.h b/include/ecs/config.h index b464106..6aabb8a 100644 --- a/include/ecs/config.h +++ b/include/ecs/config.h @@ -65,6 +65,9 @@ struct type_helper #define beg_namespace_ecs_core_parallelism ecs_define_namespace_beg(beg_namespace_ecs_core_system, parallelism) #define end_namespace_ecs_core_parallelism ecs_define_namespace_end(end_namespace_ecs_core_system) +#define beg_namespace_ecs_core_system_scheduler ecs_define_namespace_beg(beg_namespace_ecs_core_system, scheduler) +#define end_namespace_ecs_core_system_scheduler ecs_define_namespace_end(end_namespace_ecs_core_system) + #define beg_namespace_ecs_core_system_storage ecs_define_namespace_beg(beg_namespace_ecs_core_system, storage) #define end_namespace_ecs_core_system_storage ecs_define_namespace_end(end_namespace_ecs_core_system) @@ -80,6 +83,9 @@ struct type_helper #define beg_namespace_ecs_settings_refresh_parallelism ecs_define_namespace_beg(beg_namespace_ecs_settings, refresh_parallelism) #define end_namespace_ecs_settings_refresh_parallelism ecs_define_namespace_end(end_namespace_ecs_settings) +#define beg_namespace_ecs_settings_scheduler ecs_define_namespace_beg(beg_namespace_ecs_settings, scheduler) +#define end_namespace_ecs_settings_scheduler ecs_define_namespace_end(end_namespace_ecs_settings) + #define beg_namespace_ecs_settings_system_storage ecs_define_namespace_beg(beg_namespace_ecs_settings, system_storage) #define end_namespace_ecs_settings_system_storage ecs_define_namespace_end(end_namespace_ecs_settings) @@ -110,6 +116,9 @@ struct type_helper #define beg_namespace_ecs_signature_list_system ecs_define_namespace_beg(beg_namespace_ecs_signature_list, system) #define end_namespace_ecs_signature_list_system ecs_define_namespace_end(end_namespace_ecs_signature_list) +#define beg_namespace_ecs_system_execution_adapter ecs_define_namespace_beg(beg_namespace_ecs, system_execution_adapter) +#define end_namespace_ecs_system_execution_adapter ecs_define_namespace_end(end_namespace_ecs) + #define beg_namespace_ecs_tag ecs_define_namespace_beg(beg_namespace_ecs, tag) #define end_namespace_ecs_tag ecs_define_namespace_end(end_namespace_ecs) diff --git a/include/ecs/context.h b/include/ecs/context.h index f4055ef..0356e14 100644 --- a/include/ecs/context.h +++ b/include/ecs/context.h @@ -1,3 +1,6 @@ #pragma once -#include "./context/context.h" \ No newline at end of file +#include "./context/base.h" +#include "./context/context.h" +#include "./context/defer_proxy.h" +#include "./context/step_proxy.h" \ No newline at end of file diff --git a/include/ecs/context/base.h b/include/ecs/context/base.h index 766a78b..07adb96 100644 --- a/include/ecs/context/base.h +++ b/include/ecs/context/base.h @@ -5,6 +5,12 @@ #include #include +#define ecs_context_proxy_func(base, name) \ + template \ + inline decltype(auto) name(T_args&&... args) \ + noexcept(noexcept(base::name(std::forward(args)...))) \ + { return base::name(std::forward(args)...); } + beg_namespace_ecs_context { @@ -22,6 +28,7 @@ beg_namespace_ecs_context using entity_storage_type = decltype((settings_type { }).entity_storage()(settings_type { }, hana::type_c)); using entity_handle_type = typename entity_storage_type::entity_handle_type; using system_storage_type = decltype((settings_type { }).system_storage()(settings_type { }, hana::type_c)); + using scheduler_type = decltype((settings_type { }).scheduler()(settings_type { })); public: using handle_type = entity_handle_type; @@ -33,6 +40,7 @@ beg_namespace_ecs_context component_manager_type _components; entity_storage_type _entities; system_storage_type _systems; + scheduler_type _scheduler; core::utils::thread_pool _thread_pool; @@ -42,21 +50,22 @@ beg_namespace_ecs_context public: inline base_t() : _components () - , _entities (settings_type { }.entity_storage()(settings_type { }, hana::type_c)) - , _systems (settings_type { }.system_storage()(settings_type { }, hana::type_c)) + , _entities ((settings_type { }).entity_storage()(settings_type { }, hana::type_c)) + , _systems ((settings_type { }).system_storage()(settings_type { }, hana::type_c)) + , _scheduler ((settings_type { }).scheduler()(settings_type { })) , _thread_pool (std::thread::hardware_concurrency() != 0 ? std::thread::hardware_concurrency() : 8 ) { } - public: /* misc */ + protected: /* misc */ template inline decltype(auto) post_in_thread_pool(T_func&& func) { return _thread_pool.post(std::forward(func)); } - public: /* entity */ + protected: /* entity */ template inline handle_type create_entity(T_args&&... args) { @@ -74,7 +83,7 @@ beg_namespace_ecs_context return _entities.is_valid(handle); } - public: /* component */ + protected: /* component */ template inline decltype(auto) add_component(const handle_type& handle, T_component_tag ct) { @@ -115,7 +124,13 @@ beg_namespace_ecs_context bitset.set_component(ct, false); } - public: /* systems */ + protected: /* systems */ + template + inline auto& system(T_system_tag st) + { + return _systems.instance_by_tag(st).system(); + } + template inline void for_systems_sequential(T_func&& func) { @@ -150,6 +165,28 @@ beg_namespace_ecs_context _(this)->for_systems_sequential(func); }); } + + private: + template + static constexpr decltype(auto) make_system_tag_list(T_system_tags&&... tags) noexcept + { + auto list = core::mp::list::make(std::forward(tags)...); + return hana::if_( + hana::equal(hana::size(list), hana::size_c<0>), + (settings_type { }).system_signatures().tags(), + list); + } + + protected: /* execute */ + template + inline decltype(auto) execute_systems(T_system_tags&&... sts) noexcept + { + auto tags = make_system_tag_list(std::forward(sts)...); + return [tags, this](auto&&... fns) { + auto os = hana::overload_linearly(std::forward(fns)...); + this->_scheduler.execute(*this, tags, os); + }; + } }; } diff --git a/include/ecs/context/context.h b/include/ecs/context/context.h index 2dd1fec..92ab991 100644 --- a/include/ecs/context/context.h +++ b/include/ecs/context/context.h @@ -3,7 +3,7 @@ #include #include -#include "./base.h" +#include "./step_proxy.h" beg_namespace_ecs_context { @@ -12,8 +12,12 @@ beg_namespace_ecs_context { template struct context_t - : public base_t + : public step_proxy_t { + private: + using settings_type = T_settings; + using step_proxy_type = step_proxy_t; + private: void refresh() { @@ -22,11 +26,13 @@ beg_namespace_ecs_context public: template - inline decltype(auto) step(T_step_func&& set_func) + inline decltype(auto) step(T_step_func&& step_func) { ecs_make_scope_guard([this]{ this->refresh(); }); + + std::forward(step_func)(static_cast(*this)); } }; diff --git a/include/ecs/context/defer_proxy.h b/include/ecs/context/defer_proxy.h new file mode 100644 index 0000000..c0d8f4c --- /dev/null +++ b/include/ecs/context/defer_proxy.h @@ -0,0 +1,36 @@ +#pragma once + +#include + +#include "./base.h" + +beg_namespace_ecs_context +{ + + namespace __impl + { + template + struct defer_proxy_t + : public base_t + { + private: + using base_type = base_t; + + public: /* entity */ + ecs_context_proxy_func(base_type, create_entity) + ecs_context_proxy_func(base_type, kill_entity) + ecs_context_proxy_func(base_type, is_alive) + + public: /* component */ + ecs_context_proxy_func(base_type, add_component) + ecs_context_proxy_func(base_type, has_component) + ecs_context_proxy_func(base_type, get_component) + ecs_context_proxy_func(base_type, remove_component) + + public: /* system */ + ecs_context_proxy_func(base_type, system) + }; + } + +} +end_namespace_ecs_context \ No newline at end of file diff --git a/include/ecs/context/step_proxy.h b/include/ecs/context/step_proxy.h new file mode 100644 index 0000000..8628f70 --- /dev/null +++ b/include/ecs/context/step_proxy.h @@ -0,0 +1,25 @@ +#pragma once + +#include + +#include "./defer_proxy.h" + +beg_namespace_ecs_context +{ + + namespace __impl + { + template + struct step_proxy_t + : public defer_proxy_t + { + private: + using base_type = defer_proxy_t; + + public: /* execute */ + ecs_context_proxy_func(base_type, execute_systems) + }; + } + +} +end_namespace_ecs_context \ No newline at end of file diff --git a/include/ecs/core/system.h b/include/ecs/core/system.h index 485d51a..4173afe 100644 --- a/include/ecs/core/system.h +++ b/include/ecs/core/system.h @@ -2,4 +2,5 @@ #include "./system/instance.h" #include "./system/parallelism.h" +#include "./system/scheduler.h" #include "./system/storage.h" \ No newline at end of file diff --git a/include/ecs/core/system/scheduler.h b/include/ecs/core/system/scheduler.h new file mode 100644 index 0000000..d2082ba --- /dev/null +++ b/include/ecs/core/system/scheduler.h @@ -0,0 +1,3 @@ +#pragma once + +#include "./scheduler/atomic_counter.h" \ No newline at end of file diff --git a/include/ecs/core/system/scheduler/atomic_counter.h b/include/ecs/core/system/scheduler/atomic_counter.h new file mode 100644 index 0000000..e346a13 --- /dev/null +++ b/include/ecs/core/system/scheduler/atomic_counter.h @@ -0,0 +1,21 @@ +#pragma once + +#include + +beg_namespace_ecs_core_system_scheduler +{ + + template + struct atomic_counter + { + public: + using settings_type = T_settings; + + public: + template + inline void execute(T_args&&...) + { } + }; + +} +end_namespace_ecs_core_system_scheduler \ No newline at end of file diff --git a/include/ecs/settings/scheduler.h b/include/ecs/settings/scheduler.h new file mode 100644 index 0000000..d2082ba --- /dev/null +++ b/include/ecs/settings/scheduler.h @@ -0,0 +1,3 @@ +#pragma once + +#include "./scheduler/atomic_counter.h" \ No newline at end of file diff --git a/include/ecs/settings/scheduler/atomic_counter.h b/include/ecs/settings/scheduler/atomic_counter.h new file mode 100644 index 0000000..422cb1c --- /dev/null +++ b/include/ecs/settings/scheduler/atomic_counter.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include + +beg_namespace_ecs_settings_scheduler +{ + + namespace __impl + { + struct atomic_counter_t + { + template + constexpr decltype(auto) operator()(T_settings) const noexcept + { return core::system::scheduler::atomic_counter { }; } + }; + } + + constexpr decltype(auto) atomic_counter = __impl::atomic_counter_t { }; + +} +end_namespace_ecs_settings_scheduler \ No newline at end of file diff --git a/include/ecs/settings/settings.h b/include/ecs/settings/settings.h index 2554a19..36ed8f0 100644 --- a/include/ecs/settings/settings.h +++ b/include/ecs/settings/settings.h @@ -7,6 +7,7 @@ #include "./system_storage.h" #include "./entity_storage.h" #include "./refresh_parallelism.h" +#include "./scheduler.h" beg_namespace_ecs_settings { @@ -18,6 +19,7 @@ beg_namespace_ecs_settings constexpr decltype(auto) system_storage = hana::size_c<2>; constexpr decltype(auto) entity_storage = hana::size_c<3>; constexpr decltype(auto) refresh_parallelism = hana::size_c<4>; + constexpr decltype(auto) scheduler = hana::size_c<5>; } namespace __impl @@ -53,6 +55,9 @@ beg_namespace_ecs_settings constexpr decltype(auto) refresh_parallelism() const noexcept { return get(keys::refresh_parallelism); } + constexpr decltype(auto) scheduler() const noexcept + { return get(keys::scheduler); } + public: /* setter */ template constexpr decltype(auto) component_signatures(T t) const noexcept @@ -73,6 +78,10 @@ beg_namespace_ecs_settings template constexpr decltype(auto) refresh_parallelism(T t) const noexcept { return change(keys::refresh_parallelism, t); } + + template + constexpr decltype(auto) scheduler(T t) const noexcept + { return change(keys::scheduler, t); } }; struct make_t @@ -85,7 +94,8 @@ beg_namespace_ecs_settings .add(keys::system_signatures, list::empty) .add(keys::system_storage, system_storage::tuple) .add(keys::entity_storage, entity_storage::dynamic<1024>) - .add(keys::refresh_parallelism, refresh_parallelism::enable); + .add(keys::refresh_parallelism, refresh_parallelism::enable) + .add(keys::scheduler, scheduler::atomic_counter); return settings_t> { }; } }; diff --git a/include/ecs/signature_list/system.h b/include/ecs/signature_list/system.h index 28b00e8..510eeed 100644 --- a/include/ecs/signature_list/system.h +++ b/include/ecs/signature_list/system.h @@ -20,6 +20,15 @@ beg_namespace_ecs_signature_list_system { return hana::size(items); } public: /* get */ + constexpr decltype(auto) tags() const noexcept + { + return hana::unpack( + hana::transform(items, [](auto& ssig){ + return core::mp::unwrap(ssig).tag(); + }), + core::mp::list::make); + } + template constexpr decltype(auto) get_by_tag(T_system_tag st) const noexcept { diff --git a/include/ecs/system_execution_adapter.h b/include/ecs/system_execution_adapter.h new file mode 100644 index 0000000..09fb579 --- /dev/null +++ b/include/ecs/system_execution_adapter.h @@ -0,0 +1,77 @@ +#pragma once + +#include + +beg_namespace_ecs_system_execution_adapter +{ + + namespace __impl + { + template + struct predicate_holder + { + private: + using predicate_type = T_predicate; + + template + using predicate_result_type = decltype( + std::declval()( + std::declval>().system())); + + template + using enabler = std::enable_if_t; + + public: + template + constexpr decltype(auto) detailed_instance(T_func&& func) noexcept + { + return [f = std::forward(func)](auto& instance, auto& executor) + -> enabler> + { + f(instance, executor); + }; + } + + template + constexpr decltype(auto) detailed(T_func&& func) noexcept + { + return detailed_instance([f = std::forward(func)](auto& instance, auto& executor) { + f(instance.system(), executor); + }); + } + + template + constexpr decltype(auto) for_subtasks(T_func&& func) noexcept + { + return detailed([f = std::forward(func)](auto& system, auto& executor){ + executor.for_subtasks([&system, &f](auto& data){ + f(system, data); + }); + }); + } + }; + } + + template + constexpr decltype(auto) matching(T_func) noexcept + { + return __impl::predicate_holder { }; + } + + constexpr decltype(auto) all() noexcept + { + return matching(hana::always(hana::true_c)); + } + + template + constexpr decltype(auto) tags(T_system_tags... tags) noexcept + { + auto tag_set = hana::make_set(tags...); + return matching([tag_set](auto& system) { + auto tag = tag::system::make(system); + return hana::contains(tag_set, tag); + }); + } + +} +end_namespace_ecs_system_execution_adapter \ No newline at end of file diff --git a/test/dummy.cpp b/test/dummy.cpp index 5fdbd84..8567a69 100644 --- a/test/dummy.cpp +++ b/test/dummy.cpp @@ -111,16 +111,21 @@ constexpr decltype(auto) settings = ::ecs::settings::make() .component_signatures(cs_list) .system_signatures (ss_list); +namespace sea = ::ecs::system_execution_adapter; + TEST(DummyTest, fuu) { - std::mutex m; auto context = ::ecs::context::make(settings); - context.for_systems_dispatch([&m](auto& instance){ - std::lock_guard l(m); - std::cout - << std::this_thread::get_id() - << " " - << type_helper::name() - << std::endl; + context.step([](auto& step_proxy){ + step_proxy.execute_systems()( + sea::tags(st::accelerate) + .for_subtasks([](auto& s, auto& data){ + std::cout << "accelerate" << std::endl; + }), + sea::tags(st::move) + .for_subtasks([](auto& s, auto& data){ + std::cout << "move" << std::endl; + }) + ); }); } \ No newline at end of file