diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 97853b5b0..6f8ef15a1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -33,9 +33,9 @@ jobs: - name: Compile and run some examples run: | cd resources - ..\build\${{ matrix.build_type }}\c3c.exe compile-run examples\hello_world_many.c3 - ..\build\${{ matrix.build_type }}\c3c.exe compile-run examples\time.c3 - ..\build\${{ matrix.build_type }}\c3c.exe compile-run examples\fannkuch-redux.c3 + ..\build\${{ matrix.build_type }}\c3c.exe compile-run --print-linking examples\hello_world_many.c3 + ..\build\${{ matrix.build_type }}\c3c.exe compile-run --print-linking examples\time.c3 + ..\build\${{ matrix.build_type }}\c3c.exe compile-run --print-linking examples\fannkuch-redux.c3 ..\build\${{ matrix.build_type }}\c3c.exe compile-run examples\contextfree\boolerr.c3 ..\build\${{ matrix.build_type }}\c3c.exe compile-run examples\ls.c3 ..\build\${{ matrix.build_type }}\c3c.exe compile-run examples\load_world.c3 @@ -122,11 +122,11 @@ jobs: - name: Compile and run some examples run: | cd resources - ../build/c3c compile-run examples/hello_world_many.c3 - ../build/c3c compile-run examples/time.c3 - ../build/c3c compile-run examples/fannkuch-redux.c3 - ../build/c3c compile-run examples/contextfree/boolerr.c3 - ../build/c3c compile-run examples/load_world.c3 + ../build/c3c compile-run --print-linking examples/hello_world_many.c3 + ../build/c3c compile-run --print-linking examples/time.c3 + ../build/c3c compile-run --print-linking examples/fannkuch-redux.c3 + ../build/c3c compile-run --print-linking examples/contextfree/boolerr.c3 + ../build/c3c compile-run --print-linking examples/load_world.c3 ../build/c3c compile --test -g -O0 --threads 1 --target macos-x64 examples/constants.c3 - name: Build testproject @@ -293,7 +293,7 @@ jobs: ../build/c3c compile-run examples/load_world.c3 ../build/c3c compile-run examples/process.c3 ../build/c3c compile-run examples/ls.c3 - ../build/c3c compile-run --system-linker=no linux_stack.c3 + ../build/c3c compile-run --linker=builtin linux_stack.c3 ../build/c3c compile-run linux_stack.c3 - name: Compile run unit tests @@ -309,7 +309,7 @@ jobs: - name: Build testproject direct linker run: | cd resources/testproject - ../../build/c3c run --debug-log --system-linker=no + ../../build/c3c run --debug-log --linker=builtin - name: run compiler tests run: | @@ -400,7 +400,7 @@ jobs: ../build/c3c compile-run examples/factorial_macro.c3 ../build/c3c compile-run examples/fasta.c3 ../build/c3c compile-run examples/process.c3 - ../build/c3c compile-run --system-linker=no linux_stack.c3 + ../build/c3c compile-run --linker=builtin linux_stack.c3 ../build/c3c compile-run linux_stack.c3 - name: Compile run unit tests @@ -416,7 +416,7 @@ jobs: - name: Build testproject direct linker run: | cd resources/testproject - ../../build/c3c run --debug-log --system-linker=no + ../../build/c3c run --debug-log --linker=builtin - name: run compiler tests run: | @@ -474,6 +474,7 @@ jobs: ../build/c3c compile-run examples/contextfree/boolerr.c3 ../build/c3c compile-run examples/process.c3 ../build/c3c compile-run examples/load_world.c3 + ../build/c3c compile-run -O5 examples/load_world.c3 - name: Compile run unit tests run: | @@ -488,7 +489,7 @@ jobs: - name: Build testproject direct linker run: | cd resources/testproject - ../../build/c3c run --debug-log --system-linker=no + ../../build/c3c run --debug-log --linker=builtin - name: Build testproject lib run: | diff --git a/README.md b/README.md index ea7651d54..61de5d8c5 100644 --- a/README.md +++ b/README.md @@ -122,7 +122,7 @@ fn void main() - No mandatory header files - New semantic macro system - Module based name spacing -- Subarrays (slices) +- Slices - Compile time reflection - Enhanced compile time execution - Generics based on generic modules @@ -212,6 +212,8 @@ More platforms will be supported in the future. 3. Unzip executable and standard lib. 4. Run `./c3c`. +(*Note that there is a known issue with debug symbol generation on MacOS 13, see issue #1086) + #### Installing on Arch Linux There is an AUR package for the c3c compiler : [c3c-git](https://aur.archlinux.org/packages/c3c-git). diff --git a/lib/std/atomic.c3 b/lib/std/atomic.c3 index 9f39017c2..eff1d59c4 100644 --- a/lib/std/atomic.c3 +++ b/lib/std/atomic.c3 @@ -124,7 +124,7 @@ macro @atomic_exec(#func, data, value, ordering) @local case RELEASE: return #func(data, value, RELEASE); case ACQUIRE_RELEASE: return #func(data, value, ACQUIRE_RELEASE); case SEQ_CONSISTENT: return #func(data, value, SEQ_CONSISTENT); - default: assert(false, "Ordering may not be non-atomic or unordered."); + default: unreachable("Ordering may not be non-atomic or unordered."); } } diff --git a/lib/std/atomic_nolibc.c3 b/lib/std/atomic_nolibc.c3 index 753bee9b2..b9ec23e3a 100644 --- a/lib/std/atomic_nolibc.c3 +++ b/lib/std/atomic_nolibc.c3 @@ -9,7 +9,7 @@ macro @__atomic_compare_exchange_ordering_failure(ptr, expected, desired, $succe case AtomicOrdering.RELAXED.ordinal: return $$compare_exchange(ptr, expected, desired, false, false, $success, AtomicOrdering.RELAXED.ordinal, $alignment); case AtomicOrdering.ACQUIRE.ordinal: return $$compare_exchange(ptr, expected, desired, false, false, $success, AtomicOrdering.ACQUIRE.ordinal, $alignment); case AtomicOrdering.SEQ_CONSISTENT.ordinal: return $$compare_exchange(ptr, expected, desired, false, false, $success, AtomicOrdering.SEQ_CONSISTENT.ordinal, $alignment); - default: assert(false, "Unrecognized failure ordering"); + default: unreachable("Unrecognized failure ordering"); } return 0; } @@ -23,12 +23,12 @@ macro @__atomic_compare_exchange_ordering_success(ptr, expected, desired, succes case AtomicOrdering.RELEASE.ordinal: return @__atomic_compare_exchange_ordering_failure(ptr, expected, desired, AtomicOrdering.RELEASE.ordinal, failure, $alignment); case AtomicOrdering.ACQUIRE_RELEASE.ordinal: return @__atomic_compare_exchange_ordering_failure(ptr, expected, desired, AtomicOrdering.ACQUIRE_RELEASE.ordinal, failure, $alignment); case AtomicOrdering.SEQ_CONSISTENT.ordinal: return @__atomic_compare_exchange_ordering_failure(ptr, expected, desired, AtomicOrdering.SEQ_CONSISTENT.ordinal, failure, $alignment); - default: assert(false, "Unrecognized success ordering"); + default: unreachable("Unrecognized success ordering"); } return 0; } -fn CInt __atomic_compare_exchange(CInt size, any* ptr, any* expected, any* desired, CInt success, CInt failure) @extern("__atomic_compare_exchange") @export +fn CInt __atomic_compare_exchange(CInt size, any ptr, any expected, any desired, CInt success, CInt failure) @extern("__atomic_compare_exchange") @export { switch (size) { @@ -57,7 +57,7 @@ fn CInt __atomic_compare_exchange(CInt size, any* ptr, any* expected, any* desir nextcase; $endif default: - assert(false, "Unsuported size (%d) for atomic_compare_exchange", size); + unreachable("Unsuported size (%d) for atomic_compare_exchange", size); } return 0; } \ No newline at end of file diff --git a/lib/std/collections/generic_list.c3 b/lib/std/collections/anylist.c3 similarity index 70% rename from lib/std/collections/generic_list.c3 rename to lib/std/collections/anylist.c3 index 18587f0e1..90cb08bb8 100644 --- a/lib/std/collections/generic_list.c3 +++ b/lib/std/collections/anylist.c3 @@ -1,18 +1,18 @@ // Copyright (c) 2024 Christoffer Lerno. All rights reserved. // Use of self source code is governed by the MIT license // a copy of which can be found in the LICENSE_STDLIB file. -module std::collections::generic_list; +module std::collections::anylist; import std::io,std::math; -def GenericPredicate = fn bool(any* value); -def GenericTest = fn bool(any* type, any* context); +def AnyPredicate = fn bool(any value); +def AnyTest = fn bool(any type, any context); -struct GenericList (Printable) +struct AnyList (Printable) { usz size; usz capacity; - Allocator* allocator; - any** entries; + Allocator allocator; + any* entries; } @@ -20,14 +20,14 @@ struct GenericList (Printable) * @param initial_capacity "The initial capacity to reserve" * @param [&inout] allocator "The allocator to use, defaults to the heap allocator" **/ -fn GenericList* GenericList.new_init(&self, usz initial_capacity = 16, Allocator* allocator = allocator::heap()) +fn AnyList* AnyList.new_init(&self, usz initial_capacity = 16, Allocator allocator = allocator::heap()) { self.allocator = allocator; self.size = 0; if (initial_capacity > 0) { initial_capacity = math::next_power_of_2(initial_capacity); - self.entries = allocator::alloc_array(allocator, any*, initial_capacity); + self.entries = allocator::alloc_array(allocator, any, initial_capacity); } else { @@ -37,26 +37,17 @@ fn GenericList* GenericList.new_init(&self, usz initial_capacity = 16, Allocator return self; } -/** - * @param initial_capacity "The initial capacity to reserve" - * @param [&inout] allocator "The allocator to use, defaults to the heap allocator" - **/ -fn GenericList* GenericList.init_new(&self, usz initial_capacity = 16, Allocator* allocator = allocator::heap()) @deprecated("Replaced by new_init") -{ - return self.new_init(initial_capacity, allocator) @inline; -} - /** * Initialize the list using the temp allocator. * * @param initial_capacity "The initial capacity to reserve" **/ -fn GenericList* GenericList.temp_init(&self, usz initial_capacity = 16) +fn AnyList* AnyList.temp_init(&self, usz initial_capacity = 16) { return self.new_init(initial_capacity, allocator::temp()) @inline; } -fn usz! GenericList.to_format(&self, Formatter* formatter) @dynamic +fn usz! AnyList.to_format(&self, Formatter* formatter) @dynamic { switch (self.size) { @@ -76,12 +67,12 @@ fn usz! GenericList.to_format(&self, Formatter* formatter) @dynamic } } -fn String GenericList.to_new_string(&self, Allocator* allocator = allocator::heap()) @dynamic +fn String AnyList.to_new_string(&self, Allocator allocator = allocator::heap()) @dynamic { return string::new_format("%s", *self, .allocator = allocator); } -fn String GenericList.to_tstring(&self) +fn String AnyList.to_tstring(&self) { return string::tformat("%s", *self); } @@ -89,13 +80,13 @@ fn String GenericList.to_tstring(&self) /** * Push an element on the list by cloning it. **/ -macro void GenericList.push(&self, element) +macro void AnyList.push(&self, element) { if (!self.allocator) self.allocator = allocator::heap(); self.append_internal(allocator::clone(self.allocator, element)); } -fn void GenericList.append_internal(&self, any* element) @local +fn void AnyList.append_internal(&self, any element) @local { self.ensure_capacity(); self.entries[self.size++] = element; @@ -104,7 +95,7 @@ fn void GenericList.append_internal(&self, any* element) @local /** * Free a retained element removed using *_retained. **/ -fn void GenericList.free_element(&self, any* element) @inline +fn void AnyList.free_element(&self, any element) @inline { allocator::free(self.allocator, element.ptr); } @@ -115,7 +106,7 @@ fn void GenericList.free_element(&self, any* element) @inline * * @return! CastResult.TYPE_MISMATCH, IteratorResult.NO_MORE_ELEMENT **/ -macro GenericList.pop(&self, $Type) +macro AnyList.pop(&self, $Type) { if (!self.size) return IteratorResult.NO_MORE_ELEMENT?; defer self.free_element(self.entries[self.size]); @@ -126,7 +117,7 @@ macro GenericList.pop(&self, $Type) * Pop the last value and allocate the copy using the given allocator. * @return! IteratorResult.NO_MORE_ELEMENT **/ -fn any*! GenericList.new_pop(&self, Allocator* allocator = allocator::heap()) +fn any! AnyList.new_pop(&self, Allocator allocator = allocator::heap()) { if (!self.size) return IteratorResult.NO_MORE_ELEMENT?; defer self.free_element(self.entries[self.size]); @@ -137,19 +128,19 @@ fn any*! GenericList.new_pop(&self, Allocator* allocator = allocator::heap()) * Pop the last value and allocate the copy using the temp allocator * @return! IteratorResult.NO_MORE_ELEMENT **/ -fn any*! GenericList.temp_pop(&self) => self.new_pop(allocator::temp()); +fn any! AnyList.temp_pop(&self) => self.new_pop(allocator::temp()); /** * Pop the last value. It must later be released using list.free_element() * @return! IteratorResult.NO_MORE_ELEMENT **/ -fn any*! GenericList.pop_retained(&self) +fn any! AnyList.pop_retained(&self) { if (!self.size) return IteratorResult.NO_MORE_ELEMENT?; return self.entries[--self.size]; } -fn void GenericList.clear(&self) +fn void AnyList.clear(&self) { for (usz i = 0; i < self.size; i++) { @@ -161,7 +152,7 @@ fn void GenericList.clear(&self) /** * Same as pop() but pops the first value instead. **/ -macro GenericList.pop_first(&self, $Type) +macro AnyList.pop_first(&self, $Type) { if (!self.size) return IteratorResult.NO_MORE_ELEMENT?; defer self.remove_at(0); @@ -171,7 +162,7 @@ macro GenericList.pop_first(&self, $Type) /** * Same as pop_retained() but pops the first value instead. **/ -fn any*! GenericList.pop_first_retained(&self) +fn any! AnyList.pop_first_retained(&self) { if (!self.size) return IteratorResult.NO_MORE_ELEMENT?; defer self.remove_at(0); @@ -181,7 +172,7 @@ fn any*! GenericList.pop_first_retained(&self) /** * Same as new_pop() but pops the first value instead. **/ -fn any*! GenericList.new_pop_first(&self, Allocator* allocator = allocator::heap()) +fn any! AnyList.new_pop_first(&self, Allocator allocator = allocator::heap()) { if (!self.size) return IteratorResult.NO_MORE_ELEMENT?; defer self.free_element(self.entries[self.size]); @@ -192,19 +183,19 @@ fn any*! GenericList.new_pop_first(&self, Allocator* allocator = allocator::heap /** * Same as temp_pop() but pops the first value instead. **/ -fn any*! GenericList.temp_pop_first(&self) => self.new_pop_first(allocator::temp()); +fn any! AnyList.temp_pop_first(&self) => self.new_pop_first(allocator::temp()); /** * @require index < self.size **/ -fn void GenericList.remove_at(&self, usz index) +fn void AnyList.remove_at(&self, usz index) { if (!--self.size || index == self.size) return; self.free_element(self.entries[index]); self.entries[index .. self.size - 1] = self.entries[index + 1 .. self.size]; } -fn void GenericList.add_all(&self, GenericList* other_list) +fn void AnyList.add_all(&self, AnyList* other_list) { if (!other_list.size) return; self.reserve(other_list.size); @@ -217,7 +208,7 @@ fn void GenericList.add_all(&self, GenericList* other_list) /** * Reverse the elements in a list. **/ -fn void GenericList.reverse(&self) +fn void AnyList.reverse(&self) { if (self.size < 2) return; usz half = self.size / 2U; @@ -228,7 +219,7 @@ fn void GenericList.reverse(&self) } } -fn any*[] GenericList.array_view(&self) +fn any[] AnyList.array_view(&self) { return self.entries[:self.size]; } @@ -236,7 +227,7 @@ fn any*[] GenericList.array_view(&self) /** * Push an element to the front of the list. **/ -macro void GenericList.push_front(&self, type) +macro void AnyList.push_front(&self, type) { self.insert_at(0, type); } @@ -244,16 +235,16 @@ macro void GenericList.push_front(&self, type) /** * @require index < self.size **/ -macro void GenericList.insert_at(&self, usz index, type) @local +macro void AnyList.insert_at(&self, usz index, type) @local { - any* value = allocator::copy(self.allocator, type); + any value = allocator::copy(self.allocator, type); self.insert_at_internal(self, index, value); } /** * @require index < self.size **/ -fn void GenericList.insert_at_internal(&self, usz index, any* value) @local +fn void AnyList.insert_at_internal(&self, usz index, any value) @local { self.ensure_capacity(); for (usz i = self.size; i > index; i--) @@ -268,7 +259,7 @@ fn void GenericList.insert_at_internal(&self, usz index, any* value) @local /** * @require self.size > 0 **/ -fn void GenericList.remove_last(&self) +fn void AnyList.remove_last(&self) { self.free_element(self.entries[--self.size]); } @@ -276,37 +267,37 @@ fn void GenericList.remove_last(&self) /** * @require self.size > 0 **/ -fn void GenericList.remove_first(&self) +fn void AnyList.remove_first(&self) { self.remove_at(0); } -macro GenericList.first(&self, $Type) +macro AnyList.first(&self, $Type) { return *anycast(self.first_any(), $Type); } -fn any*! GenericList.first_any(&self) @inline +fn any! AnyList.first_any(&self) @inline { return self.size ? self.entries[0] : IteratorResult.NO_MORE_ELEMENT?; } -macro GenericList.last(&self, $Type) +macro AnyList.last(&self, $Type) { return *anycast(self.last_any(), $Type); } -fn any*! GenericList.last_any(&self) @inline +fn any! AnyList.last_any(&self) @inline { return self.size ? self.entries[self.size - 1] : IteratorResult.NO_MORE_ELEMENT?; } -fn bool GenericList.is_empty(&self) @inline +fn bool AnyList.is_empty(&self) @inline { return !self.size; } -fn usz GenericList.len(&self) @operator(len) @inline +fn usz AnyList.len(&self) @operator(len) @inline { return self.size; } @@ -314,7 +305,7 @@ fn usz GenericList.len(&self) @operator(len) @inline /** * @require index < self.size "Index out of range" **/ -macro GenericList.get(&self, usz index, $Type) +macro AnyList.get(&self, usz index, $Type) { return *anycast(self.entries[index], $Type); } @@ -322,12 +313,12 @@ macro GenericList.get(&self, usz index, $Type) /** * @require index < self.size "Index out of range" **/ -fn any* GenericList.get_any(&self, usz index) @inline +fn any AnyList.get_any(&self, usz index) @inline { return self.entries[index]; } -fn void GenericList.free(&self) +fn void AnyList.free(&self) { if (!self.allocator) return; self.clear(); @@ -336,9 +327,9 @@ fn void GenericList.free(&self) self.entries = null; } -fn void GenericList.swap(&self, usz i, usz j) +fn void AnyList.swap(&self, usz i, usz j) { - any* temp = self.entries[i]; + any temp = self.entries[i]; self.entries[i] = self.entries[j]; self.entries[j] = temp; } @@ -347,7 +338,7 @@ fn void GenericList.swap(&self, usz i, usz j) * @param filter "The function to determine if it should be removed or not" * @return "the number of deleted elements" **/ -fn usz GenericList.remove_if(&self, GenericPredicate filter) +fn usz AnyList.remove_if(&self, AnyPredicate filter) { return self._remove_if(filter, false); } @@ -356,12 +347,12 @@ fn usz GenericList.remove_if(&self, GenericPredicate filter) * @param selection "The function to determine if it should be kept or not" * @return "the number of deleted elements" **/ -fn usz GenericList.retain_if(&self, GenericPredicate selection) +fn usz AnyList.retain_if(&self, AnyPredicate selection) { return self._remove_if(selection, true); } -macro usz GenericList._remove_if(&self, GenericPredicate filter, bool $invert) @local +macro usz AnyList._remove_if(&self, AnyPredicate filter, bool $invert) @local { usz size = self.size; for (usz i = size, usz k = size; k > 0; k = i) @@ -387,17 +378,17 @@ macro usz GenericList._remove_if(&self, GenericPredicate filter, bool $invert) @ return size - self.size; } -fn usz GenericList.remove_using_test(&self, GenericTest filter, any* context) +fn usz AnyList.remove_using_test(&self, AnyTest filter, any context) { return self._remove_using_test(filter, false, context); } -fn usz GenericList.retain_using_test(&self, GenericTest filter, any* context) +fn usz AnyList.retain_using_test(&self, AnyTest filter, any context) { return self._remove_using_test(filter, true, context); } -macro usz GenericList._remove_using_test(&self, GenericTest filter, bool $invert, ctx) @local +macro usz AnyList._remove_using_test(&self, AnyTest filter, bool $invert, ctx) @local { usz size = self.size; for (usz i = size, usz k = size; k > 0; k = i) @@ -426,17 +417,17 @@ macro usz GenericList._remove_using_test(&self, GenericTest filter, bool $invert /** * Reserve at least min_capacity **/ -fn void GenericList.reserve(&self, usz min_capacity) +fn void AnyList.reserve(&self, usz min_capacity) { if (!min_capacity) return; if (self.capacity >= min_capacity) return; if (!self.allocator) self.allocator = allocator::heap(); min_capacity = math::next_power_of_2(min_capacity); - self.entries = allocator::realloc(self.allocator, self.entries, any*.sizeof * min_capacity); + self.entries = allocator::realloc(self.allocator, self.entries, any.sizeof * min_capacity); self.capacity = min_capacity; } -macro any* GenericList.@item_at(&self, usz index) @operator([]) +macro any AnyList.@item_at(&self, usz index) @operator([]) { return self.entries[index]; } @@ -444,7 +435,7 @@ macro any* GenericList.@item_at(&self, usz index) @operator([]) /** * @require index <= self.size "Index out of range" **/ -macro void GenericList.set(&self, usz index, value) +macro void AnyList.set(&self, usz index, value) { if (index == self.size) { @@ -455,7 +446,7 @@ macro void GenericList.set(&self, usz index, value) self.entries[index] = allocator::copy(self.allocator, value); } -fn void GenericList.ensure_capacity(&self, usz added = 1) @inline @private +fn void AnyList.ensure_capacity(&self, usz added = 1) @inline @private { usz new_size = self.size + added; if (self.capacity >= new_size) return; diff --git a/lib/std/collections/bitset.c3 b/lib/std/collections/bitset.c3 index 76af33693..6ea47cf47 100644 --- a/lib/std/collections/bitset.c3 +++ b/lib/std/collections/bitset.c3 @@ -86,31 +86,17 @@ struct GrowableBitSet * @param initial_capacity * @param [&inout] allocator "The allocator to use, defaults to the heap allocator" **/ -fn GrowableBitSet* GrowableBitSet.new_init(&self, usz initial_capacity = 1, Allocator* allocator = allocator::heap()) +fn GrowableBitSet* GrowableBitSet.new_init(&self, usz initial_capacity = 1, Allocator allocator = allocator::heap()) { self.data.new_init(initial_capacity, allocator); return self; } -/** - * @param initial_capacity - * @param [&inout] allocator "The allocator to use, defaults to the heap allocator" - **/ -fn GrowableBitSet* GrowableBitSet.init_new(&self, usz initial_capacity = 1, Allocator* allocator = allocator::heap()) @deprecated("Replaced by new_init") -{ - return self.new_init(initial_capacity, allocator) @inline; -} - fn GrowableBitSet* GrowableBitSet.temp_init(&self, usz initial_capacity = 1) { return self.new_init(initial_capacity, allocator::temp()) @inline; } -fn GrowableBitSet* GrowableBitSet.init_temp(&self, usz initial_capacity = 1) @deprecated("Replaced by temp_init") -{ - return self.temp_init(initial_capacity); -} - fn void GrowableBitSet.free(&self) { self.data.free(); diff --git a/lib/std/collections/enummap.c3 b/lib/std/collections/enummap.c3 index bf5835b08..0b254e8b4 100644 --- a/lib/std/collections/enummap.c3 +++ b/lib/std/collections/enummap.c3 @@ -25,7 +25,7 @@ fn usz! EnumMap.to_format(&self, Formatter* formatter) @dynamic return n; } -fn String EnumMap.to_new_string(&self, Allocator* allocator = allocator::heap()) @dynamic +fn String EnumMap.to_new_string(&self, Allocator allocator = allocator::heap()) @dynamic { return string::new_format("%s", *self, .allocator = allocator); } diff --git a/lib/std/collections/enumset.c3 b/lib/std/collections/enumset.c3 index 8eaa79dcd..7f207694d 100644 --- a/lib/std/collections/enumset.c3 +++ b/lib/std/collections/enumset.c3 @@ -141,7 +141,7 @@ fn usz! EnumSet.to_format(&set, Formatter* formatter) @dynamic return n; } -fn String EnumSet.to_new_string(&set, Allocator* allocator = allocator::heap()) @dynamic +fn String EnumSet.to_new_string(&set, Allocator allocator = allocator::heap()) @dynamic { return string::new_format("%s", *set, .allocator = allocator); } diff --git a/lib/std/collections/linkedlist.c3 b/lib/std/collections/linkedlist.c3 index bd3082b28..9b48ac97b 100644 --- a/lib/std/collections/linkedlist.c3 +++ b/lib/std/collections/linkedlist.c3 @@ -3,6 +3,8 @@ // a copy of which can be found in the LICENSE_STDLIB file. module std::collections::linkedlist(); +const ELEMENT_IS_EQUATABLE = types::is_equatable_type(Type); + struct Node @private { Node *next; @@ -12,51 +14,28 @@ struct Node @private struct LinkedList { - Allocator *allocator; + Allocator allocator; usz size; Node *_first; Node *_last; } -fn void LinkedList.push(&self, Type value) -{ - self.link_first(value); -} - -fn void LinkedList.push_last(&self, Type value) -{ - self.link_last(value); -} - /** * @param [&inout] allocator "The allocator to use, defaults to the heap allocator" * @return "the initialized list" **/ -fn LinkedList* LinkedList.new_init(&self, Allocator* allocator = allocator::heap()) +fn LinkedList* LinkedList.new_init(&self, Allocator allocator = allocator::heap()) { *self = { .allocator = allocator }; return self; } -/** - * @param [&inout] allocator "The allocator to use, defaults to the heap allocator" - * @return "the initialized list" - **/ -fn LinkedList* LinkedList.init_new(&self, Allocator* allocator = allocator::heap()) @deprecated("Replaced by new_init") -{ - return self.new_init(allocator); -} fn LinkedList* LinkedList.temp_init(&self) { return self.new_init(allocator::temp()) @inline; } -fn LinkedList* LinkedList.init_temp(&self) @deprecated("Replaced by temp_init") -{ - return self.temp_init() @inline; -} - /** * @require self.allocator **/ @@ -71,7 +50,7 @@ macro Node* LinkedList.alloc_node(&self) @private return allocator::alloc(self.allocator, Node); } -fn void LinkedList.link_first(&self, Type value) @private +fn void LinkedList.push_front(&self, Type value) { Node *first = self._first; Node *new_node = self.alloc_node(); @@ -88,7 +67,7 @@ fn void LinkedList.link_first(&self, Type value) @private self.size++; } -fn void LinkedList.link_last(&self, Type value) @private +fn void LinkedList.push(&self, Type value) { Node *last = self._last; Node *new_node = self.alloc_node(); @@ -172,7 +151,7 @@ fn void LinkedList.set(&self, usz index, Type element) /** * @require index < self.size **/ -fn void LinkedList.remove(&self, usz index) +fn void LinkedList.remove_at(&self, usz index) { self.unlink(self.node_at_index(index)); } @@ -180,14 +159,14 @@ fn void LinkedList.remove(&self, usz index) /** * @require index <= self.size **/ -fn void LinkedList.insert(&self, usz index, Type element) +fn void LinkedList.insert_at(&self, usz index, Type element) { switch (index) { case 0: - self.push(element); + self.push_front(element); case self.size: - self.push_last(element); + self.push(element); default: self.link_before(self.node_at_index(index), element); } @@ -232,51 +211,77 @@ fn void LinkedList.unlink_first(&self) @private self.size--; } -fn bool LinkedList.remove_value(&self, Type t) +fn usz LinkedList.remove(&self, Type t) @if(ELEMENT_IS_EQUATABLE) { - for (Node* node = self._first; node != null; node = node.next) + usz start = self.size; + Node* node = self._first; + while (node) { - if (node.value == t) + switch { - self.unlink(node); - return true; + case equals(node.value, t): + Node* next = node.next; + self.unlink(node); + node = next; + default: + node = node.next; } } - return false; + return start - self.size; } -fn bool LinkedList.remove_last_value(&self, Type t) +fn Type! LinkedList.pop(&self) { - for (Node* node = self._last; node != null; node = node.prev) - { - if (node.value == t) - { - self.unlink(node); - return true; - } - } - return false; + if (!self._last) return IteratorResult.NO_MORE_ELEMENT?; + defer self.unlink_last(); + return self._last.value; } -fn Type! LinkedList.pop(&self) +fn Type! LinkedList.pop_front(&self) { if (!self._first) return IteratorResult.NO_MORE_ELEMENT?; defer self.unlink_first(); return self._first.value; } -fn void! LinkedList.remove_last(&self) +fn void! LinkedList.remove_last(&self) @maydiscard { if (!self._first) return IteratorResult.NO_MORE_ELEMENT?; self.unlink_last(); } -fn void! LinkedList.remove_first(&self) +fn void! LinkedList.remove_first(&self) @maydiscard { if (!self._first) return IteratorResult.NO_MORE_ELEMENT?; self.unlink_first(); } + +fn bool LinkedList.remove_first_match(&self, Type t) @if(ELEMENT_IS_EQUATABLE) +{ + for (Node* node = self._first; node != null; node = node.next) + { + if (node.value == t) + { + self.unlink(node); + return true; + } + } + return false; +} + +fn bool LinkedList.remove_last_match(&self, Type t) @if(ELEMENT_IS_EQUATABLE) +{ + for (Node* node = self._last; node != null; node = node.prev) + { + if (node.value == t) + { + self.unlink(node); + return true; + } + } + return false; +} /** * @require self._last **/ diff --git a/lib/std/collections/list.c3 b/lib/std/collections/list.c3 index d1607bb68..fa3a2a2db 100644 --- a/lib/std/collections/list.c3 +++ b/lib/std/collections/list.c3 @@ -5,7 +5,7 @@ module std::collections::list(); import std::io,std::math; def ElementPredicate = fn bool(Type *type); -def ElementTest = fn bool(Type *type, any* context); +def ElementTest = fn bool(Type *type, any context); const ELEMENT_IS_EQUATABLE = types::is_equatable_type(Type); const ELEMENT_IS_POINTER = Type.kindof == POINTER; @@ -13,7 +13,7 @@ struct List (Printable) { usz size; usz capacity; - Allocator *allocator; + Allocator allocator; Type *entries; } @@ -22,7 +22,7 @@ struct List (Printable) * @param initial_capacity "The initial capacity to reserve" * @param [&inout] allocator "The allocator to use, defaults to the heap allocator" **/ -fn List* List.new_init(&self, usz initial_capacity = 16, Allocator* allocator = allocator::heap()) +fn List* List.new_init(&self, usz initial_capacity = 16, Allocator allocator = allocator::heap()) { self.allocator = allocator; self.size = 0; @@ -39,15 +39,6 @@ fn List* List.new_init(&self, usz initial_capacity = 16, Allocator* allocator = return self; } -/** - * @param initial_capacity "The initial capacity to reserve" - * @param [&inout] allocator "The allocator to use, defaults to the heap allocator" - **/ -fn List* List.init_new(&self, usz initial_capacity = 16, Allocator* allocator = allocator::heap()) @deprecated("Replaced by new_init") -{ - return self.new_init(initial_capacity, allocator) @inline; -} - /** * Initialize the list using the temp allocator. * @@ -58,20 +49,10 @@ fn List* List.temp_init(&self, usz initial_capacity = 16) return self.new_init(initial_capacity, allocator::temp()) @inline; } -/** - * Initialize the list using the temp allocator. - * - * @param initial_capacity "The initial capacity to reserve" - **/ -fn List* List.init_temp(&self, usz initial_capacity = 16) @deprecated("Replaced by temp_init") -{ - return self.temp_init(initial_capacity) @inline; -} - /** * @require self.size == 0 "The List must be empty" **/ -fn void List.init_wrapping_array(&self, Type[] types, Allocator* allocator = allocator::heap()) +fn void List.init_wrapping_array(&self, Type[] types, Allocator allocator = allocator::heap()) { self.allocator = allocator; self.size = types.len; @@ -99,7 +80,7 @@ fn usz! List.to_format(&self, Formatter* formatter) @dynamic } } -fn String List.to_new_string(&self, Allocator* allocator = allocator::heap()) @dynamic +fn String List.to_new_string(&self, Allocator allocator = allocator::heap()) @dynamic { return string::new_format("%s", *self, .allocator = allocator); } @@ -110,21 +91,14 @@ fn String List.to_tstring(&self) } fn void List.push(&self, Type element) @inline -{ - self.append(element); -} - -fn void List.append(&self, Type element) { self.ensure_capacity(); - self.entries[self.size++] = element; + self.entries[self.size++] = element; } -/** - * @require self.size > 0 - **/ -fn Type List.pop(&self) +fn Type! List.pop(&self) { + if (!self.size) return IteratorResult.NO_MORE_ELEMENT?; return self.entries[--self.size]; } @@ -136,11 +110,11 @@ fn void List.clear(&self) /** * @require self.size > 0 **/ -fn Type List.pop_first(&self) +fn Type! List.pop_first(&self) { - Type value = self.entries[0]; - self.remove_at(0); - return value; + if (!self.size) return IteratorResult.NO_MORE_ELEMENT?; + defer self.remove_at(0); + return self.entries[0]; } /** @@ -163,7 +137,7 @@ fn void List.add_all(&self, List* other_list) } -fn Type[] List.to_new_array(&self, Allocator* allocator = allocator::heap()) +fn Type[] List.to_new_array(&self, Allocator allocator = allocator::heap()) { if (!self.size) return Type[] {}; Type[] result = allocator::alloc_array(allocator, Type, self.size); @@ -232,30 +206,28 @@ fn void List.set_at(&self, usz index, Type type) self.entries[index] = type; } -/** - * @require self.size > 0 - **/ -fn void List.remove_last(&self) +fn void! List.remove_last(&self) @maydiscard { + if (!self.size) return IteratorResult.NO_MORE_ELEMENT?; self.size--; } -/** - * @require self.size > 0 - **/ -fn void List.remove_first(&self) +fn void! List.remove_first(&self) @maydiscard { + if (!self.size) return IteratorResult.NO_MORE_ELEMENT?; self.remove_at(0); } -fn Type* List.first(&self) +fn Type! List.first(&self) { - return self.size ? &self.entries[0] : null; + if (!self.size) return IteratorResult.NO_MORE_ELEMENT?; + return self.entries[0]; } -fn Type* List.last(&self) +fn Type! List.last(&self) { - return self.size ? &self.entries[self.size - 1] : null; + if (!self.size) return IteratorResult.NO_MORE_ELEMENT?; + return self.entries[self.size - 1]; } fn bool List.is_empty(&self) @inline @@ -335,12 +307,12 @@ macro usz List._remove_if(&self, ElementPredicate filter, bool $invert) @local return size - self.size; } -fn usz List.remove_using_test(&self, ElementTest filter, any* context) +fn usz List.remove_using_test(&self, ElementTest filter, any context) { return self._remove_using_test(filter, false, context); } -fn usz List.retain_using_test(&self, ElementTest filter, any* context) +fn usz List.retain_using_test(&self, ElementTest filter, any context) { return self._remove_using_test(filter, true, context); } @@ -457,18 +429,38 @@ fn bool List.contains(&self, Type value) @if(ELEMENT_IS_EQUATABLE) } +/** + * @param [&inout] self "The list to remove elements from" + * @param value "The value to remove" + * @return "true if the value was found" + **/ +fn bool List.remove_last_match(&self, Type value) @if(ELEMENT_IS_EQUATABLE) +{ + return @ok(self.remove_at(self.rindex_of(value))); +} + +/** + * @param [&inout] self "The list to remove elements from" + * @param value "The value to remove" + * @return "true if the value was found" + **/ +fn bool List.remove_first_match(&self, Type value) @if(ELEMENT_IS_EQUATABLE) +{ + return @ok(self.remove_at(self.index_of(value))); +} + /** * @param [&inout] self "The list to remove elements from" * @param value "The value to remove" * @return "the number of deleted elements." **/ -fn usz List.remove(&self, Type value) @if(ELEMENT_IS_EQUATABLE) +fn usz List.remove_all_matches(&self, Type value) @if(ELEMENT_IS_EQUATABLE) { usz size = self.size; for (usz i = size; i > 0; i--) { if (!equals(self.entries[i - 1], value)) continue; - for (usz j = i; j < size; j++) + for (usz j = i; j < self.size; j++) { self.entries[j - 1] = self.entries[j]; } @@ -477,10 +469,10 @@ fn usz List.remove(&self, Type value) @if(ELEMENT_IS_EQUATABLE) return size - self.size; } -fn void List.remove_all(&self, List* other_list) @if(ELEMENT_IS_EQUATABLE) +fn void List.remove_all_from(&self, List* other_list) @if(ELEMENT_IS_EQUATABLE) { if (!other_list.size) return; - foreach (v : other_list) self.remove(v); + foreach (v : other_list) self.remove_all_matches(v); } /** diff --git a/lib/std/collections/map.c3 b/lib/std/collections/map.c3 index 6877e85ab..fbb753131 100644 --- a/lib/std/collections/map.c3 +++ b/lib/std/collections/map.c3 @@ -13,7 +13,7 @@ const bool COPY_KEYS = types::implements_copy(Key); struct HashMap { Entry*[] table; - Allocator* allocator; + Allocator allocator; uint count; // Number of elements uint threshold; // Resize limit float load_factor; @@ -26,7 +26,7 @@ struct HashMap * @require !self.allocator "Map was already initialized" * @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum" **/ -fn HashMap* HashMap.new_init(&self, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator* allocator = allocator::heap()) +fn HashMap* HashMap.new_init(&self, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap()) { capacity = math::next_power_of_2(capacity); self.allocator = allocator; @@ -36,18 +36,6 @@ fn HashMap* HashMap.new_init(&self, uint capacity = DEFAULT_INITIAL_CAPACITY, fl return self; } -/** - * @param [&inout] allocator "The allocator to use" - * @require capacity > 0 "The capacity must be 1 or higher" - * @require load_factor > 0.0 "The load factor must be higher than 0" - * @require !map.allocator "Map was already initialized" - * @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum" - **/ -fn HashMap* HashMap.init_new(&map, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator* allocator = allocator::heap()) @deprecated("Replaced by new_init") -{ - return map.new_init(capacity, load_factor, allocator); -} - /** * @require capacity > 0 "The capacity must be 1 or higher" * @require load_factor > 0.0 "The load factor must be higher than 0" @@ -59,16 +47,6 @@ fn HashMap* HashMap.temp_init(&self, uint capacity = DEFAULT_INITIAL_CAPACITY, f return self.new_init(capacity, load_factor, allocator::temp()) @inline; } -/** - * @require capacity > 0 "The capacity must be 1 or higher" - * @require load_factor > 0.0 "The load factor must be higher than 0" - * @require !map.allocator "Map was already initialized" - * @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum" - **/ -fn HashMap* HashMap.init_temp(&map, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR) @deprecated("Replaced by temp_init") -{ - return map.temp_init(capacity, load_factor) @inline; -} /** * Has this hash map been initialized yet? @@ -85,23 +63,13 @@ fn bool HashMap.is_initialized(&map) * @param [&inout] allocator "The allocator to use" * @param [&in] other_map "The map to copy from." **/ -fn HashMap* HashMap.new_init_from_map(&self, HashMap* other_map, Allocator* allocator = allocator::heap()) +fn HashMap* HashMap.new_init_from_map(&self, HashMap* other_map, Allocator allocator = allocator::heap()) { self.new_init(other_map.table.len, other_map.load_factor, allocator); self.put_all_for_create(other_map); return self; } -/** - * @param [&inout] allocator "The allocator to use" - * @param [&in] other_map "The map to copy from." - **/ -fn HashMap* HashMap.init_new_from_map(&self, HashMap* other_map, Allocator* allocator = allocator::heap()) @deprecated("Replaced by new_init_from_map") - -{ - return self.new_init_from_map(other_map, allocator) @inline; -} - /** * @param [&in] other_map "The map to copy from." **/ @@ -110,15 +78,6 @@ fn HashMap* HashMap.temp_init_from_map(&map, HashMap* other_map) return map.new_init_from_map(other_map, allocator::temp()) @inline; } -/** - * @param [&in] other_map "The map to copy from." - **/ -fn HashMap* HashMap.init_temp_from_map(&map, HashMap* other_map) @deprecated("Replaced by temp_init_from_map") -{ - return map.temp_init_from_map(other_map) @inline; -} - - fn bool HashMap.is_empty(&map) @inline { return !map.count; @@ -243,7 +202,7 @@ fn Key[] HashMap.key_tlist(&map) return map.key_new_list(allocator::temp()) @inline; } -fn Key[] HashMap.key_new_list(&map, Allocator* allocator = allocator::heap()) +fn Key[] HashMap.key_new_list(&map, Allocator allocator = allocator::heap()) { if (!map.count) return {}; @@ -287,7 +246,7 @@ fn Value[] HashMap.value_tlist(&map) return map.value_new_list(allocator::temp()) @inline; } -fn Value[] HashMap.value_new_list(&map, Allocator* allocator = allocator::heap()) +fn Value[] HashMap.value_new_list(&map, Allocator allocator = allocator::heap()) { if (!map.count) return {}; Value[] list = allocator::alloc_array(allocator, Value, map.count); diff --git a/lib/std/collections/object.c3 b/lib/std/collections/object.c3 index 08753c198..a0ae74456 100644 --- a/lib/std/collections/object.c3 +++ b/lib/std/collections/object.c3 @@ -11,7 +11,7 @@ const Object NULL_OBJECT = { .type = void*.typeid }; struct Object (Printable) { typeid type; - Allocator* allocator; + Allocator allocator; union { uint128 i; @@ -76,7 +76,7 @@ fn usz! Object.to_format(&self, Formatter* formatter) @dynamic } } -fn Object* new_obj(Allocator* allocator) +fn Object* new_obj(Allocator allocator) { return allocator::new(allocator, Object, { .allocator = allocator, .type = void.typeid }); } @@ -86,22 +86,22 @@ fn Object* new_null() return &NULL_OBJECT; } -fn Object* new_int(int128 i, Allocator* allocator) +fn Object* new_int(int128 i, Allocator allocator) { return allocator::new(allocator, Object, { .i = i, .allocator = allocator, .type = int128.typeid }); } -macro Object* new_enum(e, Allocator* allocator) +macro Object* new_enum(e, Allocator allocator) { return allocator::new(allocator, Object, { .i = (int128)e, .allocator = allocator, .type = @typeid(e) }); } -fn Object* new_float(double f, Allocator* allocator) +fn Object* new_float(double f, Allocator allocator) { return allocator::new(allocator, Object, { .f = f, .allocator = allocator, .type = double.typeid }); } -fn Object* new_string(String s, Allocator* allocator) +fn Object* new_string(String s, Allocator allocator) { return allocator::new(allocator, Object, { .s = s.copy(allocator), .allocator = allocator, .type = String.typeid }); } @@ -234,10 +234,10 @@ macro Object* Object.set_at(&self, usz index, String key, value) * @require self.is_indexable() * @ensure return != null **/ -macro Object* Object.append(&self, value) +macro Object* Object.push(&self, value) { Object* val = self.object_from_value(value); - self.append_object(val); + self.push_object(val); return val; } @@ -268,10 +268,10 @@ fn usz Object.get_len(&self) /** * @require self.is_indexable() **/ -fn void Object.append_object(&self, Object* to_append) +fn void Object.push_object(&self, Object* to_append) { self.init_array_if_needed(); - self.array.append(to_append); + self.array.push(to_append); } /** @@ -282,11 +282,11 @@ fn void Object.set_object_at(&self, usz index, Object* to_set) self.init_array_if_needed(); while (self.array.len() < index) { - self.array.append(&NULL_OBJECT); + self.array.push(&NULL_OBJECT); } if (self.array.len() == index) { - self.array.append(to_set); + self.array.push(to_set); return; } self.array.get(index).free(); diff --git a/lib/std/collections/priorityqueue.c3 b/lib/std/collections/priorityqueue.c3 index e96bfd690..a66f616d5 100644 --- a/lib/std/collections/priorityqueue.c3 +++ b/lib/std/collections/priorityqueue.c3 @@ -36,12 +36,7 @@ struct PrivatePriorityQueue (Printable) Heap heap; } -fn void PrivatePriorityQueue.init_new(&self, usz initial_capacity = 16, Allocator* allocator = allocator::heap()) @inline @deprecated("Replaced by new_init") -{ - return self.new_init(initial_capacity, allocator); -} - -fn void PrivatePriorityQueue.new_init(&self, usz initial_capacity = 16, Allocator* allocator = allocator::heap()) @inline +fn void PrivatePriorityQueue.new_init(&self, usz initial_capacity = 16, Allocator allocator = allocator::heap()) @inline { self.heap.new_init(initial_capacity, allocator); } @@ -51,11 +46,6 @@ fn void PrivatePriorityQueue.temp_init(&self, usz initial_capacity = 16) @inline self.heap.new_init(initial_capacity, allocator::temp()) @inline; } -fn void PrivatePriorityQueue.init_temp(&self, usz initial_capacity = 16) @inline @deprecated("Replaced by temp_init") -{ - return self.temp_init(initial_capacity) @inline; -} - fn void PrivatePriorityQueue.push(&self, Type element) { self.heap.push(element); @@ -117,7 +107,7 @@ fn Type! PrivatePriorityQueue.pop(&self) return self.heap.pop(); } -fn Type! PrivatePriorityQueue.peek(&self) +fn Type! PrivatePriorityQueue.first(&self) { if (!self.len()) return IteratorResult.NO_MORE_ELEMENT?; return self.heap.get(0); @@ -141,7 +131,7 @@ fn bool PrivatePriorityQueue.is_empty(&self) /** * @require index < self.len() */ -fn Type PrivatePriorityQueue.peek_at(&self, usz index) @operator([]) +fn Type PrivatePriorityQueue.get(&self, usz index) @operator([]) { return self.heap[index]; } @@ -151,7 +141,7 @@ fn usz! PrivatePriorityQueue.to_format(&self, Formatter* formatter) @dynamic return self.heap.to_format(formatter); } -fn String PrivatePriorityQueue.to_new_string(&self, Allocator* allocator = allocator::heap()) @dynamic +fn String PrivatePriorityQueue.to_new_string(&self, Allocator allocator = allocator::heap()) @dynamic { return self.heap.to_new_string(allocator); } diff --git a/lib/std/collections/range.c3 b/lib/std/collections/range.c3 index 0b784bbe0..e09a45534 100644 --- a/lib/std/collections/range.c3 +++ b/lib/std/collections/range.c3 @@ -29,7 +29,7 @@ fn Type Range.get(&self, usz index) @operator([]) return (Type)(self.start + (usz)index); } -fn String Range.to_new_string(&self, Allocator* allocator = allocator::heap()) @dynamic +fn String Range.to_new_string(&self, Allocator allocator = allocator::heap()) @dynamic { return string::new_format("[%s..%s]", self.start, self.end, .allocator = allocator); } @@ -66,7 +66,7 @@ fn usz! ExclusiveRange.to_format(&self, Formatter* formatter) @dynamic return formatter.printf("[%s..<%s]", self.start, self.end)!; } -fn String ExclusiveRange.to_new_string(&self, Allocator* allocator = allocator::heap()) @dynamic +fn String ExclusiveRange.to_new_string(&self, Allocator allocator = allocator::heap()) @dynamic { return string::new_format("[%s..<%s]", self.start, self.end, .allocator = allocator); } diff --git a/lib/std/collections/ringbuffer.c3 b/lib/std/collections/ringbuffer.c3 index 507dd9116..895cfcf5f 100644 --- a/lib/std/collections/ringbuffer.c3 +++ b/lib/std/collections/ringbuffer.c3 @@ -12,7 +12,7 @@ fn void RingBuffer.init(&self) @inline *self = {}; } -fn void RingBuffer.putc(&self, Type c) +fn void RingBuffer.push(&self, Type c) { if (self.written < SIZE) { @@ -26,7 +26,7 @@ fn void RingBuffer.putc(&self, Type c) } } -fn Type RingBuffer.getc(&self, usz index) +fn Type RingBuffer.get(&self, usz index) @operator([]) { index %= SIZE; usz avail = SIZE - self.head; @@ -37,7 +37,7 @@ fn Type RingBuffer.getc(&self, usz index) return self.buf[index - avail]; } -fn Type! RingBuffer.popc(&self) +fn Type! RingBuffer.pop(&self) { switch { @@ -52,7 +52,7 @@ fn Type! RingBuffer.popc(&self) } } -fn usz RingBuffer.get(&self, usz index, Type[] buffer) +fn usz RingBuffer.read(&self, usz index, Type[] buffer) { index %= SIZE; if (self.written < SIZE) @@ -87,7 +87,7 @@ fn usz RingBuffer.get(&self, usz index, Type[] buffer) return n1 + n2; } -fn void RingBuffer.push(&self, Type[] buffer) +fn void RingBuffer.write(&self, Type[] buffer) { usz i; while (self.written < SIZE && i < buffer.len) diff --git a/lib/std/core/allocators/arena_allocator.c3 b/lib/std/core/allocators/arena_allocator.c3 index 49ee2c063..84a6cd026 100644 --- a/lib/std/core/allocators/arena_allocator.c3 +++ b/lib/std/core/allocators/arena_allocator.c3 @@ -52,7 +52,7 @@ fn void ArenaAllocator.reset(&self, usz mark) @dynamic => self.used = mark; * @require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big` * @require size > 0 **/ -fn void*! ArenaAllocator.acquire(&self, usz size, bool clear, usz alignment, usz offset) @dynamic +fn void*! ArenaAllocator.acquire(&self, usz size, AllocInitType init_type, usz alignment) @dynamic { alignment = alignment_for_allocation(alignment); usz total_len = self.data.len; @@ -65,7 +65,7 @@ fn void*! ArenaAllocator.acquire(&self, usz size, bool clear, usz alignment, usz self.used = end; ArenaAllocatorHeader* header = mem - ArenaAllocatorHeader.sizeof; header.size = size; - if (clear) mem::clear(mem, size, mem::DEFAULT_MEM_ALIGNMENT); + if (init_type == ZERO) mem::clear(mem, size, mem::DEFAULT_MEM_ALIGNMENT); return mem; } @@ -75,7 +75,7 @@ fn void*! ArenaAllocator.acquire(&self, usz size, bool clear, usz alignment, usz * @require old_pointer != null * @require size > 0 **/ -fn void*! ArenaAllocator.resize(&self, void *old_pointer, usz size, usz alignment, usz offset) @dynamic +fn void*! ArenaAllocator.resize(&self, void *old_pointer, usz size, usz alignment) @dynamic { alignment = alignment_for_allocation(alignment); assert(old_pointer >= self.data.ptr, "Pointer originates from a different allocator."); @@ -100,7 +100,7 @@ fn void*! ArenaAllocator.resize(&self, void *old_pointer, usz size, usz alignmen return old_pointer; } // Otherwise just allocate new memory. - void* mem = self.acquire(size, false, alignment, 0)!; + void* mem = self.acquire(size, NO_ZERO, alignment)!; mem::copy(mem, old_pointer, old_size, mem::DEFAULT_MEM_ALIGNMENT, mem::DEFAULT_MEM_ALIGNMENT); return mem; } \ No newline at end of file diff --git a/lib/std/core/allocators/dynamic_arena.c3 b/lib/std/core/allocators/dynamic_arena.c3 index 495cf6d76..8691ccaec 100644 --- a/lib/std/core/allocators/dynamic_arena.c3 +++ b/lib/std/core/allocators/dynamic_arena.c3 @@ -6,7 +6,7 @@ import std::math; struct DynamicArenaAllocator (Allocator) { - Allocator* backing_allocator; + Allocator backing_allocator; DynamicArenaPage* page; DynamicArenaPage* unused_page; usz page_size; @@ -16,7 +16,7 @@ struct DynamicArenaAllocator (Allocator) * @param [&inout] allocator * @require page_size >= 128 **/ -fn void DynamicArenaAllocator.init(&self, usz page_size, Allocator* allocator) +fn void DynamicArenaAllocator.init(&self, usz page_size, Allocator allocator) { self.page = null; self.unused_page = null; @@ -77,7 +77,7 @@ fn void DynamicArenaAllocator.release(&self, void* ptr, bool) @dynamic * @require old_pointer != null `Resize doesn't handle null pointers` * @require self.page `tried to realloc pointer on invalid allocator` */ -fn void*! DynamicArenaAllocator.resize(&self, void* old_pointer, usz size, usz alignment, usz offset) @dynamic +fn void*! DynamicArenaAllocator.resize(&self, void* old_pointer, usz size, usz alignment) @dynamic { DynamicArenaPage* current_page = self.page; alignment = alignment_for_allocation(alignment); @@ -102,7 +102,7 @@ fn void*! DynamicArenaAllocator.resize(&self, void* old_pointer, usz size, usz a current_page.used += add_size; return old_pointer; } - void* new_mem = self.acquire(size, false, alignment, 0)!; + void* new_mem = self.acquire(size, NO_ZERO, alignment)!; mem::copy(new_mem, old_pointer, old_size, mem::DEFAULT_MEM_ALIGNMENT); return new_mem; } @@ -158,7 +158,7 @@ fn void*! DynamicArenaAllocator._alloc_new(&self, usz size, usz alignment) @loca * @require size > 0 `acquire expects size > 0` * @require !alignment || math::is_power_of_2(alignment) */ -fn void*! DynamicArenaAllocator.acquire(&self, usz size, bool clear, usz alignment, usz offset) @dynamic +fn void*! DynamicArenaAllocator.acquire(&self, usz size, AllocInitType init_type, usz alignment) @dynamic { alignment = alignment_for_allocation(alignment); DynamicArenaPage* page = self.page; @@ -195,6 +195,6 @@ fn void*! DynamicArenaAllocator.acquire(&self, usz size, bool clear, usz alignme chunk.size = size; return mem; |}!; - if (clear) mem::clear(ptr, size, mem::DEFAULT_MEM_ALIGNMENT); + if (init_type == ZERO) mem::clear(ptr, size, mem::DEFAULT_MEM_ALIGNMENT); return ptr; } diff --git a/lib/std/core/allocators/heap_allocator.c3 b/lib/std/core/allocators/heap_allocator.c3 index f74d656d9..45e26bb3c 100644 --- a/lib/std/core/allocators/heap_allocator.c3 +++ b/lib/std/core/allocators/heap_allocator.c3 @@ -21,16 +21,16 @@ fn void SimpleHeapAllocator.init(&self, MemoryAllocFn allocator) self.free_list = null; } -fn void*! SimpleHeapAllocator.acquire(&self, usz size, bool clear, usz alignment, usz offset) @dynamic +fn void*! SimpleHeapAllocator.acquire(&self, usz size, AllocInitType init_type, usz alignment) @dynamic { - if (clear) + if (init_type == ZERO) { return alignment > 0 ? @aligned_alloc(self._calloc, size, alignment) : self._calloc(size); } return alignment > 0 ? @aligned_alloc(self._alloc, size, alignment) : self._alloc(size); } -fn void*! SimpleHeapAllocator.resize(&self, void* old_pointer, usz size, usz alignment, usz offset) @dynamic +fn void*! SimpleHeapAllocator.resize(&self, void* old_pointer, usz size, usz alignment) @dynamic { return alignment > 0 ? @aligned_realloc(self._calloc, self._free, old_pointer, size, alignment) diff --git a/lib/std/core/allocators/libc_allocator.c3 b/lib/std/core/allocators/libc_allocator.c3 index aafec93d9..602aa8669 100644 --- a/lib/std/core/allocators/libc_allocator.c3 +++ b/lib/std/core/allocators/libc_allocator.c3 @@ -12,9 +12,9 @@ module std::core::mem::allocator @if(env::POSIX); import std::os; import libc; -fn void*! LibcAllocator.acquire(&self, usz bytes, bool clear, usz alignment, usz offset) @dynamic +fn void*! LibcAllocator.acquire(&self, usz bytes, AllocInitType init_type, usz alignment) @dynamic { - if (clear) + if (init_type == ZERO) { void* data @noinit; if (alignment > mem::DEFAULT_MEM_ALIGNMENT) @@ -43,19 +43,9 @@ fn void*! LibcAllocator.acquire(&self, usz bytes, bool clear, usz alignment, usz } } -fn void*! LibcAllocator.resize(&self, void* old_ptr, usz new_bytes, usz alignment, usz offset) @dynamic +fn void*! LibcAllocator.resize(&self, void* old_ptr, usz new_bytes, usz alignment) @dynamic { - if (!new_bytes) - { - self.release(old_ptr, alignment > 0); - return null; - } - if (!old_ptr) - { - return self.acquire(new_bytes, false, alignment, 0); - } if (alignment <= mem::DEFAULT_MEM_ALIGNMENT) return libc::realloc(old_ptr, new_bytes) ?: AllocationFailure.OUT_OF_MEMORY?; - void* new_ptr; if (posix::posix_memalign(&new_ptr, alignment, new_bytes)) return AllocationFailure.OUT_OF_MEMORY?; @@ -83,9 +73,9 @@ module std::core::mem::allocator @if(env::WIN32); import std::os::win32; import libc; -fn void*! LibcAllocator.acquire(&self, usz bytes, bool clear, usz alignment, usz offset) @dynamic +fn void*! LibcAllocator.acquire(&self, usz bytes, AllocInitType init_type, usz alignment) @dynamic { - if (clear) + if (init_type == ZERO) { if (alignment > 0) { @@ -101,7 +91,7 @@ fn void*! LibcAllocator.acquire(&self, usz bytes, bool clear, usz alignment, usz return data; } -fn void*! LibcAllocator.resize(&self, void* old_ptr, usz new_bytes, usz alignment, usz offset) @dynamic +fn void*! LibcAllocator.resize(&self, void* old_ptr, usz new_bytes, usz alignment) @dynamic { if (alignment) { @@ -123,9 +113,9 @@ fn void LibcAllocator.release(&self, void* old_ptr, bool aligned) @dynamic module std::core::mem::allocator @if(!env::WIN32 && !env::POSIX); import libc; -fn void*! LibcAllocator.acquire(&self, usz bytes, bool clear, usz alignment, usz offset) @dynamic +fn void*! LibcAllocator.acquire(&self, usz bytes, AllocInitType init_type, usz alignment) @dynamic { - if (clear) + if (init_type == ZERO) { void* data = alignment ? @aligned_alloc(fn void*(usz bytes) => libc::calloc(bytes, 1), bytes, alignment)!! : libc::calloc(bytes, 1); return data ?: AllocationFailure.OUT_OF_MEMORY?; @@ -142,7 +132,7 @@ fn void*! LibcAllocator.acquire(&self, usz bytes, bool clear, usz alignment, usz } -fn void*! LibcAllocator.resize(&self, void* old_ptr, usz new_bytes, usz alignment, usz offset) @dynamic +fn void*! LibcAllocator.resize(&self, void* old_ptr, usz new_bytes, usz alignment) @dynamic { if (alignment) { diff --git a/lib/std/core/allocators/on_stack_allocator.c3 b/lib/std/core/allocators/on_stack_allocator.c3 index 5595ec559..ce9cc96a4 100644 --- a/lib/std/core/allocators/on_stack_allocator.c3 +++ b/lib/std/core/allocators/on_stack_allocator.c3 @@ -2,7 +2,7 @@ module std::core::mem::allocator; struct OnStackAllocator (Allocator) { - Allocator* backing_allocator; + Allocator backing_allocator; char[] data; usz used; OnStackAllocatorExtraChunk* chunk; @@ -20,7 +20,7 @@ struct OnStackAllocatorExtraChunk @local * @param [&inout] allocator * Initialize a memory arena for use using the provided bytes. **/ -fn void OnStackAllocator.init(&self, char[] data, Allocator* allocator) +fn void OnStackAllocator.init(&self, char[] data, Allocator allocator) { self.data = data; self.backing_allocator = allocator; @@ -103,18 +103,18 @@ fn OnStackAllocatorExtraChunk* on_stack_allocator_find_chunk(OnStackAllocator* a * @require old_pointer != null * @require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big` **/ -fn void*! OnStackAllocator.resize(&self, void* old_pointer, usz size, usz alignment, usz deprecated) @dynamic +fn void*! OnStackAllocator.resize(&self, void* old_pointer, usz size, usz alignment) @dynamic { if (!allocation_in_stack_mem(self, old_pointer)) { OnStackAllocatorExtraChunk* chunk = on_stack_allocator_find_chunk(self, old_pointer); assert(chunk, "Tried to realloc pointer not belonging to the allocator"); - return chunk.data = self.backing_allocator.resize(old_pointer, size, alignment, 0)!; + return chunk.data = self.backing_allocator.resize(old_pointer, size, alignment)!; } OnStackAllocatorHeader* header = old_pointer - OnStackAllocatorHeader.sizeof; usz old_size = header.size; - void* mem = self.acquire(size, false, alignment, 0)!; + void* mem = self.acquire(size, NO_ZERO, alignment)!; mem::copy(mem, old_pointer, old_size, mem::DEFAULT_MEM_ALIGNMENT, mem::DEFAULT_MEM_ALIGNMENT); return mem; } @@ -123,7 +123,7 @@ fn void*! OnStackAllocator.resize(&self, void* old_pointer, usz size, usz alignm * @require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big` * @require size > 0 **/ -fn void*! OnStackAllocator.acquire(&self, usz size, bool clear, usz alignment, usz deprecated) @dynamic +fn void*! OnStackAllocator.acquire(&self, usz size, AllocInitType init_type, usz alignment) @dynamic { bool aligned = alignment > 0; alignment = alignment_for_allocation(alignment); @@ -132,7 +132,7 @@ fn void*! OnStackAllocator.acquire(&self, usz size, bool clear, usz alignment, u void* unaligned_pointer_to_offset = start_mem + self.used + OnStackAllocatorHeader.sizeof ; void* mem = mem::aligned_pointer(unaligned_pointer_to_offset, alignment); usz end = (usz)(mem - self.data.ptr) + size; - Allocator* backing_allocator = self.backing_allocator; + Allocator backing_allocator = self.backing_allocator; if (end > total_len) { @@ -140,7 +140,7 @@ fn void*! OnStackAllocator.acquire(&self, usz size, bool clear, usz alignment, u defer catch allocator::free(backing_allocator, chunk); defer try self.chunk = chunk; *chunk = { .prev = self.chunk, .is_aligned = aligned }; - return chunk.data = backing_allocator.acquire(size, clear, aligned ? alignment : 0, 0)!; + return chunk.data = backing_allocator.acquire(size, init_type, aligned ? alignment : 0)!; } self.used = end; OnStackAllocatorHeader* header = mem - OnStackAllocatorHeader.sizeof; diff --git a/lib/std/core/allocators/temp_allocator.c3 b/lib/std/core/allocators/temp_allocator.c3 index 5b5a1c143..8f60cf4ea 100644 --- a/lib/std/core/allocators/temp_allocator.c3 +++ b/lib/std/core/allocators/temp_allocator.c3 @@ -9,7 +9,7 @@ struct TempAllocatorChunk @local struct TempAllocator (Allocator) { - Allocator* backing_allocator; + Allocator backing_allocator; TempAllocatorPage* last_page; usz used; usz capacity; @@ -35,7 +35,7 @@ macro bool TempAllocatorPage.is_aligned(&self) => self.size & PAGE_IS_ALIGNED == /** * @require size >= 16 **/ -fn TempAllocator*! new_temp_allocator(usz size, Allocator* allocator) +fn TempAllocator*! new_temp_allocator(usz size, Allocator allocator) { TempAllocator* temp = allocator::alloc_with_padding(allocator, TempAllocator, size)!; temp.last_page = null; @@ -45,11 +45,6 @@ fn TempAllocator*! new_temp_allocator(usz size, Allocator* allocator) return temp; } -fn TempAllocator*! new_temp(usz size, Allocator* allocator) @deprecated("Use new_temp_allocator") -{ - return new_temp_allocator(size, allocator); -} - fn usz TempAllocator.mark(&self) @dynamic => self.used; fn void TempAllocator.release(&self, void* old_pointer, bool) @dynamic @@ -94,13 +89,13 @@ fn void*! TempAllocator._realloc_page(&self, TempAllocatorPage* page, usz size, *pointer_to_prev = page.prev_page; usz page_size = page.pagesize(); // Clear on size > original size. - void* data = self.acquire(size, size > page_size, alignment, 0)!; + void* data = self.acquire(size, NO_ZERO, alignment)!; mem::copy(data, &page.data[0], page_size, mem::DEFAULT_MEM_ALIGNMENT, mem::DEFAULT_MEM_ALIGNMENT); self.backing_allocator.release(real_pointer, page.is_aligned()); return data; } -fn void*! TempAllocator.resize(&self, void* pointer, usz size, usz alignment, usz deprecated) @dynamic +fn void*! TempAllocator.resize(&self, void* pointer, usz size, usz alignment) @dynamic { TempAllocatorChunk *chunk = pointer - TempAllocatorChunk.sizeof; if (chunk.size == (usz)-1) @@ -111,8 +106,7 @@ fn void*! TempAllocator.resize(&self, void* pointer, usz size, usz alignment, us return self._realloc_page(page, size, alignment); } - // TODO optimize last allocation - TempAllocatorChunk* data = self.acquire(size, size > chunk.size, alignment, 0)!; + TempAllocatorChunk* data = self.acquire(size, NO_ZERO, alignment)!; mem::copy(data, pointer, chunk.size, mem::DEFAULT_MEM_ALIGNMENT, mem::DEFAULT_MEM_ALIGNMENT); return data; @@ -123,7 +117,7 @@ fn void*! TempAllocator.resize(&self, void* pointer, usz size, usz alignment, us * @require !alignment || math::is_power_of_2(alignment) * @require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big` **/ -fn void*! TempAllocator.acquire(&self, usz size, bool clear, usz alignment, usz deprecated) @dynamic +fn void*! TempAllocator.acquire(&self, usz size, AllocInitType init_type, usz alignment) @dynamic { alignment = alignment_for_allocation(alignment); void* start_mem = &self.data; @@ -142,7 +136,7 @@ fn void*! TempAllocator.acquire(&self, usz size, bool clear, usz alignment, usz TempAllocatorChunk* chunk_start = mem - TempAllocatorChunk.sizeof; chunk_start.size = size; self.used = new_usage; - if (clear) mem::clear(mem, size, mem::DEFAULT_MEM_ALIGNMENT); + if (init_type == ZERO) mem::clear(mem, size, mem::DEFAULT_MEM_ALIGNMENT); return mem; } @@ -154,7 +148,7 @@ fn void*! TempAllocator.acquire(&self, usz size, bool clear, usz alignment, usz { // This is actually simpler, since it will create the offset for us. usz total_alloc_size = mem::aligned_offset(TempAllocatorPage.sizeof + size, alignment); - if (clear) + if (init_type == ZERO) { mem = allocator::calloc_aligned(self.backing_allocator, total_alloc_size, alignment)!; } @@ -171,7 +165,7 @@ fn void*! TempAllocator.acquire(&self, usz size, bool clear, usz alignment, usz // Here we might need to pad usz padded_header_size = mem::aligned_offset(TempAllocatorPage.sizeof, mem::DEFAULT_MEM_ALIGNMENT); usz total_alloc_size = padded_header_size + size; - void* alloc = self.backing_allocator.acquire(total_alloc_size, clear, 0, 0)!; + void* alloc = self.backing_allocator.acquire(total_alloc_size, init_type, 0)!; // Find the page. page = alloc + padded_header_size - TempAllocatorPage.sizeof; diff --git a/lib/std/core/allocators/tracking_allocator.c3 b/lib/std/core/allocators/tracking_allocator.c3 index 646dc43f5..46148403b 100644 --- a/lib/std/core/allocators/tracking_allocator.c3 +++ b/lib/std/core/allocators/tracking_allocator.c3 @@ -20,7 +20,7 @@ def AllocMap = HashMap(); // is not compatible with allocators that uses mark() struct TrackingAllocator (Allocator) { - Allocator* inner_allocator; + Allocator inner_allocator; AllocMap map; usz mem_total; usz allocs_total; @@ -31,7 +31,7 @@ struct TrackingAllocator (Allocator) * * @param [&inout] allocator "The allocator to track" **/ -fn void TrackingAllocator.init(&self, Allocator* allocator) +fn void TrackingAllocator.init(&self, Allocator allocator) { *self = { .inner_allocator = allocator }; self.map.new_init(.allocator = allocator); @@ -69,7 +69,7 @@ fn usz TrackingAllocator.total_allocated(&self) => self.mem_total; **/ fn usz TrackingAllocator.total_allocation_count(&self) => self.allocs_total; -fn Allocation[] TrackingAllocator.allocations_tlist(&self, Allocator* allocator) +fn Allocation[] TrackingAllocator.allocations_tlist(&self, Allocator allocator) { return self.map.value_tlist(); } @@ -79,9 +79,9 @@ fn Allocation[] TrackingAllocator.allocations_tlist(&self, Allocator* allocator) **/ fn usz TrackingAllocator.allocation_count(&self) => self.map.count; -fn void*! TrackingAllocator.acquire(&self, usz size, bool clear, usz alignment, usz deprecated) @dynamic +fn void*! TrackingAllocator.acquire(&self, usz size, AllocInitType init_type, usz alignment) @dynamic { - void* data = self.inner_allocator.acquire(size, clear, alignment, 0)!; + void* data = self.inner_allocator.acquire(size, init_type, alignment)!; self.allocs_total++; void*[MAX_BACKTRACE] bt; backtrace::capture_current(&bt); @@ -91,9 +91,9 @@ fn void*! TrackingAllocator.acquire(&self, usz size, bool clear, usz alignment, return data; } -fn void*! TrackingAllocator.resize(&self, void* old_pointer, usz size, usz alignment, usz deprecated) @dynamic +fn void*! TrackingAllocator.resize(&self, void* old_pointer, usz size, usz alignment) @dynamic { - void* data = self.inner_allocator.resize(old_pointer, size, alignment, 0)!; + void* data = self.inner_allocator.resize(old_pointer, size, alignment)!; self.map.remove((uptr)old_pointer); void*[MAX_BACKTRACE] bt; backtrace::capture_current(&bt); @@ -107,7 +107,7 @@ fn void TrackingAllocator.release(&self, void* old_pointer, bool is_aligned) @dy { if (catch self.map.remove((uptr)old_pointer)) { - assert(false, "Attempt to release untracked pointer %p, this is likely a bug.", old_pointer); + unreachable("Attempt to release untracked pointer %p, this is likely a bug.", old_pointer); } self.inner_allocator.release(old_pointer, is_aligned); } @@ -119,7 +119,7 @@ fn void TrackingAllocator.clear(&self) fn void TrackingAllocator.print_report(&self) => self.fprint_report(io::stdout())!!; -fn void! TrackingAllocator.fprint_report(&self, OutStream* out) +fn void! TrackingAllocator.fprint_report(&self, OutStream out) { usz total = 0; diff --git a/lib/std/core/array.c3 b/lib/std/core/array.c3 index 60151d169..33d90236b 100644 --- a/lib/std/core/array.c3 +++ b/lib/std/core/array.c3 @@ -45,17 +45,17 @@ macro rindex_of(array, element) } /** - * Concatenate two arrays or subarrays, returning a subarray containing the concatenation of them. + * Concatenate two arrays or slices, returning a slice containing the concatenation of them. * * @param [in] arr1 * @param [in] arr2 * @param [&inout] allocator "The allocator to use, default is the heap allocator" - * @require @typekind(arr1) == SUBARRAY || @typekind(arr1) == ARRAY - * @require @typekind(arr2) == SUBARRAY || @typekind(arr2) == ARRAY + * @require @typekind(arr1) == SLICE || @typekind(arr1) == ARRAY + * @require @typekind(arr2) == SLICE || @typekind(arr2) == ARRAY * @require @typeis(arr1[0], $typeof(arr2[0])) "Arrays must have the same type" * @ensure result.len == arr1.len + arr2.len **/ -macro concat_new(arr1, arr2, Allocator* allocator = allocator::heap()) +macro concat_new(arr1, arr2, Allocator allocator = allocator::heap()) { var $Type = $typeof(arr1[0]); $Type[] result = allocator::alloc_array(allocator, $Type, arr1.len + arr2.len); @@ -71,13 +71,13 @@ macro concat_new(arr1, arr2, Allocator* allocator = allocator::heap()) } /** - * Concatenate two arrays or subarrays, returning a subarray containing the concatenation of them, + * Concatenate two arrays or slices, returning a slice containing the concatenation of them, * allocated using the temp allocator. * * @param [in] arr1 * @param [in] arr2 - * @require @typekind(arr1) == SUBARRAY || @typekind(arr1) == ARRAY - * @require @typekind(arr2) == SUBARRAY || @typekind(arr2) == ARRAY + * @require @typekind(arr1) == SLICE || @typekind(arr1) == ARRAY + * @require @typekind(arr2) == SLICE || @typekind(arr2) == ARRAY * @require @typeis(arr1[0], $typeof(arr2[0])) "Arrays must have the same type" * @ensure result.len == arr1.len + arr2.len **/ diff --git a/lib/std/core/bitorder.c3 b/lib/std/core/bitorder.c3 index 77a3eb5ff..431aa6116 100644 --- a/lib/std/core/bitorder.c3 +++ b/lib/std/core/bitorder.c3 @@ -88,7 +88,7 @@ bitstruct UInt128LE : uint128 @littleendian } /** - * @require is_array_or_sub_of_char(bytes) "argument must be an array, a pointer to an array or a subarray of char" + * @require is_array_or_slice_of_char(bytes) "argument must be an array, a pointer to an array or a slice of char" * @require is_bitorder($Type) "type must be a bitorder integer" **/ macro read(bytes, $Type) @@ -104,7 +104,7 @@ macro read(bytes, $Type) } /** - * @require is_arrayptr_or_sub_of_char(bytes) "argument must be a pointer to an array or a subarray of char" + * @require is_arrayptr_or_slice_of_char(bytes) "argument must be a pointer to an array or a slice of char" * @require is_bitorder($Type) "type must be a bitorder integer" **/ macro write(x, bytes, $Type) @@ -144,7 +144,7 @@ macro is_bitorder($Type) $endswitch } -macro bool is_array_or_sub_of_char(bytes) +macro bool is_array_or_slice_of_char(bytes) { $switch (@typekind(bytes)) $case POINTER: @@ -154,7 +154,7 @@ macro bool is_array_or_sub_of_char(bytes) return $Inner2.typeid == char.typeid; $endif $case ARRAY: - $case SUBARRAY: + $case SLICE: var $Inner = $typefrom($typeof(bytes).inner); return $Inner.typeid == char.typeid; $default: @@ -162,7 +162,7 @@ macro bool is_array_or_sub_of_char(bytes) $endswitch } -macro bool is_arrayptr_or_sub_of_char(bytes) +macro bool is_arrayptr_or_slice_of_char(bytes) { $switch (@typekind(bytes)) $case POINTER: @@ -171,7 +171,7 @@ macro bool is_arrayptr_or_sub_of_char(bytes) var $Inner2 = $typefrom($Inner.inner); return $Inner2.typeid == char.typeid; $endif - $case SUBARRAY: + $case SLICE: var $Inner = $typefrom($typeof(bytes).inner); return $Inner.typeid == char.typeid; $default: diff --git a/lib/std/core/builtin.c3 b/lib/std/core/builtin.c3 index 8f054d33c..22cf0895c 100644 --- a/lib/std/core/builtin.c3 +++ b/lib/std/core/builtin.c3 @@ -61,7 +61,7 @@ macro void @swap(&a, &b) @builtin * @ensure @typeis(return, $Type*) * @return! CastResult.TYPE_MISMATCH **/ -macro anycast(any* v, $Type) @builtin +macro anycast(any v, $Type) @builtin { if (v.type != $Type.typeid) return CastResult.TYPE_MISMATCH?; return ($Type*)v.ptr; @@ -126,7 +126,7 @@ PanicFn panic = &default_panic; fn void panicf(String fmt, String file, String function, uint line, args...) { - @stack_mem(512; Allocator* allocator) + @stack_mem(512; Allocator allocator) { DString s; s.new_init(.allocator = allocator); diff --git a/lib/std/core/dstring.c3 b/lib/std/core/dstring.c3 index c4a1d289f..bb9012002 100644 --- a/lib/std/core/dstring.c3 +++ b/lib/std/core/dstring.c3 @@ -8,7 +8,7 @@ const usz MIN_CAPACITY @private = 16; /** * @require !self.data() "String already initialized" **/ -fn DString DString.new_init(&self, usz capacity = MIN_CAPACITY, Allocator* allocator = allocator::heap()) +fn DString DString.new_init(&self, usz capacity = MIN_CAPACITY, Allocator allocator = allocator::heap()) { if (capacity < MIN_CAPACITY) capacity = MIN_CAPACITY; StringData* data = allocator::alloc_with_padding(allocator, StringData, capacity)!!; @@ -18,14 +18,6 @@ fn DString DString.new_init(&self, usz capacity = MIN_CAPACITY, Allocator* alloc return *self = (DString)data; } -/** - * @require !self.data() "String already initialized" - **/ -fn DString DString.init_new(&self, usz capacity = MIN_CAPACITY, Allocator* allocator = allocator::heap()) @deprecated("Replaced by new_init") -{ - return self.new_init(capacity, allocator) @inline; -} - /** * @require !self.data() "String already initialized" **/ @@ -35,22 +27,14 @@ fn DString DString.temp_init(&self, usz capacity = MIN_CAPACITY) return *self; } -/** - * @require !self.data() "String already initialized" - **/ -fn DString DString.init_temp(&self, usz capacity = MIN_CAPACITY) @deprecated("Replaced by temp_init") -{ - return self.temp_init(capacity) @inline; -} - -fn DString new_with_capacity(usz capacity, Allocator* allocator = allocator::heap()) +fn DString new_with_capacity(usz capacity, Allocator allocator = allocator::heap()) { return DString{}.new_init(capacity, allocator); } fn DString temp_with_capacity(usz capacity) => new_with_capacity(capacity, allocator::temp()) @inline; -fn DString new(String c = "", Allocator* allocator = allocator::heap()) +fn DString new(String c = "", Allocator allocator = allocator::heap()) { usz len = c.len; StringData* data = (StringData*)new_with_capacity(len, allocator); @@ -64,7 +48,7 @@ fn DString new(String c = "", Allocator* allocator = allocator::heap()) fn DString temp_new(String s = "") => new(s, allocator::temp()) @inline; -fn DString DString.new_concat(self, DString b, Allocator* allocator = allocator::heap()) +fn DString DString.new_concat(self, DString b, Allocator allocator = allocator::heap()) { DString string; string.new_init(self.len() + b.len(), allocator); @@ -75,8 +59,6 @@ fn DString DString.new_concat(self, DString b, Allocator* allocator = allocator: fn DString DString.temp_concat(self, DString b) => self.new_concat(b, allocator::temp()); -fn DString DString.new_tconcat(self, DString b) @deprecated("Replaced by temp_concat") => self.new_concat(b, allocator::temp()); - fn ZString DString.zstr_view(&self) { StringData* data = self.data(); @@ -166,7 +148,7 @@ fn void DString.append_char32(&self, Char32 c) fn DString DString.tcopy(&self) => self.copy(allocator::temp()); -fn DString DString.copy(self, Allocator* allocator = null) +fn DString DString.copy(self, Allocator allocator = null) { if (!self) { @@ -180,7 +162,7 @@ fn DString DString.copy(self, Allocator* allocator = null) return new_string; } -fn ZString DString.copy_zstr(self, Allocator* allocator = allocator::heap()) +fn ZString DString.copy_zstr(self, Allocator allocator = allocator::heap()) { usz str_len = self.len(); if (!str_len) @@ -194,7 +176,7 @@ fn ZString DString.copy_zstr(self, Allocator* allocator = allocator::heap()) return (ZString)zstr; } -fn String DString.copy_str(self, Allocator* allocator = allocator::heap()) +fn String DString.copy_str(self, Allocator allocator = allocator::heap()) { return (String)self.copy_zstr(allocator)[:self.len()]; } @@ -258,7 +240,7 @@ fn void DString.append_chars(&self, String str) data.len += other_len; } -fn Char32[] DString.copy_utf32(&self, Allocator* allocator = allocator::heap()) +fn Char32[] DString.copy_utf32(&self, Allocator allocator = allocator::heap()) { return self.str_view().to_new_utf32(allocator) @inline!!; } @@ -403,7 +385,7 @@ fn usz! DString.appendfn(&self, String format, args...) @maydiscard return len + 1; } -fn DString new_join(String[] s, String joiner, Allocator* allocator = allocator::heap()) +fn DString new_join(String[] s, String joiner, Allocator allocator = allocator::heap()) { if (!s.len) return (DString)null; usz total_size = joiner.len * s.len; @@ -450,7 +432,7 @@ fn void DString.reserve(&self, usz addition) *self = (DString)allocator::realloc(data.allocator, data, StringData.sizeof + new_capacity); } -fn usz! DString.read_from_stream(&self, InStream* reader) +fn usz! DString.read_from_stream(&self, InStream reader) { if (&reader.available) { @@ -482,7 +464,7 @@ fn usz! DString.read_from_stream(&self, InStream* reader) struct StringData @private { - Allocator* allocator; + Allocator allocator; usz len; usz capacity; char[*] chars; diff --git a/lib/std/core/env.c3 b/lib/std/core/env.c3 index 821464079..9261ef4a0 100644 --- a/lib/std/core/env.c3 +++ b/lib/std/core/env.c3 @@ -123,6 +123,7 @@ const bool BIG_ENDIAN = $$PLATFORM_BIG_ENDIAN; const bool I128_NATIVE_SUPPORT = $$PLATFORM_I128_SUPPORTED; const bool F16_SUPPORT = $$PLATFORM_F16_SUPPORTED; const bool F128_SUPPORT = $$PLATFORM_F128_SUPPORTED; +const REGISTER_SIZE = $$REGISTER_SIZE; const bool COMPILER_SAFE_MODE = $$COMPILER_SAFE_MODE; const bool DEBUG_SYMBOLS = $$DEBUG_SYMBOLS; const usz LLVM_VERSION = $$LLVM_VERSION; diff --git a/lib/std/core/mem.c3 b/lib/std/core/mem.c3 index 9955c9da7..a4f552772 100644 --- a/lib/std/core/mem.c3 +++ b/lib/std/core/mem.c3 @@ -343,9 +343,9 @@ macro void set_inline(void* dst, char val, usz $len, usz $dst_align = 0, bool $i $$memset_inline(dst, val, $len, $is_volatile, $dst_align); } /** - * @require values::@inner_kind(a) == TypeKind.SUBARRAY || values::@inner_kind(a) == TypeKind.POINTER - * @require values::@inner_kind(b) == TypeKind.SUBARRAY || values::@inner_kind(b) == TypeKind.POINTER - * @require values::@inner_kind(a) != TypeKind.SUBARRAY || len == -1 + * @require values::@inner_kind(a) == TypeKind.SLICE || values::@inner_kind(a) == TypeKind.POINTER + * @require values::@inner_kind(b) == TypeKind.SLICE || values::@inner_kind(b) == TypeKind.POINTER + * @require values::@inner_kind(a) != TypeKind.SLICE || len == -1 * @require values::@inner_kind(a) != TypeKind.POINTER || len > -1 * @require values::@assign_to(a, b) && values::@assign_to(b, a) **/ @@ -356,7 +356,7 @@ macro bool equals(a, b, isz len = -1, usz $align = 0) $endif void* x @noinit; void* y @noinit; - $if values::@inner_kind(a) == TypeKind.SUBARRAY: + $if values::@inner_kind(a) == TypeKind.SLICE: len = a.len; if (len != b.len) return false; x = a.ptr; @@ -403,9 +403,9 @@ macro type_alloc_must_be_aligned($Type) /** * Run with a specific allocator inside of the macro body. **/ -macro void @scoped(Allocator* allocator; @body()) +macro void @scoped(Allocator allocator; @body()) { - Allocator* old_allocator = allocator::thread_allocator; + Allocator old_allocator = allocator::thread_allocator; allocator::thread_allocator = allocator; defer allocator::thread_allocator = old_allocator; @body(); @@ -415,7 +415,7 @@ macro void @report_heap_allocs_in_scope(;@body()) { TrackingAllocator tracker; tracker.init(allocator::thread_allocator); - Allocator* old_allocator = allocator::thread_allocator; + Allocator old_allocator = allocator::thread_allocator; allocator::thread_allocator = &tracker; defer { @@ -426,7 +426,7 @@ macro void @report_heap_allocs_in_scope(;@body()) @body(); } -macro void @stack_mem(usz $size; @body(Allocator* mem)) @builtin +macro void @stack_mem(usz $size; @body(Allocator mem)) @builtin { char[$size] buffer; OnStackAllocator allocator; @@ -504,11 +504,6 @@ macro void @pool(TempAllocator* #other_temp = null; @body) @builtin import libc; - -macro TempAllocator* temp() @deprecated("Use allocator::temp()") => allocator::temp(); -macro Allocator* current_allocator() @deprecated("Use allocator::heap()") => allocator::heap(); -macro Allocator* heap() @deprecated("Use allocator::heap()") => allocator::heap(); - module std::core::mem @if(WASM_NOLIBC); SimpleHeapAllocator wasm_allocator @private; @@ -552,10 +547,10 @@ fn void* malloc(usz size) @builtin @inline @nodiscard return allocator::malloc(allocator::heap(), size); } -fn void* tmalloc(usz size, usz alignment = 0, usz offset = 0) @builtin @inline @nodiscard +fn void* tmalloc(usz size, usz alignment = 0) @builtin @inline @nodiscard { if (!size) return null; - return allocator::temp().acquire(size, false, alignment, 0)!!; + return allocator::temp().acquire(size, NO_ZERO, alignment)!!; } /** @@ -608,16 +603,6 @@ macro alloc_aligned($Type) @nodiscard return ($Type*)malloc_aligned($Type.sizeof, $Type.alignof); } -macro new_clear($Type) @deprecated("Use mem::new") -{ - return new($Type); -} - -macro new_temp($Type) @deprecated("Use mem::temp_alloc or mem::temp_new") -{ - return tmalloc($Type.sizeof); -} - /** * @require $vacount < 2 : "Too many arguments." * @require $or($vacount == 0, $assignable($vaexpr(0), $Type)) : "The second argument must be an initializer for the type" @@ -638,12 +623,6 @@ macro temp_alloc($Type) @nodiscard return tmalloc($Type.sizeof); } -macro new_temp_clear($Type) @deprecated("use mem::temp_new") -{ - return tcalloc($Type.sizeof); -} - - /** * @require $Type.alignof <= DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'new_array_aligned' instead" @@ -679,36 +658,16 @@ macro alloc_array_aligned($Type, usz elements) @nodiscard return allocator::alloc_array(allocator::heap(), $Type, elements); } -macro talloc_array($Type, usz elements) @nodiscard @deprecated("use mem::temp_alloc_array") -{ - return temp_alloc_array($Type, elements); -} - macro temp_alloc_array($Type, usz elements) @nodiscard { return (($Type*)tmalloc($Type.sizeof * elements, $Type.alignof))[:elements]; } -macro temp_array($Type, usz elements) @nodiscard @deprecated("use mem::temp_alloc_array") -{ - return temp_alloc_array($Type, elements); -} - macro temp_new_array($Type, usz elements) @nodiscard { return (($Type*)tcalloc($Type.sizeof * elements, $Type.alignof))[:elements]; } -macro new_zero_array($Type, usz elements) @deprecated("Use new_array") -{ - return new_array($Type, elements); -} - -macro temp_zero_array($Type, usz elements) @deprecated("Use temp_new_array") -{ - return temp_new_array($Type, elements); -} - fn void* calloc(usz size) @builtin @inline @nodiscard { return allocator::calloc(allocator::heap(), size); @@ -719,10 +678,10 @@ fn void* calloc_aligned(usz size, usz alignment) @builtin @inline @nodiscard return allocator::calloc_aligned(allocator::heap(), size, alignment)!!; } -fn void* tcalloc(usz size, usz alignment = 0, usz offset = 0) @builtin @inline @nodiscard +fn void* tcalloc(usz size, usz alignment = 0) @builtin @inline @nodiscard { if (!size) return null; - return allocator::temp().acquire(size, false, alignment, 0)!!; + return allocator::temp().acquire(size, ZERO, alignment)!!; } fn void* realloc(void *ptr, usz new_size) @builtin @inline @nodiscard @@ -749,6 +708,6 @@ fn void* trealloc(void* ptr, usz size, usz alignment = mem::DEFAULT_MEM_ALIGNMEN { if (!size) return null; if (!ptr) return tmalloc(size, alignment); - return allocator::temp().resize(ptr, size, alignment, 0)!!; + return allocator::temp().resize(ptr, size, alignment)!!; } diff --git a/lib/std/core/mem_allocator.c3 b/lib/std/core/mem_allocator.c3 index 4c0453ddd..cc1b61314 100644 --- a/lib/std/core/mem_allocator.c3 +++ b/lib/std/core/mem_allocator.c3 @@ -10,6 +10,11 @@ struct TrackingEnv uint line; } +enum AllocInitType +{ + NO_ZERO, + ZERO +} interface Allocator { @@ -18,18 +23,16 @@ interface Allocator /** * @require !alignment || math::is_power_of_2(alignment) * @require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big` - * @require offset == 0 `offset no longer supported` * @require size > 0 **/ - fn void*! acquire(usz size, bool clear, usz alignment, usz offset); + fn void*! acquire(usz size, AllocInitType init_type, usz alignment = 0); /** * @require !alignment || math::is_power_of_2(alignment) * @require alignment <= mem::MAX_MEMORY_ALIGNMENT `alignment too big` - * @require offset == 0 `offset no longer supported` * @require ptr != null * @require new_size > 0 **/ - fn void*! resize(void* ptr, usz new_size, usz alignment, usz offset); + fn void*! resize(void* ptr, usz new_size, usz alignment = 0); /** * @require ptr != null **/ @@ -49,51 +52,51 @@ fn usz alignment_for_allocation(usz alignment) @inline @private return alignment < mem::DEFAULT_MEM_ALIGNMENT ? alignment = mem::DEFAULT_MEM_ALIGNMENT : alignment; } -macro void* malloc(Allocator* allocator, usz size) @nodiscard +macro void* malloc(Allocator allocator, usz size) @nodiscard { return malloc_try(allocator, size)!!; } -macro void*! malloc_try(Allocator* allocator, usz size) @nodiscard +macro void*! malloc_try(Allocator allocator, usz size) @nodiscard { if (!size) return null; $if env::TESTING: - char* data = allocator.acquire(size, false, 0, 0)!; + char* data = allocator.acquire(size, NO_ZERO)!; mem::set(data, 0xAA, size, mem::DEFAULT_MEM_ALIGNMENT); return data; $else - return allocator.acquire(size, false, 0, 0); + return allocator.acquire(size, NO_ZERO); $endif } -macro void* calloc(Allocator* allocator, usz size) @nodiscard +macro void* calloc(Allocator allocator, usz size) @nodiscard { return calloc_try(allocator, size)!!; } -macro void*! calloc_try(Allocator* allocator, usz size) @nodiscard +macro void*! calloc_try(Allocator allocator, usz size) @nodiscard { if (!size) return null; - return allocator.acquire(size, true, 0, 0); + return allocator.acquire(size, ZERO); } -macro void* realloc(Allocator* allocator, void* ptr, usz new_size) @nodiscard +macro void* realloc(Allocator allocator, void* ptr, usz new_size) @nodiscard { return realloc_try(allocator, ptr, new_size)!!; } -macro void*! realloc_try(Allocator* allocator, void* ptr, usz new_size) @nodiscard +macro void*! realloc_try(Allocator allocator, void* ptr, usz new_size) @nodiscard { if (!new_size) { free(allocator, ptr); return null; } - if (!ptr) return allocator.acquire(new_size, false, 0, 0); - return allocator.resize(ptr, new_size, 0, 0); + if (!ptr) return allocator.acquire(new_size, NO_ZERO); + return allocator.resize(ptr, new_size); } -macro void free(Allocator* allocator, void* ptr) +macro void free(Allocator allocator, void* ptr) { if (!ptr) return; $if env::TESTING: @@ -102,25 +105,25 @@ macro void free(Allocator* allocator, void* ptr) allocator.release(ptr, false); } -macro void*! malloc_aligned(Allocator* allocator, usz size, usz alignment, usz offset = 0) @nodiscard +macro void*! malloc_aligned(Allocator allocator, usz size, usz alignment) @nodiscard { if (!size) return null; $if env::TESTING: - char* data = allocator.acquire(size, false, alignment, offset)!; + char* data = allocator.acquire(size, NO_ZERO, alignment)!; mem::set(data, 0xAA, size, mem::DEFAULT_MEM_ALIGNMENT); return data; $else - return allocator.acquire(size, false, alignment, offset); + return allocator.acquire(size, NO_ZERO, alignment); $endif } -macro void*! calloc_aligned(Allocator* allocator, usz size, usz alignment, usz offset = 0) @nodiscard +macro void*! calloc_aligned(Allocator allocator, usz size, usz alignment) @nodiscard { if (!size) return null; - return allocator.acquire(size, true, alignment, offset); + return allocator.acquire(size, ZERO, alignment); } -macro void*! realloc_aligned(Allocator* allocator, void* ptr, usz new_size, usz alignment, usz offset = 0) @nodiscard +macro void*! realloc_aligned(Allocator allocator, void* ptr, usz new_size, usz alignment) @nodiscard { if (!new_size) { @@ -131,23 +134,23 @@ macro void*! realloc_aligned(Allocator* allocator, void* ptr, usz new_size, usz { return malloc_aligned(allocator, new_size, alignment); } - return allocator.resize(ptr, new_size, alignment, offset); + return allocator.resize(ptr, new_size, alignment); } -macro void free_aligned(Allocator* allocator, void* ptr) +macro void free_aligned(Allocator allocator, void* ptr) { if (!ptr) return; $if env::TESTING: ((char*)ptr)[0] = 0xBA; $endif - allocator.release(ptr, true); + allocator.release(ptr, .aligned = true); } /** * @require $vacount < 2 : "Too many arguments." * @require $or($vacount == 0, $assignable($vaexpr(0), $Type)) : "The second argument must be an initializer for the type" **/ -macro new(Allocator* allocator, $Type, ...) @nodiscard +macro new(Allocator allocator, $Type, ...) @nodiscard { $if $vacount == 0: return ($Type*)calloc(allocator, $Type.sizeof); @@ -162,7 +165,7 @@ macro new(Allocator* allocator, $Type, ...) @nodiscard * @require $vacount < 2 : "Too many arguments." * @require $or($vacount == 0, $assignable($vaexpr(0), $Type)) : "The second argument must be an initializer for the type" **/ -macro new_try(Allocator* allocator, $Type, ...) @nodiscard +macro new_try(Allocator allocator, $Type, ...) @nodiscard { $if $vacount == 0: return ($Type*)calloc_try(allocator, $Type.sizeof); @@ -173,62 +176,62 @@ macro new_try(Allocator* allocator, $Type, ...) @nodiscard $endif } -macro new_with_padding(Allocator* allocator, $Type, usz padding) @nodiscard +macro new_with_padding(Allocator allocator, $Type, usz padding) @nodiscard { return ($Type*)calloc_try(allocator, $Type.sizeof + padding); } -macro alloc(Allocator* allocator, $Type) @nodiscard +macro alloc(Allocator allocator, $Type) @nodiscard { return ($Type*)malloc(allocator, $Type.sizeof); } -macro alloc_try(Allocator* allocator, $Type) @nodiscard +macro alloc_try(Allocator allocator, $Type) @nodiscard { return ($Type*)malloc_try(allocator, $Type.sizeof); } -macro alloc_with_padding(Allocator* allocator, $Type, usz padding) @nodiscard +macro alloc_with_padding(Allocator allocator, $Type, usz padding) @nodiscard { return ($Type*)malloc_try(allocator, $Type.sizeof + padding); } -macro new_array(Allocator* allocator, $Type, usz elements) @nodiscard +macro new_array(Allocator allocator, $Type, usz elements) @nodiscard { return new_array_try(allocator, $Type, elements)!!; } -macro new_array_try(Allocator* allocator, $Type, usz elements) @nodiscard +macro new_array_try(Allocator allocator, $Type, usz elements) @nodiscard { return (($Type*)calloc_try(allocator, $Type.sizeof * elements))[:elements]; } -macro new_array_aligned(Allocator* allocator, $Type, usz elements) @nodiscard +macro new_array_aligned(Allocator allocator, $Type, usz elements) @nodiscard { return ((Type*)calloc_aligned(allocator, $Type.sizeof * elements, $Type.alignof))[:elements]!!; } -macro alloc_array(Allocator* allocator, $Type, usz elements) @nodiscard +macro alloc_array(Allocator allocator, $Type, usz elements) @nodiscard { return alloc_array_try(allocator, $Type, elements)!!; } -macro alloc_array_aligned(Allocator* allocator, $Type, usz elements) @nodiscard +macro alloc_array_aligned(Allocator allocator, $Type, usz elements) @nodiscard { return ((Type*)malloc_aligned(allocator, $Type.sizeof * elements, $Type.alignof))[:elements]!!; } -macro alloc_array_try(Allocator* allocator, $Type, usz elements) @nodiscard +macro alloc_array_try(Allocator allocator, $Type, usz elements) @nodiscard { return (($Type*)malloc_try(allocator, $Type.sizeof * elements))[:elements]; } -macro clone(Allocator* allocator, value) @nodiscard +macro clone(Allocator allocator, value) @nodiscard { return new(allocator, $typeof(value), value); } -fn any* clone_any(Allocator* allocator, any* value) @nodiscard +fn any clone_any(Allocator allocator, any value) @nodiscard { usz size = value.type.sizeof; void* data = malloc(allocator, size); @@ -236,106 +239,6 @@ fn any* clone_any(Allocator* allocator, any* value) @nodiscard return any_make(data, value.type); } -// Allocator "functions" - -macro void*! Allocator.alloc_checked(&self, usz size) @deprecated("Use allocator::malloc_try") -{ - return malloc_try(self, size); -} - -macro void*! Allocator.calloc_checked(&self, usz size) @deprecated("Use allocator::calloc_try") -{ - return calloc_try(self, size); -} - -macro void*! Allocator.realloc_checked(&self, void* ptr, usz new_size) @deprecated("Use allocator::realloc_try") -{ - return realloc_try(ptr, new_size); -} - -macro Allocator.new_array(&self, $Type, usz size, usz end_padding = 0) @deprecated("Use allocator::alloc_array") -{ - return (($Type*)self.alloc_checked($Type.sizeof * size + end_padding))[:size]!!; -} - -macro Allocator.new_array_checked(&self, $Type, usz size, usz end_padding = 0) @deprecated("Use allocator::alloc_array_try") -{ - return (($Type*)self.alloc_checked($Type.sizeof * size + end_padding))[:size]; -} - -macro Allocator.new_zero_array(&self, $Type, usz size, usz end_padding = 0) @deprecated("Use allocator::new_array") -{ - return (($Type*)self.calloc_checked($Type.sizeof * size + end_padding))[:size]!!; -} - -macro Allocator.new_zero_array_checked(&self, $Type, usz size, usz end_padding = 0) @deprecated("Use allocator::new_array_try") -{ - return (($Type*)self.calloc_checked($Type.sizeof * size + end_padding))[:size]; -} - -macro Allocator.new(&self, $Type, usz end_padding = 0) @nodiscard @deprecated("Use allocator::alloc") -{ - return ($Type*)self.alloc_checked($Type.sizeof + end_padding)!!; -} - -macro Allocator.new_checked(&self, $Type, usz end_padding = 0) @nodiscard @deprecated("Use allocator::alloc_try") -{ - return ($Type*)self.alloc_checked($Type.sizeof + end_padding); -} - -macro Allocator.new_clear(&self, $Type, usz end_padding = 0) @nodiscard @deprecated("Use allocator::new") -{ - return ($Type*)self.calloc_checked($Type.sizeof + end_padding)!!; -} - -macro Allocator.new_clear_checked(&self, $Type, usz end_padding = 0) @nodiscard @deprecated("Use allocator::new_try") -{ - return ($Type*)self.calloc_checked($Type.sizeof + end_padding); -} -macro Allocator.clone(&self, value) @deprecated("Use allocator::clone") -{ - var x = self.alloc($typeof(value)); - *x = value; - return x; -} - -fn void* Allocator.alloc(&self, usz size) @nodiscard @deprecated("Use allocator::malloc") -{ - return malloc(self, size); -} -fn void* Allocator.calloc(&self, usz size) @nodiscard @deprecated("Use allocator::calloc") -{ - return calloc(self, size); -} -fn void* Allocator.realloc(&self, void* ptr, usz new_size) @nodiscard @deprecated("Use allocator::realloc") -{ - return realloc(self, ptr, new_size); -} - -fn void*! Allocator.alloc_aligned(&self, usz size, usz alignment, usz offset = 0) @deprecated("Use allocator::malloc_aligned") -{ - return malloc_aligned(self, size, alignment, 0); -} - -fn void*! Allocator.calloc_aligned(&self, usz size, usz alignment, usz offset = 0) @deprecated("Use allocator::calloc_aligned") -{ - return calloc_aligned(self, size, alignment, 0); -} - -fn void*! Allocator.realloc_aligned(&self, void* ptr, usz new_size, usz alignment = 0, usz offset = 0) @deprecated("Use allocator::realloc_aligned") -{ - return realloc_aligned(self, ptr, new_size, alignment, 0); -} - -fn void Allocator.free(&self, void* ptr) @deprecated("Use allocator::free") -{ - free(self, ptr); -} -fn void Allocator.free_aligned(&self, void* ptr) @deprecated("Use allocator::free_aligned") -{ - free_aligned(self, ptr); -} - /** * @require bytes > 0 @@ -395,12 +298,12 @@ macro void*! @aligned_realloc(#calloc_fn, #free_fn, void* old_pointer, usz bytes // All allocators -tlocal Allocator* thread_allocator @private = &allocator::LIBC_ALLOCATOR; +tlocal Allocator thread_allocator @private = &allocator::LIBC_ALLOCATOR; tlocal TempAllocator* thread_temp_allocator @private = null; tlocal TempAllocator*[2] temp_allocator_pair @private; -Allocator* temp_base_allocator @private = &allocator::LIBC_ALLOCATOR; +Allocator temp_base_allocator @private = &allocator::LIBC_ALLOCATOR; -macro TempAllocator* create_default_sized_temp_allocator(Allocator* allocator) @local +macro TempAllocator* create_default_sized_temp_allocator(Allocator allocator) @local { $switch (env::MEMORY_ENV) $case NORMAL: @@ -414,7 +317,7 @@ macro TempAllocator* create_default_sized_temp_allocator(Allocator* allocator) @ $endswitch } -macro Allocator* heap() => thread_allocator; +macro Allocator heap() => thread_allocator; macro TempAllocator* temp() { @@ -432,7 +335,7 @@ fn void init_default_temp_allocators() @private thread_temp_allocator = temp_allocator_pair[0]; } -fn TempAllocator *temp_allocator_next() @private +fn TempAllocator* temp_allocator_next() @private { if (!thread_temp_allocator) { diff --git a/lib/std/core/runtime.c3 b/lib/std/core/runtime.c3 index effe35950..70ca8bd92 100644 --- a/lib/std/core/runtime.c3 +++ b/lib/std/core/runtime.c3 @@ -4,13 +4,13 @@ module std::core::runtime; import libc, std::time, std::io, std::sort; -struct AnyStruct +struct AnyRaw { void* ptr; typeid type; } -struct SubArrayStruct +struct SliceRaw { void* ptr; usz len; @@ -24,7 +24,7 @@ struct BenchmarkUnit BenchmarkFn func; } -fn BenchmarkUnit[] benchmark_collection_create(Allocator* allocator = allocator::heap()) +fn BenchmarkUnit[] benchmark_collection_create(Allocator allocator = allocator::heap()) { BenchmarkFn[] fns = $$BENCHMARK_FNS; String[] names = $$BENCHMARK_NAMES; @@ -142,7 +142,7 @@ struct TestUnit TestFn func; } -fn TestUnit[] test_collection_create(Allocator* allocator = allocator::heap()) +fn TestUnit[] test_collection_create(Allocator allocator = allocator::heap()) { TestFn[] fns = $$TEST_FNS; String[] names = $$TEST_NAMES; diff --git a/lib/std/core/string.c3 b/lib/std/core/string.c3 index 69664fb73..b45ac67bd 100644 --- a/lib/std/core/string.c3 +++ b/lib/std/core/string.c3 @@ -44,8 +44,7 @@ macro ZString tformat_zstr(String fmt, ...) str.appendf(fmt, $vasplat()); return str.zstr_view(); } - -macro String new_format(String fmt, ..., Allocator* allocator = allocator::heap()) +macro String new_format(String fmt, ..., Allocator allocator = allocator::heap()) { @pool(allocator) { @@ -55,7 +54,7 @@ macro String new_format(String fmt, ..., Allocator* allocator = allocator::heap( }; } -macro ZString new_format_zstr(String fmt, ..., Allocator* allocator = allocator::heap()) +macro ZString new_format_zstr(String fmt, ..., Allocator allocator = allocator::heap()) { @pool(allocator) { @@ -71,7 +70,7 @@ macro bool char_in_set(char c, String set) return false; } -fn String join_new(String[] s, String joiner, Allocator* allocator = allocator::heap()) +fn String join_new(String[] s, String joiner, Allocator allocator = allocator::heap()) { if (!s) { @@ -169,7 +168,7 @@ fn String String.strip_end(string, String needle) * @require needle.len > 0 "The needle must be at least 1 character long" * @ensure return.len > 0 **/ -fn String[] String.split(s, String needle, usz max = 0, Allocator* allocator = allocator::heap()) +fn String[] String.split(s, String needle, usz max = 0, Allocator allocator = allocator::heap()) { usz capacity = 16; usz i = 0; @@ -328,7 +327,7 @@ fn usz ZString.len(str) } -fn ZString String.zstr_copy(s, Allocator* allocator = allocator::heap()) +fn ZString String.zstr_copy(s, Allocator allocator = allocator::heap()) { usz len = s.len; char* str = allocator::malloc(allocator, len + 1); @@ -337,7 +336,7 @@ fn ZString String.zstr_copy(s, Allocator* allocator = allocator::heap()) return (ZString)str; } -fn String String.concat(s1, String s2, Allocator* allocator = allocator::heap()) +fn String String.concat(s1, String s2, Allocator allocator = allocator::heap()) { usz full_len = s1.len + s2.len; char* str = allocator::malloc(allocator, full_len + 1); @@ -353,7 +352,7 @@ fn String String.tconcat(s1, String s2) => s1.concat(s2, allocator::temp()); fn ZString String.zstr_tcopy(s) => s.zstr_copy(allocator::temp()) @inline; -fn String String.copy(s, Allocator* allocator = allocator::heap()) +fn String String.copy(s, Allocator allocator = allocator::heap()) { usz len = s.len; char* str = allocator::malloc(allocator, len + 1); @@ -362,7 +361,7 @@ fn String String.copy(s, Allocator* allocator = allocator::heap()) return (String)str[:len]; } -fn void String.free(&s, Allocator* allocator = allocator::heap()) +fn void String.free(&s, Allocator allocator = allocator::heap()) { if (!s.len) return; allocator::free(allocator, s.ptr); @@ -371,7 +370,7 @@ fn void String.free(&s, Allocator* allocator = allocator::heap()) fn String String.tcopy(s) => s.copy(allocator::temp()) @inline; -fn String ZString.copy(z, Allocator* allocator = allocator::temp()) +fn String ZString.copy(z, Allocator allocator = allocator::temp()) { return z.str_view().copy(allocator) @inline; } @@ -387,7 +386,7 @@ fn String ZString.tcopy(z) * @return! UnicodeResult.INVALID_UTF8 "If the string contained an invalid UTF-8 sequence" * @return! AllocationFailure "If allocation of the string fails" **/ -fn Char16[]! String.to_new_utf16(s, Allocator* allocator = allocator::heap()) +fn Char16[]! String.to_new_utf16(s, Allocator allocator = allocator::heap()) { usz len16 = conv::utf16len_for_utf8(s); Char16* data = allocator::alloc_array_try(allocator, Char16, len16 + 1)!; @@ -407,7 +406,7 @@ fn Char16[]! String.to_temp_utf16(s) return s.to_new_utf16(allocator::temp()); } -fn WString! String.to_new_wstring(s, Allocator* allocator = allocator::heap()) +fn WString! String.to_new_wstring(s, Allocator allocator = allocator::heap()) { return (WString)s.to_new_utf16(allocator).ptr; } @@ -417,7 +416,7 @@ fn WString! String.to_temp_wstring(s) return (WString)s.to_temp_utf16().ptr; } -fn Char32[]! String.to_new_utf32(s, Allocator* allocator = allocator::heap()) +fn Char32[]! String.to_new_utf32(s, Allocator allocator = allocator::heap()) { usz codepoints = conv::utf8_codepoints(s); Char32* data = allocator::alloc_array_try(allocator, Char32, codepoints + 1)!; @@ -436,14 +435,14 @@ fn void String.convert_ascii_to_lower(s) foreach (&c : s) if (c.is_upper()) *c += 'a' - 'A'; } -fn String String.new_ascii_to_lower(s, Allocator* allocator = allocator::heap()) +fn String String.new_ascii_to_lower(s, Allocator allocator = allocator::heap()) { String copy = s.copy(allocator); copy.convert_ascii_to_lower(); return copy; } -fn String String.temp_ascii_to_lower(s, Allocator* allocator = allocator::heap()) +fn String String.temp_ascii_to_lower(s, Allocator allocator = allocator::heap()) { return s.new_ascii_to_lower(allocator::temp()); } @@ -453,7 +452,7 @@ fn void String.convert_ascii_to_upper(s) foreach (&c : s) if (c.is_lower()) *c -= 'a' - 'A'; } -fn String String.new_ascii_to_upper(s, Allocator* allocator = allocator::heap()) +fn String String.new_ascii_to_upper(s, Allocator allocator = allocator::heap()) { String copy = s.copy(allocator); copy.convert_ascii_to_upper(); @@ -470,7 +469,7 @@ fn String String.temp_ascii_to_upper(s) return s.new_ascii_to_upper(allocator::temp()); } -fn String! new_from_utf32(Char32[] utf32, Allocator* allocator = allocator::heap()) +fn String! new_from_utf32(Char32[] utf32, Allocator allocator = allocator::heap()) { usz len = conv::utf8len_for_utf32(utf32); char* data = allocator::malloc_try(allocator, len + 1)!; @@ -480,7 +479,7 @@ fn String! new_from_utf32(Char32[] utf32, Allocator* allocator = allocator::heap return (String)data[:len]; } -fn String! new_from_utf16(Char16[] utf16, Allocator* allocator = allocator::heap()) +fn String! new_from_utf16(Char16[] utf16, Allocator allocator = allocator::heap()) { usz len = conv::utf8len_for_utf16(utf16); char* data = allocator::malloc_try(allocator, len + 1)!; @@ -490,7 +489,7 @@ fn String! new_from_utf16(Char16[] utf16, Allocator* allocator = allocator::heap return (String)data[:len]; } -fn String! new_from_wstring(WString wstring, Allocator* allocator = allocator::heap()) +fn String! new_from_wstring(WString wstring, Allocator allocator = allocator::heap()) { usz utf16_len; while (wstring[utf16_len] != 0) utf16_len++; diff --git a/lib/std/core/types.c3 b/lib/std/core/types.c3 index 340e7ca1e..87c825606 100644 --- a/lib/std/core/types.c3 +++ b/lib/std/core/types.c3 @@ -11,7 +11,7 @@ fault ConversionResult /** * @require $Type.kindof.is_int() || $Type.kindof == TypeKind.ENUM "Argument was not an integer" **/ -macro any_to_int(any* v, $Type) +macro any_to_int(any v, $Type) { typeid any_type = v.type; TypeKind kind = any_type.kindof; @@ -108,10 +108,10 @@ fn bool TypeKind.is_int(kind) @inline return kind == TypeKind.SIGNED_INT || kind == TypeKind.UNSIGNED_INT; } -macro bool is_subarray_convertable($Type) +macro bool is_slice_convertable($Type) { $switch ($Type.kindof) - $case SUBARRAY: + $case SLICE: return true; $case POINTER: return $Type.inner.kindof == TypeKind.ARRAY; @@ -298,7 +298,7 @@ enum TypeKind : char FUNC, OPTIONAL, ARRAY, - SUBARRAY, + SLICE, VECTOR, DISTINCT, POINTER, diff --git a/lib/std/encoding/csv.c3 b/lib/std/encoding/csv.c3 index 7fc4cd1d3..25050c53f 100644 --- a/lib/std/encoding/csv.c3 +++ b/lib/std/encoding/csv.c3 @@ -3,22 +3,22 @@ import std::io; struct CsvReader { - InStream* stream; + InStream stream; String separator; } -fn void CsvReader.init(&self, InStream* stream, String separator = ",") +fn void CsvReader.init(&self, InStream stream, String separator = ",") { self.stream = stream; self.separator = separator; } -fn String[]! CsvReader.read_new_row(self, Allocator* allocator = allocator::heap()) +fn String[]! CsvReader.read_new_row(self, Allocator allocator = allocator::heap()) { return self.read_new_row_with_allocator(allocator::temp()) @inline; } -fn String[]! CsvReader.read_new_row_with_allocator(self, Allocator* allocator = allocator::heap()) +fn String[]! CsvReader.read_new_row_with_allocator(self, Allocator allocator = allocator::heap()) { @pool(allocator) { @@ -45,7 +45,7 @@ macro CsvReader.@each_row(self, int rows = int.max; @body(String[] row)) String sep = self.separator; while (rows--) { - @stack_mem(512; Allocator* mem) + @stack_mem(512; Allocator mem) { String[] parts; @pool() diff --git a/lib/std/encoding/json.c3 b/lib/std/encoding/json.c3 index 2c295e452..cbd014414 100644 --- a/lib/std/encoding/json.c3 +++ b/lib/std/encoding/json.c3 @@ -15,7 +15,7 @@ fault JsonParsingError INVALID_NUMBER, } -fn Object*! parse(InStream* s, Allocator* allocator = allocator::heap()) +fn Object*! parse(InStream s, Allocator allocator = allocator::heap()) { JsonContext context = { .last_string = dstring::new_with_capacity(64, allocator), .stream = s, .allocator = allocator }; defer context.last_string.free(); @@ -44,8 +44,8 @@ enum JsonTokenType @local struct JsonContext @local { uint line; - InStream* stream; - Allocator* allocator; + InStream stream; + Allocator allocator; JsonTokenType token; DString last_string; double last_number; @@ -170,7 +170,7 @@ fn Object*! parse_array(JsonContext* context) @local while (token != JsonTokenType.RBRACKET) { Object* element = parse_from_token(context, token)!; - list.append(element); + list.push(element); token = advance(context)!; if (token == JsonTokenType.COMMA) { diff --git a/lib/std/io/bits.c3 b/lib/std/io/bits.c3 index 04449195b..9be309e4d 100644 --- a/lib/std/io/bits.c3 +++ b/lib/std/io/bits.c3 @@ -2,12 +2,12 @@ module std::io; struct BitReader { - InStream* reader; + InStream reader; uint bits; uint len; } -fn void BitReader.init(&self, InStream* byte_reader) +fn void BitReader.init(&self, InStream byte_reader) { *self = { .reader = byte_reader }; } @@ -40,12 +40,12 @@ fn char! BitReader.read_bits(&self, uint nbits) struct BitWriter { - OutStream* writer; + OutStream writer; uint bits; uint len; } -fn void BitWriter.init(&self, OutStream* byte_writer) +fn void BitWriter.init(&self, OutStream byte_writer) { *self = { .writer = byte_writer }; } diff --git a/lib/std/io/file.c3 b/lib/std/io/file.c3 index b250893c6..db110e6b9 100644 --- a/lib/std/io/file.c3 +++ b/lib/std/io/file.c3 @@ -161,7 +161,7 @@ fn char[]! load_buffer(String filename, char[] buffer) } -fn char[]! load_new(String filename, Allocator* allocator = allocator::heap()) +fn char[]! load_new(String filename, Allocator allocator = allocator::heap()) { File file = open(filename, "rb")!; defer (void)file.close(); diff --git a/lib/std/io/formatter.c3 b/lib/std/io/formatter.c3 index bf4fa358a..aaecfc05d 100644 --- a/lib/std/io/formatter.c3 +++ b/lib/std/io/formatter.c3 @@ -6,7 +6,7 @@ const int PRINTF_NTOA_BUFFER_SIZE = 256; interface Printable { - fn String to_new_string(Allocator *allocator) @optional; + fn String to_new_string(Allocator allocator) @optional; fn usz! to_format(Formatter* formatter) @optional; } @@ -72,7 +72,7 @@ fn usz! Formatter.out(&self, char c) @private return 1; } -fn usz! Formatter.print_with_function(&self, Printable* arg) +fn usz! Formatter.print_with_function(&self, Printable arg) { if (&arg.to_format) { @@ -98,7 +98,7 @@ fn usz! Formatter.print_with_function(&self, Printable* arg) self.width = old_width; self.prec = old_prec; } - @stack_mem(1024; Allocator* mem) + @stack_mem(1024; Allocator mem) { return self.out_substr(arg.to_new_string(mem)); }; @@ -107,7 +107,7 @@ fn usz! Formatter.print_with_function(&self, Printable* arg) } -fn usz! Formatter.out_str(&self, any* arg) @private +fn usz! Formatter.out_str(&self, any arg) @private { switch (arg.type.kindof) { @@ -119,7 +119,7 @@ fn usz! Formatter.out_str(&self, any* arg) @private case FAULT: return self.out_substr((*(anyfault*)arg.ptr).nameof); case ANY: - return self.out_str(*(any**)arg); + return self.out_str(*(any*)arg); case OPTIONAL: unreachable(); case SIGNED_INT: @@ -149,7 +149,7 @@ fn usz! Formatter.out_str(&self, any* arg) @private return self.out_substr(*(bool*)arg.ptr ? "true" : "false"); default: } - usz! n = self.print_with_function((Printable*)arg); + usz! n = self.print_with_function((Printable)arg); if (catch err = n) { case SearchResult.MISSING: @@ -246,7 +246,7 @@ fn usz! Formatter.out_str(&self, any* arg) @private } len += self.out_substr(">]")!; return len; - case SUBARRAY: + case SLICE: // this is SomeType[] so grab the "SomeType" typeid inner = arg.type.inner; if (inner == char.typeid) @@ -291,7 +291,7 @@ fn void! out_null_fn(void* data @unused, char c @unused) @private -fn usz! Formatter.vprintf(&self, String format, any*[] anys) +fn usz! Formatter.vprintf(&self, String format, any[] anys) { if (!self.out_fn) { @@ -358,7 +358,7 @@ fn usz! Formatter.vprintf(&self, String format, any*[] anys) // evaluate specifier uint base = 0; if (variant_index >= anys.len) return PrintFault.MISSING_ARG?; - any* current = anys[variant_index++]; + any current = anys[variant_index++]; switch (c) { case 'd': diff --git a/lib/std/io/formatter_private.c3 b/lib/std/io/formatter_private.c3 index 13b5e2b52..57075cfd0 100644 --- a/lib/std/io/formatter_private.c3 +++ b/lib/std/io/formatter_private.c3 @@ -10,7 +10,7 @@ fn usz! Formatter.adjust(&self, usz len) @local return self.pad(' ', self.width, len); } -fn uint128! int_from_any(any* arg, bool *is_neg) @private +fn uint128! int_from_any(any arg, bool *is_neg) @private { switch (arg.type.kindof) { @@ -63,14 +63,11 @@ fn uint128! int_from_any(any* arg, bool *is_neg) @private } } -fn FloatType! float_from_any(any* arg) @private +fn FloatType! float_from_any(any arg) @private { $if env::F128_SUPPORT: if (arg.type == float128.typeid) return (FloatType)*((float128*)arg.ptr); $endif - $if env::F16_SUPPORT: - if (arg.type == float16.typeid) return *((float16*)arg.ptr); - $endif if (arg.type.kindof == TypeKind.DISTINCT) { return float_from_any(arg.as_inner()); @@ -588,14 +585,14 @@ fn usz! Formatter.ntoa_format(&self, String buf, usz len, bool negative, uint ba } -fn usz! Formatter.ntoa_any(&self, any* arg, uint base) @private +fn usz! Formatter.ntoa_any(&self, any arg, uint base) @private { bool is_neg; uint128 val = int_from_any(arg, &is_neg)!!; return self.ntoa(val, is_neg, base) @inline; } -fn usz! Formatter.out_char(&self, any* arg) @private +fn usz! Formatter.out_char(&self, any arg) @private { usz len = 1; uint l = 1; @@ -649,21 +646,21 @@ fn void! printf_advance_format(usz format_len, usz *index_ptr) @inline @private if (val >= format_len) return FormattingFault.UNTERMINATED_FORMAT?; } -fn any*! next_any(any** args_ptr, usz args_len, usz* arg_index_ptr) @inline @private +fn any! next_any(any* args_ptr, usz args_len, usz* arg_index_ptr) @inline @private { if (*arg_index_ptr >= args_len) return FormattingFault.MISSING_ARG?; return args_ptr[(*arg_index_ptr)++]; } fn int! printf_parse_format_field( - any** args_ptr, usz args_len, usz* args_index_ptr, + any* args_ptr, usz args_len, usz* args_index_ptr, char* format_ptr, usz format_len, usz* index_ptr) @inline @private { char c = format_ptr[*index_ptr]; if (c.is_digit()) return simple_atoi(format_ptr, format_len, index_ptr); if (c != '*') return 0; printf_advance_format(format_len, index_ptr)!; - any* val = next_any(args_ptr, args_len, args_index_ptr)!; + any val = next_any(args_ptr, args_len, args_index_ptr)!; if (!val.type.kindof.is_int()) return FormattingFault.INVALID_WIDTH_ARG?; uint! intval = types::any_to_int(val, int); return intval ?? FormattingFault.INVALID_WIDTH_ARG?; diff --git a/lib/std/io/io.c3 b/lib/std/io/io.c3 index 927a6fba8..d172b9f5a 100644 --- a/lib/std/io/io.c3 +++ b/lib/std/io/io.c3 @@ -49,9 +49,9 @@ fault IoError * @param stream * @require @is_instream(stream) **/ -macro String! readline(stream = io::stdin(), Allocator* allocator = allocator::heap()) +macro String! readline(stream = io::stdin(), Allocator allocator = allocator::heap()) { - bool $is_stream = @typeid(stream) == InStream*.typeid; + bool $is_stream = @typeid(stream) == InStream.typeid; $if $is_stream: $typeof(&stream.read_byte) func = &stream.read_byte; char val = func((void*)stream)!; @@ -108,14 +108,14 @@ macro usz! fprint(out, x) $endswitch } -fn usz! fprintf(OutStream* out, String format, args...) +fn usz! fprintf(OutStream out, String format, args...) { Formatter formatter; formatter.init(&out_putstream_fn, &out); return formatter.vprintf(format, args); } -fn usz! fprintfn(OutStream* out, String format, args...) @maydiscard +fn usz! fprintfn(OutStream out, String format, args...) @maydiscard { Formatter formatter; formatter.init(&out_putstream_fn, &out); @@ -133,7 +133,7 @@ macro usz! fprintn(out, x = "") usz len = fprint(out, x)!; out.write_byte('\n')!; $switch - $case @typeid(out) == OutStream*.typeid: + $case @typeid(out) == OutStream.typeid: if (&out.flush) out.flush()!; $case $defined(out.flush): out.flush()!; @@ -164,7 +164,7 @@ macro void eprintn(x) fn void! out_putstream_fn(void* data, char c) @private { - OutStream** stream = data; + OutStream* stream = data; return (*stream).write_byte(c); } @@ -193,7 +193,7 @@ fn usz! printfn(String format, args...) @maydiscard fn usz! eprintf(String format, args...) @maydiscard { Formatter formatter; - OutStream* stream = stderr(); + OutStream stream = stderr(); formatter.init(&out_putstream_fn, &stream); return formatter.vprintf(format, args); } @@ -202,7 +202,7 @@ fn usz! eprintf(String format, args...) @maydiscard fn usz! eprintfn(String format, args...) @maydiscard { Formatter formatter; - OutStream* stream = stderr(); + OutStream stream = stderr(); formatter.init(&out_putstream_fn, &stream); usz len = formatter.vprintf(format, args)! + 1; stderr().write_byte('\n')!; diff --git a/lib/std/io/os/getcwd.c3 b/lib/std/io/os/getcwd.c3 index 7dfdcc163..9e58c7093 100644 --- a/lib/std/io/os/getcwd.c3 +++ b/lib/std/io/os/getcwd.c3 @@ -1,7 +1,7 @@ module std::io::os; import libc, std::os; -macro String! getcwd(Allocator* allocator = allocator::heap()) +macro String! getcwd(Allocator allocator = allocator::heap()) { $switch $case env::WIN32: diff --git a/lib/std/io/os/ls.c3 b/lib/std/io/os/ls.c3 index dad50f7b3..0a72fb7eb 100644 --- a/lib/std/io/os/ls.c3 +++ b/lib/std/io/os/ls.c3 @@ -1,7 +1,7 @@ module std::io::os @if(env::POSIX); import std::io, std::os; -fn PathList! native_ls(Path dir, bool no_dirs, bool no_symlinks, String mask, Allocator* allocator) +fn PathList! native_ls(Path dir, bool no_dirs, bool no_symlinks, String mask, Allocator allocator) { PathList list; list.new_init(.allocator = allocator); @@ -16,7 +16,7 @@ fn PathList! native_ls(Path dir, bool no_dirs, bool no_symlinks, String mask, Al if (entry.d_type == posix::DT_LNK && no_symlinks) continue; if (entry.d_type == posix::DT_DIR && no_dirs) continue; Path path = path::new(name, allocator)!!; - list.append(path); + list.push(path); } return list; } @@ -24,7 +24,7 @@ fn PathList! native_ls(Path dir, bool no_dirs, bool no_symlinks, String mask, Al module std::io::os @if(env::WIN32); import std::time, std::os, std::io; -fn PathList! native_ls(Path dir, bool no_dirs, bool no_symlinks, String mask, Allocator* allocator) +fn PathList! native_ls(Path dir, bool no_dirs, bool no_symlinks, String mask, Allocator allocator) { PathList list; list.new_init(.allocator = allocator); @@ -43,7 +43,7 @@ fn PathList! native_ls(Path dir, bool no_dirs, bool no_symlinks, String mask, Al { String filename = string::temp_from_wstring((WString)&find_data.cFileName)!; if (filename == ".." || filename == ".") continue; - list.append(path::new(filename, allocator)!); + list.push(path::new(filename, allocator)!); }; } while (win32::findNextFileW(find, &find_data)); return list; diff --git a/lib/std/io/os/temp_directory.c3 b/lib/std/io/os/temp_directory.c3 index 6cf288b54..766876727 100644 --- a/lib/std/io/os/temp_directory.c3 +++ b/lib/std/io/os/temp_directory.c3 @@ -1,7 +1,7 @@ module std::io::os @if(env::LIBC); import std::io::path, std::os; -fn Path! native_temp_directory(Allocator* allocator = allocator::heap()) @if(!env::WIN32) +fn Path! native_temp_directory(Allocator allocator = allocator::heap()) @if(!env::WIN32) { foreach (String env : { "TMPDIR", "TMP", "TEMP", "TEMPDIR" }) { @@ -11,7 +11,7 @@ fn Path! native_temp_directory(Allocator* allocator = allocator::heap()) @if(!en return path::new("/tmp", allocator); } -fn Path! native_temp_directory(Allocator* allocator = allocator::heap()) @if(env::WIN32) +fn Path! native_temp_directory(Allocator allocator = allocator::heap()) @if(env::WIN32) { @pool(allocator) { @@ -25,7 +25,7 @@ fn Path! native_temp_directory(Allocator* allocator = allocator::heap()) @if(env module std::io::os @if(env::NO_LIBC); -macro Path! native_temp_directory(Allocator* allocator = allocator::heap()) +macro Path! native_temp_directory(Allocator allocator = allocator::heap()) { return IoError.UNSUPPORTED_OPERATION?; } diff --git a/lib/std/io/path.c3 b/lib/std/io/path.c3 index 7a2f8d073..617c17ec1 100644 --- a/lib/std/io/path.c3 +++ b/lib/std/io/path.c3 @@ -1,5 +1,6 @@ module std::io::path; import std::collections::list, std::io::os; +import std::os::win32; const PathEnv DEFAULT_PATH_ENV = env::WIN32 ? PathEnv.WIN32 : PathEnv.POSIX; const char PREFERRED_SEPARATOR_WIN32 = '\\'; @@ -26,7 +27,7 @@ enum PathEnv POSIX } -fn Path! getcwd(Allocator* allocator = allocator::heap()) +fn Path! getcwd(Allocator allocator = allocator::heap()) { @pool(allocator) { @@ -40,7 +41,7 @@ fn usz! file_size(Path path) => os::native_file_size(path.str_view()); fn bool exists(Path path) => os::native_file_or_dir_exists(path.str_view()); fn Path! tgetcwd() => getcwd(allocator::temp()) @inline; fn void! chdir(Path path) => os::native_chdir(path) @inline; -fn Path! temp_directory(Allocator* allocator = allocator::heap()) => os::native_temp_directory(allocator); +fn Path! temp_directory(Allocator allocator = allocator::heap()) => os::native_temp_directory(allocator); fn void! delete(Path path) => os::native_remove(path.str_view()) @inline; macro bool is_separator(char c, PathEnv path_env = DEFAULT_PATH_ENV) @@ -58,7 +59,7 @@ macro bool is_win32_separator(char c) return c == '/' || c == '\\'; } -fn PathList! ls(Path dir, bool no_dirs = false, bool no_symlinks = false, String mask = "", Allocator* allocator = allocator::heap()) +fn PathList! ls(Path dir, bool no_dirs = false, bool no_symlinks = false, String mask = "", Allocator allocator = allocator::heap()) { $if $defined(os::native_ls): return os::native_ls(dir, no_dirs, no_symlinks, mask, allocator); @@ -105,7 +106,7 @@ fn void! rmtree(Path path) $endif } -fn Path! new(String path, Allocator* allocator = allocator::heap(), PathEnv path_env = DEFAULT_PATH_ENV) +fn Path! new(String path, Allocator allocator = allocator::heap(), PathEnv path_env = DEFAULT_PATH_ENV) { return { normalize(path.copy(allocator), path_env), path_env }; } @@ -115,7 +116,7 @@ fn Path! temp_new(String path, PathEnv path_env = DEFAULT_PATH_ENV) return new(path, allocator::temp(), path_env); } -fn Path! new_win32_wstring(WString path, Allocator* allocator = allocator::heap()) +fn Path! new_win32_wstring(WString path, Allocator allocator = allocator::heap()) { @pool(allocator) { @@ -123,12 +124,12 @@ fn Path! new_win32_wstring(WString path, Allocator* allocator = allocator::heap( }; } -fn Path! new_windows(String path, Allocator* allocator = allocator::heap()) +fn Path! new_windows(String path, Allocator allocator = allocator::heap()) { return new(path, allocator, WIN32); } -fn Path! new_posix(String path, Allocator* allocator = allocator::heap()) +fn Path! new_posix(String path, Allocator allocator = allocator::heap()) { return new(path, allocator, POSIX); } @@ -143,7 +144,7 @@ fn bool Path.equals(self, Path p2) * * @param [in] filename **/ -fn Path! Path.append(self, String filename, Allocator* allocator = allocator::heap()) +fn Path! Path.append(self, String filename, Allocator allocator = allocator::heap()) { if (!self.path_string.len) return new(filename, allocator, self.env)!; assert(!is_separator(self.path_string[^1], self.env)); @@ -166,7 +167,19 @@ fn usz Path.start_of_base_name(self) @local if (!path_str.len) return 0; if (self.env == PathEnv.WIN32) { - return path_str.rindex_of_char('\\') + 1 ?? volume_name_len(path_str, self.env)!!; + if (try index = path_str.rindex_of_char('\\')) + { + // c:\ style path, we're done! + if (path_str[0] != '\\') return index + 1; + // Handle \\server\foo + // Find the \ before "foo" + usz last_index = 2 + path_str[2..].index_of_char('\\')!!; + // If they don't match, we're done + assert(last_index <= index, "Invalid normalized, path %d vs %s in %s", last_index, index, path_str); + if (last_index != index) return index + 1; + // Otherwise just default to the volume length. + } + return volume_name_len(path_str, self.env)!!; } return path_str.rindex_of_char('/') + 1 ?? 0; } @@ -176,28 +189,39 @@ fn bool! Path.is_absolute(self) String path_str = self.str_view(); if (!path_str.len) return false; usz path_start = volume_name_len(path_str, self.env)!; + if (path_start > 0 && path_str[0] == '\\') return true; return path_start < path_str.len && is_separator(path_str[path_start], self.env); } -fn Path! Path.absolute(self, Allocator* allocator = allocator::heap()) +/** + * @require self.env == DEFAULT_PATH_ENV : "This method is only available on native paths" + **/ +fn Path! Path.absolute(self, Allocator allocator = allocator::heap()) { String path_str = self.str_view(); - if (!path_str.len) path_str = "."; + if (!path_str.len) return PathResult.INVALID_PATH?; + if (self.is_absolute()!) return new(path_str, allocator, self.env); if (path_str == ".") { - String cwd = os::getcwd(allocator::temp())!; - return new(cwd, allocator, self.env); - } - switch (self.env) - { - case WIN32: - usz path_start = volume_name_len(path_str, self.env)!; - if (path_start > 0) return self; - case POSIX: - if (path_str[0] == PREFERRED_SEPARATOR_POSIX) return self; + @pool(allocator) + { + String cwd = os::getcwd(allocator::temp())!; + return new(cwd, allocator, self.env); + }; } - String cwd = os::getcwd(allocator::temp())!; - return Path{ cwd, self.env }.append(path_str, allocator)!; + $if DEFAULT_PATH_ENV == WIN32: + @pool(allocator) + { + const usz BUFFER_LEN = 4096; + WString buffer = (WString)mem::temp_alloc_array(Char16, BUFFER_LEN); + buffer = win32::_wfullpath(buffer, path_str.to_temp_wstring()!, BUFFER_LEN); + if (!buffer) return PathResult.INVALID_PATH?; + return { string::new_from_wstring(buffer, allocator), WIN32 }; + }; + $else + String cwd = os::getcwd(allocator::temp())!; + return Path { cwd, self.env }.append(path_str, allocator)!; + $endif } fn String Path.basename(self) @@ -208,13 +232,21 @@ fn String Path.basename(self) return path_str[basename_start..]; } + fn String Path.dirname(self) { usz basename_start = self.start_of_base_name(); String path_str = self.path_string; - if (basename_start == 0) return ""; + if (basename_start == 0) return "."; usz start = volume_name_len(path_str, self.env)!!; - if (basename_start <= start + 1) return path_str[:basename_start]; + if (basename_start <= start + 1) + { + if (self.env == WIN32 && basename_start > start && path_str[0..1] == `\\`) + { + return path_str[:basename_start - 1]; + } + return path_str[:basename_start]; + } return path_str[:basename_start - 1]; } @@ -248,13 +280,20 @@ fn usz! volume_name_len(String path, PathEnv path_env) @local while (count < len && path[count] == '\\') count++; // Not 2 => folded paths if (count != 2) return 0; - // Check that we have a name followed by '/' + // Check that we have a name followed by '\' + isz base_found = 0; for (usz i = 2; i < len; i++) { char c = path[i]; - if (is_win32_separator(c)) return i; + if (is_win32_separator(c)) + { + if (base_found) return i; + base_found = i; + continue; + } if (is_reserved_win32_path_char(c)) return PathResult.INVALID_PATH?; } + if (base_found > 0 && base_found + 1 < len) return len; return PathResult.INVALID_PATH?; case 'A'..'Z': case 'a'..'z': @@ -281,6 +320,10 @@ fn String! normalize(String path_str, PathEnv path_env = DEFAULT_PATH_ENV) { if (!path_str.len) return ""; usz path_start = volume_name_len(path_str, path_env)!; + if (path_start > 0 && path_env == PathEnv.WIN32) + { + for (usz i = 0; i < path_start; i++) if (path_str[i] == '/') path_str[i] = '\\'; + } usz path_len = path_str.len; if (path_start == path_len) return path_str; char path_separator = path_env == PathEnv.WIN32 ? PREFERRED_SEPARATOR_WIN32 : PREFERRED_SEPARATOR_POSIX; @@ -384,7 +427,9 @@ fn String! normalize(String path_str, PathEnv path_env = DEFAULT_PATH_ENV) len++; } if (len > path_start + 1 && is_separator(path_str[len - 1], path_env)) len--; - path_str.ptr[len] = 0; + if (path_str.len > len) path_str.ptr[len] = 0; + // Empty path after normalization -> "." + if (!len) return "."; return path_str[:len]; } @@ -395,6 +440,7 @@ fn String Path.root_directory(self) String path_str = self.str_view(); usz len = path_str.len; if (!len) return ""; + if (path_str == ".") return "."; if (self.env == PathEnv.WIN32) { usz root_len = volume_name_len(path_str, self.env)!!; @@ -417,11 +463,12 @@ def PathWalker = fn bool! (Path, bool is_dir, void*); /* * Walk the path recursively. PathWalker is run on every file and * directory found. Return true to abort the walk. + * @require self.env == DEFAULT_PATH_ENV : "This method is only available on native paths" */ fn bool! Path.walk(self, PathWalker w, void* data) { const PATH_MAX = 512; - @stack_mem(PATH_MAX; Allocator* allocator) + @stack_mem(PATH_MAX; Allocator allocator) { Path abs = self.absolute(allocator)!; PathList files = ls(abs, .allocator = allocator)!; @@ -448,6 +495,11 @@ fn bool Path.has_suffix(self, String str) return self.str_view().ends_with(str); } +fn void Path.free_with_allocator(self, Allocator allocator) +{ + allocator::free(allocator, self.path_string.ptr); +} + fn void Path.free(self) { free(self.path_string.ptr); @@ -459,7 +511,7 @@ fn usz! Path.to_format(&self, Formatter* formatter) @dynamic return formatter.print(self.str_view()); } -fn String Path.to_new_string(&self, Allocator* allocator = allocator::heap()) @dynamic +fn String Path.to_new_string(&self, Allocator allocator = allocator::heap()) @dynamic { return self.str_view().copy(allocator); } diff --git a/lib/std/io/stream.c3 b/lib/std/io/stream.c3 index f32702fad..61ba728ae 100644 --- a/lib/std/io/stream.c3 +++ b/lib/std/io/stream.c3 @@ -9,7 +9,7 @@ interface InStream fn usz! available() @optional; fn usz! read(char[] buffer); fn char! read_byte(); - fn usz! write_to(OutStream* out) @optional; + fn usz! write_to(OutStream out) @optional; fn void! pushback_byte() @optional; } @@ -21,10 +21,10 @@ interface OutStream fn void! flush() @optional; fn usz! write(char[] bytes); fn void! write_byte(char c); - fn usz! read_to(InStream* in) @optional; + fn usz! read_to(InStream in) @optional; } -fn usz! available(InStream* s) +fn usz! available(InStream s) { if (&s.available) return s.available(); if (&s.seek) @@ -39,19 +39,19 @@ fn usz! available(InStream* s) macro bool @is_instream(#expr) { - return $assignable(#expr, InStream*); + return $assignable(#expr, InStream); } macro bool @is_outstream(#expr) { - return $assignable(#expr, OutStream*); + return $assignable(#expr, OutStream); } /** * @param [&out] ref * @require @is_instream(stream) **/ -macro usz! read_any(stream, any* ref) +macro usz! read_any(stream, any ref) { return read_all(stream, ((char*)ref)[:ref.type.sizeof]); } @@ -61,7 +61,7 @@ macro usz! read_any(stream, any* ref) * @require @is_outstream(stream) * @ensure return == ref.type.sizeof */ -macro usz! write_any(stream, any* ref) +macro usz! write_any(stream, any ref) { return write_all(stream, ((char*)ref)[:ref.type.sizeof]); } @@ -134,7 +134,7 @@ macro void! @pushback_using_seek(&s) s.seek(-1, CURSOR)!; } -fn usz! copy_to(InStream* in, OutStream* dst, char[] buffer = {}) +fn usz! copy_to(InStream in, OutStream dst, char[] buffer = {}) { if (buffer.len) return copy_through_buffer(in, dst, buffer); if (&in.write_to) return in.write_to(dst); @@ -156,7 +156,7 @@ fn usz! copy_to(InStream* in, OutStream* dst, char[] buffer = {}) $endswitch } -macro usz! copy_through_buffer(InStream *in, OutStream* dst, char[] buffer) @local +macro usz! copy_through_buffer(InStream in, OutStream dst, char[] buffer) @local { usz total_copied; while (true) diff --git a/lib/std/io/stream/buffer.c3 b/lib/std/io/stream/buffer.c3 index 2f26d2984..301167f45 100644 --- a/lib/std/io/stream/buffer.c3 +++ b/lib/std/io/stream/buffer.c3 @@ -2,7 +2,7 @@ module std::io; struct ReadBuffer (InStream) { - InStream* wrapped_stream; + InStream wrapped_stream; char[] bytes; usz read_idx; usz write_idx; @@ -14,7 +14,7 @@ struct ReadBuffer (InStream) * @require bytes.len > 0 * @require self.bytes.len == 0 "Init may not run on already initialized data" **/ -fn ReadBuffer* ReadBuffer.init(&self, InStream* wrapped_stream, char[] bytes) +fn ReadBuffer* ReadBuffer.init(&self, InStream wrapped_stream, char[] bytes) { *self = { .wrapped_stream = wrapped_stream, .bytes = bytes }; return self; @@ -63,7 +63,7 @@ fn void! ReadBuffer.refill(&self) @local @inline struct WriteBuffer (OutStream) { - OutStream* wrapped_stream; + OutStream wrapped_stream; char[] bytes; usz index; } @@ -74,7 +74,7 @@ struct WriteBuffer (OutStream) * @require bytes.len > 0 "Non-empty buffer required" * @require self.bytes.len == 0 "Init may not run on already initialized data" **/ -fn WriteBuffer* WriteBuffer.init(&self, OutStream* wrapped_stream, char[] bytes) +fn WriteBuffer* WriteBuffer.init(&self, OutStream wrapped_stream, char[] bytes) { *self = { .wrapped_stream = wrapped_stream, .bytes = bytes }; return self; diff --git a/lib/std/io/stream/bytebuffer.c3 b/lib/std/io/stream/bytebuffer.c3 index 1e2f08c8b..8864b3630 100644 --- a/lib/std/io/stream/bytebuffer.c3 +++ b/lib/std/io/stream/bytebuffer.c3 @@ -3,7 +3,7 @@ import std::math; struct ByteBuffer (InStream, OutStream) { - Allocator* allocator; + Allocator allocator; usz max_read; char[] bytes; usz read_idx; @@ -16,17 +16,7 @@ struct ByteBuffer (InStream, OutStream) * max_read defines how many bytes might be kept before its internal buffer is shrinked. * @require self.bytes.len == 0 "Buffer already initialized." **/ -fn ByteBuffer*! ByteBuffer.init_new(&self, usz max_read, usz initial_capacity = 16, Allocator* allocator = allocator::heap()) @deprecated("Replaced by new_init") -{ - return self.new_init(max_read, initial_capacity, allocator) @inline; -} - -/** - * ByteBuffer provides a streamable read/write buffer. - * max_read defines how many bytes might be kept before its internal buffer is shrinked. - * @require self.bytes.len == 0 "Buffer already initialized." - **/ -fn ByteBuffer*! ByteBuffer.new_init(&self, usz max_read, usz initial_capacity = 16, Allocator* allocator = allocator::heap()) +fn ByteBuffer*! ByteBuffer.new_init(&self, usz max_read, usz initial_capacity = 16, Allocator allocator = allocator::heap()) { *self = { .allocator = allocator, .max_read = max_read }; initial_capacity = max(initial_capacity, 16); @@ -34,11 +24,6 @@ fn ByteBuffer*! ByteBuffer.new_init(&self, usz max_read, usz initial_capacity = return self; } -fn ByteBuffer*! ByteBuffer.init_temp(&self, usz max_read, usz initial_capacity = 16) @deprecated("Replaced by temp_init") -{ - return self.temp_init(max_read, initial_capacity) @inline; -} - fn ByteBuffer*! ByteBuffer.temp_init(&self, usz max_read, usz initial_capacity = 16) { return self.new_init(max_read, initial_capacity, allocator::temp()); diff --git a/lib/std/io/stream/bytereader.c3 b/lib/std/io/stream/bytereader.c3 index 05c93a7b3..ea2ae3c79 100644 --- a/lib/std/io/stream/bytereader.c3 +++ b/lib/std/io/stream/bytereader.c3 @@ -53,7 +53,7 @@ fn usz! ByteReader.seek(&self, isz offset, Seek seek) @dynamic return new_index; } -fn usz! ByteReader.write_to(&self, OutStream* writer) @dynamic +fn usz! ByteReader.write_to(&self, OutStream writer) @dynamic { if (self.index >= self.bytes.len) return 0; usz written = writer.write(self.bytes[self.index..])!; diff --git a/lib/std/io/stream/bytewriter.c3 b/lib/std/io/stream/bytewriter.c3 index 8c0c52993..1caeb9b00 100644 --- a/lib/std/io/stream/bytewriter.c3 +++ b/lib/std/io/stream/bytewriter.c3 @@ -5,7 +5,7 @@ struct ByteWriter (OutStream) { char[] bytes; usz index; - Allocator* allocator; + Allocator allocator; } /** @@ -14,23 +14,12 @@ struct ByteWriter (OutStream) * @require self.bytes.len == 0 "Init may not run on on already initialized data" * @ensure (bool)allocator, self.index == 0 **/ -fn ByteWriter* ByteWriter.new_init(&self, Allocator* allocator = allocator::heap()) +fn ByteWriter* ByteWriter.new_init(&self, Allocator allocator = allocator::heap()) { *self = { .bytes = {}, .allocator = allocator }; return self; } -/** - * @param [&inout] self - * @param [&inout] allocator - * @require self.bytes.len == 0 "Init may not run on on already initialized data" - * @ensure (bool)allocator, self.index == 0 - **/ -fn ByteWriter* ByteWriter.init_new(&self, Allocator* allocator = allocator::heap()) @deprecated("Replaced by new_init") -{ - return self.new_init(allocator) @inline; -} - /** * @param [&inout] self * @require self.bytes.len == 0 "Init may not run on on already initialized data" @@ -41,16 +30,6 @@ fn ByteWriter* ByteWriter.temp_init(&self) return self.new_init(allocator::temp()) @inline; } -/** - * @param [&inout] self - * @require self.bytes.len == 0 "Init may not run on on already initialized data" - * @ensure self.index == 0 - **/ -fn ByteWriter* ByteWriter.init_temp(&self) @deprecated("Replaced by temp_init") -{ - return self.temp_init() @inline; -} - fn ByteWriter* ByteWriter.init_with_buffer(&self, char[] data) { *self = { .bytes = data, .allocator = null }; @@ -97,7 +76,7 @@ fn void! ByteWriter.write_byte(&self, char c) @dynamic * @param [&inout] self * @param reader **/ -fn usz! ByteWriter.read_from(&self, InStream* reader) @dynamic +fn usz! ByteWriter.read_from(&self, InStream reader) @dynamic { usz start_index = self.index; if (&reader.available) diff --git a/lib/std/io/stream/limitreader.c3 b/lib/std/io/stream/limitreader.c3 index c248a2f2d..06ee68768 100644 --- a/lib/std/io/stream/limitreader.c3 +++ b/lib/std/io/stream/limitreader.c3 @@ -2,7 +2,7 @@ module std::io; struct LimitReader (InStream) { - InStream* wrapped_stream; + InStream wrapped_stream; usz limit; } @@ -10,7 +10,7 @@ struct LimitReader (InStream) * @param [&inout] wrapped_stream "The stream to read from" * @param limit "The max limit to read" **/ -fn LimitReader* LimitReader.init(&self, InStream* wrapped_stream, usz limit) +fn LimitReader* LimitReader.init(&self, InStream wrapped_stream, usz limit) { *self = { .wrapped_stream = wrapped_stream, .limit = limit }; return self; diff --git a/lib/std/io/stream/scanner.c3 b/lib/std/io/stream/scanner.c3 index 4965091b0..51c168003 100644 --- a/lib/std/io/stream/scanner.c3 +++ b/lib/std/io/stream/scanner.c3 @@ -2,7 +2,7 @@ module std::io; struct Scanner (InStream) { - InStream* wrapped_stream; + InStream wrapped_stream; char[] buf; usz pattern_idx; usz read_idx; @@ -16,7 +16,7 @@ struct Scanner (InStream) * @param [&in] stream "The stream to read data from." * @require buffer.len > 0 "Non-empty buffer required." **/ -fn void Scanner.init(&self, InStream* stream, char[] buffer) +fn void Scanner.init(&self, InStream stream, char[] buffer) { *self = { .wrapped_stream = stream, .buf = buffer }; } diff --git a/lib/std/math/math.c3 b/lib/std/math/math.c3 index fdd314a78..0c205dd0d 100644 --- a/lib/std/math/math.c3 +++ b/lib/std/math/math.c3 @@ -92,15 +92,13 @@ fault MatrixError def Complexf = Complex(); def Complex = Complex(); -def complexf_identity = complex::identity(); -def complex_identity = complex::identity(); +def COMPLEX_IDENTITY = complex::IDENTITY(); +def COMPLEXF_IDENTITY = complex::IDENTITY(); def Quaternionf = Quaternion(); def Quaternion = Quaternion(); def QUATERNION_IDENTITY = quaternion::IDENTITY(); def QUATERNIONF_IDENTITY = quaternion::IDENTITY(); -def quaternion_identity = quaternion::identity(); -def quaternionf_identity = quaternion::identity(); def Matrix2f = Matrix2x2(); def Matrix2 = Matrix2x2(); diff --git a/lib/std/math/math_complex.c3 b/lib/std/math/math_complex.c3 index 28871d755..c323fc60c 100644 --- a/lib/std/math/math_complex.c3 +++ b/lib/std/math/math_complex.c3 @@ -10,7 +10,7 @@ union Complex } -macro Complex identity() => { 1, 0 }; +const Complex IDENTITY = { 1, 0 }; macro Complex Complex.add(self, Complex b) => Complex { .v = self.v + b.v }; macro Complex Complex.add_each(self, Real b) => Complex { .v = self.v + b }; macro Complex Complex.sub(self, Complex b) => Complex { .v = self.v - b.v }; diff --git a/lib/std/math/math_quaternion.c3 b/lib/std/math/math_quaternion.c3 index 938df7cef..efbd0bf13 100644 --- a/lib/std/math/math_quaternion.c3 +++ b/lib/std/math/math_quaternion.c3 @@ -11,7 +11,6 @@ union Quaternion const Quaternion IDENTITY = { 0, 0, 0, 1 }; -macro Quaternion identity() @deprecated("Replaced with QUATERNION_IDENTITY constant") => { 0, 0, 0, 1 }; macro Quaternion Quaternion.add(Quaternion a, Quaternion b) => Quaternion { .v = a.v + b.v }; macro Quaternion Quaternion.add_each(Quaternion a, Real b) => Quaternion { .v = a.v + b }; macro Quaternion Quaternion.sub(Quaternion a, Quaternion b) => Quaternion { .v = a.v - b.v }; diff --git a/lib/std/net/inetaddr.c3 b/lib/std/net/inetaddr.c3 index ee783e30e..dc9318bff 100644 --- a/lib/std/net/inetaddr.c3 +++ b/lib/std/net/inetaddr.c3 @@ -4,9 +4,9 @@ import std::ascii; enum IpProtocol : char (AIFamily ai_family) { - UNSPECIFIED (os::AF_UNSPEC), - IPV4 (os::AF_INET), - IPV6 (os::AF_INET6), + UNSPECIFIED = os::AF_UNSPEC, + IPV4 = os::AF_INET, + IPV6 = os::AF_INET6, } struct InetAddress (Printable) @@ -56,7 +56,7 @@ fn usz! InetAddress.to_format(InetAddress* addr, Formatter* formatter) @dynamic return formatter.printf("%d.%d.%d.%d", addr.ipv4.a, addr.ipv4.b, addr.ipv4.c, addr.ipv4.d)!; } -fn String InetAddress.to_new_string(InetAddress* addr, Allocator* allocator = allocator::heap()) @dynamic +fn String InetAddress.to_new_string(InetAddress* addr, Allocator allocator = allocator::heap()) @dynamic { if (addr.is_ipv6) { diff --git a/lib/std/net/net.c3 b/lib/std/net/net.c3 index c2cab40c8..bc77247de 100644 --- a/lib/std/net/net.c3 +++ b/lib/std/net/net.c3 @@ -57,7 +57,7 @@ fn uint! ipv4toint(String s) return out; } -fn String! int_to_new_ipv4(uint val, Allocator* allocator = allocator::heap()) +fn String! int_to_new_ipv4(uint val, Allocator allocator = allocator::heap()) { char[3 * 4 + 3 + 1] buffer; String res = (String)io::bprintf(&buffer, "%d.%d.%d.%d", val >> 24, (val >> 16) & 0xFF, (val >> 8) & 0xFF, val & 0xFF)!; diff --git a/lib/std/net/socket.c3 b/lib/std/net/socket.c3 index 26e3deb4a..bec049ded 100644 --- a/lib/std/net/socket.c3 +++ b/lib/std/net/socket.c3 @@ -83,12 +83,12 @@ macro Socket new_socket(fd, ai) enum SocketOption : char (CInt value) { - REUSEADDR (os::SO_REUSEADDR), - REUSEPORT (os::SO_REUSEPORT) @if(!env::WIN32), - KEEPALIVE (os::SO_KEEPALIVE), - BROADCAST (os::SO_BROADCAST), - OOBINLINE (os::SO_OOBINLINE), - DONTROUTE (os::SO_DONTROUTE), + REUSEADDR = os::SO_REUSEADDR, + REUSEPORT @if(!env::WIN32) = os::SO_REUSEPORT, + KEEPALIVE = os::SO_KEEPALIVE, + BROADCAST = os::SO_BROADCAST, + OOBINLINE = os::SO_OOBINLINE, + DONTROUTE = os::SO_DONTROUTE, } fn bool! Socket.get_broadcast(&self) => self.get_option(BROADCAST); diff --git a/lib/std/os/backtrace.c3 b/lib/std/os/backtrace.c3 index df29db488..c0902be81 100644 --- a/lib/std/os/backtrace.c3 +++ b/lib/std/os/backtrace.c3 @@ -19,7 +19,7 @@ struct Backtrace (Printable) String object_file; String file; uint line; - Allocator* allocator; + Allocator allocator; } @@ -53,7 +53,7 @@ fn void Backtrace.free(&self) allocator::free(self.allocator, self.file); } -fn Backtrace* Backtrace.init(&self, uptr offset, String function, String object_file, String file = "", uint line = 0, Allocator* allocator) +fn Backtrace* Backtrace.init(&self, uptr offset, String function, String object_file, String file = "", uint line = 0, Allocator allocator) { if (!allocator) { @@ -95,7 +95,7 @@ def symbolize_backtrace = linux::symbolize_backtrace @if(env::LINUX); def symbolize_backtrace = win32::symbolize_backtrace @if(env::WIN32); def symbolize_backtrace = darwin::symbolize_backtrace @if(env::DARWIN); -fn BacktraceList! symbolize_backtrace(void*[] backtrace, Allocator* allocator) @if(!env::NATIVE_STACKTRACE) +fn BacktraceList! symbolize_backtrace(void*[] backtrace, Allocator allocator) @if(!env::NATIVE_STACKTRACE) { return {}; } \ No newline at end of file diff --git a/lib/std/os/env.c3 b/lib/std/os/env.c3 index 126302d0f..06a9be55e 100644 --- a/lib/std/os/env.c3 +++ b/lib/std/os/env.c3 @@ -9,7 +9,7 @@ import std::io::path, libc, std::os; * @require name.len > 0 * @return! SearchResult.MISSING **/ -fn String! get_var(String name, Allocator* allocator = allocator::heap()) +fn String! get_var(String name, Allocator allocator = allocator::heap()) { @pool(allocator) { @@ -72,7 +72,7 @@ fn bool set_var(String name, String value, bool overwrite = true) /** * Returns the current user's home directory. **/ -fn String! get_home_dir(Allocator* using = allocator::heap()) +fn String! get_home_dir(Allocator using = allocator::heap()) { String home; $if !env::WIN32: @@ -86,7 +86,7 @@ fn String! get_home_dir(Allocator* using = allocator::heap()) /** * Returns the current user's config directory. **/ -fn Path! get_config_dir(Allocator* allocator = allocator::heap()) +fn Path! get_config_dir(Allocator allocator = allocator::heap()) { @pool(allocator) { @@ -126,7 +126,7 @@ fn bool clear_var(String name) }; } -fn String! executable_path(Allocator *allocator = allocator::heap()) +fn String! executable_path(Allocator allocator = allocator::heap()) { $if env::DARWIN: return darwin::executable_path(allocator); diff --git a/lib/std/os/linux/linux.c3 b/lib/std/os/linux/linux.c3 index 894299a44..b1f47045c 100644 --- a/lib/std/os/linux/linux.c3 +++ b/lib/std/os/linux/linux.c3 @@ -128,7 +128,7 @@ fn ulong! elf_module_image_base(String path) @local return 0; } -fn Backtrace! backtrace_load_from_exec(void* addr, Allocator* allocator) @local +fn Backtrace! backtrace_load_from_exec(void* addr, Allocator allocator) @local { char[] buf = mem::temp_alloc_array(char, 1024); @@ -138,7 +138,7 @@ fn Backtrace! backtrace_load_from_exec(void* addr, Allocator* allocator) @local return backtrace_from_addr2line(addr, addr2line, obj_name, "???", allocator); } -fn Backtrace! backtrace_load_from_dlinfo(void* addr, Linux_Dl_info* info, Allocator* allocator) @local +fn Backtrace! backtrace_load_from_dlinfo(void* addr, Linux_Dl_info* info, Allocator allocator) @local { char[] buf = mem::temp_alloc_array(char, 1024); @@ -149,7 +149,7 @@ fn Backtrace! backtrace_load_from_dlinfo(void* addr, Linux_Dl_info* info, Alloca return backtrace_from_addr2line(addr, addr2line, info.dli_fname.str_view(), sname, allocator); } -fn Backtrace! backtrace_from_addr2line(void* addr, String addr2line, String obj_name, String func_name, Allocator* allocator) @local +fn Backtrace! backtrace_from_addr2line(void* addr, String addr2line, String obj_name, String func_name, Allocator allocator) @local { String[] parts = addr2line.tsplit(" at "); if (parts.len != 2) @@ -182,7 +182,7 @@ fn Backtrace! backtrace_from_addr2line(void* addr, String addr2line, String obj_ }; } -fn Backtrace! backtrace_load_element(void* addr, Allocator* allocator = allocator::heap()) @local +fn Backtrace! backtrace_load_element(void* addr, Allocator allocator = allocator::heap()) @local { if (!addr) return backtrace::BACKTRACE_UNKNOWN; @@ -197,7 +197,7 @@ fn Backtrace! backtrace_load_element(void* addr, Allocator* allocator = allocato }; } -fn BacktraceList! symbolize_backtrace(void*[] backtrace, Allocator* allocator) +fn BacktraceList! symbolize_backtrace(void*[] backtrace, Allocator allocator) { BacktraceList list; list.new_init(backtrace.len, allocator); @@ -214,7 +214,7 @@ fn BacktraceList! symbolize_backtrace(void*[] backtrace, Allocator* allocator) foreach (addr : backtrace) { Backtrace trace = backtrace_load_element(addr, allocator)!; - list.append(trace); + list.push(trace); } }; return list; diff --git a/lib/std/os/macos/darwin.c3 b/lib/std/os/macos/darwin.c3 index 0a2d84083..4e46836be 100644 --- a/lib/std/os/macos/darwin.c3 +++ b/lib/std/os/macos/darwin.c3 @@ -68,7 +68,7 @@ struct Darwin_segment_command_64 } -fn String! executable_path(Allocator *allocator) +fn String! executable_path(Allocator allocator) { char[4096] path; uint len = path.len; @@ -93,7 +93,7 @@ fn uptr! load_address() @local } -fn Backtrace! backtrace_load_element(String execpath, void* buffer, void* load_address, Allocator* allocator = allocator::heap()) @local +fn Backtrace! backtrace_load_element(String execpath, void* buffer, void* load_address, Allocator allocator = allocator::heap()) @local { @pool(allocator) { @@ -132,7 +132,7 @@ fn Backtrace! backtrace_load_element(String execpath, void* buffer, void* load_a }; } -fn BacktraceList! symbolize_backtrace(void*[] backtrace, Allocator* allocator) +fn BacktraceList! symbolize_backtrace(void*[] backtrace, Allocator allocator) { void *load_addr = (void *)load_address()!; BacktraceList list; @@ -150,7 +150,7 @@ fn BacktraceList! symbolize_backtrace(void*[] backtrace, Allocator* allocator) String execpath = executable_path(allocator::temp())!; foreach (addr : backtrace) { - list.append(backtrace_load_element(execpath, addr, load_addr, allocator) ?? backtrace::BACKTRACE_UNKNOWN); + list.push(backtrace_load_element(execpath, addr, load_addr, allocator) ?? backtrace::BACKTRACE_UNKNOWN); } }; return list; diff --git a/lib/std/os/macos/objc.c3 b/lib/std/os/macos/objc.c3 index 75d1c338e..ac9dfed93 100644 --- a/lib/std/os/macos/objc.c3 +++ b/lib/std/os/macos/objc.c3 @@ -24,7 +24,7 @@ macro Class! class_by_name(ZString c) return cls ?: ObjcFailure.CLASS_NOT_FOUND?; } -macro Class[] class_get_list(Allocator *allocator = allocator::heap()) +macro Class[] class_get_list(Allocator allocator = allocator::heap()) { int num_classes = macos_objc_getClassList(null, 0); if (!num_classes) return {}; diff --git a/lib/std/os/win32/files.c3 b/lib/std/os/win32/files.c3 index c51c4ec0a..75d2dfdf5 100644 --- a/lib/std/os/win32/files.c3 +++ b/lib/std/os/win32/files.c3 @@ -99,6 +99,8 @@ extern fn CFile _fdopen(int fd, ZString mode); extern fn CInt _access(ZString path, CInt mode); extern fn CInt _waccess(WString path, CInt mode); +extern fn WString _wfullpath(WString absPath, WString relPath, usz maxLength); + /* extern ulong _win32_GetCurrentDirectoryW(ulong, Char16* buffer) @extern("GetCurrentDirectoryW"); extern bool _win32_CreateSymbolicLinkW(WString symlink_file, WString target_file, ulong flags) @extern("CreateSymbolicLinkW"); diff --git a/lib/std/os/win32/process.c3 b/lib/std/os/win32/process.c3 index 9788aea29..f03d34f13 100644 --- a/lib/std/os/win32/process.c3 +++ b/lib/std/os/win32/process.c3 @@ -152,7 +152,7 @@ struct Symbol Win32_DWORD64 displacement; -fn BacktraceList! symbolize_backtrace(void*[] backtrace, Allocator* allocator) +fn BacktraceList! symbolize_backtrace(void*[] backtrace, Allocator allocator) { BacktraceList list; list.new_init(backtrace.len, allocator); @@ -161,12 +161,12 @@ fn BacktraceList! symbolize_backtrace(void*[] backtrace, Allocator* allocator) defer symCleanup(process); foreach (addr : backtrace) { - list.append(resolve_backtrace(addr, process, allocator) ?? backtrace::BACKTRACE_UNKNOWN); + list.push(resolve_backtrace(addr, process, allocator) ?? backtrace::BACKTRACE_UNKNOWN); } return list; } -fn Backtrace! resolve_backtrace(void* addr, Win32_HANDLE process, Allocator* allocator) +fn Backtrace! resolve_backtrace(void* addr, Win32_HANDLE process, Allocator allocator) { Symbol symbol; //Win32_DWORD image_type = load_modules()!; diff --git a/releasenotes.md b/releasenotes.md index a07bc66f1..41e6dc0ef 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -1,5 +1,47 @@ # C3C Release Notes +## 0.6.0 Change list + +### Changes / improvements +- `@default` implementations for interfaces removed. +- `any*` => `any`, same for interfaces. +- Private / local globals now have `internal` visibility in LLVM. +- Updated enum syntax. +- 'rgba' also available for swizzling. +- The name "subarray" has been replaced by the more well known name "slice' across the codebase. +- Improved alignment handling. +- Add `--output-dir` to command line. #1155 +- Allow making distinct types out of "void", "typeid", "anyfault" and faults. +- Removed `--system-linker` setting. +- "Try" expressions may not be any binary or unary expressions. So for example `try foo() + 1` is disallowed. +- Added `$$REGISTER_SIZE` for int register size. +- `assert(false)` only allowed in unused branches or in tests. Compile time failed asserts is a compile time error. +- Require expression blocks returning values to have the value used. +- Detect "unsigned >= 0" as errors. +- Improve callstack debug information #1184. +- Request jump table using @jump for switches. +- Improved inline debug information. +- Improved error messages on inlined macros. +- Introduce MSVC compatible SIMD ABI. + +### Fixes +- Fixed issue in safe mode when converting enums. +- Better checking of operator methods. +- Bug when assigning an optional from an optional. +- Lambdas were not type checked thoroughly #1185. + +### Stdlib changes +- "init_new/init_temp" removed. +- LinkedList API rewritten. +- List "pop" and "remove" function now return Optionals. +- RingBuffer API rewritten. Allocator interface changed. +- Deprecated Allocator, DString and mem functions removed. +- "identity" functions are now constants for Matrix and Complex numbers. +- Removed 'append' from Object and List, replaced by 'push'. +- `GenericList` renamed `AnyList`. +- Proper handling of '.' and Win32 '//server' paths. +- Path normalization - fix possible null terminator out of bounds. + ## 0.5.6 Change list ### Changes / improvements @@ -388,13 +430,13 @@ - Fixed errors on flexible array slices. - Fix of `readdir` issues on macOS. - Fix to slice assignment of distinct types. -- Fix of issue casting subarrays to distinct types. +- Fix of issue casting slices to distinct types. - Fixes to `split`, `rindex_of`. - List no longer uses the temp allocator by default. - Remove test global when not in test mode. - Fix sum/product on floats. - Fix error on void! return of macros. -- Removed too permissive casts on subarrays. +- Removed too permissive casts on slices. - Using C files correctly places objects in the build folder. - Fix of overaligned deref. - Fix negating a float vector. @@ -497,7 +539,7 @@ - Added type.inner and type.len reflection. - Support float mod operations. - Add float.max/min. -- Allow [in] contract to be used on subarray types. +- Allow [in] contract to be used on slices. - Add linker and linked dir arguments to build files. - Auto-import std::core. - LLVM 15 support. diff --git a/resources/castrules.md b/resources/castrules.md index 8dab9184c..eca24eb92 100644 --- a/resources/castrules.md +++ b/resources/castrules.md @@ -18,7 +18,7 @@ Some short names: | int | cond | sw/sn | always | explptr | no | expand | explbase | edist | no | no | no | no | no | edist | no | | float | cond | expl | sw/sn | no | no | expand | no | edist | no | no | no | no | no | no | no | | pointer | cond | explptr | no | ptrconv | arve | expand | no | edist | no | no | no | yes | expl | no | expl | -| subarray | cond | no | no | no | saconv | no | no | edist | no? | no | no | no | no | no | no | +| slice | cond | no | no | no | saconv | no | no | edist | no? | no | no | no | no | no | no | | vec | cond | no | no | no | no | as base | no | edist | expl | no | no | no | no | no | no | | bits | no | explbase | no | no | no | no | no? | edist | explbase | no | no | no | no | no | no | | distc | edist | edist | edist | edist | edist | edist | edist | edist | edist | edist | edist | edist | edist | edist | edist | diff --git a/resources/examples/brainfk.c3 b/resources/examples/brainfk.c3 index c85be28f6..a948dd74e 100644 --- a/resources/examples/brainfk.c3 +++ b/resources/examples/brainfk.c3 @@ -9,7 +9,7 @@ fault InterpretError INTEPRET_FAILED } -fn void! print_error(usz pos, String err) +fn void! print_error_type_at(usz pos, String err) { io::printfn("Error at %s: %s", pos, err); return InterpretError.INTEPRET_FAILED?; @@ -25,10 +25,10 @@ fn void! brainf(String program) switch (c) { case '<': - if (!mem) return print_error(sp, "Memory underflow"); + if (!mem) return print_error_type_at(sp, "Memory underflow"); mem--; case '>': - if (mem == BF_MEM - 1) return print_error(sp, "Memory overflow"); + if (mem == BF_MEM - 1) return print_error_type_at(sp, "Memory overflow"); mem++; case '+': memory[mem]++; @@ -45,7 +45,7 @@ fn void! brainf(String program) usz start = sp - 1; while (indent) { - if (sp == program.len) return print_error(start, "No matching ']'"); + if (sp == program.len) return print_error_type_at(start, "No matching ']'"); switch (program[sp++]) { case ']': indent--; @@ -59,7 +59,7 @@ fn void! brainf(String program) usz indent = 1; while (indent) { - if (!sp) return print_error(start, "No matching '['"); + if (!sp) return print_error_type_at(start, "No matching '['"); switch (program[--sp]) { case ']': indent++; diff --git a/resources/examples/contextfree/boolerr.c3 b/resources/examples/contextfree/boolerr.c3 index 89015acb4..a581e697b 100644 --- a/resources/examples/contextfree/boolerr.c3 +++ b/resources/examples/contextfree/boolerr.c3 @@ -27,7 +27,7 @@ struct Summary bool ok; } -fn void! Summary.print(Summary *s, OutStream* out) +fn void! Summary.print(Summary *s, OutStream out) { io::fprintf(out, "Summary({ .title = %s, .ok = %s})", s.title.get() ?? "missing", s.ok)!; } @@ -76,7 +76,7 @@ fn void main() const String[] URLS = { "good", "title-empty", "title-missing", "head-missing", "fail" }; DynamicArenaAllocator dynamic_arena; dynamic_arena.init(1024, allocator::heap()); - OutStream* out = io::stdout(); + OutStream out = io::stdout(); foreach (String url : URLS) { mem::@scoped(&dynamic_arena) diff --git a/resources/examples/levenshtein.c3 b/resources/examples/levenshtein.c3 index 7ee37e900..1804a195a 100644 --- a/resources/examples/levenshtein.c3 +++ b/resources/examples/levenshtein.c3 @@ -1,7 +1,7 @@ module levenshtein; import std::math; -// This levenshtein exercises C3 subarrays. +// This levenshtein exercises C3 slices. fn int levenshtein(String s, String t) { // if either string is empty, difference is inserting all chars diff --git a/resources/examples/nolibc/project.json b/resources/examples/nolibc/project.json index 117a59507..aeaf3d0ef 100644 --- a/resources/examples/nolibc/project.json +++ b/resources/examples/nolibc/project.json @@ -29,7 +29,7 @@ "link-libc": false, "opt": "O0", "safe": false, - "system-linker": true, + "linker": "builtin", "use-stdlib": false, }, }, @@ -68,8 +68,8 @@ // The size of the symtab, which limits the amount // of symbols that can be used. Should usually not be changed. "symtab": 1048576, - // Use the system linker. - "system-linker": false, + // Select linker. + "linker": "cc", // Include the standard library. "use-stdlib": true, // Set general level of x64 cpu: "baseline", "ssse3", "sse4", "avx1", "avx2-v1", "avx2-v2", "avx512", "native". diff --git a/resources/examples/process.c3 b/resources/examples/process.c3 index 3306c3773..e633ebb1f 100644 --- a/resources/examples/process.c3 +++ b/resources/examples/process.c3 @@ -7,7 +7,7 @@ fn void! main() String command = env::WIN32 ? "dir" : "ls"; SubProcess x = process::create({ command }, { .search_user_path = true })!!; x.join()!; - InStream* stream = &&x.stdout(); + InStream stream = &&x.stdout(); while (try char b = stream.read_byte()) { io::printf("%c", b); diff --git a/resources/examples/project_all_settings.json b/resources/examples/project_all_settings.json index 261e954a3..94a84319b 100644 --- a/resources/examples/project_all_settings.json +++ b/resources/examples/project_all_settings.json @@ -66,7 +66,7 @@ // of symbols that can be used. Should usually not be changed. "symtab": 1048576, // Use the system linker. - "system-linker": false, + "linker": "cc", // Include the standard library. "use-stdlib": true, // Set general level of x64 cpu: "baseline", "ssse3", "sse4", "avx1", "avx2-v1", "avx2-v2", "avx512", "native". diff --git a/resources/grammar/grammar.y b/resources/grammar/grammar.y index 619792850..0fe096d54 100644 --- a/resources/grammar/grammar.y +++ b/resources/grammar/grammar.y @@ -320,7 +320,12 @@ relational_stmt_expr | relational_stmt_expr relational_op additive_expr ; -rel_or_lambda_expr +try_catch_rhs_expr + : call_expr + | lambda_decl IMPLIES relational_expr + ; + +try_chain_expr : relational_expr | lambda_decl IMPLIES relational_expr ; @@ -484,7 +489,7 @@ enum_list enum_constant : CONST_IDENT opt_attributes - | CONST_IDENT '(' arg_list ')' opt_attributes + | CONST_IDENT opt_attributes '=' constant_expr ; identifier_list @@ -493,9 +498,7 @@ identifier_list ; enum_param_decl - : type - | type IDENT - | type IDENT '=' expr + : type IDENT ; base_type @@ -638,15 +641,15 @@ catch_unwrap ; try_unwrap - : TRY rel_or_lambda_expr - | TRY IDENT '=' rel_or_lambda_expr - | TRY type IDENT '=' rel_or_lambda_expr + : TRY try_catch_rhs_expr + | TRY IDENT '=' try_chain_expr + | TRY type IDENT '=' try_chain_expr ; try_unwrap_chain : try_unwrap | try_unwrap_chain AND_OP try_unwrap - | try_unwrap_chain AND_OP rel_or_lambda_expr + | try_unwrap_chain AND_OP try_chain_expr ; default_stmt @@ -1017,12 +1020,6 @@ enum_params | enum_params ',' enum_param_decl ; -enum_param_list - : '(' enum_params ')' - | '(' ')' - | empty - ; - struct_member_decl : type identifier_list opt_attributes ';' | struct_or_union IDENT opt_attributes struct_body @@ -1034,12 +1031,14 @@ struct_member_decl ; enum_spec - : ':' type enum_param_list - | empty + : ':' base_type '(' enum_params ')' + | ':' base_type + | ':' '(' enum_params ')' ; enum_declaration : ENUM TYPE_IDENT opt_interface_impl enum_spec opt_attributes '{' enum_list '}' + | ENUM TYPE_IDENT opt_interface_impl opt_attributes '{' enum_list '}' ; faults diff --git a/resources/testfragments/allocators_testing.c3 b/resources/testfragments/allocators_testing.c3 index 80fba3239..7f55e708f 100644 --- a/resources/testfragments/allocators_testing.c3 +++ b/resources/testfragments/allocators_testing.c3 @@ -21,7 +21,7 @@ fn void setstring(char* dst, String str) dst[0] = 0; } -fn void testAllocator(Allocator* a, int val) +fn void testAllocator(Allocator a, int val) { io::printn("Test"); void* data = allocator::malloc_aligned(a, val, 128, 16)!!; diff --git a/resources/testfragments/demo1.c3 b/resources/testfragments/demo1.c3 index 6fef9e5d5..74e2d2ee2 100644 --- a/resources/testfragments/demo1.c3 +++ b/resources/testfragments/demo1.c3 @@ -111,7 +111,7 @@ fn void testArrays() printArray(&x); printArray(y); printArray(x[1..]); - puts("Array to pointer to subarray---"); + puts("Array to pointer to slice---"); int* z = &x; printArray(z[0..2]); printf("Pointer to array: %p\nPointer to slice: %p\nPointer to first element of slice: %p\n", z, &y, &y[0]); diff --git a/src/build/build.h b/src/build/build.h index 323a3b1db..89501775f 100644 --- a/src/build/build.h +++ b/src/build/build.h @@ -137,12 +137,6 @@ typedef enum SINGLE_MODULE_ON = 1 } SingleModule; -typedef enum -{ - SYSTEM_LINKER_NOT_SET = -1, - SYSTEM_LINKER_OFF = 0, - SYSTEM_LINKER_ON = 1 -} SystemLinker; typedef enum { @@ -187,6 +181,13 @@ typedef enum SOFT_FLOAT_YES = 1 } SoftFloat; +typedef enum +{ + WIN64_SIMD_DEFAULT = -1, + WIN64_SIMD_FULL = 0, + WIN64_SIMD_ARRAY = 1 +} Win64Simd; + typedef enum { STRUCT_RETURN_DEFAULT = -1, @@ -366,6 +367,7 @@ typedef struct BuildOptions_ const char *testfn; const char *cc; const char *build_dir; + const char *output_dir; const char *llvm_out; const char *asm_out; const char *obj_out; @@ -373,6 +375,7 @@ typedef struct BuildOptions_ RelocModel reloc_model; X86VectorCapability x86_vector_capability; X86CpuSet x86_cpu_set; + Win64Simd win_64_simd; FpOpt fp_math; EmitStdlib emit_stdlib; UseStdlib use_stdlib; @@ -501,6 +504,7 @@ typedef struct X86VectorCapability x86_vector_capability : 4; RiscvFloatCapability riscv_float_capability : 4; bool trap_on_wrap : 1; + Win64Simd pass_win64_simd_as_arrays : 3; FpOpt fp_math; SafetyLevel safe_mode; X86CpuSet x86_cpu_set; diff --git a/src/build/build_internal.h b/src/build/build_internal.h index a9fea1b2c..6e51b992c 100644 --- a/src/build/build_internal.h +++ b/src/build/build_internal.h @@ -47,6 +47,11 @@ static const char *riscv_capability[3] = { [RISCVFLOAT_DOUBLE] = "double", }; +static const char *win64_simd_type[2] = { + [WIN64_SIMD_ARRAY] = "array", + [WIN64_SIMD_FULL] = "full", +}; + static const char *fp_math[3] = { [FP_STRICT] = "strict", [FP_RELAXED] = "relaxed", diff --git a/src/build/build_options.c b/src/build/build_options.c index d91aeea4f..2125ae116 100644 --- a/src/build/build_options.c +++ b/src/build/build_options.c @@ -105,6 +105,7 @@ static void usage(void) OUTPUT(" -D - Add feature flag ."); OUTPUT(" -U - Remove feature flag ."); OUTPUT(" --trust=