27 _max_size = get_max_size(_components);
28 init_blocks(_components);
29 _chunks.emplace_back(_blocks, _max_size);
61 auto& free_chunk = ensure_free_chunk();
62 auto entry_index = free_chunk.size();
63 auto chunk_index = _chunks.size() - 1;
64 free_chunk.emplace_back(ent, std::forward<Components>(
components)...);
78 auto&
chunk = get_chunk(location);
79 auto& last_chunk = _chunks.back();
81 if (last_chunk.empty() && _chunks.size() > 1) {
95 auto& free_chunk = other.ensure_free_chunk();
96 auto&
chunk = get_chunk(location);
98 assert((location.entry_index <
chunk.
size()) &&
"Entity location index exceeds chunk size");
100 auto entry_index =
chunk.
move(location.entry_index, free_chunk);
104 other._chunks.size() - 1,
108 return std::make_pair(new_location, moved);
117 auto& free_chunk = other.ensure_free_chunk();
118 auto&
chunk = get_chunk(location);
120 assert((location.entry_index <
chunk.
size()) &&
"Entity location index exceeds chunk size");
122 auto entry_index =
chunk.
copy(location.entry_index, free_chunk);
125 other._chunks.size() - 1,
136 get_chunk(location).visit(location.
entry_index, std::forward<
decltype(func)>(func));
143 get_chunk(location).visit(location.
entry_index, std::forward<
decltype(func)>(func));
151 template<component C>
153 return read_impl<C&>(*
this, location);
161 template<component C>
163 return read_impl<const C&>(*
this, location);
171 template<component C>
172 [[nodiscard]]
auto contains() const noexcept ->
bool {
179 auto offset = add_block(0, component_meta::of<entity>());
182 for (
const auto& meta : components_meta) {
183 offset = add_block(offset, meta);
187 auto add_block(std::size_t offset,
const component_meta& meta) -> std::size_t {
188 const std::size_t size_in_bytes = _max_size * meta.type->size;
189 const std::size_t align = meta.type->align;
191 _blocks.emplace(meta.id, offset, meta);
199 static auto get_max_size(
auto&& components_meta) -> std::size_t {
209 auto aligned_size = aligned_components_size(components_meta);
220 auto remaining_elements_count = remaining_space / packed_components_size(components_meta);
223 return remaining_elements_count + 1;
227 static auto packed_components_size(
auto&& components_meta)
noexcept -> std::size_t {
228 return std::accumulate(components_meta.
begin(),
229 components_meta.
end(),
230 component_meta::of<entity>().type->size,
231 [](
const auto& res,
const auto& meta) { return res + meta.type->size; });
235 static auto aligned_components_size(
auto&& components_meta)
noexcept -> std::size_t {
240 auto add_elements = [&end](
const component_meta& meta) {
241 end +=
detail::mod_2n(std::bit_cast<std::size_t>(end), meta.type->align);
242 end += meta.type->size;
245 add_elements(component_meta::of<entity>());
246 for (
const auto& meta : components_meta) {
253 template<component_reference ComponentRef>
254 static auto read_impl(
auto&& self, entity_location location) -> ComponentRef {
255 auto& chunk = self.get_chunk(location);
256 assert((location.entry_index < chunk.size()) &&
"Entity location index exceeds chunk size");
257 return *component_fetch::fetch_pointer<ComponentRef>(chunk, location.entry_index);
260 static auto get_chunk_impl(
auto&& self, entity_location location)
noexcept ->
decltype(
auto) {
261 assert((location.archetype == std::addressof(self))
262 &&
"Location archetype pointer does not point to this archetype");
263 assert((location.chunk_index < self._chunks.size()) &&
"Location chunk index exceeds the chunks vector size");
264 return self._chunks[location.chunk_index];
267 auto get_chunk(entity_location location)
noexcept -> chunk& {
268 return get_chunk_impl(*
this, location);
271 auto get_chunk(entity_location location)
const noexcept ->
const chunk& {
272 return get_chunk_impl(*
this, location);
275 auto ensure_free_chunk() -> chunk& {
276 auto& chunk = _chunks.back();
280 _chunks.emplace_back(_blocks, _max_size);
281 return _chunks.back();
285 std::size_t _max_size{};
287 component_meta_set _components{};
307 auto&
archetype = _archetypes[components.ids()];
309 archetype = create_archetype(components);
312 &&
"Archetype components do not match the search request");
322 _search_component_set.
clear();
323 (..., _search_component_set.
insert<Components>());
325 auto&
archetype = _archetypes[_search_component_set];
327 archetype = create_archetype(component_meta_set::create<Components...>());
330 &&
"Archetype components do not match the search request");
341 _search_component_set = anchor_archetype->components().ids();
342 (..., _search_component_set.
insert<Components>());
344 auto&
archetype = _archetypes[_search_component_set];
346 archetype = create_archetype_added<Components...>(anchor_archetype);
349 &&
"Archetype components do not match the search request");
360 _search_component_set = anchor_archetype->components().ids();
361 (..., _search_component_set.
erase<Components>());
363 auto&
archetype = _archetypes[_search_component_set];
365 archetype = create_archetype_removed<Components...>(anchor_archetype);
368 &&
"Archetype components do not match the search request");
376 return _archetypes.begin();
383 return _archetypes.end();
390 return _archetypes.begin();
397 return _archetypes.end();
403 [[nodiscard]]
auto size() const noexcept ->
std::
size_t {
404 return _archetypes.size();
408 static auto create_archetype(
auto&& components) -> std::unique_ptr<archetype> {
409 return std::make_unique<archetype>(std::forward<
decltype(components)>(components));
412 template<component... Components>
413 static auto create_archetype_added(
const archetype* anchor_archetype) -> std::unique_ptr<archetype> {
414 auto components_meta = anchor_archetype->components();
415 (..., components_meta.
insert<Components>());
416 return std::make_unique<archetype>(std::move(components_meta));
419 template<component... Components>
420 static auto create_archetype_removed(
const archetype* anchor_archetype) -> std::unique_ptr<archetype> {
421 auto components_meta = anchor_archetype->components();
422 (..., components_meta.
erase<Components>());
423 return std::make_unique<archetype>(std::move(components_meta));
432 component_set _search_component_set{};
Archetype groups entities that share the same types of components. Archetype has a list of fixed size...
Definition archetype.hpp:15
auto copy(const entity_location &location, archetype &other) -> entity_location
Copy entity and its components to a different archetype.
Definition archetype.hpp:116
std::vector< chunk > chunks_storage_t
Chunks storage type.
Definition archetype.hpp:18
auto contains() const noexcept -> bool
Check if archetype has component C.
Definition archetype.hpp:172
void visit(const entity_location &location, auto &&func) const
Visit all components of an entity (const variant).
Definition archetype.hpp:142
auto get(entity_location location) const -> const C &
Get component data, const variant.
Definition archetype.hpp:162
archetype()=default
Construct a new archetype object without components.
auto emplace(entity ent, Components &&... components) -> entity_location
Emplace new entity and assign given components to it, return entities location.
Definition archetype.hpp:60
auto move(const entity_location &location, archetype &other) -> std::pair< entity_location, std::optional< entity > >
Move entity and its components to a different archetype and returns a pair where the first element is...
Definition archetype.hpp:94
auto components() const noexcept -> const component_meta_set &
Return components set.
Definition archetype.hpp:35
void visit(const entity_location &location, auto &&func)
Visit all components of an entity.
Definition archetype.hpp:135
archetype(component_meta_set components)
Construct a new archetype object.
Definition archetype.hpp:26
auto swap_erase(const entity_location &location) noexcept -> std::optional< entity >
Swap erase an entity at given location, returns an entity that has been moved as a result of this ope...
Definition archetype.hpp:77
auto chunks() noexcept -> chunks_storage_t &
Return reference to chunks vector.
Definition archetype.hpp:42
auto chunks() const noexcept -> const chunks_storage_t &
Return const reference to chunks vector.
Definition archetype.hpp:49
auto get(entity_location location) -> C &
Get component data.
Definition archetype.hpp:152
Container for archetypes, holds a map from component set to archetype.
Definition archetype.hpp:292
storage_type::value_type value_type
Definition archetype.hpp:298
auto ensure_archetype() -> archetype *
Get or create an archetype matching the passed Components types.
Definition archetype.hpp:321
auto begin() const noexcept -> const_iterator
Returns iterator to the beginning of archetypes container.
Definition archetype.hpp:389
storage_type::mapped_type mapped_type
Definition archetype.hpp:300
storage_type::key_type key_type
Definition archetype.hpp:299
auto ensure_archetype_removed(const archetype *anchor_archetype) -> archetype *
Get or create an archetype by removing Components from an anchor archetype.
Definition archetype.hpp:359
auto begin() noexcept -> iterator
Returns iterator to the beginning of archetypes container.
Definition archetype.hpp:375
auto ensure_archetype_added(const archetype *anchor_archetype) -> archetype *
Get or create an archetype by adding new Components to an anchor archetype.
Definition archetype.hpp:340
auto size() const noexcept -> std::size_t
Returns the number of archetypes.
Definition archetype.hpp:403
auto ensure_archetype(const component_meta_set &components) -> archetype *
Get or create an archetype given the component meta set.
Definition archetype.hpp:306
auto end() const noexcept -> const_iterator
Returns an iterator to the end of archetypes container.
Definition archetype.hpp:396
storage_type::const_iterator const_iterator
Definition archetype.hpp:297
storage_type::iterator iterator
Definition archetype.hpp:296
detail::hash_map< component_set, std::unique_ptr< archetype >, component_set_hasher > storage_type
Underlying container storage type.
Definition archetype.hpp:295
auto end() noexcept -> iterator
Returns an iterator to the end of archetypes container.
Definition archetype.hpp:382
Chunk holds a 16 Kb block of memory that holds components in blocks: |A1|A2|A3|......
Definition chunk.hpp:37
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
static constexpr std::size_t alloc_alignment
Block allocation alignment.
Definition chunk.hpp:43
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 auto size() const noexcept -> std::size_t
Return size.
Definition chunk.hpp:235
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
Component set hasher.
Definition component.hpp:264
void clear() noexcept
Definition component.hpp:245
void insert()
Insert component of type T.
Definition component.hpp:200
void erase()
Erase component of type T.
Definition component.hpp:208
Entity location.
Definition entity_location.hpp:12
std::size_t entry_index
Definition entity_location.hpp:21
Component concept. The component must be a struct/class that can be move constructed and move assigna...
Definition component.hpp:86
constexpr auto mod_2n(auto value, auto divisor) noexcept -> decltype(auto)
Calculate the value % b=2^n.
Definition bits.hpp:10
hash_table< K, T, true, Hash, KeyEqual, Allocator > hash_map
Hash map.
Definition hash_map.hpp:19
Definition archetype.hpp:11
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