Merge pull request #5 from BlackMATov/dev

Dev
This commit is contained in:
BlackMat MATov
2018-12-28 02:51:13 +07:00
committed by GitHub
2 changed files with 233 additions and 71 deletions

247
ecs.hpp
View File

@@ -11,7 +11,6 @@
#include <cstdint> #include <cstdint>
#include <tuple> #include <tuple>
#include <mutex>
#include <memory> #include <memory>
#include <vector> #include <vector>
#include <limits> #include <limits>
@@ -57,10 +56,62 @@ namespace ecs_hpp
{ {
namespace detail namespace detail
{ {
//
// as_const
//
template < typename T > template < typename T >
constexpr std::add_const_t<T>& as_const(T& t) noexcept { constexpr std::add_const_t<T>& as_const(T& t) noexcept {
return t; return t;
} }
//
// tuple_tail
//
namespace impl
{
template < typename T, typename... Ts, std::size_t... Is >
std::tuple<Ts...> tuple_tail_impl(std::tuple<T, Ts...>&& t, std::index_sequence<Is...> iseq) {
(void)iseq;
return std::make_tuple(std::move(std::get<Is + 1u>(t))...);
}
template < typename T, typename... Ts, std::size_t... Is >
std::tuple<Ts...> tuple_tail_impl(const std::tuple<T, Ts...>& t, std::index_sequence<Is...> iseq) {
(void)iseq;
return std::make_tuple(std::get<Is + 1u>(t)...);
}
}
template < typename T, typename... Ts >
std::tuple<Ts...> tuple_tail(std::tuple<T, Ts...>&& t) {
return impl::tuple_tail_impl(std::move(t), std::make_index_sequence<sizeof...(Ts)>());
}
template < typename T, typename... Ts >
std::tuple<Ts...> tuple_tail(const std::tuple<T, Ts...>& t) {
return impl::tuple_tail_impl(t, std::make_index_sequence<sizeof...(Ts)>());
}
//
// tuple_contains
//
template < typename V >
bool tuple_contains(const std::tuple<>& t, const V& v) {
(void)t;
(void)v;
return false;
}
template < typename V, typename T, typename... Ts >
bool tuple_contains(const std::tuple<T, Ts...>& t, const V& v) {
if ( std::get<0>(t) == v ) {
return true;
}
return tuple_contains(tuple_tail(t), v);
}
} }
} }
@@ -666,22 +717,48 @@ namespace ecs_hpp
template < typename T > template < typename T >
const T* find_component_impl_(const entity& ent) const noexcept; const T* find_component_impl_(const entity& ent) const noexcept;
template < typename... Ts, typename F > template < typename T, typename... Ts, typename F, std::size_t I, std::size_t... Is >
void for_joined_components_impl_(F&& f); void for_joined_components_impl_(F&& f, std::index_sequence<I, Is...> iseq);
template < typename T, typename... Ts, typename F, typename... Cs >
void for_joined_components_impl_(const entity& e, F&& f, Cs&&... cs); template < typename T, typename... Ts, typename F, std::size_t I, std::size_t... Is >
template < typename F, typename... Cs > void for_joined_components_impl_(F&& f, std::index_sequence<I, Is...> iseq) const;
void for_joined_components_impl_(const entity& e, F&& f, Cs&&... cs);
template < typename T
, typename... Ts
, typename F
, typename Ss
, typename... Cs >
void for_joined_components_impl_(
const entity& e,
const F& f,
const Ss& ss,
Cs&... cs);
template < typename T
, typename... Ts
, typename F
, typename Ss
, typename... Cs >
void for_joined_components_impl_(
const entity& e,
const F& f,
const Ss& ss,
const Cs&... cs) const;
template < typename... Ts, typename F >
void for_joined_components_impl_(F&& f) const;
template < typename T, typename... Ts, typename F, typename... Cs >
void for_joined_components_impl_(const entity& e, F&& f, Cs&&... cs) const;
template < typename F, typename... Cs > template < typename F, typename... Cs >
void for_joined_components_impl_(const entity& e, F&& f, Cs&&... cs) const; void for_joined_components_impl_(
const entity& e,
const F& f,
const std::tuple<>& ss,
Cs&... cs);
template < typename F, typename... Cs >
void for_joined_components_impl_(
const entity& e,
const F& f,
const std::tuple<>& ss,
const Cs&... cs) const;
private: private:
mutable std::mutex mutex_;
entity_id last_entity_id_{0u}; entity_id last_entity_id_{0u};
std::vector<entity_id> free_entity_ids_; std::vector<entity_id> free_entity_ids_;
detail::sparse_set<entity_id> entity_ids_; detail::sparse_set<entity_id> entity_ids_;
@@ -805,7 +882,6 @@ namespace ecs_hpp
namespace ecs_hpp namespace ecs_hpp
{ {
inline entity registry::create_entity() { inline entity registry::create_entity() {
std::lock_guard<std::mutex> guard(mutex_);
if ( !free_entity_ids_.empty() ) { if ( !free_entity_ids_.empty() ) {
auto ent = entity(*this, free_entity_ids_.back()); auto ent = entity(*this, free_entity_ids_.back());
entity_ids_.insert(ent.id()); entity_ids_.insert(ent.id());
@@ -820,7 +896,6 @@ namespace ecs_hpp
} }
inline bool registry::destroy_entity(const entity& ent) { inline bool registry::destroy_entity(const entity& ent) {
std::lock_guard<std::mutex> guard(mutex_);
remove_all_components_impl_(ent); remove_all_components_impl_(ent);
if ( entity_ids_.unordered_erase(ent.id()) ) { if ( entity_ids_.unordered_erase(ent.id()) ) {
free_entity_ids_.push_back(ent.id()); free_entity_ids_.push_back(ent.id());
@@ -830,13 +905,11 @@ namespace ecs_hpp
} }
inline bool registry::is_entity_alive(const entity& ent) const noexcept { inline bool registry::is_entity_alive(const entity& ent) const noexcept {
std::lock_guard<std::mutex> guard(mutex_);
return is_entity_alive_impl_(ent); return is_entity_alive_impl_(ent);
} }
template < typename T, typename... Args > template < typename T, typename... Args >
bool registry::assign_component(const entity& ent, Args&&... args) { bool registry::assign_component(const entity& ent, Args&&... args) {
std::lock_guard<std::mutex> guard(mutex_);
if ( !is_entity_alive_impl_(ent) ) { if ( !is_entity_alive_impl_(ent) ) {
return false; return false;
} }
@@ -848,7 +921,6 @@ namespace ecs_hpp
template < typename T > template < typename T >
bool registry::remove_component(const entity& ent) { bool registry::remove_component(const entity& ent) {
std::lock_guard<std::mutex> guard(mutex_);
if ( !is_entity_alive_impl_(ent) ) { if ( !is_entity_alive_impl_(ent) ) {
return false; return false;
} }
@@ -860,7 +932,6 @@ namespace ecs_hpp
template < typename T > template < typename T >
bool registry::exists_component(const entity& ent) const noexcept { bool registry::exists_component(const entity& ent) const noexcept {
std::lock_guard<std::mutex> guard(mutex_);
if ( !is_entity_alive_impl_(ent) ) { if ( !is_entity_alive_impl_(ent) ) {
return false; return false;
} }
@@ -871,13 +942,11 @@ namespace ecs_hpp
} }
inline std::size_t registry::remove_all_components(const entity& ent) const noexcept { inline std::size_t registry::remove_all_components(const entity& ent) const noexcept {
std::lock_guard<std::mutex> guard(mutex_);
return remove_all_components_impl_(ent); return remove_all_components_impl_(ent);
} }
template < typename T > template < typename T >
T& registry::get_component(const entity& ent) { T& registry::get_component(const entity& ent) {
std::lock_guard<std::mutex> guard(mutex_);
T* component = find_component_impl_<T>(ent); T* component = find_component_impl_<T>(ent);
if ( component ) { if ( component ) {
return *component; return *component;
@@ -887,7 +956,6 @@ namespace ecs_hpp
template < typename T > template < typename T >
const T& registry::get_component(const entity& ent) const { const T& registry::get_component(const entity& ent) const {
std::lock_guard<std::mutex> guard(mutex_);
const T* component = find_component_impl_<T>(ent); const T* component = find_component_impl_<T>(ent);
if ( component ) { if ( component ) {
return *component; return *component;
@@ -897,13 +965,11 @@ namespace ecs_hpp
template < typename T > template < typename T >
T* registry::find_component(const entity& ent) noexcept { T* registry::find_component(const entity& ent) noexcept {
std::lock_guard<std::mutex> guard(mutex_);
return find_component_impl_<T>(ent); return find_component_impl_<T>(ent);
} }
template < typename T > template < typename T >
const T* registry::find_component(const entity& ent) const noexcept { const T* registry::find_component(const entity& ent) const noexcept {
std::lock_guard<std::mutex> guard(mutex_);
return find_component_impl_<T>(ent); return find_component_impl_<T>(ent);
} }
@@ -929,7 +995,6 @@ namespace ecs_hpp
template < typename T, typename F > template < typename T, typename F >
void registry::for_each_component(F&& f) { void registry::for_each_component(F&& f) {
std::lock_guard<std::mutex> guard(mutex_);
detail::component_storage<T>* storage = find_storage_<T>(); detail::component_storage<T>* storage = find_storage_<T>();
if ( storage ) { if ( storage ) {
storage->for_each_component(std::forward<F>(f)); storage->for_each_component(std::forward<F>(f));
@@ -938,7 +1003,6 @@ namespace ecs_hpp
template < typename T, typename F > template < typename T, typename F >
void registry::for_each_component(F&& f) const { void registry::for_each_component(F&& f) const {
std::lock_guard<std::mutex> guard(mutex_);
const detail::component_storage<T>* storage = find_storage_<T>(); const detail::component_storage<T>* storage = find_storage_<T>();
if ( storage ) { if ( storage ) {
storage->for_each_component(std::forward<F>(f)); storage->for_each_component(std::forward<F>(f));
@@ -947,19 +1011,20 @@ namespace ecs_hpp
template < typename... Ts, typename F > template < typename... Ts, typename F >
void registry::for_joined_components(F&& f) { void registry::for_joined_components(F&& f) {
std::lock_guard<std::mutex> guard(mutex_); for_joined_components_impl_<Ts...>(
for_joined_components_impl_<Ts...>(std::forward<F>(f)); std::forward<F>(f),
std::make_index_sequence<sizeof...(Ts)>());
} }
template < typename... Ts, typename F > template < typename... Ts, typename F >
void registry::for_joined_components(F&& f) const { void registry::for_joined_components(F&& f) const {
std::lock_guard<std::mutex> guard(mutex_); for_joined_components_impl_<Ts...>(
for_joined_components_impl_<Ts...>(std::forward<F>(f)); std::forward<F>(f),
std::make_index_sequence<sizeof...(Ts)>());
} }
template < typename T, typename... Args > template < typename T, typename... Args >
void registry::add_system(Args&&... args) { void registry::add_system(Args&&... args) {
std::lock_guard<std::mutex> guard(mutex_);
systems_.emplace_back( systems_.emplace_back(
std::make_unique<T>(std::forward<Args>(args)...)); std::make_unique<T>(std::forward<Args>(args)...));
} }
@@ -1035,51 +1100,105 @@ namespace ecs_hpp
: nullptr; : nullptr;
} }
template < typename... Ts, typename F > template < typename T
void registry::for_joined_components_impl_(F&& f) { , typename... Ts
for ( const auto id : entity_ids_ ) { , typename F
for_joined_components_impl_<Ts...>(entity(*this, id), std::forward<F>(f)); , std::size_t I
, std::size_t... Is >
void registry::for_joined_components_impl_(
F&& f,
std::index_sequence<I, Is...> iseq)
{
(void)iseq;
const auto ss = std::make_tuple(find_storage_<Ts>()...);
if ( !detail::tuple_contains(ss, nullptr) ) {
for_each_component<T>([this, &f, &ss](const entity& e, T& t) {
for_joined_components_impl_<Ts...>(e, f, ss, t);
});
} }
} }
template < typename T, typename... Ts, typename F, typename... Cs > template < typename T
void registry::for_joined_components_impl_(const entity& e, F&& f, Cs&&... cs) { , typename... Ts
T* c = find_component_impl_<T>(e); , typename F
, std::size_t I
, std::size_t... Is >
void registry::for_joined_components_impl_(
F&& f,
std::index_sequence<I, Is...> iseq) const
{
(void)iseq;
const auto ss = std::make_tuple(find_storage_<Ts>()...);
if ( !detail::tuple_contains(ss, nullptr) ) {
for_each_component<T>([this, &f, &ss](const entity& e, const T& t) {
detail::as_const(*this).for_joined_components_impl_<Ts...>(e, f, ss, t);
});
}
}
template < typename T
, typename... Ts
, typename F
, typename Ss
, typename... Cs >
void registry::for_joined_components_impl_(
const entity& e,
const F& f,
const Ss& ss,
Cs&... cs)
{
T* c = std::get<0>(ss)->find(e.id());
if ( c ) { if ( c ) {
for_joined_components_impl_<Ts...>( for_joined_components_impl_<Ts...>(
e, e,
std::forward<F>(f), f,
std::forward<Cs>(cs)..., detail::tuple_tail(ss),
cs...,
*c);
}
}
template < typename T
, typename... Ts
, typename F
, typename Ss
, typename... Cs >
void registry::for_joined_components_impl_(
const entity& e,
const F& f,
const Ss& ss,
const Cs&... cs) const
{
const T* c = std::get<0>(ss)->find(e.id());
if ( c ) {
for_joined_components_impl_<Ts...>(
e,
f,
detail::tuple_tail(ss),
cs...,
*c); *c);
} }
} }
template < typename F, typename... Cs > template < typename F, typename... Cs >
void registry::for_joined_components_impl_(const entity& e, F&& f, Cs&&... cs) { void registry::for_joined_components_impl_(
f(e, std::forward<Cs>(cs)...); const entity& e,
} const F& f,
const std::tuple<>& ss,
template < typename... Ts, typename F > Cs&... cs)
void registry::for_joined_components_impl_(F&& f) const { {
for ( const auto id : entity_ids_ ) { (void)ss;
for_joined_components_impl_<Ts...>(entity(const_cast<registry&>(*this), id), std::forward<F>(f)); f(e, cs...);
}
}
template < typename T, typename... Ts, typename F, typename... Cs >
void registry::for_joined_components_impl_(const entity& e, F&& f, Cs&&... cs) const {
const T* c = find_component_impl_<T>(e);
if ( c ) {
for_joined_components_impl_<Ts...>(
e,
std::forward<F>(f),
std::forward<Cs>(cs)...,
*c);
}
} }
template < typename F, typename... Cs > template < typename F, typename... Cs >
void registry::for_joined_components_impl_(const entity& e, F&& f, Cs&&... cs) const { void registry::for_joined_components_impl_(
f(e, std::forward<Cs>(cs)...); const entity& e,
const F& f,
const std::tuple<>& ss,
const Cs&... cs) const
{
(void)ss;
f(e, cs...);
} }
} }

View File

@@ -41,14 +41,31 @@ namespace
TEST_CASE("detail") { TEST_CASE("detail") {
SECTION("get_type_id") { SECTION("get_type_id") {
REQUIRE(ecs::detail::type_family<position_c>::id() == 1u); using namespace ecs::detail;
REQUIRE(ecs::detail::type_family<position_c>::id() == 1u); REQUIRE(type_family<position_c>::id() == 1u);
REQUIRE(type_family<position_c>::id() == 1u);
REQUIRE(ecs::detail::type_family<velocity_c>::id() == 2u); REQUIRE(type_family<velocity_c>::id() == 2u);
REQUIRE(ecs::detail::type_family<velocity_c>::id() == 2u); REQUIRE(type_family<velocity_c>::id() == 2u);
REQUIRE(ecs::detail::type_family<position_c>::id() == 1u); REQUIRE(type_family<position_c>::id() == 1u);
REQUIRE(ecs::detail::type_family<velocity_c>::id() == 2u); REQUIRE(type_family<velocity_c>::id() == 2u);
}
SECTION("tuple_tail") {
using namespace ecs::detail;
{
REQUIRE(tuple_tail(std::make_tuple(1, 2, 3)) == std::make_tuple(2, 3));
REQUIRE(tuple_tail(std::make_tuple(2, 3)) == std::make_tuple(3));
REQUIRE(tuple_tail(std::make_tuple(3)) == std::make_tuple());
}
{
const auto t1 = std::make_tuple(1);
const auto t2 = std::make_tuple(1, 2);
const auto t3 = std::make_tuple(1, 2, 3);
REQUIRE(tuple_tail(t1) == std::make_tuple());
REQUIRE(tuple_tail(t2) == std::make_tuple(2));
REQUIRE(tuple_tail(t3) == std::make_tuple(2, 3));
}
} }
SECTION("sparse_set") { SECTION("sparse_set") {
using namespace ecs::detail; using namespace ecs::detail;
@@ -71,6 +88,7 @@ TEST_CASE("detail") {
REQUIRE(s.has(42u)); REQUIRE(s.has(42u));
REQUIRE_FALSE(s.has(84u)); REQUIRE_FALSE(s.has(84u));
REQUIRE(s.find(42u) == s.begin());
REQUIRE(s.find_index(42u).second); REQUIRE(s.find_index(42u).second);
REQUIRE(s.find_index(42u).first == 0u); REQUIRE(s.find_index(42u).first == 0u);
REQUIRE(s.get_index(42u) == 0u); REQUIRE(s.get_index(42u) == 0u);
@@ -231,6 +249,14 @@ TEST_CASE("registry") {
REQUIRE_FALSE(w.destroy_entity(e1)); REQUIRE_FALSE(w.destroy_entity(e1));
REQUIRE_FALSE(w.destroy_entity(e2)); REQUIRE_FALSE(w.destroy_entity(e2));
} }
{
ecs::registry w;
const auto e1 = w.create_entity();
w.destroy_entity(e1);
const auto e2 = w.create_entity();
REQUIRE(e1 == e2);
}
} }
SECTION("component_assigning") { SECTION("component_assigning") {
{ {
@@ -355,6 +381,14 @@ TEST_CASE("registry") {
REQUIRE_FALSE(ww.find_component<velocity_c>(e2)); REQUIRE_FALSE(ww.find_component<velocity_c>(e2));
} }
} }
{
ecs::registry w;
auto e1 = w.create_entity();
e1.assign_component<position_c>(1, 2);
e1.assign_component<position_c>(3, 4);
REQUIRE(e1.get_component<position_c>().x == 3);
REQUIRE(e1.get_component<position_c>().y == 4);
}
{ {
ecs::registry w; ecs::registry w;
@@ -506,6 +540,15 @@ TEST_CASE("registry") {
REQUIRE(acc2 == 16); REQUIRE(acc2 == 16);
} }
} }
{
ecs::registry w;
auto e1 = w.create_entity();
e1.assign_component<position_c>(1, 2);
w.for_joined_components<position_c, velocity_c>([](
ecs::entity, const position_c&, const velocity_c&)
{
});
}
} }
SECTION("systems") { SECTION("systems") {
{ {
@@ -513,7 +556,7 @@ TEST_CASE("registry") {
public: public:
void process(ecs::registry& owner) override { void process(ecs::registry& owner) override {
owner.for_joined_components<position_c, velocity_c>([]( owner.for_joined_components<position_c, velocity_c>([](
ecs::entity e, 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;