Compare commits
No commits in common. "fd11638b8ce24ab9d75d78dfde47c789e8c2b6b4" and "90590b964a454aaa86231e9900f32a2918065e7a" have entirely different histories.
fd11638b8c
...
90590b964a
157 changed files with 459 additions and 637 deletions
|
|
@ -5,14 +5,16 @@
|
||||||
// @note(judah): we use relative imports here because that'll
|
// @note(judah): we use relative imports here because that'll
|
||||||
// print cleaner file locations.
|
// print cleaner file locations.
|
||||||
|
|
||||||
#import,file "./array/module.jai"(RUN_TESTS_AT_COMPILE_TIME = true);
|
#import,file "./array/module.jai"(RUN_TESTS = true);
|
||||||
#import,file "./encoding/module.jai"(RUN_TESTS_AT_COMPILE_TIME = true);
|
#import,file "./encoding/module.jai"(RUN_TESTS = true);
|
||||||
#import,file "./hash/module.jai"(RUN_TESTS_AT_COMPILE_TIME = true);
|
#import,file "./hash/module.jai"(RUN_TESTS = true);
|
||||||
#import,file "./memory/module.jai"(RUN_TESTS_AT_COMPILE_TIME = true);
|
#import,file "./memory/module.jai"(RUN_TESTS = true);
|
||||||
#import,file "./meta/module.jai"(RUN_TESTS_AT_COMPILE_TIME = true);
|
#import,file "./meta/module.jai"(RUN_TESTS = true);
|
||||||
#import,file "./platform/module.jai"(RUN_TESTS_AT_COMPILE_TIME = true);
|
#import,file "./platform/module.jai"(RUN_TESTS = true);
|
||||||
|
#import,file "./kv/module.jai"(RUN_TESTS = true);
|
||||||
|
|
||||||
rmath :: #import,file "./math/module.jai"(.radians, RUN_TESTS_AT_COMPILE_TIME = true);
|
rmath :: #import,file "./math/module.jai"(.radians, RUN_TESTS = true);
|
||||||
dmath :: #import,file "./math/module.jai"(.degrees, RUN_TESTS_AT_COMPILE_TIME = true);
|
dmath :: #import,file "./math/module.jai"(.degrees, RUN_TESTS = true);
|
||||||
tmath :: #import,file "./math/module.jai"(.turns, RUN_TESTS_AT_COMPILE_TIME = true);
|
tmath :: #import,file "./math/module.jai"(.turns, RUN_TESTS = true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
to_string :: (c: *u8, count := 1) -> string #expand {
|
|
||||||
return string.{ data = c, count = count };
|
|
||||||
}
|
|
||||||
|
|
||||||
Index_Mode :: enum {
|
|
||||||
from_left;
|
|
||||||
from_right;
|
|
||||||
}
|
|
||||||
|
|
||||||
find_index :: (b: []u8, c: u8, $mode := Index_Mode.from_left) -> bool, int {
|
|
||||||
#if #complete mode == {
|
|
||||||
case .from_left;
|
|
||||||
for b if it == c {
|
|
||||||
return true, it_index;
|
|
||||||
}
|
|
||||||
|
|
||||||
case .from_right;
|
|
||||||
i := b.count - 1;
|
|
||||||
while i >= 0 {
|
|
||||||
if b[i] == c {
|
|
||||||
return true, i;
|
|
||||||
}
|
|
||||||
|
|
||||||
i -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false, -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
find_index :: inline (s: string, c: u8, $mode := Index_Mode.from_left) -> bool, int {
|
|
||||||
ok, idx := find_index(s.([]u8), c, mode);
|
|
||||||
return ok, idx;
|
|
||||||
}
|
|
||||||
|
|
||||||
#scope_file;
|
|
||||||
|
|
||||||
// ----------------------------------------------------------
|
|
||||||
// TESTS
|
|
||||||
// ----------------------------------------------------------
|
|
||||||
|
|
||||||
#if #exists(RUN_TESTS) #run {
|
|
||||||
test :: #import "jc/meta/test";
|
|
||||||
}
|
|
||||||
|
|
@ -59,12 +59,9 @@ find_pointer :: (a: *[..]$T, $predicate: (T) -> bool) -> *T, bool, int {
|
||||||
|
|
||||||
mem :: #import "jc/memory";
|
mem :: #import "jc/memory";
|
||||||
meta :: #import "jc/meta";
|
meta :: #import "jc/meta";
|
||||||
|
|
||||||
basic :: #import "Basic"; // @future
|
basic :: #import "Basic"; // @future
|
||||||
|
|
||||||
#if #exists(RUN_TESTS) #run {
|
#if RUN_TESTS #run {
|
||||||
test :: #import "jc/meta/test";
|
|
||||||
|
|
||||||
test.run("remove_ordered", t => {
|
test.run("remove_ordered", t => {
|
||||||
a: [..]int;
|
a: [..]int;
|
||||||
append(*a, 10, 20, 30);
|
append(*a, 10, 20, 30);
|
||||||
|
|
@ -1,13 +1,11 @@
|
||||||
#module_parameters(RUN_TESTS_AT_COMPILE_TIME := false);
|
#module_parameters(RUN_TESTS := false);
|
||||||
|
|
||||||
#load "bytes.jai";
|
#load "static_array.jai";
|
||||||
#load "dynamic.jai";
|
#load "stable_array.jai";
|
||||||
#load "stable.jai";
|
#load "dynamic_array.jai";
|
||||||
#load "static.jai";
|
|
||||||
#load "xar.jai";
|
|
||||||
|
|
||||||
#scope_module;
|
#scope_module;
|
||||||
|
|
||||||
#if RUN_TESTS_AT_COMPILE_TIME {
|
#if RUN_TESTS {
|
||||||
RUN_TESTS :: true;
|
test :: #import "jc/test";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -127,8 +127,8 @@ create_chunk :: (a: *Stable_Array) -> *a.Chunk {
|
||||||
// TESTS
|
// TESTS
|
||||||
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
||||||
|
|
||||||
#if #exists(RUN_TESTS) #run {
|
#if RUN_TESTS #run {
|
||||||
test :: #import "jc/meta/test";
|
test :: #import "jc/test";
|
||||||
|
|
||||||
test.run("basic operations", t => {
|
test.run("basic operations", t => {
|
||||||
a: Stable_Array(int, 4);
|
a: Stable_Array(int, 4);
|
||||||
|
|
@ -108,8 +108,8 @@ basic :: #import "Basic"; // @future
|
||||||
// TESTS
|
// TESTS
|
||||||
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
||||||
|
|
||||||
#if #exists(RUN_TESTS) #run {
|
#if RUN_TESTS #run {
|
||||||
test :: #import "jc/meta/test";
|
test :: #import "jc/test";
|
||||||
|
|
||||||
test.run("basic operations", (t) => {
|
test.run("basic operations", (t) => {
|
||||||
a: Static_Array(10, int);
|
a: Static_Array(10, int);
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
#scope_file;
|
|
||||||
|
|
||||||
// ----------------------------------------------------------
|
|
||||||
// TESTS
|
|
||||||
// ----------------------------------------------------------
|
|
||||||
|
|
||||||
#if #exists(RUN_TESTS) #run {
|
|
||||||
test :: #import "jc/meta/test";
|
|
||||||
}
|
|
||||||
|
|
@ -6,7 +6,7 @@ Buffer :: struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
append :: inline (buf: *Buffer, ptr: *void, count: int) {
|
append :: inline (buf: *Buffer, ptr: *void, count: int) {
|
||||||
inline mem.lazy_set_allocator(buf);
|
inline meta.lazy_set_allocator(buf);
|
||||||
|
|
||||||
free_space := ensure_buffer_has_room(buf, count);
|
free_space := ensure_buffer_has_room(buf, count);
|
||||||
memcpy(free_space, ptr, count);
|
memcpy(free_space, ptr, count);
|
||||||
|
|
@ -28,7 +28,6 @@ reset :: inline (buf: *Buffer) {
|
||||||
#scope_file;
|
#scope_file;
|
||||||
|
|
||||||
array :: #import "jc/array";
|
array :: #import "jc/array";
|
||||||
mem :: #import "jc/memory";
|
|
||||||
meta :: #import "jc/meta";
|
meta :: #import "jc/meta";
|
||||||
|
|
||||||
ensure_buffer_has_room :: (buf: *Buffer, count: int) -> *u8 {
|
ensure_buffer_has_room :: (buf: *Buffer, count: int) -> *u8 {
|
||||||
|
|
@ -42,9 +41,7 @@ ensure_buffer_has_room :: (buf: *Buffer, count: int) -> *u8 {
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if #exists(RUN_TESTS) #run {
|
#if RUN_TESTS #run {
|
||||||
test :: #import "jc/meta/test";
|
|
||||||
|
|
||||||
test.run("basic operations", t => {
|
test.run("basic operations", t => {
|
||||||
buf: Buffer;
|
buf: Buffer;
|
||||||
});
|
});
|
||||||
9
bytes/module.jai
Normal file
9
bytes/module.jai
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
#module_parameters(RUN_TESTS := false);
|
||||||
|
|
||||||
|
#load "buffer.jai";
|
||||||
|
|
||||||
|
#scope_module;
|
||||||
|
|
||||||
|
#if RUN_TESTS {
|
||||||
|
test :: #import "jc/test";
|
||||||
|
}
|
||||||
|
|
@ -164,9 +164,7 @@ strings :: #import "String"; // @future
|
||||||
// TESTS
|
// TESTS
|
||||||
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
||||||
|
|
||||||
#if #exists(TESTS) #run {
|
#if RUN_TESTS #run {
|
||||||
test :: #import "jc/meta/test";
|
|
||||||
|
|
||||||
test.run("encodes", (t) => {
|
test.run("encodes", (t) => {
|
||||||
str :: "Hello, World";
|
str :: "Hello, World";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
#module_parameters(RUN_TESTS_AT_COMPILE_TIME := false);
|
#module_parameters(RUN_TESTS := false);
|
||||||
|
|
||||||
#load "base64.jai";
|
#load "base64.jai";
|
||||||
#load "json.jai";
|
#load "json.jai";
|
||||||
|
|
||||||
|
|
||||||
#scope_module;
|
#scope_module;
|
||||||
|
|
||||||
#if RUN_TESTS_AT_COMPILE_TIME {
|
#if RUN_TESTS {
|
||||||
RUN_TESTS :: true;
|
test :: #import "jc/test";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,4 @@
|
||||||
#module_parameters(RUN_TESTS_AT_COMPILE_TIME := false);
|
#module_parameters(RUN_TESTS := false);
|
||||||
|
|
||||||
#load "murmur.jai";
|
#load "murmur.jai";
|
||||||
#load "xxhash.jai";
|
#load "xxhash.jai";
|
||||||
#load "table.jai";
|
|
||||||
|
|
||||||
#scope_module;
|
|
||||||
|
|
||||||
#if RUN_TESTS_AT_COMPILE_TIME {
|
|
||||||
RUN_TESTS :: true;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
189
hash/table.jai
189
hash/table.jai
|
|
@ -1,189 +0,0 @@
|
||||||
// Dead simple key-value pair type (aka. hash table or hash map)
|
|
||||||
Table :: struct(Key: Type, Value: Type) {
|
|
||||||
allocator: Allocator;
|
|
||||||
slots: [..]Slot;
|
|
||||||
free_slots: [..]int;
|
|
||||||
count: int;
|
|
||||||
|
|
||||||
Slot :: struct {
|
|
||||||
hash: u32 = invalid_hash;
|
|
||||||
key: Key = ---;
|
|
||||||
value: Value = ---;
|
|
||||||
}
|
|
||||||
|
|
||||||
hash_proc :: hash.murmur32;
|
|
||||||
invalid_hash :: (0x8000_dead).(u32); // @note(judah): I'm curious what values would hit this hash on accident
|
|
||||||
number_of_items_to_allocate_initially :: 16; // @note(judah): must be a power of two
|
|
||||||
}
|
|
||||||
|
|
||||||
get :: (t: *Table, key: t.Key) -> t.Value, bool {
|
|
||||||
slot, ok := find_slot(t, get_hash(t, key));
|
|
||||||
if !ok {
|
|
||||||
return mem.zero_of(t.Value), false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return slot.value, true;
|
|
||||||
}
|
|
||||||
|
|
||||||
set :: (t: *Table, key: t.Key, value: t.Value) {
|
|
||||||
hash := get_hash(t, key);
|
|
||||||
slot, exists := find_slot(t, hash);
|
|
||||||
if !exists {
|
|
||||||
slot = create_or_reuse_slot(t);
|
|
||||||
slot.hash = hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
slot.key = key;
|
|
||||||
slot.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
exists :: (t: *Table, key: t.Key) -> bool {
|
|
||||||
_, exists := find_slot(t, get_hash(t, key));
|
|
||||||
return exists;
|
|
||||||
}
|
|
||||||
|
|
||||||
// @note(judah): we use 'delete' instead of 'remove' because it's a keyword...
|
|
||||||
delete :: (t: *Table, key: t.Key) -> t.Value, bool {
|
|
||||||
slot, ok, idx := find_slot(t, get_hash(t, key));
|
|
||||||
if !ok return mem.zero_of(t.Value), false;
|
|
||||||
|
|
||||||
last_value := slot.value;
|
|
||||||
mark_slot_for_reuse(t, idx);
|
|
||||||
|
|
||||||
return last_value, true;
|
|
||||||
}
|
|
||||||
|
|
||||||
reset :: (t: *Table) {
|
|
||||||
t.count = 0;
|
|
||||||
t.slots.count = 0;
|
|
||||||
t.free_slots.count = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
for_expansion :: (t: *Table, body: Code, flags: For_Flags) #expand {
|
|
||||||
#assert (flags & .POINTER == 0) "cannot iterate by pointer";
|
|
||||||
for <=(flags & .REVERSE == .REVERSE) slot: t.slots if slot.hash != t.invalid_hash {
|
|
||||||
`it := slot.value;
|
|
||||||
`it_index := slot.key;
|
|
||||||
#insert,scope(body)(break = break slot) body;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#scope_file;
|
|
||||||
|
|
||||||
get_hash :: inline (t: *Table, key: t.Key) -> u32 {
|
|
||||||
hash := t.hash_proc(key);
|
|
||||||
basic.assert(hash != t.invalid_hash, "key % collided with invalid hash marker (%)", key, t.invalid_hash);
|
|
||||||
return hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
find_slot :: (t: *Table, hash: u32) -> *t.Slot, bool, int {
|
|
||||||
for * t.slots if it.hash == hash {
|
|
||||||
return it, true, it_index;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null, false, -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
create_or_reuse_slot :: (t: *Table) -> *t.Slot {
|
|
||||||
inline try_lazy_init(t);
|
|
||||||
|
|
||||||
if t.free_slots.count > 0 {
|
|
||||||
slot_idx := t.free_slots[t.free_slots.count - 1];
|
|
||||||
t.free_slots.count -= 1;
|
|
||||||
return *t.slots[slot_idx];
|
|
||||||
}
|
|
||||||
|
|
||||||
if t.slots.allocated == 0 {
|
|
||||||
array.resize(*t.slots, t.number_of_items_to_allocate_initially);
|
|
||||||
}
|
|
||||||
else if t.slots.count >= t.slots.allocated {
|
|
||||||
array.resize(*t.slots, mem.next_power_of_two(t.slots.allocated));
|
|
||||||
}
|
|
||||||
|
|
||||||
slot := array.append(*t.slots);
|
|
||||||
t.count = t.slots.count;
|
|
||||||
return slot;
|
|
||||||
}
|
|
||||||
|
|
||||||
mark_slot_for_reuse :: (t: *Table, index: int) {
|
|
||||||
inline try_lazy_init(t);
|
|
||||||
|
|
||||||
t.count -= 1;
|
|
||||||
t.slots[index] = .{ hash = t.invalid_hash };
|
|
||||||
|
|
||||||
array.append(*t.free_slots, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
try_lazy_init :: inline (t: *Table) {
|
|
||||||
mem.lazy_set_allocator(t);
|
|
||||||
mem.lazy_set_allocator(*t.slots);
|
|
||||||
mem.lazy_set_allocator(*t.free_slots);
|
|
||||||
}
|
|
||||||
|
|
||||||
mem :: #import "jc/memory";
|
|
||||||
array :: #import "jc/array";
|
|
||||||
hash :: #import "jc/hash";
|
|
||||||
|
|
||||||
basic :: #import "Basic"; // @future
|
|
||||||
|
|
||||||
|
|
||||||
// ----------------------------------------------------------
|
|
||||||
// TESTS
|
|
||||||
// ----------------------------------------------------------
|
|
||||||
|
|
||||||
#if #exists(RUN_TESTS) #run {
|
|
||||||
test :: #import "jc/meta/test";
|
|
||||||
|
|
||||||
test.run("basic operations", t => {
|
|
||||||
ITERATIONS :: 64;
|
|
||||||
|
|
||||||
values: Table(int, int);
|
|
||||||
for 0..ITERATIONS {
|
|
||||||
set(*values, it, it * it);
|
|
||||||
}
|
|
||||||
|
|
||||||
for 0..ITERATIONS {
|
|
||||||
v, ok := get(*values, it);
|
|
||||||
test.expect(t, v == it * it);
|
|
||||||
}
|
|
||||||
|
|
||||||
for 0..ITERATIONS if it % 2 == 0 {
|
|
||||||
_, ok := delete(*values, it);
|
|
||||||
test.expect(t, ok);
|
|
||||||
}
|
|
||||||
|
|
||||||
for 0..ITERATIONS if it % 2 == 0 {
|
|
||||||
_, ok := get(*values, it);
|
|
||||||
test.expect(t, !ok);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
test.run("free slots", t => {
|
|
||||||
values: Table(int, int);
|
|
||||||
|
|
||||||
set(*values, 1, 100);
|
|
||||||
set(*values, 2, 200);
|
|
||||||
set(*values, 3, 300);
|
|
||||||
test.expect(t, values.count == 3);
|
|
||||||
test.expect(t, values.slots.allocated == values.number_of_items_to_allocate_initially);
|
|
||||||
|
|
||||||
// deleting something that doesn't exist should do nothing
|
|
||||||
_, ok := delete(*values, 0);
|
|
||||||
test.expect(t, !ok);
|
|
||||||
test.expect(t, values.count == 3);
|
|
||||||
|
|
||||||
delete(*values, 2);
|
|
||||||
test.expect(t, values.count == 2);
|
|
||||||
});
|
|
||||||
|
|
||||||
test.run("iteration", t => {
|
|
||||||
values: Table(int, int);
|
|
||||||
|
|
||||||
for 0..10 set(*values, it, it * it);
|
|
||||||
test.expect(t, values.count == 11);
|
|
||||||
|
|
||||||
for v, k: values test.expect(t, v == k * k);
|
|
||||||
for < v, k: values test.expect(t, v == k * k);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
1
jc.jai
Symbolic link
1
jc.jai
Symbolic link
|
|
@ -0,0 +1 @@
|
||||||
|
jc.jai/
|
||||||
193
kv/module.jai
Normal file
193
kv/module.jai
Normal file
|
|
@ -0,0 +1,193 @@
|
||||||
|
#module_parameters(RUN_TESTS := false);
|
||||||
|
|
||||||
|
// Dead simple key-value pair type (aka. hash table or hash map)
|
||||||
|
Kv :: struct(Key: Type, Value: Type) {
|
||||||
|
allocator: Allocator;
|
||||||
|
slots: [..]Slot;
|
||||||
|
free_slots: [..]int;
|
||||||
|
count: int;
|
||||||
|
|
||||||
|
Slot :: struct {
|
||||||
|
hash: u32 = invalid_hash;
|
||||||
|
key: Key = ---;
|
||||||
|
value: Value = ---;
|
||||||
|
}
|
||||||
|
|
||||||
|
hash_proc :: hash.murmur32;
|
||||||
|
invalid_hash :: (0x8000_dead).(u32); // @note(judah): I'm curious what values would hit this hash on accident
|
||||||
|
number_of_items_to_allocate_initially :: 16; // @note(judah): must be a power of two
|
||||||
|
}
|
||||||
|
|
||||||
|
get :: (kv: *Kv, key: kv.Key) -> kv.Value, bool {
|
||||||
|
slot, ok := find_slot(kv, get_hash(kv, key));
|
||||||
|
if !ok {
|
||||||
|
return mem.zero_of(kv.Value), false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return slot.value, true;
|
||||||
|
}
|
||||||
|
|
||||||
|
set :: (kv: *Kv, key: kv.Key, value: kv.Value) {
|
||||||
|
hash := get_hash(kv, key);
|
||||||
|
slot, exists := find_slot(kv, hash);
|
||||||
|
if !exists {
|
||||||
|
slot = create_or_reuse_slot(kv);
|
||||||
|
slot.hash = hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
slot.key = key;
|
||||||
|
slot.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
exists :: (kv: *Kv, key: kv.Key) -> bool {
|
||||||
|
_, exists := find_slot(kv, get_hash(kv, key));
|
||||||
|
return exists;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @note(judah): we use 'delete' instead of 'remove' because it's a keyword...
|
||||||
|
delete :: (kv: *Kv, key: kv.Key) -> kv.Value, bool {
|
||||||
|
slot, ok, idx := find_slot(kv, get_hash(kv, key));
|
||||||
|
if !ok return mem.zero_of(kv.Value), false;
|
||||||
|
|
||||||
|
last_value := slot.value;
|
||||||
|
mark_slot_for_reuse(kv, idx);
|
||||||
|
|
||||||
|
return last_value, true;
|
||||||
|
}
|
||||||
|
|
||||||
|
reset :: (kv: *Kv) {
|
||||||
|
kv.count = 0;
|
||||||
|
kv.slots.count = 0;
|
||||||
|
kv.free_slots.count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for_expansion :: (kv: *Kv, body: Code, flags: For_Flags) #expand {
|
||||||
|
#assert (flags & .POINTER == 0) "cannot iterate by pointer";
|
||||||
|
for <=(flags & .REVERSE == .REVERSE) slot: kv.slots if slot.hash != kv.invalid_hash {
|
||||||
|
`it := slot.value;
|
||||||
|
`it_index := slot.key;
|
||||||
|
#insert,scope(body)(break = break slot) body;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#scope_file;
|
||||||
|
|
||||||
|
get_hash :: inline (kv: *Kv, key: kv.Key) -> u32 {
|
||||||
|
hash := kv.hash_proc(key);
|
||||||
|
basic.assert(hash != kv.invalid_hash, "key % collided with invalid hash marker (%)", key, kv.invalid_hash);
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
find_slot :: (kv: *Kv, hash: u32) -> *kv.Slot, bool, int {
|
||||||
|
for * kv.slots if it.hash == hash {
|
||||||
|
return it, true, it_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null, false, -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
create_or_reuse_slot :: (kv: *Kv) -> *kv.Slot {
|
||||||
|
inline try_lazy_init(kv);
|
||||||
|
|
||||||
|
if kv.free_slots.count > 0 {
|
||||||
|
slot_idx := kv.free_slots[kv.free_slots.count - 1];
|
||||||
|
kv.free_slots.count -= 1;
|
||||||
|
return *kv.slots[slot_idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
if kv.slots.allocated == 0 {
|
||||||
|
array.resize(*kv.slots, kv.number_of_items_to_allocate_initially);
|
||||||
|
}
|
||||||
|
else if kv.slots.count >= kv.slots.allocated {
|
||||||
|
array.resize(*kv.slots, mem.next_power_of_two(kv.slots.allocated));
|
||||||
|
}
|
||||||
|
|
||||||
|
slot := array.append(*kv.slots);
|
||||||
|
kv.count = kv.slots.count;
|
||||||
|
return slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
mark_slot_for_reuse :: (kv: *Kv, index: int) {
|
||||||
|
inline try_lazy_init(kv);
|
||||||
|
|
||||||
|
kv.count -= 1;
|
||||||
|
kv.slots[index] = .{ hash = kv.invalid_hash };
|
||||||
|
|
||||||
|
array.append(*kv.free_slots, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
try_lazy_init :: inline (kv: *Kv) {
|
||||||
|
mem.lazy_set_allocator(kv);
|
||||||
|
mem.lazy_set_allocator(*kv.slots);
|
||||||
|
mem.lazy_set_allocator(*kv.free_slots);
|
||||||
|
}
|
||||||
|
|
||||||
|
mem :: #import "jc/memory";
|
||||||
|
array :: #import "jc/array";
|
||||||
|
hash :: #import "jc/hash";
|
||||||
|
|
||||||
|
basic :: #import "Basic"; // @future
|
||||||
|
|
||||||
|
|
||||||
|
// ----------------------------------------------------------
|
||||||
|
// TESTS
|
||||||
|
// ----------------------------------------------------------
|
||||||
|
|
||||||
|
#if RUN_TESTS {
|
||||||
|
test :: #import "jc/test";
|
||||||
|
|
||||||
|
#run {
|
||||||
|
test.run("basic operations", t => {
|
||||||
|
ITERATIONS :: 64;
|
||||||
|
|
||||||
|
values: Kv(int, int);
|
||||||
|
for 0..ITERATIONS {
|
||||||
|
set(*values, it, it * it);
|
||||||
|
}
|
||||||
|
|
||||||
|
for 0..ITERATIONS {
|
||||||
|
v, ok := get(*values, it);
|
||||||
|
test.expect(t, v == it * it);
|
||||||
|
}
|
||||||
|
|
||||||
|
for 0..ITERATIONS if it % 2 == 0 {
|
||||||
|
_, ok := delete(*values, it);
|
||||||
|
test.expect(t, ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
for 0..ITERATIONS if it % 2 == 0 {
|
||||||
|
_, ok := get(*values, it);
|
||||||
|
test.expect(t, !ok);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test.run("free slots", t => {
|
||||||
|
values: Kv(int, int);
|
||||||
|
|
||||||
|
set(*values, 1, 100);
|
||||||
|
set(*values, 2, 200);
|
||||||
|
set(*values, 3, 300);
|
||||||
|
test.expect(t, values.count == 3);
|
||||||
|
test.expect(t, values.slots.allocated == values.number_of_items_to_allocate_initially);
|
||||||
|
|
||||||
|
// deleting something that doesn't exist should do nothing
|
||||||
|
_, ok := delete(*values, 0);
|
||||||
|
test.expect(t, !ok);
|
||||||
|
test.expect(t, values.count == 3);
|
||||||
|
|
||||||
|
delete(*values, 2);
|
||||||
|
test.expect(t, values.count == 2);
|
||||||
|
});
|
||||||
|
|
||||||
|
test.run("iteration", t => {
|
||||||
|
values: Kv(int, int);
|
||||||
|
|
||||||
|
for 0..10 set(*values, it, it * it);
|
||||||
|
test.expect(t, values.count == 11);
|
||||||
|
|
||||||
|
for v, k: values test.expect(t, v == k * k);
|
||||||
|
for < v, k: values test.expect(t, v == k * k);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,21 +2,18 @@
|
||||||
PI :: 3.1415926;
|
PI :: 3.1415926;
|
||||||
TAU :: 6.2831853;
|
TAU :: 6.2831853;
|
||||||
|
|
||||||
#if #exists(UNITS) #if UNITS == {
|
#if UNITS == .turns {
|
||||||
case .turns;
|
|
||||||
to_rad :: turn_to_rad;
|
to_rad :: turn_to_rad;
|
||||||
from_rad :: rad_to_turn;
|
from_rad :: rad_to_turn;
|
||||||
case .radians;
|
}
|
||||||
|
else #if UNITS == .radians {
|
||||||
to_rad :: rad_to_rad;
|
to_rad :: rad_to_rad;
|
||||||
from_rad :: rad_to_rad;
|
from_rad :: rad_to_rad;
|
||||||
case .degrees;
|
}
|
||||||
|
else #if UNITS == .degrees {
|
||||||
to_rad :: deg_to_rad;
|
to_rad :: deg_to_rad;
|
||||||
from_rad :: rad_to_deg;
|
from_rad :: rad_to_deg;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
to_rad :: turn_to_rad;
|
|
||||||
from_rad :: rad_to_turn;
|
|
||||||
}
|
|
||||||
|
|
||||||
turn_to_rad :: (turns: float64) -> float #expand #no_debug {
|
turn_to_rad :: (turns: float64) -> float #expand #no_debug {
|
||||||
CONSTANT :float64: PI*2.0;
|
CONSTANT :float64: PI*2.0;
|
||||||
|
|
|
||||||
|
|
@ -404,9 +404,7 @@ inverse :: (m: Mat4) -> Mat4 {
|
||||||
|
|
||||||
#scope_file;
|
#scope_file;
|
||||||
|
|
||||||
#if #exists(RUN_TESTS) #run {
|
#if RUN_TESTS #run {
|
||||||
test :: #import "jc/meta/test";
|
|
||||||
|
|
||||||
test.run(basic.tprint("%: Mat2", UNITS), t => {
|
test.run(basic.tprint("%: Mat2", UNITS), t => {
|
||||||
{
|
{
|
||||||
identity := m2_identity;
|
identity := m2_identity;
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
UNITS: enum { radians; degrees; turns; } = .turns,
|
UNITS: enum { radians; degrees; turns; } = .turns,
|
||||||
RECT_TYPE: Type = float,
|
RECT_TYPE: Type = float,
|
||||||
// RECT_METHOD: enum { dimension; absolute; } = absolute, // Note(Jesse): Maybe at a later point we can do this
|
// RECT_METHOD: enum { dimension; absolute; } = absolute, // Note(Jesse): Maybe at a later point we can do this
|
||||||
RUN_TESTS_AT_COMPILE_TIME := false
|
RUN_TESTS := false
|
||||||
);
|
);
|
||||||
|
|
||||||
#assert meta.type_is_scalar(RECT_TYPE);
|
#assert meta.type_is_scalar(RECT_TYPE);
|
||||||
|
|
@ -34,8 +34,8 @@ meta :: #import "jc/meta";
|
||||||
math :: #import "Math"; // @future
|
math :: #import "Math"; // @future
|
||||||
basic :: #import "Basic"; // @future
|
basic :: #import "Basic"; // @future
|
||||||
|
|
||||||
#if RUN_TESTS_AT_COMPILE_TIME {
|
#if RUN_TESTS {
|
||||||
RUN_TESTS :: true;
|
test :: #import "jc/test";
|
||||||
}
|
}
|
||||||
|
|
||||||
// @temp(judah): move these to the right files
|
// @temp(judah): move these to the right files
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
|
||||||
Rect :: #type,distinct Vec(4, RECT_TYPE);
|
Rect :: #type,distinct Vec(4, RECT_TYPE);
|
||||||
|
|
||||||
Circle :: struct {
|
Circle :: struct {
|
||||||
|
|
@ -153,5 +154,7 @@ get_center :: (r: Rect) -> Vec2 {
|
||||||
|
|
||||||
basic :: #import "Basic";
|
basic :: #import "Basic";
|
||||||
|
|
||||||
#if #exists(RUN_TESTS) #run {
|
#if RUN_TESTS #run,stallable {
|
||||||
|
test.run(basic.tprint("%: Vec2", UNITS), t => {
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -653,9 +653,7 @@ cross :: (a: Vec3, b: Vec3) -> Vec3 {
|
||||||
|
|
||||||
#scope_file
|
#scope_file
|
||||||
|
|
||||||
#if #exists(RUN_TESTS) #run,stallable {
|
#if RUN_TESTS #run,stallable {
|
||||||
test :: #import "jc/meta/test";
|
|
||||||
|
|
||||||
test.run(basic.tprint("%: Vec2", UNITS), t => {
|
test.run(basic.tprint("%: Vec2", UNITS), t => {
|
||||||
{
|
{
|
||||||
a: Vec2 = v2f(0.0, 1.0);
|
a: Vec2 = v2f(0.0, 1.0);
|
||||||
|
|
|
||||||
|
|
@ -112,9 +112,10 @@ meta :: #import "jc/meta";
|
||||||
// TESTS
|
// TESTS
|
||||||
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
||||||
|
|
||||||
#if #exists(RUN_TESTS) #run {
|
#if RUN_TESTS {
|
||||||
test :: #import "jc/meta/test";
|
test :: #import "jc/test";
|
||||||
|
|
||||||
|
#run {
|
||||||
test.run("arena:basic", t => {
|
test.run("arena:basic", t => {
|
||||||
memory := request_memory(1 * Kilobyte);
|
memory := request_memory(1 * Kilobyte);
|
||||||
defer release_memory(memory);
|
defer release_memory(memory);
|
||||||
|
|
@ -130,4 +131,5 @@ meta :: #import "jc/meta";
|
||||||
basic.assert(arena.offset == size_of(int));
|
basic.assert(arena.offset == size_of(int));
|
||||||
allocator_restore(save_point);
|
allocator_restore(save_point);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#module_parameters(RUN_TESTS_AT_COMPILE_TIME := false);
|
#module_parameters(RUN_TESTS := false);
|
||||||
|
|
||||||
Kilobyte :: 1024;
|
Kilobyte :: 1024;
|
||||||
Megabyte :: 1024 * Kilobyte;
|
Megabyte :: 1024 * Kilobyte;
|
||||||
|
|
@ -174,12 +174,6 @@ lazy_set_allocator :: (array: *[..]$T, allocator := context.allocator) #expand {
|
||||||
|
|
||||||
#load "allocators.jai";
|
#load "allocators.jai";
|
||||||
|
|
||||||
#scope_module;
|
|
||||||
|
|
||||||
#if RUN_TESTS_AT_COMPILE_TIME {
|
|
||||||
RUN_TESTS :: true;
|
|
||||||
}
|
|
||||||
|
|
||||||
#scope_file;
|
#scope_file;
|
||||||
|
|
||||||
meta :: #import "jc/meta";
|
meta :: #import "jc/meta";
|
||||||
|
|
@ -192,9 +186,10 @@ compiler :: #import "Compiler"; // @future
|
||||||
// TESTS
|
// TESTS
|
||||||
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
||||||
|
|
||||||
#if #exists(RUN_TESTS) #run {
|
#if RUN_TESTS {
|
||||||
test :: #import "jc/meta/test";
|
test :: #import "jc/test";
|
||||||
|
|
||||||
|
#run {
|
||||||
test.run("request_memory:dynamic arrays", (t) => {
|
test.run("request_memory:dynamic arrays", (t) => {
|
||||||
a1 := request_memory([..]int);
|
a1 := request_memory([..]int);
|
||||||
defer release_memory(a1);
|
defer release_memory(a1);
|
||||||
|
|
@ -219,4 +214,5 @@ compiler :: #import "Compiler"; // @future
|
||||||
|
|
||||||
test.expect(t, v1.* == 0);
|
test.expect(t, v1.* == 0);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -224,9 +224,7 @@ compiler :: #import "Compiler"; // @future
|
||||||
// TESTS
|
// TESTS
|
||||||
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
||||||
|
|
||||||
#if #exists(RUN_TESTS) #run {
|
#if RUN_TESTS #run {
|
||||||
test :: #import "jc/meta/test";
|
|
||||||
|
|
||||||
test.run("this_block", (t) => {
|
test.run("this_block", (t) => {
|
||||||
i := 0;
|
i := 0;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#module_parameters(RUN_TESTS_AT_COMPILE_TIME := false);
|
#module_parameters(RUN_TESTS := false);
|
||||||
|
|
||||||
get_stack_trace_caller_location :: (loc := #caller_location) -> Source_Code_Location {
|
get_stack_trace_caller_location :: (loc := #caller_location) -> Source_Code_Location {
|
||||||
if context.stack_trace == null || context.stack_trace.info == null {
|
if context.stack_trace == null || context.stack_trace.info == null {
|
||||||
|
|
@ -67,10 +67,6 @@ snake_to_pascal :: (name: string) -> string {
|
||||||
|
|
||||||
#scope_module;
|
#scope_module;
|
||||||
|
|
||||||
#if RUN_TESTS_AT_COMPILE_TIME {
|
|
||||||
RUN_TESTS :: true;
|
|
||||||
}
|
|
||||||
|
|
||||||
mem :: #import "jc/memory";
|
mem :: #import "jc/memory";
|
||||||
|
|
||||||
basic :: #import "Basic"; // @future
|
basic :: #import "Basic"; // @future
|
||||||
|
|
@ -81,10 +77,10 @@ compiler :: #import "Compiler"; // @future
|
||||||
// TESTS
|
// TESTS
|
||||||
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
||||||
|
|
||||||
#if RUN_TESTS_AT_COMPILE_TIME #run {
|
#if RUN_TESTS {
|
||||||
test :: #import "jc/meta/test";
|
test :: #import "jc/test";
|
||||||
|
|
||||||
test.run("snake_to_pascal", t => {
|
#run test.run("snake_to_pascal", t => {
|
||||||
test.expect(t, snake_to_pascal("some_name") == "SomeName");
|
test.expect(t, snake_to_pascal("some_name") == "SomeName");
|
||||||
test.expect(t, snake_to_pascal("_some_name") == "SomeName");
|
test.expect(t, snake_to_pascal("_some_name") == "SomeName");
|
||||||
test.expect(t, snake_to_pascal("some__name") == "SomeName");
|
test.expect(t, snake_to_pascal("some__name") == "SomeName");
|
||||||
|
|
|
||||||
|
|
@ -166,9 +166,7 @@ compiler :: #import "Compiler"; // @future
|
||||||
// TESTS
|
// TESTS
|
||||||
// ----------------------------------------------------------
|
// ----------------------------------------------------------
|
||||||
|
|
||||||
#if #exists(RUN_TESTS) #run {
|
#if RUN_TESTS #run {
|
||||||
test :: #import "jc/meta/test";
|
|
||||||
|
|
||||||
test.run("lo_for:primitives", t => {
|
test.run("lo_for:primitives", t => {
|
||||||
test.expect(t, lo_for(u8) == 0);
|
test.expect(t, lo_for(u8) == 0);
|
||||||
test.expect(t, lo_for(s8) == -128);
|
test.expect(t, lo_for(s8) == -128);
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
#module_parameters(RUN_TESTS_AT_COMPILE_TIME := false);
|
#module_parameters(RUN_TESTS := false);
|
||||||
|
|
||||||
#load "arch.jai";
|
#load "arch.jai";
|
||||||
|
|
||||||
|
|
||||||
#scope_module;
|
#scope_file;
|
||||||
|
|
||||||
#if RUN_TESTS_AT_COMPILE_TIME {
|
#if RUN_TESTS {
|
||||||
RUN_TESTS :: true;
|
test :: #import "jc/test";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ G: *struct {
|
||||||
|
|
||||||
// The maximum amount of memory your program is allowed to use.
|
// The maximum amount of memory your program is allowed to use.
|
||||||
// Its true size is max_memory - state_size bytes.
|
// Its true size is max_memory - state_size bytes.
|
||||||
#program_export max_memory: u64 = 4 * mem.Gigabyte;
|
#program_export max_memory: u64 = 4 * Gigabyte;
|
||||||
|
|
||||||
// The current size of the global state structure.
|
// The current size of the global state structure.
|
||||||
#program_export state_size: u64 = size_of(type_of(G.*));
|
#program_export state_size: u64 = size_of(type_of(G.*));
|
||||||
|
|
@ -90,7 +90,6 @@ G: *struct {
|
||||||
// Use the default build options
|
// Use the default build options
|
||||||
build_options :: () => reload.Simple_Build_Options.{};
|
build_options :: () => reload.Simple_Build_Options.{};
|
||||||
|
|
||||||
reload :: #import "jc/meta/reload";
|
reload :: #import "jc/reload";
|
||||||
mem :: #import "jc/memory";
|
|
||||||
|
|
||||||
#import "Basic";
|
#import "Basic";
|
||||||
|
|
@ -2,7 +2,7 @@ G: *struct {
|
||||||
allocator: Allocator;
|
allocator: Allocator;
|
||||||
};
|
};
|
||||||
|
|
||||||
#program_export max_memory: u64 = 4 * mem.Gigabyte;
|
#program_export max_memory: u64 = 4 * Gigabyte;
|
||||||
#program_export state_size: u64 = size_of(type_of(G.*));
|
#program_export state_size: u64 = size_of(type_of(G.*));
|
||||||
|
|
||||||
#program_export init :: (state: *void, allocator: Allocator, full_reset: bool) {
|
#program_export init :: (state: *void, allocator: Allocator, full_reset: bool) {
|
||||||
|
|
@ -26,8 +26,6 @@ G: *struct {
|
||||||
|
|
||||||
#import "Basic";
|
#import "Basic";
|
||||||
|
|
||||||
mem :: #import "jc/memory";
|
|
||||||
|
|
||||||
DISABLE_HOT_RELOADING :: false;
|
DISABLE_HOT_RELOADING :: false;
|
||||||
|
|
||||||
#if DISABLE_HOT_RELOADING {
|
#if DISABLE_HOT_RELOADING {
|
||||||
|
|
@ -51,7 +49,7 @@ DISABLE_HOT_RELOADING :: false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
reload :: #import "jc/meta/reload";
|
reload :: #import "jc/reload";
|
||||||
#poke_name reload frame;
|
#poke_name reload frame;
|
||||||
#poke_name reload init;
|
#poke_name reload init;
|
||||||
#poke_name reload setup;
|
#poke_name reload setup;
|
||||||
|
|
@ -113,7 +113,7 @@ user_options :: #run -> Simple_Build_Options {
|
||||||
#load "%1";
|
#load "%1";
|
||||||
|
|
||||||
main :: () {
|
main :: () {
|
||||||
(#import "jc/meta/reload").reload_main();
|
(#import "jc/reload").reload_main();
|
||||||
}
|
}
|
||||||
END, file_path);
|
END, file_path);
|
||||||
|
|
||||||
0
ext/hmm/README → thirdparty/hmm/README
vendored
0
ext/hmm/README → thirdparty/hmm/README
vendored
0
ext/raylib/README → thirdparty/raylib/README
vendored
0
ext/raylib/README → thirdparty/raylib/README
vendored
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue