Ver a proveniência

* Added doxygen

* Removed namespace macros
* Refactoring: split inline code in header and inline file
* Continued implementation of system execution
master
bergmann há 6 anos
ascendente
cometimento
56b0d5d76c
100 ficheiros alterados com 6962 adições e 5550 eliminações
  1. +2
    -1
      .gitignore
  2. +3
    -0
      .gitmodules
  3. +18
    -4
      CMakeLists.txt
  4. +0
    -52
      cmake/GlobalCompilerFlags.cmake
  5. +0
    -4054
      cmake/cotire.cmake
  6. +1
    -0
      cmake/modules
  7. +2495
    -0
      doxygen
  8. +1
    -110
      include/ecs/config.h
  9. +3
    -1
      include/ecs/context.h
  10. +198
    -138
      include/ecs/context/base.h
  11. +210
    -0
      include/ecs/context/base.inl
  12. +5
    -6
      include/ecs/context/context.fwd.h
  13. +6
    -7
      include/ecs/context/context.h
  14. +7
    -5
      include/ecs/context/defer_proxy.h
  15. +7
    -5
      include/ecs/context/step_proxy.h
  16. +3
    -1
      include/ecs/core/component.h
  17. +219
    -101
      include/ecs/core/component/manager.h
  18. +196
    -0
      include/ecs/core/component/manager.inl
  19. +4
    -1
      include/ecs/core/component/storage.h
  20. +67
    -25
      include/ecs/core/component/storage/base.h
  21. +55
    -0
      include/ecs/core/component/storage/base.inl
  22. +12
    -4
      include/ecs/core/component/storage/dynamic.h
  23. +12
    -4
      include/ecs/core/component/storage/empty.h
  24. +14
    -5
      include/ecs/core/component/storage/fixed.h
  25. +71
    -0
      include/ecs/core/component/storage/interface.h
  26. +4
    -1
      include/ecs/core/entity/storage.h
  27. +156
    -98
      include/ecs/core/entity/storage/base.h
  28. +172
    -0
      include/ecs/core/entity/storage/base.inl
  29. +16
    -7
      include/ecs/core/entity/storage/dynamic.h
  30. +18
    -8
      include/ecs/core/entity/storage/fixed.h
  31. +69
    -0
      include/ecs/core/entity/storage/interface.h
  32. +22
    -4
      include/ecs/core/mp/core/copy_qualifiers.h
  33. +7
    -4
      include/ecs/core/mp/core/decay.h
  34. +29
    -9
      include/ecs/core/mp/core/is_list.h
  35. +10
    -4
      include/ecs/core/mp/core/is_specialization_of.h
  36. +31
    -11
      include/ecs/core/mp/core/is_valid.h
  37. +39
    -7
      include/ecs/core/mp/core/wrap.h
  38. +104
    -22
      include/ecs/core/mp/list.h
  39. +94
    -6
      include/ecs/core/mp/option_map.h
  40. +27
    -9
      include/ecs/core/mp/tag.h
  41. +1
    -0
      include/ecs/core/system.h
  42. +7
    -0
      include/ecs/core/system/data_proxy.h
  43. +54
    -0
      include/ecs/core/system/data_proxy/base.h
  44. +39
    -0
      include/ecs/core/system/data_proxy/base.inl
  45. +95
    -0
      include/ecs/core/system/data_proxy/single.h
  46. +70
    -0
      include/ecs/core/system/data_proxy/single.inl
  47. +18
    -7
      include/ecs/core/system/instance.h
  48. +3
    -0
      include/ecs/core/system/parallelism/composer.h
  49. +9
    -14
      include/ecs/core/system/parallelism/composer/fixed_threshold.h
  50. +28
    -7
      include/ecs/core/system/parallelism/strategy/none.h
  51. +6
    -5
      include/ecs/core/system/parallelism/strategy/split_evenly.h
  52. +6
    -4
      include/ecs/core/system/parallelism/strategy/split_every.h
  53. +3
    -1
      include/ecs/core/system/scheduler.h
  54. +177
    -204
      include/ecs/core/system/scheduler/atomic_counter.h
  55. +278
    -0
      include/ecs/core/system/scheduler/atomic_counter.inl
  56. +5
    -4
      include/ecs/core/system/storage/tuple.h
  57. +6
    -1
      include/ecs/core/utils.h
  58. +72
    -14
      include/ecs/core/utils/bitset.h
  59. +48
    -0
      include/ecs/core/utils/bitset.inl
  60. +36
    -40
      include/ecs/core/utils/counter_blocker.h
  61. +40
    -0
      include/ecs/core/utils/counter_blocker.inl
  62. +82
    -109
      include/ecs/core/utils/fixed_function.h
  63. +129
    -0
      include/ecs/core/utils/fixed_function.inl
  64. +33
    -10
      include/ecs/core/utils/movable_atomic.h
  65. +186
    -0
      include/ecs/core/utils/ordered_vector.h
  66. +31
    -7
      include/ecs/core/utils/scope_guard.h
  67. +15
    -5
      include/ecs/core/utils/storage_cast.h
  68. +4
    -1
      include/ecs/core/utils/thread_pool.h
  69. +51
    -73
      include/ecs/core/utils/thread_pool/pool.h
  70. +16
    -0
      include/ecs/core/utils/thread_pool/pool.inl
  71. +13
    -6
      include/ecs/core/utils/thread_pool/types.h
  72. +60
    -57
      include/ecs/core/utils/thread_pool/worker.h
  73. +46
    -0
      include/ecs/core/utils/thread_pool/worker.inl
  74. +5
    -1
      include/ecs/settings.h
  75. +10
    -10
      include/ecs/settings/entity_storage/dynamic.h
  76. +10
    -10
      include/ecs/settings/entity_storage/fixed.h
  77. +4
    -4
      include/ecs/settings/refresh_parallelism.h
  78. +7
    -7
      include/ecs/settings/scheduler/atomic_counter.h
  79. +102
    -60
      include/ecs/settings/settings.h
  80. +134
    -0
      include/ecs/settings/settings.inl
  81. +6
    -6
      include/ecs/settings/system_storage/tuple.h
  82. +3
    -1
      include/ecs/signature/component.h
  83. +102
    -42
      include/ecs/signature/component/signature.h
  84. +81
    -0
      include/ecs/signature/component/signature.inl
  85. +2
    -1
      include/ecs/signature/component/storage.h
  86. +17
    -6
      include/ecs/signature/component/storage/default.h
  87. +21
    -7
      include/ecs/signature/component/storage/dynamic.h
  88. +16
    -6
      include/ecs/signature/component/storage/empty.h
  89. +21
    -7
      include/ecs/signature/component/storage/fixed.h
  90. +31
    -0
      include/ecs/signature/component/storage/interface.h
  91. +3
    -1
      include/ecs/signature/system.h
  92. +8
    -7
      include/ecs/signature/system/output.h
  93. +8
    -6
      include/ecs/signature/system/parallelism/composer/fixed_threshold.h
  94. +7
    -6
      include/ecs/signature/system/parallelism/composer/none_below_threshold.h
  95. +7
    -6
      include/ecs/signature/system/parallelism/strategy/none.h
  96. +7
    -6
      include/ecs/signature/system/parallelism/strategy/split_evenly.h
  97. +7
    -6
      include/ecs/signature/system/parallelism/strategy/split_evenly_cores.h
  98. +7
    -6
      include/ecs/signature/system/parallelism/strategy/split_every.h
  99. +104
    -55
      include/ecs/signature/system/signature.h
  100. +158
    -0
      include/ecs/signature/system/signature.inl

+ 2
- 1
.gitignore Ver ficheiro

@@ -1,2 +1,3 @@
.vscode/
build/
build/
docu/

+ 3
- 0
.gitmodules Ver ficheiro

@@ -0,0 +1,3 @@
[submodule "cmake/modules"]
path = cmake/modules
url = b3rgmann@git.bergmann89.de:cpp/CmakeModules.git

+ 18
- 4
CMakeLists.txt Ver ficheiro

@@ -1,15 +1,22 @@
# Initialize CMake ################################################################################

CMake_Minimum_Required ( VERSION 3.5.1 FATAL_ERROR )

If ( NOT CMAKE_BUILD_TYPE )
Set ( CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build!" FORCE )
EndIf ( )

CMake_Minimum_Required ( VERSION 3.5.1 FATAL_ERROR )
Set ( CMAKE_CXX_STANDARD 17 )
Set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake" )
Include ( GlobalCompilerFlags OPTIONAL )
Set ( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH}
"${CMAKE_CURRENT_SOURCE_DIR}/cmake"
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules" )

Include ( pedantic OPTIONAL )
Include ( cotire OPTIONAL )

Set ( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${PEDANTIC_C_FLAGS}" )
Set ( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${PEDANTIC_CXX_FLAGS}" )

# Tests ###########################################################################################

Include ( CTest )
@@ -22,4 +29,11 @@ Find_Package ( Hana REQUIRED )
# Projects ########################################################################################

Add_SubDirectory ( ${CMAKE_CURRENT_SOURCE_DIR}/src )
Add_SubDirectory ( ${CMAKE_CURRENT_SOURCE_DIR}/test )
Add_SubDirectory ( ${CMAKE_CURRENT_SOURCE_DIR}/test )

# Documentation ###################################################################################

Configure_File ( ${CMAKE_CURRENT_SOURCE_DIR}/doxygen
${CMAKE_CURRENT_BINARY_DIR}/doxygen )
Add_Custom_Target ( docu
doxygen ${CMAKE_CURRENT_BINARY_DIR}/doxygen )

+ 0
- 52
cmake/GlobalCompilerFlags.cmake Ver ficheiro

@@ -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
- 4054
cmake/cotire.cmake
A apresentação das diferenças no ficheiro foi suprimida por ser demasiado grande
Ver ficheiro


+ 1
- 0
cmake/modules

@@ -0,0 +1 @@
Subproject commit 9a495487c981774d0cb57478b855d58898c1505b

+ 2495
- 0
doxygen
A apresentação das diferenças no ficheiro foi suprimida por ser demasiado grande
Ver ficheiro


+ 1
- 110
include/ecs/config.h Ver ficheiro

@@ -1,6 +1,7 @@
#pragma once

// TODO debug!!!
#include <string>
#include <cxxabi.h>

template<typename T>
@@ -18,116 +19,6 @@ struct type_helper
#include <boost/hana.hpp>
#include <boost/hana/ext/std/tuple.hpp>

#define ecs_define_namespace_beg(parent, name) \
parent { \
namespace name

#define ecs_define_namespace_end(parent) \
} \
parent

#define beg_namespace_ecs namespace ecs
#define end_namespace_ecs

#define beg_namespace_ecs_context ecs_define_namespace_beg(beg_namespace_ecs, context)
#define end_namespace_ecs_context ecs_define_namespace_end(end_namespace_ecs)

#define beg_namespace_ecs_core ecs_define_namespace_beg(beg_namespace_ecs, core)
#define end_namespace_ecs_core ecs_define_namespace_end(end_namespace_ecs)

#define beg_namespace_ecs_core_component ecs_define_namespace_beg(beg_namespace_ecs_core, component)
#define end_namespace_ecs_core_component ecs_define_namespace_end(end_namespace_ecs_core)

#define beg_namespace_ecs_core_component_storage ecs_define_namespace_beg(beg_namespace_ecs_core_component, storage)
#define end_namespace_ecs_core_component_storage ecs_define_namespace_end(end_namespace_ecs_core_component)

#define beg_namespace_ecs_core_entity ecs_define_namespace_beg(beg_namespace_ecs_core, entity)
#define end_namespace_ecs_core_entity ecs_define_namespace_end(end_namespace_ecs_core)

#define beg_namespace_ecs_core_entity_storage ecs_define_namespace_beg(beg_namespace_ecs_core_entity, storage)
#define end_namespace_ecs_core_entity_storage ecs_define_namespace_end(end_namespace_ecs_core_entity)

#define beg_namespace_ecs_core_mp ecs_define_namespace_beg(beg_namespace_ecs_core, mp)
#define end_namespace_ecs_core_mp ecs_define_namespace_end(end_namespace_ecs_core)

#define beg_namespace_ecs_core_mp_list ecs_define_namespace_beg(beg_namespace_ecs_core_mp, list)
#define end_namespace_ecs_core_mp_list ecs_define_namespace_end(end_namespace_ecs_core_mp)

#define beg_namespace_ecs_core_mp_option_map ecs_define_namespace_beg(beg_namespace_ecs_core_mp, option_map)
#define end_namespace_ecs_core_mp_option_map ecs_define_namespace_end(end_namespace_ecs_core_mp)

#define beg_namespace_ecs_core_mp_tag ecs_define_namespace_beg(beg_namespace_ecs_core_mp, tag)
#define end_namespace_ecs_core_mp_tag ecs_define_namespace_end(end_namespace_ecs_core_mp)

#define beg_namespace_ecs_core_system ecs_define_namespace_beg(beg_namespace_ecs_core, system)
#define end_namespace_ecs_core_system ecs_define_namespace_end(end_namespace_ecs_core)

#define beg_namespace_ecs_core_parallelism ecs_define_namespace_beg(beg_namespace_ecs_core_system, parallelism)
#define end_namespace_ecs_core_parallelism ecs_define_namespace_end(end_namespace_ecs_core_system)

#define beg_namespace_ecs_core_system_scheduler ecs_define_namespace_beg(beg_namespace_ecs_core_system, scheduler)
#define end_namespace_ecs_core_system_scheduler ecs_define_namespace_end(end_namespace_ecs_core_system)

#define beg_namespace_ecs_core_system_storage ecs_define_namespace_beg(beg_namespace_ecs_core_system, storage)
#define end_namespace_ecs_core_system_storage ecs_define_namespace_end(end_namespace_ecs_core_system)

#define beg_namespace_ecs_core_utils ecs_define_namespace_beg(beg_namespace_ecs_core, utils)
#define end_namespace_ecs_core_utils ecs_define_namespace_end(end_namespace_ecs_core)

#define beg_namespace_ecs_settings ecs_define_namespace_beg(beg_namespace_ecs, settings)
#define end_namespace_ecs_settings ecs_define_namespace_end(end_namespace_ecs)

#define beg_namespace_ecs_settings_entity_storage ecs_define_namespace_beg(beg_namespace_ecs_settings, entity_storage)
#define end_namespace_ecs_settings_entity_storage ecs_define_namespace_end(end_namespace_ecs_settings)

#define beg_namespace_ecs_settings_refresh_parallelism ecs_define_namespace_beg(beg_namespace_ecs_settings, refresh_parallelism)
#define end_namespace_ecs_settings_refresh_parallelism ecs_define_namespace_end(end_namespace_ecs_settings)

#define beg_namespace_ecs_settings_scheduler ecs_define_namespace_beg(beg_namespace_ecs_settings, scheduler)
#define end_namespace_ecs_settings_scheduler ecs_define_namespace_end(end_namespace_ecs_settings)

#define beg_namespace_ecs_settings_system_storage ecs_define_namespace_beg(beg_namespace_ecs_settings, system_storage)
#define end_namespace_ecs_settings_system_storage ecs_define_namespace_end(end_namespace_ecs_settings)

#define beg_namespace_ecs_signature ecs_define_namespace_beg(beg_namespace_ecs, signature)
#define end_namespace_ecs_signature ecs_define_namespace_end(end_namespace_ecs)

#define beg_namespace_ecs_signature_component ecs_define_namespace_beg(beg_namespace_ecs_signature, component)
#define end_namespace_ecs_signature_component ecs_define_namespace_end(end_namespace_ecs_signature)

#define beg_namespace_ecs_signature_component_storage ecs_define_namespace_beg(beg_namespace_ecs_signature_component, storage)
#define end_namespace_ecs_signature_component_storage ecs_define_namespace_end(end_namespace_ecs_signature_component)

#define beg_namespace_ecs_signature_system ecs_define_namespace_beg(beg_namespace_ecs_signature, system)
#define end_namespace_ecs_signature_system ecs_define_namespace_end(end_namespace_ecs_signature)

#define beg_namespace_ecs_signature_system_output ecs_define_namespace_beg(beg_namespace_ecs_signature_system, output)
#define end_namespace_ecs_signature_system_output ecs_define_namespace_end(end_namespace_ecs_signature_system)

#define beg_namespace_ecs_signature_system_parallelism ecs_define_namespace_beg(beg_namespace_ecs_signature_system, parallelism)
#define end_namespace_ecs_signature_system_parallelism ecs_define_namespace_end(end_namespace_ecs_signature_system)

#define beg_namespace_ecs_signature_list ecs_define_namespace_beg(beg_namespace_ecs, signature_list)
#define end_namespace_ecs_signature_list ecs_define_namespace_end(end_namespace_ecs)

#define beg_namespace_ecs_signature_list_component ecs_define_namespace_beg(beg_namespace_ecs_signature_list, component)
#define end_namespace_ecs_signature_list_component ecs_define_namespace_end(end_namespace_ecs_signature_list)

#define beg_namespace_ecs_signature_list_system ecs_define_namespace_beg(beg_namespace_ecs_signature_list, system)
#define end_namespace_ecs_signature_list_system ecs_define_namespace_end(end_namespace_ecs_signature_list)

#define beg_namespace_ecs_system_execution_adapter ecs_define_namespace_beg(beg_namespace_ecs, system_execution_adapter)
#define end_namespace_ecs_system_execution_adapter ecs_define_namespace_end(end_namespace_ecs)

#define beg_namespace_ecs_tag ecs_define_namespace_beg(beg_namespace_ecs, tag)
#define end_namespace_ecs_tag ecs_define_namespace_end(end_namespace_ecs)

#define beg_namespace_ecs_tag_component ecs_define_namespace_beg(beg_namespace_ecs_tag, component)
#define end_namespace_ecs_tag_component ecs_define_namespace_end(end_namespace_ecs_tag)

#define beg_namespace_ecs_tag_system ecs_define_namespace_beg(beg_namespace_ecs_tag, system)
#define end_namespace_ecs_tag_system ecs_define_namespace_end(end_namespace_ecs_tag)

namespace ecs
{



+ 3
- 1
include/ecs/context.h Ver ficheiro

@@ -3,4 +3,6 @@
#include "./context/base.h"
#include "./context/context.h"
#include "./context/defer_proxy.h"
#include "./context/step_proxy.h"
#include "./context/step_proxy.h"

#include "./context/base.inl"

+ 198
- 138
include/ecs/context/base.h Ver ficheiro

@@ -14,11 +14,17 @@
._##name(std::forward<T_args>(args)...))) \
{ return this->_##name(std::forward<T_args>(args)...); }

beg_namespace_ecs_context
{
namespace ecs {
namespace context {

namespace __impl
namespace detail
{

/**
* the base ecs context implementation
*
* @tparam T_settings settings type the environment is configured with
*/
template<typename T_settings>
struct base_t
{
@@ -28,8 +34,8 @@ beg_namespace_ecs_context
protected:
using context_type = ::ecs::context::type<settings_type>;
using component_manager_type = core::component::manager<settings_type>;
using chunk_meta_data_type = typename component_manager_type::chunk_meta_data_type;
using entity_storage_type = decltype((settings_type { }).entity_storage()(settings_type { }, hana::type_c<chunk_meta_data_type>));
using storage_meta_data_type = typename component_manager_type::storage_meta_data_type;
using entity_storage_type = decltype((settings_type { }).entity_storage()(settings_type { }, hana::type_c<storage_meta_data_type>));
using entity_handle_type = typename entity_storage_type::entity_handle_type;
using system_storage_type = decltype((settings_type { }).system_storage()(settings_type { }, hana::type_c<entity_handle_type>));
using scheduler_type = decltype((settings_type { }).scheduler()(settings_type { }, std::declval<context_type&>()));
@@ -41,179 +47,233 @@ beg_namespace_ecs_context
using handle_vector_type = std::vector<handle_type>;

protected:
context_type& _context;
context_type& _context; //!< reference to its own child class

component_manager_type _components;
entity_storage_type _entities;
system_storage_type _systems;
scheduler_type _scheduler;
component_manager_type _components; //!< object to store and manage all components
entity_storage_type _entities; //!< object to store and manage all entities
system_storage_type _systems; //!< object to store and manage all systems
scheduler_type _scheduler; //!< scheduler to execute the systems

core::utils::thread_pool _thread_pool;
core::utils::thread_pool _thread_pool; //!< thread pool to execute tasks parallel

handle_vector_type _to_match;
handle_vector_type _to_kill;
handle_vector_type _to_match; //!< handles of entities that were created in the last tick
handle_vector_type _to_kill; //!< handles of entities that were destroyed in the last tick

public:
inline base_t(context_type& p_context)
: _context (p_context)
, _components ()
, _entities ((settings_type { }).entity_storage()(settings_type { }, hana::type_c<chunk_meta_data_type>))
, _systems ((settings_type { }).system_storage()(settings_type { }, hana::type_c<entity_handle_type>))
, _scheduler ((settings_type { }).scheduler()(settings_type { }, p_context))
, _thread_pool (std::thread::hardware_concurrency() != 0
? std::thread::hardware_concurrency()
: 8 )
{ }

/**
* constructor
*
* @param p_context reference to its own child class
*/
inline base_t(context_type& p_context);

protected: /* misc */

/**
* execute the given function in the thread pool
*
* @tparam T_func type of the function to execute
*
* @param func function to execute
*/
template<typename T_func>
inline decltype(auto) _post_in_thread_pool(T_func&& func)
{
return _thread_pool.post(std::forward<T_func>(func));
}
inline void _post_in_thread_pool(T_func&& func);

protected: /* entity */

/**
* create a new entity
*
* @tparam T_args argument types to pass to the entity manager
*
* @param args arguments to pass to the entity manager
*
* @return handle of the created entity
*/
template<typename... T_args>
inline handle_type _create_entity(T_args&&... args)
{
_to_match.emplace_back(_entities.claim(std::forward<T_args>(args)...));
return _to_match.back();
}

inline void _kill_entity(const handle_type& handle)
{
_to_kill.emplace_back(handle);
}

inline bool _is_alive(const handle_type& handle) const
{
return _entities.is_valid(handle);
}
inline decltype(auto) _create_entity(T_args&&... args);

/**
* kill an entity
*
* @param handle handle of the entity to kill
*/
inline void _kill_entity(const handle_type& handle);

/**
* check if an entity is alive
*
* @param handle handle of the entity to check
*
* @retval TRUE if the entity is alive
* @retval FALSE if the entity is not alive
*/
inline bool _is_alive(const handle_type& handle) const;

protected: /* component */

/**
* add a new component to an entity
*
* @tparam T_component_tag component tag type to add to the entity
*
* @param handle handle of the entity
* @param ct tag of component to add
*
* @return reference to the created component
*/
template<typename T_component_tag>
inline decltype(auto) _add_component(const handle_type& handle, T_component_tag ct)
{
_to_match.emplace_back(handle);
auto& meta = _entities.meta_data(handle);
auto& cmd = meta.chunk_meta_data();
auto& c = _components.add(ct, handle, cmd);
auto& bitset = meta.bitset();
bitset.set_component(ct, true);
return c;
}
inline decltype(auto) _add_component(const handle_type& handle, T_component_tag ct);

/**
* check if an entity has an specific component
*
* @tparam T_component_tag component tag type to check for
*
* @param handle handle of entity to check
* @param ct component tag to check
*
* @retval TRUE if given entity has the requested component
* @retval FALSE if the given entity does not have the requested component
*/
template<typename T_component_tag>
inline decltype(auto) _has_component(const handle_type& handle, T_component_tag ct)
{
auto& meta = _entities.meta_data(handle);
auto& bitset = meta.bitset();
return bitset.has_component(ct);
}
inline decltype(auto) _has_component(const handle_type& handle, T_component_tag ct);

/**
* get a reference to the requested component
*
* @tparam T_component_tag component tag type to get
*
* @param handle handle of the entity to get the component for
* @param ct component tag to get the component for
*
* @return reference to the requested component
*/
template<typename T_component_tag>
inline decltype(auto) _get_component(const handle_type& handle, T_component_tag ct)
{
auto& meta = _entities.meta_data(handle);
auto& bitset = meta.bitset();
auto& cmd = meta.chunk_meta_data();
if (!bitset.has_component(ct))
throw std::invalid_argument("entity does not contain the requested compnent");
return _components.get(ct, handle, cmd);
}
inline decltype(auto) _get_component(const handle_type& handle, T_component_tag ct);

/**
* remove a component from an entity
*
* @tparam T_component_tag component tag type to remove
*
* @param handle handle of the entity to remove component at
* @param ct component tag to remove component for
*/
template<typename T_component_tag>
inline decltype(auto) _remove_component(const handle_type& handle, T_component_tag ct)
{
_to_match.emplace_back(handle);
auto& meta = _entities.meta_data(handle);
auto& bitset = meta.bitset();
bitset.set_component(ct, false);
}
inline void _remove_component(const handle_type& handle, T_component_tag ct);

protected: /* systems */

/**
* get the reference to a system instance by the system tag
*
* @tparam T_system_tag system tag type to get system instance for
*
* @param st system tag to get system instance for
*
* @return reference to the system instance
*/
template<typename T_system_tag>
inline auto& _instance_by_tag(T_system_tag st)
{
return _systems.instance_by_tag(st);
}
inline auto& _instance_by_tag(T_system_tag st);

/**
* get the reference to a system instance by it's index
*
* @tparam T_index index type to get system instance for
*
* @param index index to get system instance for
*
* @return reference to the system instance
*/
template<typename T_index>
inline auto& _instance_by_index(T_index)
{
return _systems.instance_by_index(T_index { });
}
inline auto& _instance_by_index(T_index index);

/**
* get the reference of a system by the system tag
*
* @tparam T_system_tag system tag type to get system for
*
* @param st system tag to get system for
*
* @return reference to the system
*/
template<typename T_system_tag>
inline auto& _system_by_tag(T_system_tag st)
{
return _systems.instance_by_tag(st).system();
}
inline auto& _system_by_tag(T_system_tag st);

/**
* get the reference to a system by it's index
*
* @tparam T_index index type to get system for
*
* @param index index to get system for
*
* @return reference to the system
*/
template<typename T_index>
inline auto& _system_by_index(T_index)
{
return _systems.instance_by_index(T_index { }).system();
}
inline auto& _system_by_index(T_index index);

/**
* execute the given function for each system sequential
*
* @tparam T_func function type to execute for each system
*
* @param func function to execute for each system
*/
template<typename T_func>
inline void _for_systems_sequential(T_func&& func)
{
_systems.for_each(std::forward<T_func>(func));
}
inline void _for_systems_sequential(T_func&& func);

/**
* execute the given function for each system in parallel
*
* @tparam T_func function type to execute for each system
*
* @param func function to execute for each system
*/
template<typename T_func>
inline void _for_systems_parallel(T_func&& func)
{
core::utils::counter_blocker counter(_systems.size());
counter.execute_and_wait_until_zero([this, &counter, func = std::forward<T_func>(func)]{
_systems.for_each([this, &counter, &func](auto& instance){
this->_post_in_thread_pool([&counter, &func, &instance]{
ecs_make_scope_guard([&counter](){
counter.decrement_and_notify_one();
});
func(instance);
});
});
});
}
inline void _for_systems_parallel(T_func&& func);

/**
* Execute function for each system, depending on the refresh_parallelism option of the settings object
* it will be executed sequentially or in parallel.
*
* @tparam T_func function type to execute for each system
*
* @param func function to execute for each system
*/
template<typename T_func>
inline void _for_systems_dispatch(T_func&& func)
{
hana::eval_if(
(settings_type { }).refresh_parallelism(),
[this, func=std::forward<T_func>(func)](auto _) {
_(this)->_for_systems_parallel(func);
},
[this, func=std::forward<T_func>(func)](auto _) {
_(this)->_for_systems_sequential(func);
});
}
inline void _for_systems_dispatch(T_func&& func);

protected: /* execute */

/**
* run the scheduler for the passed system tags (if no tags are passed, all systems are executed)
*
* @tparam T_system_tags system tag types to execute scheduler for
*
* @param sts system tags to execute scheduler for
*
* @return functor to run system execution adapter with
*/
template<typename... T_system_tags>
inline decltype(auto) _execute_systems(T_system_tags&&... sts) noexcept
{
auto tags = make_system_tag_list(std::forward<T_system_tags>(sts)...);
return [tags, this](auto&&... fns) {
auto os = hana::overload_linearly(std::forward<decltype(fns)>(fns)...);
this->_scheduler.execute(tags, os);
};
}
inline decltype(auto) _execute_systems(T_system_tags&&... sts) noexcept;

private:
private: /* static */

/**
* create a list of system tags from the passed tags (if no tag is passed all system tags are returned)
*
* @tparam T_system_tags system tag types to create list for
*
* @param tags system tags to create list for
*
* @return list of system tags
*/
template<typename... T_system_tags>
static constexpr decltype(auto) make_system_tag_list(T_system_tags&&... tags) noexcept
{
auto list = core::mp::list::make(std::forward<T_system_tags>(tags)...);
return hana::if_(
hana::equal(hana::size(list), hana::size_c<0>),
(settings_type { }).system_signatures().tags(),
list);
}
static constexpr decltype(auto) make_system_tag_list(T_system_tags&&... tags) noexcept;

};
}

}
end_namespace_ecs_context
} }

+ 210
- 0
include/ecs/context/base.inl Ver ficheiro

@@ -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);
}

} } }

+ 5
- 6
include/ecs/context/context.fwd.h Ver ficheiro

@@ -2,17 +2,16 @@

#include <ecs/config.h>

beg_namespace_ecs_context
{
namespace ecs {
namespace context {

namespace __impl
namespace detail
{
template<typename T_settings>
struct context_t;
}

template<typename T_settings>
using type = __impl::context_t<T_settings>;
using type = detail::context_t<T_settings>;

}
end_namespace_ecs_context
} }

+ 6
- 7
include/ecs/context/context.h Ver ficheiro

@@ -6,10 +6,10 @@
#include "./context.fwd.h"
#include "./step_proxy.h"

beg_namespace_ecs_context
{
namespace ecs {
namespace context {

namespace __impl
namespace detail
{
template<typename T_settings>
struct context_t
@@ -60,9 +60,8 @@ beg_namespace_ecs_context
};
}

constexpr decltype(auto) make = __impl::make_t { };
constexpr decltype(auto) make = detail::make_t { };

constexpr decltype(auto) make_uptr = __impl::make_uptr_t { };
constexpr decltype(auto) make_uptr = detail::make_uptr_t { };

}
end_namespace_ecs_context
} }

+ 7
- 5
include/ecs/context/defer_proxy.h Ver ficheiro

@@ -4,11 +4,14 @@

#include "./base.h"

beg_namespace_ecs_context
{
namespace ecs {
namespace context {

namespace __impl
namespace detail
{
/**
* proxy class to make entity, component and system management visible to users of the context
*/
template<typename T_settings>
struct defer_proxy_t
: public base_t<T_settings>
@@ -45,5 +48,4 @@ beg_namespace_ecs_context
};
}

}
end_namespace_ecs_context
} }

+ 7
- 5
include/ecs/context/step_proxy.h Ver ficheiro

@@ -4,11 +4,14 @@

#include "./defer_proxy.h"

beg_namespace_ecs_context
{
namespace ecs {
namespace context {

namespace __impl
namespace detail
{
/**
* proxy class to make system execution visible to users of the context
*/
template<typename T_settings>
struct step_proxy_t
: public defer_proxy_t<T_settings>
@@ -31,5 +34,4 @@ beg_namespace_ecs_context
};
}

}
end_namespace_ecs_context
} }

+ 3
- 1
include/ecs/core/component.h Ver ficheiro

@@ -1,4 +1,6 @@
#pragma once

#include "./component/manager.h"
#include "./component/storage.h"
#include "./component/storage.h"

#include "./component/manager.inl"

+ 219
- 101
include/ecs/core/component/manager.h Ver ficheiro

@@ -5,128 +5,189 @@
#include <ecs/core/mp/core/decay.h>
#include <ecs/core/mp/core/wrap.h>

beg_namespace_ecs_core_component
{
namespace ecs {
namespace core {
namespace component {

/* make_chunk_tuple */
/* make_storage_tuple */

namespace __impl
namespace detail
{
struct make_chunk_tuple_t
/**
* predicate type to make a tuple of the different component storages from the settings
*/
struct make_storage_tuple_t
{
/**
* execute the predicate
*
* @tparam T_settings settings type
*
* @param settings settings to build tuple from
*
* @return tuple of component storages (@ref storage_iterface_t)
*/
template<typename T_settings>
constexpr decltype(auto) operator()(T_settings s) const noexcept
{
auto cls = s.component_signatures();
return hana::unpack(
hana::transform(cls.items, [s](auto x){
auto csig = mp::unwrap(x);
return csig.storage()(s, csig.tags());;
}),
hana::make_tuple);
}
constexpr decltype(auto) operator()(T_settings settings) const noexcept;
};
}

constexpr decltype(auto) make_chunk_tuple = __impl::make_chunk_tuple_t { };
constexpr decltype(auto) make_storage_tuple = detail::make_storage_tuple_t { };

/* make_chunk_meta_data */
/* make_storage_meta_data */

namespace __impl
namespace detail
{
struct make_chunk_meta_data_t
/**
* predicate type to make a meta data object of a given storage
*/
struct make_storage_meta_data_t
{
template<typename T_chunk>
constexpr decltype(auto) operator()(T_chunk&& chunk) const noexcept
{
using chunk_type = mp::decay_t<decltype(chunk)>;
using meta_data_type = typename chunk_type::meta_data_type;
return meta_data_type { };
}
/**
* execute the predicate
*
* @tparam T_storage storage type to make the meta data object for
*
* @param storage storage to make the meta data object for
*
* @return meta data object for the given storage
*/
template<typename T_storage>
constexpr decltype(auto) operator()(T_storage&& storage) const noexcept;
};
}

constexpr decltype(auto) make_chunk_meta_data = __impl::make_chunk_meta_data_t { };
constexpr decltype(auto) make_storage_meta_data = detail::make_storage_meta_data_t { };

/* make_chunk_meta_data_tuple */
/* make_storage_meta_data_tuple */

namespace __impl
namespace detail
{
struct make_chunk_meta_data_tuple_t
/**
* predicate to create a tuple of meta data from the settings
*/
struct make_storage_meta_data_tuple_t
{
/**
* execute the predicate
*
* @tparam T_settings settings type to create the meta data tuple for
*
* @param settings settings to create the meta data tuple for
*
* @return meta data tuple for the given settings
*/
template<typename T_settings>
constexpr decltype(auto) operator()(T_settings s) const noexcept
{
using chunk_tuple_type = decltype(make_chunk_tuple(s));
using chunk_meta_data_tuple_type = decltype(hana::transform(
std::declval<chunk_tuple_type>(),
make_chunk_meta_data));
return chunk_meta_data_tuple_type { };
}
constexpr decltype(auto) operator()(T_settings settings) const noexcept;
};
}

constexpr decltype(auto) make_chunk_meta_data_tuple = __impl::make_chunk_meta_data_tuple_t { };
constexpr decltype(auto) make_storage_meta_data_tuple = detail::make_storage_meta_data_tuple_t { };

/* chunk_contains_tag */
/* storage_contains_tag */

namespace __impl
namespace detail
{
/**
* predicate type to check if the given storage contains the given component tag
*
* @tparam T_component_tag component tag type to check
*/
template<typename T_component_tag>
struct chunk_contains_tag_t
struct storage_contains_tag_t
{
template<typename T_chunk>
constexpr decltype(auto) operator()(T_chunk&&) const noexcept
{
using chunk_type = mp::decay_t<T_chunk>;
using component_tag_list_type = typename chunk_type::component_tag_list_type;
return hana::contains(component_tag_list_type { }, T_component_tag { });
}
/**
* execute the predicate
*
* @tparam T_storage storage type to check
*
* @param storage storage object to check
*
* @retval integral constant TRUE if the given component tag is managed by the given storage
* @retval integral constant FALSE if the given component tag is not managed by the given storage
*/
template<typename T_storage>
constexpr decltype(auto) operator()(T_storage&& storage) const noexcept;
};
}

template<typename T_component_tag>
constexpr decltype(auto) chunk_contains_tag = __impl::chunk_contains_tag_t<T_component_tag> { };
constexpr decltype(auto) storage_contains_tag = detail::storage_contains_tag_t<T_component_tag> { };

/* manager */

/**
* component manager
*
* @tparam T_settings settings to build the component manager for
*/
template<typename T_settings>
struct manager
{
public:
using chunk_tuple_type = decltype(make_chunk_tuple(T_settings { }));
using chunk_meta_data_type = decltype(make_chunk_meta_data_tuple(T_settings { }));
/** tuple of the different storages */
using storage_tuple_type = decltype(make_storage_tuple(T_settings { }));

/** tuple of the different storage meta data */
using storage_meta_data_type = decltype(make_storage_meta_data_tuple(T_settings { }));

private:
chunk_tuple_type _chunks;
storage_tuple_type _storages;

public:
/**
* get the storage index of the given component tag
*
* @tparam T_component_tag component tag type to get storage index for
*
* @param ct component tag to get storage index for
*
* @return integral constant of the storage index
*/
template<typename T_component_tag>
static constexpr decltype(auto) get_chunk_index(T_component_tag) noexcept
{
using ret_type = decltype(mp::list::index_of_first_matching(
std::declval<chunk_tuple_type>(),
chunk_contains_tag<T_component_tag>));
return ret_type { };
}
static constexpr decltype(auto) get_storage_index(T_component_tag ct) noexcept;

/**
* execute the given function for the storage that manages the given component tag
*
* @tparam T_self the component manager type
* @tparam T_component_tag component tag type to execute function for
* @tparam T_meta_data_tuple meta data tuple type to get meta data from
* @tparam T_func function type to execute
*
* @param self the component manager
* @param ct component tag to execute function for
* @param mdt meta data tuple to get meta data from
* @param func function to execute
*
* @return result of func
*/
template<
typename T_self,
typename T_component_tag,
typename T_meta_data_tuple,
typename T_func>
static constexpr decltype(auto) for_chunk_do(
static constexpr decltype(auto) for_storage_do(
T_self&& self,
T_component_tag ct,
T_meta_data_tuple&& mdt,
T_func&& func)
{
decltype(auto) index = get_chunk_index(ct);
decltype(auto) chunk = std::forward<T_self>(self).get_chunk_by_index(index);
decltype(auto) meta = hana::at(std::forward<T_meta_data_tuple>(mdt), index);
return std::forward<T_func>(func)(chunk, meta);
}
T_func&& func) noexcept;

/**
* get the component for the given component tag
*
* @tparam T_self the component manager type
* @tparam T_component_tag component tag type to execute function for
* @tparam T_entity_handle entity handle type
* @tparam T_meta_data_tuple meta data tuple type to get meta data from
*
* @param self the component manager
* @param ct component tag to execute function for
* qparam handle handle of the entity
* @param mdt meta data tuple to get meta data from
*
* @return the requested component
*/
template<
typename T_self,
typename T_component_tag,
@@ -136,14 +197,23 @@ beg_namespace_ecs_core_component
T_self&& self,
T_component_tag ct,
const T_entity_handle& handle,
const T_meta_data_tuple& mdt)
{
return for_chunk_do(std::forward<T_self>(self), ct, mdt,
[ct, handle](auto& chunk, const auto& md) -> decltype(auto) {
return chunk.get(ct, handle, md);
});
}
const T_meta_data_tuple& mdt) noexcept;

/**
* add a new component for the given component tag
*
* @tparam T_self the component manager type
* @tparam T_component_tag component tag type to execute function for
* @tparam T_entity_handle entity handle type
* @tparam T_meta_data_tuple meta data tuple type to get meta data from
*
* @param self the component manager
* @param ct component tag to execute function for
* qparam handle handle of the entity
* @param mdt meta data tuple to get meta data from
*
* @return the requested component
*/
template<
typename T_self,
typename T_component_tag,
@@ -153,44 +223,92 @@ beg_namespace_ecs_core_component
T_self&& self,
T_component_tag ct,
const T_entity_handle& handle,
const T_meta_data_tuple& mdt)
{
return for_chunk_do(std::forward<T_self>(self), ct, mdt,
[ct, handle](auto& chunk, const auto& md) -> decltype(auto) {
return chunk.add(ct, handle, md);
});
}
const T_meta_data_tuple& mdt) noexcept;

private:
/**
* get the component storage by index
*
* @tparam T_index index type to get component storage for
*
* @param index index to get component storage for
*
* @return component storage at the given index
*/
template<typename T_index>
constexpr decltype(auto) get_chunk_by_index(T_index index) noexcept
{
return hana::at(_chunks, index);
}
constexpr decltype(auto) get_storage_by_index(T_index index) noexcept;

/**
* get the component storage by the component tag
*
* @tparam T_component_tag component tag type to get component storage for
*
* @param ct component tag to get component storage for
*
* @return component storage for the given tag
*/
template<typename T_component_tag>
constexpr decltype(auto) get_chunk_by_tag(T_component_tag ct) noexcept
{
return hana::at(_chunks, get_chunk_index(ct));
}
constexpr decltype(auto) get_storage_by_tag(T_component_tag ct) noexcept;

public:
manager()
: _chunks(make_chunk_tuple(T_settings { }))
{ }
/**
* constructor
*/
inline manager();

/**
* get a reference to the component for the given component tag
*
* @tparam T_args set of the following parameter types
* T_component_tag component tag type to execute function for
* T_entity_handle entity handle type
* T_meta_data_tuple meta data tuple type to get meta data from
*
* @param args set of the following parameters
* ct component tag to execute function for
* handle handle of the entity
* mdt meta data tuple to get meta data from
*
* @return the requested component
*/
template<typename... T_args>
inline auto& get(T_args&&... args) & noexcept
{ return get_impl(*this, std::forward<T_args>(args)...); }
inline auto& get(T_args&&... args) &;

/**
* get a read-only reference to the component for the given component tag
*
* @tparam T_args set of the following parameter types
* T_component_tag component tag type to execute function for
* T_entity_handle entity handle type
* T_meta_data_tuple meta data tuple type to get meta data from
*
* @param args set of the following parameters
* ct component tag to execute function for
* handle handle of the entity
* mdt meta data tuple to get meta data from
*
* @return the requested component
*/
template<typename... T_args>
inline auto& get(T_args&&... args) const & noexcept
{ return get_impl(*this, std::forward<T_args>(args)...); }
inline auto& get(T_args&&... args) const &;

/**
* add a new component for the given component tag
*
* @tparam T_args set of the following parameter types
* T_component_tag component tag type to execute function for
* T_entity_handle entity handle type
* T_meta_data_tuple meta data tuple type to get meta data from
*
* @param args set of the following parameters
* ct component tag to execute function for
* handle handle of the entity
* mdt meta data tuple to get meta data from
*
* @return the requested component
*/
template<typename... T_args>
inline auto& add(T_args&&... args) & noexcept
{ return add_impl(*this, std::forward<T_args>(args)...); }
inline auto& add(T_args&&... args) &;
};

}
end_namespace_ecs_core_component
} } }

+ 196
- 0
include/ecs/core/component/manager.inl Ver ficheiro

@@ -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)...);
}

} } }

+ 4
- 1
include/ecs/core/component/storage.h Ver ficheiro

@@ -3,4 +3,7 @@
#include "./storage/base.h"
#include "./storage/dynamic.h"
#include "./storage/empty.h"
#include "./storage/fixed.h"
#include "./storage/fixed.h"
#include "./storage/interface.h"

#include "./storage/base.inl"

+ 67
- 25
include/ecs/core/component/storage/base.h Ver ficheiro

@@ -2,11 +2,21 @@

#include <ecs/config.h>

beg_namespace_ecs_core_component_storage
{
namespace ecs {
namespace core {
namespace component {
namespace storage {

struct empty_meta_data { };

/**
* Base implementation of the component storage.
*
* Specializes @ref storage_iterface_t.
*
* @tparam T_container_builder internal container type
* @tparam T_component_tag_list list of component tags that are managed by this storage
*/
template<typename T_container_builder, typename T_component_tag_list>
struct base
{
@@ -23,40 +33,72 @@ beg_namespace_ecs_core_component_storage
container_type _container;

private:
/**
* get the compoent of the given tag from the storage
*
* @tparam T_self component storage type
* @tparam T_component_tag component tag type
* @tparam T_entity_handle entity handle type
*
* @param self component storage to get component from
* @param ct component tag to get component for
* @param handle handle of the entity to get the component for
* @param meta meta data stored in the entity to get component for
*
* @return component for the given parameters
*/
template<typename T_self, typename T_component_tag, typename T_entity_handle>
static inline decltype(auto) get_impl(
T_self&& self,
T_component_tag ct,
const T_entity_handle& handle,
const meta_data_type& meta) noexcept
{
using namespace ::ecs::core::mp;
using component_type = unwrap_t<decay_t<decltype(ct)>>;
decltype(auto) index = handle.index();
decltype(auto) data = std::forward<T_self>(self)._container.at(index);
return std::get<component_type>(data);
}
const meta_data_type& meta);

public:
/**
* get a writable reference to the requested component
*
* @tparam T_component_tag component tag type to get reference for
* @tparam T_entity_handle entity handle type to get reference for
*
* @param ct component tag to get reference for
* @param handle entity handle to get reference for
* @param meta meta data for this storage class that is stored in the entity
*
* @return writable reference to the requested component
*/
template<typename T_component_tag, typename... Xs>
inline auto& get(T_component_tag ct, Xs&&... xs) & noexcept
{ return get_impl(*this, ct, std::forward<Xs>(xs)...); }
inline auto& get(T_component_tag ct, Xs&&... xs) &;

/**
* get a read-only reference to the requested component
*
* @tparam T_component_tag component tag type to get reference for
* @tparam T_entity_handle entity handle type to get reference for
*
* @param ct component tag to get reference for
* @param handle entity handle to get reference for
* @param meta meta data for this storage class that is stored in the entity
*
* @return read-only reference to the requested component
*/
template<typename T_component_tag, typename... Xs>
inline const auto& get(T_component_tag ct, Xs&&... xs) const & noexcept
{ return get_impl(*this, ct, std::forward<Xs>(xs)...); }
inline const auto& get(T_component_tag ct, Xs&&... xs) const &;

/**
* add and initialize a new component to this storage
*
* @tparam T_component_tag component tag type to get reference for
* @tparam T_entity_handle entity handle type to get reference for
*
* @param ct component tag to get reference for
* @param handle entity handle to get reference for
* @param meta meta data for this storage class that is stored in the entity
*
* @return writable reference to the requested component
*/
template<typename T_component_tag, typename T_entity_handle>
inline auto& add(T_component_tag ct, const T_entity_handle& handle, const meta_data_type& meta)
{
auto index = handle.index();
if (_container.size() <= index)
{
_container.resize(index + grow_size);
}
return get(ct, handle, meta);
}
inline auto& add(T_component_tag ct, const T_entity_handle& handle, const meta_data_type& meta);
};

}
end_namespace_ecs_core_component_storage
} } } }

+ 55
- 0
include/ecs/core/component/storage/base.inl Ver ficheiro

@@ -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);
}

} } } }

+ 12
- 4
include/ecs/core/component/storage/dynamic.h Ver ficheiro

@@ -4,8 +4,10 @@

#include "./base.h"

beg_namespace_ecs_core_component_storage
{
namespace ecs {
namespace core {
namespace component {
namespace storage {

struct vector_type_builder
{
@@ -13,6 +15,13 @@ beg_namespace_ecs_core_component_storage
using type = std::vector<T>;
};

/**
* Dynamic component storage.
*
* Specializes @ref storage_iterface_t.
*
* @tparam T_component_tag_list list of component tags that are managed by this storage
*/
template<typename T_component_tag_list>
struct dynamic
: base<vector_type_builder, T_component_tag_list>
@@ -26,5 +35,4 @@ beg_namespace_ecs_core_component_storage
{ this->_container.resize(inital_size); }
};

}
end_namespace_ecs_core_component_storage
} } } }

+ 12
- 4
include/ecs/core/component/storage/empty.h Ver ficheiro

@@ -2,9 +2,18 @@

#include <ecs/config.h>

beg_namespace_ecs_core_component_storage
{
namespace ecs {
namespace core {
namespace component {
namespace storage {

/**
* Empty component storage.
*
* Specializes @ref storage_iterface_t.
*
* @tparam T_component_tag_list list of component tags that are managed by this storage
*/
template<typename T_component_tag_list>
struct empty
{
@@ -20,5 +29,4 @@ beg_namespace_ecs_core_component_storage
{ }
};

}
end_namespace_ecs_core_component_storage
} } } }

+ 14
- 5
include/ecs/core/component/storage/fixed.h Ver ficheiro

@@ -4,8 +4,10 @@

#include "./base.h"

beg_namespace_ecs_core_component_storage
{
namespace ecs {
namespace core {
namespace component {
namespace storage {

template<size_t T_size>
struct array_type_builder
@@ -13,13 +15,21 @@ beg_namespace_ecs_core_component_storage
template<typename T>
struct impl : public std::array<T, T_size>
{
inline void resize(size_t) { }
inline void resize(size_t)
{ throw std::overflow_error("fixed component storage can not grow!"); }
};

template<typename T>
using type = impl<T>;
};

/**
* Fixed component storage.
*
* Specializes @ref storage_iterface_t.
*
* @tparam T_component_tag_list list of component tags that are managed by this storage
*/
template<typename T_component_tag_list, size_t T_size>
struct fixed
: base<array_type_builder<T_size>, T_component_tag_list>
@@ -30,5 +40,4 @@ beg_namespace_ecs_core_component_storage
using typename base_type::meta_data_type;
};

}
end_namespace_ecs_core_component_storage
} } } }

+ 71
- 0
include/ecs/core/component/storage/interface.h Ver ficheiro

@@ -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);
};

} } }

+ 4
- 1
include/ecs/core/entity/storage.h Ver ficheiro

@@ -2,4 +2,7 @@

#include "./storage/base.h"
#include "./storage/dynamic.h"
#include "./storage/fixed.h"
#include "./storage/fixed.h"
#include "./storage/interface.h"

#include "./storage/base.inl"

+ 156
- 98
include/ecs/core/entity/storage/base.h Ver ficheiro

@@ -4,9 +4,14 @@
#include <ecs/config.h>
#include <ecs/core/utils/bitset.h>

beg_namespace_ecs_core_entity_storage
{

namespace ecs {
namespace core {
namespace entity {
namespace storage {

/**
* struct to represent an entity handle
*/
struct entity_handle
{
private:
@@ -14,58 +19,125 @@ beg_namespace_ecs_core_entity_storage
uint32_t _counter;

public:
entity_handle(uint32_t i, uint32_t c)
: _index (i)
, _counter (c)
{ }

inline auto index() const
{ return _index; }

inline auto counter() const
{ return _counter; }
/**
* constructor
*
* @param i index the entity is stored at
* @param c counter to check the reusage of the entity
*/
inline entity_handle(uint32_t i, uint32_t c);

/**
* get the index of the entity
*
* @return index of the entity
*/
inline auto index() const;

/**
* get the counter of the entity
*
* @return counter of the entity
*/
inline auto counter() const;

/**
* compare with other handle
*
* @param other handle to compare with
*
* @retval -1 if this is smaller than other
* @retval 0 if this is equal to other
* @retval -1 if this is larger than other
*/
inline int compare(const entity_handle& other) const;

/* compare operators */

inline bool operator <=(const entity_handle& other) const
{ return compare(other) <= 0; }

inline bool operator <(const entity_handle& other) const
{ return compare(other) < 0; }

inline bool operator ==(const entity_handle& other) const
{ return compare(other) == 0; }

inline bool operator !=(const entity_handle& other) const
{ return compare(other) != 0; }

inline bool operator >(const entity_handle& other) const
{ return compare(other) > 0; }

inline bool operator >=(const entity_handle& other) const
{ return compare(other) >= 0; }
};

template <typename T_settings, typename T_chunk_meta_data>
/**
* struct to manage the meta data for each entity
*
* @tparam T_settings settings type the environment is configured with
* @tparam T_storage_meta_data meta data type of the component storagte container
*/
template <typename T_settings, typename T_storage_meta_data>
struct entity_meta_data
: private T_storage_meta_data
{
public:
using bitset_type = utils::bitset<T_settings>;
using chunk_meta_data_type = T_chunk_meta_data;
using counter_type = uint32_t;
using bitset_type = utils::bitset<T_settings>;
using storage_meta_data_type = T_storage_meta_data;
using counter_type = uint32_t;

private:
bitset_type _bitset;
counter_type _counter;
chunk_meta_data_type _chunk_meta_data;
bitset_type _bitset;
counter_type _counter;

public:
entity_meta_data()
: _counter(0)
{ }

inline auto& bitset()
{ return _bitset; }

inline auto counter() const
{ return _counter; }

inline auto& chunk_meta_data()
{ return _chunk_meta_data; }

inline void reset()
{
++_counter;
_bitset.clear();
}
/**
* constructor
*/
inline entity_meta_data();

/**
* get the bitset of components stored for this entity
*
* @return component bitset
*/
inline auto& bitset();

/**
* get the current reusage counter of the entity
*
* @return current reusage counter of the entity
*/
inline auto counter() const;

/**
* get the storage meta data for this entity
*
* @return storage meta data for this entity
*/
inline auto& storage_meta_data();

/**
* reset all meta data to their defaults
*/
inline void reset();
};

template<typename T_container_builder, typename T_settings, typename T_chunk_meta_data>
/**
* basic entity storage container
*
* @tparam T_container_builder type to build the inner storage container
* @tparam T_settings settings type the environemtn is configured with
* @tparam T_storage_meta_data meta data type of the component storage
*/
template<typename T_container_builder, typename T_settings, typename T_storage_meta_data>
struct base
{
public:
using entity_handle_type = entity_handle;
using entity_meta_data_type = entity_meta_data<T_settings, T_chunk_meta_data>;
using entity_meta_data_type = entity_meta_data<T_settings, T_storage_meta_data>;

private:
using container_type = typename T_container_builder::template type<entity_meta_data_type>;
@@ -78,65 +150,51 @@ beg_namespace_ecs_core_entity_storage
queue_type _free_ids;

private:
inline void grow(size_t count)
{
auto old_size = _container.size();
_container.resize(old_size + count);
for (size_t i = old_size; i < _container.size(); ++i)
{
_free_ids.emplace(i);
}
}
/**
* grow the container to the given size
*
* @param count new size of the container
*/
inline void grow(size_t count);

public:
inline bool is_valid(const entity_handle& handle) const
{
return handle.index() < _container.size()
&& _container.at(handle.index()).counter() == handle.counter();
}

inline decltype(auto) claim()
{
if (_free_ids.empty())
{
grow(grow_size);
}
assert(!_free_ids.empty());
auto index = _free_ids.back();
auto& item = _container.at(index);
_free_ids.pop();
return entity_handle(index, item.counter());
}

inline void reclaim(const entity_handle& handle)
{
if (!is_valid(handle))
throw std::invalid_argument("invalid entity handle");
auto index = handle.index();
auto& item = _container.at(index);
item.reset();
_free_ids.emplace(index);
}

inline void clear()
{
_free_ids = queue_type { };
for (size_t i = 0; i < _container.size(); ++i)
{
_container.at(i).reset();
_free_ids.emplace(i);
}
}

inline auto& meta_data(const entity_handle& handle)
{
if (!is_valid(handle))
throw std::invalid_argument("invalid entity handle");
auto index = handle.index();
return _container.at(index);
}

/**
* check if the given entity handle is valid
*
* @param handle handle to check
*
* @retval TRUE if handle is valid
* @retval FALSE if handle is invalid
*/
inline bool is_valid(const entity_handle& handle) const;

/**
* create a new entity inside the container
*
* @return handle of the new created entity
*/
inline decltype(auto) claim();

/**
* release an entiy handle
*
* @param handle entity handle to release
*/
inline void reclaim(const entity_handle& handle);

/**
* remove all stored entities
*/
inline void clear();

/**
* get the meta data stored for the given handle
*
* @param handle entity handle to get meta data for
*
* @return meta data for the given entity handle
*/
inline auto& meta_data(const entity_handle& handle);
};

}
end_namespace_ecs_core_entity_storage
} } } }

+ 172
- 0
include/ecs/core/entity/storage/base.inl Ver ficheiro

@@ -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);
}

} } } }

+ 16
- 7
include/ecs/core/entity/storage/dynamic.h Ver ficheiro

@@ -4,8 +4,10 @@

#include "./base.h"

beg_namespace_ecs_core_entity_storage
{
namespace ecs {
namespace core {
namespace entity {
namespace storage {

struct vector_type_builder
{
@@ -13,12 +15,20 @@ beg_namespace_ecs_core_entity_storage
using type = std::vector<T>;
};

template<typename T_settings, typename T_chunk_meta_data>
/**
* Dynamic entity storage.
*
* Specializes @ref storage_iterface_t.
*
* @tparam T_settings settings type the environment is configured with
* @tparam T_storage_meta_data storage meta data type to store within the entity meta data
*/
template<typename T_settings, typename T_storage_meta_data>
struct dynamic
: base<vector_type_builder, T_settings, T_chunk_meta_data>
: base<vector_type_builder, T_settings, T_storage_meta_data>
{
public:
using base_type = base<vector_type_builder, T_settings, T_chunk_meta_data>;
using base_type = base<vector_type_builder, T_settings, T_storage_meta_data>;
using typename base_type::entity_handle_type;
using typename base_type::entity_meta_data_type;

@@ -34,5 +44,4 @@ beg_namespace_ecs_core_entity_storage
}
};

}
end_namespace_ecs_core_entity_storage
} } } }

+ 18
- 8
include/ecs/core/entity/storage/fixed.h Ver ficheiro

@@ -4,8 +4,10 @@

#include "./base.h"

beg_namespace_ecs_core_entity_storage
{
namespace ecs {
namespace core {
namespace entity {
namespace storage {

template<size_t T_size>
struct array_type_builder
@@ -13,19 +15,28 @@ beg_namespace_ecs_core_entity_storage
template<typename T>
struct impl : public std::array<T, T_size>
{
inline void resize(size_t) { }
inline void resize(size_t)
{ throw std::overflow_error("fixed entity storage can not grow!"); }
};

template<typename T>
using type = impl<T>;
};

template<typename T_settings, typename T_chunk_meta_data, size_t T_size>
/**
* Fixed entity storage.
*
* Specializes @ref storage_iterface_t.
*
* @tparam T_settings settings type the environment is configured with
* @tparam T_storage_meta_data storage meta data type to store within the entity meta data
*/
template<typename T_settings, typename T_storage_meta_data, size_t T_size>
struct fixed
: base<array_type_builder<T_size>, T_settings, T_chunk_meta_data>
: base<array_type_builder<T_size>, T_settings, T_storage_meta_data>
{
public:
using base_type = base<array_type_builder<T_size>, T_settings, T_chunk_meta_data>;
using base_type = base<array_type_builder<T_size>, T_settings, T_storage_meta_data>;
using typename base_type::entity_handle_type;
using typename base_type::entity_meta_data_type;

@@ -40,5 +51,4 @@ beg_namespace_ecs_core_entity_storage
}
};

}
end_namespace_ecs_core_entity_storage
} } } }

+ 69
- 0
include/ecs/core/entity/storage/interface.h Ver ficheiro

@@ -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);
};

} } } }

+ 22
- 4
include/ecs/core/mp/core/copy_qualifiers.h Ver ficheiro

@@ -2,9 +2,16 @@

#include <ecs/config.h>

beg_namespace_ecs_core_mp
{
namespace ecs {
namespace core {
namespace mp {

/**
* type that copies the const qualifier from one type to another
*
* @tparam T type to copy qualifier to
* @tparam T_source type to copy qualifier at
*/
template <typename T, typename T_source>
using copy_const_qualifier =
std::conditional_t<
@@ -12,6 +19,12 @@ beg_namespace_ecs_core_mp
std::add_const_t<T>,
T>;

/**
* type that copies the volatile qualifier from one type to another
*
* @tparam T type to copy qualifier to
* @tparam T_source type to copy qualifier at
*/
template <typename T, typename T_source>
using copy_volatile_qualifier =
std::conditional_t<
@@ -19,11 +32,16 @@ beg_namespace_ecs_core_mp
std::add_volatile_t<T>,
T>;

/**
* type that copies the const volatile qualifier from one type to another
*
* @tparam T type to copy qualifier to
* @tparam T_source type to copy qualifier at
*/
template <typename T, typename T_source>
using copy_cv_qualifiers =
copy_const_qualifier<
copy_volatile_qualifier<T, T_source>,
T_source>;

}
end_namespace_ecs_core_mp
} } }

+ 7
- 4
include/ecs/core/mp/core/decay.h Ver ficheiro

@@ -2,11 +2,14 @@

#include <ecs/config.h>

beg_namespace_ecs_core_mp
{
namespace ecs {
namespace core {
namespace mp {

/**
* remove all classifiers from a given type
*/
template<typename T>
using decay_t = typename hana::detail::decay<T>::type;

}
end_namespace_ecs_core_mp
} } }

+ 29
- 9
include/ecs/core/mp/core/is_list.h Ver ficheiro

@@ -3,22 +3,42 @@
#include <ecs/config.h>
#include "./is_valid.h"

beg_namespace_ecs_core_mp
{
namespace ecs {
namespace core {
namespace mp {

namespace __impl
namespace detail
{
template<template<typename...> class T_tag>
/**
* predicate type to check if each element of a list is a specialization of the given type
*
* @tparam T_check template type to check each element with
*/
template<template<typename...> class T_check>
struct is_list_t
{
/**
* execute the predicate
*
* @tparam T list type to check
*
* @param t list to check
*
* @retval integral constant TRUE if each element has passed the check
* @retval integral constant TRUE if at least one element has not passed the check
*/
template<typename T>
constexpr decltype(auto) operator()(T&& t) const noexcept
{ return hana::all_of(std::forward<T>(t), is_valid<T_tag>); }
{ return hana::all_of(std::forward<T>(t), is_valid<T_check>); }
};
}

template<template<typename...> class T_tag>
constexpr decltype(auto) is_list = __impl::is_list_t<T_tag> { };
/**
* predicate type to check if the given parameter is a list of the given tag
*
* @tparam T_check check to execute for each element of the given list
*/
template<template<typename...> class T_check>
constexpr decltype(auto) is_list = detail::is_list_t<T_check> { };

}
end_namespace_ecs_core_mp
} } }

+ 10
- 4
include/ecs/core/mp/core/is_specialization_of.h Ver ficheiro

@@ -2,9 +2,16 @@

#include <ecs/config.h>

beg_namespace_ecs_core_mp
{
namespace ecs {
namespace core {
namespace mp {

/**
* template to check if a given type T is a specialization of another template T_template
*
* @tparam T_template template definition to check for
* @tparam T type to check
*/
template<template<typename...> class T_template, typename T>
struct is_specialization_of
: public hana::false_
@@ -15,5 +22,4 @@ beg_namespace_ecs_core_mp
: public hana::true_
{ };

}
end_namespace_ecs_core_mp
} } }

+ 31
- 11
include/ecs/core/mp/core/is_valid.h Ver ficheiro

@@ -4,25 +4,45 @@
#include "./is_specialization_of.h"
#include "../list.h"

beg_namespace_ecs_core_mp
{
namespace ecs {
namespace core {
namespace mp {

namespace __impl
namespace detail
{
template<template<typename...> class T_tag>
/**
* predicate type to check if the passed arguments are specializations of the given template
*
* @tparam T_check template to check for
*/
template<template<typename...> class T_check>
struct is_valid_t
{
template<typename T>
static constexpr decltype(auto) is_tag = mp::is_specialization_of<T_tag, T> { };
static constexpr decltype(auto) is_tag = mp::is_specialization_of<T_check, T> { };

template<typename... Xs>
constexpr decltype(auto) operator()(Xs... xs) const noexcept
{ return mp::list::all(is_tag<Xs>...); }
/**
* execute the predicate
*
* @tparam T_args argument types to check
*
* @param args arguments to check
*
* @retval integral constant TRUE if each element has passed the check
* @retval integral constant TRUE if at least one element has not passed the check
*/
template<typename... T_args>
constexpr decltype(auto) operator()(T_args... args) const noexcept
{ return mp::list::all(is_tag<T_args>...); }
};
}

/**
* predicate to check if the passed arguments are specializations of the given template
*
* @tparam T_check template to check for
*/
template<template<typename...> class T_tag>
constexpr decltype(auto) is_valid = __impl::is_valid_t<T_tag> { };
constexpr decltype(auto) is_valid = detail::is_valid_t<T_tag> { };

}
end_namespace_ecs_core_mp
} } }

+ 39
- 7
include/ecs/core/mp/core/wrap.h Ver ficheiro

@@ -2,35 +2,67 @@

#include <ecs/config.h>

beg_namespace_ecs_core_mp
{
namespace ecs {
namespace core {
namespace mp {

/**
* pack the given type in a boost::hana::type
*/
template<typename T>
using wrap_t = hana::type<T>;

/**
* unpack a given boost::hana::type
**/
template<typename T>
using unwrap_t = typename T::type;

namespace __impl
namespace detail
{
/**
* predicate type to wrap a given type into a boost::hana::type
*/
struct wrap_t
{
/**
* execute the predicate
*
* @tparam T type to wrap
*
* @return object of the type wrapped in boost::hana::type
*/
template<typename T>
constexpr decltype(auto) operator()(T) const noexcept
{ return mp::wrap_t<T> { }; }
};

/**
* predicate type to unwrap a given boost::hana::type
*/
struct unwrap_t
{
/**
* execute the predicate
*
* @tparam T type to unwrap
*
* @return object of the unwrapped type
*/
template<typename T>
constexpr decltype(auto) operator()(T) const noexcept
{ return mp::unwrap_t<T> { }; }
};
}

constexpr decltype(auto) wrap = __impl::wrap_t { };
/**
* predicate to wrap a given type into a boost::hana::type
*/
constexpr decltype(auto) wrap = detail::wrap_t { };

constexpr decltype(auto) unwrap = __impl::unwrap_t { };
/**
* predicate to unwrap a given boost::hana::type
*/
constexpr decltype(auto) unwrap = detail::unwrap_t { };

}
end_namespace_ecs_core_mp
} } }

+ 104
- 22
include/ecs/core/mp/list.h Ver ficheiro

@@ -2,56 +2,99 @@

#include <ecs/config.h>

beg_namespace_ecs_core_mp_list
{
namespace ecs {
namespace core {
namespace mp {
namespace list {

/* base */

namespace __impl
namespace detail
{
/**
* simple meta programming list implementation
*/
template<typename... Xs>
using list_t = hana::basic_tuple<Xs...>;
}

/**
* wrapper to the list type
*/
template<typename... Xs>
using type = __impl::list_t<Xs...>;
using type = detail::list_t<Xs...>;

/**
* create a list object
*/
template<typename... Xs>
constexpr decltype(auto) value = type<Xs...> { };

/**
* empty list
*/
constexpr decltype(auto) empty = value<>;

/* make */

namespace __impl
namespace detail
{
/**
* predicate type to create a list
*/
struct make_t
{
template<typename... Xs>
constexpr decltype(auto) operator()(Xs...) const noexcept
{ return value<Xs...>; }
/**
* execute the predicate
*
* @tparam T_args argument types to wrap into a list
*
* @return list that contains the given types
*/
template<typename... T_args>
constexpr decltype(auto) operator()(T_args...) const noexcept
{ return value<T_args...>; }
};
}

constexpr decltype(auto) make = __impl::make_t { };
/**
* predicate to create a list
*/
constexpr decltype(auto) make = detail::make_t { };

/* all */

namespace __impl
namespace detail
{
/**
* predicate type to check if all passed arguments are true-type or not
*/
struct all_t
{
template<typename... Xs>
constexpr decltype(auto) operator()(Xs&&... xs) const noexcept
{ return hana::all(hana::make_basic_tuple(std::forward<Xs>(xs)...)); }
/**
* execute the predicate
*
* @tparam T_args argument types to check
*
* @param args arguments to check
*
* @retval integral constant TRUE if each argument is the true-type
* @retval integral constant TRUE if at least one argument is not the true-type
*/
template<typename... T_args>
constexpr decltype(auto) operator()(T_args&&... args) const noexcept
{ return hana::all(hana::make_basic_tuple(std::forward<T_args>(args)...)); }
};
}

constexpr decltype(auto) all = __impl::all_t { };
/**
* predicate to check if all passed arguments are true-type or not
*/
constexpr decltype(auto) all = detail::all_t { };

/* unwrap */

namespace __impl
namespace detail
{
template<template<typename...> class T_outer, typename T_list>
struct unwrap_t;
@@ -61,15 +104,35 @@ beg_namespace_ecs_core_mp_list
{ using type = T_outer<typename Ts::type...>; };
}

/**
* type to unwrap the types stored in a list
*
* @tparam T_outer container to store unwrapped types in
* @tparam T_list list of wrapped types to unwrap
*/
template<template<typename...> class T_outer, typename T_list>
using unwrap_t = typename __impl::unwrap_t<T_outer, T_list>::type;
using unwrap_t = typename detail::unwrap_t<T_outer, T_list>::type;

/* index_of */

namespace __impl
namespace detail
{
/**
* predicate type to get the index of a certain element inside a list
*/
struct index_of_t
{
/**
* execute the predicate
*
* @tparam T_list list type to find the element in
* @tparam T element type to get index for
*
* @param list list to find the element in
* @param item element to get index for
*
* @return integral constant with the index of the searched element
*/
template<typename T_list, typename T>
constexpr decltype(auto) operator()(T_list list, T&& item) const noexcept
{
@@ -82,14 +145,31 @@ beg_namespace_ecs_core_mp_list
};
}

constexpr decltype(auto) index_of = __impl::index_of_t { };
/**
* predicate to get the index of a certain element inside a list
*/
constexpr decltype(auto) index_of = detail::index_of_t { };

/* index_of_first_matching */

namespace __impl
namespace detail
{
/**
* predicate type to get the index of an element of a list that first matches the given predicate
*/
struct index_of_first_matching_t
{
/**
* execute the predicate
*
* @tparam T_list list type to search element in
* @tparam T_func predicate type to execute for each element
*
* @param list list to search element in
* @param func predicate to execute for each element
*
* @return integral constant of the index the element where found
*/
template<typename T_list, typename T_func>
constexpr decltype(auto) operator()(T_list list, T_func&& func) const noexcept
{
@@ -102,7 +182,9 @@ beg_namespace_ecs_core_mp_list
};
}

constexpr decltype(auto) index_of_first_matching = __impl::index_of_first_matching_t { };
/**
* predicate to get the index of an element of a list that first matches the given predicate
*/
constexpr decltype(auto) index_of_first_matching = detail::index_of_first_matching_t { };

}
end_namespace_ecs_core_mp_list
} } } }

+ 94
- 6
include/ecs/core/mp/option_map.h Ver ficheiro

@@ -3,11 +3,20 @@
#include <ecs/config.h>
#include "./core/decay.h"

beg_namespace_ecs_core_mp_option_map
{
namespace ecs {
namespace core {
namespace mp {
namespace option_map {

namespace __impl
namespace detail
{

/**
* Helper template to replace a given element of the options map.
* Will forward the new pair if it was not set already.
*
* @tparam T_new_pair type of the new data pair
*/
template<typename T_new_pair>
struct replace_helper_t
{
@@ -15,6 +24,15 @@ beg_namespace_ecs_core_mp_option_map

const new_pair_type& new_pair;

/**
* execute the helper
*
* @tparam T_pair type of the existing pair
*
* @param pair existing pair
*
* @return The new pair if it is not already set, the old pair otherwise.
*/
template<typename T_pair>
constexpr decltype(auto) operator()(T_pair&& pair) const noexcept
{
@@ -25,8 +43,22 @@ beg_namespace_ecs_core_mp_option_map
}
};

/**
* predicate type to replace a certain pair of a list
*/
struct replace_t
{
/**
* execute the predicate
*
* @tparam T_map type of the map to replace a pair in
* @tparam T_new_pair type of the new pair
*
* @param map map to replace a pair in
* @param new_pair pair to replace the old pair with
*
* @return updated map
*/
template<typename T_map, typename T_new_pair>
constexpr decltype(auto) operator()(T_map&& map, T_new_pair&& new_pair) const noexcept
{
@@ -40,8 +72,14 @@ beg_namespace_ecs_core_mp_option_map
}
};

/**
* predicate to replace a certain pair of a list
*/
constexpr decltype(auto) replace = replace_t { };

/**
* implements an option map to store key value pairs
*/
template<typename T_map>
struct option_map_t
{
@@ -51,14 +89,43 @@ beg_namespace_ecs_core_mp_option_map
map_type _map;

public:
/**
* get the value for a certain key
*
* @tparam T_key key type to get value for
*
* @param key key to get value for
*
* @return value stored for the given key
*/
template<typename T_key>
constexpr decltype(auto) at(const T_key& key) const noexcept
{ return hana::first(hana::at_key(_map, key)); }

/**
* get the value type for a certain key
*
* @tparam T_key key type to get value type for
*
* @param key key to get value type for
*
* @return value type stored for the given key
*/
template<typename T_key>
constexpr decltype(auto) type_at(const T_key& key) const noexcept
{ return hana::type_c<decay_t<decltype(at(key))>>; }

/**
* add a new key to the map
*
* @tparam T_key key type to add
* @tparam T_value value type of the initial value
*
* @param key key to add
* @param value initial value
*
* @return the updated option map
*/
template<typename T_key, typename T_value>
constexpr decltype(auto) add(const T_key& key, T_value&& value) const noexcept
{
@@ -72,6 +139,17 @@ beg_namespace_ecs_core_mp_option_map
return option_map_t<decltype(new_map)> { };
}

/**
* set the value of a certain key (values can only be set once!)
*
* @tparam T_key type of the key to set value for
* @tparam T_value type of the value to set
*
* @param key key to set value for
* @param value value to set
*
* @return the updated option map
*/
template<typename T_key, typename T_value>
constexpr decltype(auto) set(const T_key& key, T_value&& value) const noexcept
{
@@ -89,14 +167,24 @@ beg_namespace_ecs_core_mp_option_map
}
};

/**
* predicate type to create a empty option map
*/
struct make_t
{
/**
* execute the predicate
*
* @return empty option map
*/
constexpr decltype(auto) operator()() const noexcept
{ return option_map_t<decay_t<decltype(hana::make_map())>> { }; }
};
}

constexpr decltype(auto) make = __impl::make_t { };
/**
* predicate to create a empty option map
*/
constexpr decltype(auto) make = detail::make_t { };

}
end_namespace_ecs_core_mp_option_map
} } } }

+ 27
- 9
include/ecs/core/mp/tag.h Ver ficheiro

@@ -3,22 +3,40 @@
#include <ecs/config.h>
#include "./core/decay.h"

beg_namespace_ecs_core_mp_tag
{
namespace ecs {
namespace core {
namespace mp {
namespace tag {

namespace __impl
namespace detail
{
/**
* predicate type to create a tag of a given type
*
* @tparam T_tag tag to create
*/
template<template<typename> class T_tag>
struct make_t
{
template<typename T_component>
constexpr decltype(auto) operator()(T_component&&) const noexcept
{ return T_tag<core::mp::decay_t<T_component>> { }; }
/**
* execute the predicate
*
* @tparam T type to create tag for
*
* @return tag of the given type
*/
template<typename T>
constexpr decltype(auto) operator()(T&&) const noexcept
{ return T_tag<core::mp::decay_t<T>> { }; }
};
}

/**
* predicate to create a tag of a given type
*
* @tparam T_tag tag to create
*/
template<template<typename> class T_tag>
constexpr decltype(auto) make = __impl::make_t<T_tag> { };
constexpr decltype(auto) make = detail::make_t<T_tag> { };

}
end_namespace_ecs_core_mp_tag
} } } }

+ 1
- 0
include/ecs/core/system.h Ver ficheiro

@@ -1,5 +1,6 @@
#pragma once

#include "./system/data_proxy.h"
#include "./system/instance.h"
#include "./system/parallelism.h"
#include "./system/scheduler.h"

+ 7
- 0
include/ecs/core/system/data_proxy.h Ver ficheiro

@@ -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"

+ 54
- 0
include/ecs/core/system/data_proxy/base.h Ver ficheiro

@@ -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);

};

} } } }

+ 39
- 0
include/ecs/core/system/data_proxy/base.inl Ver ficheiro

@@ -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 { });
});
}

} } } }

+ 95
- 0
include/ecs/core/system/data_proxy/single.h Ver ficheiro

@@ -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);

} } } }

+ 70
- 0
include/ecs/core/system/data_proxy/single.inl Ver ficheiro

@@ -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));
}

} } } }

+ 18
- 7
include/ecs/core/system/instance.h Ver ficheiro

@@ -4,9 +4,11 @@
#include <ecs/signature/system.h>
#include <ecs/core/utils/bitset.h>
#include <ecs/core/utils/fixed_function.h>
#include <ecs/core/utils/ordered_vector.h>

beg_namespace_ecs_core_system
{
namespace ecs {
namespace core {
namespace system {

template<typename T_settings>
struct deferred_function_vector
@@ -55,7 +57,7 @@ beg_namespace_ecs_core_system
using bitset_type = utils::bitset<settings_type>;
using entity_handle_type = T_entity_handle;
using executor_type = decltype(mp::unwrap(system_signature_type { }).parallelism()());
using entity_handle_set_type = std::set<entity_handle_type>;
using entity_handle_set_type = utils::ordered_vector<entity_handle_type>;

struct state_t
: public output_type
@@ -114,6 +116,12 @@ beg_namespace_ecs_core_system
}

public:
inline void prepare_states(size_t n)
{
assert(n > 0);
clear_and_prepare(n);
}

template<typename T_context, typename T_func>
inline void prepare_and_wait_subtasks(T_context& context, size_t n, T_func& func)
{
@@ -125,7 +133,7 @@ beg_namespace_ecs_core_system
return [this, &b, &context, &f](auto&&... xs) {
context.post_in_thread_pool([&f, &b, xs...]() {
ecs_make_scope_guard([&b](){
b.decrement_and_notify_one();
b.decrement();
});
f(xs...);
});
@@ -137,6 +145,10 @@ beg_namespace_ecs_core_system
});
}

template<typename T_context, typename T_func>
inline void execute(T_context& context, T_func&& func)
{ _executor(context, *this, std::forward<T_func>(func)); }

public: /* bitset */
inline const auto& bitset() const noexcept
{ return _bitset; }
@@ -162,7 +174,7 @@ beg_namespace_ecs_core_system
{ return (_subscribed.find(handle) != _subscribed.end()); }

inline void subscribe(const entity_handle_type& handle)
{ _subscribed.emplace(handle); }
{ _subscribed.insert(handle); }

inline void unsubscribe(const entity_handle_type& handle)
{ _subscribed.erase(handle); }
@@ -197,5 +209,4 @@ beg_namespace_ecs_core_system

};

}
end_namespace_ecs_core_system
} } }

+ 3
- 0
include/ecs/core/system/parallelism/composer.h Ver ficheiro

@@ -0,0 +1,3 @@
#pragma once

#include "./composer/fixed_threshold.h"

+ 9
- 14
include/ecs/core/system/parallelism/composer/fixed_threshold.h Ver ficheiro

@@ -2,8 +2,10 @@

#include <ecs/config.h>

beg_namespace_ecs_core_parallelism
{
namespace ecs {
namespace core {
namespace system {
namespace parallelism {

template<typename T_parameters>
struct fixed_threshold
@@ -15,20 +17,13 @@ beg_namespace_ecs_core_parallelism
strategy_lower_type _strategy_lower;
strategy_greater_type _strategy_greater;

template<typename T_instance, typename... T_args>
inline void operator()(T_instance& instance, T_args&&... args) const
template<typename T_context, typename T_instance, typename T_func>
inline void operator()(T_context& context, T_instance& instance, T_func&& func) const
{
bool threshold_reached = false; // TODO
if (!threshold_reached)
{
_strategy_lower(instance, std::forward<T_args>(args)...);
}
else
{
_strategy_greater(instance, std::forward<T_args>(args)...);
}
if (!threshold_reached) _strategy_lower (instance, context, std::forward<T_func>(func));
else _strategy_greater(instance, context, std::forward<T_func>(func));
}
};

}
end_namespace_ecs_core_parallelism
} } } }

+ 28
- 7
include/ecs/core/system/parallelism/strategy/none.h Ver ficheiro

@@ -1,18 +1,39 @@
#pragma once

#include <ecs/config.h>
#include <ecs/core/system/data_proxy.h>

beg_namespace_ecs_core_parallelism
{
namespace ecs {
namespace core {
namespace system {
namespace parallelism {

struct none
{
template<typename T_instance, typename T_context, typename T_func>
inline void operator()(T_instance& instance, T_context& context, T_func&& func) const
template<typename T_context, typename T_instance>
struct executor_proxy
{
// TODO
using context_type = T_context;
using instance_type = T_instance;

context_type& context;
instance_type& instance;

template<typename T_func>
inline void for_subtasks(T_func&& func)
{
instance.prepare_states(1);
auto data = data_proxy::make_single(context, instance);
func(data);
}
};

template<typename T_context, typename T_instance, typename T_func>
inline void operator()(T_context& context, T_instance& instance, T_func&& func) const
{
executor_proxy<T_context, T_instance> ep { context, instance };
func(instance, ep);
}
};

}
end_namespace_ecs_core_parallelism
} } } }

+ 6
- 5
include/ecs/core/system/parallelism/strategy/split_evenly.h Ver ficheiro

@@ -2,8 +2,10 @@

#include <ecs/config.h>

beg_namespace_ecs_core_parallelism
{
namespace ecs {
namespace core {
namespace system {
namespace parallelism {

template<typename T_parameters>
struct split_evenly
@@ -13,10 +15,9 @@ beg_namespace_ecs_core_parallelism
template<typename T_context, typename T_instance, typename T_func>
inline void operator()(T_context& context, T_instance& instance, T_func&& func) const
{
// auto split_count = parameters_type::get_split_count();
// TODO
// auto split_count = parameters_type::get_split_count();
}
};

}
end_namespace_ecs_core_parallelism
} } } }

+ 6
- 4
include/ecs/core/system/parallelism/strategy/split_every.h Ver ficheiro

@@ -2,8 +2,10 @@

#include <ecs/config.h>

beg_namespace_ecs_core_parallelism
{
namespace ecs {
namespace core {
namespace system {
namespace parallelism {

template<typename T_parameters>
struct split_every
@@ -13,9 +15,9 @@ beg_namespace_ecs_core_parallelism
template<typename T_context, typename T_instance, typename T_func>
inline void operator()(T_context& context, T_instance& instance, T_func&& func) const
{
// TODO
// auto per_split = parameters_type::get_per_split_count();
}
};

}
end_namespace_ecs_core_parallelism
} } } }

+ 3
- 1
include/ecs/core/system/scheduler.h Ver ficheiro

@@ -1,3 +1,5 @@
#pragma once

#include "./scheduler/atomic_counter.h"
#include "./scheduler/atomic_counter.h"

#include "./scheduler/atomic_counter.inl"

+ 177
- 204
include/ecs/core/system/scheduler/atomic_counter.h Ver ficheiro

@@ -1,26 +1,43 @@
#pragma once

#include <ecs/config.h>
#include <ecs/tag/system.h>
#include <ecs/context/context.fwd.h>

beg_namespace_ecs_core_system_scheduler
{
namespace ecs {
namespace core {
namespace system {
namespace scheduler {

namespace __impl
namespace detail
{
template<typename T_system_tag, typename T_execute, typename T_dependency_ids>
/**
* struct to wrap some system meta data
*/
template<
typename T_system_tag,
typename T_execute,
typename T_dependency_ids>
struct dependency_item_t
{
using system_tag_type = T_system_tag;
using execute_type = T_execute;
using dependency_ids_type = T_dependency_ids;

system_tag_type tag;
execute_type execute;
dependency_ids_type dependency_ids;
system_tag_type tag; //!< tag of system this dependency element represents
execute_type execute; //!< boolean value to determine if the system should be executed or not
dependency_ids_type dependency_ids; //!< list of system IDs that depends on this system/item
};

template<typename T_dependency_item, typename T_dependent_ids>
/**
* defines a task to be executed (represents a system to execute in the scheduler)
*
* @tparam T_dependency_item dependency item type for this task
* @tparam T_dependent_ids id types of tasks that depends on this task
*/
template<
typename T_dependency_item,
typename T_dependent_ids>
struct task_t
{
public:
@@ -32,50 +49,76 @@ beg_namespace_ecs_core_system_scheduler
std::atomic<size_t> _dependency_count;

public:
task_t()
: _dependency_count(hana::value(hana::size(mp::unwrap(dependency_item_type { }).dependency_ids)))
{ }

inline size_t dependency_count() const
{ return _dependency_count; }

inline bool decrement_and_check()
{ return (--_dependency_count == 0); }

mp::unwrap_t<dependency_item_type> dependency_item;

/**
* constructor
*/
inline task_t();

/**
* get the number unfinished tasks, this task depends on
*/
inline size_t dependency_count() const;

/**
* decrepent the unfished task counter
*
* @retval TRUE if all tasks, this task depends on, are finished
* @retval FALSE if at least on task, this task depends on, is not finished
*/
inline bool decrement_and_check();

/**
* execute the passed function for task ID that depends on this task
*
* @tparam T_func function type to execute
*
* @param func function to execute
*/
template<typename T_func>
constexpr decltype(auto) for_dependent_ids(T_func&& func) const noexcept
{ hana::for_each(dependent_ids_type { }, std::forward<T_func>(func)); }
constexpr decltype(auto) for_dependent_ids(T_func&& func) const noexcept;
};

/**
* predicate type to create a list of task IDs that depends on the given task
*/
struct dependent_ids_t
{
/**
* execute the predicate
*
* @tparam T_dependency_items list of dependency items
* @tparam T_dependency_item dependency item to get taks IDs for, that depends on that item
*
* @return list of task IDs that depends on the given dependency item
*/
template<typename T_dependency_items, typename T_dependency_item>
constexpr decltype(auto) operator()(T_dependency_items, T_dependency_item) const noexcept
{
auto item_id = mp::list::index_of(T_dependency_items { }, T_dependency_item { });
return hana::fold_right(T_dependency_items { }, mp::list::empty, [=](auto other, auto acc){
return hana::if_(
hana::contains(mp::unwrap(other).dependency_ids, item_id),
hana::append(acc, mp::list::index_of(T_dependency_items { }, other)),
acc);
});
}
constexpr decltype(auto) operator()(T_dependency_items, T_dependency_item) const noexcept;
};

/**
* predicate type to create a list of tasks
*/
struct make_tasks_t
{
/**
* execute the predicate
*
* @tparam T_dependency_items list of dependency items to create tasks from
*
* @return list of tasks
*/
template<typename T_dependency_items>
constexpr decltype(auto) operator()(T_dependency_items) const noexcept
{
return hana::transform(T_dependency_items { }, [](auto item){
using item_type = mp::decay_t<decltype(item)>;
using dependent_ids_type = mp::decay_t<decltype((dependent_ids_t { })(T_dependency_items { }, item_type { }))>;
using task_type = task_t<item_type, dependent_ids_type>;
return hana::type_c<task_type>;
});
}
constexpr decltype(auto) operator()(T_dependency_items) const noexcept;
};

/**
* defines a group of tasks to execute with
*
* @tparam T_context context type
* @tparam T_dependency_items list of dependency items
*/
template<typename T_context, typename T_dependency_items>
struct task_group_t
{
@@ -89,144 +132,93 @@ beg_namespace_ecs_core_system_scheduler
using tasks_tuple_type = mp::list::unwrap_t<hana::tuple, task_types>;

private:
context_type& _context;
utils::counter_blocker& _counter;
tasks_tuple_type _tasks;
context_type& _context; //!< context to use for system execution
utils::counter_blocker& _counter; //!< counter to track running tasks
tasks_tuple_type _tasks; //!< tuple of all tasks

public:
inline task_group_t(context_type& p_context, utils::counter_blocker& p_counter)
: _context(p_context)
, _counter(p_counter)
{ }

template<typename T_task_id>
inline void start_task(T_task_id id)
{
using task_type = mp::decay_t<decltype(hana::at(_tasks, id))>;
using dependency_item_type = typename task_type::dependency_item_type;
_counter.increment();
hana::eval_if(
mp::unwrap(dependency_item_type { }).execute,
[this](auto _) { _(this)->post_task_in_thread_pool (T_task_id { }); },
[this](auto _) { _(this)->check_and_start_dependencies(T_task_id { }); });
}
/**
* constructor
*
* @param p_context context to use for system execution
* @param p_counter counter to track running tasks
*/
inline task_group_t(context_type& p_context, utils::counter_blocker& p_counter);

/**
* start the given task
*
* @tparam T_task_id id type of the task to execute
* @tparam T_func overloaded function type to execute system with
*
* @param id id of task to execute
* @param func overloaded function to execute system with
*/
template<typename T_task_id, typename T_func>
inline void start_task(T_task_id id, T_func&& func);

private:
template<typename T_task_id>
inline void post_task_in_thread_pool(T_task_id)
{
_context.post_in_thread_pool([this]{
execute_task(T_task_id { });
});
}

template<typename T_task_id>
inline void execute_task(T_task_id)
{
check_and_start_dependencies(T_task_id { });
}

template<typename T_task_id>
inline void check_and_start_dependencies(T_task_id)
{
auto& task = hana::at(_tasks, T_task_id { });
task.for_dependent_ids([this](auto id){
auto& other = hana::at(_tasks, id);
if (other.decrement_and_check()) {
start_task(id);
}
});
_counter.decrement_and_notify_one();
}
/**
* execute the task using the thread pool
*
* @tparam T_task_id id type of task to execute
* @tparam T_func overloaded function type to execute system with
*
* @param func overloaded function to execute system with
*/
template<typename T_task_id, typename T_func>
inline void post_task_in_thread_pool(T_task_id, T_func&& func);

/**
* execute the actual task using the passed overloaded function
*
* @tparam T_task_id id type of task to execute
* @tparam T_func overloaded function type to execute system with
*
* @param func overloaded function to execute system with
*/
template<typename T_task_id, typename T_func>
inline void execute_task(T_task_id, T_func&& func);

/**
* update the dependencies of the current task and start the next task
*
* @tparam T_task_id id type of task to update dependencies for
* @tparam T_func overloaded function type to execute system with
*
* @param func overloaded function to execute system with
*/
template<typename T_task_id, typename T_func>
inline void check_and_start_dependencies(T_task_id, T_func&& func);
};

/**
* create a list of dependency items
*
* @tparam T_system_signature_list system signature list type
* @tparam T_system_tag_list list of system tag types
*
* @return list of dependency items
*/
template<typename T_system_signature_list, typename T_system_tag_list>
constexpr decltype(auto) build_dependency_list(T_system_signature_list, T_system_tag_list) noexcept
{
using system_signature_list_type = T_system_signature_list;
using system_signature_tuple_type = mp::decay_t<decltype((system_signature_list_type { }).items)>;
using system_tag_list_type = T_system_tag_list;

auto filtered = (system_signature_list_type { })
.filter([](auto ssig){
return hana::contains(system_tag_list_type { }, mp::unwrap(ssig).tag());
});
using filtered_ssig_list_type = mp::decay_t<decltype(filtered)>;

(filtered_ssig_list_type { }).for_each([](auto ssig){
using ssig_type = mp::decay_t<decltype(ssig)>;
hana::for_each(mp::unwrap(ssig).write(), [](auto tag){
using tag_type = mp::decay_t<decltype(tag)>;
(filtered_ssig_list_type { }).for_each([](auto other){
using check_dependencies_type = decltype(
hana::or_(
hana::equal(ssig_type { }, other),
(T_system_signature_list { }).depends_on(ssig_type { }, mp::unwrap(other).tag()),
(T_system_signature_list { }).depends_on(other, mp::unwrap(ssig_type { }).tag()),
hana::not_(hana::contains(mp::unwrap(other).write(), tag_type { }))));
static_assert(
check_dependencies_type { },
"independent systems can not share write access to component");
});
});
});

return hana::transform(system_signature_tuple_type { }, [](auto ssig){
using ssig_type = mp::decay_t<decltype(ssig)>;

auto tag = mp::unwrap(ssig).tag();
auto deps = mp::unwrap(ssig).dependencies();
auto execute = hana::contains(system_tag_list_type { }, mp::unwrap(ssig).tag());

auto read_deps =
hana::transform(mp::unwrap(ssig).read(), [](auto read_tag){
using read_tag_type = mp::decay_t<decltype(read_tag)>;
return hana::transform(
hana::filter((filtered_ssig_list_type { }).items, [](auto other){
return hana::and_(
hana::not_equal(ssig_type { }, other),
hana::contains(mp::unwrap(other).write(), read_tag_type { }));
}),
[](auto other){
return mp::unwrap(other).tag();
});
});
auto final_deps =
hana::transform(
hana::fold(
hana::if_(
hana::size(read_deps) == hana::size_c<0>,
hana::make_basic_tuple(hana::make_basic_tuple()),
read_deps),
deps,
hana::concat),
[](auto tmp_tag){
return (system_signature_list_type { }).id_by_tag(tmp_tag);
});

using tag_type = mp::decay_t<decltype(tag)>;
using dep_type = mp::decay_t<decltype(final_deps)>;
using execute_type = mp::decay_t<decltype(execute)>;
using item_type = dependency_item_t<tag_type, execute_type, dep_type>;

return hana::type_c<item_type>;
});
}

constexpr decltype(auto) build_dependency_list(T_system_signature_list, T_system_tag_list) noexcept;

/**
* get a list of independent items from the passed dependency list
*
* @tparam T_dependency_list dependency item list to get independent items from
*
* @return list of independent items
*/
template<typename T_dependency_list>
constexpr decltype(auto) get_independent_item_ids(T_dependency_list) noexcept
{
return
hana::transform(
hana::filter(T_dependency_list { }, [](auto item){
return hana::size(mp::unwrap(item).dependency_ids) == hana::size_c<0>;
}),
[](auto item){
return mp::list::index_of(T_dependency_list { }, item);
});
}
constexpr decltype(auto) get_independent_item_ids(T_dependency_list) noexcept;
}

/**
* scheduler that resolves the dependencies between systems and then executes the systems in a save way in parallel
*
* @tparam T_settings settings type the environment is configured with
*/
template<typename T_settings>
struct atomic_counter
{
@@ -238,43 +230,24 @@ beg_namespace_ecs_core_system_scheduler
context_type& _context;

public:
atomic_counter(context_type& p_context)
: _context(p_context)
{ }

/**
* constructor
*
* @param p_context context to use for system exeution
*/
inline atomic_counter(context_type& p_context);

/**
* execute the systems for that system tags are passed
*
* @tparam T_system_tag_list list of system tag type to execute systems for
* @tparam T_func overloaded function type to use for system execution
*
* @param stl list of system tags to execute systems for
* @param func overloaded function to use for system execution
*/
template<typename T_system_tag_list, typename T_func>
inline void execute(T_system_tag_list, T_func&& func)
{
static_assert(tag::system::is_list(T_system_tag_list { }));
using dependency_list_type = mp::decay_t<decltype(__impl::build_dependency_list(
(settings_type { }).system_signatures(),
T_system_tag_list { }))>;
using independent_item_ids_type = mp::decay_t<decltype(__impl::get_independent_item_ids(
dependency_list_type { }))>;;

size_t i = 0;
std::cout << "dependency_list" << std::endl;
hana::for_each(dependency_list_type { }, [&i](auto item){
using system_type = mp::unwrap_t<mp::decay_t<decltype(mp::unwrap(item).tag)>>;
std::cout << " " << (i++) << ": " << type_helper<system_type>::name() << " (" << hana::value(mp::unwrap(item).execute) << ")" << std::endl;
hana::for_each(mp::unwrap(item).dependency_ids, [](auto id){
std::cout << " " << hana::value(id) << std::endl;
});
});

using task_group_type = __impl::task_group_t<context_type, dependency_list_type>;

utils::counter_blocker counter (1);
task_group_type task_group (_context, counter);

counter.execute_and_wait_until_zero([&task_group, &counter]{
hana::for_each(independent_item_ids_type { }, [&task_group](auto id){
task_group.start_task(id);
});
counter.decrement_and_notify_one();
});
}
inline void execute(T_system_tag_list stl, T_func&& func);
};

}
end_namespace_ecs_core_system_scheduler
} } } }

+ 278
- 0
include/ecs/core/system/scheduler/atomic_counter.inl Ver ficheiro

@@ -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();
});
}

} } } }

+ 5
- 4
include/ecs/core/system/storage/tuple.h Ver ficheiro

@@ -4,8 +4,10 @@
#include <ecs/tag/system.h>
#include <ecs/core/system/instance.h>

beg_namespace_ecs_core_system_storage
{
namespace ecs {
namespace core {
namespace system {
namespace storage {

template<typename T_settings, typename T_entity_handle>
struct tuple
@@ -94,5 +96,4 @@ beg_namespace_ecs_core_system_storage
{ return instance_by_tag(ssig.tag()); }
};

}
end_namespace_ecs_core_system_storage
} } } }

+ 6
- 1
include/ecs/core/utils.h Ver ficheiro

@@ -4,6 +4,11 @@
#include "./utils/counter_blocker.h"
#include "./utils/fixed_function.h"
#include "./utils/movable_atomic.h"
#include "./utils/ordered_vector.h"
#include "./utils/scope_guard.h"
#include "./utils/storage_cast.h"
#include "./utils/thread_pool.h"
#include "./utils/thread_pool.h"

#include "./utils/bitset.inl"
#include "./utils/counter_blocker.inl"
#include "./utils/fixed_function.inl"

+ 72
- 14
include/ecs/core/utils/bitset.h Ver ficheiro

@@ -4,48 +4,106 @@
#include <ecs/config.h>
#include <ecs/core/mp/list.h>

beg_namespace_ecs_core_utils
{
namespace ecs {
namespace core {
namespace utils {

/**
* bitset to store components flags in
*
* @tparam T_settings settings type the environmant is configured with
*/
template<typename T_settings>
struct bitset
{
private:
/**
* get the component signature list
*
* @return component signature list
*/
static constexpr decltype(auto) csl() noexcept
{ return (T_settings { }).component_signatures(); }

/**
* get the tags of all components
*
* @return list of all component tags
*/
static constexpr decltype(auto) all_components() noexcept
{ return csl().all_components(); }

public:
/**
* get the number of components
*
* @return integral constant with number of components
*/
static constexpr decltype(auto) component_count() noexcept
{ return hana::size(all_components()); }

/**
* get the ID of the given component tag
*
* @tparam T_component_tag component tag type to get ID for
*
* @param ct component tag to get the ID for
*
* @return integral constant with the ID of the requested component tag
*/
template<typename T_component_tag>
static constexpr decltype(auto) component_id(T_component_tag ct) noexcept
{ return mp::list::index_of(all_components(), ct); }
static constexpr decltype(auto) component_id(T_component_tag ct) noexcept;

/**
* internal bitset type that contains all components
*/
using bitset_type = std::bitset<component_count()>;

private:
bitset_type _bitset;

public:
inline void clear() noexcept
{ _bitset.reset(); }
/**
* clear all bits of the bitset
*/
inline void clear() noexcept;

/**
* check if the bitset contains another bitset
*
* @tparam T_other type of the other bitset
*
* @param other bitset to compare with
*
* @retval TRUE if this bitset contains the passed bitset
* @retval FALSE if this bitset does not contain the passed bitset
*/
template<typename T_other>
inline bool contains(const T_other& other) const noexcept
{ return (_bitset & other._bitset) == _bitset; }
inline bool contains(const T_other& other) const noexcept;

/**
* check if the bitset contains the given component
*
* @tparam T_component_tag component tag type to check
*
* @param ct component tag to check
*
* @retval TRUE if this bitset contains the passed component tag
* @retval FALSE if this bitset does not contain the passed component tag
*/
template<typename T_component_tag>
inline bool has_component(T_component_tag ct) const
{ return _bitset.test(component_id(ct)); }
inline bool has_component(T_component_tag ct) const;

/**
* set the bit value of the passed component tag
*
* @tparam T_component_tag component tag type to set
*
* @param ct component tag to set
* @param value new bit value of the component inside the bitset
*/
template<typename T_component_tag>
inline void set_component(T_component_tag ct, bool value)
{ _bitset.set(component_id(ct), value); }
inline void set_component(T_component_tag ct, bool value);
};

}
end_namespace_ecs_core_utils
} } }

+ 48
- 0
include/ecs/core/utils/bitset.inl Ver ficheiro

@@ -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);
}

} } }

+ 36
- 40
include/ecs/core/utils/counter_blocker.h Ver ficheiro

@@ -2,54 +2,50 @@

#include <mutex>
#include <condition_variable>

#include <ecs/config.h>

beg_namespace_ecs_core_utils
{
namespace ecs {
namespace core {
namespace utils {

/**
* counter that blocks a given operation until it is equal zero
*/
struct counter_blocker
{
private:
std::mutex _mutex;
std::condition_variable _cond_var;
size_t _counter;
std::mutex _mutex; //!< mutex to preotect the counter
std::condition_variable _cond_var; //!< conditional variable to synchronize the counter
size_t _counter; //!< the actual counter value

public:
inline counter_blocker(size_t counter) noexcept
: _counter(counter)
{ }

inline void increment() noexcept
{
std::lock_guard lock(_mutex);
assert(_counter > 0);
++_counter;
}

inline void decrement_and_notify_one() noexcept
{
std::lock_guard lock(_mutex);
assert(_counter > 0);
--_counter;
_cond_var.notify_one();
}

inline void decrement_and_notify_all() noexcept
{
std::lock_guard lock(_mutex);
assert(_counter > 0);
--_counter;
_cond_var.notify_all();
}

/**
* constructor
*
* @param counter initial counter value
*/
inline counter_blocker(size_t counter) noexcept;

/**
* increment the counter value by one
*/
inline void increment() noexcept;

/**
* decrement the counter value by one and notify all pending threads
*/
inline void decrement() noexcept;

/**
* execute the given function and wait until the counter is equal to zero
*
* @tparam T_func type of the function to execute
*
* @param func function to execute
*/
template<typename T_func>
inline void execute_and_wait_until_zero(T_func&& func) noexcept
{
func();
std::unique_lock lock(_mutex);
_cond_var.wait(lock, [this]{ return (_counter == 0); });
}
inline void execute_and_wait_until_zero(T_func&& func) noexcept;
};

}
end_namespace_ecs_core_utils
} } }

+ 40
- 0
include/ecs/core/utils/counter_blocker.inl Ver ficheiro

@@ -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); });
}

} } }

+ 82
- 109
include/ecs/core/utils/fixed_function.h Ver ficheiro

@@ -4,9 +4,16 @@

#include "./storage_cast.h"

beg_namespace_ecs_core_utils
{

namespace ecs {
namespace core {
namespace utils {

/**
* functor to store a function of a fixed size
*
* @tparam T_signature signature of the functor
* @tparam T_storage_size max size of the functor
*/
template<typename T_signature, size_t T_storage_size = 64>
struct fixed_function;

@@ -25,122 +32,88 @@ beg_namespace_ecs_core_utils
private:
union
{
storage_type _storage;
function_ptr_type _function_ptr;
storage_type _storage; //!< memory to store the functor
function_ptr_type _function_ptr; //!< normal function pointer
};
method_type _method_ptr;
allocator_type _allocator_ptr;
method_type _method_ptr; //!< pointer to the function to call
allocator_type _allocator_ptr; //!< pointer to the function to allocate memory with

private:
void move_from_other(fixed_function& other) noexcept
{
assert(this != &o);

// cleanup
if (_allocator_ptr)
{
_allocator_ptr(&_storage, nullptr);
}
_allocator_ptr = nullptr;
_function_ptr = nullptr;

// move
_method_ptr = other._method_ptr;
other._method_ptr = nullptr;

_function_ptr = other._function_ptr;
_allocator_ptr = other._allocator_ptr;
if (_allocator_ptr)
{
_allocator_ptr(&_storage, &other._storage);
}
}
/**
* move the data from the passed object to this object
*
* @param other object to move data from
*/
inline void move_from_other(fixed_function& other) noexcept;

public:
inline fixed_function() noexcept
: _function_ptr (nullptr)
, _method_ptr (nullptr)
, _allocator_ptr(nullptr)
{ }

/**
* default constructor
*/
inline fixed_function() noexcept;

/**
* constructor
*
* @tparam T_func type of the functor to store
*
* @param func functor to call
*/
template<typename T_func>
inline fixed_function(T_func&& func) noexcept
: fixed_function()
{
using unref_type = std::remove_reference_t<T_func>;

static_assert(
sizeof(unref_type) < storage_size,
"functional object doesn't fit into internal storage");

static_assert(
std::is_move_constructible<unref_type> { },
"should be move constructable");

_method_ptr = [](const storage_type* s, function_ptr_type, T_args... args)
{
return storage_cast<const unref_type>(s)->operator()(args...);
};

_allocator_ptr = [](storage_type* s, void* obj)
{
if (obj)
{
new(s) unref_type(std::move(*static_cast<unref_type*>(obj)));
}
else
{
storage_cast<unref_type>(s)->~unref_type();
}
};

_allocator_ptr(&_storage, &func);
}

inline fixed_function(T_func&& func) noexcept;

/**
* constructor
*
* @tparam TF_return return type of the function pointer
* @tparam TF_args argument types of the function parameters
*
* @param func function pointer to call
*/
template<typename TF_return, typename... TF_args>
inline fixed_function(TF_return (*func)(TF_args...)) noexcept
: fixed_function()
{
_function_ptr = func;
_method_ptr = [](const storage_type*, function_ptr_type f, T_args... args)
{
return static_cast<decltype(func)>(f)(args...);
};
}

inline fixed_function(fixed_function&& other) noexcept
: fixed_function()
{ move_from_other(other); }

fixed_function(const fixed_function&) = delete;

inline ~fixed_function() noexcept
{
if (_allocator_ptr)
{
_allocator_ptr(&_storage, nullptr);
}
_allocator_ptr = nullptr;
_function_ptr = nullptr;
_method_ptr = nullptr;
}

inline fixed_function& operator=(fixed_function&& other) noexcept
{
move_from_other(other);
return *this;
}

inline fixed_function(TF_return (*func)(TF_args...)) noexcept;

/**
* move constructor
*/
inline fixed_function(fixed_function&& other) noexcept;

/**
* copy constructor
*/
inline fixed_function(const fixed_function&) = delete;

/**
* destructor
*/
inline ~fixed_function() noexcept;

/**
* move assignment operator
*
* @param other object to assign
*/
inline fixed_function& operator=(fixed_function&& other) noexcept;

/**
* copy assignment operator
*
* @return reference to this object
*/
fixed_function& operator=(const fixed_function&) = delete;

/**
* execution operator
*
* @tparam TF_args argument types to pass to the stored function
*
* @param args arguments to pass to the stored function
*
* @return return value of the stored function
*/
template<typename... TF_args>
inline decltype(auto) operator()(TF_args&&... args) const
{
assert(_method_ptr != nullptr);
return _method_ptr(&_storage, _function_ptr, std::forward<TF_args>(args)...);
}
inline decltype(auto) operator()(TF_args&&... args) const;

};

}
end_namespace_ecs_core_utils
} } }

+ 129
- 0
include/ecs/core/utils/fixed_function.inl Ver ficheiro

@@ -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)...);
}

} } }

+ 33
- 10
include/ecs/core/utils/movable_atomic.h Ver ficheiro

@@ -2,9 +2,15 @@

#include <ecs/config.h>

beg_namespace_ecs_core_utils
{
namespace ecs {
namespace core {
namespace utils {

/**
* atomic variable that implements the move constructor and the move assignment operator
*
* @tparam T inner type to store in the atomic
*/
template<typename T>
struct movable_atomic final
: std::atomic<T>
@@ -15,29 +21,46 @@ beg_namespace_ecs_core_utils
public:
using base_type::base_type;

movable_atomic() = default;
/**
* default constructor
*/
inline movable_atomic() = default;

movable_atomic(const movable_atomic&) = delete;
/**
* copy constructor
*/
inline movable_atomic(const movable_atomic&) = delete;

movable_atomic(movable_atomic&& other) noexcept
/**
* move constructor
*/
inline movable_atomic(movable_atomic&& other) noexcept
: base_type(other.load())
{ }

movable_atomic& operator=(const movable_atomic&) = delete;
/**
* copy assignment operator
*/
inline movable_atomic& operator=(const movable_atomic&) = delete;

movable_atomic& operator=(movable_atomic&& other) noexcept
/**
* move assignment operator
*/
inline movable_atomic& operator=(movable_atomic&& other) noexcept
{
this->store(other.load());
return *this;
}

/**
* assignment constructor to assign integral constants
*/
template<T value>
movable_atomic& operator=(std::integral_constant<T, value> x) noexcept
inline movable_atomic& operator=(std::integral_constant<T, value> x) noexcept
{
this->store(decltype(x)::value);
return *this;
}
};

}
end_namespace_ecs_core_utils
} } }

+ 186
- 0
include/ecs/core/utils/ordered_vector.h Ver ficheiro

@@ -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)...); }
};

} } }

+ 31
- 7
include/ecs/core/utils/scope_guard.h Ver ficheiro

@@ -7,28 +7,52 @@
auto scope_guard_ ## __LINE__ ( \
::ecs::core::utils::make_scope_guard(__VA_ARGS__))

beg_namespace_ecs_core_utils
{
namespace ecs {
namespace core {
namespace utils {

/**
* guard that executes the given function if the its scope is left
*
* @tparam T_func functor type to execute
*/
template<typename T_func>
struct scope_guard final
: T_func
{
template<typename... Xs>
inline scope_guard(Xs&&... xs)
/**
* constructor
*
* @tparam T_args argument types to initialize the functor with
*
* @param args arguments to initialize the functor with
*/
template<typename... T_args>
inline scope_guard(T_args&&... args)
noexcept(std::is_nothrow_constructible<T_func> { })
: T_func(std::forward<Xs>(xs)...)
: T_func(std::forward<T_args>(args)...)
{ }

/**
* destructor: will execute the stored functor
*/
inline ~scope_guard() noexcept(
noexcept(std::declval<T_func>().operator()()))
{ this->operator()(); }
};

/**
* helper to build a scope guard
*
* @tparam T_func functor type to execute
*
* @param f functor to execute
*
* @return created scope guard
*/
template<typename T_func>
inline decltype(auto) make_scope_guard(T_func&& f)
noexcept(std::is_nothrow_move_constructible<T_func> { })
{ return scope_guard<mp::decay_t<T_func>>(std::forward<T_func>(f)); }

}
end_namespace_ecs_core_utils
} } }

+ 15
- 5
include/ecs/core/utils/storage_cast.h Ver ficheiro

@@ -4,9 +4,20 @@

#include <ecs/core/mp/core/copy_qualifiers.h>

beg_namespace_ecs_core_utils
{

namespace ecs {
namespace core {
namespace utils {

/**
* cast the given storage to a certain type
*
* @tparam T type to cast storage in
* @tparam T_storage storage type to cast
*
* @param storage storage to cast
*
* @return casted storage
*/
template <typename T, typename T_storage>
inline constexpr decltype(auto) storage_cast(T_storage* storage) noexcept
{
@@ -25,5 +36,4 @@ beg_namespace_ecs_core_utils
}


}
end_namespace_ecs_core_utils
} } }

+ 4
- 1
include/ecs/core/utils/thread_pool.h Ver ficheiro

@@ -2,4 +2,7 @@

#include "./thread_pool/pool.h"
#include "./thread_pool/types.h"
#include "./thread_pool/worker.h"
#include "./thread_pool/worker.h"

#include "./thread_pool/pool.inl"
#include "./thread_pool/worker.inl"

+ 51
- 73
include/ecs/core/utils/thread_pool/pool.h Ver ficheiro

@@ -1,13 +1,19 @@
#pragma once

#include <ecs/config.h>
#include <atomic>
#include <vector>

#include "./worker.h"
#include "./types.h"
#include <ecs/config.h>
#include <ecs/core/utils/thread_pool/types.h>
#include <ecs/core/utils/thread_pool/worker.h>

beg_namespace_ecs_core_utils
{
namespace ecs {
namespace core {
namespace utils {

/**
* this class implements a thread pool
*/
struct thread_pool
{
private:
@@ -15,75 +21,47 @@ beg_namespace_ecs_core_utils
using atomic_size_t = std::atomic<size_t>;

private:
task_queue _queue;
worker_vector _workers;
atomic_size_t _outstanding_inits;

auto all_workers_finished() const noexcept
{
for (const auto& w : _workers)
{
if (!w.finished())
{
return false;
}
}
return true;
}

inline void post_dummy_task()
{ post([]{ }); }

void initialize_workers(size_t count)
{
_workers.reserve(count);
for (size_t i = 0; i < count; ++i)
{
_workers.emplace_back(_queue);
}

_outstanding_inits = count;
for (auto& w : _workers)
{
w.start(_outstanding_inits);
}
}
task_queue _queue; //!< queue to store tasks to execute
worker_vector _workers; //!< vector of worker threads
atomic_size_t _outstanding_inits; //!< number of outstanding worker initializations

/**
* check if all workers are finished or not
*
* @retval TRUE if all workers are finished
* @retval FALSE if at least one worker is running
*/
auto all_workers_finished() const noexcept;

/**
* initialize worker threads
*
* @param count number of workers to create
*/
void initialize_workers(size_t count);

public:
inline thread_pool(size_t count)
{ initialize_workers(count); }

~thread_pool()
{
// wait for uninitialized workers
while (_outstanding_inits > 0)
{
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}

// stop all workers
for (auto& w : _workers)
{
w.stop();
}

// post dummy tasks untill all workers has stopped
while (!all_workers_finished())
{
post_dummy_task();
}

// join the worker threads
for (auto& w : _workers)
{
w.join();
}
}

template<typename T_func>
inline void post(T_func&& func)
{ _queue.enqueue(std::forward<T_func>(func)); }
/**
* constructor
*
* @param count number of workers to create
*/
thread_pool(size_t count);

/**
* destructor
*/
~thread_pool();

/**
* enqueue a new task inside the thread pool
*
* @tparam T_task type of the task
*
* @param task task to execute
*/
template<typename T_task>
inline void post(T_task&& task);
};

}
end_namespace_ecs_core_utils
} } }

+ 16
- 0
include/ecs/core/utils/thread_pool/pool.inl Ver ficheiro

@@ -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));
}

} } }

+ 13
- 6
include/ecs/core/utils/thread_pool/types.h Ver ficheiro

@@ -5,11 +5,18 @@

#include "../fixed_function.h"

beg_namespace_ecs_core_utils
{
namespace ecs {
namespace core {
namespace utils {

using task = fixed_function<void(), 128>;
using task_queue = moodycamel::BlockingConcurrentQueue<task>;
/**
* Functor to execute as task inside the thread pool. The functor can have a max size of 128 bytes!
*/
using task = fixed_function<void(), 128>;

}
end_namespace_ecs_core_utils
/**
* non blocking concurrent queue to store thread pool tasks in
*/
using task_queue = moodycamel::BlockingConcurrentQueue<task>;

} } }

+ 60
- 57
include/ecs/core/utils/thread_pool/worker.h Ver ficheiro

@@ -6,78 +6,81 @@
#include "./types.h"
#include "../movable_atomic.h"

beg_namespace_ecs_core_utils
{
namespace ecs {
namespace core {
namespace utils {

/**
* worker thread to execute tasks of thread pool in
*/
struct thread_pool_worker
{
private:
/**
* state of the worker
*/
enum class state
{
uninizialized,
running,
stopped,
finished,
uninizialized, //!< the thread was not initialized yes
running, //!< the thread is running normally
stopped, //!< the thread was intended to stop execution
finished, //!< the thread has stopped execution
};

using atomic_state = movable_atomic<state>;

std::thread _thread;
task_queue& _queue;
atomic_state _state;
std::thread _thread; //!< actual thread object to use for execution
task_queue& _queue; //!< queue to poll new tasks from
atomic_state _state; //!< current state of the worker

private:
void run()
{
_state = state::running;
while (_state == state::running)
{
task t;
if (_queue.wait_dequeue_timed(t, std::chrono::milliseconds(500)))
{
t();
}
}
_state = state::finished;
}
/**
* thread worker method
*/
void run();

public:
thread_pool_worker(task_queue& queue) noexcept
: _queue(queue)
{ }

thread_pool_worker(thread_pool_worker&&) = default;
thread_pool_worker(const thread_pool_worker&) = delete;

thread_pool_worker& operator=(thread_pool_worker&&) = default;
thread_pool_worker& operator=(const thread_pool_worker&) = delete;

/**
* constructor
*
* @param queue task queue to poll tasks from
*/
inline thread_pool_worker(task_queue& queue) noexcept;

inline thread_pool_worker(thread_pool_worker&&) = default;
inline thread_pool_worker(const thread_pool_worker&) = delete;

inline thread_pool_worker& operator=(thread_pool_worker&&) = default;
inline thread_pool_worker& operator=(const thread_pool_worker&) = delete;

/**
* start the worker
*
* @tparam T_counter type of the counter
*
* @param remaining_inits number of remaining thread initialization (is decremented by this thread)
*/
template<typename T_counter>
inline void start(T_counter& remaining_inits)
{
_thread = std::thread([this, &remaining_inits]{
--remaining_inits;
run();
});
}

inline void stop() noexcept
{
assert(_state == state::running);
_state = state::stopped;
}

inline void join() noexcept
{
assert(_thread.joinable());
assert(_state == state::finished);
_thread.join();
}

inline bool finished() const noexcept
{ return _state == state::finished; }
inline void start(T_counter& remaining_inits);

/**
* stop the thread execution
*/
inline void stop() noexcept;

/**
* wait for the thread to finish
*/
inline void join() noexcept;

/**
* check if the thread has stopped execution
*
* @retval TRUE if the thread has stopped execution
* @retval FALSE if the thread is still running
*/
inline bool finished() const noexcept;

};

}
end_namespace_ecs_core_utils
} } }

+ 46
- 0
include/ecs/core/utils/thread_pool/worker.inl Ver ficheiro

@@ -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;
}

} } }

+ 5
- 1
include/ecs/settings.h Ver ficheiro

@@ -1,5 +1,9 @@
#pragma once

#include "./settings/entity_storage.h"
#include "./settings/refresh_parallelism.h"
#include "./settings/scheduler.h"
#include "./settings/settings.h"
#include "./settings/system_storage.h"
#include "./settings/system_storage.h"

#include "./settings/settings.inl"

+ 10
- 10
include/ecs/settings/entity_storage/dynamic.h Ver ficheiro

@@ -3,25 +3,25 @@
#include <ecs/config.h>
#include <ecs/core/entity/storage/dynamic.h>

beg_namespace_ecs_settings_entity_storage
{
namespace ecs {
namespace settings {
namespace entity_storage {

namespace __impl
namespace detail
{
template<size_t T_size>
struct dynamic_builder_t
{
template<typename T_settings, typename T_chunk_meta_data>
constexpr decltype(auto) operator()(T_settings settings, T_chunk_meta_data) const
template<typename T_settings, typename T_storage_meta_data>
constexpr decltype(auto) operator()(T_settings settings, T_storage_meta_data) const
{
using chunk_meta_data_type = core::mp::unwrap_t<T_chunk_meta_data>;
return core::entity::storage::dynamic<T_settings, chunk_meta_data_type>(T_size);
using storage_meta_data_type = core::mp::unwrap_t<T_storage_meta_data>;
return core::entity::storage::dynamic<T_settings, storage_meta_data_type>(T_size);
}
};
}

template<size_t T_size>
constexpr decltype(auto) dynamic = __impl::dynamic_builder_t<T_size> { };
constexpr decltype(auto) dynamic = detail::dynamic_builder_t<T_size> { };

}
end_namespace_ecs_settings_entity_storage
} } }

+ 10
- 10
include/ecs/settings/entity_storage/fixed.h Ver ficheiro

@@ -3,25 +3,25 @@
#include <ecs/config.h>
#include <ecs/core/entity/storage/fixed.h>

beg_namespace_ecs_settings_entity_storage
{
namespace ecs {
namespace settings {
namespace entity_storage {

namespace __impl
namespace detail
{
template<size_t T_size>
struct fixed_builder_t
{
template<typename T_settings, typename T_chunk_meta_data>
constexpr decltype(auto) operator()(T_settings settings, T_chunk_meta_data) const
template<typename T_settings, typename T_storage_meta_data>
constexpr decltype(auto) operator()(T_settings settings, T_storage_meta_data) const
{
using chunk_meta_data_type = core::mp::unwrap_t<T_chunk_meta_data>;
return core::entity::storage::fixed<T_settings, chunk_meta_data_type, T_size>();
using storage_meta_data_type = core::mp::unwrap_t<T_storage_meta_data>;
return core::entity::storage::fixed<T_settings, storage_meta_data_type, T_size>();
}
};
}

template<size_t T_size>
constexpr decltype(auto) fixed = __impl::fixed_builder_t<T_size> { };
constexpr decltype(auto) fixed = detail::fixed_builder_t<T_size> { };

}
end_namespace_ecs_settings_entity_storage
} } }

+ 4
- 4
include/ecs/settings/refresh_parallelism.h Ver ficheiro

@@ -2,12 +2,12 @@

#include <ecs/config.h>

beg_namespace_ecs_settings_refresh_parallelism
{
namespace ecs {
namespace settings {
namespace refresh_parallelism {

constexpr decltype(auto) enable = hana::true_c;

constexpr decltype(auto) disable = hana::false_c;

}
end_namespace_ecs_settings_refresh_parallelism
} } }

+ 7
- 7
include/ecs/settings/scheduler/atomic_counter.h Ver ficheiro

@@ -3,12 +3,13 @@
#include <ecs/config.h>
#include <ecs/core/system/scheduler/atomic_counter.h>

beg_namespace_ecs_settings_scheduler
{
namespace ecs {
namespace settings {
namespace scheduler {

namespace __impl
namespace detail
{
struct atomic_counter_t
struct atomic_counter_builder_t
{
template<typename T_settings, typename T_context>
constexpr decltype(auto) operator()(T_settings, T_context&& context) const noexcept
@@ -16,7 +17,6 @@ beg_namespace_ecs_settings_scheduler
};
}

constexpr decltype(auto) atomic_counter = __impl::atomic_counter_t { };
constexpr decltype(auto) atomic_counter = detail::atomic_counter_builder_t { };

}
end_namespace_ecs_settings_scheduler
} } }

+ 102
- 60
include/ecs/settings/settings.h Ver ficheiro

@@ -9,8 +9,8 @@
#include "./refresh_parallelism.h"
#include "./scheduler.h"

beg_namespace_ecs_settings
{
namespace ecs {
namespace settings {

namespace keys
{
@@ -22,86 +22,128 @@ beg_namespace_ecs_settings
constexpr decltype(auto) scheduler = hana::size_c<5>;
}

namespace __impl
namespace detail
{

/**
* settings of the ecs environment
*
* @tparam T_options option map for the settings
*/
template<typename T_options>
struct settings_t
{
private:
template<typename T_key, typename T_value>
constexpr decltype(auto) change(const T_key& key, T_value&& value) const noexcept
{
auto new_options = T_options { }.set(key, std::forward<T_value>(value));
return settings_t<core::mp::decay_t<decltype(new_options)>> { };
}

/**
* change the value of a given key
*
* @tparam T_key key type to change value for
* @tparam T_value type of the new value
*
* @param key key to change the value for
* @param value new value
*
* @return updated settings
*/
template<typename T_key, typename T_value>
constexpr decltype(auto) change(const T_key& key, T_value&& value) const noexcept;

/**
* get the value of a given option key
*
* @tparam T_key key type to get the value for
*
* @param key key to get the value for
*
* @return value stored for key
*/
template<typename T_key>
constexpr decltype(auto) get(const T_key& key) const noexcept
{ return T_options { }.at(key); }
constexpr decltype(auto) get(const T_key& key) const noexcept;

public: /* getter */
constexpr decltype(auto) component_signatures() const noexcept
{ return get(keys::component_signatures); }

constexpr decltype(auto) system_signatures() const noexcept
{ return get(keys::system_signatures); }

constexpr decltype(auto) system_storage() const noexcept
{ return get(keys::system_storage); }

constexpr decltype(auto) entity_storage() const noexcept
{ return get(keys::entity_storage); }

constexpr decltype(auto) refresh_parallelism() const noexcept
{ return get(keys::refresh_parallelism); }

constexpr decltype(auto) scheduler() const noexcept
{ return get(keys::scheduler); }
/**
* get the list of component signatures
*
* @return list of component signatures
*/
constexpr decltype(auto) component_signatures() const noexcept;

/**
* get the list of system signatures
*
* @return list of system signatures
*/
constexpr decltype(auto) system_signatures() const noexcept;

/**
* get the system storeage builder
*
* @return system storage builder
*/
constexpr decltype(auto) system_storage() const noexcept;

/**
* get the entity storeage builder
*
* @return entity storage builder
*/
constexpr decltype(auto) entity_storage() const noexcept;

/**
* get the refresh parallelism value
*
* @return refresh parallelism value
*/
constexpr decltype(auto) refresh_parallelism() const noexcept;

/**
* get the scheduler builder
*
* @return the scheduler builder
*/
constexpr decltype(auto) scheduler() const noexcept;

public: /* setter */
template<typename T>
constexpr decltype(auto) component_signatures(T t) const noexcept
{ return change(keys::component_signatures, t); }

template<typename T>
constexpr decltype(auto) system_signatures(T t) const noexcept
{ return change(keys::system_signatures, t); }
template<typename T_value>
constexpr decltype(auto) component_signatures(T_value value) const noexcept;

template<typename T>
constexpr decltype(auto) system_storage(T t) const noexcept
{ return change(keys::system_storage, t); }
template<typename T_value>
constexpr decltype(auto) system_signatures(T_value value) const noexcept;

template<typename T>
constexpr decltype(auto) entity_storage(T t) const noexcept
{ return change(keys::entity_storage, t); }
template<typename T_value>
constexpr decltype(auto) system_storage(T_value value) const noexcept;

template<typename T>
constexpr decltype(auto) refresh_parallelism(T t) const noexcept
{ return change(keys::refresh_parallelism, t); }
template<typename T_value>
constexpr decltype(auto) entity_storage(T_value value) const noexcept;

template<typename T>
constexpr decltype(auto) scheduler(T t) const noexcept
{ return change(keys::scheduler, t); }
template<typename T_value>
constexpr decltype(auto) refresh_parallelism(T_value value) const noexcept;

template<typename T_value>
constexpr decltype(auto) scheduler(T_value value) const noexcept;
};

/**
* predicate type to build a default settings object
*/
struct make_t
{
constexpr decltype(auto) operator()() const noexcept
{
using namespace ::ecs::core::mp;
auto options = option_map::make()
.add(keys::component_signatures, list::empty)
.add(keys::system_signatures, list::empty)
.add(keys::system_storage, system_storage::tuple)
.add(keys::entity_storage, entity_storage::dynamic<1024>)
.add(keys::refresh_parallelism, refresh_parallelism::enable)
.add(keys::scheduler, scheduler::atomic_counter);
return settings_t<decay_t<decltype(options)>> { };
}
/**
* execute the predicate
*
* @return settings object (@ref settings_t)
*/
constexpr decltype(auto) operator()() const noexcept;
};

}

constexpr decltype(auto) make = __impl::make_t { };
/**
* predicate to build a default settings object
*/
constexpr decltype(auto) make = detail::make_t { };

}
end_namespace_ecs_settings
} }

+ 134
- 0
include/ecs/settings/settings.inl Ver ficheiro

@@ -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)>> { };
}

} } }

+ 6
- 6
include/ecs/settings/system_storage/tuple.h Ver ficheiro

@@ -3,10 +3,11 @@
#include <ecs/config.h>
#include <ecs/core/system/storage/tuple.h>

beg_namespace_ecs_settings_system_storage
{
namespace ecs {
namespace settings {
namespace system_storage {

namespace __impl
namespace detail
{
struct tuple_storage_builder
{
@@ -16,7 +17,6 @@ beg_namespace_ecs_settings_system_storage
};
}

constexpr decltype(auto) tuple = __impl::tuple_storage_builder { };
constexpr decltype(auto) tuple = detail::tuple_storage_builder { };

}
end_namespace_ecs_settings_system_storage
} } }

+ 3
- 1
include/ecs/signature/component.h Ver ficheiro

@@ -2,4 +2,6 @@

#include "./component/signature.h"
#include "./component/storage.h"
#include "./system/signature.h"
#include "./system/signature.h"

#include "./component/signature.inl"

+ 102
- 42
include/ecs/signature/component/signature.h Ver ficheiro

@@ -7,73 +7,133 @@
#include <ecs/tag/component.h>
#include "./storage.h"

beg_namespace_ecs_signature_component
{
namespace ecs {
namespace signature {
namespace component {

namespace keys
{
constexpr decltype(auto) storage = hana::size_c<0>;
}

namespace __impl
namespace detail
{

/**
* defines a component signature
*
* @tparam T_component_tag component tag the signature is defined for
* @tparam T_options option map for the component signature
*/
template<typename T_component_tag_list, typename T_options>
struct signature_t
{
static_assert(tag::component::is_list(T_component_tag_list { }) == hana::true_c, "component signature needs a list of component tags");

private:
template<typename T_key, typename T_value>
constexpr decltype(auto) change(const T_key& key, T_value&& value) const noexcept
{
auto new_options = T_options { }.set(key, std::forward<T_value>(value));
return signature_t<T_component_tag_list, core::mp::decay_t<decltype(new_options)>> { };
}

/**
* change the value of the given option key
*
* @tparam T_key key type to set the value for
* @tparam T_value value type of the new value
*
* @param key key to set the value for
* @param value new value
*
* @return updated component signature
*/
template<typename T_key, typename T_value>
constexpr decltype(auto) change(const T_key& key, T_value&& value) const noexcept;

/**
* get the value of the given option key
*
* @tparam T_key key type to get the value for
*
* @param key key to get the value for
*
* @return value stored for the given key
*/
template<typename T_key>
constexpr decltype(auto) get(const T_key& key) const noexcept
{ return T_options { }.at(key); }

public:
constexpr decltype(auto) tags() const noexcept
{ return T_component_tag_list { }; }

constexpr decltype(auto) get(const T_key& key) const noexcept;

public: /* tags */

/**
* get a list of all component tags for this signature
*
* @return list of component tags managed by this signature
*/
constexpr decltype(auto) tags() const noexcept;

/**
* check if this signature has a certain component tag
*
* @tparam T_component_tag component tag type to check
*
* @param ct component tag to check
*
* @retval integral constant TRUE if the given component tag is managed by this signature
* @retval integral constant FALSE if the given component tag is not managed by this signature
*/
template<typename T_component_tag>
constexpr decltype(auto) has(T_component_tag ct) const noexcept
{ return hana::contains(T_component_tag_list { }, ct); }

constexpr decltype(auto) has(T_component_tag ct) const noexcept;

public: /* options */

/**
* set the storage option of this component signature
*
* @tparam T_storage storage builder type (specialization of @ref storage::storage_builder_interface_t)
*
* @param storage storage builder (specialized instance of @ref storage::storage_builder_interface_t)
*
* @return updated component signature
*/
template<typename T_storage>
constexpr decltype(auto) storage(T_storage&& storage) const noexcept
{ return change(keys::storage, std::forward<T_storage>(storage)); }

constexpr decltype(auto) storage() const noexcept
{ return get(keys::storage); }
constexpr decltype(auto) storage(T_storage&& storage) const noexcept;

/**
* get the storage option of this component signature
*
* @return storage builder (specialized instance of @ref storage::storage_builder_interface_t)
*/
constexpr decltype(auto) storage() const noexcept;
};

/**
* predicate class to create a component signature
*/
struct make_t
{
/**
* execute the predicate
*
* @tparam T_component_tags component tag types to build component signature for
*
* @param cts component tags to build component signature for
*
* @return component signature (@ref detail::signature_t)
*/
template<typename... T_component_tags>
constexpr decltype(auto) operator()(T_component_tags... cts) const noexcept
{
using namespace ::ecs::core::mp;

auto ctl = list::make(cts...);

auto options = option_map::make()
.add(keys::storage, storage::default_);

using signature_type = signature_t<decay_t<decltype(ctl)>, decay_t<decltype(options)>>;

return signature_type { };
}
constexpr decltype(auto) operator()(T_component_tags... cts) const noexcept;
};
}

constexpr decltype(auto) make = __impl::make_t { };
/**
* predicate to create a new component signature (see @ref detail::signature_t)
*/
constexpr decltype(auto) make = detail::make_t { };

constexpr decltype(auto) is_valid = core::mp::is_valid<__impl::signature_t>;
/**
* predicate to check if a component signature is valid
*/
constexpr decltype(auto) is_valid = core::mp::is_valid<detail::signature_t>;

constexpr decltype(auto) is_list = core::mp::is_list<__impl::signature_t>;
/**
* predicate to check if all component signatures in a list are valid
*/
constexpr decltype(auto) is_list = core::mp::is_list<detail::signature_t>;

}
end_namespace_ecs_signature_component
} } }

+ 81
- 0
include/ecs/signature/component/signature.inl Ver ficheiro

@@ -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 { };
}

}

} } }

+ 2
- 1
include/ecs/signature/component/storage.h Ver ficheiro

@@ -3,4 +3,5 @@
#include "./storage/default.h"
#include "./storage/dynamic.h"
#include "./storage/empty.h"
#include "./storage/fixed.h"
#include "./storage/fixed.h"
#include "./storage/interface.h"

+ 17
- 6
include/ecs/signature/component/storage/default.h Ver ficheiro

@@ -3,11 +3,20 @@
#include "./empty.h"
#include "./dynamic.h"

beg_namespace_ecs_signature_component_storage
{
namespace ecs {
namespace signature {
namespace component {
namespace storage {

namespace __impl
namespace detail
{
/**
* Default storage builder.
* Specializes @ref ::ecs::signature::component::storage::storage_builder_interface_t.
*
* Will redirect to the empty storage builder (@ref empty_builder_t) if the components of the component
* signature are all empty. Will use the dynamic builder (@ref dynamic_builder_t) otherwise.
*/
struct default_builder_t
{
template<typename T_settings, typename T_component_tag_list>
@@ -23,7 +32,9 @@ beg_namespace_ecs_signature_component_storage
};
}

constexpr decltype(auto) default_ = __impl::default_builder_t { };
/**
* predicate to build a default component storage
*/
constexpr decltype(auto) default_ = detail::default_builder_t { };

}
end_namespace_ecs_signature_component_storage
} } } }

+ 21
- 7
include/ecs/signature/component/storage/dynamic.h Ver ficheiro

@@ -3,11 +3,21 @@
#include <ecs/config.h>
#include <ecs/core/component/storage/dynamic.h>

beg_namespace_ecs_signature_component_storage
{
namespace ecs {
namespace signature {
namespace component {
namespace storage {

namespace __impl
namespace detail
{
/**
* Dynamic storage builder.
* Specializes @ref ::ecs::signature::component::storage::storage_builder_interface_t.
*
* Will build a component storage that will automatically increase in size if needed.
*
* @tparam T_size initial size of the storage
*/
template<size_t T_size>
struct dynamic_builder_t
{
@@ -17,8 +27,12 @@ beg_namespace_ecs_signature_component_storage
};
}

template<size_t T_size>
constexpr decltype(auto) dynamic = __impl::dynamic_builder_t<T_size> { };
/**
* predicate to build a dynamic component storage
*
* @tparam T_size initial size of the storage
*/
template<size_t T_size = 1024>
constexpr decltype(auto) dynamic = detail::dynamic_builder_t<T_size> { };

}
end_namespace_ecs_signature_component_storage
} } } }

+ 16
- 6
include/ecs/signature/component/storage/empty.h Ver ficheiro

@@ -3,11 +3,19 @@
#include <ecs/config.h>
#include <ecs/core/component/storage/empty.h>

beg_namespace_ecs_signature_component_storage
{
namespace ecs {
namespace signature {
namespace component {
namespace storage {

namespace __impl
namespace detail
{
/**
* Empty storage builder.
* Specializes @ref ::ecs::signature::component::storage::storage_builder_interface_t.
*
* Will build a component storage that does not store any component.
*/
struct empty_builder_t
{
template<typename T_settings, typename T_component_tag_list>
@@ -16,7 +24,9 @@ beg_namespace_ecs_signature_component_storage
};
}

constexpr decltype(auto) empty = __impl::empty_builder_t { };
/**
* predicate to build an empty component storage
*/
constexpr decltype(auto) empty = detail::empty_builder_t { };

}
end_namespace_ecs_signature_component_storage
} } } }

+ 21
- 7
include/ecs/signature/component/storage/fixed.h Ver ficheiro

@@ -3,11 +3,21 @@
#include <ecs/config.h>
#include <ecs/core/component/storage/fixed.h>

beg_namespace_ecs_signature_component_storage
{
namespace ecs {
namespace signature {
namespace component {
namespace storage {

namespace __impl
namespace detail
{
/**
* Fixed storage builder.
* Specializes @ref ::ecs::signature::component::storage::storage_builder_interface_t.
*
* Will build a component storage that will store components in memory of fixed size.
*
* @tparam T_size size of the storage
*/
template<size_t T_size>
struct fixed_builder_t
{
@@ -17,8 +27,12 @@ beg_namespace_ecs_signature_component_storage
};
}

template<size_t T_size>
constexpr decltype(auto) fixed = __impl::fixed_builder_t<T_size> { };
/**
* predicate to build a fixed component storage
*
* @tparam T_size size of the storage
*/
template<size_t T_size = 1024>
constexpr decltype(auto) fixed = detail::fixed_builder_t<T_size> { };

}
end_namespace_ecs_signature_component_storage
} } } }

+ 31
- 0
include/ecs/signature/component/storage/interface.h Ver ficheiro

@@ -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;
};

} } } }

+ 3
- 1
include/ecs/signature/system.h Ver ficheiro

@@ -2,4 +2,6 @@

#include "./system/output.h"
#include "./system/parallelism.h"
#include "./system/signature.h"
#include "./system/signature.h"

#include "./system/signature.inl"

+ 8
- 7
include/ecs/signature/system/output.h Ver ficheiro

@@ -2,10 +2,12 @@

#include <ecs/config.h>

beg_namespace_ecs_signature_system_output
{
namespace ecs {
namespace signature {
namespace system {
namespace output {

namespace __impl
namespace detail
{
struct empty_output
{ };
@@ -17,12 +19,11 @@ beg_namespace_ecs_signature_system_output
}

template<typename T_output>
using type = __impl::output_t<T_output>;
using type = detail::output_t<T_output>;

template<typename T_output>
constexpr decltype(auto) value = type<T_output> { };

constexpr decltype(auto) none = value<__impl::empty_output>;
constexpr decltype(auto) none = value<detail::empty_output>;

}
end_namespace_ecs_signature_system_output
} } } }

+ 8
- 6
include/ecs/signature/system/parallelism/composer/fixed_threshold.h Ver ficheiro

@@ -3,10 +3,12 @@
#include <ecs/config.h>
#include <ecs/core/system/parallelism/composer/fixed_threshold.h>

beg_namespace_ecs_signature_system_parallelism
{
namespace ecs {
namespace signature {
namespace system {
namespace parallelism {

namespace __impl
namespace detail
{
template<typename T_threshold, typename T_lower_strategy, typename T_greater_strategy>
struct fixed_threshold_builder_t
@@ -33,7 +35,7 @@ beg_namespace_ecs_signature_system_parallelism
};
}

constexpr decltype(auto) fixed_threshold = __impl::fixed_threshold_t { };
/** fuuu */
constexpr decltype(auto) fixed_threshold = detail::fixed_threshold_t { };

}
end_namespace_ecs_signature_system_parallelism
} } } }

+ 7
- 6
include/ecs/signature/system/parallelism/composer/none_below_threshold.h Ver ficheiro

@@ -5,10 +5,12 @@
#include "./fixed_threshold.h"
#include "../strategy/none.h"

beg_namespace_ecs_signature_system_parallelism
{
namespace ecs {
namespace signature {
namespace system {
namespace parallelism {

namespace __impl
namespace detail
{
struct none_below_threshold_t
{
@@ -18,7 +20,6 @@ beg_namespace_ecs_signature_system_parallelism
};
}

constexpr decltype(auto) none_below_threshold = __impl::none_below_threshold_t { };
constexpr decltype(auto) none_below_threshold = detail::none_below_threshold_t { };

}
end_namespace_ecs_signature_system_parallelism
} } } }

+ 7
- 6
include/ecs/signature/system/parallelism/strategy/none.h Ver ficheiro

@@ -3,10 +3,12 @@
#include <ecs/config.h>
#include <ecs/core/system/parallelism/strategy/none.h>

beg_namespace_ecs_signature_system_parallelism
{
namespace ecs {
namespace signature {
namespace system {
namespace parallelism {

namespace __impl
namespace detail
{
struct none_builder_t
{
@@ -21,7 +23,6 @@ beg_namespace_ecs_signature_system_parallelism
};
}

constexpr decltype(auto) none = __impl::none_t { };
constexpr decltype(auto) none = detail::none_t { };

}
end_namespace_ecs_signature_system_parallelism
} } } }

+ 7
- 6
include/ecs/signature/system/parallelism/strategy/split_evenly.h Ver ficheiro

@@ -3,10 +3,12 @@
#include <ecs/config.h>
#include <ecs/core/system/parallelism/strategy/split_evenly.h>

beg_namespace_ecs_signature_system_parallelism
{
namespace ecs {
namespace signature {
namespace system {
namespace parallelism {

namespace __impl
namespace detail
{
template<typename T_split>
struct split_evenly_builder_t
@@ -29,7 +31,6 @@ beg_namespace_ecs_signature_system_parallelism
};
}

constexpr decltype(auto) split_evenly = __impl::split_evenly_t { };
constexpr decltype(auto) split_evenly = detail::split_evenly_t { };

}
end_namespace_ecs_signature_system_parallelism
} } } }

+ 7
- 6
include/ecs/signature/system/parallelism/strategy/split_evenly_cores.h Ver ficheiro

@@ -3,10 +3,12 @@
#include <ecs/config.h>
#include <ecs/core/system/parallelism/strategy/split_evenly.h>

beg_namespace_ecs_signature_system_parallelism
{
namespace ecs {
namespace signature {
namespace system {
namespace parallelism {

namespace __impl
namespace detail
{
struct split_evenly_cores_builder_t
{
@@ -32,7 +34,6 @@ beg_namespace_ecs_signature_system_parallelism
};
}

constexpr decltype(auto) split_evenly_cores = __impl::split_evenly_cores_t { };
constexpr decltype(auto) split_evenly_cores = detail::split_evenly_cores_t { };

}
end_namespace_ecs_signature_system_parallelism
} } } }

+ 7
- 6
include/ecs/signature/system/parallelism/strategy/split_every.h Ver ficheiro

@@ -3,10 +3,12 @@
#include <ecs/config.h>
#include <ecs/core/system/parallelism/strategy/split_every.h>

beg_namespace_ecs_signature_system_parallelism
{
namespace ecs {
namespace signature {
namespace system {
namespace parallelism {

namespace __impl
namespace detail
{
template<typename T_split>
struct split_every_builder_t
@@ -29,7 +31,6 @@ beg_namespace_ecs_signature_system_parallelism
};
}

constexpr decltype(auto) split_every = __impl::split_every_t { };
constexpr decltype(auto) split_every = detail::split_every_t { };

}
end_namespace_ecs_signature_system_parallelism
} } } }

+ 104
- 55
include/ecs/signature/system/signature.h Ver ficheiro

@@ -8,8 +8,9 @@
#include "./output.h"
#include "./parallelism.h"

beg_namespace_ecs_signature_system
{
namespace ecs {
namespace signature {
namespace system {

namespace keys
{
@@ -20,8 +21,15 @@ beg_namespace_ecs_signature_system
constexpr decltype(auto) output = hana::size_c<4>;
}

namespace __impl
namespace detail
{

/**
* defines a system signature
*
* @tparam T_system_tag system tag the signature is defined for
* @tparam T_options option map for the system signature
*/
template<typename T_system_tag, typename T_options>
struct signature_t
{
@@ -30,89 +38,130 @@ beg_namespace_ecs_signature_system
using tag_type = T_system_tag;

private:
/**
* change the value of an option key
*
* @tparam T_key key type to change value for
* @tparam T_value value type of the new value
*
* @param key key to change the value for
* @param value new value
*
* @return updated system signature
*/
template<typename T_key, typename T_value>
constexpr decltype(auto) change(const T_key& key, T_value&& value) const noexcept
{
auto new_options = T_options { }.set(key, std::forward<T_value>(value));
using impl_type = signature_t<T_system_tag, core::mp::decay_t<decltype(new_options)>>;
return impl_type { };
}

constexpr decltype(auto) change(const T_key& key, T_value&& value) const noexcept;

/**
* get the value of an option key
*
* @tparam T_key key type to get value for
*
* @param key key to get the value for
*
* @return value stored for key
*/
template<typename T_key>
constexpr decltype(auto) get(const T_key& key) const noexcept
{ return T_options { }.at(key); }
constexpr decltype(auto) get(const T_key& key) const noexcept;

public: /* misc */
constexpr decltype(auto) tag() const noexcept
{ return T_system_tag { }; }

/**
* get the system tag of this system signature
*
* @return system tag of this system signature
*/
constexpr decltype(auto) tag() const noexcept;

/**
* check if the given component tag can be written by this system
*
* @tparam T_component_tag component tag type to check write access for
*
* @param ct component tag to check write access for
*
* @retval integral constant TRUE if the given component tag can be written
* @retval integral constant FALSE if the given component tag can not be written
*/
template<typename T_component_tag>
constexpr decltype(auto) can_write(T_component_tag ct) const noexcept;

/**
* check if the given component tag can be read by this system
*
* @tparam T_component_tag component tag type to check read access for
*
* @param ct component tag to check read access for
*
* @retval integral constant TRUE if the given component tag can be read
* @retval integral constant FALSE if the given component tag can not be read
*/
template<typename T_component_tag>
constexpr decltype(auto) can_read(T_component_tag ct) const noexcept;

public: /* getter */
constexpr decltype(auto) parallelism() const noexcept
{ return get(keys::parallelism); }

constexpr decltype(auto) dependencies() const noexcept
{ return get(keys::dependencies); }
/**
* get the value of the parallelism option
*/
constexpr decltype(auto) parallelism() const noexcept;

/** get a list of system tags that system depends on */
constexpr decltype(auto) dependencies() const noexcept;

constexpr decltype(auto) read() const noexcept
{ return get(keys::read_components); }
/** get a list of component tags this system wants to read */
constexpr decltype(auto) read() const noexcept;

constexpr decltype(auto) write() const noexcept
{ return get(keys::write_components); }
/** get a list of component tags this system wants to write */
constexpr decltype(auto) write() const noexcept;

constexpr decltype(auto) output() const noexcept
{ return get(keys::output); }
/** get the output type of the system */
constexpr decltype(auto) output() const noexcept;

public: /* setter */

/** set the parallelism options
* @param parallelism is a predicate the takes no parameters and returns a
* system executor interface */
template<typename T_parallelism>
constexpr decltype(auto) parallelism(T_parallelism parallelism) const noexcept
{ return change(keys::parallelism, parallelism); }
constexpr decltype(auto) parallelism(T_parallelism parallelism) const noexcept;

/** set a list of system tags, that system depends on */
template<typename... T_system_tags>
constexpr decltype(auto) dependencies(T_system_tags... tags) const noexcept
{ return change(keys::dependencies, core::mp::list::make(tags...)); }
constexpr decltype(auto) dependencies(T_system_tags... tags) const noexcept;

/** set a list of component tags, this system wants to read */
template<typename... T_component_tags>
constexpr decltype(auto) read(T_component_tags... tags) const noexcept
{ return change(keys::read_components, core::mp::list::make(tags...)); }
constexpr decltype(auto) read(T_component_tags... tags) const noexcept;

/** set a list of component tags, this system wants to write */
template<typename... T_component_tags>
constexpr decltype(auto) write(T_component_tags... tags) const noexcept
{ return change(keys::write_components, core::mp::list::make(tags...)); }
constexpr decltype(auto) write(T_component_tags... tags) const noexcept;

/** set the output type of this system */
template<typename T_output>
constexpr decltype(auto) output(T_output output) const noexcept
{ return change(keys::output, output); }
constexpr decltype(auto) output(T_output output) const noexcept;
};

/** predicate class to create a system signature */
struct make_t
{
template<typename T_system_tag>
constexpr decltype(auto) operator()(T_system_tag) const noexcept
{
using namespace ::ecs::core::mp;

auto options = option_map::make()
.add(keys::parallelism, parallelism::none())
.add(keys::dependencies, list::empty)
.add(keys::read_components, list::empty)
.add(keys::write_components, list::empty)
.add(keys::output, output::none);

using signature_type = signature_t<T_system_tag, decay_t<decltype(options)>>;

return signature_type { };
}
constexpr decltype(auto) operator()(T_system_tag) const noexcept;
};
}

constexpr decltype(auto) make = __impl::make_t { };
/** predicate to create a system signature */
constexpr decltype(auto) make = detail::make_t { };

constexpr decltype(auto) is_valid = core::mp::is_valid<__impl::signature_t>;
/** predicate to check if a system signature is valid */
constexpr decltype(auto) is_valid = core::mp::is_valid<detail::signature_t>;

constexpr decltype(auto) is_list = core::mp::is_list<__impl::signature_t>;
/** predicate to check if a list of system signatures is valid */
constexpr decltype(auto) is_list = core::mp::is_list<detail::signature_t>;

/** get the system tag type of a system signature type */
template<typename T_system_sig>
using tag_type = typename core::mp::unwrap_t<T_system_sig>::tag_type;
using tag_type_t = typename core::mp::unwrap_t<T_system_sig>::tag_type;

}
end_namespace_ecs_signature_system
} } }

+ 158
- 0
include/ecs/signature/system/signature.inl Ver ficheiro

@@ -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 { };
}

}

} } }

Alguns ficheiros não foram mostrados porque foram alterados demasiados ficheiros neste diff

Carregando…
Cancelar
Guardar