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
49 GAIA_NODISCARD constexpr Component archetype_component([[maybe_unused]] Entity term, Component component) noexcept {
50 return component;
51 }
52
54 namespace detail {
55 template <typename, typename = void>
56 struct auto_storage_policy_inter {
57 static constexpr DataStorageType data_storage_type = DataStorageType::Table;
58 };
59 template <typename T>
60 struct auto_storage_policy_inter<T, std::void_t<decltype(T::gaia_Data_Storage)>> {
61 static constexpr DataStorageType data_storage_type = T::gaia_Data_Storage;
62 };
63 } // namespace detail
65
68 template <typename T>
69 inline constexpr DataStorageType auto_storage_policy_v = detail::auto_storage_policy_inter<T>::data_storage_type;
70
72 namespace detail {
73 template <typename T, bool IsEntity = std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>, Entity>>
74 struct uses_ct_sparse_storage: std::false_type {};
75
76 template <typename T>
77 struct uses_ct_sparse_storage<T, false> {
78 using Arg = std::remove_cv_t<std::remove_reference_t<T>>;
79 using FT = typename component_type_t<Arg>::TypeFull;
80 using U = typename actual_type_t<Arg>::Type;
81
82 static constexpr bool value =
83 !mem::is_soa_layout_v<U> &&
84 (auto_storage_policy_v<U> == DataStorageType::Sparse ||
85 (auto_storage_policy_v<U> == DataStorageType::DontFragment && !std::is_empty_v<U>));
86 };
87
88 template <typename T, bool IsEntity = std::is_same_v<std::remove_cv_t<std::remove_reference_t<T>>, Entity>>
89 struct uses_ct_dont_fragment: std::false_type {};
90
91 template <typename T>
92 struct uses_ct_dont_fragment<T, false> {
93 using Arg = std::remove_cv_t<std::remove_reference_t<T>>;
94 using U = typename actual_type_t<Arg>::Type;
95
96 static constexpr bool value = auto_storage_policy_v<U> == DataStorageType::DontFragment;
97 };
98 } // namespace detail
100
105 template <typename T>
106 inline constexpr bool uses_ct_sparse_storage_v = detail::uses_ct_sparse_storage<T>::value;
107
112 template <typename T>
113 inline constexpr bool uses_ct_dont_fragment_v = detail::uses_ct_dont_fragment<T>::value;
114
115 //----------------------------------------------------------------------
116 // Component verification
117 //----------------------------------------------------------------------
118
120 namespace detail {
121 template <typename T>
122 struct is_component_size_valid: std::bool_constant<sizeof(T) < Component::MaxComponentSizeInBytes> {};
123
124 template <typename T>
125 struct is_component_type_valid:
126 std::bool_constant<
127 // SoA types need to be trivial. No restrictions otherwise.
128 (!mem::is_soa_layout_v<T> || std::is_trivially_copyable_v<T>)> {};
129
130 } // namespace detail
132
133 //----------------------------------------------------------------------
134 // Component verification
135 //----------------------------------------------------------------------
136
137 template <typename T>
138 constexpr void verify_comp() {
139 using U = typename actual_type_t<T>::TypeOriginal;
140
141 // Make sure we only use this for "raw" types
142 static_assert(
143 core::is_raw_v<U>,
144 "Components have to be \"raw\" types - no arrays, no const, reference, pointer or volatile");
145 static_assert(detail::is_component_type_valid<U>::value, "SoA components must be trivially copyable");
146 }
147
148 //----------------------------------------------------------------------
149 // Component lookup hash
150 //----------------------------------------------------------------------
151
152 template <typename Container>
153 GAIA_NODISCARD constexpr ComponentLookupHash calc_lookup_hash(Container arr) noexcept {
154 constexpr auto arrSize = arr.size();
155 if constexpr (arrSize == 0) {
156 return {0};
157 } else {
158 ComponentLookupHash::Type hash = arr[0];
159 core::each<arrSize - 1>([&hash, &arr](auto i) {
160 hash = core::hash_combine(hash, arr[i + 1]);
161 });
162 return {hash};
163 }
164 }
165
166 template <typename = void, typename...>
167 constexpr ComponentLookupHash calc_lookup_hash() noexcept;
168
169 template <typename T, typename... Rest>
170 GAIA_NODISCARD constexpr ComponentLookupHash calc_lookup_hash() noexcept {
171 if constexpr (sizeof...(Rest) == 0)
172 return {meta::type_info::hash<T>()};
173 else
174 return {core::hash_combine(meta::type_info::hash<T>(), meta::type_info::hash<Rest>()...)};
175 }
176
177 template <>
178 GAIA_NODISCARD constexpr ComponentLookupHash calc_lookup_hash() noexcept {
179 return {0};
180 }
181
185 GAIA_NODISCARD inline ComponentLookupHash calc_lookup_hash(EntitySpan comps) noexcept {
186 const auto compsSize = comps.size();
187 if (compsSize == 0)
188 return {0};
189
190 auto hash = core::calculate_hash64(comps[0].value());
191 GAIA_FOR2(1, compsSize) {
192 hash = core::hash_combine(hash, core::calculate_hash64(comps[i].value()));
193 }
194 return {hash};
195 }
196
202 template <uint32_t MAX_COMPONENTS>
203 GAIA_NODISCARD inline uint32_t comp_idx(const Entity* pComps, Entity entity) {
204 // We let the compiler know the upper iteration bound at compile-time.
205 // This way it can optimize better (e.g. loop unrolling, vectorization).
206 GAIA_FOR(MAX_COMPONENTS) {
207 if (pComps[i] == entity)
208 return i;
209 }
210
211 GAIA_ASSERT(false);
212 return BadIndex;
213 }
214
219 GAIA_NODISCARD inline uint32_t comp_idx(std::span<const Entity> comps, Entity entity) {
220 // We let the compiler know the upper iteration bound at compile-time.
221 // This way it can optimize better (e.g. loop unrolling, vectorization).
222 const auto cnt = (uint32_t)comps.size();
223 GAIA_FOR(cnt) {
224 if (comps[i] == entity)
225 return i;
226 }
227
228 GAIA_ASSERT(false);
229 return BadIndex;
230 }
231 } // namespace ecs
232} // namespace gaia