From 85e33e8a41cadec7f9c95a2caaa19a4f27b20e73 Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Tue, 15 Oct 2019 07:55:43 +0700 Subject: [PATCH 1/3] move to C++17 --- .appveyor.yml | 3 +- .travis.yml | 51 +--------- CMakeLists.txt | 4 +- README.md | 4 +- headers/ecs.hpp/ecs.hpp | 221 +++++++++++++++------------------------- untests/ecs_tests.cpp | 42 ++++---- 6 files changed, 113 insertions(+), 212 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 27089cb..793e431 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,9 +1,8 @@ version: "{build}" shallow_clone: true image: - - Visual Studio 2015 - Visual Studio 2017 - - Visual Studio 2019 Preview + - Visual Studio 2019 platform: - Win32 - x64 diff --git a/.travis.yml b/.travis.yml index 5ea4d0f..739cd3b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,18 +1,6 @@ language: cpp matrix: include: - - os: linux - dist: trusty - addons: { apt: { sources: ubuntu-toolchain-r-test, packages: ["xorg-dev", "g++-4.9"] } } - env: MATRIX_EVAL="CC=gcc-4.9 && CXX=g++-4.9" - - os: linux - dist: trusty - addons: { apt: { sources: ubuntu-toolchain-r-test, packages: ["xorg-dev", "g++-5"] } } - env: MATRIX_EVAL="CC=gcc-5 && CXX=g++-5" - - os: linux - dist: trusty - addons: { apt: { sources: ubuntu-toolchain-r-test, packages: ["xorg-dev", "g++-6"] } } - env: MATRIX_EVAL="CC=gcc-6 && CXX=g++-6" - os: linux dist: trusty addons: { apt: { sources: ubuntu-toolchain-r-test, packages: ["xorg-dev", "g++-7"] } } @@ -23,42 +11,12 @@ matrix: env: MATRIX_EVAL="CC=gcc-8 && CXX=g++-8" - os: linux dist: trusty - addons: { apt: { sources: ["ubuntu-toolchain-r-test", "llvm-toolchain-precise-3.8"], packages: ["xorg-dev", "clang-3.8", "g++-5"] } } - env: MATRIX_EVAL="CC=clang-3.8 && CXX=clang++-3.8" + addons: { apt: { sources: ["ubuntu-toolchain-r-test", "llvm-toolchain-trusty-7"], packages: ["xorg-dev", "clang-7", "g++-7"] } } + env: MATRIX_EVAL="CC=clang-7 && CXX=clang++-7" - os: linux dist: trusty - addons: { apt: { sources: ["ubuntu-toolchain-r-test", "llvm-toolchain-precise-3.9"], packages: ["xorg-dev", "clang-3.9", "g++-5"] } } - env: MATRIX_EVAL="CC=clang-3.9 && CXX=clang++-3.9" - - os: linux - dist: trusty - addons: { apt: { sources: ["ubuntu-toolchain-r-test", "llvm-toolchain-trusty-4.0"], packages: ["xorg-dev", "clang-4.0", "g++-5"] } } - env: MATRIX_EVAL="CC=clang-4.0 && CXX=clang++-4.0" - - os: linux - dist: trusty - addons: { apt: { sources: ["ubuntu-toolchain-r-test", "llvm-toolchain-trusty-5.0"], packages: ["xorg-dev", "clang-5.0", "g++-7"] } } - env: MATRIX_EVAL="CC=clang-5.0 && CXX=clang++-5.0" - - os: linux - dist: trusty - addons: { apt: { sources: ["ubuntu-toolchain-r-test", "llvm-toolchain-trusty-6.0"], packages: ["xorg-dev", "clang-6.0", "g++-7"] } } - env: MATRIX_EVAL="CC=clang-6.0 && CXX=clang++-6.0" - - os: osx - osx_image: xcode8.3 - compiler: clang - - os: osx - osx_image: xcode9 - compiler: clang - - os: osx - osx_image: xcode9.1 - compiler: clang - - os: osx - osx_image: xcode9.2 - compiler: clang - - os: osx - osx_image: xcode9.3 - compiler: clang - - os: osx - osx_image: xcode9.4 - compiler: clang + addons: { apt: { sources: ["ubuntu-toolchain-r-test", "llvm-toolchain-trusty-8"], packages: ["xorg-dev", "clang-8", "g++-7"] } } + env: MATRIX_EVAL="CC=clang-8 && CXX=clang++-8" - os: osx osx_image: xcode10 compiler: clang @@ -69,7 +27,6 @@ before_install: - if [ "$TRAVIS_OS_NAME" == 'osx' ]; then brew update; brew upgrade cmake; - brew install git-lfs; fi - if [ "$TRAVIS_OS_NAME" == 'linux' ]; then mkdir $HOME/cmake; diff --git a/CMakeLists.txt b/CMakeLists.txt index a62b77c..9966923 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -# 3.8 version is required for `cxx_std_14` +# 3.8 version is required for `cxx_std_17` cmake_minimum_required(VERSION 3.8 FATAL_ERROR) if(NOT DEFINED PROJECT_NAME) @@ -9,7 +9,7 @@ project(ecs.hpp) add_library(${PROJECT_NAME} INTERFACE) target_include_directories(${PROJECT_NAME} INTERFACE headers) -target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_14) +target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_17) if(BUILD_AS_STANDALONE) option(BUILD_WITH_UNBENCH "Build with benchmarks" OFF) diff --git a/README.md b/README.md index 1cf05db..4b4db71 100644 --- a/README.md +++ b/README.md @@ -10,14 +10,14 @@ [badge.travis]: https://img.shields.io/travis/BlackMATov/ecs.hpp/master.svg?logo=travis [badge.appveyor]: https://img.shields.io/appveyor/ci/BlackMATov/ecs-hpp/master.svg?logo=appveyor [badge.codecov]: https://img.shields.io/codecov/c/github/BlackMATov/ecs.hpp/master.svg?logo=codecov -[badge.language]: https://img.shields.io/badge/language-C%2B%2B14-red.svg +[badge.language]: https://img.shields.io/badge/language-C%2B%2B17-yellow.svg [badge.license]: https://img.shields.io/badge/license-MIT-blue.svg [badge.paypal]: https://img.shields.io/badge/donate-PayPal-orange.svg?logo=paypal&colorA=00457C [travis]: https://travis-ci.org/BlackMATov/ecs.hpp [appveyor]: https://ci.appveyor.com/project/BlackMATov/ecs-hpp [codecov]: https://codecov.io/gh/BlackMATov/ecs.hpp -[language]: https://en.wikipedia.org/wiki/C%2B%2B14 +[language]: https://en.wikipedia.org/wiki/C%2B%2B17 [license]: https://en.wikipedia.org/wiki/MIT_License [paypal]: https://www.paypal.me/matov diff --git a/headers/ecs.hpp/ecs.hpp b/headers/ecs.hpp/ecs.hpp index 89f5ad3..735ea10 100644 --- a/headers/ecs.hpp/ecs.hpp +++ b/headers/ecs.hpp/ecs.hpp @@ -53,11 +53,11 @@ namespace ecs_hpp constexpr std::size_t entity_id_version_bits = 10u; static_assert( - std::is_unsigned::value, + std::is_unsigned_v, "ecs_hpp (family_id must be an unsigned integer)"); static_assert( - std::is_unsigned::value, + std::is_unsigned_v, "ecs_hpp (entity_id must be an unsigned integer)"); static_assert( @@ -77,15 +77,6 @@ namespace ecs_hpp { namespace detail { - // - // as_const - // - - template < typename T > - constexpr std::add_const_t& as_const(T& t) noexcept { - return t; - } - // // hash_combine // @@ -102,21 +93,19 @@ namespace ecs_hpp { template < typename T, typename... Ts, std::size_t... Is > std::tuple tuple_tail_impl( - std::tuple&& t, - std::index_sequence iseq) + std::index_sequence, + std::tuple&& t) { (void)t; - (void)iseq; return std::make_tuple(std::move(std::get(t))...); } template < typename T, typename... Ts, std::size_t... Is > std::tuple tuple_tail_impl( - const std::tuple& t, - std::index_sequence iseq) + std::index_sequence, + const std::tuple& t) { (void)t; - (void)iseq; return std::make_tuple(std::get(t)...); } } @@ -124,15 +113,15 @@ namespace ecs_hpp template < typename T, typename... Ts > std::tuple tuple_tail(std::tuple&& t) { return impl::tuple_tail_impl( - std::move(t), - std::make_index_sequence()); + std::make_index_sequence(), + std::move(t)); } template < typename T, typename... Ts > std::tuple tuple_tail(const std::tuple& t) { return impl::tuple_tail_impl( - t, - std::make_index_sequence()); + std::make_index_sequence(), + t); } // @@ -141,47 +130,23 @@ namespace ecs_hpp namespace impl { - template < size_t I, typename V, typename... Ts > - std::enable_if_t - tuple_contains_impl(const std::tuple& t, const V& v) { - (void)t; - (void)v; - return false; - } - - template < size_t I, typename V, typename... Ts > - std::enable_if_t - tuple_contains_impl(const std::tuple& t, const V& v) { - if ( std::get(t) == v ) { - return true; - } - return tuple_contains_impl(t, v); + template < typename V, typename... Ts, std::size_t... Is > + bool tuple_contains_impl( + std::index_sequence, + const std::tuple& t, + const V& v) + { + (void)t; (void)v; + return (... || (std::get(t) == v)); } } template < typename V, typename... Ts > bool tuple_contains(const std::tuple& t, const V& v) { - return impl::tuple_contains_impl<0>(t, v); - } - - // - // tiny_tuple_apply - // - - namespace impl - { - template < typename F, typename Tuple, std::size_t... I > - void tiny_tuple_apply_impl(F&& f, Tuple&& args, std::index_sequence) { - std::forward(f)(std::get(std::forward(args))...); - } - } - - template < typename F, typename Tuple > - void tiny_tuple_apply(F&& f, Tuple&& args) { - impl::tiny_tuple_apply_impl( - std::forward(f), - std::forward(args), - std::make_index_sequence>::value>()); + return impl::tuple_contains_impl( + std::make_index_sequence(), + t, + v); } // @@ -242,7 +207,7 @@ namespace ecs_hpp template < typename Void = void > class type_family_base { static_assert( - std::is_void::value, + std::is_void_v, "unexpected internal error"); protected: static family_id last_id_; @@ -273,24 +238,23 @@ namespace ecs_hpp { namespace detail { - template < typename T - , bool = std::is_unsigned::value - && sizeof(T) <= sizeof(std::size_t) > - struct sparse_unsigned_indexer { + template < typename T > + struct sparse_indexer final { + static_assert(std::is_unsigned_v); + static_assert(sizeof(T) <= sizeof(std::size_t)); std::size_t operator()(const T v) const noexcept { return static_cast(v); } }; - - template < typename T > - struct sparse_unsigned_indexer {}; - - template < typename T > - struct sparse_indexer final - : public sparse_unsigned_indexer {}; } } +// ----------------------------------------------------------------------------- +// +// detail::incremental_locker +// +// ----------------------------------------------------------------------------- + namespace ecs_hpp { namespace detail @@ -354,14 +318,6 @@ namespace ecs_hpp public: using iterator = typename std::vector::iterator; using const_iterator = typename std::vector::const_iterator; - public: - static_assert( - noexcept(std::declval()(std::declval())), - "unsupported sparse_set indexer"); - static_assert( - std::is_nothrow_move_assignable::value && - noexcept(std::declval() == std::declval()), - "unsupported sparse_set value type"); public: iterator begin() noexcept { return dense_.begin(); @@ -424,7 +380,8 @@ namespace ecs_hpp const std::size_t vi = indexer_(v); const std::size_t dense_index = sparse_[vi]; if ( dense_index != dense_.size() - 1 ) { - dense_[dense_index] = std::move(dense_.back()); + using std::swap; + swap(dense_[dense_index], dense_.back()); sparse_[indexer_(dense_[dense_index])] = dense_index; } dense_.pop_back(); @@ -508,10 +465,6 @@ namespace ecs_hpp public: using iterator = typename std::vector::iterator; using const_iterator = typename std::vector::const_iterator; - public: - static_assert( - std::is_nothrow_move_assignable::value, - "unsupported sparse_map value type"); public: iterator begin() noexcept { return keys_.begin(); @@ -589,7 +542,8 @@ namespace ecs_hpp return false; } if ( value_index_p.first != values_.size() - 1 ) { - values_[value_index_p.first] = std::move(values_.back()); + using std::swap; + swap(values_[value_index_p.first], values_.back()); } values_.pop_back(); keys_.unordered_erase(k); @@ -693,7 +647,7 @@ namespace ecs_hpp virtual std::size_t memory_usage() const noexcept = 0; }; - template < typename T, bool E = std::is_empty::value > + template < typename T, bool E = std::is_empty_v > class component_storage final : public component_storage_base { public: component_storage(registry& owner) @@ -751,8 +705,7 @@ namespace ecs_hpp } void clone(entity_id from, entity_id to) override { - const T* c = find(from); - if ( c ) { + if ( const T* c = find(from) ) { assign(to, *c); } } @@ -845,8 +798,7 @@ namespace ecs_hpp } void clone(entity_id from, entity_id to) override { - const T* c = find(from); - if ( c ) { + if ( const T* c = find(from) ) { assign(to, *c); } } @@ -1425,8 +1377,8 @@ namespace ecs_hpp , std::size_t I , std::size_t... Is > void for_joined_components_impl_( - F&& f, - std::index_sequence iseq); + std::index_sequence, + F&& f); template < typename T , typename... Ts @@ -1434,8 +1386,8 @@ namespace ecs_hpp , std::size_t I , std::size_t... Is > void for_joined_components_impl_( - F&& f, - std::index_sequence iseq) const; + std::index_sequence, + F&& f) const; template < typename T , typename... Ts @@ -1561,7 +1513,7 @@ namespace ecs_hpp } inline bool entity::valid() const noexcept { - return detail::as_const(*owner_).valid_entity(id_); + return std::as_const(*owner_).valid_entity(id_); } template < typename T, typename... Args > @@ -1585,7 +1537,7 @@ namespace ecs_hpp template < typename T > bool entity::exists_component() const noexcept { - return detail::as_const(*owner_).exists_component(id_); + return std::as_const(*owner_).exists_component(id_); } inline std::size_t entity::remove_all_components() noexcept { @@ -1599,7 +1551,7 @@ namespace ecs_hpp template < typename T > const T& entity::get_component() const { - return detail::as_const(*owner_).get_component(id_); + return std::as_const(*owner_).get_component(id_); } template < typename T > @@ -1609,7 +1561,7 @@ namespace ecs_hpp template < typename T > const T* entity::find_component() const noexcept { - return detail::as_const(*owner_).find_component(id_); + return std::as_const(*owner_).find_component(id_); } template < typename... Ts > @@ -1619,7 +1571,7 @@ namespace ecs_hpp template < typename... Ts > std::tuple entity::get_components() const { - return detail::as_const(*owner_).get_components(id_); + return std::as_const(*owner_).get_components(id_); } template < typename... Ts > @@ -1629,11 +1581,11 @@ namespace ecs_hpp template < typename... Ts > std::tuple entity::find_components() const noexcept { - return detail::as_const(*owner_).find_components(id_); + return std::as_const(*owner_).find_components(id_); } inline std::size_t entity::component_count() const noexcept { - return detail::as_const(*owner_).entity_component_count(id_); + return std::as_const(*owner_).entity_component_count(id_); } inline bool operator<(const entity& l, const entity& r) noexcept { @@ -1797,7 +1749,7 @@ namespace ecs_hpp template < typename T > const T& component::get() const { - return detail::as_const(owner_).template get_component(); + return std::as_const(owner_).template get_component(); } template < typename T > @@ -1807,7 +1759,7 @@ namespace ecs_hpp template < typename T > const T* component::find() const noexcept { - return detail::as_const(owner_).template find_component(); + return std::as_const(owner_).template find_component(); } template < typename T > @@ -1884,17 +1836,17 @@ namespace ecs_hpp template < typename T > bool const_component::exists() const noexcept { - return detail::as_const(owner_).template exists_component(); + return std::as_const(owner_).template exists_component(); } template < typename T > const T& const_component::get() const { - return detail::as_const(owner_).template get_component(); + return std::as_const(owner_).template get_component(); } template < typename T > const T* const_component::find() const noexcept { - return detail::as_const(owner_).template find_component(); + return std::as_const(owner_).template find_component(); } template < typename T > @@ -1963,7 +1915,7 @@ namespace ecs_hpp template < typename T, typename... Args > void typed_applier_with_args::apply_to_entity(entity& ent, bool override) const { - detail::tiny_tuple_apply([&ent, override](const Args&... args){ + std::apply([&ent, override](const Args&... args){ if ( override || !ent.exists_component() ) { ent.assign_component(args...); } @@ -1972,7 +1924,7 @@ namespace ecs_hpp template < typename T, typename... Args > void typed_applier_with_args::apply_to_component(T& component) const { - detail::tiny_tuple_apply([&component](const Args&... args){ + std::apply([&component](const Args&... args){ component = T(args...); }, args_); } @@ -2319,8 +2271,7 @@ namespace ecs_hpp template < typename T > T& registry::get_component(const uentity& ent) { assert(valid_entity(ent)); - T* component = find_component(ent); - if ( component ) { + if ( T* component = find_component(ent) ) { return *component; } throw std::logic_error("ecs_hpp::registry (component not found)"); @@ -2329,8 +2280,7 @@ namespace ecs_hpp template < typename T > const T& registry::get_component(const const_uentity& ent) const { assert(valid_entity(ent)); - const T* component = find_component(ent); - if ( component ) { + if ( const T* component = find_component(ent) ) { return *component; } throw std::logic_error("ecs_hpp::registry (component not found)"); @@ -2423,8 +2373,7 @@ namespace ecs_hpp template < typename T, typename F > void registry::for_each_component(F&& f) { - detail::component_storage* storage = find_storage_(); - if ( storage ) { + if ( detail::component_storage* storage = find_storage_() ) { storage->for_each_component([this, &f](const entity_id e, T& t){ f(uentity{*this, e}, t); }); @@ -2433,8 +2382,7 @@ namespace ecs_hpp template < typename T, typename F > void registry::for_each_component(F&& f) const { - const detail::component_storage* storage = find_storage_(); - if ( storage ) { + if ( const detail::component_storage* storage = find_storage_() ) { storage->for_each_component([this, &f](const entity_id e, const T& t){ f(const_uentity{*this, e}, t); }); @@ -2444,15 +2392,15 @@ namespace ecs_hpp template < typename... Ts, typename F > void registry::for_joined_components(F&& f) { for_joined_components_impl_( - std::forward(f), - std::make_index_sequence()); + std::make_index_sequence(), + std::forward(f)); } template < typename... Ts, typename F > void registry::for_joined_components(F&& f) const { for_joined_components_impl_( - std::forward(f), - std::make_index_sequence()); + std::make_index_sequence(), + std::forward(f)); } template < typename T, typename... Args > @@ -2536,8 +2484,7 @@ namespace ecs_hpp template < typename T > detail::component_storage& registry::get_or_create_storage_() { - detail::component_storage* storage = find_storage_(); - if ( storage ) { + if ( detail::component_storage* storage = find_storage_() ) { return *storage; } const auto family = detail::type_family::id(); @@ -2554,16 +2501,16 @@ namespace ecs_hpp , std::size_t I , std::size_t... Is > void registry::for_joined_components_impl_( - F&& f, - std::index_sequence iseq) + std::index_sequence, + F&& f) { - (void)iseq; const auto ss = std::make_tuple(find_storage_()...); - if ( !detail::tuple_contains(ss, nullptr) ) { - for_each_component([this, &f, &ss](const uentity& e, T& t) { - for_joined_components_impl_(e, f, ss, t); - }); + if ( detail::tuple_contains(ss, nullptr) ) { + return; } + for_each_component([this, &f, &ss](const uentity& e, T& t) { + for_joined_components_impl_(e, f, ss, t); + }); } template < typename T @@ -2572,16 +2519,16 @@ namespace ecs_hpp , std::size_t I , std::size_t... Is > void registry::for_joined_components_impl_( - F&& f, - std::index_sequence iseq) const + std::index_sequence, + F&& f) const { - (void)iseq; const auto ss = std::make_tuple(find_storage_()...); - if ( !detail::tuple_contains(ss, nullptr) ) { - for_each_component([this, &f, &ss](const const_uentity& e, const T& t) { - detail::as_const(*this).for_joined_components_impl_(e, f, ss, t); - }); + if ( detail::tuple_contains(ss, nullptr) ) { + return; } + for_each_component([this, &f, &ss](const const_uentity& e, const T& t) { + std::as_const(*this).for_joined_components_impl_(e, f, ss, t); + }); } template < typename T @@ -2595,8 +2542,7 @@ namespace ecs_hpp const Ss& ss, Cs&... cs) { - T* c = std::get<0>(ss)->find(e); - if ( c ) { + if ( T* c = std::get<0>(ss)->find(e) ) { for_joined_components_impl_( e, f, @@ -2617,8 +2563,7 @@ namespace ecs_hpp const Ss& ss, const Cs&... cs) const { - const T* c = std::get<0>(ss)->find(e); - if ( c ) { + if ( const T* c = std::get<0>(ss)->find(e) ) { for_joined_components_impl_( e, f, diff --git a/untests/ecs_tests.cpp b/untests/ecs_tests.cpp index 321fa83..bc49648 100644 --- a/untests/ecs_tests.cpp +++ b/untests/ecs_tests.cpp @@ -29,7 +29,7 @@ namespace struct movable_c { }; - static_assert(std::is_empty::value, "!!!"); + static_assert(std::is_empty_v, "!!!"); bool operator==(const position_c& l, const position_c& r) noexcept { return l.x == r.x @@ -203,9 +203,9 @@ TEST_CASE("detail") { REQUIRE_FALSE(m.size()); REQUIRE_FALSE(m.has(42u)); REQUIRE_THROWS(m.get(42u)); - REQUIRE_THROWS(as_const(m).get(42u)); + REQUIRE_THROWS(std::as_const(m).get(42u)); REQUIRE_FALSE(m.find(42u)); - REQUIRE_FALSE(as_const(m).find(42u)); + REQUIRE_FALSE(std::as_const(m).find(42u)); { obj_t o{21u}; @@ -233,20 +233,20 @@ TEST_CASE("detail") { REQUIRE(m.get(21u).x == 21u); REQUIRE(m.get(42u).x == 42u); REQUIRE(m.get(84u).x == 84u); - REQUIRE(as_const(m).get(84u).x == 84u); + REQUIRE(std::as_const(m).get(84u).x == 84u); REQUIRE_THROWS(m.get(11u)); REQUIRE_THROWS(m.get(25u)); REQUIRE_THROWS(m.get(99u)); - REQUIRE_THROWS(as_const(m).get(99u)); + REQUIRE_THROWS(std::as_const(m).get(99u)); REQUIRE(m.find(21u)->x == 21u); REQUIRE(m.find(42u)->x == 42u); REQUIRE(m.find(84u)->x == 84u); - REQUIRE(as_const(m).find(84u)->x == 84u); + REQUIRE(std::as_const(m).find(84u)->x == 84u); REQUIRE_FALSE(m.find(11u)); REQUIRE_FALSE(m.find(25u)); REQUIRE_FALSE(m.find(99u)); - REQUIRE_FALSE(as_const(m).find(99u)); + REQUIRE_FALSE(std::as_const(m).find(99u)); REQUIRE(m.unordered_erase(42u)); REQUIRE_FALSE(m.unordered_erase(42u)); @@ -527,43 +527,43 @@ TEST_CASE("registry") { ecs::const_component c2 = w.wrap_component(e1); REQUIRE_FALSE(c1); - REQUIRE_FALSE(as_const(c1)); + REQUIRE_FALSE(std::as_const(c1)); REQUIRE_FALSE(c2); - REQUIRE_FALSE(as_const(c2)); + REQUIRE_FALSE(std::as_const(c2)); REQUIRE_THROWS_AS(*c1, std::logic_error); - REQUIRE_THROWS_AS(*as_const(c1), std::logic_error); + REQUIRE_THROWS_AS(*std::as_const(c1), std::logic_error); REQUIRE_THROWS_AS(*c2, std::logic_error); - REQUIRE_THROWS_AS(*as_const(c2), std::logic_error); + REQUIRE_THROWS_AS(*std::as_const(c2), std::logic_error); c1.assign(1,2); REQUIRE(c1); - REQUIRE(as_const(c1)); + REQUIRE(std::as_const(c1)); REQUIRE(c2); - REQUIRE(as_const(c2)); + REQUIRE(std::as_const(c2)); REQUIRE(*c1 == position_c(1,2)); - REQUIRE(*as_const(c1) == position_c(1,2)); + REQUIRE(*std::as_const(c1) == position_c(1,2)); REQUIRE(*c2 == position_c(1,2)); - REQUIRE(*as_const(c2) == position_c(1,2)); + REQUIRE(*std::as_const(c2) == position_c(1,2)); REQUIRE(c1->x == 1); REQUIRE(c1->y == 2); - REQUIRE(as_const(c1)->x == 1); - REQUIRE(as_const(c1)->y == 2); + REQUIRE(std::as_const(c1)->x == 1); + REQUIRE(std::as_const(c1)->y == 2); REQUIRE(c2->x == 1); REQUIRE(c2->y == 2); - REQUIRE(as_const(c2)->x == 1); - REQUIRE(as_const(c2)->y == 2); + REQUIRE(std::as_const(c2)->x == 1); + REQUIRE(std::as_const(c2)->y == 2); c1.remove(); REQUIRE_FALSE(c1); - REQUIRE_FALSE(as_const(c1)); + REQUIRE_FALSE(std::as_const(c1)); REQUIRE_FALSE(c2); - REQUIRE_FALSE(as_const(c2)); + REQUIRE_FALSE(std::as_const(c2)); } { ecs::registry w; From 89611dbf027653419296591056fcaced257fdf8f Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Tue, 15 Oct 2019 09:39:21 +0700 Subject: [PATCH 2/3] add filter and require options to for_each --- headers/ecs.hpp/ecs.hpp | 171 ++++++++++++++++++++++++++++---------- untests/ecs_tests.cpp | 179 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 304 insertions(+), 46 deletions(-) diff --git a/headers/ecs.hpp/ecs.hpp b/headers/ecs.hpp/ecs.hpp index 735ea10..1f0b32f 100644 --- a/headers/ecs.hpp/ecs.hpp +++ b/headers/ecs.hpp/ecs.hpp @@ -42,6 +42,21 @@ namespace ecs_hpp class system; class registry; + template < typename... Ts > + class filter_any; + template < typename... Ts > + class filter_all; + + template < typename... Ts > + class require_any; + template < typename... Ts > + class require_all; + + template < typename... Ts > + using filter = filter_any; + template < typename... Ts > + using require = require_all; + class entity_filler; class registry_filler; @@ -656,11 +671,11 @@ namespace ecs_hpp template < typename... Args > T& assign(entity_id id, Args&&... args) { if ( T* value = components_.find(id) ) { - *value = T(std::forward(args)...); + *value = T{std::forward(args)...}; return *value; } assert(!components_locker_.is_locked()); - return *components_.insert(id, T(std::forward(args)...)).first; + return *components_.insert(id, T{std::forward(args)...}).first; } template < typename... Args > @@ -669,7 +684,7 @@ namespace ecs_hpp return *value; } assert(!components_locker_.is_locked()); - return *components_.insert(id, T(std::forward(args)...)).first; + return *components_.insert(id, T{std::forward(args)...}).first; } bool exists(entity_id id) const noexcept { @@ -1330,20 +1345,20 @@ namespace ecs_hpp std::size_t entity_count() const noexcept; std::size_t entity_component_count(const const_uentity& ent) const noexcept; - template < typename F > - void for_each_entity(F&& f); - template < typename F > - void for_each_entity(F&& f) const; + template < typename F, typename... Opts > + void for_each_entity(F&& f, Opts&&... opts); + template < typename F, typename... Opts > + void for_each_entity(F&& f, Opts&&... opts) const; - template < typename T, typename F > - void for_each_component(F&& f); - template < typename T, typename F > - void for_each_component(F&& f) const; + template < typename T, typename F, typename... Opts > + void for_each_component(F&& f, Opts&&... opts); + template < typename T, typename F, typename... Opts > + void for_each_component(F&& f, Opts&&... opts) const; - template < typename... Ts, typename F > - void for_joined_components(F&& f); - template < typename... Ts, typename F > - void for_joined_components(F&& f) const; + template < typename... Ts, typename F, typename... Opts > + void for_joined_components(F&& f, Opts&&... opts); + template < typename... Ts, typename F, typename... Opts > + void for_joined_components(F&& f, Opts&&... opts) const; template < typename T, typename... Args > void add_system(priority_t priority, Args&&... args); @@ -1374,20 +1389,24 @@ namespace ecs_hpp template < typename T , typename... Ts , typename F + , typename... Opts , std::size_t I , std::size_t... Is > void for_joined_components_impl_( std::index_sequence, - F&& f); + F&& f, + Opts&&... opts); template < typename T , typename... Ts , typename F + , typename... Opts , std::size_t I , std::size_t... Is > void for_joined_components_impl_( std::index_sequence, - F&& f) const; + F&& f, + Opts&&... opts) const; template < typename T , typename... Ts @@ -1438,6 +1457,56 @@ namespace ecs_hpp }; } +// ----------------------------------------------------------------------------- +// +// filter +// +// ----------------------------------------------------------------------------- + +namespace ecs_hpp +{ + template < typename... Ts > + class filter_any final { + public: + bool operator()(const const_entity& e) const noexcept { + return !(... || e.exists_component()); + } + }; + + template < typename... Ts > + class filter_all final { + public: + bool operator()(const const_entity& e) const noexcept { + return !(... && e.exists_component()); + } + }; +} + +// ----------------------------------------------------------------------------- +// +// require +// +// ----------------------------------------------------------------------------- + +namespace ecs_hpp +{ + template < typename... Ts > + class require_any final { + public: + bool operator()(const const_entity& e) const noexcept { + return (... || e.exists_component()); + } + }; + + template < typename... Ts > + class require_all final { + public: + bool operator()(const const_entity& e) const noexcept { + return (... && e.exists_component()); + } + }; +} + // ----------------------------------------------------------------------------- // // fillers @@ -1925,7 +1994,7 @@ namespace ecs_hpp template < typename T, typename... Args > void typed_applier_with_args::apply_to_component(T& component) const { std::apply([&component](const Args&... args){ - component = T(args...); + component = T{args...}; }, args_); } } @@ -2355,52 +2424,62 @@ namespace ecs_hpp return component_count; } - template < typename F > - void registry::for_each_entity(F&& f) { + template < typename F, typename... Opts > + void registry::for_each_entity(F&& f, Opts&&... opts) { detail::incremental_lock_guard lock(entity_ids_locker_); - for ( const auto id : entity_ids_ ) { - f({*this, id}); + for ( const auto e : entity_ids_ ) { + if ( uentity ent{*this, e}; (... && opts(ent)) ) { + f(ent); + } } } - template < typename F > - void registry::for_each_entity(F&& f) const { + template < typename F, typename... Opts > + void registry::for_each_entity(F&& f, Opts&&... opts) const { detail::incremental_lock_guard lock(entity_ids_locker_); - for ( const auto id : entity_ids_ ) { - f({*this, id}); + for ( const auto e : entity_ids_ ) { + if ( const_uentity ent{*this, e}; (... && opts(ent)) ) { + f(ent); + } } } - template < typename T, typename F > - void registry::for_each_component(F&& f) { + template < typename T, typename F, typename... Opts > + void registry::for_each_component(F&& f, Opts&&... opts) { if ( detail::component_storage* storage = find_storage_() ) { - storage->for_each_component([this, &f](const entity_id e, T& t){ - f(uentity{*this, e}, t); + storage->for_each_component([this, &f, &opts...](const entity_id e, T& t){ + if ( uentity ent{*this, e}; (... && opts(ent)) ) { + f(ent, t); + } }); } } - template < typename T, typename F > - void registry::for_each_component(F&& f) const { + template < typename T, typename F, typename... Opts > + void registry::for_each_component(F&& f, Opts&&... opts) const { if ( const detail::component_storage* storage = find_storage_() ) { - storage->for_each_component([this, &f](const entity_id e, const T& t){ - f(const_uentity{*this, e}, t); + storage->for_each_component([this, &f, &opts...](const entity_id e, const T& t){ + if ( const_uentity ent{*this, e}; (... && opts(ent)) ) { + f(ent, t); + } }); } } - template < typename... Ts, typename F > - void registry::for_joined_components(F&& f) { + template < typename... Ts, typename F, typename... Opts > + void registry::for_joined_components(F&& f, Opts&&... opts) { for_joined_components_impl_( std::make_index_sequence(), - std::forward(f)); + std::forward(f), + std::forward(opts)...); } - template < typename... Ts, typename F > - void registry::for_joined_components(F&& f) const { + template < typename... Ts, typename F, typename... Opts > + void registry::for_joined_components(F&& f, Opts&&... opts) const { for_joined_components_impl_( std::make_index_sequence(), - std::forward(f)); + std::forward(f), + std::forward(opts)...); } template < typename T, typename... Args > @@ -2498,11 +2577,13 @@ namespace ecs_hpp template < typename T , typename... Ts , typename F + , typename... Opts , std::size_t I , std::size_t... Is > void registry::for_joined_components_impl_( std::index_sequence, - F&& f) + F&& f, + Opts&&... opts) { const auto ss = std::make_tuple(find_storage_()...); if ( detail::tuple_contains(ss, nullptr) ) { @@ -2510,17 +2591,19 @@ namespace ecs_hpp } for_each_component([this, &f, &ss](const uentity& e, T& t) { for_joined_components_impl_(e, f, ss, t); - }); + }, std::forward(opts)...); } template < typename T , typename... Ts , typename F + , typename... Opts , std::size_t I , std::size_t... Is > void registry::for_joined_components_impl_( std::index_sequence, - F&& f) const + F&& f, + Opts&&... opts) const { const auto ss = std::make_tuple(find_storage_()...); if ( detail::tuple_contains(ss, nullptr) ) { @@ -2528,7 +2611,7 @@ namespace ecs_hpp } for_each_component([this, &f, &ss](const const_uentity& e, const T& t) { std::as_const(*this).for_joined_components_impl_(e, f, ss, t); - }); + }, std::forward(opts)...); } template < typename T diff --git a/untests/ecs_tests.cpp b/untests/ecs_tests.cpp index bc49648..7c757fd 100644 --- a/untests/ecs_tests.cpp +++ b/untests/ecs_tests.cpp @@ -27,9 +27,11 @@ namespace velocity_c(int nx, int ny) : x(nx), y(ny) {} }; - struct movable_c { - }; + struct movable_c{}; + struct disabled_c{}; + static_assert(std::is_empty_v, "!!!"); + static_assert(std::is_empty_v, "!!!"); bool operator==(const position_c& l, const position_c& r) noexcept { return l.x == r.x @@ -1174,6 +1176,179 @@ TEST_CASE("registry") { }); } } + SECTION("options") { + { + ecs::registry w; + + auto e = w.create_entity(); + + REQUIRE(ecs::filter<>{}(e)); + REQUIRE(ecs::filter{}(e)); + REQUIRE(ecs::filter{}(e)); + REQUIRE(ecs::filter{}(e)); + + REQUIRE(ecs::filter_any<>{}(e)); + REQUIRE(ecs::filter_any{}(e)); + REQUIRE(ecs::filter_any{}(e)); + REQUIRE(ecs::filter_any{}(e)); + + REQUIRE_FALSE(ecs::filter_all<>{}(e)); + REQUIRE(ecs::filter_all{}(e)); + REQUIRE(ecs::filter_all{}(e)); + REQUIRE(ecs::filter_all{}(e)); + + e.assign_component(); + + REQUIRE(ecs::filter<>{}(e)); + REQUIRE_FALSE(ecs::filter{}(e)); + REQUIRE(ecs::filter{}(e)); + REQUIRE_FALSE(ecs::filter{}(e)); + + REQUIRE(ecs::filter_any<>{}(e)); + REQUIRE_FALSE(ecs::filter_any{}(e)); + REQUIRE(ecs::filter_any{}(e)); + REQUIRE_FALSE(ecs::filter_any{}(e)); + + REQUIRE_FALSE(ecs::filter_all<>{}(e)); + REQUIRE_FALSE(ecs::filter_all{}(e)); + REQUIRE(ecs::filter_all{}(e)); + REQUIRE(ecs::filter_all{}(e)); + + e.assign_component(); + + REQUIRE(ecs::filter<>{}(e)); + REQUIRE_FALSE(ecs::filter{}(e)); + REQUIRE_FALSE(ecs::filter{}(e)); + REQUIRE_FALSE(ecs::filter{}(e)); + + REQUIRE(ecs::filter_any<>{}(e)); + REQUIRE_FALSE(ecs::filter_any{}(e)); + REQUIRE_FALSE(ecs::filter_any{}(e)); + REQUIRE_FALSE(ecs::filter_any{}(e)); + + REQUIRE_FALSE(ecs::filter_all<>{}(e)); + REQUIRE_FALSE(ecs::filter_all{}(e)); + REQUIRE_FALSE(ecs::filter_all{}(e)); + REQUIRE_FALSE(ecs::filter_all{}(e)); + } + { + ecs::registry w; + + auto e = w.create_entity(); + + REQUIRE(ecs::require<>{}(e)); + REQUIRE_FALSE(ecs::require{}(e)); + REQUIRE_FALSE(ecs::require{}(e)); + REQUIRE_FALSE(ecs::require{}(e)); + + REQUIRE_FALSE(ecs::require_any<>{}(e)); + REQUIRE_FALSE(ecs::require_any{}(e)); + REQUIRE_FALSE(ecs::require_any{}(e)); + REQUIRE_FALSE(ecs::require_any{}(e)); + + REQUIRE(ecs::require_all<>{}(e)); + REQUIRE_FALSE(ecs::require_all{}(e)); + REQUIRE_FALSE(ecs::require_all{}(e)); + REQUIRE_FALSE(ecs::require_all{}(e)); + + e.assign_component(); + + REQUIRE(ecs::require<>{}(e)); + REQUIRE(ecs::require{}(e)); + REQUIRE_FALSE(ecs::require{}(e)); + REQUIRE_FALSE(ecs::require{}(e)); + + REQUIRE_FALSE(ecs::require_any<>{}(e)); + REQUIRE(ecs::require_any{}(e)); + REQUIRE_FALSE(ecs::require_any{}(e)); + REQUIRE(ecs::require_any{}(e)); + + REQUIRE(ecs::require_all<>{}(e)); + REQUIRE(ecs::require_all{}(e)); + REQUIRE_FALSE(ecs::require_all{}(e)); + REQUIRE_FALSE(ecs::require_all{}(e)); + + e.assign_component(); + + REQUIRE(ecs::require<>{}(e)); + REQUIRE(ecs::require{}(e)); + REQUIRE(ecs::require{}(e)); + REQUIRE(ecs::require{}(e)); + + REQUIRE_FALSE(ecs::require_any<>{}(e)); + REQUIRE(ecs::require_any{}(e)); + REQUIRE(ecs::require_any{}(e)); + REQUIRE(ecs::require_any{}(e)); + + REQUIRE(ecs::require_all<>{}(e)); + REQUIRE(ecs::require_all{}(e)); + REQUIRE(ecs::require_all{}(e)); + REQUIRE(ecs::require_all{}(e)); + } + { + ecs::registry w; + + auto e1 = w.create_entity(); + e1.assign_component(); + e1.assign_component(0,0); + e1.assign_component(1,2); + + auto e2 = w.create_entity(); + e2.assign_component(0,0); + e2.assign_component(1,2); + + w.for_each_component([ + ](ecs::entity, position_c& p){ + p = position_c{5,5}; + }, ecs::require{}); + + REQUIRE(e1.get_component() == position_c(5,5)); + REQUIRE(e2.get_component() == position_c(0,0)); + + w.for_joined_components([ + ](ecs::entity, position_c& p, const velocity_c& v){ + p.x += v.x; + p.y += v.y; + }, ecs::filter{}); + + REQUIRE(e1.get_component() == position_c(5,5)); + REQUIRE(e2.get_component() == position_c(1,2)); + + e1.assign_component(); + e2.assign_component(); + + w.for_joined_components([ + ](ecs::entity, position_c& p, const velocity_c& v){ + p.x += v.x; + p.y += v.y; + }, ecs::require{}, ecs::filter{}); + + REQUIRE(e1.get_component() == position_c(5,5)); + REQUIRE(e2.get_component() == position_c(2,4)); + } + { + ecs::registry w; + + auto e1 = w.create_entity(); + e1.assign_component(0,0); + e1.assign_component(1,2); + + auto e2 = w.create_entity(); + e2.assign_component(); + e2.assign_component(0,0); + e2.assign_component(1,2); + + w.for_each_entity([](ecs::entity e){ + position_c& p = e.get_component(); + const velocity_c& v = e.get_component(); + p.x += v.x; + p.y += v.y; + }, ecs::filter{}, ecs::require{}); + + REQUIRE(e1.get_component() == position_c(1,2)); + REQUIRE(e2.get_component() == position_c(0,0)); + } + } SECTION("systems") { { class movement_system : public ecs::system { From 57f0821b0effb6a41582de0dd9d46b6075fd5c2d Mon Sep 17 00:00:00 2001 From: BlackMATov Date: Tue, 15 Oct 2019 10:04:44 +0700 Subject: [PATCH 3/3] update readme example --- README.md | 68 +++++++++++++++++++++++++------------------ untests/ecs_tests.cpp | 64 ++++++++++++++++++++++------------------ 2 files changed, 74 insertions(+), 58 deletions(-) diff --git a/README.md b/README.md index 4b4db71..b198ae1 100644 --- a/README.md +++ b/README.md @@ -41,61 +41,71 @@ target_link_libraries(your_project_target ecs.hpp) ## Basic usage ```cpp -struct position_component { - float x; - float y; - position_component(float nx, float ny) - : x(nx), y(ny) {} + +#include +namespace ecs = ecs_hpp; + +struct movable {}; +struct disabled {}; + +struct position { + float x{}; + float y{}; }; -struct velocity_component { - float dx; - float dy; - velocity_component(float ndx, float ndy) - : dx(ndx), dy(ndy) {} +struct velocity { + float dx{}; + float dy{}; }; -class movement_system : public ecs_hpp::system { +class movement_system : public ecs::system { public: - void process(ecs_hpp::registry& owner) override { + void process(ecs::registry& owner) override { owner.for_joined_components< - position_component, - velocity_component - >([](const ecs_hpp::entity& e, position_component& p, const velocity_component& v) { + position, + velocity + >([](ecs::entity, position& p, const velocity& v) { p.x += v.dx; p.y += v.dy; - }); + }, ecs::require{}, ecs::filter{}); } }; -class gravity_system : public ecs_hpp::system { +class gravity_system : public ecs::system { public: gravity_system(float gravity) : gravity_(gravity) {} - void process(ecs_hpp::registry& owner) override { + void process(ecs::registry& owner) override { owner.for_each_component< - velocity_component - >([this](const ecs_hpp::entity& e, velocity_component& v) { + velocity + >([this](ecs::entity e, velocity& v) { v.dx += gravity_; v.dy += gravity_; - }); + }, ecs::filter{}); } private: - float gravity_; + float gravity_{}; }; -ecs_hpp::registry world; -world.add_system(0); -world.add_system(1, 9.8f); +ecs::registry world; + +ecs::registry_filler(world) + .system(0) + .system(1, 9.8f); auto entity_one = world.create_entity(); -world.assign_component(entity_one, 4.f, 2.f); -world.assign_component(entity_one, 10.f, 20.f); +ecs::entity_filler(entity_one) + .component() + .component(4.f, 2.f) + .component(10.f, 20.f); auto entity_two = world.create_entity(); -entity_two.assign_component(4.f, 2.f); -entity_two.assign_component(10.f, 20.f); +ecs::entity_filler(entity_two) + .component() + .component() + .component(4.f, 2.f) + .component(10.f, 20.f); world.process_all_systems(); ``` diff --git a/untests/ecs_tests.cpp b/untests/ecs_tests.cpp index 7c757fd..2e99802 100644 --- a/untests/ecs_tests.cpp +++ b/untests/ecs_tests.cpp @@ -1571,61 +1571,67 @@ TEST_CASE("registry") { } TEST_CASE("example") { - struct position_component { - float x; - float y; - position_component(float nx, float ny) - : x(nx), y(ny) {} + struct movable {}; + struct disabled {}; + + struct position { + float x{}; + float y{}; }; - struct velocity_component { - float dx; - float dy; - velocity_component(float ndx, float ndy) - : dx(ndx), dy(ndy) {} + struct velocity { + float dx{}; + float dy{}; }; - class movement_system : public ecs_hpp::system { + class movement_system : public ecs::system { public: - void process(ecs_hpp::registry& owner) override { + void process(ecs::registry& owner) override { owner.for_joined_components< - position_component, - velocity_component - >([](const ecs_hpp::entity&, position_component& p, const velocity_component& v) { + position, + velocity + >([](ecs::entity, position& p, const velocity& v) { p.x += v.dx; p.y += v.dy; - }); + }, ecs::require{}, ecs::filter{}); } }; - class gravity_system : public ecs_hpp::system { + class gravity_system : public ecs::system { public: gravity_system(float gravity) : gravity_(gravity) {} - void process(ecs_hpp::registry& owner) override { + void process(ecs::registry& owner) override { owner.for_each_component< - velocity_component - >([this](const ecs_hpp::entity&, velocity_component& v) { + velocity + >([this](ecs::entity, velocity& v) { v.dx += gravity_; v.dy += gravity_; - }); + }, ecs::filter{}); } private: - float gravity_; + float gravity_{}; }; - ecs_hpp::registry world; - world.add_system(0); - world.add_system(1, 9.8f); + ecs::registry world; + + ecs::registry_filler(world) + .system(0) + .system(1, 9.8f); auto entity_one = world.create_entity(); - world.assign_component(entity_one, 4.f, 2.f); - world.assign_component(entity_one, 10.f, 20.f); + ecs::entity_filler(entity_one) + .component() + .component(4.f, 2.f) + .component(10.f, 20.f); auto entity_two = world.create_entity(); - entity_two.assign_component(4.f, 2.f); - entity_two.assign_component(10.f, 20.f); + ecs::entity_filler(entity_two) + .component() + .component() + .component(4.f, 2.f) + .component(10.f, 20.f); world.process_all_systems(); }