24#ifndef STELLARLIB_ECS_SPARSE_MAP_HPP
25#define STELLARLIB_ECS_SPARSE_MAP_HPP
27#include <stellarlib/ecs/any_set.hpp>
28#include <stellarlib/ecs/stack_vector.hpp>
36namespace stellarlib::ecs::internal
38template <
typename Key,
typename T>
39class sparse_map final :
public any_set<Key>
43 constexpr sparse_map() noexcept = default;
46 constexpr sparse_map(const sparse_map &) noexcept = delete;
49 constexpr sparse_map(sparse_map &&) noexcept = default;
51 constexpr auto operator=(const sparse_map &) noexcept
52 -> sparse_map & = delete;
54 constexpr auto operator=(sparse_map &&) noexcept
55 -> sparse_map & = default;
57 constexpr ~sparse_map() noexcept final = default;
59 template <typename ...Args>
60 constexpr
void insert(const Key key, Args &&...args) noexcept
62 if (_sparse.extend(key + 1, std::numeric_limits<Key>::max()) || _sparse[key] == std::numeric_limits<Key>::max()) {
63 _sparse[key] = _keys.size();
65 _values.push(std::forward<Args>(args)...);
67 else if constexpr (
sizeof...(Args) == 1 && (std::is_assignable_v<T &, Args> && ...)) {
68 (*this)[key] = (std::forward<Args>(args), ...);
71 std::destroy_at(_values.begin() + _sparse[key]);
72 std::construct_at(_values.begin() + _sparse[key], std::forward<Args>(args)...);
77 constexpr auto size() const noexcept
83 constexpr auto contains(
const Key key)
const noexcept
85 return key < _sparse.size() && _sparse[key] != std::numeric_limits<Key>::max();
89 constexpr auto at(
const Key key)
const noexcept
91 return contains(key) ? _values.begin() + _sparse[key] :
nullptr;
95 constexpr auto at(
const Key key)
noexcept
97 return contains(key) ? _values.begin() + _sparse[key] :
nullptr;
101 constexpr auto operator[](
const Key key)
const noexcept
104 return _values[_sparse[key]];
108 constexpr auto operator[](
const Key key)
noexcept
111 return _values[_sparse[key]];
115 constexpr auto values() const noexcept
117 return std::ranges::subrange{_values.begin(), _values.end()};
121 constexpr auto values() noexcept
123 return std::ranges::subrange{_values.begin(), _values.end()};
127 constexpr auto zip() const noexcept
129 return std::views::zip(std::ranges::subrange{
static_cast<const Key *
>(_keys.begin()),
static_cast<const Key *
>(_keys.end())}, values());
133 constexpr auto zip() noexcept
135 return std::views::zip(std::ranges::subrange{
static_cast<const Key *
>(_keys.begin()),
static_cast<const Key *
>(_keys.end())}, values());
138 constexpr void erase(
const Key key)
noexcept final
140 if (!contains(key)) {
144 if (_sparse[key] != _keys.size() - 1) {
145 _values[_sparse[key]] = std::move(*(_values.end() - 1));
146 _keys[_sparse[key]] = *(_keys.end() - 1);
147 _sparse[_keys[_sparse[key]]] = _sparse[key];
150 _sparse[key] = std::numeric_limits<Key>::max();
155 constexpr void clear() noexcept final
163 stack_vector<Key, Key> _sparse;
164 stack_vector<T, Key> _values;
165 stack_vector<Key, Key> _keys;