#ifndef CORE_COMPONENTS_H #define CORE_COMPONENTS_H #include "data/HashMap.h" namespace Core { using Entity = int; template class Components final { HashMap entityToIndex; List indexToEntity; List components; public: template struct Node { const Entity& entity; R& component; }; template class EntityIterator final { C& components; int index; public: EntityIterator(C& components_, int index_) : components(components_), index(index_) { } EntityIterator& operator++() { index++; return *this; } bool operator!=(const EntityIterator& other) const { return index != other.index; } Node operator*() const { return {components.indexToEntity[index], components.components[index]}; } }; template struct EntityIteratorAdapter { C& components; EntityIterator begin() { return EntityIterator(components, 0); } EntityIterator end() { return EntityIterator(components, components.components.getLength()); } }; // returns a nullptr on error template check_return T* add(Entity e, Args&&... args) { int index = components.getLength(); if(entityToIndex.tryEmplace(e, index) == nullptr) { return nullptr; } else if(indexToEntity.add(e) == nullptr) { (void)entityToIndex.remove(e); return nullptr; } T* c = components.add(Core::forward(args)...); if(c == nullptr) { (void)entityToIndex.remove(e); (void)indexToEntity.removeLast(); } return c; } // returns true on error check_return bool remove(Entity e) { int* indexP = entityToIndex.search(e); if(indexP == nullptr) { return true; } int lastIndex = components.getLength() - 1; int index = *indexP; bool r = entityToIndex.remove(e); r |= components.removeBySwap(index); if(index == lastIndex) { return r | indexToEntity.removeBySwap(index); } Entity other = indexToEntity[lastIndex]; r |= indexToEntity.removeBySwap(index); return r | (entityToIndex.add(other, index) == nullptr); } T* search(Entity e) { int* index = entityToIndex.search(e); if(index == nullptr) { return nullptr; } return &(components[*index]); } const T* search(Entity e) const { const int* index = entityToIndex.search(e); if(index == nullptr) { return nullptr; } return &(components[*index]); } auto begin() { return components.begin(); } auto begin() const { return components.begin(); } auto end() { return components.end(); } auto end() const { return components.end(); } EntityIteratorAdapter entities() { return {*this}; } EntityIteratorAdapter entities() const { return {*this}; } }; } #endif