* Removed namespace macros * Refactoring: split inline code in header and inline file * Continued implementation of system executionmaster
@@ -1,2 +1,3 @@ | |||
.vscode/ | |||
build/ | |||
build/ | |||
docu/ |
@@ -0,0 +1,3 @@ | |||
[submodule "cmake/modules"] | |||
path = cmake/modules | |||
url = b3rgmann@git.bergmann89.de:cpp/CmakeModules.git |
@@ -1,15 +1,22 @@ | |||
# Initialize CMake ################################################################################ | |||
CMake_Minimum_Required ( VERSION 3.5.1 FATAL_ERROR ) | |||
If ( NOT CMAKE_BUILD_TYPE ) | |||
Set ( CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build!" FORCE ) | |||
EndIf ( ) | |||
CMake_Minimum_Required ( VERSION 3.5.1 FATAL_ERROR ) | |||
Set ( CMAKE_CXX_STANDARD 17 ) | |||
Set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ) | |||
Include ( GlobalCompilerFlags OPTIONAL ) | |||
Set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} | |||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake" | |||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules" ) | |||
Include ( pedantic OPTIONAL ) | |||
Include ( cotire OPTIONAL ) | |||
Set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${PEDANTIC_C_FLAGS}" ) | |||
Set ( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${PEDANTIC_CXX_FLAGS}" ) | |||
# Tests ########################################################################################### | |||
Include ( CTest ) | |||
@@ -22,4 +29,11 @@ Find_Package ( Hana REQUIRED ) | |||
# Projects ######################################################################################## | |||
Add_SubDirectory ( ${CMAKE_CURRENT_SOURCE_DIR}/src ) | |||
Add_SubDirectory ( ${CMAKE_CURRENT_SOURCE_DIR}/test ) | |||
Add_SubDirectory ( ${CMAKE_CURRENT_SOURCE_DIR}/test ) | |||
# Documentation ################################################################################### | |||
Configure_File ( ${CMAKE_CURRENT_SOURCE_DIR}/doxygen | |||
${CMAKE_CURRENT_BINARY_DIR}/doxygen ) | |||
Add_Custom_Target ( docu | |||
doxygen ${CMAKE_CURRENT_BINARY_DIR}/doxygen ) |
@@ -1,52 +0,0 @@ | |||
Set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} \ | |||
-g \ | |||
-Wall \ | |||
-Wextra \ | |||
-Wconversion \ | |||
-Werror \ | |||
-Wno-unused-parameter \ | |||
-Wbad-function-cast \ | |||
-Wcast-align \ | |||
-Wcast-qual \ | |||
-Wconversion \ | |||
-Wdouble-promotion \ | |||
-Wfloat-equal \ | |||
-Wnested-externs \ | |||
-Wno-attributes \ | |||
-Wno-builtin-macro-redefined \ | |||
-Wno-vla \ | |||
-Wno-pragmas \ | |||
-Wold-style-definition \ | |||
-Woverlength-strings \ | |||
-Wshadow \ | |||
-Wwrite-strings") | |||
# -Wlogical-op | |||
# -Wno-aggressive-loop-optimizations | |||
# -Wtrampolines" | |||
Set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} \ | |||
-ftemplate-depth=2000 \ | |||
-g \ | |||
-Wall \ | |||
-Wextra \ | |||
-Wconversion \ | |||
-Werror \ | |||
-Wno-reorder \ | |||
-Wno-unused-parameter \ | |||
-Wcast-align \ | |||
-Wcast-qual \ | |||
-Wconversion \ | |||
-Wdouble-promotion \ | |||
-Wfloat-equal \ | |||
-Wno-attributes \ | |||
-Wno-builtin-macro-redefined \ | |||
-Wno-vla \ | |||
-Wno-pragmas \ | |||
-Woverlength-strings \ | |||
-Wshadow \ | |||
-Wwrite-strings") | |||
# -Wlogical-op | |||
# -Wtrampolines | |||
# -Wno-aggressive-loop-optimizations |
@@ -0,0 +1 @@ | |||
Subproject commit 9a495487c981774d0cb57478b855d58898c1505b |
@@ -1,6 +1,7 @@ | |||
#pragma once | |||
// TODO debug!!! | |||
#include <string> | |||
#include <cxxabi.h> | |||
template<typename T> | |||
@@ -18,116 +19,6 @@ struct type_helper | |||
#include <boost/hana.hpp> | |||
#include <boost/hana/ext/std/tuple.hpp> | |||
#define ecs_define_namespace_beg(parent, name) \ | |||
parent { \ | |||
namespace name | |||
#define ecs_define_namespace_end(parent) \ | |||
} \ | |||
parent | |||
#define beg_namespace_ecs namespace ecs | |||
#define end_namespace_ecs | |||
#define beg_namespace_ecs_context ecs_define_namespace_beg(beg_namespace_ecs, context) | |||
#define end_namespace_ecs_context ecs_define_namespace_end(end_namespace_ecs) | |||
#define beg_namespace_ecs_core ecs_define_namespace_beg(beg_namespace_ecs, core) | |||
#define end_namespace_ecs_core ecs_define_namespace_end(end_namespace_ecs) | |||
#define beg_namespace_ecs_core_component ecs_define_namespace_beg(beg_namespace_ecs_core, component) | |||
#define end_namespace_ecs_core_component ecs_define_namespace_end(end_namespace_ecs_core) | |||
#define beg_namespace_ecs_core_component_storage ecs_define_namespace_beg(beg_namespace_ecs_core_component, storage) | |||
#define end_namespace_ecs_core_component_storage ecs_define_namespace_end(end_namespace_ecs_core_component) | |||
#define beg_namespace_ecs_core_entity ecs_define_namespace_beg(beg_namespace_ecs_core, entity) | |||
#define end_namespace_ecs_core_entity ecs_define_namespace_end(end_namespace_ecs_core) | |||
#define beg_namespace_ecs_core_entity_storage ecs_define_namespace_beg(beg_namespace_ecs_core_entity, storage) | |||
#define end_namespace_ecs_core_entity_storage ecs_define_namespace_end(end_namespace_ecs_core_entity) | |||
#define beg_namespace_ecs_core_mp ecs_define_namespace_beg(beg_namespace_ecs_core, mp) | |||
#define end_namespace_ecs_core_mp ecs_define_namespace_end(end_namespace_ecs_core) | |||
#define beg_namespace_ecs_core_mp_list ecs_define_namespace_beg(beg_namespace_ecs_core_mp, list) | |||
#define end_namespace_ecs_core_mp_list ecs_define_namespace_end(end_namespace_ecs_core_mp) | |||
#define beg_namespace_ecs_core_mp_option_map ecs_define_namespace_beg(beg_namespace_ecs_core_mp, option_map) | |||
#define end_namespace_ecs_core_mp_option_map ecs_define_namespace_end(end_namespace_ecs_core_mp) | |||
#define beg_namespace_ecs_core_mp_tag ecs_define_namespace_beg(beg_namespace_ecs_core_mp, tag) | |||
#define end_namespace_ecs_core_mp_tag ecs_define_namespace_end(end_namespace_ecs_core_mp) | |||
#define beg_namespace_ecs_core_system ecs_define_namespace_beg(beg_namespace_ecs_core, system) | |||
#define end_namespace_ecs_core_system ecs_define_namespace_end(end_namespace_ecs_core) | |||
#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) | |||
#define beg_namespace_ecs_core_utils ecs_define_namespace_beg(beg_namespace_ecs_core, utils) | |||
#define end_namespace_ecs_core_utils ecs_define_namespace_end(end_namespace_ecs_core) | |||
#define beg_namespace_ecs_settings ecs_define_namespace_beg(beg_namespace_ecs, settings) | |||
#define end_namespace_ecs_settings ecs_define_namespace_end(end_namespace_ecs) | |||
#define beg_namespace_ecs_settings_entity_storage ecs_define_namespace_beg(beg_namespace_ecs_settings, entity_storage) | |||
#define end_namespace_ecs_settings_entity_storage ecs_define_namespace_end(end_namespace_ecs_settings) | |||
#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) | |||
#define beg_namespace_ecs_signature ecs_define_namespace_beg(beg_namespace_ecs, signature) | |||
#define end_namespace_ecs_signature ecs_define_namespace_end(end_namespace_ecs) | |||
#define beg_namespace_ecs_signature_component ecs_define_namespace_beg(beg_namespace_ecs_signature, component) | |||
#define end_namespace_ecs_signature_component ecs_define_namespace_end(end_namespace_ecs_signature) | |||
#define beg_namespace_ecs_signature_component_storage ecs_define_namespace_beg(beg_namespace_ecs_signature_component, storage) | |||
#define end_namespace_ecs_signature_component_storage ecs_define_namespace_end(end_namespace_ecs_signature_component) | |||
#define beg_namespace_ecs_signature_system ecs_define_namespace_beg(beg_namespace_ecs_signature, system) | |||
#define end_namespace_ecs_signature_system ecs_define_namespace_end(end_namespace_ecs_signature) | |||
#define beg_namespace_ecs_signature_system_output ecs_define_namespace_beg(beg_namespace_ecs_signature_system, output) | |||
#define end_namespace_ecs_signature_system_output ecs_define_namespace_end(end_namespace_ecs_signature_system) | |||
#define beg_namespace_ecs_signature_system_parallelism ecs_define_namespace_beg(beg_namespace_ecs_signature_system, parallelism) | |||
#define end_namespace_ecs_signature_system_parallelism ecs_define_namespace_end(end_namespace_ecs_signature_system) | |||
#define beg_namespace_ecs_signature_list ecs_define_namespace_beg(beg_namespace_ecs, signature_list) | |||
#define end_namespace_ecs_signature_list ecs_define_namespace_end(end_namespace_ecs) | |||
#define beg_namespace_ecs_signature_list_component ecs_define_namespace_beg(beg_namespace_ecs_signature_list, component) | |||
#define end_namespace_ecs_signature_list_component ecs_define_namespace_end(end_namespace_ecs_signature_list) | |||
#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) | |||
#define beg_namespace_ecs_tag_component ecs_define_namespace_beg(beg_namespace_ecs_tag, component) | |||
#define end_namespace_ecs_tag_component ecs_define_namespace_end(end_namespace_ecs_tag) | |||
#define beg_namespace_ecs_tag_system ecs_define_namespace_beg(beg_namespace_ecs_tag, system) | |||
#define end_namespace_ecs_tag_system ecs_define_namespace_end(end_namespace_ecs_tag) | |||
namespace ecs | |||
{ | |||
@@ -3,4 +3,6 @@ | |||
#include "./context/base.h" | |||
#include "./context/context.h" | |||
#include "./context/defer_proxy.h" | |||
#include "./context/step_proxy.h" | |||
#include "./context/step_proxy.h" | |||
#include "./context/base.inl" |
@@ -14,11 +14,17 @@ | |||
._##name(std::forward<T_args>(args)...))) \ | |||
{ return this->_##name(std::forward<T_args>(args)...); } | |||
beg_namespace_ecs_context | |||
{ | |||
namespace ecs { | |||
namespace context { | |||
namespace __impl | |||
namespace detail | |||
{ | |||
/** | |||
* the base ecs context implementation | |||
* | |||
* @tparam T_settings settings type the environment is configured with | |||
*/ | |||
template<typename T_settings> | |||
struct base_t | |||
{ | |||
@@ -28,8 +34,8 @@ beg_namespace_ecs_context | |||
protected: | |||
using context_type = ::ecs::context::type<settings_type>; | |||
using component_manager_type = core::component::manager<settings_type>; | |||
using chunk_meta_data_type = typename component_manager_type::chunk_meta_data_type; | |||
using entity_storage_type = decltype((settings_type { }).entity_storage()(settings_type { }, hana::type_c<chunk_meta_data_type>)); | |||
using storage_meta_data_type = typename component_manager_type::storage_meta_data_type; | |||
using entity_storage_type = decltype((settings_type { }).entity_storage()(settings_type { }, hana::type_c<storage_meta_data_type>)); | |||
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<entity_handle_type>)); | |||
using scheduler_type = decltype((settings_type { }).scheduler()(settings_type { }, std::declval<context_type&>())); | |||
@@ -41,179 +47,233 @@ beg_namespace_ecs_context | |||
using handle_vector_type = std::vector<handle_type>; | |||
protected: | |||
context_type& _context; | |||
context_type& _context; //!< reference to its own child class | |||
component_manager_type _components; | |||
entity_storage_type _entities; | |||
system_storage_type _systems; | |||
scheduler_type _scheduler; | |||
component_manager_type _components; //!< object to store and manage all components | |||
entity_storage_type _entities; //!< object to store and manage all entities | |||
system_storage_type _systems; //!< object to store and manage all systems | |||
scheduler_type _scheduler; //!< scheduler to execute the systems | |||
core::utils::thread_pool _thread_pool; | |||
core::utils::thread_pool _thread_pool; //!< thread pool to execute tasks parallel | |||
handle_vector_type _to_match; | |||
handle_vector_type _to_kill; | |||
handle_vector_type _to_match; //!< handles of entities that were created in the last tick | |||
handle_vector_type _to_kill; //!< handles of entities that were destroyed in the last tick | |||
public: | |||
inline base_t(context_type& p_context) | |||
: _context (p_context) | |||
, _components () | |||
, _entities ((settings_type { }).entity_storage()(settings_type { }, hana::type_c<chunk_meta_data_type>)) | |||
, _systems ((settings_type { }).system_storage()(settings_type { }, hana::type_c<entity_handle_type>)) | |||
, _scheduler ((settings_type { }).scheduler()(settings_type { }, p_context)) | |||
, _thread_pool (std::thread::hardware_concurrency() != 0 | |||
? std::thread::hardware_concurrency() | |||
: 8 ) | |||
{ } | |||
/** | |||
* constructor | |||
* | |||
* @param p_context reference to its own child class | |||
*/ | |||
inline base_t(context_type& p_context); | |||
protected: /* misc */ | |||
/** | |||
* execute the given function in the thread pool | |||
* | |||
* @tparam T_func type of the function to execute | |||
* | |||
* @param func function to execute | |||
*/ | |||
template<typename T_func> | |||
inline decltype(auto) _post_in_thread_pool(T_func&& func) | |||
{ | |||
return _thread_pool.post(std::forward<T_func>(func)); | |||
} | |||
inline void _post_in_thread_pool(T_func&& func); | |||
protected: /* entity */ | |||
/** | |||
* create a new entity | |||
* | |||
* @tparam T_args argument types to pass to the entity manager | |||
* | |||
* @param args arguments to pass to the entity manager | |||
* | |||
* @return handle of the created entity | |||
*/ | |||
template<typename... T_args> | |||
inline handle_type _create_entity(T_args&&... args) | |||
{ | |||
_to_match.emplace_back(_entities.claim(std::forward<T_args>(args)...)); | |||
return _to_match.back(); | |||
} | |||
inline void _kill_entity(const handle_type& handle) | |||
{ | |||
_to_kill.emplace_back(handle); | |||
} | |||
inline bool _is_alive(const handle_type& handle) const | |||
{ | |||
return _entities.is_valid(handle); | |||
} | |||
inline decltype(auto) _create_entity(T_args&&... args); | |||
/** | |||
* kill an entity | |||
* | |||
* @param handle handle of the entity to kill | |||
*/ | |||
inline void _kill_entity(const handle_type& handle); | |||
/** | |||
* check if an entity is alive | |||
* | |||
* @param handle handle of the entity to check | |||
* | |||
* @retval TRUE if the entity is alive | |||
* @retval FALSE if the entity is not alive | |||
*/ | |||
inline bool _is_alive(const handle_type& handle) const; | |||
protected: /* component */ | |||
/** | |||
* add a new component to an entity | |||
* | |||
* @tparam T_component_tag component tag type to add to the entity | |||
* | |||
* @param handle handle of the entity | |||
* @param ct tag of component to add | |||
* | |||
* @return reference to the created component | |||
*/ | |||
template<typename T_component_tag> | |||
inline decltype(auto) _add_component(const handle_type& handle, T_component_tag ct) | |||
{ | |||
_to_match.emplace_back(handle); | |||
auto& meta = _entities.meta_data(handle); | |||
auto& cmd = meta.chunk_meta_data(); | |||
auto& c = _components.add(ct, handle, cmd); | |||
auto& bitset = meta.bitset(); | |||
bitset.set_component(ct, true); | |||
return c; | |||
} | |||
inline decltype(auto) _add_component(const handle_type& handle, T_component_tag ct); | |||
/** | |||
* check if an entity has an specific component | |||
* | |||
* @tparam T_component_tag component tag type to check for | |||
* | |||
* @param handle handle of entity to check | |||
* @param ct component tag to check | |||
* | |||
* @retval TRUE if given entity has the requested component | |||
* @retval FALSE if the given entity does not have the requested component | |||
*/ | |||
template<typename T_component_tag> | |||
inline decltype(auto) _has_component(const handle_type& handle, T_component_tag ct) | |||
{ | |||
auto& meta = _entities.meta_data(handle); | |||
auto& bitset = meta.bitset(); | |||
return bitset.has_component(ct); | |||
} | |||
inline decltype(auto) _has_component(const handle_type& handle, T_component_tag ct); | |||
/** | |||
* get a reference to the requested component | |||
* | |||
* @tparam T_component_tag component tag type to get | |||
* | |||
* @param handle handle of the entity to get the component for | |||
* @param ct component tag to get the component for | |||
* | |||
* @return reference to the requested component | |||
*/ | |||
template<typename T_component_tag> | |||
inline decltype(auto) _get_component(const handle_type& handle, T_component_tag ct) | |||
{ | |||
auto& meta = _entities.meta_data(handle); | |||
auto& bitset = meta.bitset(); | |||
auto& cmd = meta.chunk_meta_data(); | |||
if (!bitset.has_component(ct)) | |||
throw std::invalid_argument("entity does not contain the requested compnent"); | |||
return _components.get(ct, handle, cmd); | |||
} | |||
inline decltype(auto) _get_component(const handle_type& handle, T_component_tag ct); | |||
/** | |||
* remove a component from an entity | |||
* | |||
* @tparam T_component_tag component tag type to remove | |||
* | |||
* @param handle handle of the entity to remove component at | |||
* @param ct component tag to remove component for | |||
*/ | |||
template<typename T_component_tag> | |||
inline decltype(auto) _remove_component(const handle_type& handle, T_component_tag ct) | |||
{ | |||
_to_match.emplace_back(handle); | |||
auto& meta = _entities.meta_data(handle); | |||
auto& bitset = meta.bitset(); | |||
bitset.set_component(ct, false); | |||
} | |||
inline void _remove_component(const handle_type& handle, T_component_tag ct); | |||
protected: /* systems */ | |||
/** | |||
* get the reference to a system instance by the system tag | |||
* | |||
* @tparam T_system_tag system tag type to get system instance for | |||
* | |||
* @param st system tag to get system instance for | |||
* | |||
* @return reference to the system instance | |||
*/ | |||
template<typename T_system_tag> | |||
inline auto& _instance_by_tag(T_system_tag st) | |||
{ | |||
return _systems.instance_by_tag(st); | |||
} | |||
inline auto& _instance_by_tag(T_system_tag st); | |||
/** | |||
* get the reference to a system instance by it's index | |||
* | |||
* @tparam T_index index type to get system instance for | |||
* | |||
* @param index index to get system instance for | |||
* | |||
* @return reference to the system instance | |||
*/ | |||
template<typename T_index> | |||
inline auto& _instance_by_index(T_index) | |||
{ | |||
return _systems.instance_by_index(T_index { }); | |||
} | |||
inline auto& _instance_by_index(T_index index); | |||
/** | |||
* get the reference of a system by the system tag | |||
* | |||
* @tparam T_system_tag system tag type to get system for | |||
* | |||
* @param st system tag to get system for | |||
* | |||
* @return reference to the system | |||
*/ | |||
template<typename T_system_tag> | |||
inline auto& _system_by_tag(T_system_tag st) | |||
{ | |||
return _systems.instance_by_tag(st).system(); | |||
} | |||
inline auto& _system_by_tag(T_system_tag st); | |||
/** | |||
* get the reference to a system by it's index | |||
* | |||
* @tparam T_index index type to get system for | |||
* | |||
* @param index index to get system for | |||
* | |||
* @return reference to the system | |||
*/ | |||
template<typename T_index> | |||
inline auto& _system_by_index(T_index) | |||
{ | |||
return _systems.instance_by_index(T_index { }).system(); | |||
} | |||
inline auto& _system_by_index(T_index index); | |||
/** | |||
* execute the given function for each system sequential | |||
* | |||
* @tparam T_func function type to execute for each system | |||
* | |||
* @param func function to execute for each system | |||
*/ | |||
template<typename T_func> | |||
inline void _for_systems_sequential(T_func&& func) | |||
{ | |||
_systems.for_each(std::forward<T_func>(func)); | |||
} | |||
inline void _for_systems_sequential(T_func&& func); | |||
/** | |||
* execute the given function for each system in parallel | |||
* | |||
* @tparam T_func function type to execute for each system | |||
* | |||
* @param func function to execute for each system | |||
*/ | |||
template<typename T_func> | |||
inline void _for_systems_parallel(T_func&& func) | |||
{ | |||
core::utils::counter_blocker counter(_systems.size()); | |||
counter.execute_and_wait_until_zero([this, &counter, func = std::forward<T_func>(func)]{ | |||
_systems.for_each([this, &counter, &func](auto& instance){ | |||
this->_post_in_thread_pool([&counter, &func, &instance]{ | |||
ecs_make_scope_guard([&counter](){ | |||
counter.decrement_and_notify_one(); | |||
}); | |||
func(instance); | |||
}); | |||
}); | |||
}); | |||
} | |||
inline void _for_systems_parallel(T_func&& func); | |||
/** | |||
* Execute function for each system, depending on the refresh_parallelism option of the settings object | |||
* it will be executed sequentially or in parallel. | |||
* | |||
* @tparam T_func function type to execute for each system | |||
* | |||
* @param func function to execute for each system | |||
*/ | |||
template<typename T_func> | |||
inline void _for_systems_dispatch(T_func&& func) | |||
{ | |||
hana::eval_if( | |||
(settings_type { }).refresh_parallelism(), | |||
[this, func=std::forward<T_func>(func)](auto _) { | |||
_(this)->_for_systems_parallel(func); | |||
}, | |||
[this, func=std::forward<T_func>(func)](auto _) { | |||
_(this)->_for_systems_sequential(func); | |||
}); | |||
} | |||
inline void _for_systems_dispatch(T_func&& func); | |||
protected: /* execute */ | |||
/** | |||
* run the scheduler for the passed system tags (if no tags are passed, all systems are executed) | |||
* | |||
* @tparam T_system_tags system tag types to execute scheduler for | |||
* | |||
* @param sts system tags to execute scheduler for | |||
* | |||
* @return functor to run system execution adapter with | |||
*/ | |||
template<typename... T_system_tags> | |||
inline decltype(auto) _execute_systems(T_system_tags&&... sts) noexcept | |||
{ | |||
auto tags = make_system_tag_list(std::forward<T_system_tags>(sts)...); | |||
return [tags, this](auto&&... fns) { | |||
auto os = hana::overload_linearly(std::forward<decltype(fns)>(fns)...); | |||
this->_scheduler.execute(tags, os); | |||
}; | |||
} | |||
inline decltype(auto) _execute_systems(T_system_tags&&... sts) noexcept; | |||
private: | |||
private: /* static */ | |||
/** | |||
* create a list of system tags from the passed tags (if no tag is passed all system tags are returned) | |||
* | |||
* @tparam T_system_tags system tag types to create list for | |||
* | |||
* @param tags system tags to create list for | |||
* | |||
* @return list of system tags | |||
*/ | |||
template<typename... T_system_tags> | |||
static constexpr decltype(auto) make_system_tag_list(T_system_tags&&... tags) noexcept | |||
{ | |||
auto list = core::mp::list::make(std::forward<T_system_tags>(tags)...); | |||
return hana::if_( | |||
hana::equal(hana::size(list), hana::size_c<0>), | |||
(settings_type { }).system_signatures().tags(), | |||
list); | |||
} | |||
static constexpr decltype(auto) make_system_tag_list(T_system_tags&&... tags) noexcept; | |||
}; | |||
} | |||
} | |||
end_namespace_ecs_context | |||
} } |
@@ -0,0 +1,210 @@ | |||
#pragma once | |||
#include <ecs/context/base.h> | |||
namespace ecs { | |||
namespace context { | |||
namespace detail { | |||
/* constructor */ | |||
template<typename T_settings> | |||
inline base_t<T_settings> | |||
::base_t(context_type& p_context) | |||
: _context (p_context) | |||
, _components () | |||
, _entities ((settings_type { }).entity_storage()(settings_type { }, hana::type_c<storage_meta_data_type>)) | |||
, _systems ((settings_type { }).system_storage()(settings_type { }, hana::type_c<entity_handle_type>)) | |||
, _scheduler ((settings_type { }).scheduler()(settings_type { }, p_context)) | |||
, _thread_pool (std::thread::hardware_concurrency() != 0 | |||
? std::thread::hardware_concurrency() | |||
: 8 ) | |||
{ } | |||
/* misc */ | |||
template<typename T_settings> | |||
template<typename T_func> | |||
inline void base_t<T_settings> | |||
::_post_in_thread_pool(T_func&& func) | |||
{ | |||
_thread_pool.post(std::forward<T_func>(func)); | |||
} | |||
/* entity */ | |||
template<typename T_settings> | |||
template<typename... T_args> | |||
inline decltype(auto) base_t<T_settings> | |||
::_create_entity(T_args&&... args) | |||
{ | |||
_to_match.emplace_back(_entities.claim(std::forward<T_args>(args)...)); | |||
return _to_match.back(); | |||
} | |||
template<typename T_settings> | |||
inline void base_t<T_settings> | |||
::_kill_entity(const handle_type& handle) | |||
{ | |||
_to_kill.emplace_back(handle); | |||
} | |||
template<typename T_settings> | |||
inline bool base_t<T_settings> | |||
::_is_alive(const handle_type& handle) const | |||
{ | |||
return _entities.is_valid(handle); | |||
} | |||
/* components */ | |||
template<typename T_settings> | |||
template<typename T_component_tag> | |||
inline decltype(auto) base_t<T_settings> | |||
::_add_component(const handle_type& handle, T_component_tag ct) | |||
{ | |||
_to_match.emplace_back(handle); | |||
auto& meta = _entities.meta_data(handle); | |||
auto& cmd = meta.storage_meta_data(); | |||
auto& c = _components.add(ct, handle, cmd); | |||
auto& bitset = meta.bitset(); | |||
bitset.set_component(ct, true); | |||
return c; | |||
} | |||
template<typename T_settings> | |||
template<typename T_component_tag> | |||
inline decltype(auto) base_t<T_settings> | |||
::_has_component(const handle_type& handle, T_component_tag ct) | |||
{ | |||
auto& meta = _entities.meta_data(handle); | |||
auto& bitset = meta.bitset(); | |||
return bitset.has_component(ct); | |||
} | |||
template<typename T_settings> | |||
template<typename T_component_tag> | |||
inline decltype(auto) base_t<T_settings> | |||
::_get_component(const handle_type& handle, T_component_tag ct) | |||
{ | |||
auto& meta = _entities.meta_data(handle); | |||
auto& bitset = meta.bitset(); | |||
auto& cmd = meta.storage_meta_data(); | |||
if (!bitset.has_component(ct)) | |||
throw std::invalid_argument("entity does not contain the requested compnent"); | |||
return _components.get(ct, handle, cmd); | |||
} | |||
template<typename T_settings> | |||
template<typename T_component_tag> | |||
inline void base_t<T_settings> | |||
::_remove_component(const handle_type& handle, T_component_tag ct) | |||
{ | |||
_to_match.emplace_back(handle); | |||
auto& meta = _entities.meta_data(handle); | |||
auto& bitset = meta.bitset(); | |||
bitset.set_component(ct, false); | |||
} | |||
/* systems */ | |||
template<typename T_settings> | |||
template<typename T_system_tag> | |||
inline auto& base_t<T_settings> | |||
::_instance_by_tag(T_system_tag st) | |||
{ | |||
return _systems.instance_by_tag(st); | |||
} | |||
template<typename T_settings> | |||
template<typename T_index> | |||
inline auto& base_t<T_settings> | |||
::_instance_by_index(T_index index) | |||
{ | |||
return _systems.instance_by_index(T_index { }); | |||
} | |||
template<typename T_settings> | |||
template<typename T_system_tag> | |||
inline auto& base_t<T_settings> | |||
::_system_by_tag(T_system_tag st) | |||
{ | |||
return _systems.instance_by_tag(st).system(); | |||
} | |||
template<typename T_settings> | |||
template<typename T_index> | |||
inline auto& base_t<T_settings> | |||
::_system_by_index(T_index) | |||
{ | |||
return _systems.instance_by_index(T_index { }).system(); | |||
} | |||
template<typename T_settings> | |||
template<typename T_func> | |||
inline void base_t<T_settings> | |||
::_for_systems_sequential(T_func&& func) | |||
{ | |||
_systems.for_each(std::forward<T_func>(func)); | |||
} | |||
template<typename T_settings> | |||
template<typename T_func> | |||
inline void base_t<T_settings> | |||
::_for_systems_parallel(T_func&& func) | |||
{ | |||
core::utils::counter_blocker counter(_systems.size()); | |||
counter.execute_and_wait_until_zero([this, &counter, func = std::forward<T_func>(func)]{ | |||
_systems.for_each([this, &counter, &func](auto& instance){ | |||
this->_post_in_thread_pool([&counter, &func, &instance]{ | |||
ecs_make_scope_guard([&counter](){ | |||
counter.decrement(); | |||
}); | |||
func(instance); | |||
}); | |||
}); | |||
}); | |||
} | |||
template<typename T_settings> | |||
template<typename T_func> | |||
inline void base_t<T_settings> | |||
::_for_systems_dispatch(T_func&& func) | |||
{ | |||
hana::eval_if( | |||
(settings_type { }).refresh_parallelism(), | |||
[this, func=std::forward<T_func>(func)](auto _) { | |||
_(this)->_for_systems_parallel(func); | |||
}, | |||
[this, func=std::forward<T_func>(func)](auto _) { | |||
_(this)->_for_systems_sequential(func); | |||
}); | |||
} | |||
template<typename T_settings> | |||
template<typename... T_system_tags> | |||
inline decltype(auto) base_t<T_settings> | |||
::_execute_systems(T_system_tags&&... sts) noexcept | |||
{ | |||
auto tags = make_system_tag_list(std::forward<T_system_tags>(sts)...); | |||
return [tags, this](auto&&... fns) { | |||
auto os = hana::overload_linearly(std::forward<decltype(fns)>(fns)...); | |||
this->_scheduler.execute(tags, os); | |||
}; | |||
} | |||
/* static */ | |||
template<typename T_settings> | |||
template<typename... T_system_tags> | |||
constexpr decltype(auto) base_t<T_settings> | |||
::make_system_tag_list(T_system_tags&&... tags) noexcept | |||
{ | |||
auto list = core::mp::list::make(std::forward<T_system_tags>(tags)...); | |||
return hana::if_( | |||
hana::equal(hana::size(list), hana::size_c<0>), | |||
(settings_type { }).system_signatures().tags(), | |||
list); | |||
} | |||
} } } |
@@ -2,17 +2,16 @@ | |||
#include <ecs/config.h> | |||
beg_namespace_ecs_context | |||
{ | |||
namespace ecs { | |||
namespace context { | |||
namespace __impl | |||
namespace detail | |||
{ | |||
template<typename T_settings> | |||
struct context_t; | |||
} | |||
template<typename T_settings> | |||
using type = __impl::context_t<T_settings>; | |||
using type = detail::context_t<T_settings>; | |||
} | |||
end_namespace_ecs_context | |||
} } |
@@ -6,10 +6,10 @@ | |||
#include "./context.fwd.h" | |||
#include "./step_proxy.h" | |||
beg_namespace_ecs_context | |||
{ | |||
namespace ecs { | |||
namespace context { | |||
namespace __impl | |||
namespace detail | |||
{ | |||
template<typename T_settings> | |||
struct context_t | |||
@@ -60,9 +60,8 @@ beg_namespace_ecs_context | |||
}; | |||
} | |||
constexpr decltype(auto) make = __impl::make_t { }; | |||
constexpr decltype(auto) make = detail::make_t { }; | |||
constexpr decltype(auto) make_uptr = __impl::make_uptr_t { }; | |||
constexpr decltype(auto) make_uptr = detail::make_uptr_t { }; | |||
} | |||
end_namespace_ecs_context | |||
} } |
@@ -4,11 +4,14 @@ | |||
#include "./base.h" | |||
beg_namespace_ecs_context | |||
{ | |||
namespace ecs { | |||
namespace context { | |||
namespace __impl | |||
namespace detail | |||
{ | |||
/** | |||
* proxy class to make entity, component and system management visible to users of the context | |||
*/ | |||
template<typename T_settings> | |||
struct defer_proxy_t | |||
: public base_t<T_settings> | |||
@@ -45,5 +48,4 @@ beg_namespace_ecs_context | |||
}; | |||
} | |||
} | |||
end_namespace_ecs_context | |||
} } |
@@ -4,11 +4,14 @@ | |||
#include "./defer_proxy.h" | |||
beg_namespace_ecs_context | |||
{ | |||
namespace ecs { | |||
namespace context { | |||
namespace __impl | |||
namespace detail | |||
{ | |||
/** | |||
* proxy class to make system execution visible to users of the context | |||
*/ | |||
template<typename T_settings> | |||
struct step_proxy_t | |||
: public defer_proxy_t<T_settings> | |||
@@ -31,5 +34,4 @@ beg_namespace_ecs_context | |||
}; | |||
} | |||
} | |||
end_namespace_ecs_context | |||
} } |
@@ -1,4 +1,6 @@ | |||
#pragma once | |||
#include "./component/manager.h" | |||
#include "./component/storage.h" | |||
#include "./component/storage.h" | |||
#include "./component/manager.inl" |
@@ -5,128 +5,189 @@ | |||
#include <ecs/core/mp/core/decay.h> | |||
#include <ecs/core/mp/core/wrap.h> | |||
beg_namespace_ecs_core_component | |||
{ | |||
namespace ecs { | |||
namespace core { | |||
namespace component { | |||
/* make_chunk_tuple */ | |||
/* make_storage_tuple */ | |||
namespace __impl | |||
namespace detail | |||
{ | |||
struct make_chunk_tuple_t | |||
/** | |||
* predicate type to make a tuple of the different component storages from the settings | |||
*/ | |||
struct make_storage_tuple_t | |||
{ | |||
/** | |||
* execute the predicate | |||
* | |||
* @tparam T_settings settings type | |||
* | |||
* @param settings settings to build tuple from | |||
* | |||
* @return tuple of component storages (@ref storage_iterface_t) | |||
*/ | |||
template<typename T_settings> | |||
constexpr decltype(auto) operator()(T_settings s) const noexcept | |||
{ | |||
auto cls = s.component_signatures(); | |||
return hana::unpack( | |||
hana::transform(cls.items, [s](auto x){ | |||
auto csig = mp::unwrap(x); | |||
return csig.storage()(s, csig.tags());; | |||
}), | |||
hana::make_tuple); | |||
} | |||
constexpr decltype(auto) operator()(T_settings settings) const noexcept; | |||
}; | |||
} | |||
constexpr decltype(auto) make_chunk_tuple = __impl::make_chunk_tuple_t { }; | |||
constexpr decltype(auto) make_storage_tuple = detail::make_storage_tuple_t { }; | |||
/* make_chunk_meta_data */ | |||
/* make_storage_meta_data */ | |||
namespace __impl | |||
namespace detail | |||
{ | |||
struct make_chunk_meta_data_t | |||
/** | |||
* predicate type to make a meta data object of a given storage | |||
*/ | |||
struct make_storage_meta_data_t | |||
{ | |||
template<typename T_chunk> | |||
constexpr decltype(auto) operator()(T_chunk&& chunk) const noexcept | |||
{ | |||
using chunk_type = mp::decay_t<decltype(chunk)>; | |||
using meta_data_type = typename chunk_type::meta_data_type; | |||
return meta_data_type { }; | |||
} | |||
/** | |||
* execute the predicate | |||
* | |||
* @tparam T_storage storage type to make the meta data object for | |||
* | |||
* @param storage storage to make the meta data object for | |||
* | |||
* @return meta data object for the given storage | |||
*/ | |||
template<typename T_storage> | |||
constexpr decltype(auto) operator()(T_storage&& storage) const noexcept; | |||
}; | |||
} | |||
constexpr decltype(auto) make_chunk_meta_data = __impl::make_chunk_meta_data_t { }; | |||
constexpr decltype(auto) make_storage_meta_data = detail::make_storage_meta_data_t { }; | |||
/* make_chunk_meta_data_tuple */ | |||
/* make_storage_meta_data_tuple */ | |||
namespace __impl | |||
namespace detail | |||
{ | |||
struct make_chunk_meta_data_tuple_t | |||
/** | |||
* predicate to create a tuple of meta data from the settings | |||
*/ | |||
struct make_storage_meta_data_tuple_t | |||
{ | |||
/** | |||
* execute the predicate | |||
* | |||
* @tparam T_settings settings type to create the meta data tuple for | |||
* | |||
* @param settings settings to create the meta data tuple for | |||
* | |||
* @return meta data tuple for the given settings | |||
*/ | |||
template<typename T_settings> | |||
constexpr decltype(auto) operator()(T_settings s) const noexcept | |||
{ | |||
using chunk_tuple_type = decltype(make_chunk_tuple(s)); | |||
using chunk_meta_data_tuple_type = decltype(hana::transform( | |||
std::declval<chunk_tuple_type>(), | |||
make_chunk_meta_data)); | |||
return chunk_meta_data_tuple_type { }; | |||
} | |||
constexpr decltype(auto) operator()(T_settings settings) const noexcept; | |||
}; | |||
} | |||
constexpr decltype(auto) make_chunk_meta_data_tuple = __impl::make_chunk_meta_data_tuple_t { }; | |||
constexpr decltype(auto) make_storage_meta_data_tuple = detail::make_storage_meta_data_tuple_t { }; | |||
/* chunk_contains_tag */ | |||
/* storage_contains_tag */ | |||
namespace __impl | |||
namespace detail | |||
{ | |||
/** | |||
* predicate type to check if the given storage contains the given component tag | |||
* | |||
* @tparam T_component_tag component tag type to check | |||
*/ | |||
template<typename T_component_tag> | |||
struct chunk_contains_tag_t | |||
struct storage_contains_tag_t | |||
{ | |||
template<typename T_chunk> | |||
constexpr decltype(auto) operator()(T_chunk&&) const noexcept | |||
{ | |||
using chunk_type = mp::decay_t<T_chunk>; | |||
using component_tag_list_type = typename chunk_type::component_tag_list_type; | |||
return hana::contains(component_tag_list_type { }, T_component_tag { }); | |||
} | |||
/** | |||
* execute the predicate | |||
* | |||
* @tparam T_storage storage type to check | |||
* | |||
* @param storage storage object to check | |||
* | |||
* @retval integral constant TRUE if the given component tag is managed by the given storage | |||
* @retval integral constant FALSE if the given component tag is not managed by the given storage | |||
*/ | |||
template<typename T_storage> | |||
constexpr decltype(auto) operator()(T_storage&& storage) const noexcept; | |||
}; | |||
} | |||
template<typename T_component_tag> | |||
constexpr decltype(auto) chunk_contains_tag = __impl::chunk_contains_tag_t<T_component_tag> { }; | |||
constexpr decltype(auto) storage_contains_tag = detail::storage_contains_tag_t<T_component_tag> { }; | |||
/* manager */ | |||
/** | |||
* component manager | |||
* | |||
* @tparam T_settings settings to build the component manager for | |||
*/ | |||
template<typename T_settings> | |||
struct manager | |||
{ | |||
public: | |||
using chunk_tuple_type = decltype(make_chunk_tuple(T_settings { })); | |||
using chunk_meta_data_type = decltype(make_chunk_meta_data_tuple(T_settings { })); | |||
/** tuple of the different storages */ | |||
using storage_tuple_type = decltype(make_storage_tuple(T_settings { })); | |||
/** tuple of the different storage meta data */ | |||
using storage_meta_data_type = decltype(make_storage_meta_data_tuple(T_settings { })); | |||
private: | |||
chunk_tuple_type _chunks; | |||
storage_tuple_type _storages; | |||
public: | |||
/** | |||
* get the storage index of the given component tag | |||
* | |||
* @tparam T_component_tag component tag type to get storage index for | |||
* | |||
* @param ct component tag to get storage index for | |||
* | |||
* @return integral constant of the storage index | |||
*/ | |||
template<typename T_component_tag> | |||
static constexpr decltype(auto) get_chunk_index(T_component_tag) noexcept | |||
{ | |||
using ret_type = decltype(mp::list::index_of_first_matching( | |||
std::declval<chunk_tuple_type>(), | |||
chunk_contains_tag<T_component_tag>)); | |||
return ret_type { }; | |||
} | |||
static constexpr decltype(auto) get_storage_index(T_component_tag ct) noexcept; | |||
/** | |||
* execute the given function for the storage that manages the given component tag | |||
* | |||
* @tparam T_self the component manager type | |||
* @tparam T_component_tag component tag type to execute function for | |||
* @tparam T_meta_data_tuple meta data tuple type to get meta data from | |||
* @tparam T_func function type to execute | |||
* | |||
* @param self the component manager | |||
* @param ct component tag to execute function for | |||
* @param mdt meta data tuple to get meta data from | |||
* @param func function to execute | |||
* | |||
* @return result of func | |||
*/ | |||
template< | |||
typename T_self, | |||
typename T_component_tag, | |||
typename T_meta_data_tuple, | |||
typename T_func> | |||
static constexpr decltype(auto) for_chunk_do( | |||
static constexpr decltype(auto) for_storage_do( | |||
T_self&& self, | |||
T_component_tag ct, | |||
T_meta_data_tuple&& mdt, | |||
T_func&& func) | |||
{ | |||
decltype(auto) index = get_chunk_index(ct); | |||
decltype(auto) chunk = std::forward<T_self>(self).get_chunk_by_index(index); | |||
decltype(auto) meta = hana::at(std::forward<T_meta_data_tuple>(mdt), index); | |||
return std::forward<T_func>(func)(chunk, meta); | |||
} | |||
T_func&& func) noexcept; | |||
/** | |||
* get the component for the given component tag | |||
* | |||
* @tparam T_self the component manager type | |||
* @tparam T_component_tag component tag type to execute function for | |||
* @tparam T_entity_handle entity handle type | |||
* @tparam T_meta_data_tuple meta data tuple type to get meta data from | |||
* | |||
* @param self the component manager | |||
* @param ct component tag to execute function for | |||
* qparam handle handle of the entity | |||
* @param mdt meta data tuple to get meta data from | |||
* | |||
* @return the requested component | |||
*/ | |||
template< | |||
typename T_self, | |||
typename T_component_tag, | |||
@@ -136,14 +197,23 @@ beg_namespace_ecs_core_component | |||
T_self&& self, | |||
T_component_tag ct, | |||
const T_entity_handle& handle, | |||
const T_meta_data_tuple& mdt) | |||
{ | |||
return for_chunk_do(std::forward<T_self>(self), ct, mdt, | |||
[ct, handle](auto& chunk, const auto& md) -> decltype(auto) { | |||
return chunk.get(ct, handle, md); | |||
}); | |||
} | |||
const T_meta_data_tuple& mdt) noexcept; | |||
/** | |||
* add a new component for the given component tag | |||
* | |||
* @tparam T_self the component manager type | |||
* @tparam T_component_tag component tag type to execute function for | |||
* @tparam T_entity_handle entity handle type | |||
* @tparam T_meta_data_tuple meta data tuple type to get meta data from | |||
* | |||
* @param self the component manager | |||
* @param ct component tag to execute function for | |||
* qparam handle handle of the entity | |||
* @param mdt meta data tuple to get meta data from | |||
* | |||
* @return the requested component | |||
*/ | |||
template< | |||
typename T_self, | |||
typename T_component_tag, | |||
@@ -153,44 +223,92 @@ beg_namespace_ecs_core_component | |||
T_self&& self, | |||
T_component_tag ct, | |||
const T_entity_handle& handle, | |||
const T_meta_data_tuple& mdt) | |||
{ | |||
return for_chunk_do(std::forward<T_self>(self), ct, mdt, | |||
[ct, handle](auto& chunk, const auto& md) -> decltype(auto) { | |||
return chunk.add(ct, handle, md); | |||
}); | |||
} | |||
const T_meta_data_tuple& mdt) noexcept; | |||
private: | |||
/** | |||
* get the component storage by index | |||
* | |||
* @tparam T_index index type to get component storage for | |||
* | |||
* @param index index to get component storage for | |||
* | |||
* @return component storage at the given index | |||
*/ | |||
template<typename T_index> | |||
constexpr decltype(auto) get_chunk_by_index(T_index index) noexcept | |||
{ | |||
return hana::at(_chunks, index); | |||
} | |||
constexpr decltype(auto) get_storage_by_index(T_index index) noexcept; | |||
/** | |||
* get the component storage by the component tag | |||
* | |||
* @tparam T_component_tag component tag type to get component storage for | |||
* | |||
* @param ct component tag to get component storage for | |||
* | |||
* @return component storage for the given tag | |||
*/ | |||
template<typename T_component_tag> | |||
constexpr decltype(auto) get_chunk_by_tag(T_component_tag ct) noexcept | |||
{ | |||
return hana::at(_chunks, get_chunk_index(ct)); | |||
} | |||
constexpr decltype(auto) get_storage_by_tag(T_component_tag ct) noexcept; | |||
public: | |||
manager() | |||
: _chunks(make_chunk_tuple(T_settings { })) | |||
{ } | |||
/** | |||
* constructor | |||
*/ | |||
inline manager(); | |||
/** | |||
* get a reference to the component for the given component tag | |||
* | |||
* @tparam T_args set of the following parameter types | |||
* T_component_tag component tag type to execute function for | |||
* T_entity_handle entity handle type | |||
* T_meta_data_tuple meta data tuple type to get meta data from | |||
* | |||
* @param args set of the following parameters | |||
* ct component tag to execute function for | |||
* handle handle of the entity | |||
* mdt meta data tuple to get meta data from | |||
* | |||
* @return the requested component | |||
*/ | |||
template<typename... T_args> | |||
inline auto& get(T_args&&... args) & noexcept | |||
{ return get_impl(*this, std::forward<T_args>(args)...); } | |||
inline auto& get(T_args&&... args) &; | |||
/** | |||
* get a read-only reference to the component for the given component tag | |||
* | |||
* @tparam T_args set of the following parameter types | |||
* T_component_tag component tag type to execute function for | |||
* T_entity_handle entity handle type | |||
* T_meta_data_tuple meta data tuple type to get meta data from | |||
* | |||
* @param args set of the following parameters | |||
* ct component tag to execute function for | |||
* handle handle of the entity | |||
* mdt meta data tuple to get meta data from | |||
* | |||
* @return the requested component | |||
*/ | |||
template<typename... T_args> | |||
inline auto& get(T_args&&... args) const & noexcept | |||
{ return get_impl(*this, std::forward<T_args>(args)...); } | |||
inline auto& get(T_args&&... args) const &; | |||
/** | |||
* add a new component for the given component tag | |||
* | |||
* @tparam T_args set of the following parameter types | |||
* T_component_tag component tag type to execute function for | |||
* T_entity_handle entity handle type | |||
* T_meta_data_tuple meta data tuple type to get meta data from | |||
* | |||
* @param args set of the following parameters | |||
* ct component tag to execute function for | |||
* handle handle of the entity | |||
* mdt meta data tuple to get meta data from | |||
* | |||
* @return the requested component | |||
*/ | |||
template<typename... T_args> | |||
inline auto& add(T_args&&... args) & noexcept | |||
{ return add_impl(*this, std::forward<T_args>(args)...); } | |||
inline auto& add(T_args&&... args) &; | |||
}; | |||
} | |||
end_namespace_ecs_core_component | |||
} } } |
@@ -0,0 +1,196 @@ | |||
#pragma once | |||
#include <ecs/config.h> | |||
#include <ecs/core/mp/list.h> | |||
#include <ecs/core/mp/core/decay.h> | |||
#include <ecs/core/mp/core/wrap.h> | |||
namespace ecs { | |||
namespace core { | |||
namespace component { | |||
namespace detail | |||
{ | |||
/* make_tuple_t */ | |||
struct make_tuple_t | |||
{ | |||
template<typename... T_args> | |||
constexpr decltype(auto) operator()(T_args&&... args) const | |||
{ return std::make_tuple(std::forward<T_args>(args)...); } | |||
}; | |||
/* make_storage_tuple_t */ | |||
template<typename T_settings> | |||
constexpr decltype(auto) make_storage_tuple_t | |||
::operator()(T_settings settings) const noexcept | |||
{ | |||
auto cls = settings.component_signatures(); | |||
return hana::unpack( | |||
hana::transform(cls.items, [settings](auto x){ | |||
auto csig = mp::unwrap(x); | |||
return csig.storage()(settings, csig.tags());; | |||
}), | |||
make_tuple_t { }); | |||
} | |||
/* make_storage_meta_data_t */ | |||
template<typename T_storage> | |||
constexpr decltype(auto) make_storage_meta_data_t | |||
::operator()(T_storage&& storage) const noexcept | |||
{ | |||
using storage_type = mp::decay_t<decltype(storage)>; | |||
using meta_data_type = typename storage_type::meta_data_type; | |||
return meta_data_type { }; | |||
} | |||
/* make_storage_meta_data_tuple_t */ | |||
template<typename T_settings> | |||
constexpr decltype(auto) make_storage_meta_data_tuple_t | |||
::operator()(T_settings settings) const noexcept | |||
{ | |||
using storage_tuple_type = decltype(make_storage_tuple(settings)); | |||
using storage_meta_data_tuple_type = decltype(hana::transform( | |||
std::declval<storage_tuple_type>(), | |||
make_storage_meta_data)); | |||
return storage_meta_data_tuple_type { }; | |||
} | |||
/* storage_contains_tag_t */ | |||
template<typename T_component_tag> | |||
template<typename T_storage> | |||
constexpr decltype(auto) storage_contains_tag_t<T_component_tag> | |||
::operator()(T_storage&& storage) const noexcept | |||
{ | |||
using storage_type = mp::decay_t<T_storage>; | |||
using component_tag_list_type = typename storage_type::component_tag_list_type; | |||
return hana::contains(component_tag_list_type { }, T_component_tag { }); | |||
} | |||
} | |||
/* manager */ | |||
template<typename T_settings> | |||
template<typename T_component_tag> | |||
constexpr decltype(auto) manager<T_settings> | |||
::get_storage_index(T_component_tag ct) noexcept | |||
{ | |||
using ret_type = decltype(mp::list::index_of_first_matching( | |||
std::declval<storage_tuple_type>(), | |||
storage_contains_tag<T_component_tag>)); | |||
return ret_type { }; | |||
} | |||
template< | |||
typename T_settings> | |||
template< | |||
typename T_self, | |||
typename T_component_tag, | |||
typename T_meta_data_tuple, | |||
typename T_func> | |||
constexpr decltype(auto) manager<T_settings> | |||
::for_storage_do( | |||
T_self&& self, | |||
T_component_tag ct, | |||
T_meta_data_tuple&& mdt, | |||
T_func&& func) noexcept | |||
{ | |||
decltype(auto) index = get_storage_index(ct); | |||
decltype(auto) storage = std::forward<T_self>(self).get_storage_by_index(index); | |||
decltype(auto) meta = hana::at(std::forward<T_meta_data_tuple>(mdt), index); | |||
return std::forward<T_func>(func)(storage, meta); | |||
} | |||
template< | |||
typename T_settings> | |||
template< | |||
typename T_self, | |||
typename T_component_tag, | |||
typename T_entity_handle, | |||
typename T_meta_data_tuple> | |||
constexpr decltype(auto) manager<T_settings> | |||
::get_impl( | |||
T_self&& self, | |||
T_component_tag ct, | |||
const T_entity_handle& handle, | |||
const T_meta_data_tuple& mdt) noexcept | |||
{ | |||
return for_storage_do(std::forward<T_self>(self), ct, mdt, | |||
[ct, handle](auto& storage, const auto& md) -> decltype(auto) { | |||
return storage.get(ct, handle, md); | |||
}); | |||
} | |||
template< | |||
typename T_settings> | |||
template< | |||
typename T_self, | |||
typename T_component_tag, | |||
typename T_entity_handle, | |||
typename T_meta_data_tuple> | |||
constexpr decltype(auto) manager<T_settings> | |||
::add_impl( | |||
T_self&& self, | |||
T_component_tag ct, | |||
const T_entity_handle& handle, | |||
const T_meta_data_tuple& mdt) noexcept | |||
{ | |||
return for_storage_do(std::forward<T_self>(self), ct, mdt, | |||
[ct, handle](auto& storage, const auto& md) -> decltype(auto) { | |||
return storage.add(ct, handle, md); | |||
}); | |||
} | |||
template<typename T_settings> | |||
template<typename T_index> | |||
constexpr decltype(auto) manager<T_settings> | |||
::get_storage_by_index(T_index index) noexcept | |||
{ | |||
return hana::at(_storages, index); | |||
} | |||
template<typename T_settings> | |||
template<typename T_component_tag> | |||
constexpr decltype(auto) manager<T_settings> | |||
::get_storage_by_tag(T_component_tag ct) noexcept | |||
{ | |||
return hana::at(_storages, get_storage_index(ct)); | |||
} | |||
template<typename T_settings> | |||
inline manager<T_settings> | |||
::manager() | |||
: _storages(make_storage_tuple(T_settings { })) | |||
{ } | |||
template<typename T_settings> | |||
template<typename... T_args> | |||
inline auto& manager<T_settings> | |||
::get(T_args&&... args) & | |||
{ | |||
return get_impl(*this, std::forward<T_args>(args)...); | |||
} | |||
template<typename T_settings> | |||
template<typename... T_args> | |||
inline auto& manager<T_settings> | |||
::get(T_args&&... args) const & | |||
{ | |||
return get_impl(*this, std::forward<T_args>(args)...); | |||
} | |||
template<typename T_settings> | |||
template<typename... T_args> | |||
inline auto& manager<T_settings> | |||
::add(T_args&&... args) & | |||
{ | |||
return add_impl(*this, std::forward<T_args>(args)...); | |||
} | |||
} } } |
@@ -3,4 +3,7 @@ | |||
#include "./storage/base.h" | |||
#include "./storage/dynamic.h" | |||
#include "./storage/empty.h" | |||
#include "./storage/fixed.h" | |||
#include "./storage/fixed.h" | |||
#include "./storage/interface.h" | |||
#include "./storage/base.inl" |
@@ -2,11 +2,21 @@ | |||
#include <ecs/config.h> | |||
beg_namespace_ecs_core_component_storage | |||
{ | |||
namespace ecs { | |||
namespace core { | |||
namespace component { | |||
namespace storage { | |||
struct empty_meta_data { }; | |||
/** | |||
* Base implementation of the component storage. | |||
* | |||
* Specializes @ref storage_iterface_t. | |||
* | |||
* @tparam T_container_builder internal container type | |||
* @tparam T_component_tag_list list of component tags that are managed by this storage | |||
*/ | |||
template<typename T_container_builder, typename T_component_tag_list> | |||
struct base | |||
{ | |||
@@ -23,40 +33,72 @@ beg_namespace_ecs_core_component_storage | |||
container_type _container; | |||
private: | |||
/** | |||
* get the compoent of the given tag from the storage | |||
* | |||
* @tparam T_self component storage type | |||
* @tparam T_component_tag component tag type | |||
* @tparam T_entity_handle entity handle type | |||
* | |||
* @param self component storage to get component from | |||
* @param ct component tag to get component for | |||
* @param handle handle of the entity to get the component for | |||
* @param meta meta data stored in the entity to get component for | |||
* | |||
* @return component for the given parameters | |||
*/ | |||
template<typename T_self, typename T_component_tag, typename T_entity_handle> | |||
static inline decltype(auto) get_impl( | |||
T_self&& self, | |||
T_component_tag ct, | |||
const T_entity_handle& handle, | |||
const meta_data_type& meta) noexcept | |||
{ | |||
using namespace ::ecs::core::mp; | |||
using component_type = unwrap_t<decay_t<decltype(ct)>>; | |||
decltype(auto) index = handle.index(); | |||
decltype(auto) data = std::forward<T_self>(self)._container.at(index); | |||
return std::get<component_type>(data); | |||
} | |||
const meta_data_type& meta); | |||
public: | |||
/** | |||
* get a writable reference to the requested component | |||
* | |||
* @tparam T_component_tag component tag type to get reference for | |||
* @tparam T_entity_handle entity handle type to get reference for | |||
* | |||
* @param ct component tag to get reference for | |||
* @param handle entity handle to get reference for | |||
* @param meta meta data for this storage class that is stored in the entity | |||
* | |||
* @return writable reference to the requested component | |||
*/ | |||
template<typename T_component_tag, typename... Xs> | |||
inline auto& get(T_component_tag ct, Xs&&... xs) & noexcept | |||
{ return get_impl(*this, ct, std::forward<Xs>(xs)...); } | |||
inline auto& get(T_component_tag ct, Xs&&... xs) &; | |||
/** | |||
* get a read-only reference to the requested component | |||
* | |||
* @tparam T_component_tag component tag type to get reference for | |||
* @tparam T_entity_handle entity handle type to get reference for | |||
* | |||
* @param ct component tag to get reference for | |||
* @param handle entity handle to get reference for | |||
* @param meta meta data for this storage class that is stored in the entity | |||
* | |||
* @return read-only reference to the requested component | |||
*/ | |||
template<typename T_component_tag, typename... Xs> | |||
inline const auto& get(T_component_tag ct, Xs&&... xs) const & noexcept | |||
{ return get_impl(*this, ct, std::forward<Xs>(xs)...); } | |||
inline const auto& get(T_component_tag ct, Xs&&... xs) const &; | |||
/** | |||
* add and initialize a new component to this storage | |||
* | |||
* @tparam T_component_tag component tag type to get reference for | |||
* @tparam T_entity_handle entity handle type to get reference for | |||
* | |||
* @param ct component tag to get reference for | |||
* @param handle entity handle to get reference for | |||
* @param meta meta data for this storage class that is stored in the entity | |||
* | |||
* @return writable reference to the requested component | |||
*/ | |||
template<typename T_component_tag, typename T_entity_handle> | |||
inline auto& add(T_component_tag ct, const T_entity_handle& handle, const meta_data_type& meta) | |||
{ | |||
auto index = handle.index(); | |||
if (_container.size() <= index) | |||
{ | |||
_container.resize(index + grow_size); | |||
} | |||
return get(ct, handle, meta); | |||
} | |||
inline auto& add(T_component_tag ct, const T_entity_handle& handle, const meta_data_type& meta); | |||
}; | |||
} | |||
end_namespace_ecs_core_component_storage | |||
} } } } |
@@ -0,0 +1,55 @@ | |||
#pragma once | |||
#include <ecs/core/component/storage/base.h> | |||
namespace ecs { | |||
namespace core { | |||
namespace component { | |||
namespace storage { | |||
template<typename T_container_builder, typename T_component_tag_list> | |||
template<typename T_self, typename T_component_tag, typename T_entity_handle> | |||
decltype(auto) base<T_container_builder, T_component_tag_list> | |||
::get_impl( | |||
T_self&& self, | |||
T_component_tag ct, | |||
const T_entity_handle& handle, | |||
const meta_data_type& meta) | |||
{ | |||
using namespace ::ecs::core::mp; | |||
using component_type = unwrap_t<decay_t<decltype(ct)>>; | |||
decltype(auto) index = handle.index(); | |||
decltype(auto) data = std::forward<T_self>(self)._container.at(index); | |||
return std::get<component_type>(data); | |||
} | |||
template<typename T_container_builder, typename T_component_tag_list> | |||
template<typename T_component_tag, typename... Xs> | |||
auto& base<T_container_builder, T_component_tag_list> | |||
::get(T_component_tag ct, Xs&&... xs) & | |||
{ | |||
return get_impl(*this, ct, std::forward<Xs>(xs)...); | |||
} | |||
template<typename T_container_builder, typename T_component_tag_list> | |||
template<typename T_component_tag, typename... Xs> | |||
const auto& base<T_container_builder, T_component_tag_list> | |||
::get(T_component_tag ct, Xs&&... xs) const & | |||
{ | |||
return get_impl(*this, ct, std::forward<Xs>(xs)...); | |||
} | |||
template<typename T_container_builder, typename T_component_tag_list> | |||
template<typename T_component_tag, typename T_entity_handle> | |||
auto& base<T_container_builder, T_component_tag_list> | |||
::add(T_component_tag ct, const T_entity_handle& handle, const meta_data_type& meta) | |||
{ | |||
auto index = handle.index(); | |||
if (_container.size() <= index) | |||
{ | |||
_container.resize(index + grow_size); | |||
} | |||
return get(ct, handle, meta); | |||
} | |||
} } } } |
@@ -4,8 +4,10 @@ | |||
#include "./base.h" | |||
beg_namespace_ecs_core_component_storage | |||
{ | |||
namespace ecs { | |||
namespace core { | |||
namespace component { | |||
namespace storage { | |||
struct vector_type_builder | |||
{ | |||
@@ -13,6 +15,13 @@ beg_namespace_ecs_core_component_storage | |||
using type = std::vector<T>; | |||
}; | |||
/** | |||
* Dynamic component storage. | |||
* | |||
* Specializes @ref storage_iterface_t. | |||
* | |||
* @tparam T_component_tag_list list of component tags that are managed by this storage | |||
*/ | |||
template<typename T_component_tag_list> | |||
struct dynamic | |||
: base<vector_type_builder, T_component_tag_list> | |||
@@ -26,5 +35,4 @@ beg_namespace_ecs_core_component_storage | |||
{ this->_container.resize(inital_size); } | |||
}; | |||
} | |||
end_namespace_ecs_core_component_storage | |||
} } } } |
@@ -2,9 +2,18 @@ | |||
#include <ecs/config.h> | |||
beg_namespace_ecs_core_component_storage | |||
{ | |||
namespace ecs { | |||
namespace core { | |||
namespace component { | |||
namespace storage { | |||
/** | |||
* Empty component storage. | |||
* | |||
* Specializes @ref storage_iterface_t. | |||
* | |||
* @tparam T_component_tag_list list of component tags that are managed by this storage | |||
*/ | |||
template<typename T_component_tag_list> | |||
struct empty | |||
{ | |||
@@ -20,5 +29,4 @@ beg_namespace_ecs_core_component_storage | |||
{ } | |||
}; | |||
} | |||
end_namespace_ecs_core_component_storage | |||
} } } } |
@@ -4,8 +4,10 @@ | |||
#include "./base.h" | |||
beg_namespace_ecs_core_component_storage | |||
{ | |||
namespace ecs { | |||
namespace core { | |||
namespace component { | |||
namespace storage { | |||
template<size_t T_size> | |||
struct array_type_builder | |||
@@ -13,13 +15,21 @@ beg_namespace_ecs_core_component_storage | |||
template<typename T> | |||
struct impl : public std::array<T, T_size> | |||
{ | |||
inline void resize(size_t) { } | |||
inline void resize(size_t) | |||
{ throw std::overflow_error("fixed component storage can not grow!"); } | |||
}; | |||
template<typename T> | |||
using type = impl<T>; | |||
}; | |||
/** | |||
* Fixed component storage. | |||
* | |||
* Specializes @ref storage_iterface_t. | |||
* | |||
* @tparam T_component_tag_list list of component tags that are managed by this storage | |||
*/ | |||
template<typename T_component_tag_list, size_t T_size> | |||
struct fixed | |||
: base<array_type_builder<T_size>, T_component_tag_list> | |||
@@ -30,5 +40,4 @@ beg_namespace_ecs_core_component_storage | |||
using typename base_type::meta_data_type; | |||
}; | |||
} | |||
end_namespace_ecs_core_component_storage | |||
} } } } |
@@ -0,0 +1,71 @@ | |||
#pragma once | |||
#include <ecs/config.h> | |||
namespace ecs { | |||
namespace core { | |||
namespace component { | |||
/** | |||
* type to store and manage components | |||
* | |||
* @tparam T_component_tag_list list of component tags to manage in this storage type | |||
*/ | |||
template<typename T_component_tag_list> | |||
struct storage_iterface_t | |||
{ | |||
struct dummy_meta_data { }; | |||
/** list of component tags managed by this storage class */ | |||
using component_tag_list_type = T_component_tag_list; | |||
/** meta data to store in the entity for this storage class */ | |||
using meta_data_type = dummy_meta_data; | |||
/** | |||
* get a writable reference to the requested component | |||
* | |||
* @tparam T_component_tag component tag type to get reference for | |||
* @tparam T_entity_handle entity handle type to get reference for | |||
* | |||
* @param ct component tag to get reference for | |||
* @param handle entity handle to get reference for | |||
* @param meta meta data for this storage class that is stored in the entity | |||
* | |||
* @return writable reference to the requested component | |||
*/ | |||
template<typename T_component_tag, typename T_entity_handle> | |||
inline auto& get(T_component_tag ct, const T_entity_handle& handle, const meta_data_type& meta) &; | |||
/** | |||
* get a read-only reference to the requested component | |||
* | |||
* @tparam T_component_tag component tag type to get reference for | |||
* @tparam T_entity_handle entity handle type to get reference for | |||
* | |||
* @param ct component tag to get reference for | |||
* @param handle entity handle to get reference for | |||
* @param meta meta data for this storage class that is stored in the entity | |||
* | |||
* @return read-only reference to the requested component | |||
*/ | |||
template<typename T_component_tag, typename T_entity_handle> | |||
inline const auto& get(T_component_tag ct, const T_entity_handle& handle, const meta_data_type& meta) const &; | |||
/** | |||
* add and initialize a new component to this storage | |||
* | |||
* @tparam T_component_tag component tag type to get reference for | |||
* @tparam T_entity_handle entity handle type to get reference for | |||
* | |||
* @param ct component tag to get reference for | |||
* @param handle entity handle to get reference for | |||
* @param meta meta data for this storage class that is stored in the entity | |||
* | |||
* @return writable reference to the requested component | |||
*/ | |||
template<typename T_component_tag, typename T_entity_handle> | |||
inline auto& add(T_component_tag ct, const T_entity_handle& handle, const meta_data_type& meta); | |||
}; | |||
} } } |
@@ -2,4 +2,7 @@ | |||
#include "./storage/base.h" | |||
#include "./storage/dynamic.h" | |||
#include "./storage/fixed.h" | |||
#include "./storage/fixed.h" | |||
#include "./storage/interface.h" | |||
#include "./storage/base.inl" |
@@ -4,9 +4,14 @@ | |||
#include <ecs/config.h> | |||
#include <ecs/core/utils/bitset.h> | |||
beg_namespace_ecs_core_entity_storage | |||
{ | |||
namespace ecs { | |||
namespace core { | |||
namespace entity { | |||
namespace storage { | |||
/** | |||
* struct to represent an entity handle | |||
*/ | |||
struct entity_handle | |||
{ | |||
private: | |||
@@ -14,58 +19,125 @@ beg_namespace_ecs_core_entity_storage | |||
uint32_t _counter; | |||
public: | |||
entity_handle(uint32_t i, uint32_t c) | |||
: _index (i) | |||
, _counter (c) | |||
{ } | |||
inline auto index() const | |||
{ return _index; } | |||
inline auto counter() const | |||
{ return _counter; } | |||
/** | |||
* constructor | |||
* | |||
* @param i index the entity is stored at | |||
* @param c counter to check the reusage of the entity | |||
*/ | |||
inline entity_handle(uint32_t i, uint32_t c); | |||
/** | |||
* get the index of the entity | |||
* | |||
* @return index of the entity | |||
*/ | |||
inline auto index() const; | |||
/** | |||
* get the counter of the entity | |||
* | |||
* @return counter of the entity | |||
*/ | |||
inline auto counter() const; | |||
/** | |||
* compare with other handle | |||
* | |||
* @param other handle to compare with | |||
* | |||
* @retval -1 if this is smaller than other | |||
* @retval 0 if this is equal to other | |||
* @retval -1 if this is larger than other | |||
*/ | |||
inline int compare(const entity_handle& other) const; | |||
/* compare operators */ | |||
inline bool operator <=(const entity_handle& other) const | |||
{ return compare(other) <= 0; } | |||
inline bool operator <(const entity_handle& other) const | |||
{ return compare(other) < 0; } | |||
inline bool operator ==(const entity_handle& other) const | |||
{ return compare(other) == 0; } | |||
inline bool operator !=(const entity_handle& other) const | |||
{ return compare(other) != 0; } | |||
inline bool operator >(const entity_handle& other) const | |||
{ return compare(other) > 0; } | |||
inline bool operator >=(const entity_handle& other) const | |||
{ return compare(other) >= 0; } | |||
}; | |||
template <typename T_settings, typename T_chunk_meta_data> | |||
/** | |||
* struct to manage the meta data for each entity | |||
* | |||
* @tparam T_settings settings type the environment is configured with | |||
* @tparam T_storage_meta_data meta data type of the component storagte container | |||
*/ | |||
template <typename T_settings, typename T_storage_meta_data> | |||
struct entity_meta_data | |||
: private T_storage_meta_data | |||
{ | |||
public: | |||
using bitset_type = utils::bitset<T_settings>; | |||
using chunk_meta_data_type = T_chunk_meta_data; | |||
using counter_type = uint32_t; | |||
using bitset_type = utils::bitset<T_settings>; | |||
using storage_meta_data_type = T_storage_meta_data; | |||
using counter_type = uint32_t; | |||
private: | |||
bitset_type _bitset; | |||
counter_type _counter; | |||
chunk_meta_data_type _chunk_meta_data; | |||
bitset_type _bitset; | |||
counter_type _counter; | |||
public: | |||
entity_meta_data() | |||
: _counter(0) | |||
{ } | |||
inline auto& bitset() | |||
{ return _bitset; } | |||
inline auto counter() const | |||
{ return _counter; } | |||
inline auto& chunk_meta_data() | |||
{ return _chunk_meta_data; } | |||
inline void reset() | |||
{ | |||
++_counter; | |||
_bitset.clear(); | |||
} | |||
/** | |||
* constructor | |||
*/ | |||
inline entity_meta_data(); | |||
/** | |||
* get the bitset of components stored for this entity | |||
* | |||
* @return component bitset | |||
*/ | |||
inline auto& bitset(); | |||
/** | |||
* get the current reusage counter of the entity | |||
* | |||
* @return current reusage counter of the entity | |||
*/ | |||
inline auto counter() const; | |||
/** | |||
* get the storage meta data for this entity | |||
* | |||
* @return storage meta data for this entity | |||
*/ | |||
inline auto& storage_meta_data(); | |||
/** | |||
* reset all meta data to their defaults | |||
*/ | |||
inline void reset(); | |||
}; | |||
template<typename T_container_builder, typename T_settings, typename T_chunk_meta_data> | |||
/** | |||
* basic entity storage container | |||
* | |||
* @tparam T_container_builder type to build the inner storage container | |||
* @tparam T_settings settings type the environemtn is configured with | |||
* @tparam T_storage_meta_data meta data type of the component storage | |||
*/ | |||
template<typename T_container_builder, typename T_settings, typename T_storage_meta_data> | |||
struct base | |||
{ | |||
public: | |||
using entity_handle_type = entity_handle; | |||
using entity_meta_data_type = entity_meta_data<T_settings, T_chunk_meta_data>; | |||
using entity_meta_data_type = entity_meta_data<T_settings, T_storage_meta_data>; | |||
private: | |||
using container_type = typename T_container_builder::template type<entity_meta_data_type>; | |||
@@ -78,65 +150,51 @@ beg_namespace_ecs_core_entity_storage | |||
queue_type _free_ids; | |||
private: | |||
inline void grow(size_t count) | |||
{ | |||
auto old_size = _container.size(); | |||
_container.resize(old_size + count); | |||
for (size_t i = old_size; i < _container.size(); ++i) | |||
{ | |||
_free_ids.emplace(i); | |||
} | |||
} | |||
/** | |||
* grow the container to the given size | |||
* | |||
* @param count new size of the container | |||
*/ | |||
inline void grow(size_t count); | |||
public: | |||
inline bool is_valid(const entity_handle& handle) const | |||
{ | |||
return handle.index() < _container.size() | |||
&& _container.at(handle.index()).counter() == handle.counter(); | |||
} | |||
inline decltype(auto) claim() | |||
{ | |||
if (_free_ids.empty()) | |||
{ | |||
grow(grow_size); | |||
} | |||
assert(!_free_ids.empty()); | |||
auto index = _free_ids.back(); | |||
auto& item = _container.at(index); | |||
_free_ids.pop(); | |||
return entity_handle(index, item.counter()); | |||
} | |||
inline void reclaim(const entity_handle& handle) | |||
{ | |||
if (!is_valid(handle)) | |||
throw std::invalid_argument("invalid entity handle"); | |||
auto index = handle.index(); | |||
auto& item = _container.at(index); | |||
item.reset(); | |||
_free_ids.emplace(index); | |||
} | |||
inline void clear() | |||
{ | |||
_free_ids = queue_type { }; | |||
for (size_t i = 0; i < _container.size(); ++i) | |||
{ | |||
_container.at(i).reset(); | |||
_free_ids.emplace(i); | |||
} | |||
} | |||
inline auto& meta_data(const entity_handle& handle) | |||
{ | |||
if (!is_valid(handle)) | |||
throw std::invalid_argument("invalid entity handle"); | |||
auto index = handle.index(); | |||
return _container.at(index); | |||
} | |||
/** | |||
* check if the given entity handle is valid | |||
* | |||
* @param handle handle to check | |||
* | |||
* @retval TRUE if handle is valid | |||
* @retval FALSE if handle is invalid | |||
*/ | |||
inline bool is_valid(const entity_handle& handle) const; | |||
/** | |||
* create a new entity inside the container | |||
* | |||
* @return handle of the new created entity | |||
*/ | |||
inline decltype(auto) claim(); | |||
/** | |||
* release an entiy handle | |||
* | |||
* @param handle entity handle to release | |||
*/ | |||
inline void reclaim(const entity_handle& handle); | |||
/** | |||
* remove all stored entities | |||
*/ | |||
inline void clear(); | |||
/** | |||
* get the meta data stored for the given handle | |||
* | |||
* @param handle entity handle to get meta data for | |||
* | |||
* @return meta data for the given entity handle | |||
*/ | |||
inline auto& meta_data(const entity_handle& handle); | |||
}; | |||
} | |||
end_namespace_ecs_core_entity_storage | |||
} } } } |
@@ -0,0 +1,172 @@ | |||
#pragma once | |||
#include <ecs/core/entity/storage/base.h> | |||
namespace ecs { | |||
namespace core { | |||
namespace entity { | |||
namespace storage { | |||
/* entity_handle */ | |||
inline entity_handle | |||
::entity_handle(uint32_t i, uint32_t c) | |||
: _index (i) | |||
, _counter (c) | |||
{ } | |||
inline auto entity_handle | |||
::index() const | |||
{ | |||
return _index; | |||
} | |||
inline auto entity_handle | |||
::counter() const | |||
{ | |||
return _counter; | |||
} | |||
inline int entity_handle | |||
::compare(const entity_handle& other) const | |||
{ | |||
if (_counter < other._counter) { | |||
return -1; | |||
} else if (_counter > other._counter) { | |||
return 1; | |||
} else if (_index < other._index) { | |||
return -1; | |||
} else if (_index > other._index) { | |||
return 1; | |||
} else { | |||
return 0; | |||
} | |||
} | |||
/* entity_meta_data */ | |||
template <typename T_settings, typename T_storage_meta_data> | |||
inline entity_meta_data<T_settings, T_storage_meta_data> | |||
::entity_meta_data() | |||
: _counter(0) | |||
{ } | |||
template <typename T_settings, typename T_storage_meta_data> | |||
inline auto& entity_meta_data<T_settings, T_storage_meta_data> | |||
::bitset() | |||
{ | |||
return _bitset; | |||
} | |||
template <typename T_settings, typename T_storage_meta_data> | |||
inline auto entity_meta_data<T_settings, T_storage_meta_data> | |||
::counter() const | |||
{ | |||
return _counter; | |||
} | |||
template <typename T_settings, typename T_storage_meta_data> | |||
inline auto& entity_meta_data<T_settings, T_storage_meta_data> | |||
::storage_meta_data() | |||
{ | |||
return *static_cast<storage_meta_data_type*>(this); | |||
} | |||
template <typename T_settings, typename T_storage_meta_data> | |||
inline void entity_meta_data<T_settings, T_storage_meta_data> | |||
::reset() | |||
{ | |||
++_counter; | |||
_bitset.clear(); | |||
} | |||
/* base */ | |||
template< | |||
typename T_container_builder, | |||
typename T_settings, | |||
typename T_storage_meta_data> | |||
inline void base<T_container_builder, T_settings, T_storage_meta_data> | |||
::grow(size_t count) | |||
{ | |||
auto old_size = _container.size(); | |||
_container.resize(old_size + count); | |||
for (size_t i = old_size; i < _container.size(); ++i) | |||
{ | |||
_free_ids.emplace(i); | |||
} | |||
} | |||
template< | |||
typename T_container_builder, | |||
typename T_settings, | |||
typename T_storage_meta_data> | |||
inline bool base<T_container_builder, T_settings, T_storage_meta_data> | |||
::is_valid(const entity_handle& handle) const | |||
{ | |||
return handle.index() < _container.size() | |||
&& _container.at(handle.index()).counter() == handle.counter(); | |||
} | |||
template< | |||
typename T_container_builder, | |||
typename T_settings, | |||
typename T_storage_meta_data> | |||
inline decltype(auto) base<T_container_builder, T_settings, T_storage_meta_data> | |||
::claim() | |||
{ | |||
if (_free_ids.empty()) | |||
{ | |||
grow(grow_size); | |||
} | |||
assert(!_free_ids.empty()); | |||
auto index = _free_ids.back(); | |||
auto& item = _container.at(index); | |||
_free_ids.pop(); | |||
return entity_handle(index, item.counter()); | |||
} | |||
template< | |||
typename T_container_builder, | |||
typename T_settings, | |||
typename T_storage_meta_data> | |||
inline void base<T_container_builder, T_settings, T_storage_meta_data> | |||
::reclaim(const entity_handle& handle) | |||
{ | |||
if (!is_valid(handle)) | |||
throw std::invalid_argument("invalid entity handle"); | |||
auto index = handle.index(); | |||
auto& item = _container.at(index); | |||
item.reset(); | |||
_free_ids.emplace(index); | |||
} | |||
template< | |||
typename T_container_builder, | |||
typename T_settings, | |||
typename T_storage_meta_data> | |||
inline void base<T_container_builder, T_settings, T_storage_meta_data> | |||
::clear() | |||
{ | |||
_free_ids = queue_type { }; | |||
for (size_t i = 0; i < _container.size(); ++i) | |||
{ | |||
_container.at(i).reset(); | |||
_free_ids.emplace(i); | |||
} | |||
} | |||
template< | |||
typename T_container_builder, | |||
typename T_settings, | |||
typename T_storage_meta_data> | |||
inline auto& base<T_container_builder, T_settings, T_storage_meta_data> | |||
::meta_data(const entity_handle& handle) | |||
{ | |||
if (!is_valid(handle)) | |||
throw std::invalid_argument("invalid entity handle"); | |||
auto index = handle.index(); | |||
return _container.at(index); | |||
} | |||
} } } } |
@@ -4,8 +4,10 @@ | |||
#include "./base.h" | |||
beg_namespace_ecs_core_entity_storage | |||
{ | |||
namespace ecs { | |||
namespace core { | |||
namespace entity { | |||
namespace storage { | |||
struct vector_type_builder | |||
{ | |||
@@ -13,12 +15,20 @@ beg_namespace_ecs_core_entity_storage | |||
using type = std::vector<T>; | |||
}; | |||
template<typename T_settings, typename T_chunk_meta_data> | |||
/** | |||
* Dynamic entity storage. | |||
* | |||
* Specializes @ref storage_iterface_t. | |||
* | |||
* @tparam T_settings settings type the environment is configured with | |||
* @tparam T_storage_meta_data storage meta data type to store within the entity meta data | |||
*/ | |||
template<typename T_settings, typename T_storage_meta_data> | |||
struct dynamic | |||
: base<vector_type_builder, T_settings, T_chunk_meta_data> | |||
: base<vector_type_builder, T_settings, T_storage_meta_data> | |||
{ | |||
public: | |||
using base_type = base<vector_type_builder, T_settings, T_chunk_meta_data>; | |||
using base_type = base<vector_type_builder, T_settings, T_storage_meta_data>; | |||
using typename base_type::entity_handle_type; | |||
using typename base_type::entity_meta_data_type; | |||
@@ -34,5 +44,4 @@ beg_namespace_ecs_core_entity_storage | |||
} | |||
}; | |||
} | |||
end_namespace_ecs_core_entity_storage | |||
} } } } |
@@ -4,8 +4,10 @@ | |||
#include "./base.h" | |||
beg_namespace_ecs_core_entity_storage | |||
{ | |||
namespace ecs { | |||
namespace core { | |||
namespace entity { | |||
namespace storage { | |||
template<size_t T_size> | |||
struct array_type_builder | |||
@@ -13,19 +15,28 @@ beg_namespace_ecs_core_entity_storage | |||
template<typename T> | |||
struct impl : public std::array<T, T_size> | |||
{ | |||
inline void resize(size_t) { } | |||
inline void resize(size_t) | |||
{ throw std::overflow_error("fixed entity storage can not grow!"); } | |||
}; | |||
template<typename T> | |||
using type = impl<T>; | |||
}; | |||
template<typename T_settings, typename T_chunk_meta_data, size_t T_size> | |||
/** | |||
* Fixed entity storage. | |||
* | |||
* Specializes @ref storage_iterface_t. | |||
* | |||
* @tparam T_settings settings type the environment is configured with | |||
* @tparam T_storage_meta_data storage meta data type to store within the entity meta data | |||
*/ | |||
template<typename T_settings, typename T_storage_meta_data, size_t T_size> | |||
struct fixed | |||
: base<array_type_builder<T_size>, T_settings, T_chunk_meta_data> | |||
: base<array_type_builder<T_size>, T_settings, T_storage_meta_data> | |||
{ | |||
public: | |||
using base_type = base<array_type_builder<T_size>, T_settings, T_chunk_meta_data>; | |||
using base_type = base<array_type_builder<T_size>, T_settings, T_storage_meta_data>; | |||
using typename base_type::entity_handle_type; | |||
using typename base_type::entity_meta_data_type; | |||
@@ -40,5 +51,4 @@ beg_namespace_ecs_core_entity_storage | |||
} | |||
}; | |||
} | |||
end_namespace_ecs_core_entity_storage | |||
} } } } |
@@ -0,0 +1,69 @@ | |||
#pragma once | |||
#include <ecs/config.h> | |||
namespace ecs { | |||
namespace core { | |||
namespace entity { | |||
namespace storage { | |||
/** | |||
* type to store and manage entities | |||
* | |||
* @tparam T_storage_meta_data meta data type of the component storage | |||
*/ | |||
template<typename T_container_builder, typename T_settings, typename T_storage_meta_data> | |||
struct storage_iterface_t | |||
{ | |||
public: | |||
/** | |||
* type of the entity handle to identify an entity | |||
*/ | |||
using entity_handle_type = int; | |||
/** | |||
* meta data type of the entity handle containing all relevant meta information stored for an entity | |||
*/ | |||
using entity_meta_data_type = T_storage_meta_data; | |||
public: | |||
/** | |||
* check if the given entity handle is valid | |||
* | |||
* @param handle handle to check | |||
* | |||
* @retval TRUE if handle is valid | |||
* @retval FALSE if handle is invalid | |||
*/ | |||
inline bool is_valid(const entity_handle& handle) const; | |||
/** | |||
* create a new entity inside the container | |||
* | |||
* @return handle of the new created entity | |||
*/ | |||
inline decltype(auto) claim(); | |||
/** | |||
* release an entiy handle | |||
* | |||
* @param handle entity handle to release | |||
*/ | |||
inline void reclaim(const entity_handle& handle); | |||
/** | |||
* remove all stored entities | |||
*/ | |||
inline void clear(); | |||
/** | |||
* get the meta data stored for the given handle | |||
* | |||
* @param handle entity handle to get meta data for | |||
* | |||
* @return meta data for the given entity handle | |||
*/ | |||
inline auto& meta_data(const entity_handle& handle); | |||
}; | |||
} } } } |
@@ -2,9 +2,16 @@ | |||
#include <ecs/config.h> | |||
beg_namespace_ecs_core_mp | |||
{ | |||
namespace ecs { | |||
namespace core { | |||
namespace mp { | |||
/** | |||
* type that copies the const qualifier from one type to another | |||
* | |||
* @tparam T type to copy qualifier to | |||
* @tparam T_source type to copy qualifier at | |||
*/ | |||
template <typename T, typename T_source> | |||
using copy_const_qualifier = | |||
std::conditional_t< | |||
@@ -12,6 +19,12 @@ beg_namespace_ecs_core_mp | |||
std::add_const_t<T>, | |||
T>; | |||
/** | |||
* type that copies the volatile qualifier from one type to another | |||
* | |||
* @tparam T type to copy qualifier to | |||
* @tparam T_source type to copy qualifier at | |||
*/ | |||
template <typename T, typename T_source> | |||
using copy_volatile_qualifier = | |||
std::conditional_t< | |||
@@ -19,11 +32,16 @@ beg_namespace_ecs_core_mp | |||
std::add_volatile_t<T>, | |||
T>; | |||
/** | |||
* type that copies the const volatile qualifier from one type to another | |||
* | |||
* @tparam T type to copy qualifier to | |||
* @tparam T_source type to copy qualifier at | |||
*/ | |||
template <typename T, typename T_source> | |||
using copy_cv_qualifiers = | |||
copy_const_qualifier< | |||
copy_volatile_qualifier<T, T_source>, | |||
T_source>; | |||
} | |||
end_namespace_ecs_core_mp | |||
} } } |
@@ -2,11 +2,14 @@ | |||
#include <ecs/config.h> | |||
beg_namespace_ecs_core_mp | |||
{ | |||
namespace ecs { | |||
namespace core { | |||
namespace mp { | |||
/** | |||
* remove all classifiers from a given type | |||
*/ | |||
template<typename T> | |||
using decay_t = typename hana::detail::decay<T>::type; | |||
} | |||
end_namespace_ecs_core_mp | |||
} } } |
@@ -3,22 +3,42 @@ | |||
#include <ecs/config.h> | |||
#include "./is_valid.h" | |||
beg_namespace_ecs_core_mp | |||
{ | |||
namespace ecs { | |||
namespace core { | |||
namespace mp { | |||
namespace __impl | |||
namespace detail | |||
{ | |||
template<template<typename...> class T_tag> | |||
/** | |||
* predicate type to check if each element of a list is a specialization of the given type | |||
* | |||
* @tparam T_check template type to check each element with | |||
*/ | |||
template<template<typename...> class T_check> | |||
struct is_list_t | |||
{ | |||
/** | |||
* execute the predicate | |||
* | |||
* @tparam T list type to check | |||
* | |||
* @param t list to check | |||
* | |||
* @retval integral constant TRUE if each element has passed the check | |||
* @retval integral constant TRUE if at least one element has not passed the check | |||
*/ | |||
template<typename T> | |||
constexpr decltype(auto) operator()(T&& t) const noexcept | |||
{ return hana::all_of(std::forward<T>(t), is_valid<T_tag>); } | |||
{ return hana::all_of(std::forward<T>(t), is_valid<T_check>); } | |||
}; | |||
} | |||
template<template<typename...> class T_tag> | |||
constexpr decltype(auto) is_list = __impl::is_list_t<T_tag> { }; | |||
/** | |||
* predicate type to check if the given parameter is a list of the given tag | |||
* | |||
* @tparam T_check check to execute for each element of the given list | |||
*/ | |||
template<template<typename...> class T_check> | |||
constexpr decltype(auto) is_list = detail::is_list_t<T_check> { }; | |||
} | |||
end_namespace_ecs_core_mp | |||
} } } |
@@ -2,9 +2,16 @@ | |||
#include <ecs/config.h> | |||
beg_namespace_ecs_core_mp | |||
{ | |||
namespace ecs { | |||
namespace core { | |||
namespace mp { | |||
/** | |||
* template to check if a given type T is a specialization of another template T_template | |||
* | |||
* @tparam T_template template definition to check for | |||
* @tparam T type to check | |||
*/ | |||
template<template<typename...> class T_template, typename T> | |||
struct is_specialization_of | |||
: public hana::false_ | |||
@@ -15,5 +22,4 @@ beg_namespace_ecs_core_mp | |||
: public hana::true_ | |||
{ }; | |||
} | |||
end_namespace_ecs_core_mp | |||
} } } |
@@ -4,25 +4,45 @@ | |||
#include "./is_specialization_of.h" | |||
#include "../list.h" | |||
beg_namespace_ecs_core_mp | |||
{ | |||
namespace ecs { | |||
namespace core { | |||
namespace mp { | |||
namespace __impl | |||
namespace detail | |||
{ | |||
template<template<typename...> class T_tag> | |||
/** | |||
* predicate type to check if the passed arguments are specializations of the given template | |||
* | |||
* @tparam T_check template to check for | |||
*/ | |||
template<template<typename...> class T_check> | |||
struct is_valid_t | |||
{ | |||
template<typename T> | |||
static constexpr decltype(auto) is_tag = mp::is_specialization_of<T_tag, T> { }; | |||
static constexpr decltype(auto) is_tag = mp::is_specialization_of<T_check, T> { }; | |||
template<typename... Xs> | |||
constexpr decltype(auto) operator()(Xs... xs) const noexcept | |||
{ return mp::list::all(is_tag<Xs>...); } | |||
/** | |||
* execute the predicate | |||
* | |||
* @tparam T_args argument types to check | |||
* | |||
* @param args arguments to check | |||
* | |||
* @retval integral constant TRUE if each element has passed the check | |||
* @retval integral constant TRUE if at least one element has not passed the check | |||
*/ | |||
template<typename... T_args> | |||
constexpr decltype(auto) operator()(T_args... args) const noexcept | |||
{ return mp::list::all(is_tag<T_args>...); } | |||
}; | |||
} | |||
/** | |||
* predicate to check if the passed arguments are specializations of the given template | |||
* | |||
* @tparam T_check template to check for | |||
*/ | |||
template<template<typename...> class T_tag> | |||
constexpr decltype(auto) is_valid = __impl::is_valid_t<T_tag> { }; | |||
constexpr decltype(auto) is_valid = detail::is_valid_t<T_tag> { }; | |||
} | |||
end_namespace_ecs_core_mp | |||
} } } |
@@ -2,35 +2,67 @@ | |||
#include <ecs/config.h> | |||
beg_namespace_ecs_core_mp | |||
{ | |||
namespace ecs { | |||
namespace core { | |||
namespace mp { | |||
/** | |||
* pack the given type in a boost::hana::type | |||
*/ | |||
template<typename T> | |||
using wrap_t = hana::type<T>; | |||
/** | |||
* unpack a given boost::hana::type | |||
**/ | |||
template<typename T> | |||
using unwrap_t = typename T::type; | |||
namespace __impl | |||
namespace detail | |||
{ | |||
/** | |||
* predicate type to wrap a given type into a boost::hana::type | |||
*/ | |||
struct wrap_t | |||
{ | |||
/** | |||
* execute the predicate | |||
* | |||
* @tparam T type to wrap | |||
* | |||
* @return object of the type wrapped in boost::hana::type | |||
*/ | |||
template<typename T> | |||
constexpr decltype(auto) operator()(T) const noexcept | |||
{ return mp::wrap_t<T> { }; } | |||
}; | |||
/** | |||
* predicate type to unwrap a given boost::hana::type | |||
*/ | |||
struct unwrap_t | |||
{ | |||
/** | |||
* execute the predicate | |||
* | |||
* @tparam T type to unwrap | |||
* | |||
* @return object of the unwrapped type | |||
*/ | |||
template<typename T> | |||
constexpr decltype(auto) operator()(T) const noexcept | |||
{ return mp::unwrap_t<T> { }; } | |||
}; | |||
} | |||
constexpr decltype(auto) wrap = __impl::wrap_t { }; | |||
/** | |||
* predicate to wrap a given type into a boost::hana::type | |||
*/ | |||
constexpr decltype(auto) wrap = detail::wrap_t { }; | |||
constexpr decltype(auto) unwrap = __impl::unwrap_t { }; | |||
/** | |||
* predicate to unwrap a given boost::hana::type | |||
*/ | |||
constexpr decltype(auto) unwrap = detail::unwrap_t { }; | |||
} | |||
end_namespace_ecs_core_mp | |||
} } } |
@@ -2,56 +2,99 @@ | |||
#include <ecs/config.h> | |||
beg_namespace_ecs_core_mp_list | |||
{ | |||
namespace ecs { | |||
namespace core { | |||
namespace mp { | |||
namespace list { | |||
/* base */ | |||
namespace __impl | |||
namespace detail | |||
{ | |||
/** | |||
* simple meta programming list implementation | |||
*/ | |||
template<typename... Xs> | |||
using list_t = hana::basic_tuple<Xs...>; | |||
} | |||
/** | |||
* wrapper to the list type | |||
*/ | |||
template<typename... Xs> | |||
using type = __impl::list_t<Xs...>; | |||
using type = detail::list_t<Xs...>; | |||
/** | |||
* create a list object | |||
*/ | |||
template<typename... Xs> | |||
constexpr decltype(auto) value = type<Xs...> { }; | |||
/** | |||
* empty list | |||
*/ | |||
constexpr decltype(auto) empty = value<>; | |||
/* make */ | |||
namespace __impl | |||
namespace detail | |||
{ | |||
/** | |||
* predicate type to create a list | |||
*/ | |||
struct make_t | |||
{ | |||
template<typename... Xs> | |||
constexpr decltype(auto) operator()(Xs...) const noexcept | |||
{ return value<Xs...>; } | |||
/** | |||
* execute the predicate | |||
* | |||
* @tparam T_args argument types to wrap into a list | |||
* | |||
* @return list that contains the given types | |||
*/ | |||
template<typename... T_args> | |||
constexpr decltype(auto) operator()(T_args...) const noexcept | |||
{ return value<T_args...>; } | |||
}; | |||
} | |||
constexpr decltype(auto) make = __impl::make_t { }; | |||
/** | |||
* predicate to create a list | |||
*/ | |||
constexpr decltype(auto) make = detail::make_t { }; | |||
/* all */ | |||
namespace __impl | |||
namespace detail | |||
{ | |||
/** | |||
* predicate type to check if all passed arguments are true-type or not | |||
*/ | |||
struct all_t | |||
{ | |||
template<typename... Xs> | |||
constexpr decltype(auto) operator()(Xs&&... xs) const noexcept | |||
{ return hana::all(hana::make_basic_tuple(std::forward<Xs>(xs)...)); } | |||
/** | |||
* execute the predicate | |||
* | |||
* @tparam T_args argument types to check | |||
* | |||
* @param args arguments to check | |||
* | |||
* @retval integral constant TRUE if each argument is the true-type | |||
* @retval integral constant TRUE if at least one argument is not the true-type | |||
*/ | |||
template<typename... T_args> | |||
constexpr decltype(auto) operator()(T_args&&... args) const noexcept | |||
{ return hana::all(hana::make_basic_tuple(std::forward<T_args>(args)...)); } | |||
}; | |||
} | |||
constexpr decltype(auto) all = __impl::all_t { }; | |||
/** | |||
* predicate to check if all passed arguments are true-type or not | |||
*/ | |||
constexpr decltype(auto) all = detail::all_t { }; | |||
/* unwrap */ | |||
namespace __impl | |||
namespace detail | |||
{ | |||
template<template<typename...> class T_outer, typename T_list> | |||
struct unwrap_t; | |||
@@ -61,15 +104,35 @@ beg_namespace_ecs_core_mp_list | |||
{ using type = T_outer<typename Ts::type...>; }; | |||
} | |||
/** | |||
* type to unwrap the types stored in a list | |||
* | |||
* @tparam T_outer container to store unwrapped types in | |||
* @tparam T_list list of wrapped types to unwrap | |||
*/ | |||
template<template<typename...> class T_outer, typename T_list> | |||
using unwrap_t = typename __impl::unwrap_t<T_outer, T_list>::type; | |||
using unwrap_t = typename detail::unwrap_t<T_outer, T_list>::type; | |||
/* index_of */ | |||
namespace __impl | |||
namespace detail | |||
{ | |||
/** | |||
* predicate type to get the index of a certain element inside a list | |||
*/ | |||
struct index_of_t | |||
{ | |||
/** | |||
* execute the predicate | |||
* | |||
* @tparam T_list list type to find the element in | |||
* @tparam T element type to get index for | |||
* | |||
* @param list list to find the element in | |||
* @param item element to get index for | |||
* | |||
* @return integral constant with the index of the searched element | |||
*/ | |||
template<typename T_list, typename T> | |||
constexpr decltype(auto) operator()(T_list list, T&& item) const noexcept | |||
{ | |||
@@ -82,14 +145,31 @@ beg_namespace_ecs_core_mp_list | |||
}; | |||
} | |||
constexpr decltype(auto) index_of = __impl::index_of_t { }; | |||
/** | |||
* predicate to get the index of a certain element inside a list | |||
*/ | |||
constexpr decltype(auto) index_of = detail::index_of_t { }; | |||
/* index_of_first_matching */ | |||
namespace __impl | |||
namespace detail | |||
{ | |||
/** | |||
* predicate type to get the index of an element of a list that first matches the given predicate | |||
*/ | |||
struct index_of_first_matching_t | |||
{ | |||
/** | |||
* execute the predicate | |||
* | |||
* @tparam T_list list type to search element in | |||
* @tparam T_func predicate type to execute for each element | |||
* | |||
* @param list list to search element in | |||
* @param func predicate to execute for each element | |||
* | |||
* @return integral constant of the index the element where found | |||
*/ | |||
template<typename T_list, typename T_func> | |||
constexpr decltype(auto) operator()(T_list list, T_func&& func) const noexcept | |||
{ | |||
@@ -102,7 +182,9 @@ beg_namespace_ecs_core_mp_list | |||
}; | |||
} | |||
constexpr decltype(auto) index_of_first_matching = __impl::index_of_first_matching_t { }; | |||
/** | |||
* predicate to get the index of an element of a list that first matches the given predicate | |||
*/ | |||
constexpr decltype(auto) index_of_first_matching = detail::index_of_first_matching_t { }; | |||
} | |||
end_namespace_ecs_core_mp_list | |||
} } } } |
@@ -3,11 +3,20 @@ | |||
#include <ecs/config.h> | |||
#include "./core/decay.h" | |||
beg_namespace_ecs_core_mp_option_map | |||
{ | |||
namespace ecs { | |||
namespace core { | |||
namespace mp { | |||
namespace option_map { | |||
namespace __impl | |||
namespace detail | |||
{ | |||
/** | |||
* Helper template to replace a given element of the options map. | |||
* Will forward the new pair if it was not set already. | |||
* | |||
* @tparam T_new_pair type of the new data pair | |||
*/ | |||
template<typename T_new_pair> | |||
struct replace_helper_t | |||
{ | |||
@@ -15,6 +24,15 @@ beg_namespace_ecs_core_mp_option_map | |||
const new_pair_type& new_pair; | |||
/** | |||
* execute the helper | |||
* | |||
* @tparam T_pair type of the existing pair | |||
* | |||
* @param pair existing pair | |||
* | |||
* @return The new pair if it is not already set, the old pair otherwise. | |||
*/ | |||
template<typename T_pair> | |||
constexpr decltype(auto) operator()(T_pair&& pair) const noexcept | |||
{ | |||
@@ -25,8 +43,22 @@ beg_namespace_ecs_core_mp_option_map | |||
} | |||
}; | |||
/** | |||
* predicate type to replace a certain pair of a list | |||
*/ | |||
struct replace_t | |||
{ | |||
/** | |||
* execute the predicate | |||
* | |||
* @tparam T_map type of the map to replace a pair in | |||
* @tparam T_new_pair type of the new pair | |||
* | |||
* @param map map to replace a pair in | |||
* @param new_pair pair to replace the old pair with | |||
* | |||
* @return updated map | |||
*/ | |||
template<typename T_map, typename T_new_pair> | |||
constexpr decltype(auto) operator()(T_map&& map, T_new_pair&& new_pair) const noexcept | |||
{ | |||
@@ -40,8 +72,14 @@ beg_namespace_ecs_core_mp_option_map | |||
} | |||
}; | |||
/** | |||
* predicate to replace a certain pair of a list | |||
*/ | |||
constexpr decltype(auto) replace = replace_t { }; | |||
/** | |||
* implements an option map to store key value pairs | |||
*/ | |||
template<typename T_map> | |||
struct option_map_t | |||
{ | |||
@@ -51,14 +89,43 @@ beg_namespace_ecs_core_mp_option_map | |||
map_type _map; | |||
public: | |||
/** | |||
* get the value for a certain key | |||
* | |||
* @tparam T_key key type to get value for | |||
* | |||
* @param key key to get value for | |||
* | |||
* @return value stored for the given key | |||
*/ | |||
template<typename T_key> | |||
constexpr decltype(auto) at(const T_key& key) const noexcept | |||
{ return hana::first(hana::at_key(_map, key)); } | |||
/** | |||
* get the value type for a certain key | |||
* | |||
* @tparam T_key key type to get value type for | |||
* | |||
* @param key key to get value type for | |||
* | |||
* @return value type stored for the given key | |||
*/ | |||
template<typename T_key> | |||
constexpr decltype(auto) type_at(const T_key& key) const noexcept | |||
{ return hana::type_c<decay_t<decltype(at(key))>>; } | |||
/** | |||
* add a new key to the map | |||
* | |||
* @tparam T_key key type to add | |||
* @tparam T_value value type of the initial value | |||
* | |||
* @param key key to add | |||
* @param value initial value | |||
* | |||
* @return the updated option map | |||
*/ | |||
template<typename T_key, typename T_value> | |||
constexpr decltype(auto) add(const T_key& key, T_value&& value) const noexcept | |||
{ | |||
@@ -72,6 +139,17 @@ beg_namespace_ecs_core_mp_option_map | |||
return option_map_t<decltype(new_map)> { }; | |||
} | |||
/** | |||
* set the value of a certain key (values can only be set once!) | |||
* | |||
* @tparam T_key type of the key to set value for | |||
* @tparam T_value type of the value to set | |||
* | |||
* @param key key to set value for | |||
* @param value value to set | |||
* | |||
* @return the updated option map | |||
*/ | |||
template<typename T_key, typename T_value> | |||
constexpr decltype(auto) set(const T_key& key, T_value&& value) const noexcept | |||
{ | |||
@@ -89,14 +167,24 @@ beg_namespace_ecs_core_mp_option_map | |||
} | |||
}; | |||
/** | |||
* predicate type to create a empty option map | |||
*/ | |||
struct make_t | |||
{ | |||
/** | |||
* execute the predicate | |||
* | |||
* @return empty option map | |||
*/ | |||
constexpr decltype(auto) operator()() const noexcept | |||
{ return option_map_t<decay_t<decltype(hana::make_map())>> { }; } | |||
}; | |||
} | |||
constexpr decltype(auto) make = __impl::make_t { }; | |||
/** | |||
* predicate to create a empty option map | |||
*/ | |||
constexpr decltype(auto) make = detail::make_t { }; | |||
} | |||
end_namespace_ecs_core_mp_option_map | |||
} } } } |
@@ -3,22 +3,40 @@ | |||
#include <ecs/config.h> | |||
#include "./core/decay.h" | |||
beg_namespace_ecs_core_mp_tag | |||
{ | |||
namespace ecs { | |||
namespace core { | |||
namespace mp { | |||
namespace tag { | |||
namespace __impl | |||
namespace detail | |||
{ | |||
/** | |||
* predicate type to create a tag of a given type | |||
* | |||
* @tparam T_tag tag to create | |||
*/ | |||
template<template<typename> class T_tag> | |||
struct make_t | |||
{ | |||
template<typename T_component> | |||
constexpr decltype(auto) operator()(T_component&&) const noexcept | |||
{ return T_tag<core::mp::decay_t<T_component>> { }; } | |||
/** | |||
* execute the predicate | |||
* | |||
* @tparam T type to create tag for | |||
* | |||
* @return tag of the given type | |||
*/ | |||
template<typename T> | |||
constexpr decltype(auto) operator()(T&&) const noexcept | |||
{ return T_tag<core::mp::decay_t<T>> { }; } | |||
}; | |||
} | |||
/** | |||
* predicate to create a tag of a given type | |||
* | |||
* @tparam T_tag tag to create | |||
*/ | |||
template<template<typename> class T_tag> | |||
constexpr decltype(auto) make = __impl::make_t<T_tag> { }; | |||
constexpr decltype(auto) make = detail::make_t<T_tag> { }; | |||
} | |||
end_namespace_ecs_core_mp_tag | |||
} } } } |
@@ -1,5 +1,6 @@ | |||
#pragma once | |||
#include "./system/data_proxy.h" | |||
#include "./system/instance.h" | |||
#include "./system/parallelism.h" | |||
#include "./system/scheduler.h" |
@@ -0,0 +1,7 @@ | |||
#pragma once | |||
#include "./data_proxy/base.h" | |||
#include "./data_proxy/single.h" | |||
#include "./data_proxy/base.inl" | |||
#include "./data_proxy/single.inl" |
@@ -0,0 +1,54 @@ | |||
#pragma once | |||
#include <ecs/config.h> | |||
namespace ecs { | |||
namespace core { | |||
namespace system { | |||
namespace data_proxy { | |||
/** | |||
* base class for the data proxies | |||
* | |||
* @tparam T_context context type of the ECS environment | |||
* @tparam T_instance system instance type | |||
*/ | |||
template<typename T_context, typename T_instance> | |||
struct base | |||
{ | |||
protected: | |||
using context_type = T_context; | |||
using instance_type = T_instance; | |||
using system_signature_type = typename instance_type::system_signature_type; | |||
using handle_type = typename context_type::handle_type; | |||
protected: | |||
context_type& context; | |||
instance_type& instance; | |||
public: | |||
/** | |||
* constructor | |||
* | |||
* @param context context of the ECS environment | |||
* @param instance system instance | |||
*/ | |||
inline base(context_type& p_context, instance_type& p_instance); | |||
/** | |||
* get a reference to the requested component | |||
* | |||
* @tparam T_component_tag component tag type to get | |||
* | |||
* @param ct component tag to get the component for | |||
* @param handle handle of the entity to get the component for | |||
* | |||
* @return reference to the requested component | |||
*/ | |||
template<typename T_component_tag> | |||
inline decltype(auto) get_component(T_component_tag ct, const handle_type& handle); | |||
}; | |||
} } } } |
@@ -0,0 +1,39 @@ | |||
#pragma once | |||
#include <ecs/core/system/data_proxy/base.h> | |||
namespace ecs { | |||
namespace core { | |||
namespace system { | |||
namespace data_proxy { | |||
template<typename T_context, typename T_instance> | |||
inline base<T_context, T_instance> | |||
::base(T_context& p_context, T_instance& p_instance) | |||
: context (p_context) | |||
, instance (p_instance) | |||
{ } | |||
template<typename T_context, typename T_instance> | |||
template<typename T_component_tag> | |||
inline decltype(auto) base<T_context, T_instance> | |||
::get_component(T_component_tag ct, const handle_type& handle) | |||
{ | |||
using component_tag_type = T_component_tag; | |||
constexpr auto can_write = mp::unwrap(system_signature_type { }).can_write(component_tag_type { }); | |||
constexpr auto can_read = mp::unwrap(system_signature_type { }).can_read(component_tag_type { }); | |||
static_assert(can_write || can_read, "access to this component is denied for this system!"); | |||
return hana::eval_if( | |||
can_write, | |||
[this, &handle](auto _) -> auto& { | |||
return _(context).get_component(handle, component_tag_type { }); | |||
}, | |||
[this, &handle](auto _) -> const auto& { | |||
return _(context).get_component(handle, component_tag_type { }); | |||
}); | |||
} | |||
} } } } |
@@ -0,0 +1,95 @@ | |||
#pragma once | |||
#include <ecs/config.h> | |||
#include <ecs/core/system/data_proxy/base.h> | |||
namespace ecs { | |||
namespace core { | |||
namespace system { | |||
namespace data_proxy { | |||
/** | |||
* data proxy to execute system non-parallel | |||
* | |||
* @tparam T_context context type of the ECS environment | |||
* @tparam T_instance system instance type | |||
*/ | |||
template<typename T_context, typename T_instance> | |||
struct single | |||
: public base<T_context, T_instance> | |||
{ | |||
private: | |||
using context_type = T_context; | |||
using instance_type = T_instance; | |||
using base_type = base<context_type, instance_type>; | |||
public: | |||
using base_type::base_type; | |||
/** | |||
* execute the given function for all entities handled by this data proxy | |||
* | |||
* @tparam T_func function type to execute | |||
* | |||
* @param func function to execute | |||
*/ | |||
template<typename T_func> | |||
void for_entities(T_func&& func) const; | |||
/** | |||
* execute the given function for all entities not handled by this data proxy | |||
* | |||
* @tparam T_func function type to execute | |||
* | |||
* @param func function to execute | |||
*/ | |||
template<typename T_func> | |||
void for_other_entities(T_func&& func) const; | |||
/** | |||
* execute the given function for all entities | |||
* | |||
* @tparam T_func function type to execute | |||
* | |||
* @param func function to execute | |||
*/ | |||
template<typename T_func> | |||
void for_all_entities(T_func&& func) const; | |||
/** | |||
* get the number of entities handled by this data proxy | |||
* | |||
* @return number of entities handle by this data proxy | |||
*/ | |||
inline size_t entity_count() const; | |||
/** | |||
* get the number of entities not handled by this data proxy | |||
* | |||
* @return number of entities not handle by this data proxy | |||
*/ | |||
inline size_t other_entity_count() const; | |||
/** | |||
* get the number of all entities | |||
* | |||
* @return number of all entities | |||
*/ | |||
inline size_t all_entity_count() const; | |||
}; | |||
/** | |||
* create a single data proxy (data proxy that does not execute in parallel) | |||
* | |||
* @tparam T_context context type | |||
* @tparam T_instance instance type | |||
* | |||
* @param context context | |||
* @param instance instance | |||
* | |||
* @return single data proxy | |||
*/ | |||
template<typename T_context, typename T_instance> | |||
constexpr decltype(auto) make_single(T_context&& context, T_instance&& instance); | |||
} } } } |
@@ -0,0 +1,70 @@ | |||
#pragma once | |||
#include <ecs/core/system/data_proxy/single.h> | |||
namespace ecs { | |||
namespace core { | |||
namespace system { | |||
namespace data_proxy { | |||
/* single */ | |||
template<typename T_context, typename T_instance> | |||
template<typename T_func> | |||
void single<T_context, T_instance> | |||
::for_entities(T_func&& func) const | |||
{ | |||
for (auto& e : this->instance.subscribed()) | |||
{ | |||
func(e); | |||
} | |||
} | |||
template<typename T_context, typename T_instance> | |||
template<typename T_func> | |||
void single<T_context, T_instance> | |||
::for_other_entities(T_func&& func) const | |||
{ } | |||
template<typename T_context, typename T_instance> | |||
template<typename T_func> | |||
void single<T_context, T_instance> | |||
::for_all_entities(T_func&& func) const | |||
{ | |||
for_entities(std::forward<T_func>(func)); | |||
} | |||
template<typename T_context, typename T_instance> | |||
inline size_t single<T_context, T_instance> | |||
::entity_count() const | |||
{ | |||
return this->instance.subscribed_count(); | |||
} | |||
template<typename T_context, typename T_instance> | |||
inline size_t single<T_context, T_instance> | |||
::other_entity_count() const | |||
{ | |||
return 0; | |||
} | |||
template<typename T_context, typename T_instance> | |||
inline size_t single<T_context, T_instance> | |||
::all_entity_count() const | |||
{ | |||
return entity_count(); | |||
} | |||
/* make_single */ | |||
template<typename T_context, typename T_instance> | |||
constexpr decltype(auto) make_single(T_context&& context, T_instance&& instance) | |||
{ | |||
using context_type = mp::decay_t<T_context>; | |||
using instance_type = mp::decay_t<T_instance>; | |||
return single<context_type, instance_type>( | |||
std::forward<T_context>(context), | |||
std::forward<T_instance>(instance)); | |||
} | |||
} } } } |
@@ -4,9 +4,11 @@ | |||
#include <ecs/signature/system.h> | |||
#include <ecs/core/utils/bitset.h> | |||
#include <ecs/core/utils/fixed_function.h> | |||
#include <ecs/core/utils/ordered_vector.h> | |||
beg_namespace_ecs_core_system | |||
{ | |||
namespace ecs { | |||
namespace core { | |||
namespace system { | |||
template<typename T_settings> | |||
struct deferred_function_vector | |||
@@ -55,7 +57,7 @@ beg_namespace_ecs_core_system | |||
using bitset_type = utils::bitset<settings_type>; | |||
using entity_handle_type = T_entity_handle; | |||
using executor_type = decltype(mp::unwrap(system_signature_type { }).parallelism()()); | |||
using entity_handle_set_type = std::set<entity_handle_type>; | |||
using entity_handle_set_type = utils::ordered_vector<entity_handle_type>; | |||
struct state_t | |||
: public output_type | |||
@@ -114,6 +116,12 @@ beg_namespace_ecs_core_system | |||
} | |||
public: | |||
inline void prepare_states(size_t n) | |||
{ | |||
assert(n > 0); | |||
clear_and_prepare(n); | |||
} | |||
template<typename T_context, typename T_func> | |||
inline void prepare_and_wait_subtasks(T_context& context, size_t n, T_func& func) | |||
{ | |||
@@ -125,7 +133,7 @@ beg_namespace_ecs_core_system | |||
return [this, &b, &context, &f](auto&&... xs) { | |||
context.post_in_thread_pool([&f, &b, xs...]() { | |||
ecs_make_scope_guard([&b](){ | |||
b.decrement_and_notify_one(); | |||
b.decrement(); | |||
}); | |||
f(xs...); | |||
}); | |||
@@ -137,6 +145,10 @@ beg_namespace_ecs_core_system | |||
}); | |||
} | |||
template<typename T_context, typename T_func> | |||
inline void execute(T_context& context, T_func&& func) | |||
{ _executor(context, *this, std::forward<T_func>(func)); } | |||
public: /* bitset */ | |||
inline const auto& bitset() const noexcept | |||
{ return _bitset; } | |||
@@ -162,7 +174,7 @@ beg_namespace_ecs_core_system | |||
{ return (_subscribed.find(handle) != _subscribed.end()); } | |||
inline void subscribe(const entity_handle_type& handle) | |||
{ _subscribed.emplace(handle); } | |||
{ _subscribed.insert(handle); } | |||
inline void unsubscribe(const entity_handle_type& handle) | |||
{ _subscribed.erase(handle); } | |||
@@ -197,5 +209,4 @@ beg_namespace_ecs_core_system | |||
}; | |||
} | |||
end_namespace_ecs_core_system | |||
} } } |
@@ -0,0 +1,3 @@ | |||
#pragma once | |||
#include "./composer/fixed_threshold.h" |
@@ -2,8 +2,10 @@ | |||
#include <ecs/config.h> | |||
beg_namespace_ecs_core_parallelism | |||
{ | |||
namespace ecs { | |||
namespace core { | |||
namespace system { | |||
namespace parallelism { | |||
template<typename T_parameters> | |||
struct fixed_threshold | |||
@@ -15,20 +17,13 @@ beg_namespace_ecs_core_parallelism | |||
strategy_lower_type _strategy_lower; | |||
strategy_greater_type _strategy_greater; | |||
template<typename T_instance, typename... T_args> | |||
inline void operator()(T_instance& instance, T_args&&... args) const | |||
template<typename T_context, typename T_instance, typename T_func> | |||
inline void operator()(T_context& context, T_instance& instance, T_func&& func) const | |||
{ | |||
bool threshold_reached = false; // TODO | |||
if (!threshold_reached) | |||
{ | |||
_strategy_lower(instance, std::forward<T_args>(args)...); | |||
} | |||
else | |||
{ | |||
_strategy_greater(instance, std::forward<T_args>(args)...); | |||
} | |||
if (!threshold_reached) _strategy_lower (instance, context, std::forward<T_func>(func)); | |||
else _strategy_greater(instance, context, std::forward<T_func>(func)); | |||
} | |||
}; | |||
} | |||
end_namespace_ecs_core_parallelism | |||
} } } } |
@@ -1,18 +1,39 @@ | |||
#pragma once | |||
#include <ecs/config.h> | |||
#include <ecs/core/system/data_proxy.h> | |||
beg_namespace_ecs_core_parallelism | |||
{ | |||
namespace ecs { | |||
namespace core { | |||
namespace system { | |||
namespace parallelism { | |||
struct none | |||
{ | |||
template<typename T_instance, typename T_context, typename T_func> | |||
inline void operator()(T_instance& instance, T_context& context, T_func&& func) const | |||
template<typename T_context, typename T_instance> | |||
struct executor_proxy | |||
{ | |||
// TODO | |||
using context_type = T_context; | |||
using instance_type = T_instance; | |||
context_type& context; | |||
instance_type& instance; | |||
template<typename T_func> | |||
inline void for_subtasks(T_func&& func) | |||
{ | |||
instance.prepare_states(1); | |||
auto data = data_proxy::make_single(context, instance); | |||
func(data); | |||
} | |||
}; | |||
template<typename T_context, typename T_instance, typename T_func> | |||
inline void operator()(T_context& context, T_instance& instance, T_func&& func) const | |||
{ | |||
executor_proxy<T_context, T_instance> ep { context, instance }; | |||
func(instance, ep); | |||
} | |||
}; | |||
} | |||
end_namespace_ecs_core_parallelism | |||
} } } } |
@@ -2,8 +2,10 @@ | |||
#include <ecs/config.h> | |||
beg_namespace_ecs_core_parallelism | |||
{ | |||
namespace ecs { | |||
namespace core { | |||
namespace system { | |||
namespace parallelism { | |||
template<typename T_parameters> | |||
struct split_evenly | |||
@@ -13,10 +15,9 @@ beg_namespace_ecs_core_parallelism | |||
template<typename T_context, typename T_instance, typename T_func> | |||
inline void operator()(T_context& context, T_instance& instance, T_func&& func) const | |||
{ | |||
// auto split_count = parameters_type::get_split_count(); | |||
// TODO | |||
// auto split_count = parameters_type::get_split_count(); | |||
} | |||
}; | |||
} | |||
end_namespace_ecs_core_parallelism | |||
} } } } |
@@ -2,8 +2,10 @@ | |||
#include <ecs/config.h> | |||
beg_namespace_ecs_core_parallelism | |||
{ | |||
namespace ecs { | |||
namespace core { | |||
namespace system { | |||
namespace parallelism { | |||
template<typename T_parameters> | |||
struct split_every | |||
@@ -13,9 +15,9 @@ beg_namespace_ecs_core_parallelism | |||
template<typename T_context, typename T_instance, typename T_func> | |||
inline void operator()(T_context& context, T_instance& instance, T_func&& func) const | |||
{ | |||
// TODO | |||
// auto per_split = parameters_type::get_per_split_count(); | |||
} | |||
}; | |||
} | |||
end_namespace_ecs_core_parallelism | |||
} } } } |
@@ -1,3 +1,5 @@ | |||
#pragma once | |||
#include "./scheduler/atomic_counter.h" | |||
#include "./scheduler/atomic_counter.h" | |||
#include "./scheduler/atomic_counter.inl" |
@@ -1,26 +1,43 @@ | |||
#pragma once | |||
#include <ecs/config.h> | |||
#include <ecs/tag/system.h> | |||
#include <ecs/context/context.fwd.h> | |||
beg_namespace_ecs_core_system_scheduler | |||
{ | |||
namespace ecs { | |||
namespace core { | |||
namespace system { | |||
namespace scheduler { | |||
namespace __impl | |||
namespace detail | |||
{ | |||
template<typename T_system_tag, typename T_execute, typename T_dependency_ids> | |||
/** | |||
* struct to wrap some system meta data | |||
*/ | |||
template< | |||
typename T_system_tag, | |||
typename T_execute, | |||
typename T_dependency_ids> | |||
struct dependency_item_t | |||
{ | |||
using system_tag_type = T_system_tag; | |||
using execute_type = T_execute; | |||
using dependency_ids_type = T_dependency_ids; | |||
system_tag_type tag; | |||
execute_type execute; | |||
dependency_ids_type dependency_ids; | |||
system_tag_type tag; //!< tag of system this dependency element represents | |||
execute_type execute; //!< boolean value to determine if the system should be executed or not | |||
dependency_ids_type dependency_ids; //!< list of system IDs that depends on this system/item | |||
}; | |||
template<typename T_dependency_item, typename T_dependent_ids> | |||
/** | |||
* defines a task to be executed (represents a system to execute in the scheduler) | |||
* | |||
* @tparam T_dependency_item dependency item type for this task | |||
* @tparam T_dependent_ids id types of tasks that depends on this task | |||
*/ | |||
template< | |||
typename T_dependency_item, | |||
typename T_dependent_ids> | |||
struct task_t | |||
{ | |||
public: | |||
@@ -32,50 +49,76 @@ beg_namespace_ecs_core_system_scheduler | |||
std::atomic<size_t> _dependency_count; | |||
public: | |||
task_t() | |||
: _dependency_count(hana::value(hana::size(mp::unwrap(dependency_item_type { }).dependency_ids))) | |||
{ } | |||
inline size_t dependency_count() const | |||
{ return _dependency_count; } | |||
inline bool decrement_and_check() | |||
{ return (--_dependency_count == 0); } | |||
mp::unwrap_t<dependency_item_type> dependency_item; | |||
/** | |||
* constructor | |||
*/ | |||
inline task_t(); | |||
/** | |||
* get the number unfinished tasks, this task depends on | |||
*/ | |||
inline size_t dependency_count() const; | |||
/** | |||
* decrepent the unfished task counter | |||
* | |||
* @retval TRUE if all tasks, this task depends on, are finished | |||
* @retval FALSE if at least on task, this task depends on, is not finished | |||
*/ | |||
inline bool decrement_and_check(); | |||
/** | |||
* execute the passed function for task ID that depends on this task | |||
* | |||
* @tparam T_func function type to execute | |||
* | |||
* @param func function to execute | |||
*/ | |||
template<typename T_func> | |||
constexpr decltype(auto) for_dependent_ids(T_func&& func) const noexcept | |||
{ hana::for_each(dependent_ids_type { }, std::forward<T_func>(func)); } | |||
constexpr decltype(auto) for_dependent_ids(T_func&& func) const noexcept; | |||
}; | |||
/** | |||
* predicate type to create a list of task IDs that depends on the given task | |||
*/ | |||
struct dependent_ids_t | |||
{ | |||
/** | |||
* execute the predicate | |||
* | |||
* @tparam T_dependency_items list of dependency items | |||
* @tparam T_dependency_item dependency item to get taks IDs for, that depends on that item | |||
* | |||
* @return list of task IDs that depends on the given dependency item | |||
*/ | |||
template<typename T_dependency_items, typename T_dependency_item> | |||
constexpr decltype(auto) operator()(T_dependency_items, T_dependency_item) const noexcept | |||
{ | |||
auto item_id = mp::list::index_of(T_dependency_items { }, T_dependency_item { }); | |||
return hana::fold_right(T_dependency_items { }, mp::list::empty, [=](auto other, auto acc){ | |||
return hana::if_( | |||
hana::contains(mp::unwrap(other).dependency_ids, item_id), | |||
hana::append(acc, mp::list::index_of(T_dependency_items { }, other)), | |||
acc); | |||
}); | |||
} | |||
constexpr decltype(auto) operator()(T_dependency_items, T_dependency_item) const noexcept; | |||
}; | |||
/** | |||
* predicate type to create a list of tasks | |||
*/ | |||
struct make_tasks_t | |||
{ | |||
/** | |||
* execute the predicate | |||
* | |||
* @tparam T_dependency_items list of dependency items to create tasks from | |||
* | |||
* @return list of tasks | |||
*/ | |||
template<typename T_dependency_items> | |||
constexpr decltype(auto) operator()(T_dependency_items) const noexcept | |||
{ | |||
return hana::transform(T_dependency_items { }, [](auto item){ | |||
using item_type = mp::decay_t<decltype(item)>; | |||
using dependent_ids_type = mp::decay_t<decltype((dependent_ids_t { })(T_dependency_items { }, item_type { }))>; | |||
using task_type = task_t<item_type, dependent_ids_type>; | |||
return hana::type_c<task_type>; | |||
}); | |||
} | |||
constexpr decltype(auto) operator()(T_dependency_items) const noexcept; | |||
}; | |||
/** | |||
* defines a group of tasks to execute with | |||
* | |||
* @tparam T_context context type | |||
* @tparam T_dependency_items list of dependency items | |||
*/ | |||
template<typename T_context, typename T_dependency_items> | |||
struct task_group_t | |||
{ | |||
@@ -89,144 +132,93 @@ beg_namespace_ecs_core_system_scheduler | |||
using tasks_tuple_type = mp::list::unwrap_t<hana::tuple, task_types>; | |||
private: | |||
context_type& _context; | |||
utils::counter_blocker& _counter; | |||
tasks_tuple_type _tasks; | |||
context_type& _context; //!< context to use for system execution | |||
utils::counter_blocker& _counter; //!< counter to track running tasks | |||
tasks_tuple_type _tasks; //!< tuple of all tasks | |||
public: | |||
inline task_group_t(context_type& p_context, utils::counter_blocker& p_counter) | |||
: _context(p_context) | |||
, _counter(p_counter) | |||
{ } | |||
template<typename T_task_id> | |||
inline void start_task(T_task_id id) | |||
{ | |||
using task_type = mp::decay_t<decltype(hana::at(_tasks, id))>; | |||
using dependency_item_type = typename task_type::dependency_item_type; | |||
_counter.increment(); | |||
hana::eval_if( | |||
mp::unwrap(dependency_item_type { }).execute, | |||
[this](auto _) { _(this)->post_task_in_thread_pool (T_task_id { }); }, | |||
[this](auto _) { _(this)->check_and_start_dependencies(T_task_id { }); }); | |||
} | |||
/** | |||
* constructor | |||
* | |||
* @param p_context context to use for system execution | |||
* @param p_counter counter to track running tasks | |||
*/ | |||
inline task_group_t(context_type& p_context, utils::counter_blocker& p_counter); | |||
/** | |||
* start the given task | |||
* | |||
* @tparam T_task_id id type of the task to execute | |||
* @tparam T_func overloaded function type to execute system with | |||
* | |||
* @param id id of task to execute | |||
* @param func overloaded function to execute system with | |||
*/ | |||
template<typename T_task_id, typename T_func> | |||
inline void start_task(T_task_id id, T_func&& func); | |||
private: | |||
template<typename T_task_id> | |||
inline void post_task_in_thread_pool(T_task_id) | |||
{ | |||
_context.post_in_thread_pool([this]{ | |||
execute_task(T_task_id { }); | |||
}); | |||
} | |||
template<typename T_task_id> | |||
inline void execute_task(T_task_id) | |||
{ | |||
check_and_start_dependencies(T_task_id { }); | |||
} | |||
template<typename T_task_id> | |||
inline void check_and_start_dependencies(T_task_id) | |||
{ | |||
auto& task = hana::at(_tasks, T_task_id { }); | |||
task.for_dependent_ids([this](auto id){ | |||
auto& other = hana::at(_tasks, id); | |||
if (other.decrement_and_check()) { | |||
start_task(id); | |||
} | |||
}); | |||
_counter.decrement_and_notify_one(); | |||
} | |||
/** | |||
* execute the task using the thread pool | |||
* | |||
* @tparam T_task_id id type of task to execute | |||
* @tparam T_func overloaded function type to execute system with | |||
* | |||
* @param func overloaded function to execute system with | |||
*/ | |||
template<typename T_task_id, typename T_func> | |||
inline void post_task_in_thread_pool(T_task_id, T_func&& func); | |||
/** | |||
* execute the actual task using the passed overloaded function | |||
* | |||
* @tparam T_task_id id type of task to execute | |||
* @tparam T_func overloaded function type to execute system with | |||
* | |||
* @param func overloaded function to execute system with | |||
*/ | |||
template<typename T_task_id, typename T_func> | |||
inline void execute_task(T_task_id, T_func&& func); | |||
/** | |||
* update the dependencies of the current task and start the next task | |||
* | |||
* @tparam T_task_id id type of task to update dependencies for | |||
* @tparam T_func overloaded function type to execute system with | |||
* | |||
* @param func overloaded function to execute system with | |||
*/ | |||
template<typename T_task_id, typename T_func> | |||
inline void check_and_start_dependencies(T_task_id, T_func&& func); | |||
}; | |||
/** | |||
* create a list of dependency items | |||
* | |||
* @tparam T_system_signature_list system signature list type | |||
* @tparam T_system_tag_list list of system tag types | |||
* | |||
* @return list of dependency items | |||
*/ | |||
template<typename T_system_signature_list, typename T_system_tag_list> | |||
constexpr decltype(auto) build_dependency_list(T_system_signature_list, T_system_tag_list) noexcept | |||
{ | |||
using system_signature_list_type = T_system_signature_list; | |||
using system_signature_tuple_type = mp::decay_t<decltype((system_signature_list_type { }).items)>; | |||
using system_tag_list_type = T_system_tag_list; | |||
auto filtered = (system_signature_list_type { }) | |||
.filter([](auto ssig){ | |||
return hana::contains(system_tag_list_type { }, mp::unwrap(ssig).tag()); | |||
}); | |||
using filtered_ssig_list_type = mp::decay_t<decltype(filtered)>; | |||
(filtered_ssig_list_type { }).for_each([](auto ssig){ | |||
using ssig_type = mp::decay_t<decltype(ssig)>; | |||
hana::for_each(mp::unwrap(ssig).write(), [](auto tag){ | |||
using tag_type = mp::decay_t<decltype(tag)>; | |||
(filtered_ssig_list_type { }).for_each([](auto other){ | |||
using check_dependencies_type = decltype( | |||
hana::or_( | |||
hana::equal(ssig_type { }, other), | |||
(T_system_signature_list { }).depends_on(ssig_type { }, mp::unwrap(other).tag()), | |||
(T_system_signature_list { }).depends_on(other, mp::unwrap(ssig_type { }).tag()), | |||
hana::not_(hana::contains(mp::unwrap(other).write(), tag_type { })))); | |||
static_assert( | |||
check_dependencies_type { }, | |||
"independent systems can not share write access to component"); | |||
}); | |||
}); | |||
}); | |||
return hana::transform(system_signature_tuple_type { }, [](auto ssig){ | |||
using ssig_type = mp::decay_t<decltype(ssig)>; | |||
auto tag = mp::unwrap(ssig).tag(); | |||
auto deps = mp::unwrap(ssig).dependencies(); | |||
auto execute = hana::contains(system_tag_list_type { }, mp::unwrap(ssig).tag()); | |||
auto read_deps = | |||
hana::transform(mp::unwrap(ssig).read(), [](auto read_tag){ | |||
using read_tag_type = mp::decay_t<decltype(read_tag)>; | |||
return hana::transform( | |||
hana::filter((filtered_ssig_list_type { }).items, [](auto other){ | |||
return hana::and_( | |||
hana::not_equal(ssig_type { }, other), | |||
hana::contains(mp::unwrap(other).write(), read_tag_type { })); | |||
}), | |||
[](auto other){ | |||
return mp::unwrap(other).tag(); | |||
}); | |||
}); | |||
auto final_deps = | |||
hana::transform( | |||
hana::fold( | |||
hana::if_( | |||
hana::size(read_deps) == hana::size_c<0>, | |||
hana::make_basic_tuple(hana::make_basic_tuple()), | |||
read_deps), | |||
deps, | |||
hana::concat), | |||
[](auto tmp_tag){ | |||
return (system_signature_list_type { }).id_by_tag(tmp_tag); | |||
}); | |||
using tag_type = mp::decay_t<decltype(tag)>; | |||
using dep_type = mp::decay_t<decltype(final_deps)>; | |||
using execute_type = mp::decay_t<decltype(execute)>; | |||
using item_type = dependency_item_t<tag_type, execute_type, dep_type>; | |||
return hana::type_c<item_type>; | |||
}); | |||
} | |||
constexpr decltype(auto) build_dependency_list(T_system_signature_list, T_system_tag_list) noexcept; | |||
/** | |||
* get a list of independent items from the passed dependency list | |||
* | |||
* @tparam T_dependency_list dependency item list to get independent items from | |||
* | |||
* @return list of independent items | |||
*/ | |||
template<typename T_dependency_list> | |||
constexpr decltype(auto) get_independent_item_ids(T_dependency_list) noexcept | |||
{ | |||
return | |||
hana::transform( | |||
hana::filter(T_dependency_list { }, [](auto item){ | |||
return hana::size(mp::unwrap(item).dependency_ids) == hana::size_c<0>; | |||
}), | |||
[](auto item){ | |||
return mp::list::index_of(T_dependency_list { }, item); | |||
}); | |||
} | |||
constexpr decltype(auto) get_independent_item_ids(T_dependency_list) noexcept; | |||
} | |||
/** | |||
* scheduler that resolves the dependencies between systems and then executes the systems in a save way in parallel | |||
* | |||
* @tparam T_settings settings type the environment is configured with | |||
*/ | |||
template<typename T_settings> | |||
struct atomic_counter | |||
{ | |||
@@ -238,43 +230,24 @@ beg_namespace_ecs_core_system_scheduler | |||
context_type& _context; | |||
public: | |||
atomic_counter(context_type& p_context) | |||
: _context(p_context) | |||
{ } | |||
/** | |||
* constructor | |||
* | |||
* @param p_context context to use for system exeution | |||
*/ | |||
inline atomic_counter(context_type& p_context); | |||
/** | |||
* execute the systems for that system tags are passed | |||
* | |||
* @tparam T_system_tag_list list of system tag type to execute systems for | |||
* @tparam T_func overloaded function type to use for system execution | |||
* | |||
* @param stl list of system tags to execute systems for | |||
* @param func overloaded function to use for system execution | |||
*/ | |||
template<typename T_system_tag_list, typename T_func> | |||
inline void execute(T_system_tag_list, T_func&& func) | |||
{ | |||
static_assert(tag::system::is_list(T_system_tag_list { })); | |||
using dependency_list_type = mp::decay_t<decltype(__impl::build_dependency_list( | |||
(settings_type { }).system_signatures(), | |||
T_system_tag_list { }))>; | |||
using independent_item_ids_type = mp::decay_t<decltype(__impl::get_independent_item_ids( | |||
dependency_list_type { }))>;; | |||
size_t i = 0; | |||
std::cout << "dependency_list" << std::endl; | |||
hana::for_each(dependency_list_type { }, [&i](auto item){ | |||
using system_type = mp::unwrap_t<mp::decay_t<decltype(mp::unwrap(item).tag)>>; | |||
std::cout << " " << (i++) << ": " << type_helper<system_type>::name() << " (" << hana::value(mp::unwrap(item).execute) << ")" << std::endl; | |||
hana::for_each(mp::unwrap(item).dependency_ids, [](auto id){ | |||
std::cout << " " << hana::value(id) << std::endl; | |||
}); | |||
}); | |||
using task_group_type = __impl::task_group_t<context_type, dependency_list_type>; | |||
utils::counter_blocker counter (1); | |||
task_group_type task_group (_context, counter); | |||
counter.execute_and_wait_until_zero([&task_group, &counter]{ | |||
hana::for_each(independent_item_ids_type { }, [&task_group](auto id){ | |||
task_group.start_task(id); | |||
}); | |||
counter.decrement_and_notify_one(); | |||
}); | |||
} | |||
inline void execute(T_system_tag_list stl, T_func&& func); | |||
}; | |||
} | |||
end_namespace_ecs_core_system_scheduler | |||
} } } } |
@@ -0,0 +1,278 @@ | |||
#pragma once | |||
#include <ecs/core/system/scheduler/atomic_counter.h> | |||
namespace ecs { | |||
namespace core { | |||
namespace system { | |||
namespace scheduler { | |||
namespace detail | |||
{ | |||
/* task_t */ | |||
template< | |||
typename T_dependency_item, | |||
typename T_dependent_ids> | |||
inline task_t<T_dependency_item, T_dependent_ids> | |||
::task_t() | |||
: _dependency_count(hana::value(hana::size(mp::unwrap(dependency_item_type { }).dependency_ids))) | |||
{ } | |||
template< | |||
typename T_dependency_item, | |||
typename T_dependent_ids> | |||
inline size_t task_t<T_dependency_item, T_dependent_ids> | |||
::dependency_count() const | |||
{ | |||
return _dependency_count; | |||
} | |||
template< | |||
typename T_dependency_item, | |||
typename T_dependent_ids> | |||
inline bool task_t<T_dependency_item, T_dependent_ids> | |||
::decrement_and_check() | |||
{ | |||
return (--_dependency_count == 0); | |||
} | |||
template< | |||
typename T_dependency_item, | |||
typename T_dependent_ids> | |||
template<typename T_func> | |||
constexpr decltype(auto) task_t<T_dependency_item, T_dependent_ids> | |||
::for_dependent_ids(T_func&& func) const noexcept | |||
{ | |||
hana::for_each(dependent_ids_type { }, std::forward<T_func>(func)); | |||
} | |||
/* dependent_ids_t */ | |||
template<typename T_dependency_items, typename T_dependency_item> | |||
constexpr decltype(auto) dependent_ids_t | |||
::operator()(T_dependency_items, T_dependency_item) const noexcept | |||
{ | |||
auto item_id = mp::list::index_of(T_dependency_items { }, T_dependency_item { }); | |||
return hana::fold_right(T_dependency_items { }, mp::list::empty, [=](auto other, auto acc){ | |||
return hana::if_( | |||
hana::contains(mp::unwrap(other).dependency_ids, item_id), | |||
hana::append(acc, mp::list::index_of(T_dependency_items { }, other)), | |||
acc); | |||
}); | |||
} | |||
/* make_tasks_t */ | |||
template<typename T_dependency_items> | |||
constexpr decltype(auto) make_tasks_t | |||
::operator()(T_dependency_items) const noexcept | |||
{ | |||
return hana::transform(T_dependency_items { }, [](auto item){ | |||
using item_type = mp::decay_t<decltype(item)>; | |||
using dependent_ids_type = mp::decay_t<decltype((dependent_ids_t { })(T_dependency_items { }, item_type { }))>; | |||
using task_type = task_t<item_type, dependent_ids_type>; | |||
return hana::type_c<task_type>; | |||
}); | |||
} | |||
/* task_group_t */ | |||
template<typename T_context, typename T_dependency_items> | |||
inline task_group_t<T_context, T_dependency_items> | |||
::task_group_t(context_type& p_context, utils::counter_blocker& p_counter) | |||
: _context(p_context) | |||
, _counter(p_counter) | |||
{ } | |||
template<typename T_context, typename T_dependency_items> | |||
template<typename T_task_id, typename T_func> | |||
inline void task_group_t<T_context, T_dependency_items> | |||
::start_task(T_task_id id, T_func&& func) | |||
{ | |||
using task_type = mp::decay_t<decltype(hana::at(_tasks, id))>; | |||
using dependency_item_type = typename task_type::dependency_item_type; | |||
_counter.increment(); | |||
hana::eval_if( | |||
mp::unwrap(dependency_item_type { }).execute, | |||
[this, &func](auto _) { _(this)->post_task_in_thread_pool (T_task_id { }, func); }, | |||
[this, &func](auto _) { _(this)->check_and_start_dependencies(T_task_id { }, func); }); | |||
} | |||
template<typename T_context, typename T_dependency_items> | |||
template<typename T_task_id, typename T_func> | |||
inline void task_group_t<T_context, T_dependency_items> | |||
::post_task_in_thread_pool(T_task_id, T_func&& func) | |||
{ | |||
std::cout << "post_task_in_thread_pool (current=" << std::this_thread::get_id() << ", task=" << T_task_id::value << ")" << std::endl; | |||
_context.post_in_thread_pool([this, &func]{ | |||
execute_task(T_task_id { }, func); | |||
}); | |||
} | |||
template<typename T_context, typename T_dependency_items> | |||
template<typename T_task_id, typename T_func> | |||
inline void task_group_t<T_context, T_dependency_items> | |||
::execute_task(T_task_id, T_func&& func) | |||
{ | |||
std::cout << "execute_task (current=" << std::this_thread::get_id() << ", task=" << T_task_id::value << ")" << std::endl; | |||
auto& task = hana::at(_tasks, T_task_id { }); | |||
auto& instance = _context.instance_by_tag(task.dependency_item.tag); | |||
instance.execute(_context, func); | |||
check_and_start_dependencies(T_task_id { }, func); | |||
} | |||
template<typename T_context, typename T_dependency_items> | |||
template<typename T_task_id, typename T_func> | |||
inline void task_group_t<T_context, T_dependency_items> | |||
::check_and_start_dependencies(T_task_id, T_func&& func) | |||
{ | |||
std::cout << "check_and_start_dependencies (current=" << std::this_thread::get_id() << ", task=" << T_task_id::value << ")" << std::endl; | |||
auto& task = hana::at(_tasks, T_task_id { }); | |||
task.for_dependent_ids([this, &func](auto id){ | |||
auto& other = hana::at(_tasks, id); | |||
if (other.decrement_and_check()) { | |||
start_task(id, func); | |||
} | |||
}); | |||
_counter.decrement(); | |||
} | |||
/* misc */ | |||
template<typename T_system_signature_list, typename T_system_tag_list> | |||
constexpr decltype(auto) build_dependency_list(T_system_signature_list, T_system_tag_list) noexcept | |||
{ | |||
using system_signature_list_type = T_system_signature_list; | |||
using system_signature_tuple_type = mp::decay_t<decltype((system_signature_list_type { }).items)>; | |||
using system_tag_list_type = T_system_tag_list; | |||
/* filter system signature list by the passed system tags */ | |||
auto filtered = (system_signature_list_type { }) | |||
.filter([](auto ssig){ | |||
return hana::contains(system_tag_list_type { }, mp::unwrap(ssig).tag()); | |||
}); | |||
using filtered_ssig_list_type = mp::decay_t<decltype(filtered)>; | |||
/* check if any systems that does not depend on each other, wants to get write access to a component */ | |||
(filtered_ssig_list_type { }).for_each([](auto ssig){ | |||
using ssig_type = mp::decay_t<decltype(ssig)>; | |||
hana::for_each(mp::unwrap(ssig).write(), [](auto tag){ | |||
using tag_type = mp::decay_t<decltype(tag)>; | |||
(filtered_ssig_list_type { }).for_each([](auto other){ | |||
using check_dependencies_type = decltype( | |||
hana::or_( | |||
hana::equal(ssig_type { }, other), | |||
(T_system_signature_list { }).depends_on(ssig_type { }, mp::unwrap(other).tag()), | |||
(T_system_signature_list { }).depends_on(other, mp::unwrap(ssig_type { }).tag()), | |||
hana::not_(hana::contains(mp::unwrap(other).write(), tag_type { })))); | |||
static_assert( | |||
check_dependencies_type { }, | |||
"independent systems can not share write access to component"); | |||
}); | |||
}); | |||
}); | |||
/* build the actual dependency item list */ | |||
return hana::transform(system_signature_tuple_type { }, [](auto ssig){ | |||
using ssig_type = mp::decay_t<decltype(ssig)>; | |||
auto tag = mp::unwrap(ssig).tag(); | |||
auto deps = mp::unwrap(ssig).dependencies(); | |||
auto execute = hana::contains(system_tag_list_type { }, mp::unwrap(ssig).tag()); | |||
auto read_deps = | |||
hana::transform(mp::unwrap(ssig).read(), [](auto read_tag){ | |||
using read_tag_type = mp::decay_t<decltype(read_tag)>; | |||
return hana::transform( | |||
hana::filter((filtered_ssig_list_type { }).items, [](auto other){ | |||
return hana::and_( | |||
hana::not_equal(ssig_type { }, other), | |||
hana::contains(mp::unwrap(other).write(), read_tag_type { })); | |||
}), | |||
[](auto other){ | |||
return mp::unwrap(other).tag(); | |||
}); | |||
}); | |||
auto final_deps = | |||
hana::transform( | |||
hana::fold( | |||
hana::if_( | |||
hana::size(read_deps) == hana::size_c<0>, | |||
hana::make_basic_tuple(hana::make_basic_tuple()), | |||
read_deps), | |||
deps, | |||
hana::concat), | |||
[](auto tmp_tag){ | |||
return (system_signature_list_type { }).id_by_tag(tmp_tag); | |||
}); | |||
using tag_type = mp::decay_t<decltype(tag)>; | |||
using dep_type = mp::decay_t<decltype(final_deps)>; | |||
using execute_type = mp::decay_t<decltype(execute)>; | |||
using item_type = dependency_item_t<tag_type, execute_type, dep_type>; | |||
return hana::type_c<item_type>; | |||
}); | |||
} | |||
template<typename T_dependency_list> | |||
constexpr decltype(auto) get_independent_item_ids(T_dependency_list) noexcept | |||
{ | |||
return | |||
hana::transform( | |||
hana::filter(T_dependency_list { }, [](auto item){ | |||
return hana::size(mp::unwrap(item).dependency_ids) == hana::size_c<0>; | |||
}), | |||
[](auto item){ | |||
return mp::list::index_of(T_dependency_list { }, item); | |||
}); | |||
} | |||
} | |||
template<typename T_settings> | |||
inline atomic_counter<T_settings> | |||
::atomic_counter(context_type& p_context) | |||
: _context(p_context) | |||
{ } | |||
template<typename T_settings> | |||
template<typename T_system_tag_list, typename T_func> | |||
inline void atomic_counter<T_settings> | |||
::execute(T_system_tag_list stl, T_func&& func) | |||
{ | |||
static_assert(tag::system::is_list(T_system_tag_list { })); | |||
using dependency_list_type = mp::decay_t<decltype(detail::build_dependency_list( | |||
(settings_type { }).system_signatures(), | |||
T_system_tag_list { }))>; | |||
using independent_item_ids_type = mp::decay_t<decltype(detail::get_independent_item_ids( | |||
dependency_list_type { }))>;; | |||
/* TODO debug beg! */ | |||
size_t i = 0; | |||
std::cout << "dependency_list" << std::endl; | |||
hana::for_each(dependency_list_type { }, [&i](auto item){ | |||
using system_type = mp::unwrap_t<mp::decay_t<decltype(mp::unwrap(item).tag)>>; | |||
std::cout << " " << (i++) << ": " << type_helper<system_type>::name() << " (" << hana::value(mp::unwrap(item).execute) << ")" << std::endl; | |||
hana::for_each(mp::unwrap(item).dependency_ids, [](auto id){ | |||
std::cout << " " << hana::value(id) << std::endl; | |||
}); | |||
}); | |||
/* TODO debug end! */ | |||
using task_group_type = detail::task_group_t<context_type, dependency_list_type>; | |||
utils::counter_blocker counter (1); | |||
task_group_type task_group (_context, counter); | |||
counter.execute_and_wait_until_zero([&task_group, &counter, &func]{ | |||
hana::for_each(independent_item_ids_type { }, [&task_group, &func](auto id){ | |||
task_group.start_task(id, func); | |||
}); | |||
counter.decrement(); | |||
}); | |||
} | |||
} } } } |
@@ -4,8 +4,10 @@ | |||
#include <ecs/tag/system.h> | |||
#include <ecs/core/system/instance.h> | |||
beg_namespace_ecs_core_system_storage | |||
{ | |||
namespace ecs { | |||
namespace core { | |||
namespace system { | |||
namespace storage { | |||
template<typename T_settings, typename T_entity_handle> | |||
struct tuple | |||
@@ -94,5 +96,4 @@ beg_namespace_ecs_core_system_storage | |||
{ return instance_by_tag(ssig.tag()); } | |||
}; | |||
} | |||
end_namespace_ecs_core_system_storage | |||
} } } } |
@@ -4,6 +4,11 @@ | |||
#include "./utils/counter_blocker.h" | |||
#include "./utils/fixed_function.h" | |||
#include "./utils/movable_atomic.h" | |||
#include "./utils/ordered_vector.h" | |||
#include "./utils/scope_guard.h" | |||
#include "./utils/storage_cast.h" | |||
#include "./utils/thread_pool.h" | |||
#include "./utils/thread_pool.h" | |||
#include "./utils/bitset.inl" | |||
#include "./utils/counter_blocker.inl" | |||
#include "./utils/fixed_function.inl" |
@@ -4,48 +4,106 @@ | |||
#include <ecs/config.h> | |||
#include <ecs/core/mp/list.h> | |||
beg_namespace_ecs_core_utils | |||
{ | |||
namespace ecs { | |||
namespace core { | |||
namespace utils { | |||
/** | |||
* bitset to store components flags in | |||
* | |||
* @tparam T_settings settings type the environmant is configured with | |||
*/ | |||
template<typename T_settings> | |||
struct bitset | |||
{ | |||
private: | |||
/** | |||
* get the component signature list | |||
* | |||
* @return component signature list | |||
*/ | |||
static constexpr decltype(auto) csl() noexcept | |||
{ return (T_settings { }).component_signatures(); } | |||
/** | |||
* get the tags of all components | |||
* | |||
* @return list of all component tags | |||
*/ | |||
static constexpr decltype(auto) all_components() noexcept | |||
{ return csl().all_components(); } | |||
public: | |||
/** | |||
* get the number of components | |||
* | |||
* @return integral constant with number of components | |||
*/ | |||
static constexpr decltype(auto) component_count() noexcept | |||
{ return hana::size(all_components()); } | |||
/** | |||
* get the ID of the given component tag | |||
* | |||
* @tparam T_component_tag component tag type to get ID for | |||
* | |||
* @param ct component tag to get the ID for | |||
* | |||
* @return integral constant with the ID of the requested component tag | |||
*/ | |||
template<typename T_component_tag> | |||
static constexpr decltype(auto) component_id(T_component_tag ct) noexcept | |||
{ return mp::list::index_of(all_components(), ct); } | |||
static constexpr decltype(auto) component_id(T_component_tag ct) noexcept; | |||
/** | |||
* internal bitset type that contains all components | |||
*/ | |||
using bitset_type = std::bitset<component_count()>; | |||
private: | |||
bitset_type _bitset; | |||
public: | |||
inline void clear() noexcept | |||
{ _bitset.reset(); } | |||
/** | |||
* clear all bits of the bitset | |||
*/ | |||
inline void clear() noexcept; | |||
/** | |||
* check if the bitset contains another bitset | |||
* | |||
* @tparam T_other type of the other bitset | |||
* | |||
* @param other bitset to compare with | |||
* | |||
* @retval TRUE if this bitset contains the passed bitset | |||
* @retval FALSE if this bitset does not contain the passed bitset | |||
*/ | |||
template<typename T_other> | |||
inline bool contains(const T_other& other) const noexcept | |||
{ return (_bitset & other._bitset) == _bitset; } | |||
inline bool contains(const T_other& other) const noexcept; | |||
/** | |||
* check if the bitset contains the given component | |||
* | |||
* @tparam T_component_tag component tag type to check | |||
* | |||
* @param ct component tag to check | |||
* | |||
* @retval TRUE if this bitset contains the passed component tag | |||
* @retval FALSE if this bitset does not contain the passed component tag | |||
*/ | |||
template<typename T_component_tag> | |||
inline bool has_component(T_component_tag ct) const | |||
{ return _bitset.test(component_id(ct)); } | |||
inline bool has_component(T_component_tag ct) const; | |||
/** | |||
* set the bit value of the passed component tag | |||
* | |||
* @tparam T_component_tag component tag type to set | |||
* | |||
* @param ct component tag to set | |||
* @param value new bit value of the component inside the bitset | |||
*/ | |||
template<typename T_component_tag> | |||
inline void set_component(T_component_tag ct, bool value) | |||
{ _bitset.set(component_id(ct), value); } | |||
inline void set_component(T_component_tag ct, bool value); | |||
}; | |||
} | |||
end_namespace_ecs_core_utils | |||
} } } |
@@ -0,0 +1,48 @@ | |||
#pragma once | |||
#include <ecs/core/utils/bitset.h> | |||
namespace ecs { | |||
namespace core { | |||
namespace utils { | |||
template<typename T_settings> | |||
template<typename T_component_tag> | |||
constexpr decltype(auto) bitset<T_settings> | |||
::component_id(T_component_tag ct) noexcept | |||
{ | |||
return mp::list::index_of(all_components(), ct); | |||
} | |||
template<typename T_settings> | |||
inline void bitset<T_settings> | |||
::clear() noexcept | |||
{ | |||
_bitset.reset(); | |||
} | |||
template<typename T_settings> | |||
template<typename T_other> | |||
inline bool bitset<T_settings> | |||
::contains(const T_other& other) const noexcept | |||
{ | |||
return (_bitset & other._bitset) == _bitset; | |||
} | |||
template<typename T_settings> | |||
template<typename T_component_tag> | |||
inline bool bitset<T_settings> | |||
::has_component(T_component_tag ct) const | |||
{ | |||
return _bitset.test(component_id(ct)); | |||
} | |||
template<typename T_settings> | |||
template<typename T_component_tag> | |||
inline void bitset<T_settings> | |||
::set_component(T_component_tag ct, bool value) | |||
{ | |||
_bitset.set(component_id(ct), value); | |||
} | |||
} } } |
@@ -2,54 +2,50 @@ | |||
#include <mutex> | |||
#include <condition_variable> | |||
#include <ecs/config.h> | |||
beg_namespace_ecs_core_utils | |||
{ | |||
namespace ecs { | |||
namespace core { | |||
namespace utils { | |||
/** | |||
* counter that blocks a given operation until it is equal zero | |||
*/ | |||
struct counter_blocker | |||
{ | |||
private: | |||
std::mutex _mutex; | |||
std::condition_variable _cond_var; | |||
size_t _counter; | |||
std::mutex _mutex; //!< mutex to preotect the counter | |||
std::condition_variable _cond_var; //!< conditional variable to synchronize the counter | |||
size_t _counter; //!< the actual counter value | |||
public: | |||
inline counter_blocker(size_t counter) noexcept | |||
: _counter(counter) | |||
{ } | |||
inline void increment() noexcept | |||
{ | |||
std::lock_guard lock(_mutex); | |||
assert(_counter > 0); | |||
++_counter; | |||
} | |||
inline void decrement_and_notify_one() noexcept | |||
{ | |||
std::lock_guard lock(_mutex); | |||
assert(_counter > 0); | |||
--_counter; | |||
_cond_var.notify_one(); | |||
} | |||
inline void decrement_and_notify_all() noexcept | |||
{ | |||
std::lock_guard lock(_mutex); | |||
assert(_counter > 0); | |||
--_counter; | |||
_cond_var.notify_all(); | |||
} | |||
/** | |||
* constructor | |||
* | |||
* @param counter initial counter value | |||
*/ | |||
inline counter_blocker(size_t counter) noexcept; | |||
/** | |||
* increment the counter value by one | |||
*/ | |||
inline void increment() noexcept; | |||
/** | |||
* decrement the counter value by one and notify all pending threads | |||
*/ | |||
inline void decrement() noexcept; | |||
/** | |||
* execute the given function and wait until the counter is equal to zero | |||
* | |||
* @tparam T_func type of the function to execute | |||
* | |||
* @param func function to execute | |||
*/ | |||
template<typename T_func> | |||
inline void execute_and_wait_until_zero(T_func&& func) noexcept | |||
{ | |||
func(); | |||
std::unique_lock lock(_mutex); | |||
_cond_var.wait(lock, [this]{ return (_counter == 0); }); | |||
} | |||
inline void execute_and_wait_until_zero(T_func&& func) noexcept; | |||
}; | |||
} | |||
end_namespace_ecs_core_utils | |||
} } } |
@@ -0,0 +1,40 @@ | |||
#pragma once | |||
#include <ecs/core/utils/counter_blocker.h> | |||
namespace ecs { | |||
namespace core { | |||
namespace utils { | |||
inline counter_blocker | |||
::counter_blocker(size_t counter) noexcept | |||
: _counter(counter) | |||
{ } | |||
inline void counter_blocker | |||
::increment() noexcept | |||
{ | |||
std::lock_guard lock(_mutex); | |||
assert(_counter > 0); | |||
++_counter; | |||
} | |||
inline void counter_blocker | |||
::decrement() noexcept | |||
{ | |||
std::lock_guard lock(_mutex); | |||
assert(_counter > 0); | |||
--_counter; | |||
_cond_var.notify_all(); | |||
} | |||
template<typename T_func> | |||
inline void counter_blocker | |||
::execute_and_wait_until_zero(T_func&& func) noexcept | |||
{ | |||
func(); | |||
std::unique_lock lock(_mutex); | |||
_cond_var.wait(lock, [this]{ return (_counter == 0); }); | |||
} | |||
} } } |
@@ -4,9 +4,16 @@ | |||
#include "./storage_cast.h" | |||
beg_namespace_ecs_core_utils | |||
{ | |||
namespace ecs { | |||
namespace core { | |||
namespace utils { | |||
/** | |||
* functor to store a function of a fixed size | |||
* | |||
* @tparam T_signature signature of the functor | |||
* @tparam T_storage_size max size of the functor | |||
*/ | |||
template<typename T_signature, size_t T_storage_size = 64> | |||
struct fixed_function; | |||
@@ -25,122 +32,88 @@ beg_namespace_ecs_core_utils | |||
private: | |||
union | |||
{ | |||
storage_type _storage; | |||
function_ptr_type _function_ptr; | |||
storage_type _storage; //!< memory to store the functor | |||
function_ptr_type _function_ptr; //!< normal function pointer | |||
}; | |||
method_type _method_ptr; | |||
allocator_type _allocator_ptr; | |||
method_type _method_ptr; //!< pointer to the function to call | |||
allocator_type _allocator_ptr; //!< pointer to the function to allocate memory with | |||
private: | |||
void move_from_other(fixed_function& other) noexcept | |||
{ | |||
assert(this != &o); | |||
// cleanup | |||
if (_allocator_ptr) | |||
{ | |||
_allocator_ptr(&_storage, nullptr); | |||
} | |||
_allocator_ptr = nullptr; | |||
_function_ptr = nullptr; | |||
// move | |||
_method_ptr = other._method_ptr; | |||
other._method_ptr = nullptr; | |||
_function_ptr = other._function_ptr; | |||
_allocator_ptr = other._allocator_ptr; | |||
if (_allocator_ptr) | |||
{ | |||
_allocator_ptr(&_storage, &other._storage); | |||
} | |||
} | |||
/** | |||
* move the data from the passed object to this object | |||
* | |||
* @param other object to move data from | |||
*/ | |||
inline void move_from_other(fixed_function& other) noexcept; | |||
public: | |||
inline fixed_function() noexcept | |||
: _function_ptr (nullptr) | |||
, _method_ptr (nullptr) | |||
, _allocator_ptr(nullptr) | |||
{ } | |||
/** | |||
* default constructor | |||
*/ | |||
inline fixed_function() noexcept; | |||
/** | |||
* constructor | |||
* | |||
* @tparam T_func type of the functor to store | |||
* | |||
* @param func functor to call | |||
*/ | |||
template<typename T_func> | |||
inline fixed_function(T_func&& func) noexcept | |||
: fixed_function() | |||
{ | |||
using unref_type = std::remove_reference_t<T_func>; | |||
static_assert( | |||
sizeof(unref_type) < storage_size, | |||
"functional object doesn't fit into internal storage"); | |||
static_assert( | |||
std::is_move_constructible<unref_type> { }, | |||
"should be move constructable"); | |||
_method_ptr = [](const storage_type* s, function_ptr_type, T_args... args) | |||
{ | |||
return storage_cast<const unref_type>(s)->operator()(args...); | |||
}; | |||
_allocator_ptr = [](storage_type* s, void* obj) | |||
{ | |||
if (obj) | |||
{ | |||
new(s) unref_type(std::move(*static_cast<unref_type*>(obj))); | |||
} | |||
else | |||
{ | |||
storage_cast<unref_type>(s)->~unref_type(); | |||
} | |||
}; | |||
_allocator_ptr(&_storage, &func); | |||
} | |||
inline fixed_function(T_func&& func) noexcept; | |||
/** | |||
* constructor | |||
* | |||
* @tparam TF_return return type of the function pointer | |||
* @tparam TF_args argument types of the function parameters | |||
* | |||
* @param func function pointer to call | |||
*/ | |||
template<typename TF_return, typename... TF_args> | |||
inline fixed_function(TF_return (*func)(TF_args...)) noexcept | |||
: fixed_function() | |||
{ | |||
_function_ptr = func; | |||
_method_ptr = [](const storage_type*, function_ptr_type f, T_args... args) | |||
{ | |||
return static_cast<decltype(func)>(f)(args...); | |||
}; | |||
} | |||
inline fixed_function(fixed_function&& other) noexcept | |||
: fixed_function() | |||
{ move_from_other(other); } | |||
fixed_function(const fixed_function&) = delete; | |||
inline ~fixed_function() noexcept | |||
{ | |||
if (_allocator_ptr) | |||
{ | |||
_allocator_ptr(&_storage, nullptr); | |||
} | |||
_allocator_ptr = nullptr; | |||
_function_ptr = nullptr; | |||
_method_ptr = nullptr; | |||
} | |||
inline fixed_function& operator=(fixed_function&& other) noexcept | |||
{ | |||
move_from_other(other); | |||
return *this; | |||
} | |||
inline fixed_function(TF_return (*func)(TF_args...)) noexcept; | |||
/** | |||
* move constructor | |||
*/ | |||
inline fixed_function(fixed_function&& other) noexcept; | |||
/** | |||
* copy constructor | |||
*/ | |||
inline fixed_function(const fixed_function&) = delete; | |||
/** | |||
* destructor | |||
*/ | |||
inline ~fixed_function() noexcept; | |||
/** | |||
* move assignment operator | |||
* | |||
* @param other object to assign | |||
*/ | |||
inline fixed_function& operator=(fixed_function&& other) noexcept; | |||
/** | |||
* copy assignment operator | |||
* | |||
* @return reference to this object | |||
*/ | |||
fixed_function& operator=(const fixed_function&) = delete; | |||
/** | |||
* execution operator | |||
* | |||
* @tparam TF_args argument types to pass to the stored function | |||
* | |||
* @param args arguments to pass to the stored function | |||
* | |||
* @return return value of the stored function | |||
*/ | |||
template<typename... TF_args> | |||
inline decltype(auto) operator()(TF_args&&... args) const | |||
{ | |||
assert(_method_ptr != nullptr); | |||
return _method_ptr(&_storage, _function_ptr, std::forward<TF_args>(args)...); | |||
} | |||
inline decltype(auto) operator()(TF_args&&... args) const; | |||
}; | |||
} | |||
end_namespace_ecs_core_utils | |||
} } } |
@@ -0,0 +1,129 @@ | |||
#pragma once | |||
#include <cassert> | |||
#include <ecs/core/utils/fixed_function.h> | |||
namespace ecs { | |||
namespace core { | |||
namespace utils { | |||
template<typename T_return, typename... T_args, size_t T_storage_size> | |||
void fixed_function<T_return(T_args...), T_storage_size> | |||
::move_from_other(fixed_function& other) noexcept | |||
{ | |||
assert(this != &other); | |||
// cleanup | |||
if (_allocator_ptr) | |||
{ | |||
_allocator_ptr(&_storage, nullptr); | |||
} | |||
_allocator_ptr = nullptr; | |||
_function_ptr = nullptr; | |||
// move | |||
_method_ptr = other._method_ptr; | |||
other._method_ptr = nullptr; | |||
_function_ptr = other._function_ptr; | |||
_allocator_ptr = other._allocator_ptr; | |||
if (_allocator_ptr) | |||
{ | |||
_allocator_ptr(&_storage, &other._storage); | |||
} | |||
} | |||
template<typename T_return, typename... T_args, size_t T_storage_size> | |||
inline fixed_function<T_return(T_args...), T_storage_size> | |||
::fixed_function() noexcept | |||
: _function_ptr (nullptr) | |||
, _method_ptr (nullptr) | |||
, _allocator_ptr(nullptr) | |||
{ } | |||
template<typename T_return, typename... T_args, size_t T_storage_size> | |||
template<typename T_func> | |||
inline fixed_function<T_return(T_args...), T_storage_size> | |||
::fixed_function(T_func&& func) noexcept | |||
: fixed_function() | |||
{ | |||
using unref_type = std::remove_reference_t<T_func>; | |||
static_assert( | |||
sizeof(unref_type) < storage_size, | |||
"functional object doesn't fit into internal storage"); | |||
static_assert( | |||
std::is_move_constructible<unref_type> { }, | |||
"should be move constructable"); | |||
_method_ptr = [](const storage_type* s, function_ptr_type, T_args... args) | |||
{ | |||
return storage_cast<const unref_type>(s)->operator()(args...); | |||
}; | |||
_allocator_ptr = [](storage_type* s, void* obj) | |||
{ | |||
if (obj) | |||
{ | |||
new(s) unref_type(std::move(*static_cast<unref_type*>(obj))); | |||
} | |||
else | |||
{ | |||
storage_cast<unref_type>(s)->~unref_type(); | |||
} | |||
}; | |||
_allocator_ptr(&_storage, &func); | |||
} | |||
template<typename T_return, typename... T_args, size_t T_storage_size> | |||
template<typename TF_return, typename... TF_args> | |||
inline fixed_function<T_return(T_args...), T_storage_size> | |||
::fixed_function(TF_return (*func)(TF_args...)) noexcept | |||
: fixed_function() | |||
{ | |||
_function_ptr = func; | |||
_method_ptr = [](const storage_type*, function_ptr_type f, T_args... args) | |||
{ | |||
return static_cast<decltype(func)>(f)(args...); | |||
}; | |||
} | |||
template<typename T_return, typename... T_args, size_t T_storage_size> | |||
inline fixed_function<T_return(T_args...), T_storage_size> | |||
::fixed_function(fixed_function&& other) noexcept | |||
: fixed_function() | |||
{ move_from_other(other); } | |||
template<typename T_return, typename... T_args, size_t T_storage_size> | |||
inline fixed_function<T_return(T_args...), T_storage_size> | |||
::~fixed_function() noexcept | |||
{ | |||
if (_allocator_ptr) | |||
{ | |||
_allocator_ptr(&_storage, nullptr); | |||
} | |||
_allocator_ptr = nullptr; | |||
_function_ptr = nullptr; | |||
_method_ptr = nullptr; | |||
} | |||
template<typename T_return, typename... T_args, size_t T_storage_size> | |||
inline fixed_function<T_return(T_args...), T_storage_size>& fixed_function<T_return(T_args...), T_storage_size> | |||
::operator=(fixed_function&& other) noexcept | |||
{ | |||
move_from_other(other); | |||
return *this; | |||
} | |||
template<typename T_return, typename... T_args, size_t T_storage_size> | |||
template<typename... TF_args> | |||
inline decltype(auto) fixed_function<T_return(T_args...), T_storage_size> | |||
::operator()(TF_args&&... args) const | |||
{ | |||
assert(_method_ptr != nullptr); | |||
return _method_ptr(&_storage, _function_ptr, std::forward<TF_args>(args)...); | |||
} | |||
} } } |
@@ -2,9 +2,15 @@ | |||
#include <ecs/config.h> | |||
beg_namespace_ecs_core_utils | |||
{ | |||
namespace ecs { | |||
namespace core { | |||
namespace utils { | |||
/** | |||
* atomic variable that implements the move constructor and the move assignment operator | |||
* | |||
* @tparam T inner type to store in the atomic | |||
*/ | |||
template<typename T> | |||
struct movable_atomic final | |||
: std::atomic<T> | |||
@@ -15,29 +21,46 @@ beg_namespace_ecs_core_utils | |||
public: | |||
using base_type::base_type; | |||
movable_atomic() = default; | |||
/** | |||
* default constructor | |||
*/ | |||
inline movable_atomic() = default; | |||
movable_atomic(const movable_atomic&) = delete; | |||
/** | |||
* copy constructor | |||
*/ | |||
inline movable_atomic(const movable_atomic&) = delete; | |||
movable_atomic(movable_atomic&& other) noexcept | |||
/** | |||
* move constructor | |||
*/ | |||
inline movable_atomic(movable_atomic&& other) noexcept | |||
: base_type(other.load()) | |||
{ } | |||
movable_atomic& operator=(const movable_atomic&) = delete; | |||
/** | |||
* copy assignment operator | |||
*/ | |||
inline movable_atomic& operator=(const movable_atomic&) = delete; | |||
movable_atomic& operator=(movable_atomic&& other) noexcept | |||
/** | |||
* move assignment operator | |||
*/ | |||
inline movable_atomic& operator=(movable_atomic&& other) noexcept | |||
{ | |||
this->store(other.load()); | |||
return *this; | |||
} | |||
/** | |||
* assignment constructor to assign integral constants | |||
*/ | |||
template<T value> | |||
movable_atomic& operator=(std::integral_constant<T, value> x) noexcept | |||
inline movable_atomic& operator=(std::integral_constant<T, value> x) noexcept | |||
{ | |||
this->store(decltype(x)::value); | |||
return *this; | |||
} | |||
}; | |||
} | |||
end_namespace_ecs_core_utils | |||
} } } |
@@ -0,0 +1,186 @@ | |||
#pragma once | |||
#include <vector> | |||
#include <ecs/config.h> | |||
namespace ecs { | |||
namespace core { | |||
namespace utils { | |||
/** | |||
* vector with ordered elements | |||
*/ | |||
template< | |||
typename T_value, | |||
typename T_allocator = std::allocator<T_value>, | |||
typename T_compare = std::less<T_value>> | |||
struct ordered_vector | |||
{ | |||
public: | |||
using value_type = T_value; | |||
using allocator_type = T_allocator; | |||
using compare_type = T_compare; | |||
using this_type = ordered_vector<value_type, allocator_type, compare_type>; | |||
using vector_type = std::vector<value_type, allocator_type>; | |||
using size_type = typename vector_type::size_type; | |||
using difference_type = typename vector_type::difference_type; | |||
using reference = typename vector_type::reference; | |||
using const_reference = typename vector_type::const_reference; | |||
using pointer = typename vector_type::pointer; | |||
using const_pointer = typename vector_type::const_pointer; | |||
using iterator = typename vector_type::iterator; | |||
using const_iterator = typename vector_type::const_iterator; | |||
using reverse_iterator = typename vector_type::reverse_iterator; | |||
using const_reverse_iterator = typename vector_type::const_reverse_iterator; | |||
private: | |||
vector_type _items; | |||
compare_type _compare; | |||
public: | |||
/* constructor */ | |||
ordered_vector() = default; | |||
ordered_vector(const ordered_vector&) = default; | |||
ordered_vector& operator=(const ordered_vector&) = default; | |||
ordered_vector(ordered_vector&&) = default; | |||
ordered_vector& operator=(ordered_vector&&) = default; | |||
template<typename... T_args> | |||
inline ordered_vector(T_args&&... args, const compare_type& p_compare = compare_type()) | |||
: _items (std::forward<T_args>(args)...) | |||
, _compare (p_compare) | |||
{ } | |||
/* access */ | |||
inline reference operator[](size_type pos) | |||
noexcept(noexcept(_items.operator[](pos))) | |||
{ return _items[pos]; } | |||
inline const_reference operator[](size_type pos) const | |||
noexcept(noexcept(_items.operator[](pos))) | |||
{ return _items[pos]; } | |||
inline reference at(size_type pos) | |||
noexcept(noexcept(_items.at(pos))) | |||
{ return _items.at(pos); } | |||
inline const_reference at(size_type pos) const | |||
noexcept(noexcept(_items.at(pos))) | |||
{ return _items.at(pos); } | |||
/* iterators */ | |||
inline iterator begin() | |||
noexcept(noexcept(_items.begin())) | |||
{ return _items.begin(); } | |||
inline const_iterator begin() const | |||
noexcept(noexcept(_items.begin())) | |||
{ return _items.begin(); } | |||
inline const_iterator cbegin() const | |||
noexcept(noexcept(_items.cbegin())) | |||
{ return _items.cbegin(); } | |||
inline iterator end() | |||
noexcept(noexcept(_items.end())) | |||
{ return _items.end(); } | |||
inline const_iterator end() const | |||
noexcept(noexcept(_items.end())) | |||
{ return _items.end(); } | |||
inline const_iterator cend() const | |||
noexcept(noexcept(_items.cend())) | |||
{ return _items.cend(); } | |||
inline iterator rbegin() | |||
noexcept(noexcept(_items.rbegin())) | |||
{ return _items.rbegin(); } | |||
inline const_iterator rbegin() const | |||
noexcept(noexcept(_items.rbegin())) | |||
{ return _items.rbegin(); } | |||
inline const_iterator crbegin() const | |||
noexcept(noexcept(_items.crbegin())) | |||
{ return _items.crbegin(); } | |||
inline iterator rend() | |||
noexcept(noexcept(_items.rend())) | |||
{ return _items.rend(); } | |||
inline const_iterator rend() const | |||
noexcept(noexcept(_items.rend())) | |||
{ return _items.rend(); } | |||
inline const_iterator crend() const | |||
noexcept(noexcept(_items.crend())) | |||
{ return _items.crend(); } | |||
/* capacity */ | |||
inline bool empty() const | |||
noexcept(noexcept(_items.empty())) | |||
{ return _items.empty(); } | |||
inline size_type size() const | |||
noexcept(noexcept(_items.size())) | |||
{ return _items.size(); } | |||
inline size_type max_size() const | |||
noexcept(noexcept(_items.size())) | |||
{ return _items.max_size(); } | |||
inline size_type capacity() const | |||
noexcept(noexcept(_items.capacity())) | |||
{ return _items.capacity(); } | |||
inline void reserve(size_type s) const | |||
noexcept(noexcept(_items.reserve(s))) | |||
{ _items.reserve(s); } | |||
inline void shrink_to_fit() const | |||
noexcept(noexcept(_items.shrink_to_fit())) | |||
{ _items.shrink_to_fit(); } | |||
inline decltype(auto) insert(const value_type& value) | |||
{ | |||
auto it = std::lower_bound(begin(), end(), value); | |||
auto is_new = _compare(value, *it); | |||
if (it == end() || is_new) | |||
_items.insert(it, value); | |||
return std::make_pair(it, is_new); | |||
} | |||
inline decltype(auto) insert(value_type&& value) | |||
{ | |||
auto it = std::lower_bound(begin(), end(), value, _compare); | |||
auto is_new = (it != end() && _compare(value, *it)); | |||
if (it == end() || is_new) | |||
_items.insert(it, std::move(value)); | |||
return std::make_pair(it, is_new); | |||
} | |||
inline decltype(auto) find(const value_type& value) const | |||
{ | |||
auto it = std::lower_bound(begin(), end(), value, _compare); | |||
return it == end() || _compare(value, *it) | |||
? end() | |||
: it; | |||
} | |||
inline bool contains(const value_type& value) const | |||
{ return find(value) != end(); } | |||
template<typename... T_args> | |||
constexpr decltype(auto) erase(T_args&&... args) | |||
{ return _items.erase(std::forward<T_args>(args)...); } | |||
}; | |||
} } } |
@@ -7,28 +7,52 @@ | |||
auto scope_guard_ ## __LINE__ ( \ | |||
::ecs::core::utils::make_scope_guard(__VA_ARGS__)) | |||
beg_namespace_ecs_core_utils | |||
{ | |||
namespace ecs { | |||
namespace core { | |||
namespace utils { | |||
/** | |||
* guard that executes the given function if the its scope is left | |||
* | |||
* @tparam T_func functor type to execute | |||
*/ | |||
template<typename T_func> | |||
struct scope_guard final | |||
: T_func | |||
{ | |||
template<typename... Xs> | |||
inline scope_guard(Xs&&... xs) | |||
/** | |||
* constructor | |||
* | |||
* @tparam T_args argument types to initialize the functor with | |||
* | |||
* @param args arguments to initialize the functor with | |||
*/ | |||
template<typename... T_args> | |||
inline scope_guard(T_args&&... args) | |||
noexcept(std::is_nothrow_constructible<T_func> { }) | |||
: T_func(std::forward<Xs>(xs)...) | |||
: T_func(std::forward<T_args>(args)...) | |||
{ } | |||
/** | |||
* destructor: will execute the stored functor | |||
*/ | |||
inline ~scope_guard() noexcept( | |||
noexcept(std::declval<T_func>().operator()())) | |||
{ this->operator()(); } | |||
}; | |||
/** | |||
* helper to build a scope guard | |||
* | |||
* @tparam T_func functor type to execute | |||
* | |||
* @param f functor to execute | |||
* | |||
* @return created scope guard | |||
*/ | |||
template<typename T_func> | |||
inline decltype(auto) make_scope_guard(T_func&& f) | |||
noexcept(std::is_nothrow_move_constructible<T_func> { }) | |||
{ return scope_guard<mp::decay_t<T_func>>(std::forward<T_func>(f)); } | |||
} | |||
end_namespace_ecs_core_utils | |||
} } } |
@@ -4,9 +4,20 @@ | |||
#include <ecs/core/mp/core/copy_qualifiers.h> | |||
beg_namespace_ecs_core_utils | |||
{ | |||
namespace ecs { | |||
namespace core { | |||
namespace utils { | |||
/** | |||
* cast the given storage to a certain type | |||
* | |||
* @tparam T type to cast storage in | |||
* @tparam T_storage storage type to cast | |||
* | |||
* @param storage storage to cast | |||
* | |||
* @return casted storage | |||
*/ | |||
template <typename T, typename T_storage> | |||
inline constexpr decltype(auto) storage_cast(T_storage* storage) noexcept | |||
{ | |||
@@ -25,5 +36,4 @@ beg_namespace_ecs_core_utils | |||
} | |||
} | |||
end_namespace_ecs_core_utils | |||
} } } |
@@ -2,4 +2,7 @@ | |||
#include "./thread_pool/pool.h" | |||
#include "./thread_pool/types.h" | |||
#include "./thread_pool/worker.h" | |||
#include "./thread_pool/worker.h" | |||
#include "./thread_pool/pool.inl" | |||
#include "./thread_pool/worker.inl" |
@@ -1,13 +1,19 @@ | |||
#pragma once | |||
#include <ecs/config.h> | |||
#include <atomic> | |||
#include <vector> | |||
#include "./worker.h" | |||
#include "./types.h" | |||
#include <ecs/config.h> | |||
#include <ecs/core/utils/thread_pool/types.h> | |||
#include <ecs/core/utils/thread_pool/worker.h> | |||
beg_namespace_ecs_core_utils | |||
{ | |||
namespace ecs { | |||
namespace core { | |||
namespace utils { | |||
/** | |||
* this class implements a thread pool | |||
*/ | |||
struct thread_pool | |||
{ | |||
private: | |||
@@ -15,75 +21,47 @@ beg_namespace_ecs_core_utils | |||
using atomic_size_t = std::atomic<size_t>; | |||
private: | |||
task_queue _queue; | |||
worker_vector _workers; | |||
atomic_size_t _outstanding_inits; | |||
auto all_workers_finished() const noexcept | |||
{ | |||
for (const auto& w : _workers) | |||
{ | |||
if (!w.finished()) | |||
{ | |||
return false; | |||
} | |||
} | |||
return true; | |||
} | |||
inline void post_dummy_task() | |||
{ post([]{ }); } | |||
void initialize_workers(size_t count) | |||
{ | |||
_workers.reserve(count); | |||
for (size_t i = 0; i < count; ++i) | |||
{ | |||
_workers.emplace_back(_queue); | |||
} | |||
_outstanding_inits = count; | |||
for (auto& w : _workers) | |||
{ | |||
w.start(_outstanding_inits); | |||
} | |||
} | |||
task_queue _queue; //!< queue to store tasks to execute | |||
worker_vector _workers; //!< vector of worker threads | |||
atomic_size_t _outstanding_inits; //!< number of outstanding worker initializations | |||
/** | |||
* check if all workers are finished or not | |||
* | |||
* @retval TRUE if all workers are finished | |||
* @retval FALSE if at least one worker is running | |||
*/ | |||
auto all_workers_finished() const noexcept; | |||
/** | |||
* initialize worker threads | |||
* | |||
* @param count number of workers to create | |||
*/ | |||
void initialize_workers(size_t count); | |||
public: | |||
inline thread_pool(size_t count) | |||
{ initialize_workers(count); } | |||
~thread_pool() | |||
{ | |||
// wait for uninitialized workers | |||
while (_outstanding_inits > 0) | |||
{ | |||
std::this_thread::sleep_for(std::chrono::milliseconds(50)); | |||
} | |||
// stop all workers | |||
for (auto& w : _workers) | |||
{ | |||
w.stop(); | |||
} | |||
// post dummy tasks untill all workers has stopped | |||
while (!all_workers_finished()) | |||
{ | |||
post_dummy_task(); | |||
} | |||
// join the worker threads | |||
for (auto& w : _workers) | |||
{ | |||
w.join(); | |||
} | |||
} | |||
template<typename T_func> | |||
inline void post(T_func&& func) | |||
{ _queue.enqueue(std::forward<T_func>(func)); } | |||
/** | |||
* constructor | |||
* | |||
* @param count number of workers to create | |||
*/ | |||
thread_pool(size_t count); | |||
/** | |||
* destructor | |||
*/ | |||
~thread_pool(); | |||
/** | |||
* enqueue a new task inside the thread pool | |||
* | |||
* @tparam T_task type of the task | |||
* | |||
* @param task task to execute | |||
*/ | |||
template<typename T_task> | |||
inline void post(T_task&& task); | |||
}; | |||
} | |||
end_namespace_ecs_core_utils | |||
} } } |
@@ -0,0 +1,16 @@ | |||
#pragma once | |||
#include <ecs/core/utils/thread_pool/pool.h> | |||
namespace ecs { | |||
namespace core { | |||
namespace utils { | |||
template<typename T_task> | |||
inline void thread_pool | |||
::post(T_task&& task) | |||
{ | |||
_queue.enqueue(std::forward<T_task>(task)); | |||
} | |||
} } } |
@@ -5,11 +5,18 @@ | |||
#include "../fixed_function.h" | |||
beg_namespace_ecs_core_utils | |||
{ | |||
namespace ecs { | |||
namespace core { | |||
namespace utils { | |||
using task = fixed_function<void(), 128>; | |||
using task_queue = moodycamel::BlockingConcurrentQueue<task>; | |||
/** | |||
* Functor to execute as task inside the thread pool. The functor can have a max size of 128 bytes! | |||
*/ | |||
using task = fixed_function<void(), 128>; | |||
} | |||
end_namespace_ecs_core_utils | |||
/** | |||
* non blocking concurrent queue to store thread pool tasks in | |||
*/ | |||
using task_queue = moodycamel::BlockingConcurrentQueue<task>; | |||
} } } |
@@ -6,78 +6,81 @@ | |||
#include "./types.h" | |||
#include "../movable_atomic.h" | |||
beg_namespace_ecs_core_utils | |||
{ | |||
namespace ecs { | |||
namespace core { | |||
namespace utils { | |||
/** | |||
* worker thread to execute tasks of thread pool in | |||
*/ | |||
struct thread_pool_worker | |||
{ | |||
private: | |||
/** | |||
* state of the worker | |||
*/ | |||
enum class state | |||
{ | |||
uninizialized, | |||
running, | |||
stopped, | |||
finished, | |||
uninizialized, //!< the thread was not initialized yes | |||
running, //!< the thread is running normally | |||
stopped, //!< the thread was intended to stop execution | |||
finished, //!< the thread has stopped execution | |||
}; | |||
using atomic_state = movable_atomic<state>; | |||
std::thread _thread; | |||
task_queue& _queue; | |||
atomic_state _state; | |||
std::thread _thread; //!< actual thread object to use for execution | |||
task_queue& _queue; //!< queue to poll new tasks from | |||
atomic_state _state; //!< current state of the worker | |||
private: | |||
void run() | |||
{ | |||
_state = state::running; | |||
while (_state == state::running) | |||
{ | |||
task t; | |||
if (_queue.wait_dequeue_timed(t, std::chrono::milliseconds(500))) | |||
{ | |||
t(); | |||
} | |||
} | |||
_state = state::finished; | |||
} | |||
/** | |||
* thread worker method | |||
*/ | |||
void run(); | |||
public: | |||
thread_pool_worker(task_queue& queue) noexcept | |||
: _queue(queue) | |||
{ } | |||
thread_pool_worker(thread_pool_worker&&) = default; | |||
thread_pool_worker(const thread_pool_worker&) = delete; | |||
thread_pool_worker& operator=(thread_pool_worker&&) = default; | |||
thread_pool_worker& operator=(const thread_pool_worker&) = delete; | |||
/** | |||
* constructor | |||
* | |||
* @param queue task queue to poll tasks from | |||
*/ | |||
inline thread_pool_worker(task_queue& queue) noexcept; | |||
inline thread_pool_worker(thread_pool_worker&&) = default; | |||
inline thread_pool_worker(const thread_pool_worker&) = delete; | |||
inline thread_pool_worker& operator=(thread_pool_worker&&) = default; | |||
inline thread_pool_worker& operator=(const thread_pool_worker&) = delete; | |||
/** | |||
* start the worker | |||
* | |||
* @tparam T_counter type of the counter | |||
* | |||
* @param remaining_inits number of remaining thread initialization (is decremented by this thread) | |||
*/ | |||
template<typename T_counter> | |||
inline void start(T_counter& remaining_inits) | |||
{ | |||
_thread = std::thread([this, &remaining_inits]{ | |||
--remaining_inits; | |||
run(); | |||
}); | |||
} | |||
inline void stop() noexcept | |||
{ | |||
assert(_state == state::running); | |||
_state = state::stopped; | |||
} | |||
inline void join() noexcept | |||
{ | |||
assert(_thread.joinable()); | |||
assert(_state == state::finished); | |||
_thread.join(); | |||
} | |||
inline bool finished() const noexcept | |||
{ return _state == state::finished; } | |||
inline void start(T_counter& remaining_inits); | |||
/** | |||
* stop the thread execution | |||
*/ | |||
inline void stop() noexcept; | |||
/** | |||
* wait for the thread to finish | |||
*/ | |||
inline void join() noexcept; | |||
/** | |||
* check if the thread has stopped execution | |||
* | |||
* @retval TRUE if the thread has stopped execution | |||
* @retval FALSE if the thread is still running | |||
*/ | |||
inline bool finished() const noexcept; | |||
}; | |||
} | |||
end_namespace_ecs_core_utils | |||
} } } |
@@ -0,0 +1,46 @@ | |||
#pragma once | |||
#include <ecs/core/utils/thread_pool/worker.h> | |||
namespace ecs { | |||
namespace core { | |||
namespace utils { | |||
inline thread_pool_worker | |||
::thread_pool_worker(task_queue& queue) noexcept | |||
: _queue(queue) | |||
{ } | |||
template<typename T_counter> | |||
inline void thread_pool_worker | |||
::start(T_counter& remaining_inits) | |||
{ | |||
_thread = std::thread([this, &remaining_inits]{ | |||
--remaining_inits; | |||
run(); | |||
}); | |||
} | |||
inline void thread_pool_worker | |||
::stop() noexcept | |||
{ | |||
assert(_state == state::running); | |||
_state = state::stopped; | |||
} | |||
inline void thread_pool_worker | |||
::join() noexcept | |||
{ | |||
assert(_thread.joinable()); | |||
assert(_state == state::finished); | |||
_thread.join(); | |||
} | |||
inline bool thread_pool_worker | |||
::finished() const noexcept | |||
{ | |||
return _state == state::finished; | |||
} | |||
} } } |
@@ -1,5 +1,9 @@ | |||
#pragma once | |||
#include "./settings/entity_storage.h" | |||
#include "./settings/refresh_parallelism.h" | |||
#include "./settings/scheduler.h" | |||
#include "./settings/settings.h" | |||
#include "./settings/system_storage.h" | |||
#include "./settings/system_storage.h" | |||
#include "./settings/settings.inl" |
@@ -3,25 +3,25 @@ | |||
#include <ecs/config.h> | |||
#include <ecs/core/entity/storage/dynamic.h> | |||
beg_namespace_ecs_settings_entity_storage | |||
{ | |||
namespace ecs { | |||
namespace settings { | |||
namespace entity_storage { | |||
namespace __impl | |||
namespace detail | |||
{ | |||
template<size_t T_size> | |||
struct dynamic_builder_t | |||
{ | |||
template<typename T_settings, typename T_chunk_meta_data> | |||
constexpr decltype(auto) operator()(T_settings settings, T_chunk_meta_data) const | |||
template<typename T_settings, typename T_storage_meta_data> | |||
constexpr decltype(auto) operator()(T_settings settings, T_storage_meta_data) const | |||
{ | |||
using chunk_meta_data_type = core::mp::unwrap_t<T_chunk_meta_data>; | |||
return core::entity::storage::dynamic<T_settings, chunk_meta_data_type>(T_size); | |||
using storage_meta_data_type = core::mp::unwrap_t<T_storage_meta_data>; | |||
return core::entity::storage::dynamic<T_settings, storage_meta_data_type>(T_size); | |||
} | |||
}; | |||
} | |||
template<size_t T_size> | |||
constexpr decltype(auto) dynamic = __impl::dynamic_builder_t<T_size> { }; | |||
constexpr decltype(auto) dynamic = detail::dynamic_builder_t<T_size> { }; | |||
} | |||
end_namespace_ecs_settings_entity_storage | |||
} } } |
@@ -3,25 +3,25 @@ | |||
#include <ecs/config.h> | |||
#include <ecs/core/entity/storage/fixed.h> | |||
beg_namespace_ecs_settings_entity_storage | |||
{ | |||
namespace ecs { | |||
namespace settings { | |||
namespace entity_storage { | |||
namespace __impl | |||
namespace detail | |||
{ | |||
template<size_t T_size> | |||
struct fixed_builder_t | |||
{ | |||
template<typename T_settings, typename T_chunk_meta_data> | |||
constexpr decltype(auto) operator()(T_settings settings, T_chunk_meta_data) const | |||
template<typename T_settings, typename T_storage_meta_data> | |||
constexpr decltype(auto) operator()(T_settings settings, T_storage_meta_data) const | |||
{ | |||
using chunk_meta_data_type = core::mp::unwrap_t<T_chunk_meta_data>; | |||
return core::entity::storage::fixed<T_settings, chunk_meta_data_type, T_size>(); | |||
using storage_meta_data_type = core::mp::unwrap_t<T_storage_meta_data>; | |||
return core::entity::storage::fixed<T_settings, storage_meta_data_type, T_size>(); | |||
} | |||
}; | |||
} | |||
template<size_t T_size> | |||
constexpr decltype(auto) fixed = __impl::fixed_builder_t<T_size> { }; | |||
constexpr decltype(auto) fixed = detail::fixed_builder_t<T_size> { }; | |||
} | |||
end_namespace_ecs_settings_entity_storage | |||
} } } |
@@ -2,12 +2,12 @@ | |||
#include <ecs/config.h> | |||
beg_namespace_ecs_settings_refresh_parallelism | |||
{ | |||
namespace ecs { | |||
namespace settings { | |||
namespace refresh_parallelism { | |||
constexpr decltype(auto) enable = hana::true_c; | |||
constexpr decltype(auto) disable = hana::false_c; | |||
} | |||
end_namespace_ecs_settings_refresh_parallelism | |||
} } } |
@@ -3,12 +3,13 @@ | |||
#include <ecs/config.h> | |||
#include <ecs/core/system/scheduler/atomic_counter.h> | |||
beg_namespace_ecs_settings_scheduler | |||
{ | |||
namespace ecs { | |||
namespace settings { | |||
namespace scheduler { | |||
namespace __impl | |||
namespace detail | |||
{ | |||
struct atomic_counter_t | |||
struct atomic_counter_builder_t | |||
{ | |||
template<typename T_settings, typename T_context> | |||
constexpr decltype(auto) operator()(T_settings, T_context&& context) const noexcept | |||
@@ -16,7 +17,6 @@ beg_namespace_ecs_settings_scheduler | |||
}; | |||
} | |||
constexpr decltype(auto) atomic_counter = __impl::atomic_counter_t { }; | |||
constexpr decltype(auto) atomic_counter = detail::atomic_counter_builder_t { }; | |||
} | |||
end_namespace_ecs_settings_scheduler | |||
} } } |
@@ -9,8 +9,8 @@ | |||
#include "./refresh_parallelism.h" | |||
#include "./scheduler.h" | |||
beg_namespace_ecs_settings | |||
{ | |||
namespace ecs { | |||
namespace settings { | |||
namespace keys | |||
{ | |||
@@ -22,86 +22,128 @@ beg_namespace_ecs_settings | |||
constexpr decltype(auto) scheduler = hana::size_c<5>; | |||
} | |||
namespace __impl | |||
namespace detail | |||
{ | |||
/** | |||
* settings of the ecs environment | |||
* | |||
* @tparam T_options option map for the settings | |||
*/ | |||
template<typename T_options> | |||
struct settings_t | |||
{ | |||
private: | |||
template<typename T_key, typename T_value> | |||
constexpr decltype(auto) change(const T_key& key, T_value&& value) const noexcept | |||
{ | |||
auto new_options = T_options { }.set(key, std::forward<T_value>(value)); | |||
return settings_t<core::mp::decay_t<decltype(new_options)>> { }; | |||
} | |||
/** | |||
* change the value of a given key | |||
* | |||
* @tparam T_key key type to change value for | |||
* @tparam T_value type of the new value | |||
* | |||
* @param key key to change the value for | |||
* @param value new value | |||
* | |||
* @return updated settings | |||
*/ | |||
template<typename T_key, typename T_value> | |||
constexpr decltype(auto) change(const T_key& key, T_value&& value) const noexcept; | |||
/** | |||
* get the value of a given option key | |||
* | |||
* @tparam T_key key type to get the value for | |||
* | |||
* @param key key to get the value for | |||
* | |||
* @return value stored for key | |||
*/ | |||
template<typename T_key> | |||
constexpr decltype(auto) get(const T_key& key) const noexcept | |||
{ return T_options { }.at(key); } | |||
constexpr decltype(auto) get(const T_key& key) const noexcept; | |||
public: /* getter */ | |||
constexpr decltype(auto) component_signatures() const noexcept | |||
{ return get(keys::component_signatures); } | |||
constexpr decltype(auto) system_signatures() const noexcept | |||
{ return get(keys::system_signatures); } | |||
constexpr decltype(auto) system_storage() const noexcept | |||
{ return get(keys::system_storage); } | |||
constexpr decltype(auto) entity_storage() const noexcept | |||
{ return get(keys::entity_storage); } | |||
constexpr decltype(auto) refresh_parallelism() const noexcept | |||
{ return get(keys::refresh_parallelism); } | |||
constexpr decltype(auto) scheduler() const noexcept | |||
{ return get(keys::scheduler); } | |||
/** | |||
* get the list of component signatures | |||
* | |||
* @return list of component signatures | |||
*/ | |||
constexpr decltype(auto) component_signatures() const noexcept; | |||
/** | |||
* get the list of system signatures | |||
* | |||
* @return list of system signatures | |||
*/ | |||
constexpr decltype(auto) system_signatures() const noexcept; | |||
/** | |||
* get the system storeage builder | |||
* | |||
* @return system storage builder | |||
*/ | |||
constexpr decltype(auto) system_storage() const noexcept; | |||
/** | |||
* get the entity storeage builder | |||
* | |||
* @return entity storage builder | |||
*/ | |||
constexpr decltype(auto) entity_storage() const noexcept; | |||
/** | |||
* get the refresh parallelism value | |||
* | |||
* @return refresh parallelism value | |||
*/ | |||
constexpr decltype(auto) refresh_parallelism() const noexcept; | |||
/** | |||
* get the scheduler builder | |||
* | |||
* @return the scheduler builder | |||
*/ | |||
constexpr decltype(auto) scheduler() const noexcept; | |||
public: /* setter */ | |||
template<typename T> | |||
constexpr decltype(auto) component_signatures(T t) const noexcept | |||
{ return change(keys::component_signatures, t); } | |||
template<typename T> | |||
constexpr decltype(auto) system_signatures(T t) const noexcept | |||
{ return change(keys::system_signatures, t); } | |||
template<typename T_value> | |||
constexpr decltype(auto) component_signatures(T_value value) const noexcept; | |||
template<typename T> | |||
constexpr decltype(auto) system_storage(T t) const noexcept | |||
{ return change(keys::system_storage, t); } | |||
template<typename T_value> | |||
constexpr decltype(auto) system_signatures(T_value value) const noexcept; | |||
template<typename T> | |||
constexpr decltype(auto) entity_storage(T t) const noexcept | |||
{ return change(keys::entity_storage, t); } | |||
template<typename T_value> | |||
constexpr decltype(auto) system_storage(T_value value) const noexcept; | |||
template<typename T> | |||
constexpr decltype(auto) refresh_parallelism(T t) const noexcept | |||
{ return change(keys::refresh_parallelism, t); } | |||
template<typename T_value> | |||
constexpr decltype(auto) entity_storage(T_value value) const noexcept; | |||
template<typename T> | |||
constexpr decltype(auto) scheduler(T t) const noexcept | |||
{ return change(keys::scheduler, t); } | |||
template<typename T_value> | |||
constexpr decltype(auto) refresh_parallelism(T_value value) const noexcept; | |||
template<typename T_value> | |||
constexpr decltype(auto) scheduler(T_value value) const noexcept; | |||
}; | |||
/** | |||
* predicate type to build a default settings object | |||
*/ | |||
struct make_t | |||
{ | |||
constexpr decltype(auto) operator()() const noexcept | |||
{ | |||
using namespace ::ecs::core::mp; | |||
auto options = option_map::make() | |||
.add(keys::component_signatures, list::empty) | |||
.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::scheduler, scheduler::atomic_counter); | |||
return settings_t<decay_t<decltype(options)>> { }; | |||
} | |||
/** | |||
* execute the predicate | |||
* | |||
* @return settings object (@ref settings_t) | |||
*/ | |||
constexpr decltype(auto) operator()() const noexcept; | |||
}; | |||
} | |||
constexpr decltype(auto) make = __impl::make_t { }; | |||
/** | |||
* predicate to build a default settings object | |||
*/ | |||
constexpr decltype(auto) make = detail::make_t { }; | |||
} | |||
end_namespace_ecs_settings | |||
} } |
@@ -0,0 +1,134 @@ | |||
#pragma once | |||
#include <ecs/settings/settings.h> | |||
namespace ecs { | |||
namespace settings { | |||
namespace detail { | |||
/* settings_t */ | |||
template<typename T_options> | |||
template<typename T_key, typename T_value> | |||
constexpr decltype(auto) settings_t<T_options> | |||
::change(const T_key& key, T_value&& value) const noexcept | |||
{ | |||
auto new_options = T_options { }.set(key, std::forward<T_value>(value)); | |||
return settings_t<core::mp::decay_t<decltype(new_options)>> { }; | |||
} | |||
template<typename T_options> | |||
template<typename T_key> | |||
constexpr decltype(auto) settings_t<T_options> | |||
::get(const T_key& key) const noexcept | |||
{ | |||
return T_options { }.at(key); | |||
} | |||
template<typename T_options> | |||
constexpr decltype(auto) settings_t<T_options> | |||
::component_signatures() const noexcept | |||
{ | |||
return get(keys::component_signatures); | |||
} | |||
template<typename T_options> | |||
constexpr decltype(auto) settings_t<T_options> | |||
::system_signatures() const noexcept | |||
{ | |||
return get(keys::system_signatures); | |||
} | |||
template<typename T_options> | |||
constexpr decltype(auto) settings_t<T_options> | |||
::system_storage() const noexcept | |||
{ | |||
return get(keys::system_storage); | |||
} | |||
template<typename T_options> | |||
constexpr decltype(auto) settings_t<T_options> | |||
::entity_storage() const noexcept | |||
{ | |||
return get(keys::entity_storage); | |||
} | |||
template<typename T_options> | |||
constexpr decltype(auto) settings_t<T_options> | |||
::refresh_parallelism() const noexcept | |||
{ | |||
return get(keys::refresh_parallelism); | |||
} | |||
template<typename T_options> | |||
constexpr decltype(auto) settings_t<T_options> | |||
::scheduler() const noexcept | |||
{ | |||
return get(keys::scheduler); | |||
} | |||
template<typename T_options> | |||
template<typename T> | |||
constexpr decltype(auto) settings_t<T_options> | |||
::component_signatures(T t) const noexcept | |||
{ | |||
return change(keys::component_signatures, t); | |||
} | |||
template<typename T_options> | |||
template<typename T> | |||
constexpr decltype(auto) settings_t<T_options> | |||
::system_signatures(T t) const noexcept | |||
{ | |||
return change(keys::system_signatures, t); | |||
} | |||
template<typename T_options> | |||
template<typename T> | |||
constexpr decltype(auto) settings_t<T_options> | |||
::system_storage(T t) const noexcept | |||
{ | |||
return change(keys::system_storage, t); | |||
} | |||
template<typename T_options> | |||
template<typename T> | |||
constexpr decltype(auto) settings_t<T_options> | |||
::entity_storage(T t) const noexcept | |||
{ | |||
return change(keys::entity_storage, t); | |||
} | |||
template<typename T_options> | |||
template<typename T> | |||
constexpr decltype(auto) settings_t<T_options> | |||
::refresh_parallelism(T t) const noexcept | |||
{ | |||
return change(keys::refresh_parallelism, t); | |||
} | |||
template<typename T_options> | |||
template<typename T> | |||
constexpr decltype(auto) settings_t<T_options> | |||
::scheduler(T t) const noexcept | |||
{ | |||
return change(keys::scheduler, t); | |||
} | |||
/* make_t */ | |||
constexpr decltype(auto) make_t | |||
::operator()() const noexcept | |||
{ | |||
using namespace ::ecs::core::mp; | |||
auto options = option_map::make() | |||
.add(keys::component_signatures, list::empty) | |||
.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::scheduler, scheduler::atomic_counter); | |||
return settings_t<decay_t<decltype(options)>> { }; | |||
} | |||
} } } |
@@ -3,10 +3,11 @@ | |||
#include <ecs/config.h> | |||
#include <ecs/core/system/storage/tuple.h> | |||
beg_namespace_ecs_settings_system_storage | |||
{ | |||
namespace ecs { | |||
namespace settings { | |||
namespace system_storage { | |||
namespace __impl | |||
namespace detail | |||
{ | |||
struct tuple_storage_builder | |||
{ | |||
@@ -16,7 +17,6 @@ beg_namespace_ecs_settings_system_storage | |||
}; | |||
} | |||
constexpr decltype(auto) tuple = __impl::tuple_storage_builder { }; | |||
constexpr decltype(auto) tuple = detail::tuple_storage_builder { }; | |||
} | |||
end_namespace_ecs_settings_system_storage | |||
} } } |
@@ -2,4 +2,6 @@ | |||
#include "./component/signature.h" | |||
#include "./component/storage.h" | |||
#include "./system/signature.h" | |||
#include "./system/signature.h" | |||
#include "./component/signature.inl" |
@@ -7,73 +7,133 @@ | |||
#include <ecs/tag/component.h> | |||
#include "./storage.h" | |||
beg_namespace_ecs_signature_component | |||
{ | |||
namespace ecs { | |||
namespace signature { | |||
namespace component { | |||
namespace keys | |||
{ | |||
constexpr decltype(auto) storage = hana::size_c<0>; | |||
} | |||
namespace __impl | |||
namespace detail | |||
{ | |||
/** | |||
* defines a component signature | |||
* | |||
* @tparam T_component_tag component tag the signature is defined for | |||
* @tparam T_options option map for the component signature | |||
*/ | |||
template<typename T_component_tag_list, typename T_options> | |||
struct signature_t | |||
{ | |||
static_assert(tag::component::is_list(T_component_tag_list { }) == hana::true_c, "component signature needs a list of component tags"); | |||
private: | |||
template<typename T_key, typename T_value> | |||
constexpr decltype(auto) change(const T_key& key, T_value&& value) const noexcept | |||
{ | |||
auto new_options = T_options { }.set(key, std::forward<T_value>(value)); | |||
return signature_t<T_component_tag_list, core::mp::decay_t<decltype(new_options)>> { }; | |||
} | |||
/** | |||
* change the value of the given option key | |||
* | |||
* @tparam T_key key type to set the value for | |||
* @tparam T_value value type of the new value | |||
* | |||
* @param key key to set the value for | |||
* @param value new value | |||
* | |||
* @return updated component signature | |||
*/ | |||
template<typename T_key, typename T_value> | |||
constexpr decltype(auto) change(const T_key& key, T_value&& value) const noexcept; | |||
/** | |||
* get the value of the given option key | |||
* | |||
* @tparam T_key key type to get the value for | |||
* | |||
* @param key key to get the value for | |||
* | |||
* @return value stored for the given key | |||
*/ | |||
template<typename T_key> | |||
constexpr decltype(auto) get(const T_key& key) const noexcept | |||
{ return T_options { }.at(key); } | |||
public: | |||
constexpr decltype(auto) tags() const noexcept | |||
{ return T_component_tag_list { }; } | |||
constexpr decltype(auto) get(const T_key& key) const noexcept; | |||
public: /* tags */ | |||
/** | |||
* get a list of all component tags for this signature | |||
* | |||
* @return list of component tags managed by this signature | |||
*/ | |||
constexpr decltype(auto) tags() const noexcept; | |||
/** | |||
* check if this signature has a certain component tag | |||
* | |||
* @tparam T_component_tag component tag type to check | |||
* | |||
* @param ct component tag to check | |||
* | |||
* @retval integral constant TRUE if the given component tag is managed by this signature | |||
* @retval integral constant FALSE if the given component tag is not managed by this signature | |||
*/ | |||
template<typename T_component_tag> | |||
constexpr decltype(auto) has(T_component_tag ct) const noexcept | |||
{ return hana::contains(T_component_tag_list { }, ct); } | |||
constexpr decltype(auto) has(T_component_tag ct) const noexcept; | |||
public: /* options */ | |||
/** | |||
* set the storage option of this component signature | |||
* | |||
* @tparam T_storage storage builder type (specialization of @ref storage::storage_builder_interface_t) | |||
* | |||
* @param storage storage builder (specialized instance of @ref storage::storage_builder_interface_t) | |||
* | |||
* @return updated component signature | |||
*/ | |||
template<typename T_storage> | |||
constexpr decltype(auto) storage(T_storage&& storage) const noexcept | |||
{ return change(keys::storage, std::forward<T_storage>(storage)); } | |||
constexpr decltype(auto) storage() const noexcept | |||
{ return get(keys::storage); } | |||
constexpr decltype(auto) storage(T_storage&& storage) const noexcept; | |||
/** | |||
* get the storage option of this component signature | |||
* | |||
* @return storage builder (specialized instance of @ref storage::storage_builder_interface_t) | |||
*/ | |||
constexpr decltype(auto) storage() const noexcept; | |||
}; | |||
/** | |||
* predicate class to create a component signature | |||
*/ | |||
struct make_t | |||
{ | |||
/** | |||
* execute the predicate | |||
* | |||
* @tparam T_component_tags component tag types to build component signature for | |||
* | |||
* @param cts component tags to build component signature for | |||
* | |||
* @return component signature (@ref detail::signature_t) | |||
*/ | |||
template<typename... T_component_tags> | |||
constexpr decltype(auto) operator()(T_component_tags... cts) const noexcept | |||
{ | |||
using namespace ::ecs::core::mp; | |||
auto ctl = list::make(cts...); | |||
auto options = option_map::make() | |||
.add(keys::storage, storage::default_); | |||
using signature_type = signature_t<decay_t<decltype(ctl)>, decay_t<decltype(options)>>; | |||
return signature_type { }; | |||
} | |||
constexpr decltype(auto) operator()(T_component_tags... cts) const noexcept; | |||
}; | |||
} | |||
constexpr decltype(auto) make = __impl::make_t { }; | |||
/** | |||
* predicate to create a new component signature (see @ref detail::signature_t) | |||
*/ | |||
constexpr decltype(auto) make = detail::make_t { }; | |||
constexpr decltype(auto) is_valid = core::mp::is_valid<__impl::signature_t>; | |||
/** | |||
* predicate to check if a component signature is valid | |||
*/ | |||
constexpr decltype(auto) is_valid = core::mp::is_valid<detail::signature_t>; | |||
constexpr decltype(auto) is_list = core::mp::is_list<__impl::signature_t>; | |||
/** | |||
* predicate to check if all component signatures in a list are valid | |||
*/ | |||
constexpr decltype(auto) is_list = core::mp::is_list<detail::signature_t>; | |||
} | |||
end_namespace_ecs_signature_component | |||
} } } |
@@ -0,0 +1,81 @@ | |||
#pragma once | |||
#include "signature.h" | |||
namespace ecs { | |||
namespace signature { | |||
namespace component { | |||
namespace detail | |||
{ | |||
/* signature_t */ | |||
template<typename T_component_tag_list, typename T_options> | |||
template<typename T_key, typename T_value> | |||
constexpr decltype(auto) signature_t<T_component_tag_list, T_options> | |||
::change(const T_key& key, T_value&& value) const noexcept | |||
{ | |||
auto new_options = T_options { }.set(key, std::forward<T_value>(value)); | |||
return signature_t<T_component_tag_list, core::mp::decay_t<decltype(new_options)>> { }; | |||
} | |||
template<typename T_component_tag_list, typename T_options> | |||
template<typename T_key> | |||
constexpr decltype(auto) signature_t<T_component_tag_list, T_options> | |||
::get(const T_key& key) const noexcept | |||
{ | |||
return T_options { }.at(key); | |||
} | |||
template<typename T_component_tag_list, typename T_options> | |||
constexpr decltype(auto) signature_t<T_component_tag_list, T_options> | |||
::tags() const noexcept | |||
{ | |||
return T_component_tag_list { }; | |||
} | |||
template<typename T_component_tag_list, typename T_options> | |||
template<typename T_component_tag> | |||
constexpr decltype(auto) signature_t<T_component_tag_list, T_options> | |||
::has(T_component_tag ct) const noexcept | |||
{ | |||
return hana::contains(T_component_tag_list { }, ct); | |||
} | |||
template<typename T_component_tag_list, typename T_options> | |||
template<typename T_storage> | |||
constexpr decltype(auto) signature_t<T_component_tag_list, T_options> | |||
::storage(T_storage&& storage) const noexcept | |||
{ | |||
return change(keys::storage, std::forward<T_storage>(storage)); | |||
} | |||
template<typename T_component_tag_list, typename T_options> | |||
constexpr decltype(auto) signature_t<T_component_tag_list, T_options> | |||
::storage() const noexcept | |||
{ | |||
return get(keys::storage); | |||
} | |||
/* make_t */ | |||
template<typename... T_component_tags> | |||
constexpr decltype(auto) make_t | |||
::operator()(T_component_tags... cts) const noexcept | |||
{ | |||
using namespace ::ecs::core::mp; | |||
auto ctl = list::make(cts...); | |||
auto options = option_map::make() | |||
.add(keys::storage, storage::default_); | |||
using signature_type = signature_t<decay_t<decltype(ctl)>, decay_t<decltype(options)>>; | |||
return signature_type { }; | |||
} | |||
} | |||
} } } |
@@ -3,4 +3,5 @@ | |||
#include "./storage/default.h" | |||
#include "./storage/dynamic.h" | |||
#include "./storage/empty.h" | |||
#include "./storage/fixed.h" | |||
#include "./storage/fixed.h" | |||
#include "./storage/interface.h" |
@@ -3,11 +3,20 @@ | |||
#include "./empty.h" | |||
#include "./dynamic.h" | |||
beg_namespace_ecs_signature_component_storage | |||
{ | |||
namespace ecs { | |||
namespace signature { | |||
namespace component { | |||
namespace storage { | |||
namespace __impl | |||
namespace detail | |||
{ | |||
/** | |||
* Default storage builder. | |||
* Specializes @ref ::ecs::signature::component::storage::storage_builder_interface_t. | |||
* | |||
* Will redirect to the empty storage builder (@ref empty_builder_t) if the components of the component | |||
* signature are all empty. Will use the dynamic builder (@ref dynamic_builder_t) otherwise. | |||
*/ | |||
struct default_builder_t | |||
{ | |||
template<typename T_settings, typename T_component_tag_list> | |||
@@ -23,7 +32,9 @@ beg_namespace_ecs_signature_component_storage | |||
}; | |||
} | |||
constexpr decltype(auto) default_ = __impl::default_builder_t { }; | |||
/** | |||
* predicate to build a default component storage | |||
*/ | |||
constexpr decltype(auto) default_ = detail::default_builder_t { }; | |||
} | |||
end_namespace_ecs_signature_component_storage | |||
} } } } |
@@ -3,11 +3,21 @@ | |||
#include <ecs/config.h> | |||
#include <ecs/core/component/storage/dynamic.h> | |||
beg_namespace_ecs_signature_component_storage | |||
{ | |||
namespace ecs { | |||
namespace signature { | |||
namespace component { | |||
namespace storage { | |||
namespace __impl | |||
namespace detail | |||
{ | |||
/** | |||
* Dynamic storage builder. | |||
* Specializes @ref ::ecs::signature::component::storage::storage_builder_interface_t. | |||
* | |||
* Will build a component storage that will automatically increase in size if needed. | |||
* | |||
* @tparam T_size initial size of the storage | |||
*/ | |||
template<size_t T_size> | |||
struct dynamic_builder_t | |||
{ | |||
@@ -17,8 +27,12 @@ beg_namespace_ecs_signature_component_storage | |||
}; | |||
} | |||
template<size_t T_size> | |||
constexpr decltype(auto) dynamic = __impl::dynamic_builder_t<T_size> { }; | |||
/** | |||
* predicate to build a dynamic component storage | |||
* | |||
* @tparam T_size initial size of the storage | |||
*/ | |||
template<size_t T_size = 1024> | |||
constexpr decltype(auto) dynamic = detail::dynamic_builder_t<T_size> { }; | |||
} | |||
end_namespace_ecs_signature_component_storage | |||
} } } } |
@@ -3,11 +3,19 @@ | |||
#include <ecs/config.h> | |||
#include <ecs/core/component/storage/empty.h> | |||
beg_namespace_ecs_signature_component_storage | |||
{ | |||
namespace ecs { | |||
namespace signature { | |||
namespace component { | |||
namespace storage { | |||
namespace __impl | |||
namespace detail | |||
{ | |||
/** | |||
* Empty storage builder. | |||
* Specializes @ref ::ecs::signature::component::storage::storage_builder_interface_t. | |||
* | |||
* Will build a component storage that does not store any component. | |||
*/ | |||
struct empty_builder_t | |||
{ | |||
template<typename T_settings, typename T_component_tag_list> | |||
@@ -16,7 +24,9 @@ beg_namespace_ecs_signature_component_storage | |||
}; | |||
} | |||
constexpr decltype(auto) empty = __impl::empty_builder_t { }; | |||
/** | |||
* predicate to build an empty component storage | |||
*/ | |||
constexpr decltype(auto) empty = detail::empty_builder_t { }; | |||
} | |||
end_namespace_ecs_signature_component_storage | |||
} } } } |
@@ -3,11 +3,21 @@ | |||
#include <ecs/config.h> | |||
#include <ecs/core/component/storage/fixed.h> | |||
beg_namespace_ecs_signature_component_storage | |||
{ | |||
namespace ecs { | |||
namespace signature { | |||
namespace component { | |||
namespace storage { | |||
namespace __impl | |||
namespace detail | |||
{ | |||
/** | |||
* Fixed storage builder. | |||
* Specializes @ref ::ecs::signature::component::storage::storage_builder_interface_t. | |||
* | |||
* Will build a component storage that will store components in memory of fixed size. | |||
* | |||
* @tparam T_size size of the storage | |||
*/ | |||
template<size_t T_size> | |||
struct fixed_builder_t | |||
{ | |||
@@ -17,8 +27,12 @@ beg_namespace_ecs_signature_component_storage | |||
}; | |||
} | |||
template<size_t T_size> | |||
constexpr decltype(auto) fixed = __impl::fixed_builder_t<T_size> { }; | |||
/** | |||
* predicate to build a fixed component storage | |||
* | |||
* @tparam T_size size of the storage | |||
*/ | |||
template<size_t T_size = 1024> | |||
constexpr decltype(auto) fixed = detail::fixed_builder_t<T_size> { }; | |||
} | |||
end_namespace_ecs_signature_component_storage | |||
} } } } |
@@ -0,0 +1,31 @@ | |||
#pragma once | |||
#include "./empty.h" | |||
#include "./dynamic.h" | |||
namespace ecs { | |||
namespace signature { | |||
namespace component { | |||
namespace storage { | |||
/** | |||
* predicate type to build a @ref ::ecs::core::component::storage_iterface_t | |||
*/ | |||
struct storage_builder_interface_t | |||
{ | |||
/** | |||
* execute the predicate | |||
* | |||
* @tparam T_settings settings type (specialization of @ref ::ecs::settings::detail::settings_t) | |||
* @tparam T_component_tag_list list of component tags type to build storage for | |||
* | |||
* @param settings ecs system settings (instnace of @ref ::ecs::settings::detail::settings_t) | |||
* @param ctl list of component tags to build storage for | |||
* | |||
* @return component storage (instance of type @ref ::ecs::core::component::storage_iterface_t) | |||
*/ | |||
template<typename T_settings, typename T_component_tag_list> | |||
constexpr decltype(auto) operator()(T_settings settings, T_component_tag_list ctl) const; | |||
}; | |||
} } } } |
@@ -2,4 +2,6 @@ | |||
#include "./system/output.h" | |||
#include "./system/parallelism.h" | |||
#include "./system/signature.h" | |||
#include "./system/signature.h" | |||
#include "./system/signature.inl" |
@@ -2,10 +2,12 @@ | |||
#include <ecs/config.h> | |||
beg_namespace_ecs_signature_system_output | |||
{ | |||
namespace ecs { | |||
namespace signature { | |||
namespace system { | |||
namespace output { | |||
namespace __impl | |||
namespace detail | |||
{ | |||
struct empty_output | |||
{ }; | |||
@@ -17,12 +19,11 @@ beg_namespace_ecs_signature_system_output | |||
} | |||
template<typename T_output> | |||
using type = __impl::output_t<T_output>; | |||
using type = detail::output_t<T_output>; | |||
template<typename T_output> | |||
constexpr decltype(auto) value = type<T_output> { }; | |||
constexpr decltype(auto) none = value<__impl::empty_output>; | |||
constexpr decltype(auto) none = value<detail::empty_output>; | |||
} | |||
end_namespace_ecs_signature_system_output | |||
} } } } |
@@ -3,10 +3,12 @@ | |||
#include <ecs/config.h> | |||
#include <ecs/core/system/parallelism/composer/fixed_threshold.h> | |||
beg_namespace_ecs_signature_system_parallelism | |||
{ | |||
namespace ecs { | |||
namespace signature { | |||
namespace system { | |||
namespace parallelism { | |||
namespace __impl | |||
namespace detail | |||
{ | |||
template<typename T_threshold, typename T_lower_strategy, typename T_greater_strategy> | |||
struct fixed_threshold_builder_t | |||
@@ -33,7 +35,7 @@ beg_namespace_ecs_signature_system_parallelism | |||
}; | |||
} | |||
constexpr decltype(auto) fixed_threshold = __impl::fixed_threshold_t { }; | |||
/** fuuu */ | |||
constexpr decltype(auto) fixed_threshold = detail::fixed_threshold_t { }; | |||
} | |||
end_namespace_ecs_signature_system_parallelism | |||
} } } } |
@@ -5,10 +5,12 @@ | |||
#include "./fixed_threshold.h" | |||
#include "../strategy/none.h" | |||
beg_namespace_ecs_signature_system_parallelism | |||
{ | |||
namespace ecs { | |||
namespace signature { | |||
namespace system { | |||
namespace parallelism { | |||
namespace __impl | |||
namespace detail | |||
{ | |||
struct none_below_threshold_t | |||
{ | |||
@@ -18,7 +20,6 @@ beg_namespace_ecs_signature_system_parallelism | |||
}; | |||
} | |||
constexpr decltype(auto) none_below_threshold = __impl::none_below_threshold_t { }; | |||
constexpr decltype(auto) none_below_threshold = detail::none_below_threshold_t { }; | |||
} | |||
end_namespace_ecs_signature_system_parallelism | |||
} } } } |
@@ -3,10 +3,12 @@ | |||
#include <ecs/config.h> | |||
#include <ecs/core/system/parallelism/strategy/none.h> | |||
beg_namespace_ecs_signature_system_parallelism | |||
{ | |||
namespace ecs { | |||
namespace signature { | |||
namespace system { | |||
namespace parallelism { | |||
namespace __impl | |||
namespace detail | |||
{ | |||
struct none_builder_t | |||
{ | |||
@@ -21,7 +23,6 @@ beg_namespace_ecs_signature_system_parallelism | |||
}; | |||
} | |||
constexpr decltype(auto) none = __impl::none_t { }; | |||
constexpr decltype(auto) none = detail::none_t { }; | |||
} | |||
end_namespace_ecs_signature_system_parallelism | |||
} } } } |
@@ -3,10 +3,12 @@ | |||
#include <ecs/config.h> | |||
#include <ecs/core/system/parallelism/strategy/split_evenly.h> | |||
beg_namespace_ecs_signature_system_parallelism | |||
{ | |||
namespace ecs { | |||
namespace signature { | |||
namespace system { | |||
namespace parallelism { | |||
namespace __impl | |||
namespace detail | |||
{ | |||
template<typename T_split> | |||
struct split_evenly_builder_t | |||
@@ -29,7 +31,6 @@ beg_namespace_ecs_signature_system_parallelism | |||
}; | |||
} | |||
constexpr decltype(auto) split_evenly = __impl::split_evenly_t { }; | |||
constexpr decltype(auto) split_evenly = detail::split_evenly_t { }; | |||
} | |||
end_namespace_ecs_signature_system_parallelism | |||
} } } } |
@@ -3,10 +3,12 @@ | |||
#include <ecs/config.h> | |||
#include <ecs/core/system/parallelism/strategy/split_evenly.h> | |||
beg_namespace_ecs_signature_system_parallelism | |||
{ | |||
namespace ecs { | |||
namespace signature { | |||
namespace system { | |||
namespace parallelism { | |||
namespace __impl | |||
namespace detail | |||
{ | |||
struct split_evenly_cores_builder_t | |||
{ | |||
@@ -32,7 +34,6 @@ beg_namespace_ecs_signature_system_parallelism | |||
}; | |||
} | |||
constexpr decltype(auto) split_evenly_cores = __impl::split_evenly_cores_t { }; | |||
constexpr decltype(auto) split_evenly_cores = detail::split_evenly_cores_t { }; | |||
} | |||
end_namespace_ecs_signature_system_parallelism | |||
} } } } |
@@ -3,10 +3,12 @@ | |||
#include <ecs/config.h> | |||
#include <ecs/core/system/parallelism/strategy/split_every.h> | |||
beg_namespace_ecs_signature_system_parallelism | |||
{ | |||
namespace ecs { | |||
namespace signature { | |||
namespace system { | |||
namespace parallelism { | |||
namespace __impl | |||
namespace detail | |||
{ | |||
template<typename T_split> | |||
struct split_every_builder_t | |||
@@ -29,7 +31,6 @@ beg_namespace_ecs_signature_system_parallelism | |||
}; | |||
} | |||
constexpr decltype(auto) split_every = __impl::split_every_t { }; | |||
constexpr decltype(auto) split_every = detail::split_every_t { }; | |||
} | |||
end_namespace_ecs_signature_system_parallelism | |||
} } } } |
@@ -8,8 +8,9 @@ | |||
#include "./output.h" | |||
#include "./parallelism.h" | |||
beg_namespace_ecs_signature_system | |||
{ | |||
namespace ecs { | |||
namespace signature { | |||
namespace system { | |||
namespace keys | |||
{ | |||
@@ -20,8 +21,15 @@ beg_namespace_ecs_signature_system | |||
constexpr decltype(auto) output = hana::size_c<4>; | |||
} | |||
namespace __impl | |||
namespace detail | |||
{ | |||
/** | |||
* defines a system signature | |||
* | |||
* @tparam T_system_tag system tag the signature is defined for | |||
* @tparam T_options option map for the system signature | |||
*/ | |||
template<typename T_system_tag, typename T_options> | |||
struct signature_t | |||
{ | |||
@@ -30,89 +38,130 @@ beg_namespace_ecs_signature_system | |||
using tag_type = T_system_tag; | |||
private: | |||
/** | |||
* change the value of an option key | |||
* | |||
* @tparam T_key key type to change value for | |||
* @tparam T_value value type of the new value | |||
* | |||
* @param key key to change the value for | |||
* @param value new value | |||
* | |||
* @return updated system signature | |||
*/ | |||
template<typename T_key, typename T_value> | |||
constexpr decltype(auto) change(const T_key& key, T_value&& value) const noexcept | |||
{ | |||
auto new_options = T_options { }.set(key, std::forward<T_value>(value)); | |||
using impl_type = signature_t<T_system_tag, core::mp::decay_t<decltype(new_options)>>; | |||
return impl_type { }; | |||
} | |||
constexpr decltype(auto) change(const T_key& key, T_value&& value) const noexcept; | |||
/** | |||
* get the value of an option key | |||
* | |||
* @tparam T_key key type to get value for | |||
* | |||
* @param key key to get the value for | |||
* | |||
* @return value stored for key | |||
*/ | |||
template<typename T_key> | |||
constexpr decltype(auto) get(const T_key& key) const noexcept | |||
{ return T_options { }.at(key); } | |||
constexpr decltype(auto) get(const T_key& key) const noexcept; | |||
public: /* misc */ | |||
constexpr decltype(auto) tag() const noexcept | |||
{ return T_system_tag { }; } | |||
/** | |||
* get the system tag of this system signature | |||
* | |||
* @return system tag of this system signature | |||
*/ | |||
constexpr decltype(auto) tag() const noexcept; | |||
/** | |||
* check if the given component tag can be written by this system | |||
* | |||
* @tparam T_component_tag component tag type to check write access for | |||
* | |||
* @param ct component tag to check write access for | |||
* | |||
* @retval integral constant TRUE if the given component tag can be written | |||
* @retval integral constant FALSE if the given component tag can not be written | |||
*/ | |||
template<typename T_component_tag> | |||
constexpr decltype(auto) can_write(T_component_tag ct) const noexcept; | |||
/** | |||
* check if the given component tag can be read by this system | |||
* | |||
* @tparam T_component_tag component tag type to check read access for | |||
* | |||
* @param ct component tag to check read access for | |||
* | |||
* @retval integral constant TRUE if the given component tag can be read | |||
* @retval integral constant FALSE if the given component tag can not be read | |||
*/ | |||
template<typename T_component_tag> | |||
constexpr decltype(auto) can_read(T_component_tag ct) const noexcept; | |||
public: /* getter */ | |||
constexpr decltype(auto) parallelism() const noexcept | |||
{ return get(keys::parallelism); } | |||
constexpr decltype(auto) dependencies() const noexcept | |||
{ return get(keys::dependencies); } | |||
/** | |||
* get the value of the parallelism option | |||
*/ | |||
constexpr decltype(auto) parallelism() const noexcept; | |||
/** get a list of system tags that system depends on */ | |||
constexpr decltype(auto) dependencies() const noexcept; | |||
constexpr decltype(auto) read() const noexcept | |||
{ return get(keys::read_components); } | |||
/** get a list of component tags this system wants to read */ | |||
constexpr decltype(auto) read() const noexcept; | |||
constexpr decltype(auto) write() const noexcept | |||
{ return get(keys::write_components); } | |||
/** get a list of component tags this system wants to write */ | |||
constexpr decltype(auto) write() const noexcept; | |||
constexpr decltype(auto) output() const noexcept | |||
{ return get(keys::output); } | |||
/** get the output type of the system */ | |||
constexpr decltype(auto) output() const noexcept; | |||
public: /* setter */ | |||
/** set the parallelism options | |||
* @param parallelism is a predicate the takes no parameters and returns a | |||
* system executor interface */ | |||
template<typename T_parallelism> | |||
constexpr decltype(auto) parallelism(T_parallelism parallelism) const noexcept | |||
{ return change(keys::parallelism, parallelism); } | |||
constexpr decltype(auto) parallelism(T_parallelism parallelism) const noexcept; | |||
/** set a list of system tags, that system depends on */ | |||
template<typename... T_system_tags> | |||
constexpr decltype(auto) dependencies(T_system_tags... tags) const noexcept | |||
{ return change(keys::dependencies, core::mp::list::make(tags...)); } | |||
constexpr decltype(auto) dependencies(T_system_tags... tags) const noexcept; | |||
/** set a list of component tags, this system wants to read */ | |||
template<typename... T_component_tags> | |||
constexpr decltype(auto) read(T_component_tags... tags) const noexcept | |||
{ return change(keys::read_components, core::mp::list::make(tags...)); } | |||
constexpr decltype(auto) read(T_component_tags... tags) const noexcept; | |||
/** set a list of component tags, this system wants to write */ | |||
template<typename... T_component_tags> | |||
constexpr decltype(auto) write(T_component_tags... tags) const noexcept | |||
{ return change(keys::write_components, core::mp::list::make(tags...)); } | |||
constexpr decltype(auto) write(T_component_tags... tags) const noexcept; | |||
/** set the output type of this system */ | |||
template<typename T_output> | |||
constexpr decltype(auto) output(T_output output) const noexcept | |||
{ return change(keys::output, output); } | |||
constexpr decltype(auto) output(T_output output) const noexcept; | |||
}; | |||
/** predicate class to create a system signature */ | |||
struct make_t | |||
{ | |||
template<typename T_system_tag> | |||
constexpr decltype(auto) operator()(T_system_tag) const noexcept | |||
{ | |||
using namespace ::ecs::core::mp; | |||
auto options = option_map::make() | |||
.add(keys::parallelism, parallelism::none()) | |||
.add(keys::dependencies, list::empty) | |||
.add(keys::read_components, list::empty) | |||
.add(keys::write_components, list::empty) | |||
.add(keys::output, output::none); | |||
using signature_type = signature_t<T_system_tag, decay_t<decltype(options)>>; | |||
return signature_type { }; | |||
} | |||
constexpr decltype(auto) operator()(T_system_tag) const noexcept; | |||
}; | |||
} | |||
constexpr decltype(auto) make = __impl::make_t { }; | |||
/** predicate to create a system signature */ | |||
constexpr decltype(auto) make = detail::make_t { }; | |||
constexpr decltype(auto) is_valid = core::mp::is_valid<__impl::signature_t>; | |||
/** predicate to check if a system signature is valid */ | |||
constexpr decltype(auto) is_valid = core::mp::is_valid<detail::signature_t>; | |||
constexpr decltype(auto) is_list = core::mp::is_list<__impl::signature_t>; | |||
/** predicate to check if a list of system signatures is valid */ | |||
constexpr decltype(auto) is_list = core::mp::is_list<detail::signature_t>; | |||
/** get the system tag type of a system signature type */ | |||
template<typename T_system_sig> | |||
using tag_type = typename core::mp::unwrap_t<T_system_sig>::tag_type; | |||
using tag_type_t = typename core::mp::unwrap_t<T_system_sig>::tag_type; | |||
} | |||
end_namespace_ecs_signature_system | |||
} } } |
@@ -0,0 +1,158 @@ | |||
#pragma once | |||
#include <ecs/config.h> | |||
#include <ecs/core/mp/core.h> | |||
#include <ecs/core/mp/list.h> | |||
#include <ecs/core/mp/option_map.h> | |||
#include <ecs/tag/system.h> | |||
#include "./output.h" | |||
#include "./parallelism.h" | |||
namespace ecs { | |||
namespace signature { | |||
namespace system { | |||
namespace detail | |||
{ | |||
/* signature_t */ | |||
template<typename T_system_tag, typename T_options> | |||
template<typename T_key, typename T_value> | |||
constexpr decltype(auto) signature_t<T_system_tag, T_options> | |||
::change(const T_key& key, T_value&& value) const noexcept | |||
{ | |||
auto new_options = T_options { }.set(key, std::forward<T_value>(value)); | |||
using impl_type = signature_t<T_system_tag, core::mp::decay_t<decltype(new_options)>>; | |||
return impl_type { }; | |||
} | |||
template<typename T_system_tag, typename T_options> | |||
template<typename T_key> | |||
constexpr decltype(auto) signature_t<T_system_tag, T_options> | |||
::get(const T_key& key) const noexcept | |||
{ | |||
return T_options { }.at(key); | |||
} | |||
template<typename T_system_tag, typename T_options> | |||
constexpr decltype(auto) signature_t<T_system_tag, T_options> | |||
::tag() const noexcept | |||
{ | |||
return T_system_tag { }; | |||
} | |||
template<typename T_system_tag, typename T_options> | |||
template<typename T_component_tag> | |||
constexpr decltype(auto) signature_t<T_system_tag, T_options> | |||
::can_write(T_component_tag ct) const noexcept | |||
{ | |||
return hana::contains(write(), ct); | |||
} | |||
template<typename T_system_tag, typename T_options> | |||
template<typename T_component_tag> | |||
constexpr decltype(auto) signature_t<T_system_tag, T_options> | |||
::can_read(T_component_tag ct) const noexcept | |||
{ | |||
return hana::contains(read(), ct); | |||
} | |||
template<typename T_system_tag, typename T_options> | |||
constexpr decltype(auto) signature_t<T_system_tag, T_options> | |||
::parallelism() const noexcept | |||
{ | |||
return get(keys::parallelism); | |||
} | |||
template<typename T_system_tag, typename T_options> | |||
constexpr decltype(auto) signature_t<T_system_tag, T_options> | |||
::dependencies() const noexcept | |||
{ | |||
return get(keys::dependencies); | |||
} | |||
template<typename T_system_tag, typename T_options> | |||
constexpr decltype(auto) signature_t<T_system_tag, T_options> | |||
::read() const noexcept | |||
{ | |||
return get(keys::read_components); | |||
} | |||
template<typename T_system_tag, typename T_options> | |||
constexpr decltype(auto) signature_t<T_system_tag, T_options> | |||
::write() const noexcept | |||
{ | |||
return get(keys::write_components); | |||
} | |||
template<typename T_system_tag, typename T_options> | |||
constexpr decltype(auto) signature_t<T_system_tag, T_options> | |||
::output() const noexcept | |||
{ | |||
return get(keys::output); | |||
} | |||
template<typename T_system_tag, typename T_options> | |||
template<typename T_parallelism> | |||
constexpr decltype(auto) signature_t<T_system_tag, T_options> | |||
::parallelism(T_parallelism parallelism) const noexcept | |||
{ | |||
return change(keys::parallelism, parallelism); | |||
} | |||
template<typename T_system_tag, typename T_options> | |||
template<typename... T_system_tags> | |||
constexpr decltype(auto) signature_t<T_system_tag, T_options> | |||
::dependencies(T_system_tags... tags) const noexcept | |||
{ | |||
return change(keys::dependencies, core::mp::list::make(tags...)); | |||
} | |||
template<typename T_system_tag, typename T_options> | |||
template<typename... T_component_tags> | |||
constexpr decltype(auto) signature_t<T_system_tag, T_options> | |||
::read(T_component_tags... tags) const noexcept | |||
{ | |||
return change(keys::read_components, core::mp::list::make(tags...)); | |||
} | |||
template<typename T_system_tag, typename T_options> | |||
template<typename... T_component_tags> | |||
constexpr decltype(auto) signature_t<T_system_tag, T_options> | |||
::write(T_component_tags... tags) const noexcept | |||
{ | |||
return change(keys::write_components, core::mp::list::make(tags...)); | |||
} | |||
template<typename T_system_tag, typename T_options> | |||
template<typename T_output> | |||
constexpr decltype(auto) signature_t<T_system_tag, T_options> | |||
::output(T_output output) const noexcept | |||
{ | |||
return change(keys::output, output); | |||
} | |||
/* make_t */ | |||
template<typename T_system_tag> | |||
constexpr decltype(auto) make_t | |||
::operator()(T_system_tag) const noexcept | |||
{ | |||
using namespace ::ecs::core::mp; | |||
auto options = option_map::make() | |||
.add(keys::parallelism, parallelism::none()) | |||
.add(keys::dependencies, list::empty) | |||
.add(keys::read_components, list::empty) | |||
.add(keys::write_components, list::empty) | |||
.add(keys::output, output::none); | |||
using signature_type = signature_t<T_system_tag, decay_t<decltype(options)>>; | |||
return signature_type { }; | |||
} | |||
} | |||
} } } |