#ifndef LIBCATBOY_ECS_COMPONENT_VIEW_HPP #define LIBCATBOY_ECS_COMPONENT_VIEW_HPP #include "sparseSet.hpp" #include #include #include #include #include #include namespace libcatboy { namespace ecs { template requires(sizeof...(Sum) >= 1) class component_view { friend class iterator; public: class iterator { friend class component_view; private: iterator(component_view* view, std::size_t index) : m_view(view), m_denseMap(view->m_minimal->dense_map()), m_index(index) { find_valid(); } public: using value_type = std::tuple; using difference_type = std::ptrdiff_t; using reference = std::tuple; using iterator_category = std::forward_iterator_tag; public: reference operator*() { return std::tuple_cat(std::make_tuple(index()), current_tuple()); } iterator& operator++() { ++m_index; find_valid(); return *this; } iterator operator++(int) { iterator ret = *this; ++(*this); return ret; } public: bool operator==(const iterator& rhs) const noexcept { return m_view == rhs.m_view && m_index == rhs.m_index; } bool operator!=(const iterator& rhs) const noexcept { return m_view != rhs.m_view || m_index != rhs.m_index; } public: void swap(iterator& other) noexcept { std::swap(m_view, other.m_view); std::swap(m_denseMap, other.m_denseMap); std::swap(m_index, other.m_index); } private: void find_valid() { while (m_index < m_denseMap.size() && !m_view->valid(index())) ++m_index; } private: using component_types = std::tuple; private: auto current_tuple() { return current_tuple(std::make_index_sequence{}); } template auto current_tuple(std::index_sequence) { return std::forward_as_tuple( (reinterpret_cast>&>(*m_view->m_sets[Is]) .at(index()))...); } auto current_tuple() const { return current_tuple(std::make_index_sequence{}); } template auto current_tuple(std::index_sequence) const { return std::forward_as_tuple( (reinterpret_cast>&>(*m_view->m_sets[Is]) .at(index()))...); } private: std::size_t index() const noexcept { return m_denseMap[m_index]; } private: component_view* m_view; std::span m_denseMap; std::size_t m_index = 0; }; public: component_view(std::array sets) : m_sets(sets), m_minimal(sets.front()) { for (std::size_t i = 1; i < sets.size(); ++i) { if (m_minimal->size() > sets[i]->size()) m_minimal = sets[i]; } } public: std::size_t size() const noexcept { std::size_t count = 0; for (auto idx : m_minimal->dense_map()) { if (valid(idx)) ++count; } return count; } public: iterator begin() { return { this, 0 }; } iterator end() { return { this, m_minimal->size() }; } private: bool valid(Entity entity) const noexcept { for (isparse_set* set : m_sets) { if (!set->contains(entity)) return false; } return true; } private: std::array m_sets; isparse_set* m_minimal = nullptr; }; } // namespace ecs } // namespace libcatboy #endif // LIBCATBOY_ECS_COMPONENT_VIEW_HPP