option combinator improvements

This commit is contained in:
2019-10-15 15:24:13 +07:00
parent 1f5d08a675
commit 6b34c00b34
3 changed files with 221 additions and 114 deletions

View File

@@ -67,7 +67,7 @@ public:
>([](ecs::entity, position& p, const velocity& v) { >([](ecs::entity, position& p, const velocity& v) {
p.x += v.dx; p.x += v.dx;
p.y += v.dy; p.y += v.dy;
}, ecs::require<movable>{}, ecs::filter<disabled>{}); }, ecs::exists<movable>{} && !ecs::exists<disabled>{});
} }
}; };
@@ -82,7 +82,7 @@ public:
>([this](ecs::entity e, velocity& v) { >([this](ecs::entity e, velocity& v) {
v.dx += gravity_; v.dx += gravity_;
v.dy += gravity_; v.dy += gravity_;
}, ecs::filter<disabled>{}); }, !ecs::exists<disabled>{});
} }
private: private:
float gravity_{}; float gravity_{};

View File

@@ -42,24 +42,26 @@ namespace ecs_hpp
class system; class system;
class registry; class registry;
template < typename T >
class exists;
template < typename... Ts > template < typename... Ts >
class filter_any; class exists_any;
template < typename... Ts > template < typename... Ts >
class filter_all; class exists_all;
template < typename T >
class option_neg;
template < typename... Ts > template < typename... Ts >
class require_any; class option_conj;
template < typename... Ts > template < typename... Ts >
class require_all; class option_disj;
template < typename... Ts >
using filter = filter_any<Ts...>;
template < typename... Ts >
using require = require_all<Ts...>;
class entity_filler; class entity_filler;
class registry_filler; class registry_filler;
}
namespace ecs_hpp
{
using family_id = std::uint16_t; using family_id = std::uint16_t;
using entity_id = std::uint32_t; using entity_id = std::uint32_t;
using priority_t = std::int32_t; using priority_t = std::int32_t;
@@ -1461,52 +1463,149 @@ namespace ecs_hpp
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// //
// filter // options
// //
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
namespace ecs_hpp namespace ecs_hpp
{ {
//
// traits
//
template < typename T >
struct option {
static constexpr bool instance = false;
};
template < typename T >
struct option<exists<T>> {
static constexpr bool instance = true;
};
template < typename... Ts > template < typename... Ts >
class filter_any final { struct option<exists_any<Ts...>> {
static constexpr bool instance = true;
};
template < typename... Ts >
struct option<exists_all<Ts...>> {
static constexpr bool instance = true;
};
template < typename T >
struct option<option_neg<T>> {
static constexpr bool instance = true;
};
template < typename... Ts >
struct option<option_conj<Ts...>> {
static constexpr bool instance = true;
};
template < typename... Ts >
struct option<option_disj<Ts...>> {
static constexpr bool instance = true;
};
//
// options
//
template < typename T >
class exists final {
public: public:
bool operator()(const const_entity& e) const noexcept { bool operator()(const const_entity& e) const {
return !(... || e.exists_component<Ts>()); return e.exists_component<T>();
} }
}; };
template < typename... Ts > template < typename... Ts >
class filter_all final { class exists_any final {
public: public:
bool operator()(const const_entity& e) const noexcept { bool operator()(const const_entity& e) const {
return !(... && e.exists_component<Ts>());
}
};
}
// -----------------------------------------------------------------------------
//
// require
//
// -----------------------------------------------------------------------------
namespace ecs_hpp
{
template < typename... Ts >
class require_any final {
public:
bool operator()(const const_entity& e) const noexcept {
return (... || e.exists_component<Ts>()); return (... || e.exists_component<Ts>());
} }
}; };
template < typename... Ts > template < typename... Ts >
class require_all final { class exists_all final {
public: public:
bool operator()(const const_entity& e) const noexcept { bool operator()(const const_entity& e) const {
return (... && e.exists_component<Ts>()); return (... && e.exists_component<Ts>());
} }
}; };
//
// combinators
//
template < typename T >
class option_neg final {
public:
option_neg(T opt)
: opt_(std::move(opt)) {}
bool operator()(const const_entity& e) const {
return !opt_(e);
}
private:
T opt_;
};
template < typename... Ts >
class option_conj final {
public:
option_conj(Ts... opts)
: opts_(std::make_tuple(std::move(opts)...)) {}
bool operator()(const const_entity& e) const {
return std::apply([&e](auto&&... opts){
return (... && opts(e));
}, opts_);
}
private:
std::tuple<Ts...> opts_;
};
template < typename... Ts >
class option_disj final {
public:
option_disj(Ts... opts)
: opts_(std::make_tuple(std::move(opts)...)) {}
bool operator()(const const_entity& e) const {
return std::apply([&e](auto&&... opts){
return (... || opts(e));
}, opts_);
}
private:
std::tuple<Ts...> opts_;
};
//
// operators
//
template < typename A
, typename = std::enable_if_t<option<A>::instance>>
option_neg<std::decay_t<A>> operator!(A&& a) {
return {std::forward<A>(a)};
}
template < typename A, typename B
, typename = std::enable_if_t<option<A>::instance>
, typename = std::enable_if_t<option<B>::instance> >
option_conj<std::decay_t<A>, std::decay_t<B>> operator&&(A&& a, B&& b) {
return {std::forward<A>(a), std::forward<B>(b)};
}
template < typename A, typename B
, typename = std::enable_if_t<option<A>::instance>
, typename = std::enable_if_t<option<B>::instance> >
option_disj<std::decay_t<A>, std::decay_t<B>> operator||(A&& a, B&& b) {
return {std::forward<A>(a), std::forward<B>(b)};
}
} }
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------

View File

@@ -1191,108 +1191,96 @@ TEST_CASE("registry") {
auto e = w.create_entity(); auto e = w.create_entity();
REQUIRE(ecs::filter<>{}(e)); REQUIRE((!ecs::exists<position_c>{})(e));
REQUIRE(ecs::filter<position_c>{}(e)); REQUIRE((!ecs::exists<velocity_c>{})(e));
REQUIRE(ecs::filter<velocity_c>{}(e));
REQUIRE(ecs::filter<position_c, velocity_c>{}(e));
REQUIRE(ecs::filter_any<>{}(e)); REQUIRE((!ecs::exists_any<>{})(e));
REQUIRE(ecs::filter_any<position_c>{}(e)); REQUIRE((!ecs::exists_any<position_c>{})(e));
REQUIRE(ecs::filter_any<velocity_c>{}(e)); REQUIRE((!ecs::exists_any<velocity_c>{})(e));
REQUIRE(ecs::filter_any<position_c, velocity_c>{}(e)); REQUIRE((!ecs::exists_any<position_c, velocity_c>{})(e));
REQUIRE_FALSE(ecs::filter_all<>{}(e)); REQUIRE_FALSE((!ecs::exists_all<>{})(e));
REQUIRE(ecs::filter_all<position_c>{}(e)); REQUIRE((!ecs::exists_all<position_c>{})(e));
REQUIRE(ecs::filter_all<velocity_c>{}(e)); REQUIRE((!ecs::exists_all<velocity_c>{})(e));
REQUIRE(ecs::filter_all<position_c, velocity_c>{}(e)); REQUIRE((!ecs::exists_all<position_c, velocity_c>{})(e));
e.assign_component<position_c>(); e.assign_component<position_c>();
REQUIRE(ecs::filter<>{}(e)); REQUIRE_FALSE((!ecs::exists<position_c>{})(e));
REQUIRE_FALSE(ecs::filter<position_c>{}(e)); REQUIRE((!ecs::exists<velocity_c>{})(e));
REQUIRE(ecs::filter<velocity_c>{}(e));
REQUIRE_FALSE(ecs::filter<position_c, velocity_c>{}(e));
REQUIRE(ecs::filter_any<>{}(e)); REQUIRE((!ecs::exists_any<>{})(e));
REQUIRE_FALSE(ecs::filter_any<position_c>{}(e)); REQUIRE_FALSE((!ecs::exists_any<position_c>{})(e));
REQUIRE(ecs::filter_any<velocity_c>{}(e)); REQUIRE((!ecs::exists_any<velocity_c>{})(e));
REQUIRE_FALSE(ecs::filter_any<position_c, velocity_c>{}(e)); REQUIRE_FALSE((!ecs::exists_any<position_c, velocity_c>{})(e));
REQUIRE_FALSE(ecs::filter_all<>{}(e)); REQUIRE_FALSE((!ecs::exists_all<>{})(e));
REQUIRE_FALSE(ecs::filter_all<position_c>{}(e)); REQUIRE_FALSE((!ecs::exists_all<position_c>{})(e));
REQUIRE(ecs::filter_all<velocity_c>{}(e)); REQUIRE((!ecs::exists_all<velocity_c>{})(e));
REQUIRE(ecs::filter_all<position_c, velocity_c>{}(e)); REQUIRE((!ecs::exists_all<position_c, velocity_c>{})(e));
e.assign_component<velocity_c>(); e.assign_component<velocity_c>();
REQUIRE(ecs::filter<>{}(e)); REQUIRE_FALSE((!ecs::exists<position_c>{})(e));
REQUIRE_FALSE(ecs::filter<position_c>{}(e)); REQUIRE_FALSE((!ecs::exists<velocity_c>{})(e));
REQUIRE_FALSE(ecs::filter<velocity_c>{}(e));
REQUIRE_FALSE(ecs::filter<position_c, velocity_c>{}(e));
REQUIRE(ecs::filter_any<>{}(e)); REQUIRE((!ecs::exists_any<>{})(e));
REQUIRE_FALSE(ecs::filter_any<position_c>{}(e)); REQUIRE_FALSE((!ecs::exists_any<position_c>{})(e));
REQUIRE_FALSE(ecs::filter_any<velocity_c>{}(e)); REQUIRE_FALSE((!ecs::exists_any<velocity_c>{})(e));
REQUIRE_FALSE(ecs::filter_any<position_c, velocity_c>{}(e)); REQUIRE_FALSE((!ecs::exists_any<position_c, velocity_c>{})(e));
REQUIRE_FALSE(ecs::filter_all<>{}(e)); REQUIRE_FALSE((!ecs::exists_all<>{})(e));
REQUIRE_FALSE(ecs::filter_all<position_c>{}(e)); REQUIRE_FALSE((!ecs::exists_all<position_c>{})(e));
REQUIRE_FALSE(ecs::filter_all<velocity_c>{}(e)); REQUIRE_FALSE((!ecs::exists_all<velocity_c>{})(e));
REQUIRE_FALSE(ecs::filter_all<position_c, velocity_c>{}(e)); REQUIRE_FALSE((!ecs::exists_all<position_c, velocity_c>{})(e));
} }
{ {
ecs::registry w; ecs::registry w;
auto e = w.create_entity(); auto e = w.create_entity();
REQUIRE(ecs::require<>{}(e)); REQUIRE_FALSE(ecs::exists<position_c>{}(e));
REQUIRE_FALSE(ecs::require<position_c>{}(e)); REQUIRE_FALSE(ecs::exists<velocity_c>{}(e));
REQUIRE_FALSE(ecs::require<velocity_c>{}(e));
REQUIRE_FALSE(ecs::require<position_c, velocity_c>{}(e));
REQUIRE_FALSE(ecs::require_any<>{}(e)); REQUIRE_FALSE(ecs::exists_any<>{}(e));
REQUIRE_FALSE(ecs::require_any<position_c>{}(e)); REQUIRE_FALSE(ecs::exists_any<position_c>{}(e));
REQUIRE_FALSE(ecs::require_any<velocity_c>{}(e)); REQUIRE_FALSE(ecs::exists_any<velocity_c>{}(e));
REQUIRE_FALSE(ecs::require_any<position_c, velocity_c>{}(e)); REQUIRE_FALSE(ecs::exists_any<position_c, velocity_c>{}(e));
REQUIRE(ecs::require_all<>{}(e)); REQUIRE(ecs::exists_all<>{}(e));
REQUIRE_FALSE(ecs::require_all<position_c>{}(e)); REQUIRE_FALSE(ecs::exists_all<position_c>{}(e));
REQUIRE_FALSE(ecs::require_all<velocity_c>{}(e)); REQUIRE_FALSE(ecs::exists_all<velocity_c>{}(e));
REQUIRE_FALSE(ecs::require_all<position_c, velocity_c>{}(e)); REQUIRE_FALSE(ecs::exists_all<position_c, velocity_c>{}(e));
e.assign_component<position_c>(); e.assign_component<position_c>();
REQUIRE(ecs::require<>{}(e)); REQUIRE(ecs::exists<position_c>{}(e));
REQUIRE(ecs::require<position_c>{}(e)); REQUIRE_FALSE(ecs::exists<velocity_c>{}(e));
REQUIRE_FALSE(ecs::require<velocity_c>{}(e));
REQUIRE_FALSE(ecs::require<position_c, velocity_c>{}(e));
REQUIRE_FALSE(ecs::require_any<>{}(e)); REQUIRE_FALSE(ecs::exists_any<>{}(e));
REQUIRE(ecs::require_any<position_c>{}(e)); REQUIRE(ecs::exists_any<position_c>{}(e));
REQUIRE_FALSE(ecs::require_any<velocity_c>{}(e)); REQUIRE_FALSE(ecs::exists_any<velocity_c>{}(e));
REQUIRE(ecs::require_any<position_c, velocity_c>{}(e)); REQUIRE(ecs::exists_any<position_c, velocity_c>{}(e));
REQUIRE(ecs::require_all<>{}(e)); REQUIRE(ecs::exists_all<>{}(e));
REQUIRE(ecs::require_all<position_c>{}(e)); REQUIRE(ecs::exists_all<position_c>{}(e));
REQUIRE_FALSE(ecs::require_all<velocity_c>{}(e)); REQUIRE_FALSE(ecs::exists_all<velocity_c>{}(e));
REQUIRE_FALSE(ecs::require_all<position_c, velocity_c>{}(e)); REQUIRE_FALSE(ecs::exists_all<position_c, velocity_c>{}(e));
e.assign_component<velocity_c>(); e.assign_component<velocity_c>();
REQUIRE(ecs::require<>{}(e)); REQUIRE(ecs::exists<position_c>{}(e));
REQUIRE(ecs::require<position_c>{}(e)); REQUIRE(ecs::exists<velocity_c>{}(e));
REQUIRE(ecs::require<velocity_c>{}(e));
REQUIRE(ecs::require<position_c, velocity_c>{}(e));
REQUIRE_FALSE(ecs::require_any<>{}(e)); REQUIRE_FALSE(ecs::exists_any<>{}(e));
REQUIRE(ecs::require_any<position_c>{}(e)); REQUIRE(ecs::exists_any<position_c>{}(e));
REQUIRE(ecs::require_any<velocity_c>{}(e)); REQUIRE(ecs::exists_any<velocity_c>{}(e));
REQUIRE(ecs::require_any<position_c, velocity_c>{}(e)); REQUIRE(ecs::exists_any<position_c, velocity_c>{}(e));
REQUIRE(ecs::require_all<>{}(e)); REQUIRE(ecs::exists_all<>{}(e));
REQUIRE(ecs::require_all<position_c>{}(e)); REQUIRE(ecs::exists_all<position_c>{}(e));
REQUIRE(ecs::require_all<velocity_c>{}(e)); REQUIRE(ecs::exists_all<velocity_c>{}(e));
REQUIRE(ecs::require_all<position_c, velocity_c>{}(e)); REQUIRE(ecs::exists_all<position_c, velocity_c>{}(e));
} }
{ {
ecs::registry w; ecs::registry w;
@@ -1309,7 +1297,7 @@ TEST_CASE("registry") {
w.for_each_component<position_c>([ w.for_each_component<position_c>([
](ecs::entity, position_c& p){ ](ecs::entity, position_c& p){
p = position_c{5,5}; p = position_c{5,5};
}, ecs::require<movable_c>{}); }, ecs::exists<movable_c>{});
REQUIRE(e1.get_component<position_c>() == position_c(5,5)); REQUIRE(e1.get_component<position_c>() == position_c(5,5));
REQUIRE(e2.get_component<position_c>() == position_c(0,0)); REQUIRE(e2.get_component<position_c>() == position_c(0,0));
@@ -1318,7 +1306,7 @@ TEST_CASE("registry") {
](ecs::entity, position_c& p, const velocity_c& v){ ](ecs::entity, position_c& p, const velocity_c& v){
p.x += v.x; p.x += v.x;
p.y += v.y; p.y += v.y;
}, ecs::filter<movable_c>{}); }, !ecs::exists<movable_c>{});
REQUIRE(e1.get_component<position_c>() == position_c(5,5)); REQUIRE(e1.get_component<position_c>() == position_c(5,5));
REQUIRE(e2.get_component<position_c>() == position_c(1,2)); REQUIRE(e2.get_component<position_c>() == position_c(1,2));
@@ -1330,7 +1318,7 @@ TEST_CASE("registry") {
](ecs::entity, position_c& p, const velocity_c& v){ ](ecs::entity, position_c& p, const velocity_c& v){
p.x += v.x; p.x += v.x;
p.y += v.y; p.y += v.y;
}, ecs::require<movable_c>{}, ecs::filter<disabled_c>{}); }, ecs::exists<movable_c>{} && !ecs::exists<disabled_c>{});
REQUIRE(e1.get_component<position_c>() == position_c(5,5)); REQUIRE(e1.get_component<position_c>() == position_c(5,5));
REQUIRE(e2.get_component<position_c>() == position_c(2,4)); REQUIRE(e2.get_component<position_c>() == position_c(2,4));
@@ -1352,11 +1340,31 @@ TEST_CASE("registry") {
const velocity_c& v = e.get_component<velocity_c>(); const velocity_c& v = e.get_component<velocity_c>();
p.x += v.x; p.x += v.x;
p.y += v.y; p.y += v.y;
}, ecs::filter<disabled_c>{}, ecs::require<position_c, velocity_c>{}); }, !ecs::exists<disabled_c>{} && ecs::exists_all<position_c, velocity_c>{});
REQUIRE(e1.get_component<position_c>() == position_c(1,2)); REQUIRE(e1.get_component<position_c>() == position_c(1,2));
REQUIRE(e2.get_component<position_c>() == position_c(0,0)); REQUIRE(e2.get_component<position_c>() == position_c(0,0));
} }
{
ecs::registry w;
struct ignore_disabled {};
auto e1 = w.create_entity();
ecs::entity_filler(e1)
.component<disabled_c>()
.component<ignore_disabled>()
.component<position_c>(0,0)
.component<velocity_c>(1,2);
w.for_joined_components<position_c, velocity_c>([
](ecs::entity, position_c& p, const velocity_c& v){
p.x += v.x;
p.y += v.y;
}, !ecs::exists<disabled_c>{} || ecs::exists<ignore_disabled>{});
REQUIRE(e1.get_component<position_c>() == position_c(1,2));
}
} }
SECTION("systems") { SECTION("systems") {
{ {
@@ -1602,7 +1610,7 @@ TEST_CASE("example") {
>([](ecs::entity, position& p, const velocity& v) { >([](ecs::entity, position& p, const velocity& v) {
p.x += v.dx; p.x += v.dx;
p.y += v.dy; p.y += v.dy;
}, ecs::require<movable>{}, ecs::filter<disabled>{}); }, ecs::exists<movable>{} && !ecs::exists<disabled>{});
} }
}; };
@@ -1617,7 +1625,7 @@ TEST_CASE("example") {
>([this](ecs::entity, velocity& v) { >([this](ecs::entity, velocity& v) {
v.dx += gravity_; v.dx += gravity_;
v.dy += gravity_; v.dy += gravity_;
}, ecs::filter<disabled>{}); }, !ecs::exists<disabled>{});
} }
private: private:
float gravity_{}; float gravity_{};