| @@ -0,0 +1,25 @@ | |||
| # Initialize CMake ################################################################################ | |||
| 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 ) | |||
| Include ( cotire OPTIONAL ) | |||
| # Tests ########################################################################################### | |||
| Include ( CTest ) | |||
| Enable_Testing ( ) | |||
| # Dependencies #################################################################################### | |||
| Find_Package ( Hana REQUIRED ) | |||
| # Projects ######################################################################################## | |||
| Add_SubDirectory ( ${CMAKE_CURRENT_SOURCE_DIR}/src ) | |||
| Add_SubDirectory ( ${CMAKE_CURRENT_SOURCE_DIR}/test ) | |||
| @@ -0,0 +1,2 @@ | |||
| Original code by Vittorio Romeo alias SuperV1234 | |||
| https://github.com/SuperV1234/ecst/ | |||
| @@ -0,0 +1,52 @@ | |||
| Set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} \ | |||
| -g \ | |||
| -Wall \ | |||
| -Wextra \ | |||
| -Wconversion \ | |||
| -Werror \ | |||
| -Wno-unused-parameter \ | |||
| -Wbad-function-cast \ | |||
| -Wcast-align \ | |||
| -Wcast-qual \ | |||
| -Wconversion \ | |||
| -Wdouble-promotion \ | |||
| -Wfloat-equal \ | |||
| -Wnested-externs \ | |||
| -Wno-attributes \ | |||
| -Wno-builtin-macro-redefined \ | |||
| -Wno-vla \ | |||
| -Wno-pragmas \ | |||
| -Wold-style-definition \ | |||
| -Woverlength-strings \ | |||
| -Wshadow \ | |||
| -Wwrite-strings") | |||
| # -Wlogical-op | |||
| # -Wno-aggressive-loop-optimizations | |||
| # -Wtrampolines" | |||
| Set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} \ | |||
| -ftemplate-depth=2000 \ | |||
| -g \ | |||
| -Wall \ | |||
| -Wextra \ | |||
| -Wconversion \ | |||
| -Werror \ | |||
| -Wno-reorder \ | |||
| -Wno-unused-parameter \ | |||
| -Wcast-align \ | |||
| -Wcast-qual \ | |||
| -Wconversion \ | |||
| -Wdouble-promotion \ | |||
| -Wfloat-equal \ | |||
| -Wno-attributes \ | |||
| -Wno-builtin-macro-redefined \ | |||
| -Wno-vla \ | |||
| -Wno-pragmas \ | |||
| -Woverlength-strings \ | |||
| -Wshadow \ | |||
| -Wwrite-strings") | |||
| # -Wlogical-op | |||
| # -Wtrampolines | |||
| # -Wno-aggressive-loop-optimizations | |||
| @@ -0,0 +1,6 @@ | |||
| #pragma once | |||
| #include <ecs/component/signature_list.h> | |||
| #include <ecs/component/signature.h> | |||
| #include <ecs/component/storage.h> | |||
| #include <ecs/component/tag.h> | |||
| @@ -0,0 +1,71 @@ | |||
| #pragma once | |||
| #include <ecs/config.h> | |||
| #include <ecs/mp/core.h> | |||
| #include <ecs/mp/list.h> | |||
| #include <ecs/mp/option_map.h> | |||
| #include <ecs/component/tag.h> | |||
| #include <ecs/component/storage.h> | |||
| namespace ecs { | |||
| namespace component { | |||
| namespace signature { | |||
| namespace keys | |||
| { | |||
| constexpr decltype(auto) storage = mp::size_c<0>; | |||
| } | |||
| namespace __impl | |||
| { | |||
| template<typename T_component_tag_list, typename T_options> | |||
| struct signature_t | |||
| { | |||
| static_assert(component::tag::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)); | |||
| using impl_type = signature_t<T_component_tag_list, mp::decay_t<decltype(new_options)>>; | |||
| return impl_type { }; | |||
| } | |||
| public: | |||
| constexpr decltype(auto) tags() const noexcept | |||
| { return T_component_tag_list { }; } | |||
| template<typename T_component_tag> | |||
| constexpr decltype(auto) has(T_component_tag ct) const noexcept | |||
| { return hana::contains(T_component_tag_list { }, ct); } | |||
| template<typename T_storage> | |||
| constexpr decltype(auto) storage(T_storage&& storage) const noexcept | |||
| { return change(keys::storage, std::forward<T_storage>(storage)); } | |||
| }; | |||
| struct make_t | |||
| { | |||
| template<typename... T_component_tags> | |||
| constexpr decltype(auto) operator()(T_component_tags... cts) const noexcept | |||
| { | |||
| auto ctl = mp::list::make(cts...); | |||
| auto options = mp::option_map::make() | |||
| .add(keys::storage, storage::default_); | |||
| using signature_type = signature_t<mp::decay_t<decltype(ctl)>, mp::decay_t<decltype(options)>>; | |||
| return signature_type { }; | |||
| } | |||
| }; | |||
| } | |||
| constexpr decltype(auto) make = __impl::make_t { }; | |||
| constexpr decltype(auto) is_valid = mp::is_valid<__impl::signature_t>; | |||
| constexpr decltype(auto) is_list = mp::is_list<__impl::signature_t>; | |||
| } } } | |||
| @@ -0,0 +1,27 @@ | |||
| #pragma once | |||
| #include <ecs/config.h> | |||
| #include <ecs/component/signature.h> | |||
| namespace ecs { | |||
| namespace component { | |||
| namespace signature_list { | |||
| namespace __impl | |||
| { | |||
| struct make_t | |||
| { | |||
| template<typename... T_component_signatures> | |||
| constexpr decltype(auto) operator()(T_component_signatures... css) const noexcept | |||
| { | |||
| static_assert( | |||
| decltype(signature::is_valid(css...)) { }, | |||
| "component::signature_list::make() needs a list of component signatures"); | |||
| return mp::list::make(mp::wrap(css)...); | |||
| } | |||
| }; | |||
| } | |||
| constexpr decltype(auto) make = __impl::make_t { }; | |||
| } } } | |||
| @@ -0,0 +1,5 @@ | |||
| #pragma once | |||
| #include <ecs/component/storage/contigous_buffer.h> | |||
| #include <ecs/component/storage/default.h> | |||
| #include <ecs/component/storage/empty.h> | |||
| @@ -0,0 +1,14 @@ | |||
| #pragma once | |||
| namespace ecs { | |||
| namespace component { | |||
| namespace storage { | |||
| namespace __impl | |||
| { | |||
| struct contigous_buffer_t { }; | |||
| } | |||
| constexpr decltype(auto) contigous_buffer = __impl::contigous_buffer_t { }; | |||
| } } } | |||
| @@ -0,0 +1,14 @@ | |||
| #pragma once | |||
| namespace ecs { | |||
| namespace component { | |||
| namespace storage { | |||
| namespace __impl | |||
| { | |||
| struct default_t { }; | |||
| } | |||
| constexpr decltype(auto) default_ = __impl::default_t { }; | |||
| } } } | |||
| @@ -0,0 +1,14 @@ | |||
| #pragma once | |||
| namespace ecs { | |||
| namespace component { | |||
| namespace storage { | |||
| namespace __impl | |||
| { | |||
| struct empty_t { }; | |||
| } | |||
| constexpr decltype(auto) empty = __impl::empty_t { }; | |||
| } } } | |||
| @@ -0,0 +1,31 @@ | |||
| #pragma once | |||
| #include <ecs/config.h> | |||
| #include <ecs/mp/core.h> | |||
| #include <ecs/mp/list.h> | |||
| #include <ecs/mp/tag.h> | |||
| namespace ecs { | |||
| namespace component { | |||
| namespace tag { | |||
| namespace __impl | |||
| { | |||
| template<typename T_component> | |||
| struct tag_t : public hana::type<T_component> | |||
| { }; | |||
| } | |||
| template<typename T_component> | |||
| using type = __impl::tag_t<T_component>; | |||
| template<typename T_component> | |||
| constexpr auto value = type<T_component> { }; | |||
| constexpr decltype(auto) make = mp::tag::make<__impl::tag_t>; | |||
| constexpr decltype(auto) is_valid = mp::is_valid<__impl::tag_t>; | |||
| constexpr decltype(auto) is_list = mp::is_list<__impl::tag_t>; | |||
| } } } | |||
| @@ -0,0 +1,24 @@ | |||
| #pragma once | |||
| #include <boost/hana.hpp> | |||
| namespace ecs | |||
| { | |||
| namespace hana = ::boost::hana; | |||
| } | |||
| #include <cxxabi.h> | |||
| template<typename T> | |||
| struct type_helper | |||
| { | |||
| static inline std::string name() | |||
| { | |||
| int status; | |||
| auto name = abi::__cxa_demangle(typeid(T).name(), 0, 0, & status); | |||
| return std::string(name ? name : typeid(T).name()); | |||
| } | |||
| }; | |||
| @@ -0,0 +1,7 @@ | |||
| #pragma once | |||
| #include <ecs/context/entity_storage.h> | |||
| #include <ecs/context/refresh.h> | |||
| #include <ecs/context/scheduler.h> | |||
| #include <ecs/context/settings.h> | |||
| #include <ecs/context/threading.h> | |||
| @@ -0,0 +1,27 @@ | |||
| #pragma once | |||
| #include <ecs/config.h> | |||
| #include <ecs/mp/core/alias.h> | |||
| namespace ecs { | |||
| namespace context { | |||
| namespace entity_storage { | |||
| namespace __impl | |||
| { | |||
| template<typename T_size> | |||
| struct fixed_t | |||
| { using size = T_size; }; | |||
| template<typename T_size> | |||
| struct dynamic_t | |||
| { using initial_size = T_size; }; | |||
| } | |||
| template<size_t N> | |||
| constexpr decltype(auto) fixed = __impl::fixed_t<hana::size_t<N>> { }; | |||
| template<size_t N> | |||
| constexpr decltype(auto) dynamic = __impl::dynamic_t<hana::size_t<N>> { }; | |||
| } } } | |||
| @@ -0,0 +1,26 @@ | |||
| #pragma once | |||
| #include <ecs/config.h> | |||
| namespace ecs { | |||
| namespace context { | |||
| namespace refresh { | |||
| namespace __impl | |||
| { | |||
| struct base_t { }; | |||
| struct enabled_t | |||
| : public base_t | |||
| { }; | |||
| struct disabled_t | |||
| : public base_t | |||
| { }; | |||
| } | |||
| constexpr decltype(auto) parallelism_enabled = __impl::enabled_t { }; | |||
| constexpr decltype(auto) parallelism_disabled = __impl::disabled_t { }; | |||
| } } } | |||
| @@ -0,0 +1,3 @@ | |||
| #pragma once | |||
| #include <ecs/context/scheduler/atomic_counter.h> | |||
| @@ -0,0 +1,11 @@ | |||
| #pragma once | |||
| #include <ecs/config.h> | |||
| namespace ecs { | |||
| namespace context { | |||
| namespace scheduler { | |||
| constexpr decltype(auto) atomic_counter = hana::type_c<void>; | |||
| } } } | |||
| @@ -0,0 +1,82 @@ | |||
| #pragma once | |||
| #include <ecs/config.h> | |||
| #include <ecs/mp/list.h> | |||
| #include <ecs/mp/option_map.h> | |||
| #include <ecs/context/entity_storage.h> | |||
| #include <ecs/context/scheduler.h> | |||
| #include <ecs/context/threading.h> | |||
| #include <ecs/context/refresh.h> | |||
| namespace ecs { | |||
| namespace context { | |||
| namespace settings { | |||
| namespace keys | |||
| { | |||
| constexpr decltype(auto) threading = mp::size_c<0>; | |||
| constexpr decltype(auto) entity_storage = mp::size_c<1>; | |||
| constexpr decltype(auto) component_signatures = mp::size_c<2>; | |||
| constexpr decltype(auto) system_signatures = mp::size_c<3>; | |||
| constexpr decltype(auto) scheduler = mp::size_c<4>; | |||
| constexpr decltype(auto) refresh_parallelism = mp::size_c<5>; | |||
| } | |||
| namespace __impl | |||
| { | |||
| 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<mp::decay_t<decltype(new_options)>> { }; | |||
| } | |||
| public: /* setter */ | |||
| template<typename T> | |||
| constexpr decltype(auto) set_threading(T&& t) const noexcept | |||
| { return change(keys::threading, std::forward<T>(t)); } | |||
| template<typename T> | |||
| constexpr decltype(auto) set_entity_storage(T&& t) const noexcept | |||
| { return change(keys::entity_storage, std::forward<T>(t)); } | |||
| template<typename T> | |||
| constexpr decltype(auto) set_component_signatures(T t) const noexcept | |||
| { return change(keys::component_signatures, t); } | |||
| template<typename T> | |||
| constexpr decltype(auto) set_system_signatures(T t) const noexcept | |||
| { return change(keys::system_signatures, t); } | |||
| template<typename T> | |||
| constexpr decltype(auto) set_scheduler(T t) const noexcept | |||
| { return change(keys::scheduler, t); } | |||
| template<typename T> | |||
| constexpr decltype(auto) set_refresh_parallelism(T t) const noexcept | |||
| { return change(keys::refresh_parallelism, t); } | |||
| }; | |||
| struct make_t | |||
| { | |||
| constexpr decltype(auto) operator()() const noexcept | |||
| { | |||
| auto options = mp::option_map::make() | |||
| .add(keys::threading, threading::allow_inner_parallelism) | |||
| .add(keys::entity_storage, entity_storage::dynamic<1000>) | |||
| .add(keys::component_signatures, mp::list::empty) | |||
| .add(keys::system_signatures, mp::list::empty) | |||
| .add(keys::scheduler, scheduler::atomic_counter) | |||
| .add(keys::refresh_parallelism, refresh::parallelism_enabled); | |||
| return settings_t<mp::decay_t<decltype(options)>> { }; | |||
| } | |||
| }; | |||
| } | |||
| constexpr decltype(auto) make = __impl::make_t { }; | |||
| } } } | |||
| @@ -0,0 +1,14 @@ | |||
| #pragma once | |||
| #include <ecs/config.h> | |||
| #include <ecs/mp/core/alias.h> | |||
| namespace ecs { | |||
| namespace context { | |||
| namespace threading { | |||
| constexpr decltype(auto) singlethreaded = mp::size_c<0>; | |||
| constexpr decltype(auto) allow_inner_parallelism = mp::size_c<1>; | |||
| constexpr decltype(auto) deny_inner_parallelism = mp::size_c<2>; | |||
| } } } | |||
| @@ -0,0 +1,5 @@ | |||
| #pragma once | |||
| #include <ecs/mp/core.h> | |||
| #include <ecs/mp/list.h> | |||
| #include <ecs/mp/tag.h> | |||
| @@ -0,0 +1,8 @@ | |||
| #pragma once | |||
| #include <ecs/mp/core/alias.h> | |||
| #include <ecs/mp/core/decay.h> | |||
| #include <ecs/mp/core/is_list.h> | |||
| #include <ecs/mp/core/is_specialization_of.h> | |||
| #include <ecs/mp/core/is_valid.h> | |||
| #include <ecs/mp/core/wrap.h> | |||
| @@ -0,0 +1,17 @@ | |||
| #pragma once | |||
| #include <ecs/config.h> | |||
| namespace ecs { | |||
| namespace mp { | |||
| template<size_t I> | |||
| constexpr decltype(auto) size_c = hana::size_t<I> { }; | |||
| template<typename T> | |||
| constexpr decltype(auto) type_c = hana::type_c<T>; | |||
| template<typename T> | |||
| using unwrap = typename T::type; | |||
| } } | |||
| @@ -0,0 +1,11 @@ | |||
| #pragma once | |||
| #include <ecs/config.h> | |||
| namespace ecs { | |||
| namespace mp { | |||
| template<typename T> | |||
| using decay_t = typename hana::detail::decay<T>::type; | |||
| } } | |||
| @@ -0,0 +1,22 @@ | |||
| #pragma once | |||
| #include <ecs/mp/core/is_valid.h> | |||
| namespace ecs { | |||
| namespace mp { | |||
| namespace __impl | |||
| { | |||
| template<template<typename...> class T_tag> | |||
| struct is_list_t | |||
| { | |||
| template<typename T> | |||
| constexpr decltype(auto) operator()(T&& t) const noexcept | |||
| { return hana::all_of(std::forward<T>(t), is_valid<T_tag>); } | |||
| }; | |||
| } | |||
| template<template<typename...> class T_tag> | |||
| constexpr decltype(auto) is_list = __impl::is_list_t<T_tag> { }; | |||
| } } | |||
| @@ -0,0 +1,18 @@ | |||
| #pragma once | |||
| #include <ecs/config.h> | |||
| namespace ecs { | |||
| namespace mp { | |||
| template<template<typename...> class T_template, typename T> | |||
| struct is_specialization_of | |||
| : public hana::false_ | |||
| { }; | |||
| template<template<typename...> class T_template, typename... Xs> | |||
| struct is_specialization_of<T_template, T_template<Xs...>> | |||
| : public hana::true_ | |||
| { }; | |||
| } } | |||
| @@ -0,0 +1,27 @@ | |||
| #pragma once | |||
| #include <ecs/config.h> | |||
| #include <ecs/mp/list.h> | |||
| #include <ecs/mp/core/is_specialization_of.h> | |||
| namespace ecs { | |||
| namespace mp { | |||
| namespace __impl | |||
| { | |||
| template<template<typename...> class T_tag> | |||
| struct is_valid_t | |||
| { | |||
| template<typename T> | |||
| static constexpr decltype(auto) is_tag = mp::is_specialization_of<T_tag, T> { }; | |||
| template<typename... Xs> | |||
| constexpr decltype(auto) operator()(Xs... xs) const noexcept | |||
| { return mp::list::all(is_tag<Xs>...); } | |||
| }; | |||
| } | |||
| template<template<typename...> class T_tag> | |||
| constexpr decltype(auto) is_valid = __impl::is_valid_t<T_tag> { }; | |||
| } } | |||
| @@ -0,0 +1,30 @@ | |||
| #pragma once | |||
| #include <ecs/config.h> | |||
| #include <ecs/mp/core/alias.h> | |||
| namespace ecs { | |||
| namespace mp { | |||
| namespace __impl | |||
| { | |||
| struct wrap_t | |||
| { | |||
| template<typename T> | |||
| constexpr decltype(auto) operator()(T) const noexcept | |||
| { return type_c<T>; } | |||
| }; | |||
| struct unwrapped_t | |||
| { | |||
| template<typename T> | |||
| constexpr decltype(auto) operator()(T) const noexcept | |||
| { return unwrap<T> { }; } | |||
| }; | |||
| } | |||
| constexpr decltype(auto) wrap = __impl::wrap_t { }; | |||
| constexpr decltype(auto) unwrapped = __impl::unwrapped_t { }; | |||
| } } | |||
| @@ -0,0 +1,53 @@ | |||
| #pragma once | |||
| #include <ecs/config.h> | |||
| namespace ecs { | |||
| namespace mp { | |||
| namespace list { | |||
| /* base */ | |||
| namespace __impl | |||
| { | |||
| template<typename... Xs> | |||
| using list_t = hana::basic_tuple<Xs...>; | |||
| } | |||
| template<typename... Xs> | |||
| using type = __impl::list_t<Xs...>; | |||
| template<typename... Xs> | |||
| constexpr decltype(auto) value = type<Xs...> { }; | |||
| constexpr decltype(auto) empty = value<>; | |||
| /* make */ | |||
| namespace __impl | |||
| { | |||
| struct make_t | |||
| { | |||
| template<typename... Xs> | |||
| constexpr decltype(auto) operator()(Xs...) const noexcept | |||
| { return value<Xs...>; } | |||
| }; | |||
| } | |||
| constexpr decltype(auto) make = __impl::make_t { }; | |||
| /* all */ | |||
| namespace __impl | |||
| { | |||
| 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)...)); } | |||
| }; | |||
| } | |||
| constexpr decltype(auto) all = __impl::all_t { }; | |||
| } } } | |||
| @@ -0,0 +1,102 @@ | |||
| #pragma once | |||
| #include <ecs/config.h> | |||
| #include <ecs/mp/core/decay.h> | |||
| namespace ecs { | |||
| namespace mp { | |||
| namespace option_map { | |||
| namespace __impl | |||
| { | |||
| template<typename T_new_pair> | |||
| struct replace_helper_t | |||
| { | |||
| using new_pair_type = T_new_pair; | |||
| const new_pair_type& new_pair; | |||
| template<typename T_pair> | |||
| constexpr decltype(auto) operator()(T_pair&& pair) const noexcept | |||
| { | |||
| return hana::if_( | |||
| hana::equal(hana::first(new_pair), hana::first(pair)), | |||
| new_pair, | |||
| std::forward<T_pair>(pair)); | |||
| } | |||
| }; | |||
| struct replace_t | |||
| { | |||
| template<typename T_map, typename T_new_pair> | |||
| constexpr decltype(auto) operator()(T_map&& map, T_new_pair&& new_pair) const noexcept | |||
| { | |||
| return hana::unpack( | |||
| std::forward<T_map>(map), | |||
| hana::on( | |||
| hana::make_map, | |||
| replace_helper_t<T_new_pair> { | |||
| std::forward<T_new_pair>(new_pair) | |||
| })); | |||
| } | |||
| }; | |||
| constexpr decltype(auto) replace = replace_t { }; | |||
| template<typename T_map> | |||
| struct impl_t | |||
| { | |||
| private: | |||
| using map_type = T_map; | |||
| map_type _map; | |||
| public: | |||
| template<typename T_key> | |||
| constexpr decltype(auto) at(const T_key& key) const noexcept | |||
| { return hana::first(hana::at_key(_map, key)); } | |||
| template<typename T_key> | |||
| constexpr decltype(auto) type_at(const T_key& key) const noexcept | |||
| { return type_c<decay_t<decltype(at(key))>>; } | |||
| template<typename T_key, typename T_value> | |||
| constexpr decltype(auto) add(const T_key& key, T_value&& value) const noexcept | |||
| { | |||
| auto new_map = hana::insert( | |||
| _map, | |||
| hana::make_pair( | |||
| key, | |||
| hana::make_pair( | |||
| std::forward<T_value>(value), | |||
| hana::false_c))); | |||
| return impl_t<decltype(new_map)> { }; | |||
| } | |||
| template<typename T_key, typename T_value> | |||
| constexpr decltype(auto) set(const T_key& key, T_value&& value) const noexcept | |||
| { | |||
| static_assert( | |||
| decltype(hana::equal(hana::second(hana::at_key(_map, key)), hana::false_c)) { }, | |||
| "this value has alreay been set"); | |||
| auto new_map = replace( | |||
| _map, | |||
| hana::make_pair( | |||
| key, | |||
| hana::make_pair( | |||
| std::forward<T_value>(value), | |||
| hana::true_c))); | |||
| return impl_t<decltype(new_map)> { }; | |||
| } | |||
| }; | |||
| struct make_t | |||
| { | |||
| constexpr decltype(auto) operator()() const noexcept | |||
| { return impl_t<decay_t<decltype(hana::make_map())>> { }; } | |||
| }; | |||
| } | |||
| constexpr decltype(auto) make = __impl::make_t { }; | |||
| } } } | |||
| @@ -0,0 +1,26 @@ | |||
| #pragma once | |||
| #include <ecs/config.h> | |||
| #include <ecs/mp/list.h> | |||
| namespace ecs { | |||
| namespace mp { | |||
| namespace tag { | |||
| /* make */ | |||
| namespace __impl | |||
| { | |||
| template<template<typename> class T_tag> | |||
| struct make_t | |||
| { | |||
| template<typename T_component> | |||
| constexpr decltype(auto) operator()(T_component&&) const noexcept | |||
| { return T_tag<ecs::mp::decay_t<T_component>> { }; } | |||
| }; | |||
| } | |||
| template<template<typename> class T_tag> | |||
| constexpr decltype(auto) make = __impl::make_t<T_tag> { }; | |||
| } } } | |||
| @@ -0,0 +1,7 @@ | |||
| #pragma once | |||
| #include <ecs/system/output.h> | |||
| #include <ecs/system/parallelism.h> | |||
| #include <ecs/system/signature_list.h> | |||
| #include <ecs/system/signature.h> | |||
| #include <ecs/system/tag.h> | |||
| @@ -0,0 +1,28 @@ | |||
| #pragma once | |||
| #include <ecs/config.h> | |||
| namespace ecs { | |||
| namespace system { | |||
| namespace output { | |||
| namespace __impl | |||
| { | |||
| struct empty_output | |||
| { }; | |||
| template<typename T_output> | |||
| struct output_t | |||
| : public hana::type<T_output> | |||
| { }; | |||
| } | |||
| template<typename T_output> | |||
| using type = __impl::output_t<T_output>; | |||
| template<typename T_output> | |||
| constexpr decltype(auto) value = type<T_output> { }; | |||
| constexpr decltype(auto) none = value<__impl::empty_output>; | |||
| } } } | |||
| @@ -0,0 +1,3 @@ | |||
| #pragma once | |||
| #include <ecs/system/parallelism/none.h> | |||
| @@ -0,0 +1,23 @@ | |||
| #pragma once | |||
| namespace ecs { | |||
| namespace system { | |||
| namespace parallelism { | |||
| namespace __impl | |||
| { | |||
| struct none_executor_t | |||
| { | |||
| }; | |||
| struct none_t | |||
| { | |||
| constexpr decltype(auto) operator()() const noexcept | |||
| { return none_executor_t { }; } | |||
| }; | |||
| } | |||
| constexpr decltype(auto) none = __impl::none_t { }; | |||
| } } } | |||
| @@ -0,0 +1,90 @@ | |||
| #pragma once | |||
| #include <ecs/config.h> | |||
| #include <ecs/mp/core.h> | |||
| #include <ecs/mp/list.h> | |||
| #include <ecs/mp/option_map.h> | |||
| #include <ecs/system/tag.h> | |||
| #include <ecs/system/parallelism.h> | |||
| #include <ecs/system/output.h> | |||
| namespace ecs { | |||
| namespace system { | |||
| namespace signature { | |||
| namespace keys | |||
| { | |||
| constexpr decltype(auto) parallelism = mp::size_c<0>; | |||
| constexpr decltype(auto) dependencies = mp::size_c<1>; | |||
| constexpr decltype(auto) read_components = mp::size_c<2>; | |||
| constexpr decltype(auto) write_components = mp::size_c<3>; | |||
| constexpr decltype(auto) output = mp::size_c<4>; | |||
| } | |||
| namespace __impl | |||
| { | |||
| template<typename T_system_tag, typename T_options> | |||
| struct signature_t | |||
| { | |||
| static_assert(system::tag::is_valid(T_system_tag { }) == hana::true_c, "system signature needs a system 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)); | |||
| using impl_type = signature_t<T_system_tag, mp::decay_t<decltype(new_options)>>; | |||
| return impl_type { }; | |||
| } | |||
| public: | |||
| constexpr decltype(auto) tag() const noexcept | |||
| { return T_system_tag { }; } | |||
| template<typename T_parallelism> | |||
| constexpr decltype(auto) parallelism(T_parallelism parallelism) const noexcept | |||
| { return change(keys::parallelism, parallelism); } | |||
| template<typename... T_system_tags> | |||
| constexpr decltype(auto) dependencies(T_system_tags... tags) const noexcept | |||
| { return change(keys::dependencies, mp::list::make(tags...)); } | |||
| template<typename... T_component_tags> | |||
| constexpr decltype(auto) read(T_component_tags... tags) const noexcept | |||
| { return change(keys::read_components, mp::list::make(tags...)); } | |||
| template<typename... T_component_tags> | |||
| constexpr decltype(auto) write(T_component_tags... tags) const noexcept | |||
| { return change(keys::write_components, mp::list::make(tags...)); } | |||
| template<typename T_output> | |||
| constexpr decltype(auto) output(T_output output) const noexcept | |||
| { return change(keys::output, output); } | |||
| }; | |||
| struct make_t | |||
| { | |||
| template<typename T_system_tag> | |||
| constexpr decltype(auto) operator()(T_system_tag) const noexcept | |||
| { | |||
| auto options = mp::option_map::make() | |||
| .add(keys::parallelism, parallelism::none()) | |||
| .add(keys::dependencies, mp::list::empty) | |||
| .add(keys::read_components, mp::list::empty) | |||
| .add(keys::write_components, mp::list::empty) | |||
| .add(keys::output, output::none); | |||
| using signature_type = signature_t<T_system_tag, mp::decay_t<decltype(options)>>; | |||
| return signature_type { }; | |||
| } | |||
| }; | |||
| } | |||
| constexpr decltype(auto) make = __impl::make_t { }; | |||
| constexpr decltype(auto) is_valid = mp::is_valid<__impl::signature_t>; | |||
| constexpr decltype(auto) is_list = mp::is_list<__impl::signature_t>; | |||
| } } } | |||
| @@ -0,0 +1,27 @@ | |||
| #pragma once | |||
| #include <ecs/config.h> | |||
| #include <ecs/system/signature.h> | |||
| namespace ecs { | |||
| namespace system { | |||
| namespace signature_list { | |||
| namespace __impl | |||
| { | |||
| struct make_t | |||
| { | |||
| template<typename... T_system_signatures> | |||
| constexpr decltype(auto) operator()(T_system_signatures... sss) const noexcept | |||
| { | |||
| static_assert( | |||
| decltype(signature::is_valid(sss...)) { }, | |||
| "system::signature_list::make() needs a list of system signatures"); | |||
| return mp::list::make(mp::wrap(sss)...); | |||
| } | |||
| }; | |||
| } | |||
| constexpr decltype(auto) make = __impl::make_t { }; | |||
| } } } | |||
| @@ -0,0 +1,31 @@ | |||
| #pragma once | |||
| #include <ecs/config.h> | |||
| #include <ecs/mp/core.h> | |||
| #include <ecs/mp/list.h> | |||
| #include <ecs/mp/tag.h> | |||
| namespace ecs { | |||
| namespace system { | |||
| namespace tag { | |||
| namespace __impl | |||
| { | |||
| template<typename T_component> | |||
| struct tag_t : public hana::type<T_component> | |||
| { }; | |||
| } | |||
| template<typename T_component> | |||
| using type = __impl::tag_t<T_component>; | |||
| template<typename T_component> | |||
| constexpr auto value = type<T_component> { }; | |||
| constexpr decltype(auto) make = mp::tag::make<__impl::tag_t>; | |||
| constexpr decltype(auto) is_valid = mp::is_valid<__impl::tag_t>; | |||
| constexpr decltype(auto) is_list = mp::is_list<__impl::tag_t>; | |||
| } } } | |||
| @@ -0,0 +1,18 @@ | |||
| # Project: ecs #################################################################################### | |||
| Project ( ecs VERSION 1.0.0.0 LANGUAGES CXX ) | |||
| # File ( GLOB_RECURSE SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp ) | |||
| # Add_Library ( ecs ${SOURCE_FILES} ) | |||
| Add_Library ( ecs INTERFACE ) | |||
| Target_Include_Directories ( | |||
| ecs | |||
| INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/../include | |||
| ) | |||
| Target_Link_Libraries ( | |||
| ecs | |||
| INTERFACE hana | |||
| ) | |||
| If ( __COTIRE_INCLUDED ) | |||
| Cotire ( ecs ) | |||
| EndIf ( ) | |||
| @@ -0,0 +1,35 @@ | |||
| # Project: test_ecs ############################################################################### | |||
| Project ( test_ecs ) | |||
| File ( GLOB_RECURSE SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp ) | |||
| Add_Executable ( test_ecs EXCLUDE_FROM_ALL ${SOURCE_FILES} ) | |||
| If ( __COTIRE_INCLUDED ) | |||
| Cotire ( test_ecs ) | |||
| EndIf ( ) | |||
| Target_Link_Libraries ( | |||
| test_ecs | |||
| ecs | |||
| gmock_main | |||
| gmock | |||
| gtest | |||
| pthread | |||
| ) | |||
| # Build Tests ##################################################################################### | |||
| If ( NOT TARGET build_tests ) | |||
| Add_Custom_Target ( build_tests ) | |||
| EndIf ( ) | |||
| Add_Dependencies ( build_tests test_ecs ) | |||
| # Run Tests ####################################################################################### | |||
| If ( NOT TARGET tests ) | |||
| Add_Custom_Target ( tests ) | |||
| EndIf ( ) | |||
| Add_Custom_Target ( run_test_ecs DEPENDS test_ecs COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test_ecs ) | |||
| Add_Dependencies ( tests run_test_ecs ) | |||
| # CTest ########################################################################################### | |||
| Add_Test ( NAME ecs COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test_ecs ) | |||
| @@ -0,0 +1,119 @@ | |||
| #include <gtest/gtest.h> | |||
| #include <ecs/context.h> | |||
| #include <ecs/system.h> | |||
| #include <ecs/component.h> | |||
| #define MAKE_COMPONENT_TAG(x) \ | |||
| namespace tag \ | |||
| { \ | |||
| constexpr decltype(auto) x = ::ecs::component::tag::value<component::x>; \ | |||
| constexpr decltype(auto) warning_supressor_##x() { (void) x; } \ | |||
| } | |||
| #define MAKE_SYSTEM_TAG(x) \ | |||
| namespace tag \ | |||
| { \ | |||
| constexpr decltype(auto) x = ::ecs::system::tag::value<system::x>; \ | |||
| constexpr decltype(auto) warning_supressor_##x() { (void) x; } \ | |||
| } | |||
| namespace test | |||
| { | |||
| namespace component | |||
| { | |||
| struct position | |||
| { | |||
| double x; | |||
| double y; | |||
| }; | |||
| struct velocity | |||
| { | |||
| double x; | |||
| double y; | |||
| }; | |||
| struct acceleration | |||
| { | |||
| double x; | |||
| double y; | |||
| }; | |||
| MAKE_COMPONENT_TAG(position) | |||
| MAKE_COMPONENT_TAG(velocity) | |||
| MAKE_COMPONENT_TAG(acceleration) | |||
| } | |||
| namespace system | |||
| { | |||
| struct accelerate | |||
| { | |||
| }; | |||
| struct move | |||
| { | |||
| }; | |||
| MAKE_SYSTEM_TAG(accelerate) | |||
| MAKE_SYSTEM_TAG(move) | |||
| } | |||
| } | |||
| using namespace test; | |||
| namespace c = component; | |||
| namespace ct = c::tag; | |||
| namespace cs = ecs::component::signature; | |||
| namespace csl = ecs::component::signature_list; | |||
| namespace s = system; | |||
| namespace st = s::tag; | |||
| namespace ss = ecs::system::signature; | |||
| namespace ssl = ecs::system::signature_list; | |||
| constexpr decltype(auto) cs_position = | |||
| cs::make(ct::position) | |||
| .storage(::ecs::component::storage::contigous_buffer); | |||
| constexpr decltype(auto) cs_velocity = | |||
| cs::make(ct::velocity) | |||
| .storage(::ecs::component::storage::contigous_buffer); | |||
| constexpr decltype(auto) cs_acceleration = | |||
| cs::make(ct::acceleration) | |||
| .storage(::ecs::component::storage::contigous_buffer); | |||
| constexpr decltype(auto) cs_list = csl::make( | |||
| cs_position, | |||
| cs_velocity, | |||
| cs_acceleration); | |||
| constexpr decltype(auto) ss_accelerate = | |||
| ss::make(st::accelerate) | |||
| .read(ct::acceleration) | |||
| .write(ct::velocity); | |||
| constexpr decltype(auto) ss_move = | |||
| ss::make(st::move) | |||
| .dependencies(st::accelerate) | |||
| .read(ct::velocity) | |||
| .write(ct::position); | |||
| constexpr decltype(auto) ss_list = ssl::make( | |||
| ss_accelerate, | |||
| ss_move); | |||
| TEST(DummyTest, fuu) | |||
| { | |||
| std::cout | |||
| << type_helper<decltype(cs_list)>::name() | |||
| << std::endl | |||
| << std::endl | |||
| << type_helper<decltype(ss_list)>::name() | |||
| << std::endl | |||
| << std::endl; | |||
| EXPECT_TRUE ( true ); | |||
| } | |||