dummy component storage

This commit is contained in:
2018-12-25 19:18:26 +07:00
parent 89a52de8b8
commit 828b4ab07e
2 changed files with 207 additions and 1 deletions

169
ecs.hpp
View File

@@ -11,11 +11,13 @@
#include <cstdint>
#include <mutex>
#include <memory>
#include <limits>
#include <utility>
#include <functional>
#include <type_traits>
#include <unordered_set>
#include <unordered_map>
// -----------------------------------------------------------------------------
//
@@ -42,7 +44,7 @@ namespace ecs_hpp
// -----------------------------------------------------------------------------
//
// detail
// detail::type_family
//
// -----------------------------------------------------------------------------
@@ -74,6 +76,52 @@ namespace ecs_hpp
}
}
// -----------------------------------------------------------------------------
//
// detail::component_storage
//
// -----------------------------------------------------------------------------
namespace ecs_hpp
{
namespace detail
{
class component_storage_base {
public:
virtual ~component_storage_base() = default;
virtual bool remove(entity_id id) noexcept = 0;
virtual bool exists(entity_id id) const noexcept = 0;
};
template < typename T >
class component_storage : public component_storage_base {
public:
template < typename... Args >
void assign(entity_id id, Args&&... args);
bool remove(entity_id id) noexcept override;
bool exists(entity_id id) const noexcept override;
private:
std::unordered_map<entity_id, T> components_;
};
template < typename T >
template < typename... Args >
void component_storage<T>::assign(entity_id id, Args&&... args) {
components_[id] = T(std::forward<Args>(args)...);
}
template < typename T >
bool component_storage<T>::remove(entity_id id) noexcept {
return components_.erase(id) > 0u;
}
template < typename T >
bool component_storage<T>::exists(entity_id id) const noexcept {
return components_.find(id) != components_.end();
}
}
}
// -----------------------------------------------------------------------------
//
// entity
@@ -91,6 +139,18 @@ namespace ecs_hpp
entity_id id() const noexcept;
bool destroy();
bool is_alive() const noexcept;
template < typename T, typename... Args >
void assign_component(Args&&... args);
template < typename T >
bool remove_component();
template < typename T >
bool exists_component() const noexcept;
std::size_t remove_all_components() noexcept;
private:
world& owner_;
entity_id id_{0u};
@@ -128,10 +188,30 @@ namespace ecs_hpp
entity create_entity();
bool destroy_entity(const entity& ent);
bool is_entity_alive(const entity& ent) const noexcept;
template < typename T, typename... Args >
void assign_component(const entity& ent, Args&&... args);
template < typename T >
bool remove_component(const entity& ent);
template < typename T >
bool exists_component(const entity& ent) const noexcept;
std::size_t remove_all_components(const entity& ent) const noexcept;
private:
template < typename T >
detail::component_storage<T>* find_storage_() const;
template < typename T >
detail::component_storage<T>& get_or_create_storage_();
private:
mutable std::mutex mutex_;
entity_id last_entity_id_{0u};
std::unordered_set<entity> entities_;
using storage_uptr = std::unique_ptr<detail::component_storage_base>;
std::unordered_map<family_id, storage_uptr> storages_;
};
}
@@ -162,6 +242,31 @@ namespace ecs_hpp
return owner_.destroy_entity(*this);
}
inline bool entity::is_alive() const noexcept {
return owner_.is_entity_alive(*this);
}
template < typename T, typename... Args >
void entity::assign_component(Args&&... args) {
owner_.assign_component<T>(
*this,
std::forward<Args>(args)...);
}
template < typename T >
bool entity::remove_component() {
return owner_.remove_component<T>(*this);
}
template < typename T >
bool entity::exists_component() const noexcept {
return owner_.exists_component<T>(*this);
}
inline std::size_t entity::remove_all_components() noexcept {
return owner_.remove_all_components(*this);
}
inline bool operator==(const entity& l, const entity& r) noexcept {
return l.id() == r.id();
}
@@ -199,4 +304,66 @@ namespace ecs_hpp
std::lock_guard<std::mutex> guard(mutex_);
return entities_.count(ent) > 0u;
}
template < typename T, typename... Args >
void world::assign_component(const entity& ent, Args&&... args) {
std::lock_guard<std::mutex> guard(mutex_);
get_or_create_storage_<T>().assign(
ent.id(),
std::forward<Args>(args)...);
}
template < typename T >
bool world::remove_component(const entity& ent) {
std::lock_guard<std::mutex> guard(mutex_);
const detail::component_storage<T>* storage = find_storage_<T>();
return storage
? storage->remove(ent.id())
: false;
}
template < typename T >
bool world::exists_component(const entity& ent) const noexcept {
std::lock_guard<std::mutex> guard(mutex_);
const detail::component_storage<T>* storage = find_storage_<T>();
return storage
? storage->exists(ent.id())
: false;
}
inline std::size_t world::remove_all_components(const entity& ent) const noexcept {
std::lock_guard<std::mutex> guard(mutex_);
std::size_t removed_components = 0u;
for ( auto& storage_p : storages_ ) {
if ( storage_p.second->remove(ent.id()) ) {
++removed_components;
}
}
return removed_components;
}
template < typename T >
detail::component_storage<T>* world::find_storage_() const {
const auto family = detail::type_family<T>::id();
const auto iter = storages_.find(family);
if ( iter != storages_.end() ) {
return static_cast<detail::component_storage<T>*>(iter->second.get());
}
return nullptr;
}
template < typename T >
detail::component_storage<T>& world::get_or_create_storage_() {
detail::component_storage<T>* storage = find_storage_<T>();
if ( storage ) {
return *storage;
}
const auto family = detail::type_family<T>::id();
const auto emplace_r = storages_.emplace(std::make_pair(
family,
std::make_unique<detail::component_storage<T>>()));
assert(emplace_r.second && "unexpected internal error");
return *static_cast<detail::component_storage<T>*>(
emplace_r.first->second.get());
}
}

View File

@@ -80,5 +80,44 @@ TEST_CASE("world") {
}
}
SECTION("components") {
{
ecs::world w;
ecs::entity e1{w};
{
REQUIRE_FALSE(w.exists_component<position_c>(e1));
REQUIRE_FALSE(w.exists_component<velocity_c>(e1));
w.assign_component<position_c>(e1);
REQUIRE(w.exists_component<position_c>(e1));
REQUIRE_FALSE(w.exists_component<velocity_c>(e1));
w.assign_component<velocity_c>(e1);
REQUIRE(w.exists_component<position_c>(e1));
REQUIRE(w.exists_component<velocity_c>(e1));
REQUIRE(w.remove_all_components(e1) == 2u);
REQUIRE_FALSE(w.exists_component<position_c>(e1));
REQUIRE_FALSE(w.exists_component<velocity_c>(e1));
}
{
REQUIRE_FALSE(e1.exists_component<position_c>());
REQUIRE_FALSE(e1.exists_component<velocity_c>());
e1.assign_component<position_c>();
REQUIRE(e1.exists_component<position_c>());
REQUIRE_FALSE(e1.exists_component<velocity_c>());
e1.assign_component<velocity_c>();
REQUIRE(e1.exists_component<position_c>());
REQUIRE(e1.exists_component<velocity_c>());
}
}
}
}