Compare commits

..

No commits in common. "8822811dbbf262657d206a32bc3d3e8bbde05f07" and "3045cda7a399243c48d9377a264141d6cba6a1b8" have entirely different histories.

3 changed files with 44 additions and 89 deletions

2
TODO
View file

@ -1,6 +1,7 @@
*** IN PROGRESS *** *** IN PROGRESS ***
[Judah] [Judah]
065 [array] add dynamic, but stable array implementation (values should not move in memory once appended to the array; should mirror procedures on 'Static_Array')
[Jesse] [Jesse]
011 [math] add more Vec math procedures 011 [math] add more Vec math procedures
@ -82,4 +83,3 @@
024 [x] create file to document conventions/style guide 024 [x] create file to document conventions/style guide
034 [x] can we add location info to Allocator_Proc? 034 [x] can we add location info to Allocator_Proc?
012 [map] create a simple arena-backed hash map implementation 'Map(K, V)', should be able to hash a key of any type (must include: get, set, remove, for_expansion) - possibly blocked by 032 012 [map] create a simple arena-backed hash map implementation 'Map(K, V)', should be able to hash a key of any type (must include: get, set, remove, for_expansion) - possibly blocked by 032
065 [array] add dynamic, but stable array implementation (values should not move in memory once appended to the array; should mirror procedures on 'Static_Array')

View file

@ -18,3 +18,5 @@
tmath :: #import,file "./math/module.jai"(.turns, RUN_TESTS = true); tmath :: #import,file "./math/module.jai"(.turns, RUN_TESTS = true);
} }

View file

@ -1,13 +1,9 @@
// A dynamic array whose values will never move in memory. Stable_Array :: struct(T: Type, ITEMS_PER_CHUNK := 32) {
//
// This means it is safe to take a pointer to a value within the array
// while continuing to append to it.
Stable_Array :: struct(T: Type, items_per_chunk := 32) {
allocator: Allocator; allocator: Allocator;
chunks: [..]*Chunk; chunks: [..]*Chunk;
count: int; count: int;
Chunk :: Static_Array(items_per_chunk, T); Chunk :: Static_Array(ITEMS_PER_CHUNK, T);
} }
init :: (a: *Stable_Array, allocator: Allocator) { init :: (a: *Stable_Array, allocator: Allocator) {
@ -17,8 +13,9 @@ init :: (a: *Stable_Array, allocator: Allocator) {
append :: (a: *Stable_Array) -> *a.T { append :: (a: *Stable_Array) -> *a.T {
chunk := find_or_create_chunk(a, 1); chunk := find_or_create_chunk(a, 1);
item := append(chunk);
a.count += 1; a.count += 1;
return append(chunk); return item;
} }
append :: (a: *Stable_Array, value: a.T) -> *a.T { append :: (a: *Stable_Array, value: a.T) -> *a.T {
@ -29,9 +26,6 @@ append :: (a: *Stable_Array, value: a.T) -> *a.T {
} }
append :: (a: *Stable_Array, values: ..a.T) -> *a.T { append :: (a: *Stable_Array, values: ..a.T) -> *a.T {
// @todo(judah): this should look for chunks where can just copy values directly
// rather than calling append for each one.
first: *a.T; first: *a.T;
for values { for values {
if first == null { if first == null {
@ -52,44 +46,39 @@ reset :: (a: *Stable_Array) {
} }
operator [] :: (a: Stable_Array, index: int, loc := #caller_location) -> a.T #no_abc { operator [] :: (a: Stable_Array, index: int, loc := #caller_location) -> a.T #no_abc {
cidx := index / a.items_per_chunk; b_idx := index / a.ITEMS_PER_CHUNK;
iidx := index % a.items_per_chunk; i_idx := index % a.ITEMS_PER_CHUNK;
meta.check_bounds(cidx, a.chunks.count, loc = loc); meta.check_bounds(b_idx, a.chunks.count, loc = loc);
meta.check_bounds(iidx, a.chunks[cidx].count, loc = loc); meta.check_bounds(i_idx, a.chunks[b_idx].count, loc = loc);
return a.chunks[cidx].items[iidx]; return a.chunks[b_idx].items[i_idx];
} }
operator *[] :: (a: *Stable_Array, index: int, loc := #caller_location) -> *a.T #no_abc { operator *[] :: (a: *Stable_Array, index: int, loc := #caller_location) -> *a.T #no_abc {
cidx := index / a.items_per_chunk; b_idx := index / a.ITEMS_PER_CHUNK;
iidx := index % a.items_per_chunk; i_idx := index % a.ITEMS_PER_CHUNK;
meta.check_bounds(cidx, a.chunks.count, loc = loc); meta.check_bounds(b_idx, a.chunks.count, loc = loc);
meta.check_bounds(iidx, a.chunks[cidx].count, loc = loc); meta.check_bounds(i_idx, a.chunks[b_idx].count, loc = loc);
return *a.chunks[cidx].items[iidx]; return *a.chunks[b_idx].items[i_idx];
} }
operator []= :: (a: *Stable_Array, index: int, value: a.T, loc := #caller_location) #no_abc { operator []= :: (a: *Stable_Array, index: int, value: a.T, loc := #caller_location) #no_abc {
cidx := index / a.items_per_chunk; c_idx := index / a.ITEMS_PER_CHUNK;
iidx := index % a.items_per_chunk; i_idx := index % a.ITEMS_PER_CHUNK;
meta.check_bounds(cidx, a.chunks.count, loc = loc); meta.check_bounds(c_idx, a.chunks.count, loc = loc);
meta.check_bounds(iidx, a.chunks[cidx].count, loc = loc); meta.check_bounds(i_idx, a.chunks[b_idx].count, loc = loc);
a.chunks[cidx].items[iidx] = value;
chunk := a.chunks[c_idx];
chunk.items[i_idx] = value;
} }
for_expansion :: (a: Stable_Array, body: Code, flags: For_Flags) #expand { for_expansion :: (a: Stable_Array, body: Code, flags: For_Flags) #expand {
for #v2 <=(flags & .REVERSE == .REVERSE) i: 0..a.count - 1 { for i: 0..a.count - 1 {
`it_index := i;
#if flags & .POINTER == .POINTER {
`it := *a[i];
}
else {
`it := a[i]; `it := a[i];
} `it_index := i;
#insert,scope(body) body; #insert,scope(body) body;
} }
} }
#scope_file; #scope_file;
mem :: #import "jc/memory"; mem :: #import "jc/memory";
@ -101,7 +90,7 @@ find_or_create_chunk :: (a: *Stable_Array, amount: int) -> *a.Chunk {
} }
last := a.chunks[a.chunks.count - 1]; last := a.chunks[a.chunks.count - 1];
if amount > a.items_per_chunk - last.count { if amount > a.ITEMS_PER_CHUNK - last.count {
last = create_chunk(a); last = create_chunk(a);
} }
@ -122,60 +111,24 @@ try_lazy_init :: (a: *Stable_Array) {
} }
} }
// #run {
// #import "Basic";
// ---------------------------------------------------------- // {
// TESTS // a: Stable_Array(int);
// ---------------------------------------------------------- // for 0..64 {
// append(*a, it * it);
// }
basic :: #import "Basic"; // reset(*a);
#if RUN_TESTS #run { // append(*a, 10);
test :: #import "jc/test"; // append(*a, 20);
// append(*a, 30);
test.run("basic operations", t => { // for a {
a: Stable_Array(int, 4); // print("%: %\n", it_index, it);
// }
// }
// }
append(*a, 10, 20, 30, 40);
test.expect(t, a.count == 4);
test.expect(t, a.chunks.count == 1, "chunk count was %", a.chunks.count);
append(*a, 50);
test.expect(t, a.count == 5);
test.expect(t, a.chunks.count == 2, "chunk count was %", a.chunks.count);
append(*a, 60, 70, 80, 90, 100, 110, 120);
test.expect(t, a.count == 12);
test.expect(t, a.chunks.count == 3, "chunk count was %", a.chunks.count);
for a {
test.expect(t, it == (it_index + 1) * 10, "% was %", it, (it_index + 1) * 10);
}
});
test.run("iteration", t => {
a: Stable_Array(int);
append(*a, 10, 20, 30, 40);
last := 999;
for < a {
test.expect(t, it == (it_index + 1) * 10);
test.expect(t, it < last);
last = it;
}
for * a it.* = 1;
for a test.expect(t, it == 1);
});
test.run("stability", t => {
a: Stable_Array(int, 1);
first := append(*a, 10);
addr := first.(u64);
for 0..10 append(*a, it * 10);
test.expect(t, first.(u64) == addr);
test.expect(t, first.* == 10);
});
}