Skip to content

Instantly share code, notes, and snippets.

@dezashibi
Forked from karl-zylinski/handle_array.odin
Created November 28, 2024 11:01
Show Gist options
  • Save dezashibi/7e5281340f203f456c225745b8e861e7 to your computer and use it in GitHub Desktop.
Save dezashibi/7e5281340f203f456c225745b8e861e7 to your computer and use it in GitHub Desktop.
// Handle-based array. Used like this:
//
// EntityHandle :: distinct Handle
// entities: HandleArray(Entity, EntityHandle)
//
// It expects the type used (in this case Entity) to contains a field called handle
// of type Handle
//
// You can then fetch entities using ha_get() and add handles using ha_add()
package game
Handle :: struct {
idx: u32,
gen: u32,
}
HandleNone :: Handle {}
HandleArray :: struct($T: typeid, $HT: typeid) {
items: [dynamic]T,
freelist: [dynamic]HT,
num: int,
}
ha_clear :: proc(ha: ^HandleArray($T, $HT)) {
clear(&ha.items)
clear(&ha.freelist)
}
ha_delete :: proc(ha: HandleArray($T, $HT)) {
delete(ha.items)
delete(ha.freelist)
}
ha_add :: proc(ha: ^HandleArray($T, $HT), v: T) -> HT {
v := v
if len(ha.freelist) > 0 {
h := pop(&ha.freelist)
h.gen += 1
v.handle = h
ha.items[h.idx] = v
ha.num += 1
return h
}
if len(ha.items) == 0 {
append_nothing(&ha.items) // Item at index zero is always "dummy" used for zero comparison
}
idx := u32(len(ha.items))
v.handle.idx = idx
v.handle.gen = 1
append(&ha.items, v)
ha.num += 1
return v.handle
}
ha_get :: proc(ha: HandleArray($T, $HT), h: HT) -> (T, bool) {
if h.idx > 0 && int(h.idx) < len(ha.items) && ha.items[h.idx].handle == h {
return ha.items[h.idx], true
}
return {}, false
}
ha_get_ptr :: proc(ha: HandleArray($T, $HT), h: HT) -> ^T {
if h.idx > 0 && int(h.idx) < len(ha.items) && ha.items[h.idx].handle == h {
return &ha.items[h.idx]
}
return nil
}
ha_remove :: proc(ha: ^HandleArray($T, $HT), h: HT) {
if h.idx > 0 && int(h.idx) < len(ha.items) && ha.items[h.idx].handle == h {
append(&ha.freelist, h)
ha.items[h.idx] = {}
ha.num -= 1
}
}
ha_valid :: proc(ha: HandleArray($T, $HT), h: HT) -> bool {
return ha_get(ha, h) != nil
}
// Iterators for iterating over all used slots in the array.
// Used like this:
//
// ent_iter := ha_make_iter(your_handle_based_array)
// for e in ha_iter_ptr(&ent_iter) {
// }
HandleArrayIter :: struct($T: typeid, $HT: typeid) {
ha: HandleArray(T, HT),
index: int,
}
ha_make_iter :: proc(ha: HandleArray($T, $HT)) -> HandleArrayIter(T, HT) {
return HandleArrayIter(T, HT) { ha = ha }
}
ha_iter :: proc(it: ^HandleArrayIter($T, $HT)) -> (val: T, h: HT, cond: bool) {
in_range := it.index < len(it.ha.items)
for in_range {
cond = it.index > 0 && in_range && it.ha.items[it.index].handle.idx > 0
if cond {
val = it.ha.items[it.index]
h = it.ha.items[it.index].handle
it.index += 1
return
}
it.index += 1
in_range = it.index < len(it.ha.items)
}
return
}
ha_iter_ptr :: proc(it: ^HandleArrayIter($T, $HT)) -> (val: ^T, h: HT, cond: bool) {
in_range := it.index < len(it.ha.items)
for in_range {
cond = it.index > 0 && in_range && it.ha.items[it.index].handle.idx > 0
if cond {
val = &it.ha.items[it.index]
h = it.ha.items[it.index].handle
it.index += 1
return
}
it.index += 1
in_range = it.index < len(it.ha.items)
}
return
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment