Skip to content

Instantly share code, notes, and snippets.

@Hexlord
Created October 14, 2022 17:56
Show Gist options
  • Save Hexlord/c0b40095fac77faf06dc10d7128e6459 to your computer and use it in GitHub Desktop.
Save Hexlord/c0b40095fac77faf06dc10d7128e6459 to your computer and use it in GitHub Desktop.
cref implementation
// This class is at least 32 bytes long.
template<typename... Ts>
class cref {
public:
using TPrimaryType = Meta::TParameterPackFirstType<Ts...>;
cref() {
Clear();
}
cref(entity_view InEntity) {
WorldPtr = (ecs_world_t *)ecs_get_world(InEntity.world().c_ptr());
EntityId = InEntity.id();
Record = ecs_record_find(WorldPtr, EntityId);
TableRecords = Array::RepeatStatic<ecs_table_record_t *, sizeof...(Ts)>(nullptr);
#if SE_VERBOSE_DEBUG
ECSIndex = Impl::ECSMeta.Index;
#endif
}
cref(const cref &Other) {
WorldPtr = Other.WorldPtr;
EntityId = Other.EntityId;
Record = Other.Record;
TableRecords = Other.TableRecords;
#if SE_VERBOSE_DEBUG
ECSIndex = Other.ECSIndex;
#endif
}
cref &operator=(entity_view InEntity) {
var NewWorldPtr = (ecs_world_t *)ecs_get_world(InEntity.world().c_ptr());
if(!WorldPtr || EntityId != InEntity.id()) {
WorldPtr = NewWorldPtr;
EntityId = InEntity.id();
Record = ecs_record_find(WorldPtr, EntityId);
#if SE_VERBOSE_DEBUG
ECSIndex = Impl::ECSMeta.Index;
#endif
} else {
VerboseCheckf(ECSIndex == Impl::ECSMeta.Index, "Ref persisted from another world");
}
return *this;
}
cref &operator=(const cref &Other) {
WorldPtr = Other.WorldPtr;
EntityId = Other.EntityId;
Record = Other.Record;
TableRecords = Other.TableRecords;
#if SE_VERBOSE_DEBUG
ECSIndex = Other.ECSIndex;
#endif
return *this;
}
static cref FormKey(entity_id InEntityId) {
cref<Ts...> Result;
Result.EntityId = InEntityId;
return Result;
}
bool operator==(const cref &Other) const {
return EntityId == Other.EntityId;
}
bool operator!=(const cref &Other) const {
return !operator==(Other);
}
template<typename T>
requires(Meta::ParameterPackContains<T, Ts...>)
operator const T *() const {
if(!WorldPtr) {
return nullptr;
}
VerboseCheckf(ECSIndex == Impl::ECSMeta.Index, "Ref persisted from another world");
Impl::AssertNoMutations();
var ECS = ecs(WorldPtr);
var Component = SE::Component<T>();
AssertReadAccess(EntityId, Component);
return (T *)ecs_record_get_mut_cached_id(WorldPtr, Record, Component, &TableRecords[Meta::ParameterPackTypeIndex<T, Ts...>]);
}
template<typename T>
requires(Meta::ParameterPackContains<T, Ts...>)
operator T *() const {
if(!WorldPtr) {
return nullptr;
}
VerboseCheckf(ECSIndex == Impl::ECSMeta.Index, "Ref persisted from another world");
Impl::AssertNoMutations();
var ECS = ecs(WorldPtr);
var Component = SE::Component<T>();
if constexpr(Meta::IsConst<T>) {
AssertReadAccess(EntityId, Component);
} else {
AssertWriteAccess(EntityId, Component);
}
return (T *)ecs_record_get_mut_cached_id(WorldPtr, Record, Component, &TableRecords[Meta::ParameterPackTypeIndex<T, Ts...>]);
}
TPrimaryType *operator*() const {
return operator TPrimaryType *();
}
TPrimaryType *operator->() const {
if(!WorldPtr) {
return nullptr;
}
VerboseCheckf(ECSIndex == Impl::ECSMeta.Index, "Ref persisted from another world");
var ECS = ecs(WorldPtr);
var Component = SE::Component<TPrimaryType>();
if constexpr(Meta::IsConst<TPrimaryType>) {
AssertReadAccess(EntityId, Component);
} else {
AssertWriteAccess(EntityId, Component);
}
return (TPrimaryType *)ecs_record_get_mut_cached_id(WorldPtr, Record, Component, &TableRecords.First());
}
entity_view entity() const {
VerboseCheckf(!WorldPtr || ECSIndex == Impl::ECSMeta.Index, "Ref persisted from another world");
return flecs::entity_view(WorldPtr, EntityId);
}
operator entity_view() const {
VerboseCheckf(!WorldPtr || ECSIndex == Impl::ECSMeta.Index, "Ref persisted from another world");
return flecs::entity_view(WorldPtr, EntityId);
}
void Clear() {
WorldPtr = nullptr;
EntityId = 0;
Record = nullptr;
TableRecords = Array::RepeatStatic<ecs_table_record_t *, sizeof...(Ts)>(nullptr);
#if SE_VERBOSE_DEBUG
ECSIndex = 0u;
#endif
}
hash ComputeHash() const {
return EntityId;
}
flecs::world_t *WorldPtr;
entity_id EntityId;
ecs_record_t *Record;
mutable TStaticArray<ecs_table_record_t *, sizeof...(Ts)> TableRecords;
private:
#if SE_VERBOSE_DEBUG
uint32 ECSIndex;
#endif
void AssertReadAccess(entity_id Entity, entity_id Id) const {
if constexpr(SE_VERBOSE_DEBUG) {
if(Entity) {
Impl::Mutations.AssertArbitraryReadAccess(entity_view(WorldPtr, Entity), Id);
}
}
}
void AssertWriteAccess(entity_id Entity, entity_id Id) const {
if constexpr(SE_VERBOSE_DEBUG) {
if(Entity) {
Impl::Mutations.AssertArbitraryWriteAccess(entity_view(WorldPtr, Entity), Id);
}
}
}
};
template<typename... Ts>
inline bool IsSet(const cref<Ts...> &Ref) {
return Ref.WorldPtr;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment