40 static constexpr std::size_t
chunk_bytes =
static_cast<const std::size_t
>(16U * 1024);
47 std::byte data[chunk_bytes];
55 _blocks(&blocks), _max_size(max_size), _buffer((new
chunk_buffer)->data) {
72 _buffer(std::exchange(rhs._buffer,
nullptr)), _size(rhs._size), _max_size(rhs._max_size), _blocks(rhs._blocks) {
80 _buffer = std::exchange(rhs._buffer, _buffer);
81 _size = std::exchange(rhs._size, _size);
82 _max_size = std::exchange(rhs._max_size, _max_size);
83 _blocks = std::exchange(rhs._blocks, _blocks);
89 if (_buffer ==
nullptr) {
92 for (
const auto& [
id, block] : *_blocks) {
93 for (std::size_t i = 0; i < _size; i++) {
94 block.meta.type->destruct(_buffer + block.offset + i * block.meta.type->size);
107 assert((!full()) &&
"Chunk is full, cannot add more entities");
108 std::construct_at(ptr_unchecked<entity>(size()), ent);
109 (..., std::construct_at(ptr_mut<Args>(size()), std::forward<Args>(args)));
115 assert((!empty()) &&
"Chunk is empty, cannot pop out any entity");
128 assert((index < _size) &&
"Entity index exceeds chunk size");
129 if (size() == 1 || index == _size - 1) {
133 assert((!other.empty()) &&
"Other chunk is empty, cannot move entity out of it");
134 const std::size_t other_chunk_index = other._size - 1;
135 entity ent = *other.ptr_unchecked<
entity>(other_chunk_index);
136 for (
const auto& [
id, block] : *_blocks) {
137 auto other_block = other._blocks->find(
id)->second;
138 const auto* type = block.meta.type;
139 auto* ptr = other._buffer + other_block.offset + other_chunk_index * type->size;
140 type->move_assign(_buffer + block.offset + index * type->size, ptr);
151 auto move(std::size_t index,
chunk& other_chunk) -> std::size_t {
152 assert((index < _size) &&
"Entity index exceeds chunk size");
153 assert((!other_chunk.full()) &&
"Other chunk is full, cannot move entity to it");
154 const std::size_t other_chunk_index = other_chunk._size;
155 for (
const auto& [
id, block] : *_blocks) {
156 const auto* type = block.meta.type;
157 if (!other_chunk._blocks->contains(
id)) {
160 auto* ptr = other_chunk._buffer + other_chunk._blocks->at(
id).offset + other_chunk_index * type->size;
161 type->move_construct(ptr, _buffer + block.offset + index * type->size);
164 return other_chunk_index;
172 auto copy(std::size_t index,
chunk& other_chunk) -> std::size_t {
173 assert((index < _size) &&
"Entity index exceeds chunk size");
174 assert((!other_chunk.full()) &&
"Other chunk is full, cannot move entity to it");
175 const std::size_t other_chunk_index = other_chunk._size;
176 for (
const auto& [
id, block] : *_blocks) {
177 const auto* type = block.meta.type;
178 if (!other_chunk._blocks->contains(
id)) {
181 auto* ptr = other_chunk._buffer + other_chunk._blocks->at(
id).offset + other_chunk_index * type->size;
182 if (type->copy_construct) {
183 type->copy_construct(ptr, _buffer + block.offset + index * type->size);
187 return other_chunk_index;
193 constexpr void visit(std::size_t index,
auto&& func)
noexcept {
194 visit_impl(*
this, index, std::forward<
decltype(func)>(func));
200 constexpr void visit(std::size_t index,
auto&& func)
const noexcept {
201 visit_impl(*
this, index, std::forward<
decltype(func)>(func));
209 template<component T>
210 inline auto ptr_const(std::size_t index)
const ->
const T* {
211 return ptr_unchecked_impl<const T*>(*
this, index);
219 template<component T>
220 inline auto ptr_mut(std::size_t index) -> T* {
221 static_assert(!std::is_same_v<T, entity>,
"Cannot give a mutable pointer/reference to the entity");
222 return ptr_unchecked_impl<T*>(*
this, index);
228 [[nodiscard]]
constexpr auto max_size() const noexcept ->
std::
size_t {
235 [[nodiscard]]
constexpr auto size() const noexcept ->
std::
size_t {
243 [[nodiscard]]
constexpr auto full() const noexcept ->
bool {
244 return size() == max_size();
251 [[nodiscard]]
constexpr auto empty() const noexcept ->
bool {
258 constexpr static void visit_impl(
auto&& self, std::size_t index,
auto&& func)
noexcept {
259 assert((index < self._size) &&
"Entity index exceeds chunk size");
261 constexpr auto is_const = std::is_const_v<std::remove_reference_t<
decltype(self)>>;
262 using ptr_t = std::conditional_t<is_const, const void*, void*>;
264 for (
const auto& [
id, block] :
265 *self._blocks | detail::views::drop(1))
267 const auto* type = block.meta.type;
268 ptr_t ptr = self._buffer + block.offset + index * type->size;
269 func(block.meta, ptr);
273 template<component T>
274 [[nodiscard]]
constexpr auto ptr_unchecked(std::size_t index) -> T* {
275 return ptr_unchecked_impl<T*>(*
this, index);
278 template<component T>
279 [[nodiscard]]
constexpr auto ptr_unchecked(std::size_t index)
const noexcept ->
const T* {
280 return ptr_unchecked_impl<const T*>(*
this, index);
284 [[nodiscard]]
static inline auto ptr_unchecked_impl(
auto&& self, std::size_t index) -> P {
285 using component_type = std::remove_const_t<std::remove_pointer_t<P>>;
286 const auto& block = self.get_block(component_id::value<component_type>);
287 return (
reinterpret_cast<P
>(self._buffer + block.offset) + index);
290 [[nodiscard]]
auto get_block(component_id_t
id)
const ->
const block_metadata& {
291 return _blocks->at(
id);
294 inline void destroy_at(std::size_t index)
noexcept {
295 for (
const auto& [
id, block] : *_blocks) {
296 block.meta.type->destruct(_buffer + block.offset + index * block.meta.type->size);
300 std::byte* _buffer{};
302 std::size_t _max_size{};
314 template<component_reference C>
318 return chunk.template ptr_const<decay_component_t<C>>(index);
319 }
catch (
const std::out_of_range&) {
327 template<component_reference C>
331 return chunk.template ptr_mut<decay_component_t<C>>(index);
332 }
catch (
const std::out_of_range&) {
343template<component_reference... Args>
349 using chunk_type = std::conditional_t<is_const, const chunk&, chunk&>;
401 std::apply([](
auto&&... args) { (args++, ...); }, _ptrs);
410 std::apply([](
auto&&... args) { (args++, ...); }, _ptrs);
418 return std::apply([](
auto&&... args) {
return std::make_tuple(std::ref(*args)...); }, _ptrs);
426 return std::get<0>(_ptrs) == std::get<0>(rhs._ptrs);
434 return std::get<0>(_ptrs) <=> std::get<0>(rhs._ptrs);
438 std::tuple<std::add_pointer_t<std::remove_reference_t<Args>>...> _ptrs;
458 return iterator(_chunk, _chunk.size());
Definition base_registry.hpp:35
Chunk view iterator.
Definition chunk.hpp:352
constexpr iterator(const iterator &rhs) noexcept=default
Default copy constructor.
constexpr auto operator++(int) noexcept -> iterator
Post-increment iterator.
Definition chunk.hpp:408
constexpr iterator(chunk_type c, std::size_t index=0)
Create iterator out of chunk pointing to the index.
Definition chunk.hpp:371
std::tuple< Args... > reference
Definition chunk.hpp:358
std::forward_iterator_tag iterator_category
Definition chunk.hpp:355
constexpr iterator(iterator &&rhs) noexcept=default
Default move constructor.
constexpr bool operator==(const iterator &rhs) const noexcept
Equality operator.
Definition chunk.hpp:425
constexpr auto operator=(iterator &&rhs) noexcept -> iterator &=default
Default move assignment operator.
int difference_type
Definition chunk.hpp:356
reference element_type
Definition chunk.hpp:359
constexpr auto operator=(const iterator &rhs) noexcept -> iterator &=default
Default copy assignment operator.
constexpr auto operator<=>(const iterator &rhs) const noexcept
Spaceship operator.
Definition chunk.hpp:433
std::forward_iterator_tag iterator_concept
Definition chunk.hpp:354
constexpr iterator()=default
Default constructor.
constexpr ~iterator()=default
Default destructor.
constexpr auto operator*() const noexcept -> reference
Dereference iterator.
Definition chunk.hpp:417
std::tuple< Args... > value_type
Definition chunk.hpp:357
constexpr auto operator++() noexcept -> iterator &
Pre-increment iterator.
Definition chunk.hpp:400
A type aware view into a chunk components.
Definition chunk.hpp:344
std::conditional_t< is_const, const chunk &, chunk & > chunk_type
Definition chunk.hpp:349
chunk_view(chunk_type c)
Construct a new chunk view object.
Definition chunk.hpp:444
constexpr auto end() noexcept -> iterator
Return iterator to the end of a chunk.
Definition chunk.hpp:457
constexpr auto begin() noexcept -> iterator
Return iterator to the beginning of a chunk.
Definition chunk.hpp:450
Chunk holds a 16 Kb block of memory that holds components in blocks: |A1|A2|A3|......
Definition chunk.hpp:37
~chunk()
Destroy the chunk object.
Definition chunk.hpp:88
constexpr auto empty() const noexcept -> bool
Check if chunk is empty.
Definition chunk.hpp:251
chunk(const chunk &rhs)=delete
Deleted copy constructor.
constexpr auto full() const noexcept -> bool
Check if chunk is full.
Definition chunk.hpp:243
constexpr void visit(std::size_t index, auto &&func) noexcept
Visit components at given index.
Definition chunk.hpp:193
auto copy(std::size_t index, chunk &other_chunk) -> std::size_t
Copy components in blocks at position index into other_chunk.
Definition chunk.hpp:172
static constexpr std::size_t chunk_bytes
Chunk size in bytes.
Definition chunk.hpp:40
auto operator=(const chunk &rhs) -> chunk &=delete
Deleted copy assignment operator.
static constexpr std::size_t alloc_alignment
Block allocation alignment.
Definition chunk.hpp:43
auto operator=(chunk &&rhs) noexcept -> chunk &
Move assignment operator.
Definition chunk.hpp:79
chunk(chunk &&rhs) noexcept
Move constructor.
Definition chunk.hpp:71
auto move(std::size_t index, chunk &other_chunk) -> std::size_t
Move components in blocks at position index into other_chunk.
Definition chunk.hpp:151
constexpr void visit(std::size_t index, auto &&func) const noexcept
Visit components at given index.
Definition chunk.hpp:200
constexpr auto size() const noexcept -> std::size_t
Return size.
Definition chunk.hpp:235
constexpr auto max_size() const noexcept -> std::size_t
Get max size, how many elements can this chunk hold.
Definition chunk.hpp:228
chunk(const blocks_type &blocks, std::size_t max_size)
Construct a new chunk object.
Definition chunk.hpp:54
void emplace_back(entity ent, Args &&... args)
Emplace back components into blocks.
Definition chunk.hpp:106
auto swap_erase(std::size_t index, chunk &other) noexcept -> std::optional< entity >
Swap end removes a components in blocks at position index and swaps it with the last element from oth...
Definition chunk.hpp:127
auto ptr_const(std::size_t index) const -> const T *
Give a const pointer to a component T at index.
Definition chunk.hpp:210
auto ptr_mut(std::size_t index) -> T *
Give a pointer to a component T at index.
Definition chunk.hpp:220
void pop_back() noexcept
Remove back elements from blocks.
Definition chunk.hpp:114
Exception raised when accessing entities component which was not assigned.
Definition exceptions.hpp:36
Component concept. The component must be a struct/class that can be move constructed and move assigna...
Definition component.hpp:86
sparse_table< K, T, true, Allocator > sparse_map
Sparse map.
Definition sparse_map.hpp:12
Definition archetype.hpp:11
constexpr bool const_component_references_v
Returns true when all Args are const references.
Definition component.hpp:142
std::decay_t< T > decay_component_t
Decay component; converts component_reference to component by removing cv-qualifiers and reference.
Definition component.hpp:100
detail::handle< struct entity_tag_t > entity
Represents an entity, consisting of an ID and generation.
Definition entity.hpp:13
detail::sparse_map< component_id_t, block_metadata > blocks_type
Definition chunk.hpp:32
Chunk buffer type.
Definition chunk.hpp:46
Component fetch is a namespace for routines that figure out based on input component_reference how to...
Definition chunk.hpp:308
static auto fetch_pointer(auto &&chunk, std::size_t index) -> decay_component_t< C > *requires(mutable_component_reference_v< C >)
Fetches pointer for mutable component reference.
Definition chunk.hpp:328
static auto fetch_pointer(auto &&chunk, std::size_t index) -> const decay_component_t< C > *requires(const_component_reference_v< C >)
Fetches pointer for const component reference.
Definition chunk.hpp:315