Merge pull request #9 from BlackMATov/dev

Dev
This commit is contained in:
BlackMat MATov
2019-01-02 18:23:27 +07:00
committed by GitHub
3 changed files with 448 additions and 180 deletions

View File

@@ -35,15 +35,15 @@
```cpp ```cpp
struct position_component { struct position_component {
float x{0}; float x;
float y{0}; float y;
position_component(float nx, float ny) position_component(float nx, float ny)
: x(nx), y(ny) {} : x(nx), y(ny) {}
}; };
struct velocity_component { struct velocity_component {
float dx{0}; float dx;
float dy{0}; float dy;
velocity_component(float ndx, float ndy) velocity_component(float ndx, float ndy)
: dx(ndx), dy(ndy) {} : dx(ndx), dy(ndy) {}
}; };

507
ecs.hpp
View File

@@ -74,6 +74,14 @@ namespace ecs_hpp
return t; return t;
} }
//
// hash_combine
//
constexpr std::size_t hash_combine(std::size_t l, std::size_t r) noexcept {
return l ^ (r + 0x9e3779b9 + (l << 6) + (l >> 2));
}
// //
// tuple_tail // tuple_tail
// //
@@ -189,7 +197,7 @@ namespace ecs_hpp
}; };
template < typename T > template < typename T >
class type_family : public type_family_base<> { class type_family final : public type_family_base<> {
public: public:
static family_id id() noexcept { static family_id id() noexcept {
static family_id self_id = ++last_id_; static family_id self_id = ++last_id_;
@@ -226,7 +234,7 @@ namespace ecs_hpp
struct sparse_unsigned_indexer<T, false> {}; struct sparse_unsigned_indexer<T, false> {};
template < typename T > template < typename T >
struct sparse_indexer struct sparse_indexer final
: public sparse_unsigned_indexer<T> {}; : public sparse_unsigned_indexer<T> {};
} }
} }
@@ -466,7 +474,9 @@ namespace ecs_hpp
std::enable_if_t< std::enable_if_t<
std::is_nothrow_move_assignable<K>::value, std::is_nothrow_move_assignable<K>::value,
bool> bool>
unordered_erase(const K& k) { unordered_erase(const K& k)
noexcept(std::is_nothrow_move_assignable<T>::value)
{
if ( !keys_.has(k) ) { if ( !keys_.has(k) ) {
return false; return false;
} }
@@ -532,7 +542,7 @@ namespace ecs_hpp
{ {
namespace detail namespace detail
{ {
struct entity_id_indexer { struct entity_id_indexer final {
std::size_t operator()(entity_id id) const noexcept { std::size_t operator()(entity_id id) const noexcept {
return entity_id_index(id); return entity_id_index(id);
} }
@@ -554,21 +564,25 @@ namespace ecs_hpp
public: public:
virtual ~component_storage_base() = default; virtual ~component_storage_base() = default;
virtual bool remove(entity_id id) noexcept = 0; virtual bool remove(entity_id id) noexcept = 0;
virtual bool exists(entity_id id) const noexcept = 0; virtual bool has(entity_id id) const noexcept = 0;
}; };
template < typename T > template < typename T >
class component_storage : public component_storage_base { class component_storage final : public component_storage_base {
public: public:
component_storage(registry& owner); component_storage(registry& owner);
template < typename... Args > template < typename... Args >
void assign(entity_id id, Args&&... args); void assign(entity_id id, Args&&... args);
bool exists(entity_id id) const noexcept;
bool remove(entity_id id) noexcept override; bool remove(entity_id id) noexcept override;
bool exists(entity_id id) const noexcept override;
T* find(entity_id id) noexcept; T* find(entity_id id) noexcept;
const T* find(entity_id id) const noexcept; const T* find(entity_id id) const noexcept;
std::size_t count() const noexcept;
bool has(entity_id id) const noexcept override;
template < typename F > template < typename F >
void for_each_component(F&& f) noexcept; void for_each_component(F&& f) noexcept;
template < typename F > template < typename F >
@@ -591,13 +605,13 @@ namespace ecs_hpp
} }
template < typename T > template < typename T >
bool component_storage<T>::remove(entity_id id) noexcept { bool component_storage<T>::exists(entity_id id) const noexcept {
return components_.unordered_erase(id); return components_.has(id);
} }
template < typename T > template < typename T >
bool component_storage<T>::exists(entity_id id) const noexcept { bool component_storage<T>::remove(entity_id id) noexcept {
return components_.has(id); return components_.unordered_erase(id);
} }
template < typename T > template < typename T >
@@ -610,11 +624,21 @@ namespace ecs_hpp
return components_.find(id); return components_.find(id);
} }
template < typename T >
std::size_t component_storage<T>::count() const noexcept {
return components_.size();
}
template < typename T >
bool component_storage<T>::has(entity_id id) const noexcept {
return components_.has(id);
}
template < typename T > template < typename T >
template < typename F > template < typename F >
void component_storage<T>::for_each_component(F&& f) noexcept { void component_storage<T>::for_each_component(F&& f) noexcept {
for ( const auto id : components_ ) { for ( const auto id : components_ ) {
f(entity(owner_, id), components_.get(id)); f(id, components_.get(id));
} }
} }
@@ -622,7 +646,7 @@ namespace ecs_hpp
template < typename F > template < typename F >
void component_storage<T>::for_each_component(F&& f) const noexcept { void component_storage<T>::for_each_component(F&& f) const noexcept {
for ( const auto id : components_ ) { for ( const auto id : components_ ) {
f(const_entity(owner_, id), components_.get(id)); f(id, components_.get(id));
} }
} }
} }
@@ -641,11 +665,13 @@ namespace ecs_hpp
entity(registry& owner) noexcept; entity(registry& owner) noexcept;
entity(registry& owner, entity_id id) noexcept; entity(registry& owner, entity_id id) noexcept;
registry& owner() noexcept;
const registry& owner() const noexcept; const registry& owner() const noexcept;
entity_id id() const noexcept; entity_id id() const noexcept;
bool destroy(); bool destroy();
bool is_alive() const noexcept; bool alive() const noexcept;
template < typename T, typename... Args > template < typename T, typename... Args >
bool assign_component(Args&&... args); bool assign_component(Args&&... args);
@@ -680,7 +706,7 @@ namespace ecs_hpp
template < typename... Ts > template < typename... Ts >
std::tuple<const Ts*...> find_components() const noexcept; std::tuple<const Ts*...> find_components() const noexcept;
private: private:
registry* owner_; registry* owner_{nullptr};
entity_id id_{0u}; entity_id id_{0u};
}; };
@@ -691,11 +717,13 @@ namespace ecs_hpp
namespace std namespace std
{ {
template <> template <>
struct hash<ecs_hpp::entity> struct hash<ecs_hpp::entity> final
: std::unary_function<const ecs_hpp::entity&, std::size_t> : std::unary_function<const ecs_hpp::entity&, std::size_t>
{ {
std::size_t operator()(const ecs_hpp::entity& ent) const noexcept { std::size_t operator()(const ecs_hpp::entity& ent) const noexcept {
return std::hash<ecs_hpp::entity_id>()(ent.id()); return ecs_hpp::detail::hash_combine(
std::hash<const ecs_hpp::registry*>()(&ent.owner()),
std::hash<ecs_hpp::entity_id>()(ent.id()));
} }
}; };
} }
@@ -718,7 +746,7 @@ namespace ecs_hpp
const registry& owner() const noexcept; const registry& owner() const noexcept;
entity_id id() const noexcept; entity_id id() const noexcept;
bool is_alive() const noexcept; bool alive() const noexcept;
template < typename T > template < typename T >
bool exists_component() const noexcept; bool exists_component() const noexcept;
@@ -735,7 +763,7 @@ namespace ecs_hpp
template < typename... Ts > template < typename... Ts >
std::tuple<const Ts*...> find_components() const noexcept; std::tuple<const Ts*...> find_components() const noexcept;
private: private:
const registry* owner_; const registry* owner_{nullptr};
entity_id id_{0u}; entity_id id_{0u};
}; };
@@ -746,11 +774,13 @@ namespace ecs_hpp
namespace std namespace std
{ {
template <> template <>
struct hash<ecs_hpp::const_entity> struct hash<ecs_hpp::const_entity> final
: std::unary_function<const ecs_hpp::const_entity&, std::size_t> : std::unary_function<const ecs_hpp::const_entity&, std::size_t>
{ {
std::size_t operator()(const ecs_hpp::const_entity& ent) const noexcept { std::size_t operator()(const ecs_hpp::const_entity& ent) const noexcept {
return std::hash<ecs_hpp::entity_id>()(ent.id()); return ecs_hpp::detail::hash_combine(
std::hash<const ecs_hpp::registry*>()(&ent.owner()),
std::hash<ecs_hpp::entity_id>()(ent.id()));
} }
}; };
} }
@@ -779,44 +809,92 @@ namespace ecs_hpp
namespace ecs_hpp namespace ecs_hpp
{ {
class registry final { class registry final {
private:
class uentity {
public:
uentity(registry& owner, entity_id id) noexcept;
uentity(entity_id ent) noexcept;
uentity(entity ent) noexcept;
operator entity_id() const noexcept;
operator entity() const noexcept;
operator const_entity() const noexcept;
entity_id id() const noexcept;
registry* owner() noexcept;
const registry* owner() const noexcept;
bool check_owner(const registry* owner) const noexcept;
private:
entity_id id_{0u};
registry* owner_{nullptr};
};
class const_uentity {
public:
const_uentity(const registry& owner, entity_id id) noexcept;
const_uentity(entity_id ent) noexcept;
const_uentity(entity ent) noexcept;
const_uentity(const_entity ent) noexcept;
const_uentity(const uentity& ent) noexcept;
operator entity_id() const noexcept;
operator const_entity() const noexcept;
entity_id id() const noexcept;
const registry* owner() const noexcept;
bool check_owner(const registry* owner) const noexcept;
private:
entity_id id_{0u};
const registry* owner_{nullptr};
};
public: public:
registry() = default; registry() = default;
~registry() noexcept = default; ~registry() noexcept = default;
entity create_entity(); entity create_entity();
bool destroy_entity(const entity& ent);
bool is_entity_alive(const const_entity& ent) const noexcept; bool destroy_entity(const uentity& ent);
bool alive_entity(const const_uentity& ent) const noexcept;
template < typename T, typename... Args > template < typename T, typename... Args >
bool assign_component(const entity& ent, Args&&... args); bool assign_component(const uentity& ent, Args&&... args);
template < typename T > template < typename T >
bool remove_component(const entity& ent); bool remove_component(const uentity& ent);
template < typename T > template < typename T >
bool exists_component(const const_entity& ent) const noexcept; bool exists_component(const const_uentity& ent) const noexcept;
std::size_t remove_all_components(const entity& ent) noexcept; std::size_t remove_all_components(const uentity& ent) noexcept;
template < typename T > template < typename T >
T& get_component(const entity& ent); T& get_component(const uentity& ent);
template < typename T > template < typename T >
const T& get_component(const const_entity& ent) const; const T& get_component(const const_uentity& ent) const;
template < typename T > template < typename T >
T* find_component(const entity& ent) noexcept; T* find_component(const uentity& ent) noexcept;
template < typename T > template < typename T >
const T* find_component(const const_entity& ent) const noexcept; const T* find_component(const const_uentity& ent) const noexcept;
template < typename... Ts > template < typename... Ts >
std::tuple<Ts&...> get_components(const entity& ent); std::tuple<Ts&...> get_components(const uentity& ent);
template < typename... Ts > template < typename... Ts >
std::tuple<const Ts&...> get_components(const const_entity& ent) const; std::tuple<const Ts&...> get_components(const const_uentity& ent) const;
template < typename... Ts > template < typename... Ts >
std::tuple<Ts*...> find_components(const entity& ent) noexcept; std::tuple<Ts*...> find_components(const uentity& ent) noexcept;
template < typename... Ts > template < typename... Ts >
std::tuple<const Ts*...> find_components(const const_entity& ent) const noexcept; std::tuple<const Ts*...> find_components(const const_uentity& ent) const noexcept;
template < typename T >
std::size_t component_count() const noexcept;
template < typename T >
std::size_t entity_component_count(const const_uentity& ent) const noexcept;
template < typename F > template < typename F >
void for_each_entity(F&& f); void for_each_entity(F&& f);
@@ -839,25 +917,30 @@ namespace ecs_hpp
private: private:
template < typename T > template < typename T >
detail::component_storage<T>* find_storage_() noexcept; detail::component_storage<T>* find_storage_() noexcept;
template < typename T > template < typename T >
const detail::component_storage<T>* find_storage_() const noexcept; const detail::component_storage<T>* find_storage_() const noexcept;
template < typename T > template < typename T >
detail::component_storage<T>& get_or_create_storage_(); detail::component_storage<T>& get_or_create_storage_();
bool is_entity_alive_impl_(const const_entity& ent) const noexcept; template < typename T
std::size_t remove_all_components_impl_(const entity& ent) noexcept; , typename... Ts
, typename F
, std::size_t I
, std::size_t... Is >
void for_joined_components_impl_(
F&& f,
std::index_sequence<I, Is...> iseq);
template < typename T > template < typename T
T* find_component_impl_(const entity& ent) noexcept; , typename... Ts
template < typename T > , typename F
const T* find_component_impl_(const const_entity& ent) const noexcept; , std::size_t I
, std::size_t... Is >
template < typename T, typename... Ts, typename F, std::size_t I, std::size_t... Is > void for_joined_components_impl_(
void for_joined_components_impl_(F&& f, std::index_sequence<I, Is...> iseq); F&& f,
std::index_sequence<I, Is...> iseq) const;
template < typename T, typename... Ts, typename F, std::size_t I, std::size_t... Is >
void for_joined_components_impl_(F&& f, std::index_sequence<I, Is...> iseq) const;
template < typename T template < typename T
, typename... Ts , typename... Ts
@@ -865,7 +948,7 @@ namespace ecs_hpp
, typename Ss , typename Ss
, typename... Cs > , typename... Cs >
void for_joined_components_impl_( void for_joined_components_impl_(
const entity& e, const uentity& e,
const F& f, const F& f,
const Ss& ss, const Ss& ss,
Cs&... cs); Cs&... cs);
@@ -876,21 +959,21 @@ namespace ecs_hpp
, typename Ss , typename Ss
, typename... Cs > , typename... Cs >
void for_joined_components_impl_( void for_joined_components_impl_(
const const_entity& e, const const_uentity& e,
const F& f, const F& f,
const Ss& ss, const Ss& ss,
const Cs&... cs) const; const Cs&... cs) const;
template < typename F, typename... Cs > template < typename F, typename... Cs >
void for_joined_components_impl_( void for_joined_components_impl_(
const entity& e, const uentity& e,
const F& f, const F& f,
const std::tuple<>& ss, const std::tuple<>& ss,
Cs&... cs); Cs&... cs);
template < typename F, typename... Cs > template < typename F, typename... Cs >
void for_joined_components_impl_( void for_joined_components_impl_(
const const_entity& e, const const_uentity& e,
const F& f, const F& f,
const std::tuple<>& ss, const std::tuple<>& ss,
const Cs&... cs) const; const Cs&... cs) const;
@@ -922,6 +1005,10 @@ namespace ecs_hpp
: owner_(&owner) : owner_(&owner)
, id_(id) {} , id_(id) {}
inline registry& entity::owner() noexcept {
return *owner_;
}
inline const registry& entity::owner() const noexcept { inline const registry& entity::owner() const noexcept {
return *owner_; return *owner_;
} }
@@ -931,72 +1018,72 @@ namespace ecs_hpp
} }
inline bool entity::destroy() { inline bool entity::destroy() {
return (*owner_).destroy_entity(*this); return (*owner_).destroy_entity(id_);
} }
inline bool entity::is_alive() const noexcept { inline bool entity::alive() const noexcept {
return detail::as_const(*owner_).is_entity_alive(*this); return detail::as_const(*owner_).alive_entity(id_);
} }
template < typename T, typename... Args > template < typename T, typename... Args >
bool entity::assign_component(Args&&... args) { bool entity::assign_component(Args&&... args) {
return (*owner_).assign_component<T>( return (*owner_).assign_component<T>(
*this, id_,
std::forward<Args>(args)...); std::forward<Args>(args)...);
} }
template < typename T > template < typename T >
bool entity::remove_component() { bool entity::remove_component() {
return (*owner_).remove_component<T>(*this); return (*owner_).remove_component<T>(id_);
} }
template < typename T > template < typename T >
bool entity::exists_component() const noexcept { bool entity::exists_component() const noexcept {
return detail::as_const(*owner_).exists_component<T>(*this); return detail::as_const(*owner_).exists_component<T>(id_);
} }
inline std::size_t entity::remove_all_components() noexcept { inline std::size_t entity::remove_all_components() noexcept {
return (*owner_).remove_all_components(*this); return (*owner_).remove_all_components(id_);
} }
template < typename T > template < typename T >
T& entity::get_component() { T& entity::get_component() {
return (*owner_).get_component<T>(*this); return (*owner_).get_component<T>(id_);
} }
template < typename T > template < typename T >
const T& entity::get_component() const { const T& entity::get_component() const {
return detail::as_const(*owner_).get_component<T>(*this); return detail::as_const(*owner_).get_component<T>(id_);
} }
template < typename T > template < typename T >
T* entity::find_component() noexcept { T* entity::find_component() noexcept {
return (*owner_).find_component<T>(*this); return (*owner_).find_component<T>(id_);
} }
template < typename T > template < typename T >
const T* entity::find_component() const noexcept { const T* entity::find_component() const noexcept {
return detail::as_const(*owner_).find_component<T>(*this); return detail::as_const(*owner_).find_component<T>(id_);
} }
template < typename... Ts > template < typename... Ts >
std::tuple<Ts&...> entity::get_components() { std::tuple<Ts&...> entity::get_components() {
return (*owner_).get_components<Ts...>(*this); return (*owner_).get_components<Ts...>(id_);
} }
template < typename... Ts > template < typename... Ts >
std::tuple<const Ts&...> entity::get_components() const { std::tuple<const Ts&...> entity::get_components() const {
return detail::as_const(*owner_).get_components<Ts...>(*this); return detail::as_const(*owner_).get_components<Ts...>(id_);
} }
template < typename... Ts > template < typename... Ts >
std::tuple<Ts*...> entity::find_components() noexcept { std::tuple<Ts*...> entity::find_components() noexcept {
return (*owner_).find_components<Ts...>(*this); return (*owner_).find_components<Ts...>(id_);
} }
template < typename... Ts > template < typename... Ts >
std::tuple<const Ts*...> entity::find_components() const noexcept { std::tuple<const Ts*...> entity::find_components() const noexcept {
return detail::as_const(*owner_).find_components<Ts...>(*this); return detail::as_const(*owner_).find_components<Ts...>(id_);
} }
inline bool operator==(const entity& l, const entity& r) noexcept { inline bool operator==(const entity& l, const entity& r) noexcept {
@@ -1036,33 +1123,33 @@ namespace ecs_hpp
return id_; return id_;
} }
inline bool const_entity::is_alive() const noexcept { inline bool const_entity::alive() const noexcept {
return (*owner_).is_entity_alive(*this); return (*owner_).alive_entity(id_);
} }
template < typename T > template < typename T >
bool const_entity::exists_component() const noexcept { bool const_entity::exists_component() const noexcept {
return (*owner_).exists_component<T>(*this); return (*owner_).exists_component<T>(id_);
} }
template < typename T > template < typename T >
const T& const_entity::get_component() const { const T& const_entity::get_component() const {
return (*owner_).get_component<T>(*this); return (*owner_).get_component<T>(id_);
} }
template < typename T > template < typename T >
const T* const_entity::find_component() const noexcept { const T* const_entity::find_component() const noexcept {
return (*owner_).find_component<T>(*this); return (*owner_).find_component<T>(id_);
} }
template < typename... Ts > template < typename... Ts >
std::tuple<const Ts&...> const_entity::get_components() const { std::tuple<const Ts&...> const_entity::get_components() const {
return (*owner_).get_components<Ts...>(*this); return (*owner_).get_components<Ts...>(id_);
} }
template < typename... Ts > template < typename... Ts >
std::tuple<const Ts*...> const_entity::find_components() const noexcept { std::tuple<const Ts*...> const_entity::find_components() const noexcept {
return (*owner_).find_components<Ts...>(*this); return (*owner_).find_components<Ts...>(id_);
} }
inline bool operator==(const const_entity& l, const const_entity& r) noexcept { inline bool operator==(const const_entity& l, const const_entity& r) noexcept {
@@ -1083,77 +1170,184 @@ namespace ecs_hpp
namespace ecs_hpp namespace ecs_hpp
{ {
//
// registry::uentity
//
inline registry::uentity::uentity(registry& owner, entity_id id) noexcept
: id_(id)
, owner_(&owner) {}
inline registry::uentity::uentity(entity_id ent) noexcept
: id_(ent) {}
inline registry::uentity::uentity(entity ent) noexcept
: id_(ent.id())
, owner_(&ent.owner()) {}
inline registry::uentity::operator entity_id() const noexcept {
return id_;
}
inline registry::uentity::operator entity() const noexcept {
assert(owner_);
return {*owner_, id_};
}
inline registry::uentity::operator const_entity() const noexcept {
assert(owner_);
return {*owner_, id_};
}
inline entity_id registry::uentity::id() const noexcept {
return id_;
}
inline registry* registry::uentity::owner() noexcept {
return owner_;
}
inline const registry* registry::uentity::owner() const noexcept {
return owner_;
}
inline bool registry::uentity::check_owner(const registry* owner) const noexcept {
return !owner_ || owner_ == owner;
}
//
// registry::const_uentity
//
inline registry::const_uentity::const_uentity(const registry& owner, entity_id id) noexcept
: id_(id)
, owner_(&owner) {}
inline registry::const_uentity::const_uentity(entity_id ent) noexcept
: id_(ent) {}
inline registry::const_uentity::const_uentity(entity ent) noexcept
: id_(ent.id())
, owner_(&ent.owner()) {}
inline registry::const_uentity::const_uentity(const_entity ent) noexcept
: id_(ent.id())
, owner_(&ent.owner()) {}
inline registry::const_uentity::const_uentity(const uentity& ent) noexcept
: id_(ent.id())
, owner_(ent.owner()) {}
inline registry::const_uentity::operator entity_id() const noexcept {
return id_;
}
inline registry::const_uentity::operator const_entity() const noexcept {
assert(owner_);
return {*owner_, id_};
}
inline entity_id registry::const_uentity::id() const noexcept {
return id_;
}
inline const registry* registry::const_uentity::owner() const noexcept {
return owner_;
}
inline bool registry::const_uentity::check_owner(const registry* owner) const noexcept {
return !owner_ || owner_ == owner;
}
//
// registry
//
inline entity registry::create_entity() { inline entity registry::create_entity() {
if ( !free_entity_ids_.empty() ) { if ( !free_entity_ids_.empty() ) {
const auto free_ent_id = free_entity_ids_.back(); const auto free_ent_id = free_entity_ids_.back();
const auto new_ent_id = detail::upgrade_entity_id(free_ent_id); const auto new_ent_id = detail::upgrade_entity_id(free_ent_id);
auto ent = entity(*this, new_ent_id);
entity_ids_.insert(new_ent_id); entity_ids_.insert(new_ent_id);
free_entity_ids_.pop_back(); free_entity_ids_.pop_back();
return ent; return {*this, new_ent_id};
} }
if ( last_entity_id_ < detail::entity_id_index_mask ) { if ( last_entity_id_ < detail::entity_id_index_mask ) {
auto ent = entity(*this, ++last_entity_id_); entity_ids_.insert(last_entity_id_ + 1);
entity_ids_.insert(ent.id()); return {*this, ++last_entity_id_};
return ent;
} }
throw std::logic_error("ecs_hpp::registry (entity index overlow)"); throw std::logic_error("ecs_hpp::registry (entity index overlow)");
} }
inline bool registry::destroy_entity(const entity& ent) { inline bool registry::destroy_entity(const uentity& ent) {
remove_all_components_impl_(ent); assert(ent.check_owner(this));
if ( entity_ids_.unordered_erase(ent.id()) ) { remove_all_components(ent);
free_entity_ids_.push_back(ent.id()); if ( entity_ids_.unordered_erase(ent) ) {
free_entity_ids_.push_back(ent);
return true; return true;
} }
return false; return false;
} }
inline bool registry::is_entity_alive(const const_entity& ent) const noexcept { inline bool registry::alive_entity(const const_uentity& ent) const noexcept {
return is_entity_alive_impl_(ent); assert(ent.check_owner(this));
return entity_ids_.has(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 uentity& ent, Args&&... args) {
if ( !is_entity_alive_impl_(ent) ) { assert(ent.check_owner(this));
if ( !alive_entity(ent) ) {
return false; return false;
} }
get_or_create_storage_<T>().assign( get_or_create_storage_<T>().assign(
ent.id(), ent,
std::forward<Args>(args)...); std::forward<Args>(args)...);
return true; return true;
} }
template < typename T > template < typename T >
bool registry::remove_component(const entity& ent) { bool registry::remove_component(const uentity& ent) {
if ( !is_entity_alive_impl_(ent) ) { assert(ent.check_owner(this));
if ( !alive_entity(ent) ) {
return false; return false;
} }
const detail::component_storage<T>* storage = find_storage_<T>(); detail::component_storage<T>* storage = find_storage_<T>();
return storage return storage
? storage->remove(ent.id()) ? storage->remove(ent)
: false; : false;
} }
template < typename T > template < typename T >
bool registry::exists_component(const const_entity& ent) const noexcept { bool registry::exists_component(const const_uentity& ent) const noexcept {
if ( !is_entity_alive_impl_(ent) ) { assert(ent.check_owner(this));
if ( !alive_entity(ent) ) {
return false; return false;
} }
const detail::component_storage<T>* storage = find_storage_<T>(); const detail::component_storage<T>* storage = find_storage_<T>();
return storage return storage
? storage->exists(ent.id()) ? storage->exists(ent)
: false; : false;
} }
inline std::size_t registry::remove_all_components(const entity& ent) noexcept { inline std::size_t registry::remove_all_components(const uentity& ent) noexcept {
return remove_all_components_impl_(ent); assert(ent.check_owner(this));
if ( !alive_entity(ent) ) {
return 0u;
}
std::size_t removed_count = 0u;
for ( const auto family_id : storages_ ) {
if ( storages_.get(family_id)->remove(ent) ) {
++removed_count;
}
}
return removed_count;
} }
template < typename T > template < typename T >
T& registry::get_component(const entity& ent) { T& registry::get_component(const uentity& ent) {
T* component = find_component_impl_<T>(ent); assert(ent.check_owner(this));
T* component = find_component<T>(ent);
if ( component ) { if ( component ) {
return *component; return *component;
} }
@@ -1161,8 +1355,9 @@ namespace ecs_hpp
} }
template < typename T > template < typename T >
const T& registry::get_component(const const_entity& ent) const { const T& registry::get_component(const const_uentity& ent) const {
const T* component = find_component_impl_<T>(ent); assert(ent.check_owner(this));
const T* component = find_component<T>(ent);
if ( component ) { if ( component ) {
return *component; return *component;
} }
@@ -1170,46 +1365,81 @@ namespace ecs_hpp
} }
template < typename T > template < typename T >
T* registry::find_component(const entity& ent) noexcept { T* registry::find_component(const uentity& ent) noexcept {
return find_component_impl_<T>(ent); assert(ent.check_owner(this));
detail::component_storage<T>* storage = find_storage_<T>();
return storage
? storage->find(ent)
: nullptr;
} }
template < typename T > template < typename T >
const T* registry::find_component(const const_entity& ent) const noexcept { const T* registry::find_component(const const_uentity& ent) const noexcept {
return find_component_impl_<T>(ent); assert(ent.check_owner(this));
const detail::component_storage<T>* storage = find_storage_<T>();
return storage
? storage->find(ent)
: nullptr;
} }
template < typename... Ts > template < typename... Ts >
std::tuple<Ts&...> registry::get_components(const entity& ent) { std::tuple<Ts&...> registry::get_components(const uentity& ent) {
assert(ent.check_owner(this));
return std::make_tuple(std::ref(get_component<Ts>(ent))...); return std::make_tuple(std::ref(get_component<Ts>(ent))...);
} }
template < typename... Ts > template < typename... Ts >
std::tuple<const Ts&...> registry::get_components(const const_entity& ent) const { std::tuple<const Ts&...> registry::get_components(const const_uentity& ent) const {
assert(ent.check_owner(this));
return std::make_tuple(std::cref(get_component<Ts>(ent))...); return std::make_tuple(std::cref(get_component<Ts>(ent))...);
} }
template < typename... Ts > template < typename... Ts >
std::tuple<Ts*...> registry::find_components(const entity& ent) noexcept { std::tuple<Ts*...> registry::find_components(const uentity& ent) noexcept {
assert(ent.check_owner(this));
return std::make_tuple(find_component<Ts>(ent)...); return std::make_tuple(find_component<Ts>(ent)...);
} }
template < typename... Ts > template < typename... Ts >
std::tuple<const Ts*...> registry::find_components(const const_entity& ent) const noexcept { std::tuple<const Ts*...> registry::find_components(const const_uentity& ent) const noexcept {
assert(ent.check_owner(this));
return std::make_tuple(find_component<Ts>(ent)...); return std::make_tuple(find_component<Ts>(ent)...);
} }
template < typename T >
std::size_t registry::component_count() const noexcept {
const detail::component_storage<T>* storage = find_storage_<T>();
return storage
? storage->count()
: 0u;
}
template < typename T >
std::size_t registry::entity_component_count(const const_uentity& ent) const noexcept {
assert(ent.check_owner(this));
if ( !alive_entity(ent) ) {
return 0u;
}
std::size_t component_count = 0u;
for ( const auto family_id : storages_ ) {
if ( storages_.get(family_id)->has(ent) ) {
++component_count;
}
}
return component_count;
}
template < typename F > template < typename F >
void registry::for_each_entity(F&& f) { void registry::for_each_entity(F&& f) {
for ( const auto id : entity_ids_ ) { for ( const auto id : entity_ids_ ) {
f(entity(*this, id)); f({*this, id});
} }
} }
template < typename F > template < typename F >
void registry::for_each_entity(F&& f) const { void registry::for_each_entity(F&& f) const {
for ( const auto id : entity_ids_ ) { for ( const auto id : entity_ids_ ) {
f(const_entity(*this, id)); f({*this, id});
} }
} }
@@ -1217,7 +1447,9 @@ namespace ecs_hpp
void registry::for_each_component(F&& f) { void registry::for_each_component(F&& f) {
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([this, &f](const entity_id e, T& t){
f(uentity{*this, e}, t);
});
} }
} }
@@ -1225,7 +1457,9 @@ namespace ecs_hpp
void registry::for_each_component(F&& f) const { void registry::for_each_component(F&& f) const {
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([this, &f](const entity_id e, const T& t){
f(const_uentity{*this, e}, t);
});
} }
} }
@@ -1289,39 +1523,6 @@ namespace ecs_hpp
storages_.get(family).get()); storages_.get(family).get());
} }
inline bool registry::is_entity_alive_impl_(const const_entity& ent) const noexcept {
return entity_ids_.has(ent.id());
}
inline std::size_t registry::remove_all_components_impl_(const entity& ent) noexcept {
if ( !is_entity_alive_impl_(ent) ) {
return 0u;
}
std::size_t removed_components = 0u;
for ( const auto id : storages_ ) {
if ( storages_.get(id)->remove(ent.id()) ) {
++removed_components;
}
}
return removed_components;
}
template < typename T >
T* registry::find_component_impl_(const entity& ent) noexcept {
detail::component_storage<T>* storage = find_storage_<T>();
return storage
? storage->find(ent.id())
: nullptr;
}
template < typename T >
const T* registry::find_component_impl_(const const_entity& ent) const noexcept {
const detail::component_storage<T>* storage = find_storage_<T>();
return storage
? storage->find(ent.id())
: nullptr;
}
template < typename T template < typename T
, typename... Ts , typename... Ts
, typename F , typename F
@@ -1334,7 +1535,7 @@ namespace ecs_hpp
(void)iseq; (void)iseq;
const auto ss = std::make_tuple(find_storage_<Ts>()...); const auto ss = std::make_tuple(find_storage_<Ts>()...);
if ( !detail::tuple_contains(ss, nullptr) ) { if ( !detail::tuple_contains(ss, nullptr) ) {
for_each_component<T>([this, &f, &ss](const entity& e, T& t) { for_each_component<T>([this, &f, &ss](const uentity& e, T& t) {
for_joined_components_impl_<Ts...>(e, f, ss, t); for_joined_components_impl_<Ts...>(e, f, ss, t);
}); });
} }
@@ -1352,7 +1553,7 @@ namespace ecs_hpp
(void)iseq; (void)iseq;
const auto ss = std::make_tuple(find_storage_<Ts>()...); const auto ss = std::make_tuple(find_storage_<Ts>()...);
if ( !detail::tuple_contains(ss, nullptr) ) { if ( !detail::tuple_contains(ss, nullptr) ) {
for_each_component<T>([this, &f, &ss](const const_entity& e, const T& t) { for_each_component<T>([this, &f, &ss](const const_uentity& e, const T& t) {
detail::as_const(*this).for_joined_components_impl_<Ts...>(e, f, ss, t); detail::as_const(*this).for_joined_components_impl_<Ts...>(e, f, ss, t);
}); });
} }
@@ -1364,12 +1565,12 @@ namespace ecs_hpp
, typename Ss , typename Ss
, typename... Cs > , typename... Cs >
void registry::for_joined_components_impl_( void registry::for_joined_components_impl_(
const entity& e, const uentity& e,
const F& f, const F& f,
const Ss& ss, const Ss& ss,
Cs&... cs) Cs&... cs)
{ {
T* c = std::get<0>(ss)->find(e.id()); T* c = std::get<0>(ss)->find(e);
if ( c ) { if ( c ) {
for_joined_components_impl_<Ts...>( for_joined_components_impl_<Ts...>(
e, e,
@@ -1386,12 +1587,12 @@ namespace ecs_hpp
, typename Ss , typename Ss
, typename... Cs > , typename... Cs >
void registry::for_joined_components_impl_( void registry::for_joined_components_impl_(
const const_entity& e, const const_uentity& e,
const F& f, const F& f,
const Ss& ss, const Ss& ss,
const Cs&... cs) const const Cs&... cs) const
{ {
const T* c = std::get<0>(ss)->find(e.id()); const T* c = std::get<0>(ss)->find(e);
if ( c ) { if ( c ) {
for_joined_components_impl_<Ts...>( for_joined_components_impl_<Ts...>(
e, e,
@@ -1404,7 +1605,7 @@ namespace ecs_hpp
template < typename F, typename... Cs > template < typename F, typename... Cs >
void registry::for_joined_components_impl_( void registry::for_joined_components_impl_(
const entity& e, const uentity& e,
const F& f, const F& f,
const std::tuple<>& ss, const std::tuple<>& ss,
Cs&... cs) Cs&... cs)
@@ -1415,7 +1616,7 @@ namespace ecs_hpp
template < typename F, typename... Cs > template < typename F, typename... Cs >
void registry::for_joined_components_impl_( void registry::for_joined_components_impl_(
const const_entity& e, const const_uentity& e,
const F& f, const F& f,
const std::tuple<>& ss, const std::tuple<>& ss,
const Cs&... cs) const const Cs&... cs) const

View File

@@ -292,8 +292,8 @@ TEST_CASE("registry") {
ecs::entity e2{w}; ecs::entity e2{w};
REQUIRE(e1 == e2); REQUIRE(e1 == e2);
REQUIRE_FALSE(w.is_entity_alive(e1)); REQUIRE_FALSE(w.alive_entity(e1));
REQUIRE_FALSE(w.is_entity_alive(e2)); REQUIRE_FALSE(w.alive_entity(e2));
REQUIRE_FALSE(w.destroy_entity(e1)); REQUIRE_FALSE(w.destroy_entity(e1));
REQUIRE_FALSE(w.destroy_entity(e2)); REQUIRE_FALSE(w.destroy_entity(e2));
@@ -305,16 +305,16 @@ TEST_CASE("registry") {
auto e2 = w.create_entity(); auto e2 = w.create_entity();
REQUIRE(e1 != e2); REQUIRE(e1 != e2);
REQUIRE(w.is_entity_alive(e1)); REQUIRE(w.alive_entity(e1));
REQUIRE(w.is_entity_alive(e2)); REQUIRE(w.alive_entity(e2));
REQUIRE(w.destroy_entity(e1)); REQUIRE(w.destroy_entity(e1));
REQUIRE_FALSE(w.is_entity_alive(e1)); REQUIRE_FALSE(w.alive_entity(e1));
REQUIRE(w.is_entity_alive(e2)); REQUIRE(w.alive_entity(e2));
REQUIRE(w.destroy_entity(e2)); REQUIRE(w.destroy_entity(e2));
REQUIRE_FALSE(w.is_entity_alive(e1)); REQUIRE_FALSE(w.alive_entity(e1));
REQUIRE_FALSE(w.is_entity_alive(e2)); REQUIRE_FALSE(w.alive_entity(e2));
REQUIRE_FALSE(w.destroy_entity(e1)); REQUIRE_FALSE(w.destroy_entity(e1));
REQUIRE_FALSE(w.destroy_entity(e2)); REQUIRE_FALSE(w.destroy_entity(e2));
@@ -372,13 +372,21 @@ TEST_CASE("registry") {
{ {
REQUIRE_FALSE(w.exists_component<position_c>(e1)); REQUIRE_FALSE(w.exists_component<position_c>(e1));
REQUIRE_FALSE(w.exists_component<velocity_c>(e1)); REQUIRE_FALSE(w.exists_component<velocity_c>(e1));
REQUIRE_FALSE(w.component_count<position_c>());
REQUIRE_FALSE(w.entity_component_count<position_c>(e1));
REQUIRE(w.assign_component<position_c>(e1)); REQUIRE(w.assign_component<position_c>(e1));
REQUIRE(w.exists_component<position_c>(e1)); REQUIRE(w.exists_component<position_c>(e1));
REQUIRE_FALSE(w.exists_component<velocity_c>(e1)); REQUIRE_FALSE(w.exists_component<velocity_c>(e1));
REQUIRE(w.component_count<position_c>() == 1u);
REQUIRE(w.component_count<velocity_c>() == 0u);
REQUIRE(w.entity_component_count<position_c>(e1) == 1u);
REQUIRE(w.assign_component<velocity_c>(e1)); REQUIRE(w.assign_component<velocity_c>(e1));
REQUIRE(w.component_count<position_c>() == 1u);
REQUIRE(w.component_count<velocity_c>() == 1u);
REQUIRE(w.entity_component_count<position_c>(e1) == 2u);
REQUIRE(w.exists_component<position_c>(e1)); REQUIRE(w.exists_component<position_c>(e1));
REQUIRE(w.exists_component<velocity_c>(e1)); REQUIRE(w.exists_component<velocity_c>(e1));
@@ -387,6 +395,9 @@ TEST_CASE("registry") {
REQUIRE_FALSE(w.exists_component<position_c>(e1)); REQUIRE_FALSE(w.exists_component<position_c>(e1));
REQUIRE_FALSE(w.exists_component<velocity_c>(e1)); REQUIRE_FALSE(w.exists_component<velocity_c>(e1));
REQUIRE_FALSE(w.component_count<position_c>());
REQUIRE_FALSE(w.component_count<velocity_c>());
REQUIRE_FALSE(w.entity_component_count<position_c>(e1));
} }
{ {
@@ -402,6 +413,11 @@ TEST_CASE("registry") {
REQUIRE(e1.exists_component<position_c>()); REQUIRE(e1.exists_component<position_c>());
REQUIRE(e1.exists_component<velocity_c>()); REQUIRE(e1.exists_component<velocity_c>());
REQUIRE(e1.destroy());
REQUIRE_FALSE(e1.exists_component<position_c>());
REQUIRE_FALSE(e1.exists_component<velocity_c>());
} }
} }
{ {
@@ -431,6 +447,19 @@ TEST_CASE("registry") {
REQUIRE_FALSE(e1.assign_component<position_c>()); REQUIRE_FALSE(e1.assign_component<position_c>());
REQUIRE_FALSE(w.exists_component<position_c>(e1)); REQUIRE_FALSE(w.exists_component<position_c>(e1));
} }
{
ecs::registry w;
auto e1 = w.create_entity();
auto e2 = w.create_entity();
REQUIRE(w.assign_component<position_c>(e1));
REQUIRE(w.assign_component<position_c>(e2));
REQUIRE(w.assign_component<velocity_c>(e2));
REQUIRE(e1.destroy());
}
} }
SECTION("component_accessing") { SECTION("component_accessing") {
{ {
@@ -595,6 +624,17 @@ TEST_CASE("registry") {
e2.assign_component<position_c>(5, 6); e2.assign_component<position_c>(5, 6);
e2.assign_component<velocity_c>(7, 8); e2.assign_component<velocity_c>(7, 8);
{
ecs::entity_id acc1 = 0;
int acc2 = 0;
w.for_each_component<position_c>([&acc1, &acc2](ecs::entity_id id, position_c& p){
acc1 += id;
acc2 += p.x;
});
REQUIRE(acc1 == e1.id() + e2.id());
REQUIRE(acc2 == 6);
}
{ {
ecs::entity_id acc1 = 0; ecs::entity_id acc1 = 0;
int acc2 = 0; int acc2 = 0;
@@ -665,6 +705,19 @@ TEST_CASE("registry") {
e3.assign_component<position_c>(100, 500); e3.assign_component<position_c>(100, 500);
e4.assign_component<velocity_c>(500, 100); e4.assign_component<velocity_c>(500, 100);
{
ecs::entity_id acc1 = 0;
int acc2 = 0;
w.for_joined_components<position_c, velocity_c>([&acc1, &acc2](
ecs::entity_id id, const position_c& p, const velocity_c& v)
{
acc1 += id;
acc2 += p.x + v.x;
});
REQUIRE(acc1 == e1.id() + e2.id());
REQUIRE(acc2 == 16);
}
{ {
ecs::entity_id acc1 = 0; ecs::entity_id acc1 = 0;
int acc2 = 0; int acc2 = 0;
@@ -680,16 +733,30 @@ TEST_CASE("registry") {
{ {
const ecs::registry& ww = w; const ecs::registry& ww = w;
ecs::entity_id acc1 = 0;
int acc2 = 0;
ww.for_joined_components<position_c, velocity_c>([&acc1, &acc2](
ecs::const_entity e, const position_c& p, const velocity_c& v)
{ {
acc1 += e.id(); ecs::entity_id acc1 = 0;
acc2 += p.x + v.x; int acc2 = 0;
}); ww.for_joined_components<position_c, velocity_c>([&acc1, &acc2](
REQUIRE(acc1 == e1.id() + e2.id()); ecs::entity_id id, const position_c& p, const velocity_c& v)
REQUIRE(acc2 == 16); {
acc1 += id;
acc2 += p.x + v.x;
});
REQUIRE(acc1 == e1.id() + e2.id());
REQUIRE(acc2 == 16);
}
{
ecs::entity_id acc1 = 0;
int acc2 = 0;
ww.for_joined_components<position_c, velocity_c>([&acc1, &acc2](
ecs::const_entity e, const position_c& p, const velocity_c& v)
{
acc1 += e.id();
acc2 += p.x + v.x;
});
REQUIRE(acc1 == e1.id() + e2.id());
REQUIRE(acc2 == 16);
}
} }
} }
{ {
@@ -740,15 +807,15 @@ TEST_CASE("registry") {
TEST_CASE("example") { TEST_CASE("example") {
struct position_component { struct position_component {
float x{0}; float x;
float y{0}; float y;
position_component(float nx, float ny) position_component(float nx, float ny)
: x(nx), y(ny) {} : x(nx), y(ny) {}
}; };
struct velocity_component { struct velocity_component {
float dx{0}; float dx;
float dy{0}; float dy;
velocity_component(float ndx, float ndy) velocity_component(float ndx, float ndy)
: dx(ndx), dy(ndy) {} : dx(ndx), dy(ndy) {}
}; };
@@ -759,7 +826,7 @@ TEST_CASE("example") {
owner.for_joined_components< owner.for_joined_components<
position_component, position_component,
velocity_component velocity_component
>([](const ecs_hpp::entity& e, position_component& p, const velocity_component& v) { >([](const ecs_hpp::entity&, position_component& p, const velocity_component& v) {
p.x += v.dx; p.x += v.dx;
p.y += v.dy; p.y += v.dy;
}); });
@@ -774,7 +841,7 @@ TEST_CASE("example") {
void process(ecs_hpp::registry& owner) override { void process(ecs_hpp::registry& owner) override {
owner.for_each_component< owner.for_each_component<
velocity_component velocity_component
>([this](const ecs_hpp::entity& e, velocity_component& v) { >([this](const ecs_hpp::entity&, velocity_component& v) {
v.dx += gravity_; v.dx += gravity_;
v.dy += gravity_; v.dy += gravity_;
}); });