* Removed namespace macros * Refactoring: split inline code in header and inline file * Continued implementation of system executionmaster
@@ -1,2 +1,3 @@ | |||||
.vscode/ | .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 ################################################################################ | # Initialize CMake ################################################################################ | ||||
CMake_Minimum_Required ( VERSION 3.5.1 FATAL_ERROR ) | |||||
If ( NOT CMAKE_BUILD_TYPE ) | If ( NOT CMAKE_BUILD_TYPE ) | ||||
Set ( CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build!" FORCE ) | Set ( CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build!" FORCE ) | ||||
EndIf ( ) | EndIf ( ) | ||||
CMake_Minimum_Required ( VERSION 3.5.1 FATAL_ERROR ) | |||||
Set ( CMAKE_CXX_STANDARD 17 ) | 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 ) | Include ( cotire OPTIONAL ) | ||||
Set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${PEDANTIC_C_FLAGS}" ) | |||||
Set ( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${PEDANTIC_CXX_FLAGS}" ) | |||||
# Tests ########################################################################################### | # Tests ########################################################################################### | ||||
Include ( CTest ) | Include ( CTest ) | ||||
@@ -22,4 +29,11 @@ Find_Package ( Hana REQUIRED ) | |||||
# Projects ######################################################################################## | # Projects ######################################################################################## | ||||
Add_SubDirectory ( ${CMAKE_CURRENT_SOURCE_DIR}/src ) | 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 | #pragma once | ||||
// TODO debug!!! | // TODO debug!!! | ||||
#include <string> | |||||
#include <cxxabi.h> | #include <cxxabi.h> | ||||
template<typename T> | template<typename T> | ||||
@@ -18,116 +19,6 @@ struct type_helper | |||||
#include <boost/hana.hpp> | #include <boost/hana.hpp> | ||||
#include <boost/hana/ext/std/tuple.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 | namespace ecs | ||||
{ | { | ||||
@@ -3,4 +3,6 @@ | |||||
#include "./context/base.h" | #include "./context/base.h" | ||||
#include "./context/context.h" | #include "./context/context.h" | ||||
#include "./context/defer_proxy.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)...))) \ | ._##name(std::forward<T_args>(args)...))) \ | ||||
{ return this->_##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> | template<typename T_settings> | ||||
struct base_t | struct base_t | ||||
{ | { | ||||
@@ -28,8 +34,8 @@ beg_namespace_ecs_context | |||||
protected: | protected: | ||||
using context_type = ::ecs::context::type<settings_type>; | using context_type = ::ecs::context::type<settings_type>; | ||||
using component_manager_type = core::component::manager<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 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 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&>())); | 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>; | using handle_vector_type = std::vector<handle_type>; | ||||
protected: | 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: | 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 */ | 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> | 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 */ | 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> | 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 */ | 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> | 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> | 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> | 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> | 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 */ | 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> | 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> | 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> | 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> | 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> | 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> | 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> | 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 */ | 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> | 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> | 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> | #include <ecs/config.h> | ||||
beg_namespace_ecs_context | |||||
{ | |||||
namespace ecs { | |||||
namespace context { | |||||
namespace __impl | |||||
namespace detail | |||||
{ | { | ||||
template<typename T_settings> | template<typename T_settings> | ||||
struct context_t; | struct context_t; | ||||
} | } | ||||
template<typename T_settings> | 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 "./context.fwd.h" | ||||
#include "./step_proxy.h" | #include "./step_proxy.h" | ||||
beg_namespace_ecs_context | |||||
{ | |||||
namespace ecs { | |||||
namespace context { | |||||
namespace __impl | |||||
namespace detail | |||||
{ | { | ||||
template<typename T_settings> | template<typename T_settings> | ||||
struct context_t | 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" | #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> | template<typename T_settings> | ||||
struct defer_proxy_t | struct defer_proxy_t | ||||
: public base_t<T_settings> | : 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" | #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> | template<typename T_settings> | ||||
struct step_proxy_t | struct step_proxy_t | ||||
: public defer_proxy_t<T_settings> | : public defer_proxy_t<T_settings> | ||||
@@ -31,5 +34,4 @@ beg_namespace_ecs_context | |||||
}; | }; | ||||
} | } | ||||
} | |||||
end_namespace_ecs_context | |||||
} } |
@@ -1,4 +1,6 @@ | |||||
#pragma once | #pragma once | ||||
#include "./component/manager.h" | #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/decay.h> | ||||
#include <ecs/core/mp/core/wrap.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> | 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> | 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> | 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> | 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 */ | /* manager */ | ||||
/** | |||||
* component manager | |||||
* | |||||
* @tparam T_settings settings to build the component manager for | |||||
*/ | |||||
template<typename T_settings> | template<typename T_settings> | ||||
struct manager | struct manager | ||||
{ | { | ||||
public: | 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: | private: | ||||
chunk_tuple_type _chunks; | |||||
storage_tuple_type _storages; | |||||
public: | 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> | 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< | template< | ||||
typename T_self, | typename T_self, | ||||
typename T_component_tag, | typename T_component_tag, | ||||
typename T_meta_data_tuple, | typename T_meta_data_tuple, | ||||
typename T_func> | typename T_func> | ||||
static constexpr decltype(auto) for_chunk_do( | |||||
static constexpr decltype(auto) for_storage_do( | |||||
T_self&& self, | T_self&& self, | ||||
T_component_tag ct, | T_component_tag ct, | ||||
T_meta_data_tuple&& mdt, | 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< | template< | ||||
typename T_self, | typename T_self, | ||||
typename T_component_tag, | typename T_component_tag, | ||||
@@ -136,14 +197,23 @@ beg_namespace_ecs_core_component | |||||
T_self&& self, | T_self&& self, | ||||
T_component_tag ct, | T_component_tag ct, | ||||
const T_entity_handle& handle, | 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< | template< | ||||
typename T_self, | typename T_self, | ||||
typename T_component_tag, | typename T_component_tag, | ||||
@@ -153,44 +223,92 @@ beg_namespace_ecs_core_component | |||||
T_self&& self, | T_self&& self, | ||||
T_component_tag ct, | T_component_tag ct, | ||||
const T_entity_handle& handle, | 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: | 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> | 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> | 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: | 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> | 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> | 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> | 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/base.h" | ||||
#include "./storage/dynamic.h" | #include "./storage/dynamic.h" | ||||
#include "./storage/empty.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> | #include <ecs/config.h> | ||||
beg_namespace_ecs_core_component_storage | |||||
{ | |||||
namespace ecs { | |||||
namespace core { | |||||
namespace component { | |||||
namespace storage { | |||||
struct empty_meta_data { }; | 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> | template<typename T_container_builder, typename T_component_tag_list> | ||||
struct base | struct base | ||||
{ | { | ||||
@@ -23,40 +33,72 @@ beg_namespace_ecs_core_component_storage | |||||
container_type _container; | container_type _container; | ||||
private: | 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> | template<typename T_self, typename T_component_tag, typename T_entity_handle> | ||||
static inline decltype(auto) get_impl( | static inline decltype(auto) get_impl( | ||||
T_self&& self, | T_self&& self, | ||||
T_component_tag ct, | T_component_tag ct, | ||||
const T_entity_handle& handle, | 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: | 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> | 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> | 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> | 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" | #include "./base.h" | ||||
beg_namespace_ecs_core_component_storage | |||||
{ | |||||
namespace ecs { | |||||
namespace core { | |||||
namespace component { | |||||
namespace storage { | |||||
struct vector_type_builder | struct vector_type_builder | ||||
{ | { | ||||
@@ -13,6 +15,13 @@ beg_namespace_ecs_core_component_storage | |||||
using type = std::vector<T>; | 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> | template<typename T_component_tag_list> | ||||
struct dynamic | struct dynamic | ||||
: base<vector_type_builder, T_component_tag_list> | : base<vector_type_builder, T_component_tag_list> | ||||
@@ -26,5 +35,4 @@ beg_namespace_ecs_core_component_storage | |||||
{ this->_container.resize(inital_size); } | { this->_container.resize(inital_size); } | ||||
}; | }; | ||||
} | |||||
end_namespace_ecs_core_component_storage | |||||
} } } } |
@@ -2,9 +2,18 @@ | |||||
#include <ecs/config.h> | #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> | template<typename T_component_tag_list> | ||||
struct empty | 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" | #include "./base.h" | ||||
beg_namespace_ecs_core_component_storage | |||||
{ | |||||
namespace ecs { | |||||
namespace core { | |||||
namespace component { | |||||
namespace storage { | |||||
template<size_t T_size> | template<size_t T_size> | ||||
struct array_type_builder | struct array_type_builder | ||||
@@ -13,13 +15,21 @@ beg_namespace_ecs_core_component_storage | |||||
template<typename T> | template<typename T> | ||||
struct impl : public std::array<T, T_size> | 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> | template<typename T> | ||||
using type = impl<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> | template<typename T_component_tag_list, size_t T_size> | ||||
struct fixed | struct fixed | ||||
: base<array_type_builder<T_size>, T_component_tag_list> | : 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; | 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/base.h" | ||||
#include "./storage/dynamic.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/config.h> | ||||
#include <ecs/core/utils/bitset.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 | struct entity_handle | ||||
{ | { | ||||
private: | private: | ||||
@@ -14,58 +19,125 @@ beg_namespace_ecs_core_entity_storage | |||||
uint32_t _counter; | uint32_t _counter; | ||||
public: | 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 | struct entity_meta_data | ||||
: private T_storage_meta_data | |||||
{ | { | ||||
public: | 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: | private: | ||||
bitset_type _bitset; | |||||
counter_type _counter; | |||||
chunk_meta_data_type _chunk_meta_data; | |||||
bitset_type _bitset; | |||||
counter_type _counter; | |||||
public: | 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 | struct base | ||||
{ | { | ||||
public: | public: | ||||
using entity_handle_type = entity_handle; | 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: | private: | ||||
using container_type = typename T_container_builder::template type<entity_meta_data_type>; | 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; | queue_type _free_ids; | ||||
private: | 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: | 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" | #include "./base.h" | ||||
beg_namespace_ecs_core_entity_storage | |||||
{ | |||||
namespace ecs { | |||||
namespace core { | |||||
namespace entity { | |||||
namespace storage { | |||||
struct vector_type_builder | struct vector_type_builder | ||||
{ | { | ||||
@@ -13,12 +15,20 @@ beg_namespace_ecs_core_entity_storage | |||||
using type = std::vector<T>; | 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 | struct dynamic | ||||
: base<vector_type_builder, T_settings, T_chunk_meta_data> | |||||
: base<vector_type_builder, T_settings, T_storage_meta_data> | |||||
{ | { | ||||
public: | 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_handle_type; | ||||
using typename base_type::entity_meta_data_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" | #include "./base.h" | ||||
beg_namespace_ecs_core_entity_storage | |||||
{ | |||||
namespace ecs { | |||||
namespace core { | |||||
namespace entity { | |||||
namespace storage { | |||||
template<size_t T_size> | template<size_t T_size> | ||||
struct array_type_builder | struct array_type_builder | ||||
@@ -13,19 +15,28 @@ beg_namespace_ecs_core_entity_storage | |||||
template<typename T> | template<typename T> | ||||
struct impl : public std::array<T, T_size> | 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> | template<typename T> | ||||
using type = impl<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 | 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: | 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_handle_type; | ||||
using typename base_type::entity_meta_data_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> | #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> | template <typename T, typename T_source> | ||||
using copy_const_qualifier = | using copy_const_qualifier = | ||||
std::conditional_t< | std::conditional_t< | ||||
@@ -12,6 +19,12 @@ beg_namespace_ecs_core_mp | |||||
std::add_const_t<T>, | std::add_const_t<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> | template <typename T, typename T_source> | ||||
using copy_volatile_qualifier = | using copy_volatile_qualifier = | ||||
std::conditional_t< | std::conditional_t< | ||||
@@ -19,11 +32,16 @@ beg_namespace_ecs_core_mp | |||||
std::add_volatile_t<T>, | std::add_volatile_t<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> | template <typename T, typename T_source> | ||||
using copy_cv_qualifiers = | using copy_cv_qualifiers = | ||||
copy_const_qualifier< | copy_const_qualifier< | ||||
copy_volatile_qualifier<T, T_source>, | copy_volatile_qualifier<T, T_source>, | ||||
T_source>; | T_source>; | ||||
} | |||||
end_namespace_ecs_core_mp | |||||
} } } |
@@ -2,11 +2,14 @@ | |||||
#include <ecs/config.h> | #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> | template<typename T> | ||||
using decay_t = typename hana::detail::decay<T>::type; | using decay_t = typename hana::detail::decay<T>::type; | ||||
} | |||||
end_namespace_ecs_core_mp | |||||
} } } |
@@ -3,22 +3,42 @@ | |||||
#include <ecs/config.h> | #include <ecs/config.h> | ||||
#include "./is_valid.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 | 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> | template<typename T> | ||||
constexpr decltype(auto) operator()(T&& t) const noexcept | 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> | #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> | template<template<typename...> class T_template, typename T> | ||||
struct is_specialization_of | struct is_specialization_of | ||||
: public hana::false_ | : public hana::false_ | ||||
@@ -15,5 +22,4 @@ beg_namespace_ecs_core_mp | |||||
: public hana::true_ | : public hana::true_ | ||||
{ }; | { }; | ||||
} | |||||
end_namespace_ecs_core_mp | |||||
} } } |
@@ -4,25 +4,45 @@ | |||||
#include "./is_specialization_of.h" | #include "./is_specialization_of.h" | ||||
#include "../list.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 | struct is_valid_t | ||||
{ | { | ||||
template<typename 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> | 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> | #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> | template<typename T> | ||||
using wrap_t = hana::type<T>; | using wrap_t = hana::type<T>; | ||||
/** | |||||
* unpack a given boost::hana::type | |||||
**/ | |||||
template<typename T> | template<typename T> | ||||
using unwrap_t = typename T::type; | 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 | struct wrap_t | ||||
{ | { | ||||
/** | |||||
* execute the predicate | |||||
* | |||||
* @tparam T type to wrap | |||||
* | |||||
* @return object of the type wrapped in boost::hana::type | |||||
*/ | |||||
template<typename T> | template<typename T> | ||||
constexpr decltype(auto) operator()(T) const noexcept | constexpr decltype(auto) operator()(T) const noexcept | ||||
{ return mp::wrap_t<T> { }; } | { return mp::wrap_t<T> { }; } | ||||
}; | }; | ||||
/** | |||||
* predicate type to unwrap a given boost::hana::type | |||||
*/ | |||||
struct unwrap_t | struct unwrap_t | ||||
{ | { | ||||
/** | |||||
* execute the predicate | |||||
* | |||||
* @tparam T type to unwrap | |||||
* | |||||
* @return object of the unwrapped type | |||||
*/ | |||||
template<typename T> | template<typename T> | ||||
constexpr decltype(auto) operator()(T) const noexcept | constexpr decltype(auto) operator()(T) const noexcept | ||||
{ return mp::unwrap_t<T> { }; } | { 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> | #include <ecs/config.h> | ||||
beg_namespace_ecs_core_mp_list | |||||
{ | |||||
namespace ecs { | |||||
namespace core { | |||||
namespace mp { | |||||
namespace list { | |||||
/* base */ | /* base */ | ||||
namespace __impl | |||||
namespace detail | |||||
{ | { | ||||
/** | |||||
* simple meta programming list implementation | |||||
*/ | |||||
template<typename... Xs> | template<typename... Xs> | ||||
using list_t = hana::basic_tuple<Xs...>; | using list_t = hana::basic_tuple<Xs...>; | ||||
} | } | ||||
/** | |||||
* wrapper to the list type | |||||
*/ | |||||
template<typename... Xs> | template<typename... Xs> | ||||
using type = __impl::list_t<Xs...>; | |||||
using type = detail::list_t<Xs...>; | |||||
/** | |||||
* create a list object | |||||
*/ | |||||
template<typename... Xs> | template<typename... Xs> | ||||
constexpr decltype(auto) value = type<Xs...> { }; | constexpr decltype(auto) value = type<Xs...> { }; | ||||
/** | |||||
* empty list | |||||
*/ | |||||
constexpr decltype(auto) empty = value<>; | constexpr decltype(auto) empty = value<>; | ||||
/* make */ | /* make */ | ||||
namespace __impl | |||||
namespace detail | |||||
{ | { | ||||
/** | |||||
* predicate type to create a list | |||||
*/ | |||||
struct make_t | 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 */ | /* all */ | ||||
namespace __impl | |||||
namespace detail | |||||
{ | { | ||||
/** | |||||
* predicate type to check if all passed arguments are true-type or not | |||||
*/ | |||||
struct all_t | 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 */ | /* unwrap */ | ||||
namespace __impl | |||||
namespace detail | |||||
{ | { | ||||
template<template<typename...> class T_outer, typename T_list> | template<template<typename...> class T_outer, typename T_list> | ||||
struct unwrap_t; | struct unwrap_t; | ||||
@@ -61,15 +104,35 @@ beg_namespace_ecs_core_mp_list | |||||
{ using type = T_outer<typename Ts::type...>; }; | { 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> | 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 */ | /* index_of */ | ||||
namespace __impl | |||||
namespace detail | |||||
{ | { | ||||
/** | |||||
* predicate type to get the index of a certain element inside a list | |||||
*/ | |||||
struct index_of_t | 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> | template<typename T_list, typename T> | ||||
constexpr decltype(auto) operator()(T_list list, T&& item) const noexcept | 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 */ | /* 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 | 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> | template<typename T_list, typename T_func> | ||||
constexpr decltype(auto) operator()(T_list list, T_func&& func) const noexcept | 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 <ecs/config.h> | ||||
#include "./core/decay.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> | template<typename T_new_pair> | ||||
struct replace_helper_t | struct replace_helper_t | ||||
{ | { | ||||
@@ -15,6 +24,15 @@ beg_namespace_ecs_core_mp_option_map | |||||
const new_pair_type& new_pair; | 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> | template<typename T_pair> | ||||
constexpr decltype(auto) operator()(T_pair&& pair) const noexcept | 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 | 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> | template<typename T_map, typename T_new_pair> | ||||
constexpr decltype(auto) operator()(T_map&& map, T_new_pair&& new_pair) const noexcept | 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 { }; | constexpr decltype(auto) replace = replace_t { }; | ||||
/** | |||||
* implements an option map to store key value pairs | |||||
*/ | |||||
template<typename T_map> | template<typename T_map> | ||||
struct option_map_t | struct option_map_t | ||||
{ | { | ||||
@@ -51,14 +89,43 @@ beg_namespace_ecs_core_mp_option_map | |||||
map_type _map; | map_type _map; | ||||
public: | 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> | template<typename T_key> | ||||
constexpr decltype(auto) at(const T_key& key) const noexcept | constexpr decltype(auto) at(const T_key& key) const noexcept | ||||
{ return hana::first(hana::at_key(_map, key)); } | { 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> | template<typename T_key> | ||||
constexpr decltype(auto) type_at(const T_key& key) const noexcept | constexpr decltype(auto) type_at(const T_key& key) const noexcept | ||||
{ return hana::type_c<decay_t<decltype(at(key))>>; } | { 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> | template<typename T_key, typename T_value> | ||||
constexpr decltype(auto) add(const T_key& key, T_value&& value) const noexcept | 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)> { }; | 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> | template<typename T_key, typename T_value> | ||||
constexpr decltype(auto) set(const T_key& key, T_value&& value) const noexcept | 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 | struct make_t | ||||
{ | { | ||||
/** | |||||
* execute the predicate | |||||
* | |||||
* @return empty option map | |||||
*/ | |||||
constexpr decltype(auto) operator()() const noexcept | constexpr decltype(auto) operator()() const noexcept | ||||
{ return option_map_t<decay_t<decltype(hana::make_map())>> { }; } | { 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 <ecs/config.h> | ||||
#include "./core/decay.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> | template<template<typename> class T_tag> | ||||
struct make_t | 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> | 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 | #pragma once | ||||
#include "./system/data_proxy.h" | |||||
#include "./system/instance.h" | #include "./system/instance.h" | ||||
#include "./system/parallelism.h" | #include "./system/parallelism.h" | ||||
#include "./system/scheduler.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/signature/system.h> | ||||
#include <ecs/core/utils/bitset.h> | #include <ecs/core/utils/bitset.h> | ||||
#include <ecs/core/utils/fixed_function.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> | template<typename T_settings> | ||||
struct deferred_function_vector | struct deferred_function_vector | ||||
@@ -55,7 +57,7 @@ beg_namespace_ecs_core_system | |||||
using bitset_type = utils::bitset<settings_type>; | using bitset_type = utils::bitset<settings_type>; | ||||
using entity_handle_type = T_entity_handle; | using entity_handle_type = T_entity_handle; | ||||
using executor_type = decltype(mp::unwrap(system_signature_type { }).parallelism()()); | 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 | struct state_t | ||||
: public output_type | : public output_type | ||||
@@ -114,6 +116,12 @@ beg_namespace_ecs_core_system | |||||
} | } | ||||
public: | public: | ||||
inline void prepare_states(size_t n) | |||||
{ | |||||
assert(n > 0); | |||||
clear_and_prepare(n); | |||||
} | |||||
template<typename T_context, typename T_func> | template<typename T_context, typename T_func> | ||||
inline void prepare_and_wait_subtasks(T_context& context, size_t n, T_func& 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) { | return [this, &b, &context, &f](auto&&... xs) { | ||||
context.post_in_thread_pool([&f, &b, xs...]() { | context.post_in_thread_pool([&f, &b, xs...]() { | ||||
ecs_make_scope_guard([&b](){ | ecs_make_scope_guard([&b](){ | ||||
b.decrement_and_notify_one(); | |||||
b.decrement(); | |||||
}); | }); | ||||
f(xs...); | 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 */ | public: /* bitset */ | ||||
inline const auto& bitset() const noexcept | inline const auto& bitset() const noexcept | ||||
{ return _bitset; } | { return _bitset; } | ||||
@@ -162,7 +174,7 @@ beg_namespace_ecs_core_system | |||||
{ return (_subscribed.find(handle) != _subscribed.end()); } | { return (_subscribed.find(handle) != _subscribed.end()); } | ||||
inline void subscribe(const entity_handle_type& handle) | inline void subscribe(const entity_handle_type& handle) | ||||
{ _subscribed.emplace(handle); } | |||||
{ _subscribed.insert(handle); } | |||||
inline void unsubscribe(const entity_handle_type& handle) | inline void unsubscribe(const entity_handle_type& handle) | ||||
{ _subscribed.erase(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> | #include <ecs/config.h> | ||||
beg_namespace_ecs_core_parallelism | |||||
{ | |||||
namespace ecs { | |||||
namespace core { | |||||
namespace system { | |||||
namespace parallelism { | |||||
template<typename T_parameters> | template<typename T_parameters> | ||||
struct fixed_threshold | struct fixed_threshold | ||||
@@ -15,20 +17,13 @@ beg_namespace_ecs_core_parallelism | |||||
strategy_lower_type _strategy_lower; | strategy_lower_type _strategy_lower; | ||||
strategy_greater_type _strategy_greater; | 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 | 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 | #pragma once | ||||
#include <ecs/config.h> | #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 | 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> | #include <ecs/config.h> | ||||
beg_namespace_ecs_core_parallelism | |||||
{ | |||||
namespace ecs { | |||||
namespace core { | |||||
namespace system { | |||||
namespace parallelism { | |||||
template<typename T_parameters> | template<typename T_parameters> | ||||
struct split_evenly | struct split_evenly | ||||
@@ -13,10 +15,9 @@ beg_namespace_ecs_core_parallelism | |||||
template<typename T_context, typename T_instance, typename T_func> | template<typename T_context, typename T_instance, typename T_func> | ||||
inline void operator()(T_context& context, T_instance& instance, T_func&& func) const | inline void operator()(T_context& context, T_instance& instance, T_func&& func) const | ||||
{ | { | ||||
// auto split_count = parameters_type::get_split_count(); | |||||
// TODO | // TODO | ||||
// auto split_count = parameters_type::get_split_count(); | |||||
} | } | ||||
}; | }; | ||||
} | |||||
end_namespace_ecs_core_parallelism | |||||
} } } } |
@@ -2,8 +2,10 @@ | |||||
#include <ecs/config.h> | #include <ecs/config.h> | ||||
beg_namespace_ecs_core_parallelism | |||||
{ | |||||
namespace ecs { | |||||
namespace core { | |||||
namespace system { | |||||
namespace parallelism { | |||||
template<typename T_parameters> | template<typename T_parameters> | ||||
struct split_every | struct split_every | ||||
@@ -13,9 +15,9 @@ beg_namespace_ecs_core_parallelism | |||||
template<typename T_context, typename T_instance, typename T_func> | template<typename T_context, typename T_instance, typename T_func> | ||||
inline void operator()(T_context& context, T_instance& instance, T_func&& func) const | inline void operator()(T_context& context, T_instance& instance, T_func&& func) const | ||||
{ | { | ||||
// TODO | |||||
// auto per_split = parameters_type::get_per_split_count(); | // auto per_split = parameters_type::get_per_split_count(); | ||||
} | } | ||||
}; | }; | ||||
} | |||||
end_namespace_ecs_core_parallelism | |||||
} } } } |
@@ -1,3 +1,5 @@ | |||||
#pragma once | #pragma once | ||||
#include "./scheduler/atomic_counter.h" | |||||
#include "./scheduler/atomic_counter.h" | |||||
#include "./scheduler/atomic_counter.inl" |
@@ -1,26 +1,43 @@ | |||||
#pragma once | #pragma once | ||||
#include <ecs/config.h> | #include <ecs/config.h> | ||||
#include <ecs/tag/system.h> | |||||
#include <ecs/context/context.fwd.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 | struct dependency_item_t | ||||
{ | { | ||||
using system_tag_type = T_system_tag; | using system_tag_type = T_system_tag; | ||||
using execute_type = T_execute; | using execute_type = T_execute; | ||||
using dependency_ids_type = T_dependency_ids; | 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 | struct task_t | ||||
{ | { | ||||
public: | public: | ||||
@@ -32,50 +49,76 @@ beg_namespace_ecs_core_system_scheduler | |||||
std::atomic<size_t> _dependency_count; | std::atomic<size_t> _dependency_count; | ||||
public: | 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> | 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 | 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> | 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 | 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> | 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> | template<typename T_context, typename T_dependency_items> | ||||
struct task_group_t | 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>; | using tasks_tuple_type = mp::list::unwrap_t<hana::tuple, task_types>; | ||||
private: | 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: | 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: | 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> | 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> | 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> | template<typename T_settings> | ||||
struct atomic_counter | struct atomic_counter | ||||
{ | { | ||||
@@ -238,43 +230,24 @@ beg_namespace_ecs_core_system_scheduler | |||||
context_type& _context; | context_type& _context; | ||||
public: | 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> | 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/tag/system.h> | ||||
#include <ecs/core/system/instance.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> | template<typename T_settings, typename T_entity_handle> | ||||
struct tuple | struct tuple | ||||
@@ -94,5 +96,4 @@ beg_namespace_ecs_core_system_storage | |||||
{ return instance_by_tag(ssig.tag()); } | { return instance_by_tag(ssig.tag()); } | ||||
}; | }; | ||||
} | |||||
end_namespace_ecs_core_system_storage | |||||
} } } } |
@@ -4,6 +4,11 @@ | |||||
#include "./utils/counter_blocker.h" | #include "./utils/counter_blocker.h" | ||||
#include "./utils/fixed_function.h" | #include "./utils/fixed_function.h" | ||||
#include "./utils/movable_atomic.h" | #include "./utils/movable_atomic.h" | ||||
#include "./utils/ordered_vector.h" | |||||
#include "./utils/scope_guard.h" | #include "./utils/scope_guard.h" | ||||
#include "./utils/storage_cast.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/config.h> | ||||
#include <ecs/core/mp/list.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> | template<typename T_settings> | ||||
struct bitset | struct bitset | ||||
{ | { | ||||
private: | private: | ||||
/** | |||||
* get the component signature list | |||||
* | |||||
* @return component signature list | |||||
*/ | |||||
static constexpr decltype(auto) csl() noexcept | static constexpr decltype(auto) csl() noexcept | ||||
{ return (T_settings { }).component_signatures(); } | { return (T_settings { }).component_signatures(); } | ||||
/** | |||||
* get the tags of all components | |||||
* | |||||
* @return list of all component tags | |||||
*/ | |||||
static constexpr decltype(auto) all_components() noexcept | static constexpr decltype(auto) all_components() noexcept | ||||
{ return csl().all_components(); } | { return csl().all_components(); } | ||||
public: | public: | ||||
/** | |||||
* get the number of components | |||||
* | |||||
* @return integral constant with number of components | |||||
*/ | |||||
static constexpr decltype(auto) component_count() noexcept | static constexpr decltype(auto) component_count() noexcept | ||||
{ return hana::size(all_components()); } | { 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> | 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()>; | using bitset_type = std::bitset<component_count()>; | ||||
private: | private: | ||||
bitset_type _bitset; | bitset_type _bitset; | ||||
public: | 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> | 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> | 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> | 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 <mutex> | ||||
#include <condition_variable> | #include <condition_variable> | ||||
#include <ecs/config.h> | #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 | struct counter_blocker | ||||
{ | { | ||||
private: | 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: | 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> | 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" | #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> | template<typename T_signature, size_t T_storage_size = 64> | ||||
struct fixed_function; | struct fixed_function; | ||||
@@ -25,122 +32,88 @@ beg_namespace_ecs_core_utils | |||||
private: | private: | ||||
union | 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: | 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: | 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> | 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> | 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; | 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> | 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> | #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> | template<typename T> | ||||
struct movable_atomic final | struct movable_atomic final | ||||
: std::atomic<T> | : std::atomic<T> | ||||
@@ -15,29 +21,46 @@ beg_namespace_ecs_core_utils | |||||
public: | public: | ||||
using base_type::base_type; | 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()) | : 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()); | this->store(other.load()); | ||||
return *this; | return *this; | ||||
} | } | ||||
/** | |||||
* assignment constructor to assign integral constants | |||||
*/ | |||||
template<T value> | 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); | this->store(decltype(x)::value); | ||||
return *this; | 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__ ( \ | auto scope_guard_ ## __LINE__ ( \ | ||||
::ecs::core::utils::make_scope_guard(__VA_ARGS__)) | ::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> | template<typename T_func> | ||||
struct scope_guard final | struct scope_guard final | ||||
: T_func | : 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> { }) | 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( | inline ~scope_guard() noexcept( | ||||
noexcept(std::declval<T_func>().operator()())) | noexcept(std::declval<T_func>().operator()())) | ||||
{ this->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> | template<typename T_func> | ||||
inline decltype(auto) make_scope_guard(T_func&& f) | inline decltype(auto) make_scope_guard(T_func&& f) | ||||
noexcept(std::is_nothrow_move_constructible<T_func> { }) | noexcept(std::is_nothrow_move_constructible<T_func> { }) | ||||
{ return scope_guard<mp::decay_t<T_func>>(std::forward<T_func>(f)); } | { 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> | #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> | template <typename T, typename T_storage> | ||||
inline constexpr decltype(auto) storage_cast(T_storage* storage) noexcept | 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/pool.h" | ||||
#include "./thread_pool/types.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 | #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 | struct thread_pool | ||||
{ | { | ||||
private: | private: | ||||
@@ -15,75 +21,47 @@ beg_namespace_ecs_core_utils | |||||
using atomic_size_t = std::atomic<size_t>; | using atomic_size_t = std::atomic<size_t>; | ||||
private: | 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: | 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" | #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 "./types.h" | ||||
#include "../movable_atomic.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 | struct thread_pool_worker | ||||
{ | { | ||||
private: | private: | ||||
/** | |||||
* state of the worker | |||||
*/ | |||||
enum class state | 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>; | 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: | 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: | 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> | 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 | #pragma once | ||||
#include "./settings/entity_storage.h" | #include "./settings/entity_storage.h" | ||||
#include "./settings/refresh_parallelism.h" | |||||
#include "./settings/scheduler.h" | |||||
#include "./settings/settings.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/config.h> | ||||
#include <ecs/core/entity/storage/dynamic.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> | template<size_t T_size> | ||||
struct dynamic_builder_t | 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> | 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/config.h> | ||||
#include <ecs/core/entity/storage/fixed.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> | template<size_t T_size> | ||||
struct fixed_builder_t | 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> | 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> | #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) enable = hana::true_c; | ||||
constexpr decltype(auto) disable = hana::false_c; | constexpr decltype(auto) disable = hana::false_c; | ||||
} | |||||
end_namespace_ecs_settings_refresh_parallelism | |||||
} } } |
@@ -3,12 +3,13 @@ | |||||
#include <ecs/config.h> | #include <ecs/config.h> | ||||
#include <ecs/core/system/scheduler/atomic_counter.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> | template<typename T_settings, typename T_context> | ||||
constexpr decltype(auto) operator()(T_settings, T_context&& context) const noexcept | 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 "./refresh_parallelism.h" | ||||
#include "./scheduler.h" | #include "./scheduler.h" | ||||
beg_namespace_ecs_settings | |||||
{ | |||||
namespace ecs { | |||||
namespace settings { | |||||
namespace keys | namespace keys | ||||
{ | { | ||||
@@ -22,86 +22,128 @@ beg_namespace_ecs_settings | |||||
constexpr decltype(auto) scheduler = hana::size_c<5>; | 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> | template<typename T_options> | ||||
struct settings_t | struct settings_t | ||||
{ | { | ||||
private: | 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> | 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 */ | 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 */ | 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 | 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/config.h> | ||||
#include <ecs/core/system/storage/tuple.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 | 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/signature.h" | ||||
#include "./component/storage.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 <ecs/tag/component.h> | ||||
#include "./storage.h" | #include "./storage.h" | ||||
beg_namespace_ecs_signature_component | |||||
{ | |||||
namespace ecs { | |||||
namespace signature { | |||||
namespace component { | |||||
namespace keys | namespace keys | ||||
{ | { | ||||
constexpr decltype(auto) storage = hana::size_c<0>; | 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> | template<typename T_component_tag_list, typename T_options> | ||||
struct signature_t | struct signature_t | ||||
{ | { | ||||
static_assert(tag::component::is_list(T_component_tag_list { }) == hana::true_c, "component signature needs a list of component tags"); | static_assert(tag::component::is_list(T_component_tag_list { }) == hana::true_c, "component signature needs a list of component tags"); | ||||
private: | 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> | 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> | 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> | 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 | 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> | 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/default.h" | ||||
#include "./storage/dynamic.h" | #include "./storage/dynamic.h" | ||||
#include "./storage/empty.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 "./empty.h" | ||||
#include "./dynamic.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 | struct default_builder_t | ||||
{ | { | ||||
template<typename T_settings, typename T_component_tag_list> | 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/config.h> | ||||
#include <ecs/core/component/storage/dynamic.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> | template<size_t T_size> | ||||
struct dynamic_builder_t | 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/config.h> | ||||
#include <ecs/core/component/storage/empty.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 | struct empty_builder_t | ||||
{ | { | ||||
template<typename T_settings, typename T_component_tag_list> | 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/config.h> | ||||
#include <ecs/core/component/storage/fixed.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> | template<size_t T_size> | ||||
struct fixed_builder_t | 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/output.h" | ||||
#include "./system/parallelism.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> | #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 | struct empty_output | ||||
{ }; | { }; | ||||
@@ -17,12 +19,11 @@ beg_namespace_ecs_signature_system_output | |||||
} | } | ||||
template<typename T_output> | template<typename T_output> | ||||
using type = __impl::output_t<T_output>; | |||||
using type = detail::output_t<T_output>; | |||||
template<typename T_output> | template<typename T_output> | ||||
constexpr decltype(auto) value = type<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/config.h> | ||||
#include <ecs/core/system/parallelism/composer/fixed_threshold.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> | template<typename T_threshold, typename T_lower_strategy, typename T_greater_strategy> | ||||
struct fixed_threshold_builder_t | 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 "./fixed_threshold.h" | ||||
#include "../strategy/none.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 | 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/config.h> | ||||
#include <ecs/core/system/parallelism/strategy/none.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 | 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/config.h> | ||||
#include <ecs/core/system/parallelism/strategy/split_evenly.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> | template<typename T_split> | ||||
struct split_evenly_builder_t | 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/config.h> | ||||
#include <ecs/core/system/parallelism/strategy/split_evenly.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 | 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/config.h> | ||||
#include <ecs/core/system/parallelism/strategy/split_every.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> | template<typename T_split> | ||||
struct split_every_builder_t | 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 "./output.h" | ||||
#include "./parallelism.h" | #include "./parallelism.h" | ||||
beg_namespace_ecs_signature_system | |||||
{ | |||||
namespace ecs { | |||||
namespace signature { | |||||
namespace system { | |||||
namespace keys | namespace keys | ||||
{ | { | ||||
@@ -20,8 +21,15 @@ beg_namespace_ecs_signature_system | |||||
constexpr decltype(auto) output = hana::size_c<4>; | 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> | template<typename T_system_tag, typename T_options> | ||||
struct signature_t | struct signature_t | ||||
{ | { | ||||
@@ -30,89 +38,130 @@ beg_namespace_ecs_signature_system | |||||
using tag_type = T_system_tag; | using tag_type = T_system_tag; | ||||
private: | 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> | 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> | 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 */ | 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 */ | 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 */ | 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> | 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> | 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> | 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> | 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> | 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 | struct make_t | ||||
{ | { | ||||
template<typename T_system_tag> | 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> | 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 { }; | |||||
} | |||||
} | |||||
} } } |