@@ -0,0 +1,124 @@
|
||||
#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
|
||||
|
||||
Reference in New Issue
Block a user