Gaia-ECS v1.0.0
A simple and powerful entity component system
Loading...
Searching...
No Matches
component.h
1#pragma once
2#include "gaia/config/config.h"
3
4#include <cstdint>
5#include <type_traits>
6
7#include "gaia/core/hashing_policy.h"
8#include "gaia/core/utility.h"
9#include "gaia/ecs/id.h"
10#include "gaia/mem/data_layout_policy.h"
11#include "gaia/meta/type_info.h"
12
13namespace gaia {
14 namespace ecs {
15 //----------------------------------------------------------------------
16 // Component-related types
17 //----------------------------------------------------------------------
18
19 using ComponentVersion = uint32_t;
20 using ChunkDataVersionOffset = uint8_t;
21 using CompOffsetMappingIndex = uint8_t;
22 using ChunkDataOffset = uint16_t;
23 using ComponentLookupHash = core::direct_hash_key<uint64_t>;
24 using EntitySpan = std::span<const Entity>;
25 using EntitySpanMut = std::span<Entity>;
26 using ComponentSpan = std::span<const Component>;
27 using ChunkDataOffsetSpan = std::span<const ChunkDataOffset>;
28 using SortComponentCond = core::is_smaller<Entity>;
29
33 GAIA_NODISCARD constexpr bool component_uses_table_storage(Component component) noexcept {
34 return component.size() != 0U && (component.storage_type() != DataStorageType::Sparse || component.soa() != 0U);
35 }
36
40 GAIA_NODISCARD constexpr bool component_uses_sparse_storage(Component component) noexcept {
41 return component.size() != 0U && component.storage_type() == DataStorageType::Sparse && component.soa() == 0U;
42 }
43
45 namespace detail {
46 template <typename, typename = void>
47 struct auto_storage_policy_inter {
48 static constexpr DataStorageType data_storage_type = DataStorageType::Table;
49 };
50 template <typename T>
51 struct auto_storage_policy_inter<T, std::void_t<decltype(T::gaia_Data_Storage)>> {
52 static constexpr DataStorageType data_storage_type = T::gaia_Data_Storage;
53 };
54 } // namespace detail
56
59 template <typename T>
60 inline constexpr DataStorageType auto_storage_policy_v = detail::auto_storage_policy_inter<T>::data_storage_type;
61
62 //----------------------------------------------------------------------
63 // Component verification
64 //----------------------------------------------------------------------
65
67 namespace detail {
68 template <typename T>
69 struct is_component_size_valid: std::bool_constant<sizeof(T) < Component::MaxComponentSizeInBytes> {};
70
71 template <typename T>
72 struct is_component_type_valid:
73 std::bool_constant<
74 // SoA types need to be trivial. No restrictions otherwise.
75 (!mem::is_soa_layout_v<T> || std::is_trivially_copyable_v<T>)> {};
76
77 } // namespace detail
79
80 //----------------------------------------------------------------------
81 // Component verification
82 //----------------------------------------------------------------------
83
84 template <typename T>
85 constexpr void verify_comp() {
86 using U = typename actual_type_t<T>::TypeOriginal;
87
88 // Make sure we only use this for "raw" types
89 static_assert(
90 core::is_raw_v<U>,
91 "Components have to be \"raw\" types - no arrays, no const, reference, pointer or volatile");
92 static_assert(detail::is_component_type_valid<U>::value, "SoA components must be trivially copyable");
93 }
94
95 //----------------------------------------------------------------------
96 // Component lookup hash
97 //----------------------------------------------------------------------
98
99 template <typename Container>
100 GAIA_NODISCARD constexpr ComponentLookupHash calc_lookup_hash(Container arr) noexcept {
101 constexpr auto arrSize = arr.size();
102 if constexpr (arrSize == 0) {
103 return {0};
104 } else {
105 ComponentLookupHash::Type hash = arr[0];
106 core::each<arrSize - 1>([&hash, &arr](auto i) {
107 hash = core::hash_combine(hash, arr[i + 1]);
108 });
109 return {hash};
110 }
111 }
112
113 template <typename = void, typename...>
114 constexpr ComponentLookupHash calc_lookup_hash() noexcept;
115
116 template <typename T, typename... Rest>
117 GAIA_NODISCARD constexpr ComponentLookupHash calc_lookup_hash() noexcept {
118 if constexpr (sizeof...(Rest) == 0)
119 return {meta::type_info::hash<T>()};
120 else
121 return {core::hash_combine(meta::type_info::hash<T>(), meta::type_info::hash<Rest>()...)};
122 }
123
124 template <>
125 GAIA_NODISCARD constexpr ComponentLookupHash calc_lookup_hash() noexcept {
126 return {0};
127 }
128
132 GAIA_NODISCARD inline ComponentLookupHash calc_lookup_hash(EntitySpan comps) noexcept {
133 const auto compsSize = comps.size();
134 if (compsSize == 0)
135 return {0};
136
137 auto hash = core::calculate_hash64(comps[0].value());
138 GAIA_FOR2(1, compsSize) {
139 hash = core::hash_combine(hash, core::calculate_hash64(comps[i].value()));
140 }
141 return {hash};
142 }
143
149 template <uint32_t MAX_COMPONENTS>
150 GAIA_NODISCARD inline uint32_t comp_idx(const Entity* pComps, Entity entity) {
151 // We let the compiler know the upper iteration bound at compile-time.
152 // This way it can optimize better (e.g. loop unrolling, vectorization).
153 GAIA_FOR(MAX_COMPONENTS) {
154 if (pComps[i] == entity)
155 return i;
156 }
157
158 GAIA_ASSERT(false);
159 return BadIndex;
160 }
161
166 GAIA_NODISCARD inline uint32_t comp_idx(std::span<const Entity> comps, Entity entity) {
167 // We let the compiler know the upper iteration bound at compile-time.
168 // This way it can optimize better (e.g. loop unrolling, vectorization).
169 const auto cnt = (uint32_t)comps.size();
170 GAIA_FOR(cnt) {
171 if (comps[i] == entity)
172 return i;
173 }
174
175 GAIA_ASSERT(false);
176 return BadIndex;
177 }
178 } // namespace ecs
179} // namespace gaia