82 lines
1.5 KiB
Odin
82 lines
1.5 KiB
Odin
package spanpool
|
|
|
|
import "core:slice"
|
|
|
|
Element :: struct($E: typeid) {
|
|
value: $T,
|
|
gen: i32,
|
|
}
|
|
|
|
Span :: struct {
|
|
first, len: i32,
|
|
}
|
|
|
|
Span_Pool :: struct($E: typeid) {
|
|
elems: [dynamic]Element(E),
|
|
free_spans: [dynamic]Span,
|
|
}
|
|
|
|
Handle :: struct {
|
|
first: i32,
|
|
len: i32,
|
|
gen: i32,
|
|
}
|
|
|
|
allocate :: proc(s: ^$T/Span_Pool($E), elems: []T) -> (handle: Handle) {
|
|
handle = _allocate(s, len(elems))
|
|
|
|
for i in 0..<handle.len {
|
|
s.elems[i + handle.first].value = elems[i]
|
|
}
|
|
}
|
|
|
|
_allocate :: proc(s: ^$T/Span_Pool($E), count: i32) -> (handle: Handle) {
|
|
handle.len = count
|
|
|
|
maybe_existing_span: Maybe(i32)
|
|
for span, i in s.free_spans {
|
|
if span.len >= count {
|
|
maybe_existing_span = i
|
|
break
|
|
}
|
|
}
|
|
|
|
existing_span, ok := maybe_existing_span.?
|
|
if ok {
|
|
span := s.free_spans[existing_span]
|
|
handle.first = span.first
|
|
new_len := span.len - count
|
|
|
|
if new_len == 0 {
|
|
ordered_remove(&s.free_spans, existing_span)
|
|
} else {
|
|
s.free_spans[existing_span].first += count
|
|
s.free_spans[existing_span].len = new_len
|
|
}
|
|
} else {
|
|
handle.first = len(s.elems)
|
|
resize(&s.elems, len(s.elems) + count)
|
|
}
|
|
|
|
// Now figure out the generation index
|
|
max_gen := 0
|
|
for i in handle.first..<handle.first + handle.len {
|
|
gen = max(s.elems[i].gen)
|
|
}
|
|
|
|
handle.gen = max_gen + 1
|
|
for i in handle.first..<handle.first + handle.len {
|
|
s.elems[i].gen = handle.gen
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
free :: proc(s: ^$T/Span_Pool($E), handle: Handle) {
|
|
append(&s.free_spans, Span{first = handle.first, len = handle.len})
|
|
}
|
|
|
|
reconcile :: proc(s: ^$T/Span_Pool($E)) {
|
|
|
|
}
|