#pragma region CPL License /* Nuclex Native Framework Copyright (C) 2002-2013 Nuclex Development Labs This library is free software; you can redistribute it and/or modify it under the terms of the IBM Common Public License as published by the IBM Corporation; either version 1.0 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the IBM Common Public License for more details. You should have received a copy of the IBM Common Public License along with this library */ #pragma endregion // CPL License #ifndef NUCLEX_SCENE_GRAPH_COMPONENTSET_H #define NUCLEX_SCENE_GRAPH_COMPONENTSET_H #include "Nuclex/Scene/Config.h" #include #include #include #include #include namespace Nuclex { namespace Scene { namespace Graph { // ------------------------------------------------------------------------------------------- // /// Stores the components added to an entity class ComponentSet { #pragma region struct TypeComponentPair /// Stores a component and its type private: struct TypeComponentPair { /// Initializes a new type/component pair /// Type of component the pair is storing /// Component being stored /// Function that will be used to delete the component public: NUCLEX_SCENE_API TypeComponentPair( const std::type_info &type, void *component, const std::function &deleter ) : Type(&type), Component(component), deleter(deleter) {} /// Constructs a new instance by taking over another instance /// Other instance that will be taken over public: NUCLEX_SCENE_API TypeComponentPair(TypeComponentPair &&other) : Type(other.Type), Component(other.Component), deleter([](void *) {}) { std::swap(this->deleter, other.deleter); } /// Moves the contents of another instance into this instance /// Other instance that will be moved into this one /// This instance public: NUCLEX_SCENE_API TypeComponentPair &operator =(TypeComponentPair &&other) { this->deleter(this->Component); this->Type = other.Type; this->Component = other.Component; this->deleter = other.deleter; other.deleter = [](void *) {}; return *this; } /// Destroys a new type/component pair, deleting the component public: NUCLEX_SCENE_API ~TypeComponentPair() { this->deleter; } private: TypeComponentPair(const TypeComponentPair &); private: TypeComponentPair &operator =(const TypeComponentPair &); /// Type the container is storing public: const std::type_info *Type; /// Component stored by the container public: void *Component; /// Whether this component is built-in and must not be deleted private: std::function deleter; }; #pragma endregion // struct TypeComponentPair #pragma region class Iterator /// Iterates over the component types in the set public: class Iterator { /// Initializes a new component type iterator /// Component set whose types will be enumerated /// Index the iterator will be placed at public: NUCLEX_SCENE_API Iterator(const ComponentSet &componentSet, std::size_t index = 0) : componentSet(&componentSet), index(index) {} /// Initializes a component type iterator as copy of another iterator /// Other iterator that will be copied public: NUCLEX_SCENE_API Iterator(const Iterator &other) : componentSet(other.componentSet), index(other.index) {} /// Tests whether another iterator is at a different position /// Other iterator that will be compared /// True if the other iterator is at a different position public: NUCLEX_SCENE_API bool operator !=(const Iterator &other) { using namespace std; assert( (this->componentSet == other.componentSet) && "Compared iterators must belong to the same component set" ); return this->index != other.index; } /// Advances the iterator to the next position /// The iterator itself after incrementing public: NUCLEX_SCENE_API Iterator &operator ++() { ++this->index; return *this; } /// Accesses the element at the iterator's current position /// The type of the component at the enumerator's current position public: NUCLEX_SCENE_API const std::type_info &operator *() { using namespace std; assert( (this->index < this->componentSet->components.size()) && "Iterator must be on a valid position to be dereferenced" ); return *this->componentSet->components[this->index].Type; } /// Accesses the element at the iterator's current position /// The type of the component at the enumerator's current position public: NUCLEX_SCENE_API Iterator &operator =(const Iterator &other) { this->componentSet = other.componentSet; this->index = other.index; return *this; } /// Component set whose types the iterator is iterating over private: const ComponentSet *componentSet; /// Current position of the enumerator private: std::size_t index; }; #pragma endregion // class Iterator /// Initializes a new component set public: NUCLEX_SCENE_API ComponentSet() {} /// Destroys the component set, deleting all its components public: NUCLEX_SCENE_API ~ComponentSet() {} /// Adds a new component to the entity /// Type of component that will be added /// Component that will be added public: template void Add(std::unique_ptr component) { Add( typeid(TComponent), component.release(), [](void *component) { delete static_cast(component); } ); } /// Adds a new component to the entity /// Type of component that will be added /// Component that will be added /// Function that will be used to delete the component public: NUCLEX_SCENE_API void Add( const std::type_info &componentType, void *component, const std::function &deleter ) { this->components.push_back( TypeComponentPair(componentType, component, deleter) ); } /// Removes the component of the specified type from the entity /// Type of component that will be removed /// True if the component was present and has been removed public: template bool Remove() { return Remove(typeid(TComponent)); } /// Removes the component of the specified type from the entity /// Type of component that will be removed /// True if the component was present and has been removed public: NUCLEX_SCENE_API bool Remove(const std::type_info &componentType) { for(std::size_t index = 0; index < this->components.size(); ++index) { if(*this->components[index].Type == componentType) { this->components.erase(this->components.begin() + index); return true; } } return false; } /// Accesses the component of the specified type /// Type of component that will be accessed /// A reference to the specified component public: template TComponent &Access() { void *component = Access(typeid(TComponent)); return *static_cast(component); } /// Accesses the component of the specified type /// Type of component that will be accessed /// A reference to the specified component public: template const TComponent &Access() const { const void *component = Access(typeid(TComponent)); return *static_cast(component); } /// Accesses the component of the specified type /// Type of component that will be accessed /// A reference to the specified component public: NUCLEX_SCENE_API void *Access(const std::type_info &componentType) { for(std::size_t index = 0; index < this->components.size(); ++index) { if(*this->components[index].Type == componentType) { return this->components[index].Component; } } throw std::exception("Entity does not have the requested component"); } /// Accesses the component of the specified type /// Type of component that will be accessed /// A reference to the specified component public: NUCLEX_SCENE_API const void *Access(const std::type_info &componentType) const { for(std::size_t index = 0; index < this->components.size(); ++index) { if(*this->components[index].Type == componentType) { return this->components[index].Component; } } throw std::exception("Entity does not have the requested component"); } /// Returns the number of components in the set public: NUCLEX_SCENE_API std::size_t Count() const { return this->components.size(); } /// An iterator pointing to the first entry in the component list public: NUCLEX_SCENE_API Iterator begin() { return Iterator(*this); } /// An iterator pointing one past the end of the component list public: NUCLEX_SCENE_API Iterator end() { return Iterator(*this, this->components.size()); } /// List holding type/component pairs private: typedef std::vector ComponentList; /// Stores the components in the component set private: ComponentList components; }; // ------------------------------------------------------------------------------------------- // }}} // namespace Nuclex::Scene::Graph #endif // NUCLEX_SCENE_GRAPH_COMPONENTSET_H