diff options
author | Clyne Sullivan <tullivan99@gmail.com> | 2017-01-10 21:26:13 -0500 |
---|---|---|
committer | Clyne Sullivan <tullivan99@gmail.com> | 2017-01-10 21:26:13 -0500 |
commit | f800dbc034e7a70a613bab8cd9d147be4f6e88b6 (patch) | |
tree | c8714ddc8f6712f07d921c08fd92ae8ef228494b /entityx/Entity.h | |
parent | c6651145a4a6e6611b585c1a87c127f38751db4b (diff) |
windows build
Diffstat (limited to 'entityx/Entity.h')
-rw-r--r-- | entityx/Entity.h | 1104 |
1 files changed, 1104 insertions, 0 deletions
diff --git a/entityx/Entity.h b/entityx/Entity.h new file mode 100644 index 0000000..3217ae5 --- /dev/null +++ b/entityx/Entity.h @@ -0,0 +1,1104 @@ +/* + * Copyright (C) 2012 Alec Thomas <alec@swapoff.org> + * All rights reserved. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. + * + * Author: Alec Thomas <alec@swapoff.org> + */ + +#pragma once + + +#include <cstdint> +#include <tuple> +#include <new> +#include <cstdlib> +#include <algorithm> +#include <bitset> +#include <cassert> +#include <iostream> +#include <iterator> +#include <list> +#include <memory> +#include <set> +#include <string> +#include <utility> +#include <vector> +#include <type_traits> + #include <functional> + +#include "entityx/help/Pool.h" +#include "entityx/config.h" +#include "entityx/Event.h" +#include "entityx/help/NonCopyable.h" + +namespace entityx { + +typedef std::uint32_t uint32_t; +typedef std::uint64_t uint64_t; + +class EntityManager; + + +template <typename C, typename EM = EntityManager> +class ComponentHandle; + + + +/** A convenience handle around an Entity::Id. + * + * If an entity is destroyed, any copies will be invalidated. Use valid() to + * check for validity before using. + * + * Create entities with `EntityManager`: + * + * Entity entity = entity_manager->create(); + */ +class Entity { +public: + struct Id { + Id() : id_(0) {} + explicit Id(uint64_t id) : id_(id) {} + Id(uint32_t index, uint32_t version) : id_(uint64_t(index) | uint64_t(version) << 32UL) {} + + uint64_t id() const { return id_; } + + bool operator == (const Id &other) const { return id_ == other.id_; } + bool operator != (const Id &other) const { return id_ != other.id_; } + bool operator < (const Id &other) const { return id_ < other.id_; } + + uint32_t index() const { return id_ & 0xffffffffUL; } + uint32_t version() const { return id_ >> 32; } + + private: + friend class EntityManager; + + uint64_t id_; + }; + + + /** + * Id of an invalid Entity. + */ + static const Id INVALID; + + Entity() = default; + Entity(EntityManager *manager, Entity::Id id) : manager_(manager), id_(id) {} + Entity(const Entity &other) = default; + Entity &operator = (const Entity &other) = default; + + /** + * Check if Entity handle is invalid. + */ + operator bool() const { + return valid(); + } + + bool operator == (const Entity &other) const { + return other.manager_ == manager_ && other.id_ == id_; + } + + bool operator != (const Entity &other) const { + return !(other == *this); + } + + bool operator < (const Entity &other) const { + return other.id_ < id_; + } + + /** + * Is this Entity handle valid? + * + * In older versions of EntityX, there were no guarantees around entity + * validity if a previously allocated entity slot was reassigned. That is no + * longer the case: if a slot is reassigned, old Entity::Id's will be + * invalid. + */ + bool valid() const; + + /** + * Invalidate Entity handle, disassociating it from an EntityManager and invalidating its ID. + * + * Note that this does *not* affect the underlying entity and its + * components. Use destroy() to destroy the associated Entity and components. + */ + void invalidate(); + + Id id() const { return id_; } + + template <typename C, typename ... Args> + ComponentHandle<C> assign(Args && ... args); + + template <typename C> + ComponentHandle<C> assign_from_copy(const C &component); + + template <typename C, typename ... Args> + ComponentHandle<C> replace(Args && ... args); + + template <typename C> + void remove(); + + template <typename C, typename = typename std::enable_if<!std::is_const<C>::value>::type> + ComponentHandle<C> component(); + + template <typename C, typename = typename std::enable_if<std::is_const<C>::value>::type> + const ComponentHandle<C, const EntityManager> component() const; + + template <typename ... Components> + std::tuple<ComponentHandle<Components>...> components(); + + template <typename ... Components> + std::tuple<ComponentHandle<const Components, const EntityManager>...> components() const; + + template <typename C> + bool has_component() const; + + template <typename A, typename ... Args> + void unpack(ComponentHandle<A> &a, ComponentHandle<Args> & ... args); + + /** + * Destroy and invalidate this Entity. + */ + void destroy(); + + std::bitset<entityx::MAX_COMPONENTS> component_mask() const; + + private: + EntityManager *manager_ = nullptr; + Entity::Id id_ = INVALID; +}; + + +/** + * A ComponentHandle<C> is a wrapper around an instance of a component. + * + * It provides safe access to components. The handle will be invalidated under + * the following conditions: + * + * - If a component is removed from its host entity. + * - If its host entity is destroyed. + */ +template <typename C, typename EM> +class ComponentHandle { +public: + typedef C ComponentType; + + ComponentHandle() : manager_(nullptr) {} + + bool valid() const; + operator bool() const; + + C *operator -> (); + const C *operator -> () const; + + C &operator * (); + const C &operator * () const; + + C *get(); + const C *get() const; + + /** + * Remove the component from its entity and destroy it. + */ + void remove(); + + /** + * Returns the Entity associated with the component + */ + Entity entity(); + + bool operator == (const ComponentHandle<C> &other) const { + return manager_ == other.manager_ && id_ == other.id_; + } + + bool operator != (const ComponentHandle<C> &other) const { + return !(*this == other); + } + +private: + friend class EntityManager; + + ComponentHandle(EM *manager, Entity::Id id) : + manager_(manager), id_(id) {} + + EM *manager_; + Entity::Id id_; +}; + + +/** + * Base component class, only used for insertion into collections. + * + * Family is used for registration. + */ +struct BaseComponent { + public: + typedef size_t Family; + + // NOTE: Component memory is *always* managed by the EntityManager. + // Use Entity::destroy() instead. + void operator delete(void *p) { (void)p; fail(); } + void operator delete[](void *p) { (void)p; fail(); } + + + protected: + static void fail() { +#if defined(_HAS_EXCEPTIONS) || defined(__EXCEPTIONS) + throw std::bad_alloc(); +#else + std::abort(); +#endif + } + + static Family family_counter_; +}; + + +/** + * Component implementations should inherit from this. + * + * Components MUST provide a no-argument constructor. + * Components SHOULD provide convenience constructors for initializing on assignment to an Entity::Id. + * + * This is a struct to imply that components should be data-only. + * + * Usage: + * + * struct Position : public Component<Position> { + * Position(float x = 0.0f, float y = 0.0f) : x(x), y(y) {} + * + * float x, y; + * }; + * + * family() is used for registration. + */ +template <typename Derived> +struct Component : public BaseComponent { + public: + typedef ComponentHandle<Derived> Handle; + typedef ComponentHandle<const Derived, const EntityManager> ConstHandle; + +private: + friend class EntityManager; + /// Used internally for registration. + static Family family(); +}; + + +/** + * Emitted when an entity is added to the system. + */ +struct EntityCreatedEvent : public Event<EntityCreatedEvent> { + explicit EntityCreatedEvent(Entity entity) : entity(entity) {} + virtual ~EntityCreatedEvent(); + + Entity entity; +}; + + +/** + * Called just prior to an entity being destroyed. + */ +struct EntityDestroyedEvent : public Event<EntityDestroyedEvent> { + explicit EntityDestroyedEvent(Entity entity) : entity(entity) {} + virtual ~EntityDestroyedEvent(); + + Entity entity; +}; + + +/** + * Emitted when any component is added to an entity. + */ +template <typename C> +struct ComponentAddedEvent : public Event<ComponentAddedEvent<C>> { + ComponentAddedEvent(Entity entity, ComponentHandle<C> component) : + entity(entity), component(component) {} + + Entity entity; + ComponentHandle<C> component; +}; + +/** + * Emitted when any component is removed from an entity. + */ +template <typename C> +struct ComponentRemovedEvent : public Event<ComponentRemovedEvent<C>> { + ComponentRemovedEvent(Entity entity, ComponentHandle<C> component) : + entity(entity), component(component) {} + + Entity entity; + ComponentHandle<C> component; +}; + +/** + * Helper class to perform component operations in a typed manner. + */ +class BaseComponentHelper { +public: + virtual ~BaseComponentHelper() {} + virtual void remove_component(Entity e) = 0; + virtual void copy_component_to(Entity source, Entity target) = 0; +}; + +template <typename C> +class ComponentHelper : public BaseComponentHelper { +public: + void remove_component(Entity e) override { + e.remove<C>(); + } + void copy_component_to(Entity source, Entity target) override { + target.assign_from_copy<C>(*(source.component<C>().get())); + } +}; + +/** + * Manages Entity::Id creation and component assignment. + */ +class EntityManager : entityx::help::NonCopyable { + public: + typedef std::bitset<entityx::MAX_COMPONENTS> ComponentMask; + + explicit EntityManager(EventManager &event_manager); + virtual ~EntityManager(); + + /// An iterator over a view of the entities in an EntityManager. + /// If All is true it will iterate over all valid entities and will ignore the entity mask. + template <class Delegate, bool All = false> + class ViewIterator : public std::iterator<std::input_iterator_tag, Entity::Id> { + public: + Delegate &operator ++() { + ++i_; + next(); + return *static_cast<Delegate*>(this); + } + bool operator == (const Delegate& rhs) const { return i_ == rhs.i_; } + bool operator != (const Delegate& rhs) const { return i_ != rhs.i_; } + Entity operator * () { return Entity(manager_, manager_->create_id(i_)); } + const Entity operator * () const { return Entity(manager_, manager_->create_id(i_)); } + + protected: + ViewIterator(EntityManager *manager, uint32_t index) + : manager_(manager), i_(index), capacity_(manager_->capacity()), free_cursor_(~0UL) { + if (All) { + std::sort(manager_->free_list_.begin(), manager_->free_list_.end()); + free_cursor_ = 0; + } + } + ViewIterator(EntityManager *manager, const ComponentMask mask, uint32_t index) + : manager_(manager), mask_(mask), i_(index), capacity_(manager_->capacity()), free_cursor_(~0UL) { + if (All) { + std::sort(manager_->free_list_.begin(), manager_->free_list_.end()); + free_cursor_ = 0; + } + } + + void next() { + while (i_ < capacity_ && !predicate()) { + ++i_; + } + + if (i_ < capacity_) { + Entity entity = manager_->get(manager_->create_id(i_)); + static_cast<Delegate*>(this)->next_entity(entity); + } + } + + inline bool predicate() { + return (All && valid_entity()) || (manager_->entity_component_mask_[i_] & mask_) == mask_; + } + + inline bool valid_entity() { + const std::vector<uint32_t> &free_list = manager_->free_list_; + if (free_cursor_ < free_list.size() && free_list[free_cursor_] == i_) { + ++free_cursor_; + return false; + } + return true; + } + + EntityManager *manager_; + ComponentMask mask_; + uint32_t i_; + size_t capacity_; + size_t free_cursor_; + }; + + template <bool All> + class BaseView { + public: + class Iterator : public ViewIterator<Iterator, All> { + public: + Iterator(EntityManager *manager, + const ComponentMask mask, + uint32_t index) : ViewIterator<Iterator, All>(manager, mask, index) { + ViewIterator<Iterator, All>::next(); + } + + void next_entity(Entity &entity) { (void)entity; } + }; + + Iterator begin() { return Iterator(manager_, mask_, 0); } + Iterator end() { return Iterator(manager_, mask_, uint32_t(manager_->capacity())); } + const Iterator begin() const { return Iterator(manager_, mask_, 0); } + const Iterator end() const { return Iterator(manager_, mask_, manager_->capacity()); } + + private: + friend class EntityManager; + + explicit BaseView(EntityManager *manager) : manager_(manager) { mask_.set(); } + BaseView(EntityManager *manager, ComponentMask mask) : + manager_(manager), mask_(mask) {} + + EntityManager *manager_; + ComponentMask mask_; + }; + + template <bool All, typename ... Components> + class TypedView: public BaseView<All> { + public: + template <typename T> struct identity { typedef T type; }; + + void each(typename identity<std::function<void(Entity entity, Components&...)>>::type f) { + for (auto it : *this) + f(it, *(it.template component<Components>().get())...); + } + + private: + friend class EntityManager; + + explicit TypedView(EntityManager *manager) : BaseView<All>(manager) {} + TypedView(EntityManager *manager, ComponentMask mask) : BaseView<All>(manager, mask) {} + }; + + template <typename ... Components> using View = TypedView<false, Components...>; + typedef BaseView<true> DebugView; + + template <typename ... Components> + class UnpackingView { + public: + struct Unpacker { + explicit Unpacker(ComponentHandle<Components> & ... handles) : + handles(std::tuple<ComponentHandle<Components> & ...>(handles...)) {} + + void unpack(entityx::Entity &entity) const { + unpack_<0, Components...>(entity); + } + + + private: + template <int N, typename C> + void unpack_(entityx::Entity &entity) const { + std::get<N>(handles) = entity.component<C>(); + } + + template <int N, typename C0, typename C1, typename ... Cn> + void unpack_(entityx::Entity &entity) const { + std::get<N>(handles) = entity.component<C0>(); + unpack_<N + 1, C1, Cn...>(entity); + } + + std::tuple<ComponentHandle<Components> & ...> handles; + }; + + + class Iterator : public ViewIterator<Iterator> { + public: + Iterator(EntityManager *manager, + const ComponentMask mask, + uint32_t index, + const Unpacker &unpacker) : ViewIterator<Iterator>(manager, mask, index), unpacker_(unpacker) { + ViewIterator<Iterator>::next(); + } + + void next_entity(Entity &entity) { + unpacker_.unpack(entity); + } + + private: + const Unpacker &unpacker_; + }; + + + Iterator begin() { return Iterator(manager_, mask_, 0, unpacker_); } + Iterator end() { return Iterator(manager_, mask_, static_cast<uint32_t>(manager_->capacity()), unpacker_); } + const Iterator begin() const { return Iterator(manager_, mask_, 0, unpacker_); } + const Iterator end() const { return Iterator(manager_, mask_, static_cast<uint32_t>(manager_->capacity()), unpacker_); } + + + private: + friend class EntityManager; + + UnpackingView(EntityManager *manager, ComponentMask mask, ComponentHandle<Components> & ... handles) : + manager_(manager), mask_(mask), unpacker_(handles...) {} + + EntityManager *manager_; + ComponentMask mask_; + Unpacker unpacker_; + }; + + /** + * Number of managed entities. + */ + size_t size() const { return entity_component_mask_.size() - free_list_.size(); } + + /** + * Current entity capacity. + */ + size_t capacity() const { return entity_component_mask_.size(); } + + /** + * Return true if the given entity ID is still valid. + */ + bool valid(Entity::Id id) const { + return id.index() < entity_version_.size() && entity_version_[id.index()] == id.version(); + } + + /** + * Create a new Entity::Id. + * + * Emits EntityCreatedEvent. + */ + Entity create() { + uint32_t index, version; + if (free_list_.empty()) { + index = index_counter_++; + accomodate_entity(index); + version = entity_version_[index] = 1; + } else { + index = free_list_.back(); + free_list_.pop_back(); + version = entity_version_[index]; + } + Entity entity(this, Entity::Id(index, version)); + event_manager_.emit<EntityCreatedEvent>(entity); + return entity; + } + + /** + * Create a new Entity by copying another. Copy-constructs each component. + * + * Emits EntityCreatedEvent. + */ + Entity create_from_copy(Entity original) { + assert(original.valid()); + auto clone = create(); + auto mask = original.component_mask(); + for (size_t i = 0; i < component_helpers_.size(); i++) { + BaseComponentHelper *helper = component_helpers_[i]; + if (helper && mask.test(i)) + helper->copy_component_to(original, clone); + } + return clone; + } + + + /** + * Destroy an existing Entity::Id and its associated Components. + * + * Emits EntityDestroyedEvent. + */ + void destroy(Entity::Id entity) { + assert_valid(entity); + uint32_t index = entity.index(); + auto mask = entity_component_mask_[index]; + for (size_t i = 0; i < component_helpers_.size(); i++) { + BaseComponentHelper *helper = component_helpers_[i]; + if (helper && mask.test(i)) + helper->remove_component(Entity(this, entity)); + } + event_manager_.emit<EntityDestroyedEvent>(Entity(this, entity)); + entity_component_mask_[index].reset(); + entity_version_[index]++; + free_list_.push_back(index); + } + + Entity get(Entity::Id id) { + assert_valid(id); + return Entity(this, id); + } + + /** + * Create an Entity::Id for a slot. + * + * NOTE: Does *not* check for validity, but the Entity::Id constructor will + * fail if the ID is invalid. + */ + Entity::Id create_id(uint32_t index) const { + return Entity::Id(index, entity_version_[index]); + } + + /** + * Assign a Component to an Entity::Id, passing through Component constructor arguments. + * + * Position &position = em.assign<Position>(e, x, y); + * + * @returns Smart pointer to newly created component. + */ + template <typename C, typename ... Args> + ComponentHandle<C> assign(Entity::Id id, Args && ... args) { + assert_valid(id); + const BaseComponent::Family family = component_family<C>(); + assert(!entity_component_mask_[id.index()].test(family)); + + // Placement new into the component pool. + Pool<C> *pool = accomodate_component<C>(); + ::new(pool->get(id.index())) C(std::forward<Args>(args) ...); + + // Set the bit for this component. + entity_component_mask_[id.index()].set(family); + + // Create and return handle. + ComponentHandle<C> component(this, id); + event_manager_.emit<ComponentAddedEvent<C>>(Entity(this, id), component); + return component; + } + + /** + * Remove a Component from an Entity::Id + * + * Emits a ComponentRemovedEvent<C> event. + */ + template <typename C> + void remove(Entity::Id id) { + assert_valid(id); + const BaseComponent::Family family = component_family<C>(); + const uint32_t index = id.index(); + + // Find the pool for this component family. + BasePool *pool = component_pools_[family]; + ComponentHandle<C> component(this, id); + event_manager_.emit<ComponentRemovedEvent<C>>(Entity(this, id), component); + + // Remove component bit. + entity_component_mask_[id.index()].reset(family); + + // Call destructor. + pool->destroy(index); + } + + /** + * Check if an Entity has a component. + */ + template <typename C> + bool has_component(Entity::Id id) const { + assert_valid(id); + size_t family = component_family<C>(); + // We don't bother checking the component mask, as we return a nullptr anyway. + if (family >= component_pools_.size()) + return false; + BasePool *pool = component_pools_[family]; + if (!pool || !entity_component_mask_[id.index()][family]) + return false; + return true; + } + + /** + * Retrieve a Component assigned to an Entity::Id. + * + * @returns Pointer to an instance of C, or nullptr if the Entity::Id does not have that Component. + */ + template <typename C, typename = typename std::enable_if<!std::is_const<C>::value>::type> + ComponentHandle<C> component(Entity::Id id) { + assert_valid(id); + size_t family = component_family<C>(); + // We don't bother checking the component mask, as we return a nullptr anyway. + if (family >= component_pools_.size()) + return ComponentHandle<C>(); + BasePool *pool = component_pools_[family]; + if (!pool || !entity_component_mask_[id.index()][family]) + return ComponentHandle<C>(); + return ComponentHandle<C>(this, id); + } + + /** + * Retrieve a Component assigned to an Entity::Id. + * + * @returns Component instance, or nullptr if the Entity::Id does not have that Component. + */ + template <typename C, typename = typename std::enable_if<std::is_const<C>::value>::type> + const ComponentHandle<C, const EntityManager> component(Entity::Id id) const { + assert_valid(id); + size_t family = component_family<C>(); + // We don't bother checking the component mask, as we return a nullptr anyway. + if (family >= component_pools_.size()) + return ComponentHandle<C, const EntityManager>(); + BasePool *pool = component_pools_[family]; + if (!pool || !entity_component_mask_[id.index()][family]) + return ComponentHandle<C, const EntityManager>(); + return ComponentHandle<C, const EntityManager>(this, id); + } + + template <typename ... Components> + std::tuple<ComponentHandle<Components>...> components(Entity::Id id) { + return std::make_tuple(component<Components>(id)...); + } + + template <typename ... Components> + std::tuple<ComponentHandle<const Components, const EntityManager>...> components(Entity::Id id) const { + return std::make_tuple(component<const Components>(id)...); + } + + /** + * Find Entities that have all of the specified Components. + * + * @code + * for (Entity entity : entity_manager.entities_with_components<Position, Direction>()) { + * ComponentHandle<Position> position = entity.component<Position>(); + * ComponentHandle<Direction> direction = entity.component<Direction>(); + * + * ... + * } + * @endcode + */ + template <typename ... Components> + View<Components...> entities_with_components() { + auto mask = component_mask<Components ...>(); + return View<Components...>(this, mask); + } + + template <typename T> struct identity { typedef T type; }; + + template <typename ... Components> + void each(typename identity<std::function<void(Entity entity, Components&...)>>::type f) { + return entities_with_components<Components...>().each(f); + } + + /** + * Find Entities that have all of the specified Components and assign them + * to the given parameters. + * + * @code + * ComponentHandle<Position> position; + * ComponentHandle<Direction> direction; + * for (Entity entity : entity_manager.entities_with_components(position, direction)) { + * // Use position and component here. + * } + * @endcode + */ + template <typename ... Components> + UnpackingView<Components...> entities_with_components(ComponentHandle<Components> & ... components) { + auto mask = component_mask<Components...>(); + return UnpackingView<Components...>(this, mask, components...); + } + + /** + * Iterate over all *valid* entities (ie. not in the free list). Not fast, + * so should only be used for debugging. + * + * @code + * for (Entity entity : entity_manager.entities_for_debugging()) {} + * + * @return An iterator view over all valid entities. + */ + DebugView entities_for_debugging() { + return DebugView(this); + } + + template <typename C> + void unpack(Entity::Id id, ComponentHandle<C> &a) { + assert_valid(id); + a = component<C>(id); + } + + /** + * Unpack components directly into pointers. + * + * Components missing from the entity will be set to nullptr. + * + * Useful for fast bulk iterations. + * + * ComponentHandle<Position> p; + * ComponentHandle<Direction> d; + * unpack<Position, Direction>(e, p, d); + */ + template <typename A, typename ... Args> + void unpack(Entity::Id id, ComponentHandle<A> &a, ComponentHandle<Args> & ... args) { + assert_valid(id); + a = component<A>(id); + unpack<Args ...>(id, args ...); + } + + /** + * Destroy all entities and reset the EntityManager. + */ + void reset(); + + // Retrieve the component family for a type. + template <typename C> + static BaseComponent::Family component_family() { + return Component<typename std::remove_const<C>::type>::family(); + } + + private: + friend class Entity; + template <typename C, typename EM> + friend class ComponentHandle; + + + inline void assert_valid(Entity::Id id) const { + assert(id.index() < entity_component_mask_.size() && "Entity::Id ID outside entity vector range"); + assert(entity_version_[id.index()] == id.version() && "Attempt to access Entity via a stale Entity::Id"); + } + + template <typename C> + C *get_component_ptr(Entity::Id id) { + assert(valid(id)); + BasePool *pool = component_pools_[component_family<C>()]; + assert(pool); + return static_cast<C*>(pool->get(id.index())); + } + + template <typename C> + const C *get_component_ptr(Entity::Id id) const { + assert_valid(id); + BasePool *pool = component_pools_[component_family<C>()]; + assert(pool); + return static_cast<const C*>(pool->get(id.index())); + } + + ComponentMask component_mask(Entity::Id id) { + assert_valid(id); + return entity_component_mask_.at(id.index()); + } + + template <typename C> + ComponentMask component_mask() { + ComponentMask mask; + mask.set(component_family<C>()); + return mask; + } + + template <typename C1, typename C2, typename ... Components> + ComponentMask component_mask() { + return component_mask<C1>() | component_mask<C2, Components ...>(); + } + + template <typename C> + ComponentMask component_mask(const ComponentHandle<C> &c) { + return component_mask<C>(); + } + + template <typename C1, typename ... Components> + ComponentMask component_mask(const ComponentHandle<C1> &c1, const ComponentHandle<Components> &... args) { + return component_mask<C1, Components ...>(); + } + + inline void accomodate_entity(uint32_t index) { + if (entity_component_mask_.size() <= index) { + entity_component_mask_.resize(index + 1); + entity_version_.resize(index + 1); + for (BasePool *pool : component_pools_) + if (pool) pool->expand(index + 1); + } + } + + template <typename C> + Pool<C> *accomodate_component() { + BaseComponent::Family family = component_family<C>(); + if (component_pools_.size() <= family) { + component_pools_.resize(family + 1, nullptr); + } + if (!component_pools_[family]) { + Pool<C> *pool = new Pool<C>(); + pool->expand(index_counter_); + component_pools_[family] = pool; + } + if (component_helpers_.size() <= family) { + component_helpers_.resize(family + 1, nullptr); + } + if (!component_helpers_[family]) { + ComponentHelper<C> *helper = new ComponentHelper<C>(); + component_helpers_[family] = helper; + } + return static_cast<Pool<C>*>(component_pools_[family]); + } + + + uint32_t index_counter_ = 0; + + EventManager &event_manager_; + // Each element in component_pools_ corresponds to a Pool for a Component. + // The index into the vector is the Component::family(). + std::vector<BasePool*> component_pools_; + // Each element in component_helpers_ corresponds to a ComponentHelper for a Component type. + // The index into the vector is the Component::family(). + std::vector<BaseComponentHelper*> component_helpers_; + // Bitmask of components associated with each entity. Index into the vector is the Entity::Id. + std::vector<ComponentMask> entity_component_mask_; + // Vector of entity version numbers. Incremented each time an entity is destroyed + std::vector<uint32_t> entity_version_; + // List of available entity slots. + std::vector<uint32_t> free_list_; +}; + + +template <typename C> +BaseComponent::Family Component<C>::family() { + static Family family = family_counter_++; + assert(family < entityx::MAX_COMPONENTS); + return family; +} + + +template <typename C, typename ... Args> +ComponentHandle<C> Entity::assign(Args && ... args) { + assert(valid()); + return manager_->assign<C>(id_, std::forward<Args>(args) ...); +} + +template <typename C> +ComponentHandle<C> Entity::assign_from_copy(const C &component) { + assert(valid()); + return manager_->assign<C>(id_, std::forward<const C &>(component)); +} + +template <typename C, typename ... Args> +ComponentHandle<C> Entity::replace(Args && ... args) { + assert(valid()); + auto handle = component<C>(); + if (handle) { + *(handle.get()) = C(std::forward<Args>(args) ...); + } else { + handle = manager_->assign<C>(id_, std::forward<Args>(args) ...); + } + return handle; +} + +template <typename C> +void Entity::remove() { + assert(valid() && has_component<C>()); + manager_->remove<C>(id_); +} + +template <typename C, typename> +ComponentHandle<C> Entity::component() { + assert(valid()); + return manager_->component<C>(id_); +} + + template <typename C, typename> +const ComponentHandle<C, const EntityManager> Entity::component() const { + assert(valid()); + return const_cast<const EntityManager*>(manager_)->component<const C>(id_); +} + +template <typename ... Components> +std::tuple<ComponentHandle<Components>...> Entity::components() { + assert(valid()); + return manager_->components<Components...>(id_); +} + +template <typename ... Components> +std::tuple<ComponentHandle<const Components, const EntityManager>...> Entity::components() const { + assert(valid()); + return const_cast<const EntityManager*>(manager_)->components<const Components...>(id_); +} + + +template <typename C> +bool Entity::has_component() const { + assert(valid()); + return manager_->has_component<C>(id_); +} + +template <typename A, typename ... Args> +void Entity::unpack(ComponentHandle<A> &a, ComponentHandle<Args> & ... args) { + assert(valid()); + manager_->unpack(id_, a, args ...); +} + +inline bool Entity::valid() const { + return manager_ && manager_->valid(id_); +} + +inline std::ostream &operator << (std::ostream &out, const Entity::Id &id) { + out << "Entity::Id(" << id.index() << "." << id.version() << ")"; + return out; +} + + +inline std::ostream &operator << (std::ostream &out, const Entity &entity) { + out << "Entity(" << entity.id() << ")"; + return out; +} + + +template <typename C, typename EM> +inline ComponentHandle<C, EM>::operator bool() const { + return valid(); +} + +template <typename C, typename EM> +inline bool ComponentHandle<C, EM>::valid() const { + return manager_ && manager_->valid(id_) && manager_->template has_component<C>(id_); +} + +template <typename C, typename EM> +inline C *ComponentHandle<C, EM>::operator -> () { + assert(valid()); + return manager_->template get_component_ptr<C>(id_); +} + +template <typename C, typename EM> +inline const C *ComponentHandle<C, EM>::operator -> () const { + assert(valid()); + return manager_->template get_component_ptr<C>(id_); +} + +template <typename C, typename EM> +inline C &ComponentHandle<C, EM>::operator * () { + assert(valid()); + return *manager_->template get_component_ptr<C>(id_); +} + +template <typename C, typename EM> +inline const C &ComponentHandle<C, EM>::operator * () const { + assert(valid()); + return *manager_->template get_component_ptr<C>(id_); +} + +template <typename C, typename EM> +inline C *ComponentHandle<C, EM>::get() { + assert(valid()); + return manager_->template get_component_ptr<C>(id_); +} + +template <typename C, typename EM> +inline const C *ComponentHandle<C, EM>::get() const { + assert(valid()); + return manager_->template get_component_ptr<C>(id_); +} + +template <typename C, typename EM> +inline void ComponentHandle<C, EM>::remove() { + assert(valid()); + manager_->template remove<C>(id_); +} + +template <typename C, typename EM> +inline Entity ComponentHandle<C, EM>::entity() { + assert(valid()); + return manager_->get(id_); +} + + +} // namespace entityx + + +namespace std { +template <> struct hash<entityx::Entity> { + std::size_t operator () (const entityx::Entity &entity) const { + return static_cast<std::size_t>(entity.id().index() ^ entity.id().version()); + } +}; + +template <> struct hash<const entityx::Entity> { + std::size_t operator () (const entityx::Entity &entity) const { + return static_cast<std::size_t>(entity.id().index() ^ entity.id().version()); + } +}; +} + |