23 #include <unordered_map> 33 template <
typename Data>
37 inline bool batchable(
const std::optional<T>& lhs,
const std::optional<T>& rhs)
39 return !!lhs == !!rhs && (lhs == std::nullopt ||
batchable(*lhs, *rhs));
42 template <
typename Data>
45 if (!!lhs.
ptr != !!rhs.
ptr)
47 if (lhs.
ptr ==
nullptr)
54 template <
typename Data>
63 template <
typename Data>
72 template <
typename Data>
77 typedef std::pair<const std::string, mapped_type>
value_type;
82 template <
typename Data>
87 typedef std::pair<const std::string, mapped_type>
value_type;
93 template <
typename Data,
typename Base>
112 iComponentData{ aOther.iComponentData }
118 iComponentData = aRhs.iComponentData;
142 return data_meta_type::name();
146 return data_meta_type::field_count();
150 return data_meta_type::field_type(aFieldIndex);
154 return data_meta_type::field_type_id(aFieldIndex);
158 return data_meta_type::field_name(aFieldIndex);
163 return iComponentData;
167 return iComponentData;
169 const value_type&
operator[](
typename component_data_t::size_type aIndex)
const 171 return *std::next(component_data().begin(), aIndex);
173 value_type&
operator[](
typename component_data_t::size_type aIndex)
175 return *std::next(component_data().begin(), aIndex);
179 mutable std::recursive_mutex iMutex;
180 component_data_t iComponentData;
183 template <
typename Data>
189 using typename base_type::entity_record_not_found;
190 using typename base_type::invalid_data;
208 std::scoped_lock<std::recursive_mutex> lock{ iOwner.
mutex() };
209 ++iOwner.iUsingSnapshot;
212 iOwner{ aOther.iOwner }
214 std::scoped_lock<std::recursive_mutex> lock{ iOwner.
mutex() };
215 ++iOwner.iUsingSnapshot;
219 std::scoped_lock<std::recursive_mutex> lock{ iOwner.mutex() };
220 --iOwner.iUsingSnapshot;
225 return *iOwner.iSnapshot;
231 static constexpr reverse_index_t invalid = ~reverse_index_t{};
235 iHaveSnapshot{
false },
241 iEntities{ aOther.iEntities },
242 iFreeIndices{ aOther.iFreeIndices },
243 iReverseIndices{ aOther.iReverseIndices },
244 iHaveSnapshot{
false },
251 base_type::operator=(aRhs);
252 iEntities = aRhs.iEntities;
253 iFreeIndices = aRhs.iFreeIndices;
254 iReverseIndices = aRhs.iReverseIndices;
258 using base_type::ecs;
260 using base_type::mutex;
262 using base_type::is_data_optional;
263 using base_type::name;
264 using base_type::field_count;
265 using base_type::field_type;
266 using base_type::field_type_id;
267 using base_type::field_name;
269 using base_type::component_data;
270 using base_type::operator[];
274 const data_type* lhs = &aData;
275 const data_type* rhs = &base_type::component_data()[0];
276 auto index = lhs - rhs;
277 return entities()[index];
289 return iReverseIndices;
293 return iReverseIndices;
297 if (reverse_indices().
size() > aEntity)
298 return reverse_indices()[aEntity];
303 return reverse_index(aEntity) != invalid;
307 auto reverseIndex = reverse_index(aEntity);
308 if (reverseIndex == invalid)
309 throw entity_record_not_found();
310 return base_type::component_data()[reverseIndex];
314 return const_cast<value_type&
>(
to_const(*this).entity_record(aEntity));
318 auto reverseIndex = reverse_index(aEntity);
319 if (reverseIndex == invalid)
320 throw entity_record_not_found();
321 if constexpr (data_meta_type::has_handles)
322 data_meta_type::free_handles(base_type::component_data()[reverseIndex],
ecs());
324 reverse_indices()[aEntity] = invalid;
325 free_indices().push_back(reverseIndex);
328 std::scoped_lock<std::recursive_mutex> lock{ mutex() };
331 auto ss = snapshot();
332 ss.data().destroy_entity_record(aEntity);
340 return do_populate(aEntity, aData);
344 return do_populate(aEntity, aData);
346 void*
populate(
entity_id aEntity,
const void* aComponentData, std::size_t aComponentDataSize)
override 348 if ((aComponentData ==
nullptr && !is_data_optional()) || aComponentDataSize !=
sizeof(data_type))
349 throw invalid_data();
350 if (aComponentData !=
nullptr)
351 return &do_populate(aEntity, *static_cast<const data_type*>(aComponentData));
353 return &do_populate(aEntity, value_type{});
358 return iHaveSnapshot;
362 std::scoped_lock<std::recursive_mutex> lock{ mutex() };
365 if (iSnapshot ==
nullptr)
366 iSnapshot = snapshot_ptr{
new self_type{*
this} };
369 iHaveSnapshot =
true;
374 std::scoped_lock<std::recursive_mutex> lock{ mutex() };
377 template <
typename Compare>
381 [
this](
auto lhs,
auto rhs)
384 auto lhsIndex = lhs - base_type::component_data().begin();
385 auto rhsIndex = rhs - base_type::component_data().begin();
386 auto& lhsEntity = entities()[lhsIndex];
387 auto& rhsEntity = entities()[rhsIndex];
389 if (lhsEntity != invalid)
390 reverse_indices()[lhsEntity] = lhsIndex;
391 if (rhsEntity != invalid)
392 reverse_indices()[rhsEntity] = rhsIndex;
396 free_indices_t& free_indices()
400 template <
typename T>
401 value_type& do_populate(
entity_id aEntity, T&& aComponentData)
403 if (has_entity_record(aEntity))
404 return do_update(aEntity, aComponentData);
405 reverse_index_t reverseIndex = invalid;
406 if (!free_indices().empty())
408 reverseIndex = free_indices().back();
409 free_indices().pop_back();
410 base_type::component_data()[reverseIndex] = std::forward<T>(aComponentData);
411 entities()[reverseIndex] = aEntity;
415 reverseIndex = base_type::component_data().size();
416 base_type::component_data().push_back(std::forward<T>(aComponentData));
419 entities().push_back(aEntity);
423 base_type::component_data().pop_back();
429 if (reverse_indices().
size() <= aEntity)
430 reverse_indices().resize(aEntity + 1, invalid);
431 reverse_indices()[aEntity] = reverseIndex;
438 return base_type::component_data()[reverseIndex];
440 template <
typename T>
441 value_type& do_update(
entity_id aEntity, T&& aComponentData)
443 auto& record = entity_record(aEntity);
444 record = aComponentData;
448 component_data_entities_t iEntities;
449 free_indices_t iFreeIndices;
450 reverse_indices_t iReverseIndices;
451 mutable std::atomic<bool> iHaveSnapshot;
452 mutable std::atomic<uint32_t> iUsingSnapshot;
453 mutable snapshot_ptr iSnapshot;
456 template <
typename Data>
463 template <
typename Data>
469 using typename base_type::entity_record_not_found;
470 using typename base_type::invalid_data;
483 using base_type::ecs;
485 using base_type::mutex;
487 using base_type::is_data_optional;
488 using base_type::name;
489 using base_type::field_count;
490 using base_type::field_type;
491 using base_type::field_type_id;
492 using base_type::field_name;
494 using base_type::component_data;
496 const mapped_type&
operator[](
typename component_data_t::size_type aIndex)
const 498 return std::next(component_data().begin(), aIndex)->second;
500 mapped_type&
operator[](
typename component_data_t::size_type aIndex)
502 return std::next(component_data().begin(), aIndex)->second;
504 const mapped_type&
operator[](
const std::string& aName)
const 506 return component_data()[aName];
510 return component_data()[aName];
513 mapped_type&
populate(
const std::string& aName,
const mapped_type& aData)
515 base_type::component_data()[aName] = aData;
516 auto& result = base_type::component_data()[aName];
517 if constexpr (mapped_type::meta::has_updater)
521 mapped_type&
populate(
const std::string& aName, mapped_type&& aData)
523 base_type::component_data()[aName] = std::move(aData);
524 auto& result = base_type::component_data()[aName];
525 if constexpr (mapped_type::meta::has_updater)
529 void*
populate(
const std::string& aName,
const void* aComponentData, std::size_t aComponentDataSize)
override 531 if ((aComponentData ==
nullptr && !is_data_optional()) || aComponentDataSize !=
sizeof(mapped_type))
532 throw invalid_data();
533 if (aComponentData !=
nullptr)
534 return &populate(aName, *static_cast<const mapped_type*>(aComponentData));
536 return &populate(aName, mapped_type{});
component_data_t::mapped_type mapped_type
data_type::meta data_meta_type
constexpr entity_id null_entity
base_type::data_type data_type
static_component_base(const self_type &aOther)
value_type & populate(entity_id aEntity, value_type &&aData)
const value_type & operator[](typename component_data_t::size_type aIndex) const
const component_id & id() const override
ecs_data_type_t< Data > data_type
const component_data_entities_t & entities() const
const mapped_type & operator[](typename component_data_t::size_type aIndex) const
std::remove_cv_t< std::remove_reference_t< _Ty > > ecs_data_type_t
void swap(any &aLhs, any &aRhs)
std::unordered_map< std::string, mapped_type > container_type
base_type::data_meta_type data_meta_type
mapped_type & operator[](typename component_data_t::size_type aIndex)
neolib::uuid field_type_id(uint32_t aFieldIndex) const override
base_type::data_meta_type data_meta_type
entity_id entity(const data_type &aData) const
static constexpr bool optional
base_type::component_data_t component_data_t
self_type & operator=(const self_type &aRhs)
ecs_data_type_t< Data > data_type
mapped_type & operator[](const std::string &aName)
detail::crack_component_data< shared< neogfx::game::mesh > >::mapped_type mapped_type
const i_string & field_name(uint32_t aFieldIndex) const override
static_shared_component(game::i_ecs &aEcs)
void * populate(entity_id aEntity, const void *aComponentData, std::size_t aComponentDataSize) override
void sort(Compare aComparator)
std::recursive_mutex & mutex() const
bool have_snapshot() const
component_data_field_type field_type(uint32_t aFieldIndex) const override
ecs_data_type_t< Data > data_type
component_data_t & component_data()
std::unordered_map< std::string, mapped_type > container_type
reverse_index_t reverse_index(entity_id aEntity) const
std::pair< const std::string, mapped_type > value_type
std::vector< reverse_index_t > reverse_indices_t
base_type::component_data_t component_data_t
bool batchable(const std::optional< T > &lhs, const std::optional< T > &rhs)
std::unique_ptr< self_type > snapshot_ptr
basic_size< coordinate > size
scoped_snapshot(self_type &aOwner)
static_component(const self_type &aOther)
const reverse_indices_t & reverse_indices() const
mapped_type & populate(const std::string &aName, const mapped_type &aData)
to_const_reference_t< T > to_const(T &&object)
std::vector< value_type > container_type
scoped_snapshot(const scoped_snapshot &aOther)
self_type & operator=(const self_type &aRhs)
std::optional< data_type > mapped_type
reverse_indices_t & reverse_indices()
void destroy_entity_record(entity_id aEntity) override
std::vector< value_type > container_type
entity_record_not_found()
value_type & operator[](typename component_data_t::size_type aIndex)
mapped_type & populate(const std::string &aName, mapped_type &&aData)
void intrusive_sort(RandomIt first, RandomIt last, Swapper swapper, Compare comp)
ecs_data_type_t< Data > data_type
base_type::data_type data_type
component_data_entities_t & entities()
component_data_t::size_type reverse_index_t
std::vector< entity_id > component_data_entities_t
static_component_base(game::i_ecs &aEcs)
const component_data_t & component_data() const
value_type & entity_record(entity_id aEntity)
value_type & populate(entity_id aEntity, const value_type &aData)
detail::crack_component_data< Data >::container_type component_data_t
bool has_entity_record(entity_id aEntity) const override
std::pair< const std::string, mapped_type > value_type
const i_string & name() const override
scoped_snapshot snapshot()
static_component(game::i_ecs &aEcs)
uint32_t field_count() const override
detail::crack_component_data< Data >::value_type value_type
base_type::value_type value_type
void * populate(const std::string &aName, const void *aComponentData, std::size_t aComponentDataSize) override
std::vector< reverse_index_t > free_indices_t
game::i_ecs & ecs() const override
const mapped_type & operator[](const std::string &aName) const
const data_type & entity_record(entity_id aEntity) const
detail::crack_component_data< Data >::data_type data_type
bool is_data_optional() const override
std::optional< data_type > value_type
component_data_field_type
base_type::value_type value_type