diff --git a/+internal/arenas.jai b/+internal/arenas.jai index 77db098..8dc4325 100644 --- a/+internal/arenas.jai +++ b/+internal/arenas.jai @@ -1,8 +1,5 @@ -// @todo(judah): Conditionally added to the context because it causes some weirdness in tests -#if !RunTests { - #add_context arena := Arena.{ proc = PagingArenaProc }; - #add_context temp_arena := Arena.{ proc = TempArenaProc }; -} +#add_context arena := Arena.{ proc = PagingArenaProc }; +#add_context temp_arena := Arena.{ proc = TempArenaProc }; Arena :: struct { proc: ArenaProc; diff --git a/+internal/array.jai b/+internal/arrays.jai similarity index 64% rename from +internal/array.jai rename to +internal/arrays.jai index cb658a2..a01935f 100644 --- a/+internal/array.jai +++ b/+internal/arrays.jai @@ -4,7 +4,7 @@ /// Note: If no allocator has been set, ArrayAppend will use the current context allocator. /// Note: Calls to Append may invalidate pre-existing pointers. ArrayAppend :: inline (arr: *[..]$T, values: ..T) -> *T { - TrySetAllocator(arr); + TrySetAllocator(arr,, allocator = ArenaToAllocator(*context.arena)); if values.count == 0 { return basic.array_add(arr); @@ -23,7 +23,7 @@ ArrayGrow :: inline (arr: *[..]$T, new_count: int) { if new_count <= arr.allocated { return; } - TrySetAllocator(arr); + TrySetAllocator(arr,, allocator = ArenaToAllocator(*context.arena)); basic.array_reserve(arr, new_count,, allocator = arr.allocator); } @@ -58,18 +58,6 @@ ArrayEquals :: (lhs: []$T, rhs: []T) -> bool { return MemEqual(lhs.data, rhs.data, lhs.count * size_of(T)); } -CheckBounds :: ($$index: $T, $$count: T, loc := #caller_location) #expand { - Message :: "bounds check failed!"; - #if is_constant(index) && is_constant(count) { - if index < 0 || index >= count { - CompileError(Message, loc = loc); - } - } - else if index < 0 || index > count { - Panic(Message, loc = loc); - } -} - ArrayIndex :: struct(T: Type) { value: T = ---; index: int; @@ -157,89 +145,19 @@ ArrayTrim :: (view: []$T, cutset: []T, $flags: ArrayTrimFlags = .FromStart) -> [ } +CheckBounds :: ($$index: $T, $$count: T, loc := #caller_location) #expand { + Message :: "bounds check failed!"; + #if is_constant(index) && is_constant(count) { + if index < 0 || index >= count { + CompileError(Message, loc = loc); + } + } + else if index < 0 || index > count { + Panic(Message, loc = loc); + } +} + + #scope_file basic :: #import "Basic"; // @future - -#if RunTests #run,stallable { - Test("slice", t => { - a1 := int.[ 1, 2, 3, 4, 5 ]; - a2 := ArraySlice(a1, 2); - Expect(a2.count == 3); - Expect(ArrayEquals(a2, int.[ 3, 4, 5 ])); - - b1 := int.[ 1, 2, 3, 4, 5 ]; - b2 := ArraySlice(b1, 2, 0); - Expect(b2.count == 0); - Expect(b2.data == b1.data + 2); - - c1 := int.[ 1, 2, 3, 4, 5 ]; - c2 := ArraySlice(c1, 3, 1); - Expect(c2.count == 1); - Expect(ArrayEquals(c2, int.[ 4 ])); - - d1 := int.[ 1, 2, 3 ]; - d2 := ArraySlice(d1, 2); - Expect(d2.count == 1); - Expect(ArrayEquals(d2, int.[ 3 ])); - }); - - Test("find", t => { - a := int.[ 1, 2, 3, 4, 5 ]; - - ok, res := ArrayFind(a, 3); - Expect(ok && res.index == 2); - Expect(res.value == 3); - - ok, res = ArrayFind(a, -1); - Expect(!ok && res.index == -1); - - b := int.[ 1, 2, 2, 3, 4, 5, 2 ]; - - ok, res = ArrayFind(b, 2); - Expect(ok && res.index == 1); - - ok, res = ArrayFind(b, 2, .FromEnd); - Expect(ok && res.index == 6); - - c := int.[ 0, 0, 0, 1, 2, 3, 0, 0, 0 ]; - - ok, res = ArrayFind(c, 0, .Last); - Expect(ok && res.index == 8); - - ok, res = ArrayFind(c, 0, .FromEnd | .Last); - Expect(ok && res.index == 0); - }); - - Test("contains", t => { - a := int.[ 1, 2, 3, 4, 5 ]; - Expect(ArrayContains(a, 3)); - Expect(!ArrayContains(a, -1)); - }); - - Test("trim", t => { - a1 := int.[ 0, 0, 0, 1, 2, 3 ]; - a2 := ArrayTrim(a1, .[ 0 ]); - Expect(ArrayEquals(a1, .[ 0, 0, 0, 1, 2, 3 ])); - Expect(ArrayEquals(a2, .[ 1, 2, 3 ])); - - b1 := int.[ 0, 0, 0, 1, 2, 3, 0, 0, 0 ]; - b2 := ArrayTrim(b1, .[ 0 ], .FromEnd); - Expect(ArrayEquals(b1, .[ 0, 0, 0, 1, 2, 3, 0, 0, 0 ])); - Expect(ArrayEquals(b2, .[ 0, 0, 0, 1, 2, 3 ])); - - c1 := int.[ 0, 0, 0, 1, 2, 3, 0, 0, 0 ]; - c2 := ArrayTrim(c1, .[ 0 ], .FromStart | .FromEnd); - Expect(ArrayEquals(c1, .[ 0, 0, 0, 1, 2, 3, 0, 0, 0 ])); - Expect(ArrayEquals(c2, .[ 1, 2, 3 ])); - - d1 := int.[ 0, 0, 0, 1, 2, 3, 0, 0, 0 ]; - d2 := ArrayTrim(d1, .[ 0, 0, 0 ], .FromStart | .MatchInFull); - d3 := ArrayTrim(d1, .[ 0, 0, 0 ], .FromEnd | .MatchInFull); - d4 := ArrayTrim(d1, .[ 0, 0, 0 ], .FromStart | .FromEnd | .MatchInFull); - Expect(ArrayEquals(d1, .[ 0, 0, 0, 1, 2, 3, 0, 0, 0 ])); - Expect(ArrayEquals(d2, .[ 1, 2, 3, 0, 0, 0 ])); - Expect(ArrayEquals(d3, .[ 0, 0, 0, 1, 2, 3 ])); - Expect(ArrayEquals(d4, .[ 1, 2, 3 ])); - }); -} diff --git a/+internal/keywords.jai b/+internal/keywords.jai index b731fa5..979872d 100644 --- a/+internal/keywords.jai +++ b/+internal/keywords.jai @@ -192,50 +192,3 @@ range_of :: ($T: Type, loc := #caller_location) -> (T, T) #expand { return min_of(T, loc = loc), max_of(T, loc = loc); } - -#scope_file - -#if RunTests #run { - Test("min_of/max_of:enums", t => { - U8Enum :: enum u8 { lo :: -1; hi :: +1; } - S8Enum :: enum s8 { lo :: -2; hi :: -1; } - { - Expect(min_of(U8Enum) == U8Enum.lo); - Expect(min_of(S8Enum) == S8Enum.lo); - Expect(max_of(U8Enum) == U8Enum.hi); - Expect(max_of(S8Enum) == S8Enum.hi); - } - - U16Enum :: enum u16 { lo :: -1; hi :: +1; } - S16Enum :: enum s16 { lo :: -2; hi :: -1; } - { - Expect(min_of(U16Enum) == U16Enum.lo); - Expect(min_of(S16Enum) == S16Enum.lo); - Expect(max_of(U16Enum) == U16Enum.hi); - Expect(max_of(S16Enum) == S16Enum.hi); - } - - U32Enum :: enum u32 { lo :: -1; hi :: +1; } - S32Enum :: enum s32 { lo :: -2; hi :: -1; } - { - Expect(min_of(U32Enum) == U32Enum.lo); - Expect(min_of(S32Enum) == S32Enum.lo); - Expect(max_of(U32Enum) == U32Enum.hi); - Expect(max_of(S32Enum) == S32Enum.hi); - } - - U64Enum :: enum u64 { lo :: -1; hi :: +1; } - S64Enum :: enum s64 { lo :: -2; hi :: -1; } - { - Expect(min_of(U64Enum) == U64Enum.lo); - Expect(min_of(S64Enum) == S64Enum.lo); - Expect(max_of(U64Enum) == U64Enum.hi); - Expect(max_of(S64Enum) == S64Enum.hi); - } - - // @note(judah): just making sure this compiles - lo, hi := range_of(U64Enum); - Expect(lo == U64Enum.lo); - Expect(hi == U64Enum.hi); - }); -} diff --git a/+internal/map.jai b/+internal/map.jai index 51e2e50..51a94b8 100644 --- a/+internal/map.jai +++ b/+internal/map.jai @@ -120,57 +120,3 @@ LazyInit :: inline (t: *Map) { TrySetAllocator(*t.free_slots); } - -#if RunTests #run { - Test("map:basic operations", t => { - ITERATIONS :: 64; - - values: Map(int, int); - for 0..ITERATIONS { - MapSet(*values, it, it * it); - } - - for 0..ITERATIONS { - v, ok := MapGet(*values, it); - Expect(v == it * it); - } - - for 0..ITERATIONS if it % 2 == 0 { - ok := MapRemove(*values, it); - Expect(ok); - } - - for 0..ITERATIONS if it % 2 == 0 { - _, ok := MapGet(*values, it); - Expect(!ok); - } - }); - - Test("map:free slots", t => { - values: Map(int, int); - - MapSet(*values, 1, 100); - MapSet(*values, 2, 200); - MapSet(*values, 3, 300); - Expect(values.count == 3); - Expect(values.slots.allocated == values.AllocatedItemsAtStart); - - // deleting something that doesn't exist should do nothing - ok := MapRemove(*values, 0); - Expect(!ok); - Expect(values.count == 3); - - MapRemove(*values, 2); - Expect(values.count == 2); - }); - - Test("map:iteration", t => { - values: Map(int, int); - - for 0..10 MapSet(*values, it, it * it); - Expect(values.count == 11); - - for v, k: values Expect(v == k * k); - for < v, k: values Expect(v == k * k); - }); -} diff --git a/+internal/tests/module.jai b/+internal/tests/module.jai new file mode 100644 index 0000000..7ee4019 --- /dev/null +++ b/+internal/tests/module.jai @@ -0,0 +1,185 @@ +// @note(judah): these are put in a separate module to fix some weirdness with #module_parameters +// when used in the test runner. + +#import "jc"; + +#run,stallable { + // arrays + Test("slice", t => { + a1 := int.[ 1, 2, 3, 4, 5 ]; + a2 := ArraySlice(a1, 2); + Expect(a2.count == 3); + Expect(ArrayEquals(a2, int.[ 3, 4, 5 ])); + + b1 := int.[ 1, 2, 3, 4, 5 ]; + b2 := ArraySlice(b1, 2, 0); + Expect(b2.count == 0); + Expect(b2.data == b1.data + 2); + + c1 := int.[ 1, 2, 3, 4, 5 ]; + c2 := ArraySlice(c1, 3, 1); + Expect(c2.count == 1); + Expect(ArrayEquals(c2, int.[ 4 ])); + + d1 := int.[ 1, 2, 3 ]; + d2 := ArraySlice(d1, 2); + Expect(d2.count == 1); + Expect(ArrayEquals(d2, int.[ 3 ])); + }); + + Test("find", t => { + a := int.[ 1, 2, 3, 4, 5 ]; + + ok, res := ArrayFind(a, 3); + Expect(ok && res.index == 2); + Expect(res.value == 3); + + ok, res = ArrayFind(a, -1); + Expect(!ok && res.index == -1); + + b := int.[ 1, 2, 2, 3, 4, 5, 2 ]; + + ok, res = ArrayFind(b, 2); + Expect(ok && res.index == 1); + + ok, res = ArrayFind(b, 2, .FromEnd); + Expect(ok && res.index == 6); + + c := int.[ 0, 0, 0, 1, 2, 3, 0, 0, 0 ]; + + ok, res = ArrayFind(c, 0, .Last); + Expect(ok && res.index == 8); + + ok, res = ArrayFind(c, 0, .FromEnd | .Last); + Expect(ok && res.index == 0); + }); + + Test("contains", t => { + a := int.[ 1, 2, 3, 4, 5 ]; + Expect(ArrayContains(a, 3)); + Expect(!ArrayContains(a, -1)); + }); + + Test("trim", t => { + a1 := int.[ 0, 0, 0, 1, 2, 3 ]; + a2 := ArrayTrim(a1, .[ 0 ]); + Expect(ArrayEquals(a1, .[ 0, 0, 0, 1, 2, 3 ])); + Expect(ArrayEquals(a2, .[ 1, 2, 3 ])); + + b1 := int.[ 0, 0, 0, 1, 2, 3, 0, 0, 0 ]; + b2 := ArrayTrim(b1, .[ 0 ], .FromEnd); + Expect(ArrayEquals(b1, .[ 0, 0, 0, 1, 2, 3, 0, 0, 0 ])); + Expect(ArrayEquals(b2, .[ 0, 0, 0, 1, 2, 3 ])); + + c1 := int.[ 0, 0, 0, 1, 2, 3, 0, 0, 0 ]; + c2 := ArrayTrim(c1, .[ 0 ], .FromStart | .FromEnd); + Expect(ArrayEquals(c1, .[ 0, 0, 0, 1, 2, 3, 0, 0, 0 ])); + Expect(ArrayEquals(c2, .[ 1, 2, 3 ])); + + d1 := int.[ 0, 0, 0, 1, 2, 3, 0, 0, 0 ]; + d2 := ArrayTrim(d1, .[ 0, 0, 0 ], .FromStart | .MatchInFull); + d3 := ArrayTrim(d1, .[ 0, 0, 0 ], .FromEnd | .MatchInFull); + d4 := ArrayTrim(d1, .[ 0, 0, 0 ], .FromStart | .FromEnd | .MatchInFull); + Expect(ArrayEquals(d1, .[ 0, 0, 0, 1, 2, 3, 0, 0, 0 ])); + Expect(ArrayEquals(d2, .[ 1, 2, 3, 0, 0, 0 ])); + Expect(ArrayEquals(d3, .[ 0, 0, 0, 1, 2, 3 ])); + Expect(ArrayEquals(d4, .[ 1, 2, 3 ])); + }); + + // type_info + Test("min_of/max_of:enums", t => { + U8Enum :: enum u8 { lo :: -1; hi :: +1; } + S8Enum :: enum s8 { lo :: -2; hi :: -1; } + { + Expect(min_of(U8Enum) == U8Enum.lo); + Expect(min_of(S8Enum) == S8Enum.lo); + Expect(max_of(U8Enum) == U8Enum.hi); + Expect(max_of(S8Enum) == S8Enum.hi); + } + + U16Enum :: enum u16 { lo :: -1; hi :: +1; } + S16Enum :: enum s16 { lo :: -2; hi :: -1; } + { + Expect(min_of(U16Enum) == U16Enum.lo); + Expect(min_of(S16Enum) == S16Enum.lo); + Expect(max_of(U16Enum) == U16Enum.hi); + Expect(max_of(S16Enum) == S16Enum.hi); + } + + U32Enum :: enum u32 { lo :: -1; hi :: +1; } + S32Enum :: enum s32 { lo :: -2; hi :: -1; } + { + Expect(min_of(U32Enum) == U32Enum.lo); + Expect(min_of(S32Enum) == S32Enum.lo); + Expect(max_of(U32Enum) == U32Enum.hi); + Expect(max_of(S32Enum) == S32Enum.hi); + } + + U64Enum :: enum u64 { lo :: -1; hi :: +1; } + S64Enum :: enum s64 { lo :: -2; hi :: -1; } + { + Expect(min_of(U64Enum) == U64Enum.lo); + Expect(min_of(S64Enum) == S64Enum.lo); + Expect(max_of(U64Enum) == U64Enum.hi); + Expect(max_of(S64Enum) == S64Enum.hi); + } + + // @note(judah): just making sure this compiles + lo, hi := range_of(U64Enum); + Expect(lo == U64Enum.lo); + Expect(hi == U64Enum.hi); + }); + + // map + Test("map:basic operations", t => { + ITERATIONS :: 64; + + values: Map(int, int); + for 0..ITERATIONS { + MapSet(*values, it, it * it); + } + + for 0..ITERATIONS { + v, ok := MapGet(*values, it); + Expect(v == it * it); + } + + for 0..ITERATIONS if it % 2 == 0 { + ok := MapRemove(*values, it); + Expect(ok); + } + + for 0..ITERATIONS if it % 2 == 0 { + _, ok := MapGet(*values, it); + Expect(!ok); + } + }); + + Test("map:free slots", t => { + values: Map(int, int); + + MapSet(*values, 1, 100); + MapSet(*values, 2, 200); + MapSet(*values, 3, 300); + Expect(values.count == 3); + Expect(values.slots.allocated == values.AllocatedItemsAtStart); + + // deleting something that doesn't exist should do nothing + ok := MapRemove(*values, 0); + Expect(!ok); + Expect(values.count == 3); + + MapRemove(*values, 2); + Expect(values.count == 2); + }); + + Test("map:iteration", t => { + values: Map(int, int); + + for 0..10 MapSet(*values, it, it * it); + Expect(values.count == 11); + + for v, k: values Expect(v == k * k); + for < v, k: values Expect(v == k * k); + }); +} diff --git a/_run_all_tests.jai b/_run_all_tests.jai index 33c51fb..b90dee7 100644 --- a/_run_all_tests.jai +++ b/_run_all_tests.jai @@ -2,7 +2,8 @@ compiler :: #import "Compiler"; compiler.set_build_options_dc(.{ do_output = false }); - _ :: #import "jc"(true); + _ :: #import "jc"; + _ :: #import "jc/+internal/tests"; _ :: #import "jc/math"(RUN_TESTS = true); _ :: #import "jc/fmt/base64"(true); diff --git a/module.jai b/module.jai index e7cc183..fefefdf 100644 --- a/module.jai +++ b/module.jai @@ -5,14 +5,13 @@ /// Additionally, it provides a platform-independant /// interface for interacting with the target operating /// system. -#module_parameters(RunTests := false); #load "+internal/builtin.jai"; -#load "+internal/array.jai"; +#load "+internal/arenas.jai"; +#load "+internal/memory.jai"; +#load "+internal/arrays.jai"; #load "+internal/map.jai"; #load "+internal/hashing.jai"; -#load "+internal/memory.jai"; -#load "+internal/arenas.jai"; #load "+internal/testing.jai"; #load "+internal/keywords.jai"; #load "+internal/type_info.jai";