jc/array/stable_array.jai

134 lines
3 KiB
Text

Stable_Array :: struct(T: Type, ITEMS_PER_CHUNK := 32) {
allocator: Allocator;
chunks: [..]*Chunk;
count: int;
Chunk :: Static_Array(ITEMS_PER_CHUNK, T);
}
init :: (a: *Stable_Array, allocator: Allocator) {
a.allocator = allocator;
a.chunks.allocator = allocator;
}
append :: (a: *Stable_Array) -> *a.T {
chunk := find_or_create_chunk(a, 1);
item := append(chunk);
a.count += 1;
return item;
}
append :: (a: *Stable_Array, value: a.T) -> *a.T {
chunk := find_or_create_chunk(a, 1);
item := append(chunk, value);
a.count += 1;
return item;
}
append :: (a: *Stable_Array, values: ..a.T) -> *a.T {
first: *a.T;
for values {
if first == null {
first = inline append(a, it);
}
else {
inline append(a, it);
}
}
return first;
}
reset :: (a: *Stable_Array) {
for a.chunks it.count = 0;
a.count = 0;
a.chunks.count = 0;
}
operator [] :: (a: Stable_Array, index: int, loc := #caller_location) -> a.T #no_abc {
b_idx := index / a.ITEMS_PER_CHUNK;
i_idx := index % a.ITEMS_PER_CHUNK;
meta.check_bounds(b_idx, a.chunks.count, loc = loc);
meta.check_bounds(i_idx, a.chunks[b_idx].count, loc = loc);
return a.chunks[b_idx].items[i_idx];
}
operator *[] :: (a: *Stable_Array, index: int, loc := #caller_location) -> *a.T #no_abc {
b_idx := index / a.ITEMS_PER_CHUNK;
i_idx := index % a.ITEMS_PER_CHUNK;
meta.check_bounds(b_idx, a.chunks.count, loc = loc);
meta.check_bounds(i_idx, a.chunks[b_idx].count, loc = loc);
return *a.chunks[b_idx].items[i_idx];
}
operator []= :: (a: *Stable_Array, index: int, value: a.T, loc := #caller_location) #no_abc {
c_idx := index / a.ITEMS_PER_CHUNK;
i_idx := index % a.ITEMS_PER_CHUNK;
meta.check_bounds(c_idx, a.chunks.count, loc = loc);
meta.check_bounds(i_idx, a.chunks[b_idx].count, loc = loc);
chunk := a.chunks[c_idx];
chunk.items[i_idx] = value;
}
for_expansion :: (a: Stable_Array, body: Code, flags: For_Flags) #expand {
for i: 0..a.count - 1 {
`it := a[i];
`it_index := i;
#insert,scope(body) body;
}
}
#scope_file;
mem :: #import "jc/memory";
meta :: #import "jc/meta";
find_or_create_chunk :: (a: *Stable_Array, amount: int) -> *a.Chunk {
if a.chunks.count == 0 {
return create_chunk(a);
}
last := a.chunks[a.chunks.count - 1];
if amount > a.ITEMS_PER_CHUNK - last.count {
last = create_chunk(a);
}
return last;
}
create_chunk :: (a: *Stable_Array) -> *a.Chunk {
inline try_lazy_init(a);
chunk := mem.request_memory(a.Chunk,, allocator = a.allocator);
append(*a.chunks, chunk);
return chunk;
}
try_lazy_init :: (a: *Stable_Array) {
if a.allocator.proc == null {
init(a, context.allocator);
}
}
// #run {
// #import "Basic";
// {
// a: Stable_Array(int);
// for 0..64 {
// append(*a, it * it);
// }
// reset(*a);
// append(*a, 10);
// append(*a, 20);
// append(*a, 30);
// for a {
// print("%: %\n", it_index, it);
// }
// }
// }