Files
catboy_engine/include/libcatboy/ecs/component_view.hpp
T
2026-09-07 23:05:39 +02:00

125 lines
3.9 KiB
C++

#ifndef LIBCATBOY_ECS_COMPONENT_VIEW_HPP
#define LIBCATBOY_ECS_COMPONENT_VIEW_HPP
#include "sparseSet.hpp"
#include <array>
#include <concepts>
#include <cstddef>
#include <iterator>
#include <tuple>
#include <utility>
namespace libcatboy {
namespace ecs {
template <std::integral Entity, typename... Sum>
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<Entity, Sum...>;
using difference_type = std::ptrdiff_t;
using reference = std::tuple<Entity, Sum&...>;
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<Sum...>;
private:
auto current_tuple() { return current_tuple(std::make_index_sequence<sizeof...(Sum)>{}); }
template <std::size_t... Is>
auto current_tuple(std::index_sequence<Is...>) {
return std::forward_as_tuple(
(reinterpret_cast<sparse_set<std::tuple_element_t<Is, component_types>>&>(*m_view->m_sets[Is])
.at(index()))...);
}
auto current_tuple() const { return current_tuple(std::make_index_sequence<sizeof...(Sum)>{}); }
template <std::size_t... Is>
auto current_tuple(std::index_sequence<Is...>) const {
return std::forward_as_tuple(
(reinterpret_cast<const sparse_set<std::tuple_element_t<Is, component_types>>&>(*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<std::size_t> m_denseMap;
std::size_t m_index = 0;
};
public:
component_view(std::array<isparse_set*, sizeof...(Sum)> 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<isparse_set*, sizeof...(Sum)> m_sets;
isparse_set* m_minimal = nullptr;
};
} // namespace ecs
} // namespace libcatboy
#endif // LIBCATBOY_ECS_COMPONENT_VIEW_HPP