Investigate using a CGS instead of an ECS
@mlange I am not sure whether this is going somewhere worth reaching, but I recently learned about Froggy respectively CGS as an alternative to ECS. This avoid the pathologies of ECS by conceptually removing the entity and there by allowing arbitrary graphs of components with arbitrary iteration roots. The cost is that memory access is not as contiguous if components are iterated in different orders compared to their creation (whereas an ECS will always visit elements in entity order so to speak). However, it also supports access patterns involving multiple entities that a join in an ECS cannot handle, e.g. iterating a component and updating it for another entity at the same time. Also the CGS implementation is rather simple even if it contains quite a bit of unsafe code.
The code here does work and is already a wee bit faster than the SPECS-based variant even though the data model is the ECS-inspired one without taking advantage of the CGS flexiblity, e.g. removing the indirection for randomness, foraging and exploration. There is large amount of boiler plate in the main scheduling due to splitting the world borrow and handing it out to systems running in parallel. But then this is compile-time checked instead of runtime checked as with SPECS.
I also added two improvements upon the Froggy approach: Using the Arc
pointer value as a token to check affinity between Storage
and Pointer
so that reference count and bounds checks can be avoided. And using the reference count to check unique access via non-aliases pointer so that multiple threads can work on multiple component values at the same time via these pointers, i.e. a runtime version of what SPECS calls DistinctStorage
.
As written in the beginning, I am not sure whether I want to follow up on this but I found Froggy interesting indeed especially since the claims of comparable performance seem warranted. (Even though performance seems to degrade faster as entities are removed and created due to the non-contiguous access described above. Mitigated by reusing components in FIFO instead of LIFO order.) Maybe you find it interesting as well.