mirror of
https://github.com/BlackMATov/ecs.hpp.git
synced 2025-12-16 14:11:14 +07:00
empty component storage optimization
This commit is contained in:
187
ecs.hpp
187
ecs.hpp
@@ -659,103 +659,142 @@ namespace ecs_hpp
|
|||||||
virtual std::size_t memory_usage() const noexcept = 0;
|
virtual std::size_t memory_usage() const noexcept = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
template < typename T >
|
template < typename T, bool E = std::is_empty<T>::value >
|
||||||
class component_storage final : public component_storage_base {
|
class component_storage final : public component_storage_base {
|
||||||
public:
|
public:
|
||||||
component_storage(registry& owner);
|
component_storage(registry& owner)
|
||||||
|
: owner_(owner) {}
|
||||||
|
|
||||||
template < typename... Args >
|
template < typename... Args >
|
||||||
T& assign(entity_id id, Args&&... args);
|
T& assign(entity_id id, Args&&... args) {
|
||||||
bool exists(entity_id id) const noexcept;
|
components_.insert_or_assign(id, T(std::forward<Args>(args)...));
|
||||||
bool remove(entity_id id) noexcept override;
|
return components_.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
T* find(entity_id id) noexcept;
|
bool exists(entity_id id) const noexcept {
|
||||||
const T* find(entity_id id) const noexcept;
|
return components_.has(id);
|
||||||
|
}
|
||||||
|
|
||||||
std::size_t count() const noexcept;
|
bool remove(entity_id id) noexcept override {
|
||||||
bool has(entity_id id) const noexcept override;
|
return components_.unordered_erase(id);
|
||||||
void clone(entity_id from, entity_id to) override;
|
}
|
||||||
|
|
||||||
|
T* find(entity_id id) noexcept {
|
||||||
|
return components_.find(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
const T* find(entity_id id) const noexcept {
|
||||||
|
return components_.find(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t count() const noexcept {
|
||||||
|
return components_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has(entity_id id) const noexcept override {
|
||||||
|
return components_.has(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clone(entity_id from, entity_id to) override {
|
||||||
|
const T* c = components_.find(from);
|
||||||
|
if ( c ) {
|
||||||
|
components_.insert_or_assign(to, *c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template < typename F >
|
template < typename F >
|
||||||
void for_each_component(F&& f);
|
void for_each_component(F&& f) {
|
||||||
template < typename F >
|
for ( const entity_id id : components_ ) {
|
||||||
void for_each_component(F&& f) const;
|
f(id, components_.get(id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::size_t memory_usage() const noexcept override;
|
template < typename F >
|
||||||
|
void for_each_component(F&& f) const {
|
||||||
|
for ( const entity_id id : components_ ) {
|
||||||
|
f(id, components_.get(id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t memory_usage() const noexcept override {
|
||||||
|
return components_.memory_usage();
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
registry& owner_;
|
registry& owner_;
|
||||||
detail::sparse_map<entity_id, T, entity_id_indexer> components_;
|
detail::sparse_map<entity_id, T, entity_id_indexer> components_;
|
||||||
};
|
};
|
||||||
|
|
||||||
template < typename T >
|
template < typename T >
|
||||||
component_storage<T>::component_storage(registry& owner)
|
class component_storage<T, true> final : public component_storage_base {
|
||||||
: owner_(owner) {}
|
public:
|
||||||
|
component_storage(registry& owner)
|
||||||
|
: owner_(owner) {}
|
||||||
|
|
||||||
template < typename T >
|
template < typename... Args >
|
||||||
template < typename... Args >
|
T& assign(entity_id id, Args&&... args) {
|
||||||
T& component_storage<T>::assign(entity_id id, Args&&... args) {
|
components_.insert(id);
|
||||||
components_.insert_or_assign(id, T(std::forward<Args>(args)...));
|
return empty_value_;
|
||||||
return components_.get(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
template < typename T >
|
|
||||||
bool component_storage<T>::exists(entity_id id) const noexcept {
|
|
||||||
return components_.has(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
template < typename T >
|
|
||||||
bool component_storage<T>::remove(entity_id id) noexcept {
|
|
||||||
return components_.unordered_erase(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
template < typename T >
|
|
||||||
T* component_storage<T>::find(entity_id id) noexcept {
|
|
||||||
return components_.find(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
template < typename T >
|
|
||||||
const T* component_storage<T>::find(entity_id id) const noexcept {
|
|
||||||
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 >
|
|
||||||
void component_storage<T>::clone(entity_id from, entity_id to) {
|
|
||||||
const T* c = components_.find(from);
|
|
||||||
if ( c ) {
|
|
||||||
components_.insert_or_assign(to, *c);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
template < typename T >
|
bool exists(entity_id id) const noexcept {
|
||||||
template < typename F >
|
return components_.has(id);
|
||||||
void component_storage<T>::for_each_component(F&& f) {
|
|
||||||
for ( const entity_id id : components_ ) {
|
|
||||||
f(id, components_.get(id));
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
template < typename T >
|
bool remove(entity_id id) noexcept override {
|
||||||
template < typename F >
|
return components_.unordered_erase(id);
|
||||||
void component_storage<T>::for_each_component(F&& f) const {
|
|
||||||
for ( const entity_id id : components_ ) {
|
|
||||||
f(id, components_.get(id));
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
T* find(entity_id id) noexcept {
|
||||||
|
return components_.has(id)
|
||||||
|
? &empty_value_
|
||||||
|
: nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
const T* find(entity_id id) const noexcept {
|
||||||
|
return components_.has(id)
|
||||||
|
? &empty_value_
|
||||||
|
: nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t count() const noexcept {
|
||||||
|
return components_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has(entity_id id) const noexcept override {
|
||||||
|
return components_.has(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clone(entity_id from, entity_id to) override {
|
||||||
|
if ( components_.has(from) ) {
|
||||||
|
components_.insert(to);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename F >
|
||||||
|
void for_each_component(F&& f) {
|
||||||
|
for ( const entity_id id : components_ ) {
|
||||||
|
f(id, empty_value_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template < typename F >
|
||||||
|
void for_each_component(F&& f) const {
|
||||||
|
for ( const entity_id id : components_ ) {
|
||||||
|
f(id, empty_value_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t memory_usage() const noexcept override {
|
||||||
|
return components_.memory_usage();
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
registry& owner_;
|
||||||
|
static T empty_value_;
|
||||||
|
detail::sparse_set<entity_id, entity_id_indexer> components_;
|
||||||
|
};
|
||||||
|
|
||||||
template < typename T >
|
template < typename T >
|
||||||
std::size_t component_storage<T>::memory_usage() const noexcept {
|
T component_storage<T, true>::empty_value_;
|
||||||
return components_.memory_usage();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,10 @@ namespace
|
|||||||
velocity_c(int nx, int ny) : x(nx), y(ny) {}
|
velocity_c(int nx, int ny) : x(nx), y(ny) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct movable_c {
|
||||||
|
};
|
||||||
|
static_assert(std::is_empty<movable_c>::value, "!!!");
|
||||||
|
|
||||||
bool operator==(const position_c& l, const position_c& r) noexcept {
|
bool operator==(const position_c& l, const position_c& r) noexcept {
|
||||||
return l.x == r.x
|
return l.x == r.x
|
||||||
&& l.y == r.y;
|
&& l.y == r.y;
|
||||||
@@ -1226,6 +1230,29 @@ TEST_CASE("registry") {
|
|||||||
3 * sizeof(std::size_t) +
|
3 * sizeof(std::size_t) +
|
||||||
1 * sizeof(ecs::entity_id));
|
1 * sizeof(ecs::entity_id));
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
ecs::registry w;
|
||||||
|
auto e1 = w.create_entity();
|
||||||
|
auto e2 = w.create_entity();
|
||||||
|
e1.assign_component<movable_c>();
|
||||||
|
e2.assign_component<movable_c>();
|
||||||
|
REQUIRE(w.component_memory_usage<movable_c>() ==
|
||||||
|
4 * sizeof(std::size_t) +
|
||||||
|
2 * sizeof(ecs::entity_id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SECTION("empty_component") {
|
||||||
|
ecs::registry w;
|
||||||
|
auto e1 = w.create_entity();
|
||||||
|
ecs::entity_filler(e1)
|
||||||
|
.component<movable_c>()
|
||||||
|
.component<position_c>(1, 2)
|
||||||
|
.component<velocity_c>(3, 4);
|
||||||
|
REQUIRE(w.exists_component<movable_c>(e1));
|
||||||
|
REQUIRE(w.find_component<movable_c>(e1));
|
||||||
|
w.for_joined_components<movable_c, position_c>([
|
||||||
|
](const ecs::const_entity&, movable_c&, position_c&){
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user