Skip to content

Instantly share code, notes, and snippets.

@planetis-m
Created June 6, 2020 19:55
Show Gist options
  • Save planetis-m/23e97bc315cc3b6829ebfbe9d9cc595f to your computer and use it in GitHub Desktop.
Save planetis-m/23e97bc315cc3b6829ebfbe9d9cc595f to your computer and use it in GitHub Desktop.
type
Entity = uint16
Version = uint8
Registry = object
destroyed: Entity
entities: seq[Entity]
const
entityMask = 0xFFF.uint16 # Mask to use to get the entity number out of an identifier.
versionMask = 0xF.uint16 # Mask to use to get the version out of an identifier.
entityShift = 12 # Extent of the entity number within an identifier.
invalidId = entityMask
proc index(entity: Entity): int =
## Returns the entity identifier without the version.
result = int(entity and entityMask)
proc version(entity: Entity): Version =
## Returns the version stored along with an entity identifier.
result = Version(entity shr entityShift)
proc isValid(reg: Registry; entity: Entity): bool =
## Checks if an entity identifier refers to a valid entity.
let pos = entity.index
result = pos < reg.entities.len and reg.entities[pos] == entity
proc current(reg: Registry; entity: Entity): Version =
## Returns the actual version for an entity identifier.
let pos = entity.index
assert(pos < reg.entities.len)
result = reg.entities[pos].version
proc create(reg: var Registry): Entity =
## Creates a new entity and returns it.
## There are two kinds of possible entity identifiers:
##
## Newly created ones in case no entities have been previously destroyed.
## Recycled ones with updated versions.
if reg.destroyed == invalidId:
result = Entity(reg.entities.len)
reg.entities.add(result)
# entityMask is reserved to allow for null identifiers
assert(result < entityMask)
else:
let curr = reg.destroyed
let version = reg.entities[curr] and (versionMask shl entityShift)
echo version
reg.destroyed = Entity(reg.entities[curr] and entityMask)
result = Entity(curr or version)
reg.entities[curr] = result
proc destroy(reg: var Registry; entity: Entity) =
## When an entity is destroyed, its version is updated and the identifier
## can be recycled at any time.
let version = entity.version + 1
# lengthens the implicit list of destroyed entities
let index = entity.index
reg.entities[index] = Entity(reg.destroyed or (version shl entityShift))
reg.destroyed = Entity(index)
proc main =
var reg = Registry(destroyed: invalidId)
let ent1 = create(reg)
let ent2 = create(reg)
reg.destroy(ent1)
let ent3 = create(reg)
reg.destroy(ent2)
let ent4 = create(reg)
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment