// // Created by Zoe Roux on 2021-06-03. // #pragma once #include #include #include #include #include #include #include "Entity/Entity.hpp" namespace WAL { template class ViewEntity { private: std::tuple, std::reference_wrapper...> &_value; public: explicit ViewEntity(std::tuple, std::reference_wrapper...> &value) : _value(value) {} Entity *operator->() { return &(std::get<0>(this->_value).get()); } Entity &operator*() { return std::get<0>(this->_value); } operator Entity &() { return std::get<0>(this->_value); } template T &get() { return std::get>(this->_value); } template auto &get() { return std::get(this->_value); } }; template class ViewIterator { private: It _it; std::optional> _entity; public: using iterator_category = std::forward_iterator_tag; using difference_type = std::ptrdiff_t; using value_type = ViewEntity; using pointer = value_type *; using reference = value_type &; reference operator*() { if (!this->_entity) this->_entity.emplace(*this->_it); return *this->_entity; } pointer operator->() { if (!this->_entity) this->_entity =(*this->_it); return &this->_entity; } ViewIterator &operator++() { this->_it++; this->_entity = std::nullopt; return *this; } ViewIterator operator++(int) { ViewIterator copy = *this; this->_it++; this->_entity = std::nullopt; return *this; } bool operator==(const ViewIterator &other) const { return this->_it == other._it; } bool operator!=(const ViewIterator &other) const { return !this->operator==(other); } explicit ViewIterator(It current) : _it(current), _entity(std::nullopt) {} }; //! @brief A basic view used to manipulate view without knowing their type at compile time. class IView { public: //! @brief The list of types that every entity of the view has. virtual const std::vector &getTypes() const = 0; virtual void emplace_back(Entity &) = 0; virtual void erase(const Entity &) = 0; //! @brief A default destructor virtual ~IView() = default; }; //! @brief A view allowing one to easily access entities containing a set list of component. //! A view is always updated and only references to entities are kept. template class View : public IView { private: using entity_type = std::tuple, std::reference_wrapper...>; //! @brief The list of entities in the view. std::vector _entities = {}; //! @brief The list of types that every entity of the view has. std::vector _types = {}; public: using iterator = ViewIterator::iterator, Components...>; iterator begin() { return iterator(this->_entities.begin()); } iterator end() { return iterator(this->_entities.end()); } std::size_t size() const { return this->_entities.size(); } ViewEntity front() { return *iterator(this->_entities.begin()); } ViewEntity back() { return *iterator(--this->_entities.end()); } const std::vector &getTypes() const override { return this->_types; } void emplace_back(Entity &entity) override { auto tuple = std::make_tuple(entity.tryGetComponent()...); if (std::apply([](const auto *...component) {return ((component == nullptr) || ...);}, tuple)) return; std::apply([&](auto *...component) { this->_entities.emplace_back(entity, *component...); }, tuple); } void erase(const Entity &entity) override { this->_entities.erase(std::remove_if(this->_entities.begin(), this->_entities.end(), [&entity](const auto &ref) { return std::get<0>(ref).get().getUid() == entity.getUid(); }), this->_entities.end()); } //! @brief Construct a view from a list of entities. //! Those entities are never copied but references to them are kept internally. explicit View(std::list &scene) { this->_types = {typeid(Components)...}; for (auto &entity : scene) this->emplace_back(entity); } //! @brief Copying a view is not possible since a view must be managed by a scene. View(const View &) = delete; //! @brief A default destructor ~View() override = default; //! @brief A view is not assignable. View &operator=(const View &) = delete; }; } namespace std { template struct tuple_size<::WAL::ViewEntity> : public std::integral_constant {}; template struct tuple_element<0, ::WAL::ViewEntity> { using type = WAL::Entity &; }; template struct tuple_element> { using type = typename std::tuple_element>::type; }; }