From 92ee8efb69bbe2dd145f7a4716c5deea49b19004 Mon Sep 17 00:00:00 2001 From: Christoffer Lerno Date: Fri, 23 Feb 2024 00:18:43 +0100 Subject: [PATCH] 0.6.0: 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. `@default` implementations for interfaces removed. `any*` => `any`, same for interfaces. Emit local/private globals as "private" in LLVM, following C "static". Updated enum syntax. Add support [rgba] properties in vectors. Improved checks of aliased "void". Subarray -> slice. Some tentative float16 support. Fix of llvm codegen enum check. Improved alignment handling. Add --output-dir #1155. Removed List/Object append. `GenericList` renamed `AnyList`. Remove unused "unwrap". Fixes to cond. Optimize output in dead branches. Better checking of operator methods. Disallow `any` from implementing dynamic methods. Check for operator mismatch. Remove unnecessary bitfield. Remove numbering in --list* commands Old style enum declaration for params/type, but now the type is optional. Add note on #1086. Allow making distinct types out of "void", "typeid", "anyfault" and faults. Remove system linker build options. "Try" expressions must be simple expressions. Add optimized build to Mac tests. Register int. `assert(false)` only allowed in unused branches or in tests. Compile time failed asserts is a compile time error. Remove current_block_is_target. Bug when assigning an optional from an optional. Remove unused emit_zstring. Simplify phi code. Remove unnecessary unreachable blocks and remove unnecessary current_block NULL assignments. Proper handling of '.' and Win32 '//server' paths. Unify expression and macro blocks in the middle end. Add "no discard" to expression blocks with a return value. Detect "unsigned >= 0" as errors. --- .github/workflows/main.yml | 27 +- README.md | 4 +- lib/std/atomic.c3 | 2 +- lib/std/atomic_nolibc.c3 | 8 +- .../{generic_list.c3 => anylist.c3} | 121 ++- lib/std/collections/bitset.c3 | 16 +- lib/std/collections/enummap.c3 | 2 +- lib/std/collections/enumset.c3 | 2 +- lib/std/collections/linkedlist.c3 | 105 +- lib/std/collections/list.c3 | 106 +- lib/std/collections/map.c3 | 51 +- lib/std/collections/object.c3 | 24 +- lib/std/collections/priorityqueue.c3 | 18 +- lib/std/collections/range.c3 | 4 +- lib/std/collections/ringbuffer.c3 | 10 +- lib/std/core/allocators/arena_allocator.c3 | 8 +- lib/std/core/allocators/dynamic_arena.c3 | 12 +- lib/std/core/allocators/heap_allocator.c3 | 6 +- lib/std/core/allocators/libc_allocator.c3 | 28 +- lib/std/core/allocators/on_stack_allocator.c3 | 16 +- lib/std/core/allocators/temp_allocator.c3 | 24 +- lib/std/core/allocators/tracking_allocator.c3 | 18 +- lib/std/core/array.c3 | 14 +- lib/std/core/bitorder.c3 | 12 +- lib/std/core/builtin.c3 | 4 +- lib/std/core/dstring.c3 | 40 +- lib/std/core/env.c3 | 1 + lib/std/core/mem.c3 | 67 +- lib/std/core/mem_allocator.c3 | 191 +--- lib/std/core/runtime.c3 | 8 +- lib/std/core/string.c3 | 37 +- lib/std/core/types.c3 | 8 +- lib/std/encoding/csv.c3 | 10 +- lib/std/encoding/json.c3 | 8 +- lib/std/io/bits.c3 | 8 +- lib/std/io/file.c3 | 2 +- lib/std/io/formatter.c3 | 18 +- lib/std/io/formatter_private.c3 | 19 +- lib/std/io/io.c3 | 16 +- lib/std/io/os/getcwd.c3 | 2 +- lib/std/io/os/ls.c3 | 8 +- lib/std/io/os/temp_directory.c3 | 6 +- lib/std/io/path.c3 | 110 ++- lib/std/io/stream.c3 | 18 +- lib/std/io/stream/buffer.c3 | 8 +- lib/std/io/stream/bytebuffer.c3 | 19 +- lib/std/io/stream/bytereader.c3 | 2 +- lib/std/io/stream/bytewriter.c3 | 27 +- lib/std/io/stream/limitreader.c3 | 4 +- lib/std/io/stream/scanner.c3 | 4 +- lib/std/math/math.c3 | 6 +- lib/std/math/math_complex.c3 | 2 +- lib/std/math/math_quaternion.c3 | 1 - lib/std/net/inetaddr.c3 | 8 +- lib/std/net/net.c3 | 2 +- lib/std/net/socket.c3 | 12 +- lib/std/os/backtrace.c3 | 6 +- lib/std/os/env.c3 | 8 +- lib/std/os/linux/linux.c3 | 12 +- lib/std/os/macos/darwin.c3 | 8 +- lib/std/os/macos/objc.c3 | 2 +- lib/std/os/win32/files.c3 | 2 + lib/std/os/win32/process.c3 | 6 +- releasenotes.md | 42 +- resources/castrules.md | 2 +- resources/examples/contextfree/boolerr.c3 | 4 +- resources/examples/levenshtein.c3 | 2 +- resources/examples/nolibc/project.json | 6 +- resources/examples/process.c3 | 2 +- resources/examples/project_all_settings.json | 2 +- resources/grammar/grammar.y | 33 +- resources/testfragments/allocators_testing.c3 | 2 +- resources/testfragments/demo1.c3 | 2 +- src/build/build.h | 7 +- src/build/build_options.c | 35 +- src/build/builder.c | 1 + src/compiler/abi/c_abi_x64.c | 16 +- src/compiler/abi/c_abi_x86.c | 14 +- src/compiler/codegen_general.c | 6 +- src/compiler/codegen_internal.h | 10 +- src/compiler/compiler.c | 46 +- src/compiler/compiler_internal.h | 99 +- src/compiler/copying.c | 11 +- src/compiler/enums.h | 35 +- src/compiler/expr.c | 23 +- src/compiler/float.c | 119 +-- src/compiler/headers.c | 18 +- src/compiler/json_output.c | 2 +- src/compiler/llvm_codegen.c | 57 +- src/compiler/llvm_codegen_builtins.c | 19 +- src/compiler/llvm_codegen_debug_info.c | 14 +- src/compiler/llvm_codegen_expr.c | 588 +++++------ src/compiler/llvm_codegen_function.c | 75 +- src/compiler/llvm_codegen_instr.c | 4 - src/compiler/llvm_codegen_internal.h | 87 +- src/compiler/llvm_codegen_internal_impl.h | 22 +- src/compiler/llvm_codegen_module.c | 1 - src/compiler/llvm_codegen_stmt.c | 272 ++--- src/compiler/llvm_codegen_storeload.c | 2 +- src/compiler/llvm_codegen_type.c | 19 +- src/compiler/llvm_codegen_value.c | 12 +- src/compiler/number.c | 5 +- src/compiler/parse_expr.c | 29 +- src/compiler/parse_global.c | 71 +- src/compiler/sema_builtins.c | 2 +- src/compiler/sema_casts.c | 181 ++-- src/compiler/sema_decls.c | 926 +++++++++++------- src/compiler/sema_expr.c | 390 +++++--- src/compiler/sema_initializers.c | 6 +- src/compiler/sema_internal.h | 31 +- src/compiler/sema_liveness.c | 28 +- src/compiler/sema_name_resolution.c | 10 +- src/compiler/sema_stmts.c | 247 +++-- src/compiler/sema_types.c | 92 +- src/compiler/semantic_analyser.c | 7 +- src/compiler/symtab.c | 1 - src/compiler/target.c | 35 + src/compiler/target.h | 1 + src/compiler/tilde_codegen_expr.c | 2 +- src/compiler/tokens.c | 6 +- src/compiler/types.c | 165 ++-- src/utils/file_utils.c | 4 +- src/utils/find_msvc.c | 542 +++++----- src/utils/lib.h | 4 +- src/utils/stringutils.c | 33 + src/version.h | 2 +- test/test_suite/any/any_in_any.c3t | 26 +- test/test_suite/any/variant_assign.c3t | 94 +- test/test_suite/any/variant_switch.c3t | 28 +- test/test_suite/any/variant_test.c3t | 92 +- test/test_suite/arrays/array_struct.c3t | 2 +- .../test_suite/arrays/complex_array_const.c3t | 2 +- test/test_suite/arrays/global_init.c3t | 26 +- test/test_suite/assert/assert_with_void.c3 | 2 +- test/test_suite/assert/assertf.c3t | 24 +- test/test_suite/assert/unreachable.c3t | 6 +- .../test_suite/assignment/alignment_index.c3t | 22 + test/test_suite/assignment/int_assign.c3t | 1 + .../{var_variable.c3t => var_variable.c3} | 1 - .../bitstruct/bitstruct_anon_in_struct_ok.c3t | 46 +- .../test_suite/bitstruct/bitstruct_arrays.c3t | 350 +++---- test/test_suite/bitstruct/bitstruct_be.c3t | 54 +- .../bitstruct/bitstruct_initializer.c3t | 120 +-- test/test_suite/bitstruct/bitstruct_ops.c3t | 116 +-- test/test_suite/cast/cast_to_failable.c3 | 4 +- test/test_suite/clang/2002-07.c3t | 4 +- .../compile_time_access_subscript.c3t | 10 +- test/test_suite/compile_time/ct_assert_bug.c3 | 2 +- .../compile_time/ct_builtin_time_date.c3t | 24 +- test/test_suite/compile_time/ct_funcptr.c3t | 8 +- test/test_suite/compile_time/ct_memberof.c3t | 401 +++----- .../compile_time/untyped_conversions.c3t | 48 +- .../concurrency/atomic_load_store.c3t | 8 +- .../concurrency/atomic_load_store_debug.c3t | 10 +- test/test_suite/constants/constants.c3t | 18 +- test/test_suite/debug_symbols/constants.c3t | 6 +- .../debug_symbols/constants_mingw.c3t | 6 +- .../test_suite/defer/defer_and_expr_block.c3t | 8 +- test/test_suite/defer/defer_catch_err.c3t | 33 +- test/test_suite/defer/defer_with_return.c3 | 2 +- test/test_suite/define/aliased_consts.c3t | 4 +- test/test_suite/define/forbidden_defines.c3 | 2 +- test/test_suite/distinct/distinct_invalid.c3 | 6 +- test/test_suite/dynamic/any_cast.c3 | 10 +- .../dynamic/dynamic_with_default.c3t | 131 --- test/test_suite/dynamic/inherit_linux.c3t | 20 +- test/test_suite/dynamic/inherit_macos.c3t | 20 +- test/test_suite/dynamic/null_and_protocol.c3t | 20 +- .../dynamic/overlapping_function_linux.c3t | 20 +- .../dynamic/overlapping_function_macos.c3t | 20 +- .../enumerations/enum_associated_value.c3t | 4 +- .../enum_associated_values_other.c3t | 6 +- .../enumerations/enum_conversions.c3t | 112 +-- .../enumerations/enum_invalid_param.c3 | 6 +- .../enumerations/enum_reflect_associated.c3t | 26 +- .../enumerations/enum_same_param.c3 | 8 +- test/test_suite/enumerations/missing_type.c3 | 2 +- test/test_suite/errors/error_introspect.c3t | 24 +- test/test_suite/errors/multiple_catch.c3t | 24 +- .../errors/optional_chained_init.c3t | 96 +- test/test_suite/errors/optional_sizeof.c3 | 6 +- .../errors/optional_with_optional.c3t | 64 +- test/test_suite/errors/or_and_rethrow.c3t | 208 +--- test/test_suite/errors/printing_errors.c3t | 14 +- test/test_suite/errors/rethrow_macro.c3 | 2 +- .../expression_block/expr_block_no_assign.c3 | 6 + .../expressions/assign_optional.c3t | 69 ++ .../expressions/unsafe_comparisons.c3 | 10 + test/test_suite/from_docs/examples_struct.c3 | 2 +- .../func_ptr_conversions_and_names.c3t | 64 +- test/test_suite/functions/test_regression.c3t | 18 +- .../functions/test_regression_mingw.c3t | 19 +- .../test_suite/functions/typeless_varargs.c3t | 20 +- .../functions/varargs_followed_by_named.c3t | 30 +- test/test_suite/generic/enum_set_test.c3t | 40 +- .../generic/generic_lambda_complex.c3t | 34 +- test/test_suite/generic/generic_num.c3t | 8 +- test/test_suite/generic/generic_recursion.c3t | 2 +- test/test_suite/initializer_lists/fasta.c3t | 2 +- .../initializers_to_macros.c3 | 2 +- test/test_suite/lambda/nested_lambda_def.c3t | 2 +- test/test_suite/lambda/simple_lambda.c3t | 2 +- test/test_suite/literals/bin_literal.c3t | 34 +- .../macros/macro_failable_return_rethrow.c3t | 18 +- .../test_suite/macros/macro_typed_varargs.c3t | 52 +- .../macros/macro_untyped_varargs_2.c3t | 92 +- test/test_suite/macros/macro_vasplat.c3t | 168 ++-- .../macros/unifying_implicit_void.c3t | 32 +- .../methods/dynamic_method_fails.c3 | 6 + .../methods/extension_method_generic.c3 | 13 +- .../methods/operator_defined_twice.c3 | 9 + test/test_suite/methods/operator_mismatch.c3 | 10 + .../methods/unsupported_operator.c3 | 3 + .../module/module_section_export.c3t | 2 +- test/test_suite/pointers/const_pointer.c3t | 8 +- .../pointers/subarray_variant_to_ptr.c3t | 14 +- .../slices/slice_to_slice_assign.c3t | 52 +- .../slices/slice_to_slice_vector_assign.c3t | 52 +- .../foreach_more_implementations.c3t | 16 +- test/test_suite/stdlib/map_linux.c3t | 114 +-- test/test_suite/stdlib/map_macos.c3t | 114 +-- test/test_suite/struct/simple_struct.c3t | 2 +- .../struct/struct_const_construct_simple.c3t | 18 +- .../test_suite/subarrays/slice_comparison.c3t | 120 +-- .../switch/switch_in_defer_macro.c3t | 50 +- test/test_suite/types/enum_ok.c3 | 4 +- test/test_suite/types/enum_parse_errors.c3 | 6 +- test/test_suite/union/union_codegen_const.c3t | 6 +- test/test_suite/vector/swizzling.c3 | 11 + test/unit/regression/any.c3 | 8 +- test/unit/regression/catch_err.c3 | 21 + test/unit/regression/liveness_any.c3 | 2 +- test/unit/regression/subtype.c3 | 2 +- test/unit/regression/swizzle.c3 | 11 +- test/unit/stdlib/collections/generic_list.c3 | 2 +- test/unit/stdlib/collections/linkedlist.c3 | 123 +-- test/unit/stdlib/collections/list.c3 | 4 +- test/unit/stdlib/collections/object.c3 | 4 +- test/unit/stdlib/collections/ringbuffer.c3 | 30 +- test/unit/stdlib/core/builtintests.c3 | 2 +- test/unit/stdlib/io/bytestream.c3 | 8 +- test/unit/stdlib/io/dstringstream.c3 | 2 +- test/unit/stdlib/io/path.c3 | 101 +- test/unit/stdlib/mem/temp_mem.c3 | 10 +- test/unit/stdlib/os/env.c3 | 2 +- test/unit/stdlib/threads/simple_thread.c3 | 2 +- 246 files changed, 4976 insertions(+), 5062 deletions(-) rename lib/std/collections/{generic_list.c3 => anylist.c3} (70%) create mode 100644 test/test_suite/assignment/alignment_index.c3t rename test/test_suite/assignment/{var_variable.c3t => var_variable.c3} (99%) delete mode 100644 test/test_suite/dynamic/dynamic_with_default.c3t create mode 100644 test/test_suite/expression_block/expr_block_no_assign.c3 create mode 100644 test/test_suite/expressions/assign_optional.c3t create mode 100644 test/test_suite/methods/dynamic_method_fails.c3 create mode 100644 test/test_suite/methods/operator_defined_twice.c3 create mode 100644 test/test_suite/methods/operator_mismatch.c3 create mode 100644 test/test_suite/methods/unsupported_operator.c3 create mode 100644 test/test_suite/vector/swizzling.c3 create mode 100644 test/unit/regression/catch_err.c3 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index b328b83e0..49c4c0f79 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..050964ce0 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()); @@ -99,6 +96,8 @@ fn FloatType! float_from_any(any* arg) @private return *arg; case uint128: return *arg; + case float16: + return (FloatType)*arg; case float: return (FloatType)*arg; case double: @@ -588,14 +587,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 +648,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..ab7fd01ea 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; @@ -385,6 +428,8 @@ fn String! normalize(String path_str, PathEnv path_env = DEFAULT_PATH_ENV) } if (len > path_start + 1 && is_separator(path_str[len - 1], path_env)) 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 dd6738b60..d53fd3b8a 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 e5c98358d..8b7cb9481 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -1,5 +1,41 @@ # 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. + +### Fixes +- Fixed issue in safe mode when converting enums. +- Better checking of operator methods. +- Bug when assigning an optional from an optional. + +### 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. +- "float16" can now be printed. +- Removed 'append' from Object and List, replaced by 'push'. +- `GenericList` renamed `AnyList`. +- Proper handling of '.' and Win32 '//server' paths. + ## 0.5.6 Change list ### Changes / improvements @@ -377,13 +413,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. @@ -486,7 +522,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/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..7b42ca9fd 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 { @@ -366,6 +360,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; diff --git a/src/build/build_options.c b/src/build/build_options.c index d91aeea4f..9939e1407 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=