Compare commits

..

2 Commits

Author SHA1 Message Date
Christoffer Lerno
058d637407 Additional codegen. 2024-12-28 16:46:12 +01:00
Christoffer Lerno
01335f6862 Additional codegen. 2024-12-28 16:23:25 +01:00
2001 changed files with 11916 additions and 138612 deletions

View File

@@ -11,7 +11,7 @@ env:
LLVM_RELEASE_VERSION_MAC: 17
LLVM_RELEASE_VERSION_LINUX: 17
LLVM_RELEASE_VERSION_UBUNTU20: 17
LLVM_DEV_VERSION: 21
LLVM_DEV_VERSION: 20
jobs:
build-msvc:
@@ -51,17 +51,17 @@ jobs:
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
cd resources/testproject
..\..\build\${{ matrix.build_type }}\c3c.exe -vvv --emit-llvm run hello_world_win32 --trust=full
dir build\llvm\windows-x64
..\..\build\${{ matrix.build_type }}\c3c.exe -vvv --emit-llvm run hello_world_win32
dir build\llvm_ir
..\..\build\${{ matrix.build_type }}\c3c.exe clean
dir build\llvm\windows-x64
dir build\llvm_ir
- name: Build testproject lib
run: |
cd resources/testproject
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
..\..\build\${{ matrix.build_type }}\c3c.exe -vvv build hello_world_win32_lib --trust=full
..\..\build\${{ matrix.build_type }}\c3c.exe -vvv build hello_world_win32_lib
- name: Compile and run dynlib-test
run: |
@@ -87,16 +87,16 @@ jobs:
..\build\${{ matrix.build_type }}\c3c.exe compile --lib raylib5 --print-linking examples\raylib\raylib_snake.c3
..\build\${{ matrix.build_type }}\c3c.exe compile --lib raylib5 --print-linking examples\raylib\raylib_tetris.c3
- name: run compiler tests
run: |
cd test
python3.exe src/tester.py ..\build\${{ matrix.build_type }}\c3c.exe test_suite/
- name: Compile run unit tests
run: |
cd test
..\build\${{ matrix.build_type }}\c3c.exe compile-test unit -O1
- name: run compiler tests
run: |
cd test
..\build\${{ matrix.build_type }}\c3c.exe compile-run -O1 src/test_suite_runner.c3 --stdlib ..\lib7 --enable-new-generics -- ..\build\${{ matrix.build_type }}\c3c.exe test_suite7/ --stdlib ../lib7 --no-terminal
- name: Test python script
run: |
py msvc_build_libraries.py --accept-license
@@ -132,8 +132,8 @@ jobs:
install: git binutils mingw-w64-x86_64-clang mingw-w64-x86_64-ninja mingw-w64-x86_64-cmake mingw-w64-x86_64-toolchain mingw-w64-x86_64-python
- shell: msys2 {0}
run: |
pacman --noconfirm -U https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-llvm-19.1.7-1-any.pkg.tar.zst
pacman --noconfirm -U https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-lld-19.1.7-1-any.pkg.tar.zst
pacman --noconfirm -U https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-llvm-19.1.6-1-any.pkg.tar.zst
pacman --noconfirm -U https://mirror.msys2.org/mingw/mingw64/mingw-w64-x86_64-lld-19.1.6-1-any.pkg.tar.zst
- name: CMake
run: |
cmake -B build -G Ninja -DCMAKE_C_COMPILER=clang -DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
@@ -143,7 +143,6 @@ jobs:
run: |
cd resources
../build/c3c compile-run --print-linking examples/hello_world_many.c3
../build/c3c compile-run --print-linking examples/process.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
@@ -154,7 +153,7 @@ jobs:
- name: Build testproject
run: |
cd resources/testproject
../../build/c3c run -vvv --trust=full
../../build/c3c run -vvv
- name: Vendor-fetch
run: |
@@ -163,13 +162,13 @@ jobs:
- name: Build testproject lib
run: |
cd resources/testproject
../../build/c3c build hello_world_lib --cc cc -vvv --trust=full
../../build/c3c build hello_world_lib --cc cc -vvv
- name: run compiler tests
run: |
cd test
../build/c3c.exe compile --target windows-x64 -O1 src/test_suite_runner.c3 --stdlib ../lib7 --enable-new-generics
./test_suite_runner.exe ../build/c3c.exe test_suite7/ --stdlib ../lib7 --no-terminal
python3 src/tester.py ../build/c3c.exe test_suite/
build-msys2-clang:
runs-on: windows-latest
@@ -210,26 +209,26 @@ jobs:
- name: Build testproject
run: |
cd resources/testproject
../../build/c3c run -vvv --trust=full
../../build/c3c run -vvv
- name: Build testproject lib
run: |
cd resources/testproject
../../build/c3c build hello_world_lib -vvv --trust=full
../../build/c3c build hello_world_lib -vvv
- name: run compiler tests
run: |
cd test
../build/c3c.exe compile-run -O1 --stdlib ../lib7 src/test_suite_runner.c3 --enable-new-generics -- ../build/c3c.exe test_suite7/ --stdlib ../lib7 --no-terminal
python3 src/tester.py ../build/c3c.exe test_suite/
build-linux:
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
strategy:
# Don't abort runners if a single one fails
fail-fast: false
matrix:
build_type: [Release, Debug]
llvm_version: [17, 18, 19, 20, 21]
llvm_version: [17, 18, 19]
steps:
- uses: actions/checkout@v4
@@ -350,7 +349,7 @@ jobs:
- name: Build testproject
run: |
cd resources/testproject
../../build/c3c run -vvv --trust=full
../../build/c3c run -vvv
- name: Test WASM
run: |
@@ -369,7 +368,7 @@ jobs:
- name: Build testproject direct linker
run: |
cd resources/testproject
../../build/c3c run -vvv --linker=builtin --trust=full
../../build/c3c run -vvv --linker=builtin
- name: Init a library & a project
run: |
@@ -381,7 +380,7 @@ jobs:
- name: run compiler tests
run: |
cd test
../build/c3c compile-run -O1 src/test_suite_runner.c3 --stdlib ../lib7 --enable-new-generics -- ../build/c3c test_suite7/ --stdlib ../lib7
python3 src/tester.py ../build/c3c test_suite/
- name: bundle_output
if: matrix.llvm_version == env.LLVM_RELEASE_VERSION_LINUX
@@ -406,7 +405,7 @@ jobs:
fail-fast: false
matrix:
build_type: [Release, Debug]
llvm_version: [17, 18, 19, 20, 21]
llvm_version: [17, 18, 19]
steps:
- uses: actions/checkout@v4
- name: Install common deps
@@ -487,22 +486,22 @@ jobs:
- name: Compile run unit tests
run: |
cd test
../build/c3c compile-test unit --sanitize=address
../build/c3c compile-test unit
- name: Build testproject
run: |
cd resources/testproject
../../build/c3c run -vvv --trust=full
../../build/c3c run -vvv
- name: Build testproject direct linker
run: |
cd resources/testproject
../../build/c3c run -vvv --linker=builtin --trust=full
../../build/c3c run -vvv --linker=builtin
- name: run compiler tests
run: |
cd test
../build/c3c compile-run -O1 src/test_suite_runner.c3 --stdlib ../lib7 --enable-new-generics -- ../build/c3c test_suite7/ --stdlib ../lib7
python3 src/tester.py ../build/c3c test_suite/
- name: bundle_output
if: matrix.llvm_version == env.LLVM_RELEASE_VERSION_UBUNTU20
@@ -521,7 +520,7 @@ jobs:
path: c3-ubuntu-20-${{matrix.build_type}}.tar.gz
build-with-docker:
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
@@ -584,7 +583,7 @@ jobs:
- name: Build testproject
run: |
cd resources/testproject
../../build/c3c run -vvv --trust=full
../../build/c3c run -vvv
- name: Test WASM
run: |
@@ -594,7 +593,7 @@ jobs:
- name: Build testproject direct linker
run: |
cd resources/testproject
../../build/c3c run -vvv --linker=builtin --trust=full
../../build/c3c run -vvv --linker=builtin
- name: Init a library & a project
run: |
@@ -606,7 +605,7 @@ jobs:
- name: run compiler tests
run: |
cd test
../build/c3c compile-run -O1 src/test_suite_runner.c3 --stdlib ../lib7 --enable-new-generics -- ../build/c3c test_suite7/ --stdlib ../lib7
python3 src/tester.py ../build/c3c test_suite/
build-mac:
runs-on: macos-latest
@@ -661,7 +660,7 @@ jobs:
- name: Compile run unit tests
run: |
cd test
../build/c3c compile-test unit -O1
../build/c3c compile-test unit
- name: Test WASM
run: |
@@ -671,28 +670,22 @@ jobs:
- name: Build testproject
run: |
cd resources/testproject
../../build/c3c run -vvv --trust=full
../../build/c3c run -vvv
- name: Build testproject direct linker
run: |
cd resources/testproject
../../build/c3c run -vvv --linker=builtin --trust=full
../../build/c3c run -vvv --linker=builtin
- name: Build testproject lib
run: |
cd resources/testproject
../../build/c3c build hello_world_lib -vvv --trust=full
../../build/c3c build hello_world_lib -vvv
- name: run compiler tests
run: |
cd test
../build/c3c compile -O1 src/test_suite_runner.c3 --stdlib ../lib7 --enable-new-generics
./test_suite_runner ../build/c3c test_suite7/ --stdlib ../lib7
- name: run build test suite runner
run: |
cd test
../build/c3c compile -O1 src/test_suite_runner.c3 --stdlib ../lib7 --enable-new-generics
python3 src/tester.py ../build/c3c test_suite/
- name: bundle_output
if: matrix.llvm_version == env.LLVM_RELEASE_VERSION_MAC
@@ -710,39 +703,9 @@ jobs:
name: c3-macos-${{matrix.build_type}}
path: c3-macos-${{matrix.build_type}}.zip
build-nix:
runs-on: ubuntu-22.04
strategy:
# Don't abort runners if a single one fails
fail-fast: false
matrix:
build_type: [ Release, Debug ]
nixpkgs: [ Lock, Latest ]
steps:
- uses: actions/checkout@v4
- name: Install Nix
uses: cachix/install-nix-action@v30
with:
github_access_token: ${{ secrets.GITHUB_TOKEN }}
- name: Update flake (if necessary)
run: |
if [[ matrix.nixpkgs == "Latest" ]]; then
nix flake update
fi
nix flake info
- name: Build and check
run: |
if [[ ${{ matrix.build_type }} = "Debug" ]]; then
nix build -L ".#c3c-debug-checks"
else
nix build -L ".#c3c-checks"
fi
release:
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
needs: [build-msvc, build-linux, build-mac, build-linux-ubuntu20]
if: github.ref == 'refs/heads/master'

6
.gitignore vendored
View File

@@ -79,9 +79,3 @@ TAGS
# 'nix build' resulting symlink
result
# macOS
.DS_Store
# tests
/test/tmp/*
/test/testrun

View File

@@ -38,14 +38,14 @@ set(CMAKE_CXX_STANDARD 17)
if(MSVC)
message(STATUS "MSVC version ${MSVC_VERSION}")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /O2 /EHsc /utf-8")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /O2 /EHsc /utf-8")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Od /Zi /EHa /utf-8")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /Od /Zi /EHa /utf-8")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /O2 /EHsc")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /O2 /EHsc")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Od /Zi /EHa")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /Od /Zi /EHa")
else()
if (true)
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O0 -fno-exceptions")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -gdwarf-3 -O0 -fno-exceptions")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -fno-exceptions")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -gdwarf-3 -fno-exceptions")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -gdwarf-3 -O3 -fno-exceptions")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -gdwarf-3 -fno-exceptions")
else()
@@ -65,7 +65,6 @@ option(C3_USE_TB "Use TB" OFF)
set(C3_MIMALLOC_TAG "v1.7.3" CACHE STRING "Used version of mimalloc")
option(C3_WITH_LLVM "Build with LLVM" ON)
option(C3_LLD_DIR "Use custom LLD directory" "")
option(LLVM_CRT_LIBRARY_DIR "Use custom llvm's compiler-rt directory" "")
set(C3_USE_MIMALLOC OFF)
if(C3_USE_MIMALLOC)
@@ -85,7 +84,7 @@ if (NOT WIN32)
endif()
if(C3_WITH_LLVM)
if (NOT C3_LLVM_VERSION STREQUAL "auto")
if (${C3_LLVM_VERSION} VERSION_LESS 17 OR ${C3_LLVM_VERSION} VERSION_GREATER 21)
if (${C3_LLVM_VERSION} VERSION_LESS 17 OR ${C3_LLVM_VERSION} VERSION_GREATER 20)
message(FATAL_ERROR "LLVM ${C3_LLVM_VERSION} is not supported!")
endif()
endif()
@@ -151,13 +150,6 @@ if(C3_WITH_LLVM)
endif()
endif()
if (EXISTS /usr/lib)
# Some systems (such as Alpine Linux) seem to put some of the relevant
# LLVM files in /usr/lib, but this doesn't seem to be included in the
# value of LLVM_LIBRARY_DIRS.
list(APPEND LLVM_LIBRARY_DIRS /usr/lib)
endif()
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
message(STATUS "Libraries located in: ${LLVM_LIBRARY_DIRS}")
@@ -253,19 +245,19 @@ if(C3_WITH_LLVM)
find_library(LLD_LOONG NAMES libLLVMLoongArchCodeGen.lib libLLVMLoongArchAsmParser.lib libLLVMLoongArchCodeGen.a libLLVMLoongArchAsmParser.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
set(lld_libs
${LLD_COFF}
${LLD_COMMON}
${LLD_WASM}
${LLD_MINGW}
${LLD_ELF}
${LLD_MACHO}
${LLD_COMMON}
)
if (APPLE)
set(lld_libs ${lld_libs} xar)
find_file(RT_ASAN_DYNAMIC NAMES libclang_rt.asan_osx_dynamic.dylib PATHS "${LLVM_LIBRARY_DIR}/clang/${LLVM_MAJOR_VERSION}/lib/darwin" ${LLVM_CRT_LIBRARY_DIR})
find_file(RT_TSAN_DYNAMIC NAMES libclang_rt.tsan_osx_dynamic.dylib PATHS "${LLVM_LIBRARY_DIR}/clang/${LLVM_MAJOR_VERSION}/lib/darwin" ${LLVM_CRT_LIBRARY_DIR})
find_file(RT_UBSAN_DYNAMIC NAMES libclang_rt.ubsan_osx_dynamic.dylib PATHS "${LLVM_LIBRARY_DIR}/clang/${LLVM_MAJOR_VERSION}/lib/darwin" ${LLVM_CRT_LIBRARY_DIR})
find_file(RT_LSAN_DYNAMIC NAMES libclang_rt.lsan_osx_dynamic.dylib PATHS "${LLVM_LIBRARY_DIR}/clang/${LLVM_MAJOR_VERSION}/lib/darwin" ${LLVM_CRT_LIBRARY_DIR})
find_file(RT_ASAN_DYNAMIC NAMES libclang_rt.asan_osx_dynamic.dylib PATHS "${LLVM_LIBRARY_DIR}/clang/${LLVM_MAJOR_VERSION}/lib/darwin")
find_file(RT_TSAN_DYNAMIC NAMES libclang_rt.tsan_osx_dynamic.dylib PATHS "${LLVM_LIBRARY_DIR}/clang/${LLVM_MAJOR_VERSION}/lib/darwin")
find_file(RT_UBSAN_DYNAMIC NAMES libclang_rt.ubsan_osx_dynamic.dylib PATHS "${LLVM_LIBRARY_DIR}/clang/${LLVM_MAJOR_VERSION}/lib/darwin")
find_file(RT_LSAN_DYNAMIC NAMES libclang_rt.lsan_osx_dynamic.dylib PATHS "${LLVM_LIBRARY_DIR}/clang/${LLVM_MAJOR_VERSION}/lib/darwin")
set(sanitizer_runtime_libraries
${RT_ASAN_DYNAMIC}
${RT_TSAN_DYNAMIC}
@@ -350,7 +342,6 @@ add_executable(c3c
src/utils/whereami.c
src/utils/cpus.c
src/utils/unzipper.c
src/compiler/c_codegen.c
src/compiler/decltable.c
src/compiler/mac_support.c
src/compiler/windows_support.c
@@ -380,6 +371,7 @@ endif()
if(C3_WITH_LLVM)
target_sources(c3c PRIVATE
src/compiler/c_codegen.c
src/compiler/llvm_codegen.c
src/compiler/llvm_codegen_debug_info.c
src/compiler/llvm_codegen_expr.c

View File

@@ -138,7 +138,7 @@ fn void main()
### Current status
The current stable version of the compiler is **version 0.6.7**.
The current stable version of the compiler is **version 0.6.5**.
The upcoming 0.6.x releases will focus on expanding the standard library.
Follow the issues [here](https://github.com/c3lang/c3c/issues).
@@ -275,14 +275,6 @@ A `c3c` executable will be found under `bin/`.
8. Set up CMake build for debug: `cmake ..`
9. Build: `cmake --build .`
#### Installing on Windows using Scoop
c3c is included in 'Main' bucket.
```sh
scoop install c3
```
#### Getting started with a "hello world"
Create a `main.c3` file with:
@@ -357,20 +349,6 @@ Your c3c executable should have compiled properly. You may want to test it: `./c
For a sytem-wide installation, run the following as root: `cmake --install .`
#### Compiling on Fedora
1. Install required project dependencies: `dnf install cmake clang git llvm llvm-devel lld lld-devel ncurses-devel`
2. Optionally, install additional dependencies: `dnf install libcurl-devel zlib-devel libzstd-devel libxml2-devel libffi-devel`
3. Clone the C3C repository: `git clone https://github.com/c3lang/c3c.git`
- If you only need the latest commit, you may want to make a shallow clone: `git clone https://github.com/c3lang/c3c.git --depth=1`
4. Enter the C3C directory: `cd c3c`
5. Create a build directory and navigate into it: `mkdir build && cd build`
6. Create the CMake build cache. The Fedora repositories provide `.so` libraries for lld, so you need to set the C3_LINK_DYNAMIC flag: `cmake .. -DC3_LINK_DYNAMIC=1`
7. Build the project: `cmake --build .`
The c3c binary should be created in the build directory. You can try it out by running some sample code: `./c3c compile ../resources/examples/hash.c3`
#### Compiling on other Linux / Unix variants
1. Install CMake.

View File

@@ -8,7 +8,7 @@ fn void init() @init
set_benchmark_max_iterations(10_000);
}
fn void quicksort_bench() @benchmark
fn void! quicksort_bench() @benchmark
{
// test set: 500 numbers between 0 and 99;
int[] data = {

12
flake.lock generated
View File

@@ -5,11 +5,11 @@
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"lastModified": 1726560853,
"narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a",
"type": "github"
},
"original": {
@@ -20,11 +20,11 @@
},
"nixpkgs": {
"locked": {
"lastModified": 1738297584,
"narHash": "sha256-AYvaFBzt8dU0fcSK2jKD0Vg23K2eIRxfsVXIPCW9a0E=",
"lastModified": 1730958623,
"narHash": "sha256-JwQZIGSYnRNOgDDoIgqKITrPVil+RMWHsZH1eE1VGN0=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "9189ac18287c599860e878e905da550aa6dec1cd",
"rev": "85f7e662eda4fa3a995556527c87b2524b691933",
"type": "github"
},
"original": {

View File

@@ -8,17 +8,12 @@
outputs = { self, ... } @ inputs: inputs.flake-utils.lib.eachDefaultSystem
(system:
let pkgs = import inputs.nixpkgs { inherit system; };
call = set: pkgs.callPackage ./nix/default.nix (
set // {
rev = self.rev or "unknown";
}
);
in {
let pkgs = import inputs.nixpkgs { inherit system; }; in
{
packages = {
default = self.packages.${system}.c3c;
c3c = call {};
c3c = pkgs.callPackage ./nix/default.nix {};
c3c-checks = pkgs.callPackage ./nix/default.nix {
checks = true;

View File

@@ -4,7 +4,6 @@ set(GIT_HASH "unknown")
if(GIT_FOUND AND EXISTS "${CMAKE_CURRENT_LIST_DIR}/.git")
execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse HEAD
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
OUTPUT_VARIABLE GIT_HASH
OUTPUT_STRIP_TRAILING_WHITESPACE
COMMAND_ERROR_IS_FATAL ANY)

View File

@@ -10,85 +10,85 @@ macro reverse(i) => $$bitreverse(i);
*>
macro bswap(i) @builtin => $$bswap(i);
macro uint[<?>].popcount(self) => $$popcount(self);
macro uint[<?>].ctz(self) => $$ctz(self);
macro uint[<?>].clz(self) => $$clz(self);
macro uint[<?>] uint[<?>].fshl(hi, uint[<?>] lo, uint[<?>] shift) => $$fshl(hi, lo, shift);
macro uint[<?>] uint[<?>].fshr(hi, uint[<?>] lo, uint[<?>] shift) => $$fshr(hi, lo, shift);
macro uint[<?>] uint[<?>].rotl(self, uint[<?>] shift) => $$fshl(self, self, shift);
macro uint[<?>] uint[<?>].rotr(self, uint[<?>] shift) => $$fshr(self, self, shift);
macro uint[<*>].popcount(self) => $$popcount(self);
macro uint[<*>].ctz(self) => $$ctz(self);
macro uint[<*>].clz(self) => $$clz(self);
macro uint[<*>] uint[<*>].fshl(hi, uint[<*>] lo, uint[<*>] shift) => $$fshl(hi, lo, shift);
macro uint[<*>] uint[<*>].fshr(hi, uint[<*>] lo, uint[<*>] shift) => $$fshr(hi, lo, shift);
macro uint[<*>] uint[<*>].rotl(self, uint[<*>] shift) => $$fshl(self, self, shift);
macro uint[<*>] uint[<*>].rotr(self, uint[<*>] shift) => $$fshr(self, self, shift);
macro int[<?>].popcount(self) => $$popcount(self);
macro int[<?>].ctz(self) => $$ctz(self);
macro int[<?>].clz(self) => $$clz(self);
macro int[<?>] int[<?>].fshl(hi, int[<?>] lo, int[<?>] shift) => $$fshl(hi, lo, shift);
macro int[<?>] int[<?>].fshr(hi, int[<?>] lo, int[<?>] shift) => $$fshr(hi, lo, shift);
macro int[<?>] int[<?>].rotl(self, int[<?>] shift) => $$fshl(self, self, shift);
macro int[<?>] int[<?>].rotr(self, int[<?>] shift) => $$fshr(self, self, shift);
macro int[<*>].popcount(self) => $$popcount(self);
macro int[<*>].ctz(self) => $$ctz(self);
macro int[<*>].clz(self) => $$clz(self);
macro int[<*>] int[<*>].fshl(hi, int[<*>] lo, int[<*>] shift) => $$fshl(hi, lo, shift);
macro int[<*>] int[<*>].fshr(hi, int[<*>] lo, int[<*>] shift) => $$fshr(hi, lo, shift);
macro int[<*>] int[<*>].rotl(self, int[<*>] shift) => $$fshl(self, self, shift);
macro int[<*>] int[<*>].rotr(self, int[<*>] shift) => $$fshr(self, self, shift);
macro ushort[<?>].popcount(self) => $$popcount(self);
macro ushort[<?>].ctz(self) => $$ctz(self);
macro ushort[<?>].clz(self) => $$clz(self);
macro ushort[<?>] ushort[<?>].fshl(hi, ushort[<?>] lo, ushort[<?>] shift) => $$fshl(hi, lo, shift);
macro ushort[<?>] ushort[<?>].fshr(hi, ushort[<?>] lo, ushort[<?>] shift) => $$fshr(hi, lo, shift);
macro ushort[<?>] ushort[<?>].rotl(self, ushort[<?>] shift) => $$fshl(self, self, shift);
macro ushort[<?>] ushort[<?>].rotr(self, ushort[<?>] shift) => $$fshr(self, self, shift);
macro ushort[<*>].popcount(self) => $$popcount(self);
macro ushort[<*>].ctz(self) => $$ctz(self);
macro ushort[<*>].clz(self) => $$clz(self);
macro ushort[<*>] ushort[<*>].fshl(hi, ushort[<*>] lo, ushort[<*>] shift) => $$fshl(hi, lo, shift);
macro ushort[<*>] ushort[<*>].fshr(hi, ushort[<*>] lo, ushort[<*>] shift) => $$fshr(hi, lo, shift);
macro ushort[<*>] ushort[<*>].rotl(self, ushort[<*>] shift) => $$fshl(self, self, shift);
macro ushort[<*>] ushort[<*>].rotr(self, ushort[<*>] shift) => $$fshr(self, self, shift);
macro short[<?>].popcount(self) => $$popcount(self);
macro short[<?>].ctz(self) => $$ctz(self);
macro short[<?>].clz(self) => $$clz(self);
macro short[<?>] short[<?>].fshl(hi, short[<?>] lo, short[<?>] shift) => $$fshl(hi, lo, shift);
macro short[<?>] short[<?>].fshr(hi, short[<?>] lo, short[<?>] shift) => $$fshr(hi, lo, shift);
macro short[<?>] short[<?>].rotl(self, short[<?>] shift) => $$fshl(self, self, shift);
macro short[<?>] short[<?>].rotr(self, short[<?>] shift) => $$fshr(self, self, shift);
macro short[<*>].popcount(self) => $$popcount(self);
macro short[<*>].ctz(self) => $$ctz(self);
macro short[<*>].clz(self) => $$clz(self);
macro short[<*>] short[<*>].fshl(hi, short[<*>] lo, short[<*>] shift) => $$fshl(hi, lo, shift);
macro short[<*>] short[<*>].fshr(hi, short[<*>] lo, short[<*>] shift) => $$fshr(hi, lo, shift);
macro short[<*>] short[<*>].rotl(self, short[<*>] shift) => $$fshl(self, self, shift);
macro short[<*>] short[<*>].rotr(self, short[<*>] shift) => $$fshr(self, self, shift);
macro char[<?>].popcount(self) => $$popcount(self);
macro char[<?>].ctz(self) => $$ctz(self);
macro char[<?>].clz(self) => $$clz(self);
macro char[<?>] char[<?>].fshl(hi, char[<?>] lo, char[<?>] shift) => $$fshl(hi, lo, shift);
macro char[<?>] char[<?>].fshr(hi, char[<?>] lo, char[<?>] shift) => $$fshr(hi, lo, shift);
macro char[<?>] char[<?>].rotl(self, char[<?>] shift) => $$fshl(self, self, shift);
macro char[<?>] char[<?>].rotr(self, char[<?>] shift) => $$fshr(self, self, shift);
macro char[<*>].popcount(self) => $$popcount(self);
macro char[<*>].ctz(self) => $$ctz(self);
macro char[<*>].clz(self) => $$clz(self);
macro char[<*>] char[<*>].fshl(hi, char[<*>] lo, char[<*>] shift) => $$fshl(hi, lo, shift);
macro char[<*>] char[<*>].fshr(hi, char[<*>] lo, char[<*>] shift) => $$fshr(hi, lo, shift);
macro char[<*>] char[<*>].rotl(self, char[<*>] shift) => $$fshl(self, self, shift);
macro char[<*>] char[<*>].rotr(self, char[<*>] shift) => $$fshr(self, self, shift);
macro ichar[<?>].popcount(self) => $$popcount(self);
macro ichar[<?>].ctz(self) => $$ctz(self);
macro ichar[<?>].clz(self) => $$clz(self);
macro ichar[<?>] ichar[<?>].fshl(hi, ichar[<?>] lo, ichar[<?>] shift) => $$fshl(hi, lo, shift);
macro ichar[<?>] ichar[<?>].fshr(hi, ichar[<?>] lo, ichar[<?>] shift) => $$fshr(hi, lo, shift);
macro ichar[<?>] ichar[<?>].rotl(self, ichar[<?>] shift) => $$fshl(self, self, shift);
macro ichar[<?>] ichar[<?>].rotr(self, ichar[<?>] shift) => $$fshr(self, self, shift);
macro ichar[<*>].popcount(self) => $$popcount(self);
macro ichar[<*>].ctz(self) => $$ctz(self);
macro ichar[<*>].clz(self) => $$clz(self);
macro ichar[<*>] ichar[<*>].fshl(hi, ichar[<*>] lo, ichar[<*>] shift) => $$fshl(hi, lo, shift);
macro ichar[<*>] ichar[<*>].fshr(hi, ichar[<*>] lo, ichar[<*>] shift) => $$fshr(hi, lo, shift);
macro ichar[<*>] ichar[<*>].rotl(self, ichar[<*>] shift) => $$fshl(self, self, shift);
macro ichar[<*>] ichar[<*>].rotr(self, ichar[<*>] shift) => $$fshr(self, self, shift);
macro ulong[<?>].popcount(self) => $$popcount(self);
macro ulong[<?>].ctz(self) => $$ctz(self);
macro ulong[<?>].clz(self) => $$clz(self);
macro ulong[<?>] ulong[<?>].fshl(hi, ulong[<?>] lo, ulong[<?>] shift) => $$fshl(hi, lo, shift);
macro ulong[<?>] ulong[<?>].fshr(hi, ulong[<?>] lo, ulong[<?>] shift) => $$fshr(hi, lo, shift);
macro ulong[<?>] ulong[<?>].rotl(self, ulong[<?>] shift) => $$fshl(self, self, shift);
macro ulong[<?>] ulong[<?>].rotr(self, ulong[<?>] shift) => $$fshr(self, self, shift);
macro ulong[<*>].popcount(self) => $$popcount(self);
macro ulong[<*>].ctz(self) => $$ctz(self);
macro ulong[<*>].clz(self) => $$clz(self);
macro ulong[<*>] ulong[<*>].fshl(hi, ulong[<*>] lo, ulong[<*>] shift) => $$fshl(hi, lo, shift);
macro ulong[<*>] ulong[<*>].fshr(hi, ulong[<*>] lo, ulong[<*>] shift) => $$fshr(hi, lo, shift);
macro ulong[<*>] ulong[<*>].rotl(self, ulong[<*>] shift) => $$fshl(self, self, shift);
macro ulong[<*>] ulong[<*>].rotr(self, ulong[<*>] shift) => $$fshr(self, self, shift);
macro long[<?>].popcount(self) => $$popcount(self);
macro long[<?>].ctz(self) => $$ctz(self);
macro long[<?>].clz(self) => $$clz(self);
macro long[<?>] long[<?>].fshl(hi, long[<?>] lo, long[<?>] shift) => $$fshl(hi, lo, shift);
macro long[<?>] long[<?>].fshr(hi, long[<?>] lo, long[<?>] shift) => $$fshr(hi, lo, shift);
macro long[<?>] long[<?>].rotl(self, long[<?>] shift) => $$fshl(self, self, shift);
macro long[<?>] long[<?>].rotr(self, long[<?>] shift) => $$fshr(self, self, shift);
macro long[<*>].popcount(self) => $$popcount(self);
macro long[<*>].ctz(self) => $$ctz(self);
macro long[<*>].clz(self) => $$clz(self);
macro long[<*>] long[<*>].fshl(hi, long[<*>] lo, long[<*>] shift) => $$fshl(hi, lo, shift);
macro long[<*>] long[<*>].fshr(hi, long[<*>] lo, long[<*>] shift) => $$fshr(hi, lo, shift);
macro long[<*>] long[<*>].rotl(self, long[<*>] shift) => $$fshl(self, self, shift);
macro long[<*>] long[<*>].rotr(self, long[<*>] shift) => $$fshr(self, self, shift);
macro uint128[<?>].popcount(self) => $$popcount(self);
macro uint128[<?>].ctz(self) => $$ctz(self);
macro uint128[<?>].clz(self) => $$clz(self);
macro uint128[<?>] uint128[<?>].fshl(hi, uint128[<?>] lo, uint128[<?>] shift) => $$fshl(hi, lo, shift);
macro uint128[<?>] uint128[<?>].fshr(hi, uint128[<?>] lo, uint128[<?>] shift) => $$fshr(hi, lo, shift);
macro uint128[<?>] uint128[<?>].rotl(self, uint128[<?>] shift) => $$fshl(self, self, shift);
macro uint128[<?>] uint128[<?>].rotr(self, uint128[<?>] shift) => $$fshr(self, self, shift);
macro uint128[<*>].popcount(self) => $$popcount(self);
macro uint128[<*>].ctz(self) => $$ctz(self);
macro uint128[<*>].clz(self) => $$clz(self);
macro uint128[<*>] uint128[<*>].fshl(hi, uint128[<*>] lo, uint128[<*>] shift) => $$fshl(hi, lo, shift);
macro uint128[<*>] uint128[<*>].fshr(hi, uint128[<*>] lo, uint128[<*>] shift) => $$fshr(hi, lo, shift);
macro uint128[<*>] uint128[<*>].rotl(self, uint128[<*>] shift) => $$fshl(self, self, shift);
macro uint128[<*>] uint128[<*>].rotr(self, uint128[<*>] shift) => $$fshr(self, self, shift);
macro int128[<?>].popcount(self) => $$popcount(self);
macro int128[<?>].ctz(self) => $$ctz(self);
macro int128[<?>].clz(self) => $$clz(self);
macro int128[<?>] int128[<?>].fshl(hi, int128[<?>] lo, int128[<?>] shift) => $$fshl(hi, lo, shift);
macro int128[<?>] int128[<?>].fshr(hi, int128[<?>] lo, int128[<?>] shift) => $$fshr(hi, lo, shift);
macro int128[<?>] int128[<?>].rotl(self, int128[<?>] shift) => $$fshl(self, self, shift);
macro int128[<?>] int128[<?>].rotr(self, int128[<?>] shift) => $$fshr(self, self, shift);
macro int128[<*>].popcount(self) => $$popcount(self);
macro int128[<*>].ctz(self) => $$ctz(self);
macro int128[<*>].clz(self) => $$clz(self);
macro int128[<*>] int128[<*>].fshl(hi, int128[<*>] lo, int128[<*>] shift) => $$fshl(hi, lo, shift);
macro int128[<*>] int128[<*>].fshr(hi, int128[<*>] lo, int128[<*>] shift) => $$fshr(hi, lo, shift);
macro int128[<*>] int128[<*>].rotl(self, int128[<*>] shift) => $$fshl(self, self, shift);
macro int128[<*>] int128[<*>].rotr(self, int128[<*>] shift) => $$fshr(self, self, shift);
macro uint.popcount(self) => $$popcount(self);
macro uint.ctz(self) => $$ctz(self);

View File

@@ -21,7 +21,7 @@ struct AnyList (Printable)
@param initial_capacity "The initial capacity to reserve"
*>
fn AnyList* AnyList.new_init(&self, usz initial_capacity = 16, Allocator allocator = null) @deprecated("Use init(mem)")
fn AnyList* AnyList.new_init(&self, usz initial_capacity = 16, Allocator allocator = null)
{
return self.init(allocator ?: allocator::heap(), initial_capacity) @inline;
}
@@ -52,18 +52,7 @@ fn AnyList* AnyList.init(&self, Allocator allocator, usz initial_capacity = 16)
@param initial_capacity "The initial capacity to reserve"
*>
fn AnyList* AnyList.temp_init(&self, usz initial_capacity = 16) @deprecated("Use tinit")
{
return self.init(allocator::temp(), initial_capacity) @inline;
}
<*
Initialize the list using the temp allocator.
@param initial_capacity "The initial capacity to reserve"
*>
fn AnyList* AnyList.tinit(&self, usz initial_capacity = 16)
fn AnyList* AnyList.temp_init(&self, usz initial_capacity = 16)
{
return self.init(allocator::temp(), initial_capacity) @inline;
}

View File

@@ -86,30 +86,15 @@ 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()) @deprecated("Use init(mem)")
fn GrowableBitSet* GrowableBitSet.new_init(&self, usz initial_capacity = 1, Allocator allocator = allocator::heap())
{
self.data.init(allocator, initial_capacity);
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(&self, Allocator allocator, usz initial_capacity = 1)
fn GrowableBitSet* GrowableBitSet.temp_init(&self, usz initial_capacity = 1)
{
self.data.init(allocator, initial_capacity);
return self;
}
fn GrowableBitSet* GrowableBitSet.temp_init(&self, usz initial_capacity = 1) @deprecated("Use tinit()")
{
return self.init(allocator::temp(), initial_capacity) @inline;
}
fn GrowableBitSet* GrowableBitSet.tinit(&self, usz initial_capacity = 1)
{
return self.init(allocator::temp(), initial_capacity) @inline;
return self.new_init(initial_capacity, allocator::temp()) @inline;
}
fn void GrowableBitSet.free(&self)
@@ -132,10 +117,15 @@ fn void GrowableBitSet.set(&self, usz i)
usz q = i / BITS;
usz r = i % BITS;
usz current_len = self.data.len();
while (q >= current_len)
if (q >= current_len)
{
self.data.push(0);
current_len++;
usz n = q + 1;
self.data.reserve(n);
if (n - 1 >= current_len)
{
self.data.entries[current_len .. (n - 1)] = 0;
}
self.data.size = n;
}
self.data.set(q, self.data[q] | (1 << r));
}

View File

@@ -2,13 +2,12 @@
// Use of this source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
<*
@require $defined((Key){}.hash()) `No .hash function found on the key`
@require $defined(Key{}.hash()) `No .hash function found on the key`
*>
module std::collections::map(<Key, Value>);
import std::math;
import std::io @norecurse;
struct HashMap (Printable)
struct HashMap
{
Entry*[] table;
Allocator allocator;
@@ -24,7 +23,7 @@ struct HashMap (Printable)
@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 = null) @deprecated("Use init(mem)")
fn HashMap* HashMap.new_init(&self, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = null)
{
return self.init(allocator ?: allocator::heap(), capacity, load_factor);
}
@@ -52,18 +51,7 @@ fn HashMap* HashMap.init(&self, Allocator allocator, uint capacity = DEFAULT_INI
@require !self.allocator "Map was already initialized"
@require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
*>
fn HashMap* HashMap.temp_init(&self, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR) @deprecated("Use tinit()")
{
return self.init(allocator::temp(), capacity, load_factor) @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 !self.allocator "Map was already initialized"
@require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
*>
fn HashMap* HashMap.tinit(&self, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR)
fn HashMap* HashMap.temp_init(&self, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR)
{
return self.init(allocator::temp(), capacity, load_factor) @inline;
}
@@ -76,9 +64,9 @@ fn HashMap* HashMap.tinit(&self, uint capacity = DEFAULT_INITIAL_CAPACITY, float
@require !self.allocator "Map was already initialized"
@require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
*>
macro HashMap* HashMap.new_init_with_key_values(&self, ..., uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap()) @deprecated("Use init_with_key_values(mem)")
macro HashMap* HashMap.new_init_with_key_values(&self, ..., uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap())
{
self.init(capacity, load_factor, allocator);
self.new_init(capacity, load_factor, allocator);
$for (var $i = 0; $i < $vacount; $i += 2)
self.set($vaarg[$i], $vaarg[$i+1]);
$endfor
@@ -95,10 +83,10 @@ macro HashMap* HashMap.new_init_with_key_values(&self, ..., uint capacity = DEFA
@require !self.allocator "Map was already initialized"
@require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
*>
fn HashMap* HashMap.new_init_from_keys_and_values(&self, Key[] keys, Value[] values, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap()) @deprecated("Use init_from_keys_and_values(mem)")
fn HashMap* HashMap.new_init_from_keys_and_values(&self, Key[] keys, Value[] values, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap())
{
assert(keys.len == values.len);
self.init(allocator, capacity, load_factor);
self.new_init(capacity, load_factor, allocator);
for (usz i = 0; i < keys.len; i++)
{
self.set(keys[i], values[i]);
@@ -113,25 +101,9 @@ fn HashMap* HashMap.new_init_from_keys_and_values(&self, Key[] keys, Value[] val
@require !self.allocator "Map was already initialized"
@require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
*>
macro HashMap* HashMap.temp_init_with_key_values(&self, ..., uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR) @deprecated("Use tinit_with_key_values")
macro HashMap* HashMap.temp_init_with_key_values(&self, ..., uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR)
{
self.tinit(capacity, load_factor);
$for (var $i = 0; $i < $vacount; $i += 2)
self.set($vaarg[$i], $vaarg[$i+1]);
$endfor
return self;
}
<*
@require $vacount % 2 == 0 "There must be an even number of arguments provided for keys and values"
@require capacity > 0 "The capacity must be 1 or higher"
@require load_factor > 0.0 "The load factor must be higher than 0"
@require !self.allocator "Map was already initialized"
@require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
*>
macro HashMap* HashMap.tinit_with_key_values(&self, ..., uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR)
{
self.tinit(capacity, load_factor);
self.temp_init(capacity, load_factor);
$for (var $i = 0; $i < $vacount; $i += 2)
self.set($vaarg[$i], $vaarg[$i+1]);
$endfor
@@ -148,31 +120,10 @@ macro HashMap* HashMap.tinit_with_key_values(&self, ..., uint capacity = DEFAULT
@require !self.allocator "Map was already initialized"
@require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
*>
fn HashMap* HashMap.temp_init_from_keys_and_values(&self, Key[] keys, Value[] values, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap()) @deprecated("Use tinit_from_keys_and_values")
fn HashMap* HashMap.temp_init_from_keys_and_values(&self, Key[] keys, Value[] values, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap())
{
assert(keys.len == values.len);
self.tinit(capacity, load_factor);
for (usz i = 0; i < keys.len; i++)
{
self.set(keys[i], values[i]);
}
return self;
}
<*
@param [in] keys "The keys for the HashMap entries"
@param [in] values "The values for the HashMap entries"
@param [&inout] allocator "The allocator to use"
@require keys.len == values.len "Both keys and values arrays must be the same length"
@require capacity > 0 "The capacity must be 1 or higher"
@require load_factor > 0.0 "The load factor must be higher than 0"
@require !self.allocator "Map was already initialized"
@require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
*>
fn HashMap* HashMap.tinit_from_keys_and_values(&self, Key[] keys, Value[] values, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap())
{
assert(keys.len == values.len);
self.tinit(capacity, load_factor);
self.temp_init(capacity, load_factor);
for (usz i = 0; i < keys.len; i++)
{
self.set(keys[i], values[i]);
@@ -194,18 +145,18 @@ fn bool HashMap.is_initialized(&map)
<*
@param [&in] other_map "The map to copy from."
*>
fn HashMap* HashMap.new_init_from_map(&self, HashMap* other_map) @deprecated("Use init_from_map(mem, map)")
fn HashMap* HashMap.new_init_from_map(&self, HashMap* other_map)
{
return self.init_from_map(allocator::heap(), other_map) @inline;
return self.init_from_map(other_map, allocator::heap()) @inline;
}
<*
@param [&inout] allocator "The allocator to use"
@param [&in] other_map "The map to copy from."
*>
fn HashMap* HashMap.init_from_map(&self, Allocator allocator, HashMap* other_map)
fn HashMap* HashMap.init_from_map(&self, HashMap* other_map, Allocator allocator)
{
self.init(allocator, other_map.table.len, other_map.load_factor);
self.new_init(other_map.table.len, other_map.load_factor, allocator);
self.put_all_for_create(other_map);
return self;
}
@@ -213,17 +164,9 @@ fn HashMap* HashMap.init_from_map(&self, Allocator allocator, HashMap* other_map
<*
@param [&in] other_map "The map to copy from."
*>
fn HashMap* HashMap.temp_init_from_map(&map, HashMap* other_map) @deprecated("Use tinit_from_map")
fn HashMap* HashMap.temp_init_from_map(&map, HashMap* other_map)
{
return map.init_from_map(allocator::temp(), other_map) @inline;
}
<*
@param [&in] other_map "The map to copy from."
*>
fn HashMap* HashMap.tinit_from_map(&map, HashMap* other_map)
{
return map.init_from_map(allocator::temp(), other_map) @inline;
return map.init_from_map(other_map, allocator::temp()) @inline;
}
fn bool HashMap.is_empty(&map) @inline
@@ -296,7 +239,7 @@ fn bool HashMap.set(&map, Key key, Value value) @operator([]=)
// If the map isn't initialized, use the defaults to initialize it.
if (!map.allocator)
{
map.init(allocator::heap());
map.new_init();
}
uint hash = rehash(key.hash());
uint index = index_for(hash, map.table.len);
@@ -503,18 +446,6 @@ fn void HashMap.resize(&map, uint new_capacity) @private
map.threshold = (uint)(new_capacity * map.load_factor);
}
fn usz! HashMap.to_format(&self, Formatter* f) @dynamic
{
usz len;
len += f.print("{ ")!;
self.@each_entry(; Entry* entry)
{
if (len > 2) len += f.print(", ")!;
len += f.printf("%s: %s", entry.key, entry.value)!;
};
return len + f.print(" }");
}
fn void HashMap.transfer(&map, Entry*[] new_table) @private
{
Entry*[] src = map.table;

View File

@@ -33,24 +33,19 @@ fn LinkedList* LinkedList.init(&self, Allocator allocator)
<*
@return "the initialized list"
*>
fn LinkedList* LinkedList.new_init(&self) @deprecated("Use init(mem)")
fn LinkedList* LinkedList.new_init(&self)
{
return self.init(allocator::heap()) @inline;
}
fn LinkedList* LinkedList.temp_init(&self) @deprecated("Use tinit()")
{
return self.init(allocator::temp()) @inline;
}
fn LinkedList* LinkedList.tinit(&self)
fn LinkedList* LinkedList.temp_init(&self)
{
return self.init(allocator::temp()) @inline;
}
<*
@require self.allocator != null
@require self.allocator
*>
macro void LinkedList.free_node(&self, Node* node) @private
{
@@ -205,7 +200,7 @@ fn void LinkedList.link_before(&self, Node *succ, Type value) @private
}
<*
@require self._first != null
@require self._first
*>
fn void LinkedList.unlink_first(&self) @private
{
@@ -301,7 +296,7 @@ fn bool LinkedList.remove_last_match(&self, Type t) @if(ELEMENT_IS_EQUATABLE)
return false;
}
<*
@require self._last != null
@require self._last
*>
fn void LinkedList.unlink_last(&self) @inline @private
{

View File

@@ -23,21 +23,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.init(&self, Allocator allocator, usz initial_capacity = 16)
{
self.allocator = allocator;
self.size = 0;
self.capacity = 0;
self.entries = null;
self.reserve(initial_capacity);
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.new_init(&self, usz initial_capacity = 16, Allocator allocator = allocator::heap()) @deprecated("Use init(mem)")
fn List* List.new_init(&self, usz initial_capacity = 16, Allocator allocator = allocator::heap())
{
self.allocator = allocator;
self.size = 0;
@@ -52,19 +38,9 @@ fn List* List.new_init(&self, usz initial_capacity = 16, Allocator allocator = a
@param initial_capacity "The initial capacity to reserve"
*>
fn List* List.temp_init(&self, usz initial_capacity = 16) @deprecated("Use tinit()")
fn List* List.temp_init(&self, usz initial_capacity = 16)
{
return self.init(allocator::temp(), initial_capacity) @inline;
}
<*
Initialize the list using the temp allocator.
@param initial_capacity "The initial capacity to reserve"
*>
fn List* List.tinit(&self, usz initial_capacity = 16)
{
return self.init(allocator::temp(), initial_capacity) @inline;
return self.new_init(initial_capacity, allocator::temp()) @inline;
}
<*
@@ -73,20 +49,9 @@ fn List* List.tinit(&self, usz initial_capacity = 16)
@param [in] values `The values to initialize the list with.`
@require self.size == 0 "The List must be empty"
*>
fn List* List.new_init_with_array(&self, Type[] values, Allocator allocator = allocator::heap()) @deprecated("Use init_with_array(mem)")
fn List* List.new_init_with_array(&self, Type[] values, Allocator allocator = allocator::heap())
{
return self.init_with_array(allocator, values);
}
<*
Initialize a new list with an array.
@param [in] values `The values to initialize the list with.`
@require self.size == 0 "The List must be empty"
*>
fn List* List.init_with_array(&self, Allocator allocator, Type[] values)
{
self.init(allocator, values.len) @inline;
self.new_init(values.len, allocator) @inline;
self.add_array(values) @inline;
return self;
}
@@ -97,22 +62,9 @@ fn List* List.init_with_array(&self, Allocator allocator, Type[] values)
@param [in] values `The values to initialize the list with.`
@require self.size == 0 "The List must be empty"
*>
fn List* List.temp_init_with_array(&self, Type[] values) @deprecated("Use tinit_with_array()")
fn List* List.temp_init_with_array(&self, Type[] values)
{
self.tinit(values.len) @inline;
self.add_array(values) @inline;
return self;
}
<*
Initialize a temporary list with an array.
@param [in] values `The values to initialize the list with.`
@require self.size == 0 "The List must be empty"
*>
fn List* List.tinit_with_array(&self, Type[] values)
{
self.tinit(values.len) @inline;
self.temp_init(values.len) @inline;
self.add_array(values) @inline;
return self;
}
@@ -268,11 +220,11 @@ fn void List.push_front(&self, Type type) @inline
fn void List.insert_at(&self, usz index, Type type)
{
self.reserve(1);
self.set_size(self.size + 1);
for (isz i = self.size - 1; i > index; i--)
for (usz i = self.size; i > index; i--)
{
self.entries[i] = self.entries[i - 1];
}
self.set_size(self.size + 1);
self.entries[index] = type;
}
@@ -376,8 +328,7 @@ fn usz List.retain_if(&self, ElementPredicate selection)
fn usz List.remove_using_test(&self, ElementTest filter, any context)
{
usz old_size = self.size;
defer
{
defer {
if (old_size != self.size) self._update_size_change(old_size, self.size);
}
return list_common::list_remove_using_test(self, filter, false, context);
@@ -474,7 +425,7 @@ macro void List.pre_free(&self) @private
}
<*
@require self.capacity > 0
@require self.capacity
*>
macro void List.post_alloc(&self) @private
{

View File

@@ -5,7 +5,7 @@ module std::collections::list_common;
*>
macro list_to_new_aligned_array($Type, self, Allocator allocator)
{
if (!self.size) return ($Type[]){};
if (!self.size) return $Type[] {};
$Type[] result = allocator::alloc_array_aligned(allocator, $Type, self.size);
result[..] = self.entries[:self.size];
return result;
@@ -13,7 +13,7 @@ macro list_to_new_aligned_array($Type, self, Allocator allocator)
macro list_to_new_array($Type, self, Allocator allocator)
{
if (!self.size) return ($Type[]){};
if (!self.size) return $Type[] {};
$Type[] result = allocator::alloc_array(allocator, $Type, self.size);
result[..] = self.entries[:self.size];
return result;

View File

@@ -26,7 +26,7 @@ struct MapImpl
@require load_factor > 0.0 "The load factor must be higher than 0"
@require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
*>
fn Map new(uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap()) @deprecated("Map is deprecated")
fn Map new(uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator allocator = allocator::heap())
{
MapImpl* map = allocator::alloc(allocator, MapImpl);
_init(map, capacity, load_factor, allocator);

View File

@@ -1,43 +1,16 @@
module std::collections::maybe(<Type>);
import std::io;
struct Maybe (Printable)
struct Maybe
{
Type value;
bool has_value;
}
fn usz! Maybe.to_format(&self, Formatter* f) @dynamic
{
if (self.has_value) return f.printf("[%s]", self.value);
return f.printf("[EMPTY]");
}
fn void Maybe.set(&self, Type val)
{
*self = { .value = val, .has_value = true };
}
fn void Maybe.reset(&self)
{
*self = {};
}
fn Maybe value(Type val)
{
return { .value = val, .has_value = true };
}
fn Maybe Maybe.with_value(Type val) @deprecated("Use maybe::value instead.") @operator(construct)
{
return { .value = val, .has_value = true };
}
fn Maybe Maybe.empty() @deprecated("Use maybe::EMPTY instead.") @operator(construct)
{
return { };
}
const Maybe EMPTY = { };
macro Type! Maybe.get(self)

View File

@@ -156,7 +156,7 @@ fn void Object.init_map_if_needed(&self) @private
if (self.is_empty())
{
self.type = ObjectInternalMap.typeid;
self.map.init(self.allocator);
self.map.new_init(allocator: self.allocator);
}
}
@@ -168,7 +168,7 @@ fn void Object.init_array_if_needed(&self) @private
if (self.is_empty())
{
self.type = ObjectInternalList.typeid;
self.array.init(self.allocator);
self.array.new_init(allocator: self.allocator);
}
}

View File

@@ -36,11 +36,6 @@ struct PrivatePriorityQueue (Printable)
Heap heap;
}
fn void PrivatePriorityQueue.init(&self, Allocator allocator, usz initial_capacity = 16, ) @inline
{
self.heap.new_init(initial_capacity, allocator);
}
fn void PrivatePriorityQueue.new_init(&self, usz initial_capacity = 16, Allocator allocator = allocator::heap()) @inline
{
self.heap.new_init(initial_capacity, allocator);

View File

@@ -71,21 +71,23 @@ import std::io;
@param [in] input `The raw RGB or RGBA pixels to encode`
@param [&in] desc `The descriptor of the image`
*>
fn usz! write(String filename, char[] input, QOIDesc* desc) => @pool()
fn usz! write(String filename, char[] input, QOIDesc* desc)
{
// encode data
char[] output = new_encode(input, desc, allocator: allocator::temp())!;
@pool() {
// encode data
char[] output = encode(input, desc)!;
// open file
File! f = file::open(filename, "wb");
if (catch f) return QOIError.FILE_OPEN_FAILED?;
// open file
File! f = file::open(filename, "wb");
if (catch f) { return QOIError.FILE_OPEN_FAILED?; }
// write data to file and close it
usz! written = f.write(output);
if (catch written) return QOIError.FILE_WRITE_FAILED?;
if (catch f.close()) return QOIError.FILE_WRITE_FAILED?;
// write data to file and close it
usz! written = f.write(output);
if (catch written) { return QOIError.FILE_WRITE_FAILED?; }
if (catch f.close()) { return QOIError.FILE_WRITE_FAILED?; }
return written;
return written;
};
}
@@ -110,17 +112,15 @@ fn usz! write(String filename, char[] input, QOIDesc* desc) => @pool()
@param [&out] desc `The descriptor to fill with the image's info`
@param channels `The channels to be used`
*>
fn char[]! new_read(String filename, QOIDesc* desc, QOIChannels channels = AUTO, Allocator allocator = allocator::heap()) => @pool(allocator)
fn char[]! read(String filename, QOIDesc* desc, QOIChannels channels = AUTO, Allocator allocator = allocator::heap())
{
// read file
char[] data = file::load_temp(filename) ?? QOIError.FILE_OPEN_FAILED?!;
// pass data to decode function
return new_decode(data, desc, channels, allocator);
}
char[]! data = file::load_new(filename);
if (catch data) return QOIError.FILE_OPEN_FAILED?;
defer mem::free(data);
fn char[]! read(String filename, QOIDesc* desc, QOIChannels channels = AUTO, Allocator allocator = allocator::heap()) @deprecated("Use new_read")
{
return new_read(filename, desc, channels, allocator);
// pass data to decode function
return decode(data, desc, channels, allocator);
}
@@ -128,11 +128,6 @@ fn char[]! read(String filename, QOIDesc* desc, QOIChannels channels = AUTO, All
module std::compression::qoi;
import std::bits;
fn char[]! encode(char[] input, QOIDesc* desc, Allocator allocator = allocator::heap()) @deprecated("use encode_new")
{
return new_encode(input, desc, allocator);
}
<*
Encode raw RGB or RGBA pixels into a QOI image in memory.
@@ -146,7 +141,7 @@ fn char[]! encode(char[] input, QOIDesc* desc, Allocator allocator = allocator::
@param [in] input `The raw RGB or RGBA pixels to encode`
@param [&in] desc `The descriptor of the image`
*>
fn char[]! new_encode(char[] input, QOIDesc* desc, Allocator allocator = allocator::heap()) @nodiscard
fn char[]! encode(char[] input, QOIDesc* desc, Allocator allocator = allocator::heap())
{
// check info in desc
if (desc.width == 0 || desc.height == 0) return QOIError.INVALID_PARAMETERS?;
@@ -196,77 +191,70 @@ fn char[]! new_encode(char[] input, QOIDesc* desc, Allocator allocator = allocat
if (desc.channels == RGBA) p.a = input[loc + 3];
// check if we can run the previous pixel
if (prev == p)
{
if (prev == p) {
run_length++;
if (run_length == 62 || loc == loc_end)
{
if (run_length == 62 || loc == loc_end) {
*@extract(OpRun, output, &pos) = { OP_RUN, run_length - 1 };
run_length = 0;
}
} else {
// end last run if there was one
if (run_length > 0) {
*@extract(OpRun, output, &pos) = { OP_RUN, run_length - 1 };
run_length = 0;
}
continue;
}
// end last run if there was one
if (run_length > 0)
{
*@extract(OpRun, output, &pos) = { OP_RUN, run_length - 1 };
run_length = 0;
}
switch
{
// check if we can index the palette
case (palette[p.hash()] == p):
*@extract(OpIndex, output, &pos) = {
OP_INDEX,
p.hash()
};
// check if we can use diff or luma
case (prev != p && prev.a == p.a):
// diff the pixels
diff = p.rgb - prev.rgb;
if (diff.r > -3 && diff.r < 2
&& diff.g > -3 && diff.g < 2
&& diff.b > -3 && diff.b < 2)
{
*@extract(OpDiff, output, &pos) = {
OP_DIFF,
(char)diff.r + 2,
(char)diff.g + 2,
(char)diff.b + 2
switch {
// check if we can index the palette
case (palette[p.hash()] == p):
*@extract(OpIndex, output, &pos) = {
OP_INDEX,
p.hash()
};
palette[p.hash()] = p;
break;
}
// check luma eligibility
luma = { diff.r - diff.g, diff.g, diff.b - diff.g };
if (luma.r >= -8 && luma.r <= 7
&& luma.g >= -32 && luma.g <= 31
&& luma.b >= -8 && luma.b <= 7)
{
*@extract(OpLuma, output, &pos) = {
OP_LUMA,
(char)luma.g + 32,
(char)luma.r + 8,
(char)luma.b + 8
};
palette[p.hash()] = p;
break;
}
nextcase;
// worst case scenario: just encode the raw pixel
default:
if (prev.a != p.a)
{
*@extract(OpRGBA, output, &pos) = { OP_RGBA, p.r, p.g, p.b, p.a };
}
else
{
*@extract(OpRGB, output, &pos) = { OP_RGB, p.r, p.g, p.b };
}
palette[p.hash()] = p;
// check if we can use diff or luma
case (prev != p && prev.a == p.a):
// diff the pixels
diff = p.rgb - prev.rgb;
if (
diff.r > -3 && diff.r < 2 &&
diff.g > -3 && diff.g < 2 &&
diff.b > -3 && diff.b < 2
) {
*@extract(OpDiff, output, &pos) = {
OP_DIFF,
(char)diff.r + 2,
(char)diff.g + 2,
(char)diff.b + 2
};
palette[p.hash()] = p;
} else {
// check luma eligibility
luma = { diff.r - diff.g, diff.g, diff.b - diff.g };
if (
luma.r >= -8 && luma.r <= 7 &&
luma.g >= -32 && luma.g <= 31 &&
luma.b >= -8 && luma.b <= 7
) {
*@extract(OpLuma, output, &pos) = {
OP_LUMA,
(char)luma.g + 32,
(char)luma.r + 8,
(char)luma.b + 8
};
palette[p.hash()] = p;
} else { nextcase; }
}
// worst case scenario: just encode the raw pixel
default:
if (prev.a != p.a) {
*@extract(OpRGBA, output, &pos) = { OP_RGBA, p.r, p.g, p.b, p.a };
} else {
*@extract(OpRGB, output, &pos) = { OP_RGB, p.r, p.g, p.b };
}
palette[p.hash()] = p;
}
}
}
@@ -278,11 +266,6 @@ fn char[]! new_encode(char[] input, QOIDesc* desc, Allocator allocator = allocat
}
fn char[]! decode(char[] data, QOIDesc* desc, QOIChannels channels = AUTO, Allocator allocator = allocator::heap())
{
return new_decode(data, desc, channels, allocator);
}
<*
Decode a QOI image from memory.
@@ -304,7 +287,7 @@ fn char[]! decode(char[] data, QOIDesc* desc, QOIChannels channels = AUTO, Alloc
@param [&out] desc `The descriptor to fill with the image's info`
@param channels `The channels to be used`
*>
fn char[]! new_decode(char[] data, QOIDesc* desc, QOIChannels channels = AUTO, Allocator allocator = allocator::heap()) @nodiscard
fn char[]! decode(char[] data, QOIDesc* desc, QOIChannels channels = AUTO, Allocator allocator = allocator::heap())
{
// check input data
if (data.len < Header.sizeof + END_OF_STREAM.len) return QOIError.INVALID_DATA?;
@@ -426,21 +409,19 @@ struct Header @packed
char colorspace; // 0 = sRGB with linear alpha, 1 = all channels linear
}
const char[?] END_OF_STREAM = {0, 0, 0, 0, 0, 0, 0, 1};
const char[*] END_OF_STREAM = {0, 0, 0, 0, 0, 0, 0, 1};
// inefficient, but it's only run once at a time
macro @enumcast($Type, raw)
{
foreach (value : $Type.values)
{
foreach (value : $Type.values) {
if (value.id == raw) return value;
}
return QOIError.INVALID_DATA?;
}
distinct Pixel = inline char[<4>];
macro char Pixel.hash(Pixel p)
{
macro char Pixel.hash(Pixel p) {
return (p.r * 3 + p.g * 5 + p.b * 7 + p.a * 11) % 64;
}
@@ -471,7 +452,7 @@ bitstruct OpDiff : char
char diff_green : 2..3;
char diff_blue : 0..1;
}
bitstruct OpLuma : ushort @align(1)
bitstruct OpLuma : ushort
{
char tag : 6..7;
char diff_green : 0..5;

View File

@@ -28,12 +28,7 @@ fn void ArenaAllocator.clear(&self)
struct ArenaAllocatorHeader @local
{
usz size;
char[?] data;
}
macro ArenaAllocator* wrap(char[] bytes)
{
return (ArenaAllocator){}.init(bytes);
char[*] data;
}
<*

View File

@@ -61,8 +61,8 @@ struct DynamicArenaChunk @local
}
<*
@require ptr != null
@require self.page != null `tried to free pointer on invalid allocator`
@require ptr
@require self.page `tried to free pointer on invalid allocator`
*>
fn void DynamicArenaAllocator.release(&self, void* ptr, bool) @dynamic
{
@@ -77,7 +77,7 @@ fn void DynamicArenaAllocator.release(&self, void* ptr, bool) @dynamic
<*
@require size > 0 `Resize doesn't support zeroing`
@require old_pointer != null `Resize doesn't handle null pointers`
@require self.page != null `tried to realloc pointer on invalid allocator`
@require self.page `tried to realloc pointer on invalid allocator`
*>
fn void*! DynamicArenaAllocator.resize(&self, void* old_pointer, usz size, usz alignment) @dynamic
{
@@ -164,21 +164,14 @@ fn void*! DynamicArenaAllocator.acquire(&self, usz size, AllocInitType init_type
{
alignment = alignment_for_allocation(alignment);
DynamicArenaPage* page = self.page;
void* ptr @noinit;
do SET_DONE:
{
void* ptr = {|
if (!page && self.unused_page)
{
self.page = page = self.unused_page;
self.unused_page = page.prev_arena;
page.prev_arena = null;
}
if (!page)
{
ptr = self._alloc_new(size, alignment)!;
break SET_DONE;
}
if (!page) return self._alloc_new(size, alignment);
void* start = mem::aligned_pointer(page.memory + page.used + DynamicArenaChunk.sizeof, alignment);
usz new_used = start - page.memory + size;
if ALLOCATE_NEW: (new_used > page.total)
@@ -195,15 +188,15 @@ fn void*! DynamicArenaAllocator.acquire(&self, usz size, AllocInitType init_type
break ALLOCATE_NEW;
}
}
ptr = self._alloc_new(size, alignment)!;
break SET_DONE;
return self._alloc_new(size, alignment);
}
page.used = new_used;
assert(start + size == page.memory + page.used);
ptr = start;
DynamicArenaChunk* chunk = (DynamicArenaChunk*)ptr - 1;
void* mem = start;
DynamicArenaChunk* chunk = (DynamicArenaChunk*)mem - 1;
chunk.size = size;
};
return mem;
|}!;
if (init_type == ZERO) mem::clear(ptr, size, mem::DEFAULT_MEM_ALIGNMENT);
return ptr;
}

View File

@@ -12,7 +12,7 @@ struct SimpleHeapAllocator (Allocator)
}
<*
@require allocator != null "An underlying memory provider must be given"
@require allocator "An underlying memory provider must be given"
@require !self.free_list "The allocator may not be already initialized"
*>
fn void SimpleHeapAllocator.init(&self, MemoryAllocFn allocator)

View File

@@ -52,11 +52,11 @@ fn void OnStackAllocator.free(&self)
struct OnStackAllocatorHeader
{
usz size;
char[?] data;
char[*] data;
}
<*
@require old_pointer != null
@require old_pointer
*>
fn void OnStackAllocator.release(&self, void* old_pointer, bool aligned) @dynamic
{

View File

@@ -4,7 +4,7 @@ import std::io, std::math;
struct TempAllocatorChunk @local
{
usz size;
char[?] data;
char[*] data;
}
struct TempAllocator (Allocator)
@@ -13,7 +13,7 @@ struct TempAllocator (Allocator)
TempAllocatorPage* last_page;
usz used;
usz capacity;
char[?] data;
char[*] data;
}
const usz PAGE_IS_ALIGNED @private = (usz)isz.max + 1u;
@@ -26,7 +26,7 @@ struct TempAllocatorPage
usz mark;
usz size;
usz ident;
char[?] data;
char[*] data;
}
macro usz TempAllocatorPage.pagesize(&self) => self.size & ~PAGE_IS_ALIGNED;
@@ -80,7 +80,7 @@ fn void TempAllocator.reset(&self, usz mark) @dynamic
usz cleaned = self.used - mark;
if (cleaned > 0)
{
$if env::COMPILER_SAFE_MODE && !env::ADDRESS_SANITIZER:
$if env::COMPILER_SAFE_MODE:
self.data[mark : cleaned] = 0xAA;
$endif
asan::poison_memory_region(&self.data[mark], cleaned);

View File

@@ -34,7 +34,7 @@ struct TrackingAllocator (Allocator)
fn void TrackingAllocator.init(&self, Allocator allocator)
{
*self = { .inner_allocator = allocator };
self.map.init(allocator);
self.map.new_init(allocator: allocator);
}
<*
@@ -49,10 +49,13 @@ fn void TrackingAllocator.free(&self)
<*
@return "the total allocated memory not yet freed."
*>
fn usz TrackingAllocator.allocated(&self) => @pool()
fn usz TrackingAllocator.allocated(&self)
{
usz allocated = 0;
foreach (&allocation : self.map.value_tlist()) allocated += allocation.size;
@pool()
{
foreach (&allocation : self.map.value_tlist()) allocated += allocation.size;
};
return allocated;
}
@@ -113,103 +116,101 @@ fn void TrackingAllocator.clear(&self)
self.map.clear();
}
fn bool TrackingAllocator.has_leaks(&self)
{
return self.map.len() > 0;
}
fn void TrackingAllocator.print_report(&self) => self.fprint_report(io::stdout())!!;
fn void! TrackingAllocator.fprint_report(&self, OutStream out) => @pool()
fn void! TrackingAllocator.fprint_report(&self, OutStream out)
{
usz total = 0;
usz entries = 0;
bool leaks = false;
Allocation[] allocs = self.map.value_tlist();
if (allocs.len)
@pool()
{
if (!allocs[0].backtrace[0])
Allocation[] allocs = self.map.value_tlist();
if (allocs.len)
{
io::fprintn(out, "======== Memory Report ========")!;
io::fprintn(out, "Size in bytes Address")!;
foreach (i, &allocation : allocs)
if (!allocs[0].backtrace[0])
{
entries++;
total += allocation.size;
io::fprintfn(out, "%13s %p", allocation.size, allocation.ptr)!;
}
io::fprintn(out, "===============================")!;
io::fprintn(out, "======== Memory Report ========")!;
io::fprintn(out, "Size in bytes Address")!;
foreach (i, &allocation : allocs)
{
entries++;
total += allocation.size;
io::fprintfn(out, "%13s %p", allocation.size, allocation.ptr)!;
}
io::fprintn(out, "===============================")!;
}
else
{
io::fprintn(out, "================================== Memory Report ==================================")!;
io::fprintn(out, "Size in bytes Address Function ")!;
foreach (i, &allocation : allocs)
{
entries++;
total += allocation.size;
BacktraceList backtraces = {};
Backtrace trace = backtrace::BACKTRACE_UNKNOWN;
if (allocation.backtrace[3])
{
trace = backtrace::symbolize_backtrace(allocation.backtrace[3:1], allocator::temp()).get(0) ?? backtrace::BACKTRACE_UNKNOWN;
}
if (trace.function.len) leaks = true;
io::fprintfn(out, "%13s %p %s:%d", allocation.size,
allocation.ptr, trace.function.len ? trace.function : "???",
trace.line ? trace.line : 0)!;
}
io::fprintn(out, "===================================================================================")!;
}
}
else
{
io::fprintn(out, "================================== Memory Report ==================================")!;
io::fprintn(out, "Size in bytes Address Function ")!;
io::fprintn(out, "* NO ALLOCATIONS FOUND *")!;
}
io::fprintfn(out, "- Total currently allocated memory: %d", total)!;
io::fprintfn(out, "- Total current allocations: %d", entries)!;
io::fprintfn(out, "- Total allocations (freed and retained): %d", self.allocs_total)!;
io::fprintfn(out, "- Total allocated memory (freed and retained): %d", self.mem_total)!;
if (leaks)
{
io::fprintn(out)!;
io::fprintn(out, "Full leak report:")!;
foreach (i, &allocation : allocs)
{
entries++;
total += allocation.size;
if (!allocation.backtrace[3])
{
io::fprintfn(out, "Allocation %d (%d bytes) - no backtrace available.", i + 1, allocation.size)!;
continue;
}
BacktraceList backtraces = {};
Backtrace trace = backtrace::BACKTRACE_UNKNOWN;
if (allocation.backtrace[3])
usz end = MAX_BACKTRACE;
foreach (j, val : allocation.backtrace)
{
trace = backtrace::symbolize_backtrace(allocation.backtrace[3:1], allocator::temp()).get(0) ?? backtrace::BACKTRACE_UNKNOWN;
if (!val)
{
end = j;
break;
}
}
if (trace.function.len) leaks = true;
io::fprintfn(out, "%13s %p %s:%d", allocation.size,
allocation.ptr, trace.function.len ? trace.function : "???",
trace.line ? trace.line : 0)!;
}
io::fprintn(out, "===================================================================================")!;
}
}
else
{
io::fprintn(out, "* NO ALLOCATIONS FOUND *")!;
}
io::fprintfn(out, "- Total currently allocated memory: %d", total)!;
io::fprintfn(out, "- Total current allocations: %d", entries)!;
io::fprintfn(out, "- Total allocations (freed and retained): %d", self.allocs_total)!;
io::fprintfn(out, "- Total allocated memory (freed and retained): %d", self.mem_total)!;
if (leaks)
{
io::fprintn(out)!;
io::fprintn(out, "Full leak report:")!;
foreach (i, &allocation : allocs)
{
if (!allocation.backtrace[3])
{
io::fprintfn(out, "Allocation %d (%d bytes) - no backtrace available.", i + 1, allocation.size)!;
continue;
}
BacktraceList backtraces = {};
usz end = MAX_BACKTRACE;
foreach (j, val : allocation.backtrace)
{
if (!val)
BacktraceList list = backtrace::symbolize_backtrace(allocation.backtrace[3..(end - 1)], allocator::temp())!;
io::fprintfn(out, "Allocation %d (%d bytes): ", i + 1, allocation.size)!;
foreach (trace : list)
{
end = j;
break;
if (trace.has_file())
{
io::fprintfn(out, " %s (in %s:%d)", trace.function, trace.file, trace.line);
continue;
}
if (trace.is_unknown())
{
io::fprintfn(out, " ??? (in unknown)");
continue;
}
io::fprintfn(out, " %s (source unavailable)", trace.function);
}
}
BacktraceList list = backtrace::symbolize_backtrace(allocation.backtrace[3..(end - 1)], allocator::temp())!;
io::fprintfn(out, "Allocation %d (%d bytes): ", i + 1, allocation.size)!;
foreach (trace : list)
{
if (trace.has_file())
{
io::fprintfn(out, " %s (in %s:%d)", trace.function, trace.file, trace.line);
continue;
}
if (trace.is_unknown())
{
io::fprintfn(out, " ??? (in unknown)");
continue;
}
io::fprintfn(out, " %s (source unavailable)", trace.function);
}
}
}
};
}

View File

@@ -79,7 +79,7 @@ macro concat(arr1, arr2, Allocator allocator) @nodiscard
@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 return.len == arr1.len + arr2.len
@ensure result.len == arr1.len + arr2.len
*>
macro concat_new(arr1, arr2, Allocator allocator = allocator::heap()) @nodiscard
{
@@ -95,7 +95,7 @@ macro concat_new(arr1, arr2, Allocator allocator = allocator::heap()) @nodiscard
@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 return.len == arr1.len + arr2.len
@ensure result.len == arr1.len + arr2.len
*>
macro tconcat(arr1, arr2) @nodiscard => concat(arr1, arr2, allocator::temp());

View File

@@ -26,25 +26,24 @@ def VoidFn = fn void();
Stores a variable on the stack, then restores it at the end of the
macro scope.
@param #variable `the variable to store and restore`
@require values::@is_lvalue(#variable)
@param variable `the variable to store and restore`
*>
macro void @scope(#variable; @body) @builtin
macro void @scope(&variable; @body) @builtin
{
var temp = #variable;
defer #variable = temp;
var temp = *variable;
defer *variable = temp;
@body();
}
<*
Swap two variables
@require $defined(#a = #b, #b = #a) `The values must be mutually assignable`
@require $assignable(*b, $typeof(*a)) && $assignable(*a, $typeof(*b))
*>
macro void @swap(#a, #b) @builtin
macro void @swap(&a, &b) @builtin
{
var temp = #a;
#a = #b;
#b = temp;
var temp = *a;
*a = *b;
*b = temp;
}
<*
@@ -62,43 +61,45 @@ macro anycast(any v, $Type) @builtin
return ($Type*)v.ptr;
}
fn bool print_backtrace(String message, int backtraces_to_ignore) @if(env::NATIVE_STACKTRACE) => @pool()
fn bool print_backtrace(String message, int backtraces_to_ignore) @if(env::NATIVE_STACKTRACE)
{
void*[256] buffer;
void*[] backtraces = backtrace::capture_current(&buffer);
backtraces_to_ignore++;
BacktraceList! backtrace = backtrace::symbolize_backtrace(backtraces, allocator::temp());
if (catch backtrace) return false;
if (backtrace.len() <= backtraces_to_ignore) return false;
io::eprint("\nERROR: '");
io::eprint(message);
io::eprintn("'");
foreach (i, &trace : backtrace)
@pool()
{
if (i < backtraces_to_ignore) continue;
String inline_suffix = trace.is_inline ? " [inline]" : "";
if (trace.is_unknown())
void*[256] buffer;
void*[] backtraces = backtrace::capture_current(&buffer);
backtraces_to_ignore++;
BacktraceList! backtrace = backtrace::symbolize_backtrace(backtraces, allocator::temp());
if (catch backtrace) return false;
if (backtrace.len() <= backtraces_to_ignore) return false;
io::eprint("\nERROR: '");
io::eprint(message);
io::eprintn("'");
foreach (i, &trace : backtrace)
{
io::eprintfn(" in ???%s", inline_suffix);
continue;
if (i < backtraces_to_ignore) continue;
String inline_suffix = trace.is_inline ? " [inline]" : "";
if (trace.is_unknown())
{
io::eprintfn(" in ???%s", inline_suffix);
continue;
}
if (trace.has_file())
{
io::eprintfn(" in %s (%s:%d) [%s]%s", trace.function, trace.file, trace.line, trace.object_file, inline_suffix);
continue;
}
io::eprintfn(" in %s (source unavailable) [%s]%s", trace.function, trace.object_file, inline_suffix);
}
if (trace.has_file())
{
io::eprintfn(" in %s (%s:%d) [%s]%s", trace.function, trace.file, trace.line, trace.object_file, inline_suffix);
continue;
}
io::eprintfn(" in %s (source unavailable) [%s]%s", trace.function, trace.object_file, inline_suffix);
}
return true;
return true;
};
}
fn void default_panic(String message, String file, String function, uint line) @if(env::NATIVE_STACKTRACE)
{
$if $defined(io::stderr):
if (!print_backtrace(message, 2))
{
io::eprintfn("\nERROR: '%s', in %s (%s:%d)", message, function, file, line);
return;
}
$endif
$$trap();
@@ -146,7 +147,7 @@ fn void panicf(String fmt, String file, String function, uint line, args...)
@stack_mem(512; Allocator allocator)
{
DString s;
s.init(allocator);
s.new_init(allocator: allocator);
s.appendf(fmt, ...args);
in_panic = false;
panic(s.str_view(), file, function, line);
@@ -237,8 +238,8 @@ macro enum_by_name($Type, String enum_name) @builtin
<*
@param $Type `The type of the enum`
@require $Type.kindof == ENUM `Only enums may be used`
@require $defined($Type.#value) `Expected '#value' to match an enum associated value`
@require $assignable(value, $typeof(($Type){}.#value)) `Expected the value to match the type of the associated value`
@require $defined($Type.#value1) `Expected '#value' to match an enum associated value`
@require $assignable(value, $typeof($Type{}.#value)) `Expected the value to match the type of the associated value`
@ensure @typeis(return, $Type)
@return! SearchResult.MISSING
*>
@@ -351,7 +352,7 @@ macro swizzle2(v, v2, ...) @builtin
macro anyfault @catch(#expr) @builtin
{
if (catch f = #expr) return f;
return {};
return anyfault {};
}
<*
@@ -366,12 +367,9 @@ macro bool @ok(#expr) @builtin
return true;
}
<*
@require $defined(&#value, (char*)&#value) "This must be a value that can be viewed as a char array"
*>
macro char[] @as_char_view(#value) @builtin
macro char[] @as_char_view(&value) @builtin
{
return ((char*)&#value)[:$sizeof(#value)];
return ((char*)value)[:$sizeof(*value)];
}
macro isz @str_find(String $string, String $needle) @builtin => $$str_find($string, $needle);
@@ -379,39 +377,21 @@ macro String @str_upper(String $str) @builtin => $$str_upper($str);
macro String @str_lower(String $str) @builtin => $$str_lower($str);
macro uint @str_hash(String $str) @builtin => $$str_hash($str);
macro @generic_hash_core(h, value)
{
h ^= (uint)value; // insert lowest 32 bits
h *= 0x96f59e5b; // diffuse them up
h ^= h >> 16; // diffuse them down
return h;
}
macro @generic_hash(value)
{
uint h = @generic_hash_core((uint)0x3efd4391, value);
$for (var $cnt = 4; $cnt < $sizeof(value); $cnt += 4)
value >>= 32; // reduce value
h = @generic_hash_core(h, value);
$endfor
return h;
}
macro uint int.hash(int i) => @generic_hash(i);
macro uint uint.hash(uint i) => @generic_hash(i);
macro uint short.hash(short s) => @generic_hash(s);
macro uint ushort.hash(ushort s) => @generic_hash(s);
macro uint char.hash(char c) => @generic_hash(c);
macro uint ichar.hash(ichar c) => @generic_hash(c);
macro uint long.hash(long i) => @generic_hash(i);
macro uint ulong.hash(ulong i) => @generic_hash(i);
macro uint int128.hash(int128 i) => @generic_hash(i);
macro uint uint128.hash(uint128 i) => @generic_hash(i);
macro uint bool.hash(bool b) => @generic_hash(b);
macro uint typeid.hash(typeid t) => @generic_hash(((ulong)(uptr)t));
macro uint int.hash(int i) => i;
macro uint uint.hash(uint i) => i;
macro uint short.hash(short s) => s;
macro uint ushort.hash(ushort s) => s;
macro uint char.hash(char c) => c;
macro uint ichar.hash(ichar c) => c;
macro uint long.hash(long i) => (uint)((i >> 32) ^ i);
macro uint ulong.hash(ulong i) => (uint)((i >> 32) ^ i);
macro uint int128.hash(int128 i) => (uint)((i >> 96) ^ (i >> 64) ^ (i >> 32) ^ i);
macro uint uint128.hash(uint128 i) => (uint)((i >> 96) ^ (i >> 64) ^ (i >> 32) ^ i);
macro uint bool.hash(bool b) => (uint)b;
macro uint typeid.hash(typeid t) => ((ulong)(uptr)t).hash();
macro uint String.hash(String c) => (uint)fnv32a::encode(c);
macro uint char[].hash(char[] c) => (uint)fnv32a::encode(c);
macro uint void*.hash(void* ptr) => @generic_hash(((ulong)(uptr)ptr));
macro uint void*.hash(void* ptr) => ((ulong)(uptr)ptr).hash();
distinct EmptySlot = void*;
const EmptySlot EMPTY_MACRO_SLOT @builtin = null;

View File

@@ -29,7 +29,7 @@ def CUChar = char;
def CChar = $typefrom($$C_CHAR_IS_SIGNED ? ichar.typeid : char.typeid);
enum CBool : char
enum CBool : CInt
{
FALSE,
TRUE

View File

@@ -9,7 +9,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()) @deprecated("Use init(mem)")
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)!!;
@@ -22,37 +22,15 @@ fn DString DString.new_init(&self, usz capacity = MIN_CAPACITY, Allocator alloca
<*
@require !self.data() "String already initialized"
*>
fn DString DString.init(&self, Allocator allocator, usz capacity = MIN_CAPACITY)
fn DString DString.temp_init(&self, usz capacity = MIN_CAPACITY)
{
if (capacity < MIN_CAPACITY) capacity = MIN_CAPACITY;
StringData* data = allocator::alloc_with_padding(allocator, StringData, capacity)!!;
data.allocator = allocator;
data.len = 0;
data.capacity = capacity;
return *self = (DString)data;
}
<*
@require !self.data() "String already initialized"
*>
fn DString DString.temp_init(&self, usz capacity = MIN_CAPACITY) @deprecated("Use tinit()")
{
self.init(allocator::temp(), capacity) @inline;
return *self;
}
<*
@require !self.data() "String already initialized"
*>
fn DString DString.tinit(&self, usz capacity = MIN_CAPACITY)
{
self.init(allocator::temp(), capacity) @inline;
self.new_init(capacity, allocator::temp()) @inline;
return *self;
}
fn DString new_with_capacity(usz capacity, Allocator allocator = allocator::heap())
{
return (DString){}.init(allocator, capacity);
return DString{}.new_init(capacity, allocator);
}
fn DString temp_with_capacity(usz capacity) => new_with_capacity(capacity, allocator::temp()) @inline;
@@ -121,25 +99,16 @@ fn void DString.replace(&self, String needle, String replacement)
};
}
fn DString DString.new_concat(self, DString b, Allocator allocator = allocator::heap()) @deprecated("Use concat(mem)")
fn DString DString.new_concat(self, DString b, Allocator allocator = allocator::heap())
{
DString string;
string.init(allocator, self.len() + b.len());
string.new_init(self.len() + b.len(), allocator);
string.append(self);
string.append(b);
return string;
}
fn DString DString.concat(self, Allocator allocator, DString b)
{
DString string;
string.init(allocator, self.len() + b.len());
string.append(self);
string.append(b);
return string;
}
fn DString DString.temp_concat(self, DString b) => self.concat(allocator::temp(), b);
fn DString DString.temp_concat(self, DString b) => self.new_concat(b, allocator::temp());
fn ZString DString.zstr_view(&self)
{
@@ -188,7 +157,7 @@ fn String DString.str_view(self)
<*
@require index < self.len()
@require self.data() != null "Empty string"
@require self.data() "Empty string"
*>
fn char DString.char_at(self, usz index) @operator([])
{
@@ -197,7 +166,7 @@ fn char DString.char_at(self, usz index) @operator([])
<*
@require index < self.len()
@require self.data() != null "Empty string"
@require self.data() "Empty string"
*>
fn char* DString.char_ref(&self, usz index) @operator(&[])
{
@@ -574,7 +543,7 @@ macro void DString.insert_at(&self, usz index, value)
fn usz! DString.appendf(&self, String format, args...) @maydiscard
{
if (!self.data()) self.init(mem, format.len + 20);
if (!self.data()) self.new_init(format.len + 20);
@pool(self.data().allocator)
{
Formatter formatter;
@@ -585,7 +554,7 @@ fn usz! DString.appendf(&self, String format, args...) @maydiscard
fn usz! DString.appendfn(&self, String format, args...) @maydiscard
{
if (!self.data()) self.init(mem, format.len + 20);
if (!self.data()) self.new_init(format.len + 20);
@pool(self.data().allocator)
{
Formatter formatter;
@@ -691,5 +660,5 @@ struct StringData @private
Allocator allocator;
usz len;
usz capacity;
char[?] chars;
char[*] chars;
}

View File

@@ -25,7 +25,7 @@ macro bool @constant_is_power_of_2($x) @const @private
@return "A vector with the loaded values where the mask is true, passthru where the mask is false"
*>
macro masked_load(ptr, bool[<?>] mask, passthru)
macro masked_load(ptr, bool[<*>] mask, passthru)
{
return $$masked_load(ptr, mask, passthru, 0);
}
@@ -45,7 +45,7 @@ macro masked_load(ptr, bool[<?>] mask, passthru)
@return "A vector with the loaded values where the mask is true, passthru where the mask is false"
*>
macro @masked_load_aligned(ptr, bool[<?>] mask, passthru, usz $alignment)
macro @masked_load_aligned(ptr, bool[<*>] mask, passthru, usz $alignment)
{
return $$masked_load(ptr, mask, passthru, $alignment);
}
@@ -65,7 +65,7 @@ macro @masked_load_aligned(ptr, bool[<?>] mask, passthru, usz $alignment)
@return "A vector with the loaded values where the mask is true, passthru where the mask is false"
*>
macro gather(ptrvec, bool[<?>] mask, passthru)
macro gather(ptrvec, bool[<*>] mask, passthru)
{
return $$gather(ptrvec, mask, passthru, 0);
}
@@ -88,7 +88,7 @@ macro gather(ptrvec, bool[<?>] mask, passthru)
@return "A vector with the loaded values where the mask is true, passthru where the mask is false"
*>
macro @gather_aligned(ptrvec, bool[<?>] mask, passthru, usz $alignment)
macro @gather_aligned(ptrvec, bool[<*>] mask, passthru, usz $alignment)
{
return $$gather(ptrvec, mask, passthru, $alignment);
}
@@ -105,7 +105,7 @@ macro @gather_aligned(ptrvec, bool[<?>] mask, passthru, usz $alignment)
@require @typekind(value) == VECTOR : "Expected value to be a vector"
@require value.len == mask.len : "Mask and value must have the same length"
*>
macro masked_store(ptr, value, bool[<?>] mask)
macro masked_store(ptr, value, bool[<*>] mask)
{
return $$masked_store(ptr, value, mask, 0);
}
@@ -122,7 +122,7 @@ macro masked_store(ptr, value, bool[<?>] mask)
@require @constant_is_power_of_2($alignment) : "The alignment must be a power of two"
*>
macro @masked_store_aligned(ptr, value, bool[<?>] mask, usz $alignment)
macro @masked_store_aligned(ptr, value, bool[<*>] mask, usz $alignment)
{
return $$masked_store(ptr, value, mask, $alignment);
}
@@ -138,7 +138,7 @@ macro @masked_store_aligned(ptr, value, bool[<?>] mask, usz $alignment)
@require mask.len == ptrvec.len : "Mask and ptrvec must have the same length"
*>
macro scatter(ptrvec, value, bool[<?>] mask)
macro scatter(ptrvec, value, bool[<*>] mask)
{
return $$scatter(ptrvec, value, mask, 0);
}
@@ -156,61 +156,48 @@ macro scatter(ptrvec, value, bool[<?>] mask)
@require mask.len == ptrvec.len : "Mask and ptrvec must have the same length"
@require @constant_is_power_of_2($alignment) : "The alignment must be a power of two"
*>
macro @scatter_aligned(ptrvec, value, bool[<?>] mask, usz $alignment)
macro @scatter_aligned(ptrvec, value, bool[<*>] mask, usz $alignment)
{
return $$scatter(ptrvec, value, mask, $alignment);
}
<*
@param #x "The variable or dereferenced pointer to load."
@param [in] x "The variable or dereferenced pointer to load."
@param $alignment "The alignment to assume for the load"
@return "The value of the variable"
@return "The value of x"
@require @constant_is_power_of_2($alignment) : "The alignment must be a power of two"
@require $defined(&#x) : "This must be a variable or dereferenced pointer"
*>
macro @unaligned_load(#x, usz $alignment) @builtin
macro @unaligned_load(&x, usz $alignment) @builtin
{
return $$unaligned_load(&#x, $alignment);
return $$unaligned_load(x, $alignment);
}
<*
@param #x "The variable or dereferenced pointer to store to."
@param [out] x "The variable or dereferenced pointer to store to."
@param value "The value to store."
@param $alignment "The alignment to assume for the store"
@return "The value stored"
@return "The value of x"
@require $defined(&#x) : "This must be a variable or dereferenced pointer"
@require $defined(#x = value) : "The value doesn't match the variable"
@require $assignable(value, $typeof(*x)) : "The value doesn't match the variable"
@require @constant_is_power_of_2($alignment) : "The alignment must be a power of two"
*>
macro @unaligned_store(#x, value, usz $alignment) @builtin
macro @unaligned_store(&x, value, usz $alignment) @builtin
{
return $$unaligned_store(&#x, ($typeof(#x))value, $alignment);
return $$unaligned_store(x, ($typeof(*x))value, $alignment);
}
macro @volatile_load(&x) @builtin
{
return $$volatile_load(x);
}
<*
@param #x "The variable or dereferenced pointer to load."
@return "The value of the variable"
@require $defined(&#x) : "This must be a variable or dereferenced pointer"
@require $assignable(y, $typeof(*x)) : "The value doesn't match the variable"
*>
macro @volatile_load(#x) @builtin
macro @volatile_store(&x, y) @builtin
{
return $$volatile_load(&#x);
}
<*
@param #x "The variable or dereferenced pointer to store to."
@param value "The value to store."
@return "The value stored"
@require $defined(&#x) : "This must be a variable or dereferenced pointer"
@require $defined(#x = value) : "The value doesn't match the variable"
*>
macro @volatile_store(#x, value) @builtin
{
return $$volatile_store(&#x, ($typeof(#x))value);
return $$volatile_store(x, ($typeof(*x))y);
}
enum AtomicOrdering : int
@@ -225,36 +212,34 @@ enum AtomicOrdering : int
}
<*
@param #x "the variable or dereferenced pointer to load."
@param [in] x "the variable or dereferenced pointer to load."
@param $ordering "atomic ordering of the load, defaults to SEQ_CONSISTENT"
@param $volatile "whether the load should be volatile, defaults to 'false'"
@return "returns the value of x"
@require $defined(&#x) : "This must be a variable or dereferenced pointer"
@require $ordering != AtomicOrdering.RELEASE "Release ordering is not valid for load."
@require $ordering != AtomicOrdering.ACQUIRE_RELEASE "Acquire release is not valid for load."
@require types::may_load_atomic($typeof(#x)) "Only integer, float and pointers may be used."
@require types::may_load_atomic($typeof(x)) "Only integer, float and pointers may be used."
@require @typekind(x) == POINTER "You can only load from a pointer"
*>
macro @atomic_load(#x, AtomicOrdering $ordering = SEQ_CONSISTENT, $volatile = false) @builtin
macro @atomic_load(&x, AtomicOrdering $ordering = SEQ_CONSISTENT, $volatile = false) @builtin
{
return $$atomic_load(&#x, $volatile, $ordering.ordinal);
return $$atomic_load(x, $volatile, $ordering.ordinal);
}
<*
@param #x "the variable or dereferenced pointer to store to."
@param [out] x "the variable or dereferenced pointer to store to."
@param value "the value to store."
@param $ordering "the atomic ordering of the store, defaults to SEQ_CONSISTENT"
@param $volatile "whether the store should be volatile, defaults to 'false'"
@require $ordering != AtomicOrdering.ACQUIRE "Acquire ordering is not valid for store."
@require $ordering != AtomicOrdering.ACQUIRE_RELEASE "Acquire release is not valid for store."
@require types::may_load_atomic($typeof(#x)) "Only integer, float and pointers may be used."
@require $defined(&#x) : "This must be a variable or dereferenced pointer"
@require $defined(#x = value) : "The value doesn't match the variable"
@require types::may_load_atomic($typeof(x)) "Only integer, float and pointers may be used."
*>
macro void @atomic_store(#x, value, AtomicOrdering $ordering = SEQ_CONSISTENT, $volatile = false) @builtin
macro void @atomic_store(&x, value, AtomicOrdering $ordering = SEQ_CONSISTENT, $volatile = false) @builtin
{
$$atomic_store(&#x, value, $volatile, $ordering.ordinal);
$$atomic_store(x, value, $volatile, $ordering.ordinal);
}
<*
@@ -301,7 +286,7 @@ macro void zero_volatile(char[] data)
$$memset(data.ptr, (char)0, data.len, true, (usz)1);
}
macro void clear(void* dst, usz len, usz $dst_align = 0, bool $is_volatile = false)
macro void clear(void* dst, usz len, usz $dst_align = 0, bool $is_volatile = false, bool $inlined = false)
{
$$memset(dst, (char)0, len, $is_volatile, $dst_align);
}
@@ -323,7 +308,7 @@ macro void clear_inline(void* dst, usz $len, usz $dst_align = 0, bool $is_volati
@require len == 0 || dst + len <= src || src + len <= dst : "Ranges may not overlap"
*>
macro void copy(void* dst, void* src, usz len, usz $dst_align = 0, usz $src_align = 0, bool $is_volatile = false)
macro void copy(void* dst, void* src, usz len, usz $dst_align = 0, usz $src_align = 0, bool $is_volatile = false, bool $inlined = false)
{
$$memcpy(dst, src, len, $is_volatile, $dst_align, $src_align);
}
@@ -490,40 +475,6 @@ macro void @report_heap_allocs_in_scope($enabled = true; @body())
@body();
}
<*
Assert on memory leak in the scope of the macro body.
@param $report "Set to false to disable memory report"
*>
macro void @assert_leak($report = true; @body()) @builtin
{
$if env::DEBUG_SYMBOLS || $feature(MEMORY_ASSERTS):
TrackingAllocator tracker;
tracker.init(allocator::thread_allocator);
Allocator old_allocator = allocator::thread_allocator;
allocator::thread_allocator = &tracker;
defer
{
allocator::thread_allocator = old_allocator;
defer tracker.free();
usz allocated = tracker.allocated();
if (allocated)
{
DString report = dstring::new();
defer report.free();
$if $report:
report.append_char('\n');
(void)tracker.fprint_report(&report);
$endif
assert(allocated == 0, "Memory leak detected"
" (%d bytes allocated).%s",
allocated, report.str_view());
}
}
$endif
@body();
}
<*
Allocate [size] bytes on the stack to use for allocation,
with the heap allocator as the backing allocator.
@@ -584,21 +535,19 @@ fn void temp_pop(TempState old_state)
allocator::thread_temp_allocator = old_state.old;
}
<*
@require @is_empty_macro_slot(#other_temp) ||| $assignable(#other_temp, Allocator) "Must be an allocator"
*>
macro void @pool(#other_temp = EMPTY_MACRO_SLOT; @body) @builtin
macro void @pool(TempAllocator* #other_temp = null; @body) @builtin
{
TempAllocator* current = allocator::temp();
$if @is_valid_macro_slot(#other_temp):
var $has_arg = !$is_const(#other_temp);
$if $has_arg:
TempAllocator* original = current;
if (current == #other_temp.ptr) current = allocator::temp_allocator_next();
if (current == (void*)#other_temp) current = allocator::temp_allocator_next();
$endif
usz mark = current.used;
defer
{
current.reset(mark);
$if @is_valid_macro_slot(#other_temp):
$if $has_arg:
allocator::thread_temp_allocator = original;
$endif;
}
@@ -683,22 +632,6 @@ macro new($Type, ...) @nodiscard
$endif
}
<*
@require $vacount < 2 : "Too many arguments."
@require $vacount == 0 ||| $assignable($vaexpr[0], $Type) : "The second argument must be an initializer for the type"
@require $Type.alignof <= DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'alloc_aligned' instead"
*>
macro new_with_padding($Type, usz padding, ...) @nodiscard
{
$if $vacount == 0:
return ($Type*)calloc($Type.sizeof + padding);
$else
$Type* val = malloc($Type.sizeof + padding);
*val = $vaexpr[0];
return val;
$endif
}
<*
Allocate using an aligned allocation. This is necessary for types with a default memory alignment
exceeding DEFAULT_MEM_ALIGNMENT. IMPORTANT! It must be freed using free_aligned.
@@ -724,14 +657,6 @@ macro alloc($Type) @nodiscard
return ($Type*)malloc($Type.sizeof);
}
<*
@require $Type.alignof <= DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'alloc_aligned' instead"
*>
macro alloc_with_padding($Type, usz padding) @nodiscard
{
return ($Type*)malloc($Type.sizeof + padding);
}
<*
Allocate using an aligned allocation. This is necessary for types with a default memory alignment
exceeding DEFAULT_MEM_ALIGNMENT. IMPORTANT! It must be freed using free_aligned.
@@ -756,30 +681,11 @@ macro temp_new($Type, ...) @nodiscard
$endif
}
<*
@require $vacount < 2 : "Too many arguments."
@require $vacount == 0 ||| $assignable($vaexpr[0], $Type) : "The second argument must be an initializer for the type"
*>
macro temp_new_with_padding($Type, usz padding, ...) @nodiscard
{
$if $vacount == 0:
return ($Type*)tcalloc($Type.sizeof + padding) @inline;
$else
$Type* val = tmalloc($Type.sizeof + padding) @inline;
*val = $vaexpr[0];
return val;
$endif
}
macro temp_alloc($Type) @nodiscard
{
return tmalloc($Type.sizeof);
}
macro temp_alloc_with_padding($Type, usz padding) @nodiscard
{
return tmalloc($Type.sizeof + padding);
}
<*
@require $Type.alignof <= DEFAULT_MEM_ALIGNMENT : "Types with alignment exceeding the default must use 'new_array_aligned' instead"
@@ -909,3 +815,4 @@ fn void* __memcpy(void* dst, void* src, usz n) @weak @export("memcpy")
}
return dst;
}

View File

@@ -184,12 +184,12 @@ macro new_try(Allocator allocator, $Type, ...) @nodiscard
@require $vacount < 2 : "Too many arguments."
@require $vacount == 0 ||| $assignable($vaexpr[0], $Type) : "The second argument must be an initializer for the type"
*>
macro new_aligned(Allocator allocator, $Type, ...) @nodiscard
macro new_aligned($Type, ...) @nodiscard
{
$if $vacount == 0:
return ($Type*)calloc_aligned(allocator, $Type.sizeof, $Type.alignof);
$else
$Type* val = malloc_aligned(allocator, $Type.sizeof, $Type.alignof)!;
$Type* val = malloc_aligned(allocator, $Type.sizeof, $Type.alignof);
*val = $vaexpr[0];
return val;
$endif
@@ -360,7 +360,6 @@ macro void*! @aligned_realloc(#calloc_fn, #free_fn, void* old_pointer, usz bytes
// All allocators
def mem = thread_allocator @builtin;
tlocal Allocator thread_allocator @private = base_allocator();
Allocator temp_base_allocator @private = base_allocator();

View File

@@ -150,14 +150,14 @@ fn void x86_initialize_cpu_features()
{
uint max_level = x86_cpuid(0).eax;
CpuId feat = x86_cpuid(1);
CpuId leaf7 = max_level >= 8 ? x86_cpuid(7) : {};
CpuId leaf7s1 = leaf7.eax >= 1 ? x86_cpuid(7, 1) : {};
CpuId ext1 = x86_cpuid(0x80000000).eax >= 0x80000001 ? x86_cpuid(0x80000001) : {};
CpuId ext8 = x86_cpuid(0x80000000).eax >= 0x80000008 ? x86_cpuid(0x80000008) : {};
CpuId leaf_d = max_level >= 0xd ? x86_cpuid(0xd, 0x1) : {};
CpuId leaf_14 = max_level >= 0x14 ? x86_cpuid(0x14) : {};
CpuId leaf_19 = max_level >= 0x19 ? x86_cpuid(0x19) : {};
CpuId leaf_24 = max_level >= 0x24 ? x86_cpuid(0x24) : {};
CpuId leaf7 = max_level >= 8 ? x86_cpuid(7) : CpuId {};
CpuId leaf7s1 = leaf7.eax >= 1 ? x86_cpuid(7, 1) : CpuId {};
CpuId ext1 = x86_cpuid(0x80000000).eax >= 0x80000001 ? x86_cpuid(0x80000001) : CpuId {};
CpuId ext8 = x86_cpuid(0x80000000).eax >= 0x80000008 ? x86_cpuid(0x80000008) : CpuId {};
CpuId leaf_d = max_level >= 0xd ? x86_cpuid(0xd, 0x1) : CpuId {};
CpuId leaf_14 = max_level >= 0x14 ? x86_cpuid(0x14) : CpuId {};
CpuId leaf_19 = max_level >= 0x19 ? x86_cpuid(0x19) : CpuId {};
CpuId leaf_24 = max_level >= 0x24 ? x86_cpuid(0x24) : CpuId {};
add_feature_if_bit(ADX, leaf7.ebx, 19);
add_feature_if_bit(AES, feat.ecx, 25);
add_feature_if_bit(AMX_BF16, leaf7.edx, 22);

View File

@@ -101,7 +101,7 @@ macro find_segment_section_body(MachHeader* header, char* segname, char* sectnam
Section64*! section = find_section(find_segment(header, segname), sectname);
if (catch section)
{
return ($Type[]){};
return $Type[] {};
}
$Type* ptr = (void*)header + section.offset;
return ptr[:section.size / $Type.sizeof];
@@ -214,7 +214,7 @@ struct TypeId
usz sizeof;
TypeId* inner;
usz len;
typeid[?] additional;
typeid[*] additional;
}
fn void dl_reg_callback(MachHeader* mh, isz vmaddr_slide)

View File

@@ -47,13 +47,6 @@ macro int @main_to_int_main_args(#m, int argc, char** argv)
return #m(list);
}
macro int @_main_runner(#m, int argc, char** argv)
{
String[] list = args_to_strings(argc, argv);
defer free(list.ptr);
return #m(list) ? 0 : 1;
}
macro int @main_to_void_main_args(#m, int argc, char** argv)
{
String[] list = args_to_strings(argc, argv);
@@ -164,13 +157,6 @@ macro int @wmain_to_int_main_args(#m, int argc, Char16** argv)
return #m(args);
}
macro int @_wmain_runner(#m, int argc, Char16** argv)
{
String[] args = wargs_strings(argc, argv);
defer release_wargs(args);
return #m(args) ? 0 : 1;
}
macro int @wmain_to_void_main_args(#m, int argc, Char16** argv)
{
String[] args = wargs_strings(argc, argv);

View File

@@ -22,6 +22,230 @@ struct SliceRaw
usz len;
}
def BenchmarkFn = fn void!();
struct BenchmarkUnit
{
String name;
BenchmarkFn func;
}
fn BenchmarkUnit[] benchmark_collection_create(Allocator allocator = allocator::heap())
{
BenchmarkFn[] fns = $$BENCHMARK_FNS;
String[] names = $$BENCHMARK_NAMES;
BenchmarkUnit[] benchmarks = allocator::alloc_array(allocator, BenchmarkUnit, names.len);
foreach (i, benchmark : fns)
{
benchmarks[i] = { names[i], fns[i] };
}
return benchmarks;
}
const DEFAULT_BENCHMARK_WARMUP_ITERATIONS = 3;
const DEFAULT_BENCHMARK_MAX_ITERATIONS = 10000;
uint benchmark_warmup_iterations @private = DEFAULT_BENCHMARK_WARMUP_ITERATIONS;
uint benchmark_max_iterations @private = DEFAULT_BENCHMARK_MAX_ITERATIONS;
fn void set_benchmark_warmup_iterations(uint value) @builtin
{
benchmark_warmup_iterations = value;
}
fn void set_benchmark_max_iterations(uint value) @builtin
{
assert(value > 0);
benchmark_max_iterations = value;
}
fn bool run_benchmarks(BenchmarkUnit[] benchmarks)
{
int benchmarks_passed = 0;
int benchmark_count = benchmarks.len;
usz max_name;
foreach (&unit : benchmarks)
{
if (max_name < unit.name.len) max_name = unit.name.len;
}
usz len = max_name + 9;
DString name = dstring::temp_with_capacity(64);
name.append_repeat('-', len / 2);
name.append(" BENCHMARKS ");
name.append_repeat('-', len - len / 2);
io::printn(name);
name.clear();
long sys_clock_started;
long sys_clock_finished;
long sys_clocks;
Clock clock;
anyfault err;
foreach(unit : benchmarks)
{
defer name.clear();
name.appendf("Benchmarking %s ", unit.name);
name.append_repeat('.', max_name - unit.name.len + 2);
io::printf("%s ", name.str_view());
for (uint i = 0; i < benchmark_warmup_iterations; i++)
{
err = @catch(unit.func()) @inline;
@volatile_load(err);
}
clock = std::time::clock::now();
sys_clock_started = $$sysclock();
for (uint i = 0; i < benchmark_max_iterations; i++)
{
err = @catch(unit.func()) @inline;
@volatile_load(err);
}
sys_clock_finished = $$sysclock();
NanoDuration nano_seconds = clock.mark();
sys_clocks = sys_clock_finished - sys_clock_started;
if (err)
{
io::printfn("[failed] Failed due to: %s", err);
continue;
}
io::printfn("[ok] %.2f ns, %.2f CPU's clocks", (float)nano_seconds / benchmark_max_iterations, (float)sys_clocks / benchmark_max_iterations);
benchmarks_passed++;
}
io::printfn("\n%d benchmark%s run.\n", benchmark_count, benchmark_count > 1 ? "s" : "");
io::printfn("Benchmarks Result: %s. %d passed, %d failed.",
benchmarks_passed < benchmark_count ? "FAILED" : "ok",
benchmarks_passed,
benchmark_count - benchmarks_passed);
return benchmark_count == benchmarks_passed;
}
fn bool default_benchmark_runner()
{
@pool()
{
return run_benchmarks(benchmark_collection_create(allocator::temp()));
};
}
def TestFn = fn void!();
struct TestUnit
{
String name;
TestFn func;
}
fn TestUnit[] test_collection_create(Allocator allocator = allocator::heap())
{
TestFn[] fns = $$TEST_FNS;
String[] names = $$TEST_NAMES;
TestUnit[] tests = allocator::alloc_array(allocator, TestUnit, names.len);
foreach (i, test : fns)
{
tests[i] = { names[i], fns[i] };
}
return tests;
}
struct TestContext
{
JmpBuf buf;
}
// Sort the tests by their name in ascending order.
fn int cmp_test_unit(TestUnit a, TestUnit b)
{
usz an = a.name.len;
usz bn = b.name.len;
if (an > bn) @swap(a, b);
foreach (i, ac : a.name)
{
char bc = b.name[i];
if (ac != bc) return an > bn ? bc - ac : ac - bc;
}
return (int)(an - bn);
}
TestContext* test_context @private;
fn void test_panic(String message, String file, String function, uint line)
{
io::printn("[error]");
io::print("\n Error: ");
io::print(message);
io::printn();
io::printfn(" - in %s %s:%s.\n", function, file, line);
libc::longjmp(&test_context.buf, 1);
}
fn bool run_tests(TestUnit[] tests)
{
usz max_name;
foreach (&unit : tests)
{
if (max_name < unit.name.len) max_name = unit.name.len;
}
quicksort(tests, &cmp_test_unit);
TestContext context;
test_context = &context;
PanicFn old_panic = builtin::panic;
defer builtin::panic = old_panic;
builtin::panic = &test_panic;
int tests_passed = 0;
int test_count = tests.len;
DString name = dstring::temp_with_capacity(64);
usz len = max_name + 9;
name.append_repeat('-', len / 2);
name.append(" TESTS ");
name.append_repeat('-', len - len / 2);
io::printn(name);
name.clear();
foreach(unit : tests)
{
defer name.clear();
name.appendf("Testing %s ", unit.name);
name.append_repeat('.', max_name - unit.name.len + 2);
io::printf("%s ", name.str_view());
(void)io::stdout().flush();
if (libc::setjmp(&context.buf) == 0)
{
if (catch err = unit.func())
{
io::printfn("[failed] Failed due to: %s", err);
continue;
}
io::printn("[ok]");
tests_passed++;
}
}
io::printfn("\n%d test%s run.\n", test_count, test_count > 1 ? "s" : "");
io::printfn("Test Result: %s. %d passed, %d failed.",
tests_passed < test_count ? "FAILED" : "ok", tests_passed, test_count - tests_passed);
return test_count == tests_passed;
}
fn bool default_test_runner()
{
@pool()
{
return run_tests(test_collection_create(allocator::temp()));
};
}
module std::core::runtime @if(WASM_NOLIBC);

View File

@@ -1,174 +0,0 @@
module std::core::runtime;
import libc, std::time, std::io, std::sort;
def BenchmarkFn = fn void!() @if($$OLD_TEST);
def BenchmarkFn = fn void() @if(!$$OLD_TEST);
struct BenchmarkUnit
{
String name;
BenchmarkFn func;
}
fn BenchmarkUnit[] benchmark_collection_create(Allocator allocator = allocator::heap())
{
BenchmarkFn[] fns = $$BENCHMARK_FNS;
String[] names = $$BENCHMARK_NAMES;
BenchmarkUnit[] benchmarks = allocator::alloc_array(allocator, BenchmarkUnit, names.len);
foreach (i, benchmark : fns)
{
benchmarks[i] = { names[i], fns[i] };
}
return benchmarks;
}
const DEFAULT_BENCHMARK_WARMUP_ITERATIONS = 3;
const DEFAULT_BENCHMARK_MAX_ITERATIONS = 10000;
uint benchmark_warmup_iterations @private = DEFAULT_BENCHMARK_WARMUP_ITERATIONS;
uint benchmark_max_iterations @private = DEFAULT_BENCHMARK_MAX_ITERATIONS;
fn void set_benchmark_warmup_iterations(uint value) @builtin
{
benchmark_warmup_iterations = value;
}
fn void set_benchmark_max_iterations(uint value) @builtin
{
assert(value > 0);
benchmark_max_iterations = value;
}
fn bool run_benchmarks(BenchmarkUnit[] benchmarks) @if($$OLD_TEST)
{
int benchmarks_passed = 0;
int benchmark_count = benchmarks.len;
usz max_name;
foreach (&unit : benchmarks)
{
if (max_name < unit.name.len) max_name = unit.name.len;
}
usz len = max_name + 9;
DString name = dstring::temp_with_capacity(64);
name.append_repeat('-', len / 2);
name.append(" BENCHMARKS ");
name.append_repeat('-', len - len / 2);
io::printn(name);
name.clear();
long sys_clock_started;
long sys_clock_finished;
long sys_clocks;
Clock clock;
anyfault err;
foreach(unit : benchmarks)
{
defer name.clear();
name.appendf("Benchmarking %s ", unit.name);
name.append_repeat('.', max_name - unit.name.len + 2);
io::printf("%s ", name.str_view());
for (uint i = 0; i < benchmark_warmup_iterations; i++)
{
err = @catch(unit.func()) @inline;
@volatile_load(err);
}
clock = std::time::clock::now();
sys_clock_started = $$sysclock();
for (uint i = 0; i < benchmark_max_iterations; i++)
{
err = @catch(unit.func()) @inline;
@volatile_load(err);
}
sys_clock_finished = $$sysclock();
NanoDuration nano_seconds = clock.mark();
sys_clocks = sys_clock_finished - sys_clock_started;
if (err)
{
io::printfn("[failed] Failed due to: %s", err);
continue;
}
io::printfn("[ok] %.2f ns, %.2f CPU's clocks", (float)nano_seconds / benchmark_max_iterations, (float)sys_clocks / benchmark_max_iterations);
benchmarks_passed++;
}
io::printfn("\n%d benchmark%s run.\n", benchmark_count, benchmark_count > 1 ? "s" : "");
io::printfn("Benchmarks Result: %s. %d passed, %d failed.",
benchmarks_passed < benchmark_count ? "FAILED" : "ok",
benchmarks_passed,
benchmark_count - benchmarks_passed);
return benchmark_count == benchmarks_passed;
}
fn bool run_benchmarks(BenchmarkUnit[] benchmarks) @if(!$$OLD_TEST)
{
usz max_name;
foreach (&unit : benchmarks)
{
if (max_name < unit.name.len) max_name = unit.name.len;
}
usz len = max_name + 9;
DString name = dstring::temp_with_capacity(64);
name.append_repeat('-', len / 2);
name.append(" BENCHMARKS ");
name.append_repeat('-', len - len / 2);
io::printn(name);
name.clear();
long sys_clock_started;
long sys_clock_finished;
long sys_clocks;
Clock clock;
foreach(unit : benchmarks)
{
defer name.clear();
name.appendf("Benchmarking %s ", unit.name);
name.append_repeat('.', max_name - unit.name.len + 2);
io::printf("%s ", name.str_view());
for (uint i = 0; i < benchmark_warmup_iterations; i++)
{
unit.func() @inline;
}
clock = std::time::clock::now();
sys_clock_started = $$sysclock();
for (uint i = 0; i < benchmark_max_iterations; i++)
{
unit.func() @inline;
}
sys_clock_finished = $$sysclock();
NanoDuration nano_seconds = clock.mark();
sys_clocks = sys_clock_finished - sys_clock_started;
io::printfn("[COMPLETE] %.2f ns, %.2f CPU's clocks", (float)nano_seconds / benchmark_max_iterations, (float)sys_clocks / benchmark_max_iterations);
}
io::printfn("\n%d benchmark%s run.\n", benchmarks.len, benchmarks.len > 1 ? "s" : "");
return true;
}
fn bool default_benchmark_runner(String[] args) => @pool()
{
return run_benchmarks(benchmark_collection_create(allocator::temp()));
}

View File

@@ -1,342 +0,0 @@
// Copyright (c) 2025 Christoffer Lerno. All rights reserved.
// Use of this source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
module std::core::runtime;
import std::core::test @public;
import std::core::mem::allocator @public;
import libc, std::time, std::io, std::sort;
import std::os::env;
def TestFn = fn void!() @if($$OLD_TEST);
def TestFn = fn void() @if(!$$OLD_TEST);
TestContext* test_context @private;
struct TestContext
{
JmpBuf buf;
// Allows filtering test cased or modules by substring, e.g. 'foo::', 'foo::test_add'
String test_filter;
// Triggers debugger breakpoint when assert or test:: checks failed
bool breakpoint_on_assert;
// internal state
bool assert_print_backtrace;
bool has_ansi_codes;
bool is_in_panic;
bool is_quiet_mode;
bool is_no_capture;
String current_test_name;
TestFn setup_fn;
TestFn teardown_fn;
char* error_buffer;
usz error_buffer_capacity;
File fake_stdout;
struct stored
{
File stdout;
File stderr;
Allocator allocator;
}
}
struct TestUnit
{
String name;
TestFn func;
}
fn TestUnit[] test_collection_create(Allocator allocator = allocator::heap())
{
TestFn[] fns = $$TEST_FNS;
String[] names = $$TEST_NAMES;
TestUnit[] tests = allocator::alloc_array(allocator, TestUnit, names.len);
foreach (i, test : fns)
{
tests[i] = { names[i], fns[i] };
}
return tests;
}
// Sort the tests by their name in ascending order.
fn int cmp_test_unit(TestUnit a, TestUnit b)
{
usz an = a.name.len;
usz bn = b.name.len;
if (an > bn) @swap(a, b);
foreach (i, ac : a.name)
{
char bc = b.name[i];
if (ac != bc) return an > bn ? bc - ac : ac - bc;
}
return (int)(an - bn);
}
fn bool terminal_has_ansi_codes() @local => @pool()
{
if (try v = env::get_var_temp("TERM"))
{
if (v.contains("xterm") || v.contains("vt100") || v.contains("screen")) return true;
}
$if env::WIN32 || env::NO_LIBC:
return false;
$else
return io::stdout().isatty();
$endif
}
fn void test_panic(String message, String file, String function, uint line) @local
{
if (test_context.is_in_panic) return;
test_context.is_in_panic = true;
unmute_output(true);
(void)io::stdout().flush();
if (test_context.assert_print_backtrace)
{
$if env::NATIVE_STACKTRACE:
builtin::print_backtrace(message, 0);
$endif
}
io::printf("\nTest failed ^^^ ( %s:%s ) %s\n", file, line, message);
test_context.assert_print_backtrace = true;
if (test_context.breakpoint_on_assert)
{
breakpoint();
}
if (test_context.teardown_fn)
{
test_context.teardown_fn();
}
test_context.is_in_panic = false;
allocator::thread_allocator = test_context.stored.allocator;
libc::longjmp(&test_context.buf, 1);
}
fn void mute_output() @local
{
if (test_context.is_no_capture || !test_context.fake_stdout.file) return;
File* stdout = io::stdout();
File* stderr = io::stderr();
*stderr = test_context.fake_stdout;
*stdout = test_context.fake_stdout;
(void)test_context.fake_stdout.seek(0, Seek.SET)!!;
}
fn void unmute_output(bool has_error) @local
{
if (test_context.is_no_capture || !test_context.fake_stdout.file) return;
File* stdout = io::stdout();
File* stderr = io::stderr();
*stderr = test_context.stored.stderr;
*stdout = test_context.stored.stdout;
usz log_size = test_context.fake_stdout.seek(0, Seek.CURSOR)!!;
if (has_error)
{
io::printf("\nTesting %s ", test_context.current_test_name);
io::printn(test_context.has_ansi_codes ? "[\e[0;31mFAIL\e[0m]" : "[FAIL]");
}
if (has_error && log_size > 0)
{
test_context.fake_stdout.write_byte('\n')!!;
test_context.fake_stdout.write_byte('\0')!!;
(void)test_context.fake_stdout.seek(0, Seek.SET)!!;
io::printfn("\n========== TEST LOG ============");
io::printfn("%s\n", test_context.current_test_name);
while (try c = test_context.fake_stdout.read_byte())
{
if (@unlikely(c == '\0'))
{
// ignore junk from previous tests
break;
}
libc::putchar(c);
}
io::printf("========== TEST END ============");
}
(void)stdout.flush();
}
fn bool run_tests(String[] args, TestUnit[] tests) @private
{
usz max_name;
bool sort_tests = true;
bool check_leaks = true;
foreach (&unit : tests)
{
if (max_name < unit.name.len) max_name = unit.name.len;
}
TestContext context =
{
.assert_print_backtrace = true,
.breakpoint_on_assert = false,
.test_filter = "",
.has_ansi_codes = terminal_has_ansi_codes(),
.stored.allocator = allocator::heap(),
.stored.stderr = *io::stderr(),
.stored.stdout = *io::stdout(),
};
for (int i = 1; i < args.len; i++)
{
switch (args[i])
{
case "--test-breakpoint":
context.breakpoint_on_assert = true;
case "--test-nosort":
sort_tests = false;
case "--test-noleak":
check_leaks = false;
case "--test-nocapture":
context.is_no_capture = true;
case "--noansi":
context.has_ansi_codes = false;
case "--useansi":
context.has_ansi_codes = true;
case "--test-quiet":
context.is_quiet_mode = true;
case "--test-filter":
if (i == args.len - 1)
{
io::printn("Invalid arguments to test runner.");
return false;
}
context.test_filter = args[i + 1];
i++;
default:
io::printfn("Unknown argument: %s", args[i]);
}
}
test_context = &context;
if (sort_tests)
{
quicksort(tests, &cmp_test_unit);
}
// Buffer for hijacking the output
$if (!env::NO_LIBC):
context.fake_stdout.file = libc::tmpfile();
$endif
if (context.fake_stdout.file == null)
{
io::print("Failed to hijack stdout, tests will print everything");
}
PanicFn old_panic = builtin::panic;
defer builtin::panic = old_panic;
builtin::panic = &test_panic;
int tests_passed = 0;
int tests_skipped = 0;
int test_count = tests.len;
DString name = dstring::temp_with_capacity(64);
usz len = max_name + 9;
name.append_repeat('-', len / 2);
name.append(" TESTS ");
name.append_repeat('-', len - len / 2);
if (!context.is_quiet_mode) io::printn(name);
name.clear();
TempState temp_state = mem::temp_push();
defer mem::temp_pop(temp_state);
foreach(unit : tests)
{
mem::temp_pop(temp_state);
if (context.test_filter && !unit.name.contains(context.test_filter))
{
tests_skipped++;
continue;
}
context.setup_fn = null;
context.teardown_fn = null;
context.current_test_name = unit.name;
defer name.clear();
name.appendf("Testing %s ", unit.name);
name.append_repeat('.', max_name - unit.name.len + 2);
if (context.is_quiet_mode)
{
io::print(".");
}
else
{
io::printf("%s ", name.str_view());
}
(void)io::stdout().flush();
TrackingAllocator mem;
mem.init(context.stored.allocator);
if (libc::setjmp(&context.buf) == 0)
{
mute_output();
mem.clear();
if (check_leaks) allocator::thread_allocator = &mem;
$if(!$$OLD_TEST):
unit.func();
$else
if (catch err = unit.func())
{
io::printf("[FAIL] Failed due to: %s", err);
continue;
}
$endif
// track cleanup that may take place in teardown_fn
if (context.teardown_fn)
{
context.teardown_fn();
}
if (check_leaks) allocator::thread_allocator = context.stored.allocator;
unmute_output(false); // all good, discard output
if (mem.has_leaks())
{
if(context.is_quiet_mode) io::printf("\n%s ", context.current_test_name);
io::print(context.has_ansi_codes ? "[\e[0;31mFAIL\e[0m]" : "[FAIL]");
io::printn(" LEAKS DETECTED!");
mem.print_report();
}
else
{
if (!context.is_quiet_mode)
{
io::printfn(context.has_ansi_codes ? "[\e[0;32mPASS\e[0m]" : "[PASS]");
}
tests_passed++;
}
}
mem.free();
}
io::printfn("\n%d test%s run.\n", test_count-tests_skipped, test_count > 1 ? "s" : "");
int n_failed = test_count - tests_passed - tests_skipped;
io::printf("Test Result: %s%s%s: ",
context.has_ansi_codes ? (n_failed ? "\e[0;31m" : "\e[0;32m") : "",
n_failed ? "FAILED" : "PASSED",
context.has_ansi_codes ? "\e[0m" : "",
);
io::printfn("%d passed, %d failed, %d skipped.",
tests_passed,
n_failed,
tests_skipped);
// cleanup fake_stdout file
if (context.fake_stdout.file) libc::fclose(context.fake_stdout.file);
context.fake_stdout.file = null;
return n_failed == 0;
}
fn bool default_test_runner(String[] args) => @pool()
{
assert(test_context == null, "test suite is already running");
return run_tests(args, test_collection_create(allocator::temp()));
}

View File

@@ -52,11 +52,14 @@ fn ZString tformat_zstr(String fmt, args...)
@param [inout] allocator `The allocator to use`
@param [in] fmt `The formatting string`
*>
fn String format(String fmt, args..., Allocator allocator) => @pool(allocator)
fn String format(String fmt, args..., Allocator allocator)
{
DString str = dstring::temp_with_capacity(fmt.len + args.len * 8);
str.appendf(fmt, ...args);
return str.copy_str(allocator);
@pool(allocator)
{
DString str = dstring::temp_with_capacity(fmt.len + args.len * 8);
str.appendf(fmt, ...args);
return str.copy_str(allocator);
};
}
<*
@@ -84,11 +87,14 @@ fn String tformat(String fmt, args...)
@param [in] fmt `The formatting string`
@param [inout] allocator `The allocator to use`
*>
fn ZString new_format_zstr(String fmt, args..., Allocator allocator = allocator::heap()) => @pool(allocator)
fn ZString new_format_zstr(String fmt, args..., Allocator allocator = allocator::heap())
{
DString str = dstring::temp_with_capacity(fmt.len + args.len * 8);
str.appendf(fmt, ...args);
return str.copy_zstr(allocator);
@pool(allocator)
{
DString str = dstring::temp_with_capacity(fmt.len + args.len * 8);
str.appendf(fmt, ...args);
return str.copy_zstr(allocator);
};
}
<*
@@ -139,40 +145,14 @@ fn String join_new(String[] s, String joiner, Allocator allocator = allocator::h
@return `a substring of the string passed in`
*>
fn String String.trim(string, String to_trim = "\t\n\r ")
{
return string.trim_left(to_trim).trim_right(to_trim);
}
<*
Remove characters from the front of a string.
@param [in] string `The string to trim`
@param [in] to_trim `The set of characters to trim, defaults to whitespace`
@pure
@return `a substring of the string passed in`
*>
fn String String.trim_left(string, String to_trim = "\t\n\r ")
{
usz start = 0;
usz len = string.len;
while (start < len && char_in_set(string[start], to_trim)) start++;
if (start == len) return string[:0];
return string[start..];
}
<*
Remove characters from the end of a string.
@param [in] string `The string to trim`
@param [in] to_trim `The set of characters to trim, defaults to whitespace`
@pure
@return `a substring of the string passed in`
*>
fn String String.trim_right(string, String to_trim = "\t\n\r ")
{
usz len = string.len;
while (len > 0 && char_in_set(string[len - 1], to_trim)) len--;
return string[:len];
usz end = len - 1;
while (end > start && char_in_set(string[end], to_trim)) end--;
return string[start..end];
}
<*
@@ -382,29 +362,6 @@ fn usz! String.index_of_char(s, char needle)
return SearchResult.MISSING?;
}
<*
Find the index of the first incidence of a one of the chars.
@param [in] s
@param [in] needle "The characters to look for"
@pure
@ensure return < s.len
@return "the index of the needle"
@return! SearchResult.MISSING "if the needle cannot be found"
*>
fn usz! String.index_of_chars(String s, char[] needle)
{
foreach (i, c : s)
{
foreach (j, pin : needle)
{
if (c == pin) return i;
}
}
return SearchResult.MISSING?;
}
<*
Find the index of the first incidence of a character.
@@ -546,11 +503,6 @@ fn String String.tconcat(s1, String s2) => s1.concat(s2, allocator::temp());
fn ZString String.zstr_tcopy(s) => s.zstr_copy(allocator::temp()) @inline;
<*
Copy this string, by duplicating the string, always adding a zero byte
sentinel, so that it safely can be converted to a ZString by a
cast.
*>
fn String String.copy(s, Allocator allocator = allocator::heap())
{
usz len = s.len;
@@ -562,7 +514,7 @@ fn String String.copy(s, Allocator allocator = allocator::heap())
fn void String.free(&s, Allocator allocator = allocator::heap())
{
if (!s.ptr) return;
if (!s.len) return;
allocator::free(allocator, s.ptr);
*s = "";
}
@@ -780,28 +732,26 @@ macro String.to_integer(string, $Type, int base = 10)
$Type value = 0;
while (index != len)
{
char c = string[index++];
switch
{
case base_used != 16 || c < 'A': c -= '0';
case c <= 'F': c -= 'A' - 10;
case c < 'a' || c > 'f': return NumberConversion.MALFORMED_INTEGER?;
default: c -= 'a' - 10;
}
char c = {|
char ch = string[index++];
if (base_used != 16 || ch < 'A') return (char)(ch - '0');
if (ch <= 'F') return (char)(ch - 'A' + 10);
if (ch < 'a') return NumberConversion.MALFORMED_INTEGER?;
if (ch > 'f') return NumberConversion.MALFORMED_INTEGER?;
return (char)(ch - 'a' + 10);
|}!;
if (c >= base_used) return NumberConversion.MALFORMED_INTEGER?;
do
{
value = {|
if (is_negative)
{
$Type new_value = value * base_used - c;
if (new_value > value) return NumberConversion.INTEGER_OVERFLOW?;
value = new_value;
break;
return new_value;
}
$Type new_value = value * base_used + c;
if (new_value < value) return NumberConversion.INTEGER_OVERFLOW?;
value = new_value;
};
return new_value;
|}!;
}
return value;
}
@@ -870,7 +820,7 @@ macro String new_struct_to_str(x, Allocator allocator = allocator::heap())
DString s;
@stack_mem(512; Allocator mem)
{
s.init(mem);
s.new_init(allocator: mem);
io::fprint(&s, x)!!;
return s.copy_str(allocator);
};

View File

@@ -40,7 +40,7 @@ macro double! decfloat(char[] chars, int $bits, int $emin, int sign)
const uint[2] TH = B1B_MAX;
int emax = - $emin - $bits + 3;
const int[?] P10S = { 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 };
const int[*] P10S = { 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 };
usz index;
bool got_digit = chars[0] == '0';
bool got_rad;
@@ -376,7 +376,10 @@ macro double! hexfloat(char[] chars, int $bits, int $emin, int sign)
else
{
got_digit = true;
int d = c > '9' ? ((c | 32) + 10 - 'a') : (c - '0');
int d = {|
if (c > '9') return (c | 32) + 10 - 'a';
return c - '0';
|};
switch
{
case dc < 8:

View File

@@ -1,223 +0,0 @@
<*
Unit test module
This module provides a toolset of macros for running unit test checks
Example:
```c3
module sample::m;
import std::io;
fault MathError
{
DIVISION_BY_ZERO
}
fn double! divide(int a, int b)
{
if (b == 0) return MathError.DIVISION_BY_ZERO?;
return (double)(a) / (double)(b);
}
fn void! test_div() @test
{
test::eq(2, divide(6, 3)!);
test::ne(1, 2);
test::ge(3, 3);
test::gt(2, divide(3, 3)!);
test::lt(2, 3);
test::le(2, 3);
test::eq_approx(m::divide(1, 3)!, 0.333, places: 3);
test::@check(2 == 2, "divide: %d", divide(6, 3)!);
test::@error(m::divide(3, 0), MathError.DIVISION_BY_ZERO);
}
```
*>
// Copyright (c) 2025 Alex Veden <i@alexveden.com>. All rights reserved.
// Use of this source code is governed by the MIT license
// a copy of which can be found in the LICENSE_STDLIB file.
module std::core::test;
import std::core::runtime @public;
import std::math, std::io, libc;
<*
Initializes test case context.
@param setup_fn `initializer function for test case`
@param teardown_fn `cleanup function for test context (may be null)`
@require runtime::test_context != null "Only allowed in @test functions"
@require setup_fn != null "setup_fn must always be set"
*>
macro @setup(TestFn setup_fn, TestFn teardown_fn = null)
{
runtime::test_context.setup_fn = setup_fn;
runtime::test_context.teardown_fn = teardown_fn;
runtime::test_context.setup_fn();
}
<*
Checks condition and fails assertion if not true
@param #condition `any boolean condition, will be expanded by text`
@param format `printf compatible format`
@param args `vargs for format`
@require runtime::test_context != null "Only allowed in @test functions"
*>
macro @check(#condition, String format = "", args...)
{
if (!#condition)
{
@stack_mem(512; Allocator allocator)
{
DString s;
s.init(allocator);
s.appendf("check `%s` failed. ", $stringify(#condition));
s.appendf(format, ...args);
print_panicf(s.str_view());
};
}
}
<*
Check if function returns specific error
@param #funcresult `result of function execution`
@param error_expected `expected error of function execution`
@require runtime::test_context != null "Only allowed in @test functions"
*>
macro @error(#funcresult, anyfault error_expected)
{
if (catch err = #funcresult)
{
if (err != error_expected)
{
print_panicf("`%s` expected to return error [%s], got [%s]",
$stringify(#funcresult), error_expected, err);
}
return;
}
print_panicf("`%s` error [%s] was not returned.", $stringify(#funcresult), error_expected);
}
<*
Check if left == right
@param left `left argument of any comparable type`
@param right `right argument of any comparable type`
@require runtime::test_context != null "Only allowed in @test functions"
*>
macro eq(left, right)
{
if (!equals(left, right))
{
print_panicf("`%s` != `%s`", left, right);
}
}
<*
Check left floating point value is approximately equals to right value
@param places `number of decimal places to compare (default: 7)`
@param delta `minimal allowed difference (overrides places parameter)`
@param equal_nan `allows comparing nan values, if left and right both nans result is ok`
@require places > 0, places <= 20 "too many decimal places"
@require delta >= 0, delta <= 1 "delta must be a small number"
@require runtime::test_context != null "Only allowed in @test functions"
*>
macro void eq_approx(double left, double right, uint places = 7, double delta = 0, bool equal_nan = true)
{
double diff = left - right;
double eps = delta;
if (eps == 0) eps = 1.0 / math::pow(10.0, places);
if (!math::is_approx(left, right, eps))
{
if (equal_nan && math::is_nan(left) && math::is_nan(right)) return;
print_panicf("Not almost equal: `%s` !~~ `%s` delta=%e diff: %e", left, right, eps, diff);
}
}
<*
Check if left != right
@param left `left argument of any comparable type`
@param right `right argument of any comparable type`
@require runtime::test_context != null "Only allowed in @test functions"
*>
macro void ne(left, right)
{
if (equals(left, right))
{
print_panicf("`%s` == `%s`", left, right);
}
}
<*
Check if left > right
@param left `left argument of any comparable type`
@param right `right argument of any comparable type`
@require runtime::test_context != null "Only allowed in @test functions"
*>
macro gt(left, right)
{
if (!builtin::greater(left, right))
{
print_panicf("`%s` <= `%s`", left, right);
}
}
<*
Check if left >= right
@param left `left argument of any comparable type`
@param right `right argument of any comparable type`
@require runtime::test_context != null "Only allowed in @test functions"
*>
macro ge(left, right)
{
if (!builtin::greater_eq(left, right))
{
print_panicf("`%s` < `%s`", left, right);
}
}
<*
Check if left < right
@param left `left argument of any comparable type`
@param right `right argument of any comparable type`
@require runtime::test_context != null "Only allowed in @test functions"
*>
macro lt(left, right)
{
if (!builtin::less(left, right))
{
print_panicf("`%s` >= `%s`", left, right);
}
}
<*
Check if left <= right
@param left `left argument of any comparable type`
@param right `right argument of any comparable type`
@require runtime::test_context != null "Only allowed in @test functions"
*>
macro le(left, right)
{
if (!builtin::less_eq(left, right))
{
print_panicf("`%s` > `%s`", left, right);
}
}
macro void print_panicf(format, ...) @local
{
runtime::test_context.assert_print_backtrace = false;
builtin::panicf(format, $$FILE, $$FUNC, $$LINE, $vasplat);
}

View File

@@ -8,24 +8,18 @@ fault ConversionResult
VALUE_OUT_OF_RANGE,
VALUE_OUT_OF_UNSIGNED_RANGE,
}
<*
@require $Type.kindof.is_int() "Type was not an integer"
@require v.type.kindof == ENUM "Value was not an enum"
*>
macro any_to_enum_ordinal(any v, $Type)
{
return any_to_int(v.as_inner(), $Type);
}
<*
@require $Type.kindof.is_int() "Type was not an integer"
@require v.type.kindof.is_int() "Value was not an integer"
@require $Type.kindof.is_int() || $Type.kindof == TypeKind.ENUM "Argument was not an integer"
*>
macro any_to_int(any v, $Type)
{
typeid any_type = v.type;
TypeKind kind = any_type.kindof;
if (kind == TypeKind.ENUM)
{
any_type = any_type.inner;
kind = any_type.kindof;
}
bool is_mixed_signed = $Type.kindof != any_type.kindof;
$Type max = $Type.max;
$Type min = $Type.min;
@@ -162,12 +156,12 @@ macro bool is_unsigned($Type) @const
macro bool is_indexable($Type) @const
{
return $defined(($Type){}[0]);
return $defined($Type{}[0]);
}
macro bool is_ref_indexable($Type) @const
{
return $defined(&($Type){}[0]);
return $defined(&$Type{}[0]);
}
macro bool is_intlike($Type) @const
@@ -251,7 +245,6 @@ macro bool @has_same(#a, #b, ...) @const
macro bool may_load_atomic($Type) @const
{
$switch ($Type.kindof)
$case BOOL:
$case SIGNED_INT:
$case UNSIGNED_INT:
$case POINTER:

View File

@@ -16,7 +16,6 @@ macro bool @is_promotable_to_float(#value) @const => types::is_promotable_to_flo
macro bool @is_vector(#value) @const => types::is_vector($typeof(#value));
macro bool @is_same_vector_type(#value1, #value2) @const => types::is_same_vector_type($typeof(#value1), $typeof(#value2));
macro bool @assign_to(#value1, #value2) @const => $assignable(#value1, $typeof(#value2));
macro bool @is_lvalue(#value) => $defined(#value = #value);
macro promote_int(x)
{
@@ -27,25 +26,6 @@ macro promote_int(x)
$endif
}
<*
Select between two values at compile time,
the values do not have to be of the same type.
This acts like `$bool ? #value_1 : #value_2` but at compile time.
@param $bool `true for picking the first value, false for the other`
@param #value_1
@param #value_2
@returns `The selected value.`
*>
macro @select(bool $bool, #value_1, #value_2) @builtin
{
$if $bool:
return #value_1;
$else
return #value_2;
$endif
}
macro promote_int_same(x, y)
{
$if @is_int(x):

View File

@@ -61,7 +61,7 @@ fn CsvRow! CsvReader.read_temp_row(self)
}
<*
@require self.allocator != null `Row already freed`
@require self.allocator `Row already freed`
*>
fn void CsvRow.free(&self)
{
@@ -70,12 +70,15 @@ fn void CsvRow.free(&self)
self.allocator = null;
}
fn void! CsvReader.skip_row(self) @maydiscard => @pool()
fn void! CsvReader.skip_row(self) @maydiscard
{
(void)io::treadline(self.stream);
@pool()
{
(void)io::treadline(self.stream);
};
}
macro void! CsvReader.@each_row(self, int rows = int.max; @body(String[] row)) @maydiscard
macro CsvReader.@each_row(self, int rows = int.max; @body(String[] row))
{
InStream stream = self.stream;
String sep = self.separator;

View File

@@ -89,8 +89,8 @@ fn usz! decode_bytes(char[] src, char[] dst)
return i;
}
const char[?] HEXALPHABET @private = "0123456789abcdef";
const char[?] HEXREVERSE @private =
const char[*] HEXALPHABET @private = "0123456789abcdef";
const char[*] HEXREVERSE @private =
x`ffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffff

View File

@@ -17,12 +17,12 @@ fault JsonParsingError
fn Object*! parse_string(String s, Allocator allocator = allocator::heap())
{
return parse((ByteReader){}.init(s), allocator);
return parse(ByteReader{}.init(s), allocator);
}
fn Object*! temp_parse_string(String s)
{
return parse((ByteReader){}.init(s), allocator::temp());
return parse(ByteReader{}.init(s), allocator::temp());
}
fn Object*! parse(InStream s, Allocator allocator = allocator::heap())

View File

@@ -1,94 +0,0 @@
module std::experimental::scheduler(<Event>);
import std::collections, std::thread, std::time;
struct DelayedSchedulerEvent @local
{
inline Event event;
Clock execution_time;
}
fn int DelayedSchedulerEvent.compare_to(self, DelayedSchedulerEvent other) @local
{
switch
{
case self.execution_time < other.execution_time: return -1;
case self.execution_time > other.execution_time: return 1;
default: return 0;
}
}
struct FrameScheduler
{
PriorityQueue(<DelayedSchedulerEvent>) delayed_events;
List(<Event>) events;
List(<Event>) pending_events;
bool pending;
Mutex mtx;
}
fn void FrameScheduler.init(&self)
{
self.events.init(mem);
self.pending_events.init(mem);
self.delayed_events.init(mem);
(void)self.mtx.init();
bool pending;
}
macro void FrameScheduler.@destroy(&self; @destruct(Event e))
{
foreach (e : self.events) @destruct(e);
foreach (e : self.pending_events) @destruct(e);
foreach (e : self.delayed_events.heap) @destruct(e.event);
self.events.free();
self.pending_events.free();
self.delayed_events.free();
(void)self.mtx.destroy();
}
fn void FrameScheduler.queue_delayed_event(&self, Event event, Duration delay)
{
self.mtx.@in_lock()
{
self.delayed_events.push({ event, clock::now().add_duration(delay)});
@atomic_store(self.pending, true);
};
}
fn bool FrameScheduler.has_delayed(&self)
{
self.mtx.@in_lock()
{
return @ok(self.delayed_events.first());
};
}
fn void FrameScheduler.queue_event(&self, Event event)
{
self.mtx.@in_lock()
{
self.pending_events.push(event);
@atomic_store(self.pending, true);
};
}
fn Event! FrameScheduler.pop_event(&self)
{
while (true)
{
if (try event = self.events.pop()) return event;
if (!@atomic_load(self.pending)) return IteratorResult.NO_MORE_ELEMENT?;
self.mtx.@in_lock()
{
self.events.add_all(&self.pending_events);
self.pending_events.clear();
Clock c = clock::now();
while (try top = self.delayed_events.first())
{
if (top.execution_time > c) break;
self.events.push(self.delayed_events.pop()!!);
}
@atomic_store(self.pending, self.delayed_events.len() > 0);
if (!self.events.len()) return IteratorResult.NO_MORE_ELEMENT?;
};
}
}

View File

@@ -8,7 +8,7 @@ distinct Fnv32a = uint;
const FNV32A_START @private = 0x811c9dc5;
const FNV32A_MUL @private = 0x01000193;
macro void update(h, char x) @private => *h = (*h ^ ($typeof(*h))x) * FNV32A_MUL;
macro void @update(&h, char x) @private => *h = (*h ^ ($typeof(*h))x) * FNV32A_MUL;
fn void Fnv32a.init(&self)
{
@@ -20,14 +20,14 @@ fn void Fnv32a.update(&self, char[] data)
Fnv32a h = *self;
foreach (char x : data)
{
update(&h, x);
@update(h, x);
}
*self = h;
}
macro void Fnv32a.update_char(&self, char c)
{
update(self, c);
@update(*self, c);
}
fn uint encode(char[] data)
@@ -35,7 +35,7 @@ fn uint encode(char[] data)
uint h = FNV32A_START;
foreach (char x : data)
{
update(&h, x);
@update(h, x);
}
return h;
}

View File

@@ -8,7 +8,7 @@ distinct Fnv64a = ulong;
const FNV64A_START @private = 0xcbf29ce484222325;
const FNV64A_MUL @private = 0x00000100000001b3;
macro void update(h, char x) @private => *h = (*h ^ ($typeof(*h))x) * FNV64A_MUL;
macro void @update(&h, char x) @private => *h = (*h ^ ($typeof(*h))x) * FNV64A_MUL;
fn void Fnv64a.init(&self)
{
@@ -20,14 +20,14 @@ fn void Fnv64a.update(&self, char[] data)
Fnv64a h = *self;
foreach (char x : data)
{
update(&h, x);
@update(h, x);
}
*self = h;
}
macro void Fnv64a.update_char(&self, char c)
{
update(self, c);
@update(*self, c);
}
fn ulong encode(char[] data)
@@ -35,7 +35,7 @@ fn ulong encode(char[] data)
ulong h = FNV64A_START;
foreach (char x : data)
{
update(&h, x);
@update(h, x);
}
return h;
}

View File

@@ -106,9 +106,9 @@ macro @h(x, y, z) => (x ^ y) ^ z;
macro @h2(x, y, z) => x ^ (y ^ z);
macro @i(x, y, z) => y ^ (x | ~z);
macro @step(#f, a, b, c, d, ptr, n, t, s)
macro @step(#f, &a, b, c, d, ptr, n, t, s)
{
*a += #f(b, c, d) + @unaligned_load(*(uint *)&ptr[n * 4], 2) + t;
*a += #f(b, c, d) + *(uint *)&ptr[n * 4] + t;
*a = (*a << s) | ((*a & 0xffffffff) >> (32 - s));
*a += b;
}
@@ -133,76 +133,76 @@ fn char* body(Md5* ctx, void* data, usz size)
saved_d = d;
/* Round 1 */
@step(@f, &a, b, c, d, ptr, 0, 0xd76aa478, 7) ;
@step(@f, &d, a, b, c, ptr, 1, 0xe8c7b756, 12) ;
@step(@f, &c, d, a, b, ptr, 2, 0x242070db, 17) ;
@step(@f, &b, c, d, a, ptr, 3, 0xc1bdceee, 22) ;
@step(@f, &a, b, c, d, ptr, 4, 0xf57c0faf, 7) ;
@step(@f, &d, a, b, c, ptr, 5, 0x4787c62a, 12) ;
@step(@f, &c, d, a, b, ptr, 6, 0xa8304613, 17) ;
@step(@f, &b, c, d, a, ptr, 7, 0xfd469501, 22) ;
@step(@f, &a, b, c, d, ptr, 8, 0x698098d8, 7) ;
@step(@f, &d, a, b, c, ptr, 9, 0x8b44f7af, 12) ;
@step(@f, &c, d, a, b, ptr, 10, 0xffff5bb1, 17);
@step(@f, &b, c, d, a, ptr, 11, 0x895cd7be, 22);
@step(@f, &a, b, c, d, ptr, 12, 0x6b901122, 7) ;
@step(@f, &d, a, b, c, ptr, 13, 0xfd987193, 12);
@step(@f, &c, d, a, b, ptr, 14, 0xa679438e, 17);
@step(@f, &b, c, d, a, ptr, 15, 0x49b40821, 22);
@step(@f, a, b, c, d, ptr, 0, 0xd76aa478, 7) ;
@step(@f, d, a, b, c, ptr, 1, 0xe8c7b756, 12) ;
@step(@f, c, d, a, b, ptr, 2, 0x242070db, 17) ;
@step(@f, b, c, d, a, ptr, 3, 0xc1bdceee, 22) ;
@step(@f, a, b, c, d, ptr, 4, 0xf57c0faf, 7) ;
@step(@f, d, a, b, c, ptr, 5, 0x4787c62a, 12) ;
@step(@f, c, d, a, b, ptr, 6, 0xa8304613, 17) ;
@step(@f, b, c, d, a, ptr, 7, 0xfd469501, 22) ;
@step(@f, a, b, c, d, ptr, 8, 0x698098d8, 7) ;
@step(@f, d, a, b, c, ptr, 9, 0x8b44f7af, 12) ;
@step(@f, c, d, a, b, ptr, 10, 0xffff5bb1, 17);
@step(@f, b, c, d, a, ptr, 11, 0x895cd7be, 22);
@step(@f, a, b, c, d, ptr, 12, 0x6b901122, 7) ;
@step(@f, d, a, b, c, ptr, 13, 0xfd987193, 12);
@step(@f, c, d, a, b, ptr, 14, 0xa679438e, 17);
@step(@f, b, c, d, a, ptr, 15, 0x49b40821, 22);
/* Round 2 */
@step(@g, &a, b, c, d, ptr, 1, 0xf61e2562, 5) ;
@step(@g, &d, a, b, c, ptr, 6, 0xc040b340, 9) ;
@step(@g, &c, d, a, b, ptr, 11, 0x265e5a51, 14);
@step(@g, &b, c, d, a, ptr, 0, 0xe9b6c7aa, 20) ;
@step(@g, &a, b, c, d, ptr, 5, 0xd62f105d, 5) ;
@step(@g, &d, a, b, c, ptr, 10, 0x02441453, 9) ;
@step(@g, &c, d, a, b, ptr, 15, 0xd8a1e681, 14);
@step(@g, &b, c, d, a, ptr, 4, 0xe7d3fbc8, 20) ;
@step(@g, &a, b, c, d, ptr, 9, 0x21e1cde6, 5) ;
@step(@g, &d, a, b, c, ptr, 14, 0xc33707d6, 9) ;
@step(@g, &c, d, a, b, ptr, 3, 0xf4d50d87, 14) ;
@step(@g, &b, c, d, a, ptr, 8, 0x455a14ed, 20) ;
@step(@g, &a, b, c, d, ptr, 13, 0xa9e3e905, 5) ;
@step(@g, &d, a, b, c, ptr, 2, 0xfcefa3f8, 9) ;
@step(@g, &c, d, a, b, ptr, 7, 0x676f02d9, 14) ;
@step(@g, &b, c, d, a, ptr, 12, 0x8d2a4c8a, 20);
@step(@g, a, b, c, d, ptr, 1, 0xf61e2562, 5) ;
@step(@g, d, a, b, c, ptr, 6, 0xc040b340, 9) ;
@step(@g, c, d, a, b, ptr, 11, 0x265e5a51, 14);
@step(@g, b, c, d, a, ptr, 0, 0xe9b6c7aa, 20) ;
@step(@g, a, b, c, d, ptr, 5, 0xd62f105d, 5) ;
@step(@g, d, a, b, c, ptr, 10, 0x02441453, 9) ;
@step(@g, c, d, a, b, ptr, 15, 0xd8a1e681, 14);
@step(@g, b, c, d, a, ptr, 4, 0xe7d3fbc8, 20) ;
@step(@g, a, b, c, d, ptr, 9, 0x21e1cde6, 5) ;
@step(@g, d, a, b, c, ptr, 14, 0xc33707d6, 9) ;
@step(@g, c, d, a, b, ptr, 3, 0xf4d50d87, 14) ;
@step(@g, b, c, d, a, ptr, 8, 0x455a14ed, 20) ;
@step(@g, a, b, c, d, ptr, 13, 0xa9e3e905, 5) ;
@step(@g, d, a, b, c, ptr, 2, 0xfcefa3f8, 9) ;
@step(@g, c, d, a, b, ptr, 7, 0x676f02d9, 14) ;
@step(@g, b, c, d, a, ptr, 12, 0x8d2a4c8a, 20);
/* Round 3 */
@step(@h, &a, b, c, d, ptr, 5, 0xfffa3942, 4);
@step(@h2, &d, a, b, c, ptr, 8, 0x8771f681, 11);
@step(@h, &c, d, a, b, ptr, 11, 0x6d9d6122, 16);
@step(@h2, &b, c, d, a, ptr, 14, 0xfde5380c, 23);
@step(@h, &a, b, c, d, ptr, 1, 0xa4beea44, 4);
@step(@h2, &d, a, b, c, ptr, 4, 0x4bdecfa9, 11);
@step(@h, &c, d, a, b, ptr, 7, 0xf6bb4b60, 16);
@step(@h2, &b, c, d, a, ptr, 10, 0xbebfbc70, 23);
@step(@h, &a, b, c, d, ptr, 13, 0x289b7ec6, 4) ;
@step(@h2, &d, a, b, c, ptr, 0, 0xeaa127fa, 11) ;
@step(@h, &c, d, a, b, ptr, 3, 0xd4ef3085, 16) ;
@step(@h2, &b, c, d, a, ptr, 6, 0x04881d05, 23) ;
@step(@h, &a, b, c, d, ptr, 9, 0xd9d4d039, 4) ;
@step(@h2, &d, a, b, c, ptr, 12, 0xe6db99e5, 11) ;
@step(@h, &c, d, a, b, ptr, 15, 0x1fa27cf8, 16) ;
@step(@h2, &b, c, d, a, ptr, 2, 0xc4ac5665, 23) ;
@step(@h, a, b, c, d, ptr, 5, 0xfffa3942, 4);
@step(@h2, d, a, b, c, ptr, 8, 0x8771f681, 11);
@step(@h, c, d, a, b, ptr, 11, 0x6d9d6122, 16);
@step(@h2, b, c, d, a, ptr, 14, 0xfde5380c, 23);
@step(@h, a, b, c, d, ptr, 1, 0xa4beea44, 4);
@step(@h2, d, a, b, c, ptr, 4, 0x4bdecfa9, 11);
@step(@h, c, d, a, b, ptr, 7, 0xf6bb4b60, 16);
@step(@h2, b, c, d, a, ptr, 10, 0xbebfbc70, 23);
@step(@h, a, b, c, d, ptr, 13, 0x289b7ec6, 4) ;
@step(@h2, d, a, b, c, ptr, 0, 0xeaa127fa, 11) ;
@step(@h, c, d, a, b, ptr, 3, 0xd4ef3085, 16) ;
@step(@h2, b, c, d, a, ptr, 6, 0x04881d05, 23) ;
@step(@h, a, b, c, d, ptr, 9, 0xd9d4d039, 4) ;
@step(@h2, d, a, b, c, ptr, 12, 0xe6db99e5, 11) ;
@step(@h, c, d, a, b, ptr, 15, 0x1fa27cf8, 16) ;
@step(@h2, b, c, d, a, ptr, 2, 0xc4ac5665, 23) ;
/* Round 4 */
@step(@i, &a, b, c, d, ptr, 0, 0xf4292244, 6) ;
@step(@i, &d, a, b, c, ptr, 7, 0x432aff97, 10) ;
@step(@i, &c, d, a, b, ptr, 14, 0xab9423a7, 15) ;
@step(@i, &b, c, d, a, ptr, 5, 0xfc93a039, 21) ;
@step(@i, &a, b, c, d, ptr, 12, 0x655b59c3, 6) ;
@step(@i, &d, a, b, c, ptr, 3, 0x8f0ccc92, 10) ;
@step(@i, &c, d, a, b, ptr, 10, 0xffeff47d, 15) ;
@step(@i, &b, c, d, a, ptr, 1, 0x85845dd1, 21) ;
@step(@i, &a, b, c, d, ptr, 8, 0x6fa87e4f, 6) ;
@step(@i, &d, a, b, c, ptr, 15, 0xfe2ce6e0, 10) ;
@step(@i, &c, d, a, b, ptr, 6, 0xa3014314, 15) ;
@step(@i, &b, c, d, a, ptr, 13, 0x4e0811a1, 21) ;
@step(@i, &a, b, c, d, ptr, 4, 0xf7537e82, 6) ;
@step(@i, &d, a, b, c, ptr, 11, 0xbd3af235, 10) ;
@step(@i, &c, d, a, b, ptr, 2, 0x2ad7d2bb, 15) ;
@step(@i, &b, c, d, a, ptr, 9, 0xeb86d391, 21) ;
@step(@i, a, b, c, d, ptr, 0, 0xf4292244, 6) ;
@step(@i, d, a, b, c, ptr, 7, 0x432aff97, 10) ;
@step(@i, c, d, a, b, ptr, 14, 0xab9423a7, 15) ;
@step(@i, b, c, d, a, ptr, 5, 0xfc93a039, 21) ;
@step(@i, a, b, c, d, ptr, 12, 0x655b59c3, 6) ;
@step(@i, d, a, b, c, ptr, 3, 0x8f0ccc92, 10) ;
@step(@i, c, d, a, b, ptr, 10, 0xffeff47d, 15) ;
@step(@i, b, c, d, a, ptr, 1, 0x85845dd1, 21) ;
@step(@i, a, b, c, d, ptr, 8, 0x6fa87e4f, 6) ;
@step(@i, d, a, b, c, ptr, 15, 0xfe2ce6e0, 10) ;
@step(@i, c, d, a, b, ptr, 6, 0xa3014314, 15) ;
@step(@i, b, c, d, a, ptr, 13, 0x4e0811a1, 21) ;
@step(@i, a, b, c, d, ptr, 4, 0xf7537e82, 6) ;
@step(@i, d, a, b, c, ptr, 11, 0xbd3af235, 10) ;
@step(@i, c, d, a, b, ptr, 2, 0x2ad7d2bb, 15) ;
@step(@i, b, c, d, a, ptr, 9, 0xeb86d391, 21) ;
a += saved_a;
b += saved_b;

View File

@@ -78,10 +78,10 @@ fn char[HASH_BYTES] Sha1.final(&self)
{
finalcount[i] = (char)((self.count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 0xFF);
}
self.update((char[]){ 0o200 });
self.update(char[] { 0o200 });
while ((self.count[0] & 504) != 448)
{
self.update((char[]){ 0 });
self.update(char[] { 0 });
}
self.update(&finalcount);
@@ -103,13 +103,13 @@ union Long16 @local
uint[16] l;
}
macro blk(Long16* block, i) @local
macro @blk(&block, i) @local
{
return (block.l[i & 15] = (block.l[(i + 13) & 15] ^ block.l[(i + 8) & 15]
^ block.l[(i + 2) & 15] ^ block.l[i & 15]).rotl(1));
}
macro blk0(Long16* block, i) @local
macro @blk0(&block, i) @local
{
$if env::BIG_ENDIAN:
return block.l[i];
@@ -119,38 +119,38 @@ macro blk0(Long16* block, i) @local
$endif
}
macro r0(Long16* block, uint v, uint* wref, uint x, uint y, uint* z, uint i) @local
macro @r0(&block, v, &wref, x, y, &z, i) @local
{
var w = *wref;
*z += ((w & (x ^ y)) ^ y) + blk0(block, i) + 0x5A827999 + v.rotl(5);
*z += ((w & (x ^ y)) ^ y) + @blk0(*block, i) + 0x5A827999 + v.rotl(5);
*wref = w.rotl(30);
}
macro r1(Long16* block, uint v, uint* wref, uint x, uint y, uint* z, uint i) @local
macro @r1(&block, v, &wref, x, y, &z, i) @local
{
var w = *wref;
*z += ((w & (x ^ y)) ^ y) + blk(block, i) + 0x5A827999 + v.rotl(5);
*z += ((w & (x ^ y)) ^ y) + @blk(*block, i) + 0x5A827999 + v.rotl(5);
*wref = w.rotl(30);
}
macro r2(Long16* block, uint v, uint* wref, uint x, uint y, uint* z, uint i) @local
macro @r2(&block, v, &wref, x, y, &z, i) @local
{
var w = *wref;
*z += (w ^ x ^ y) + blk(block, i) + 0x6ED9EBA1 + v.rotl(5);
*z += (w ^ x ^ y) + @blk(*block, i) + 0x6ED9EBA1 + v.rotl(5);
*wref = w.rotl(30);
}
macro r3(Long16* block, uint v, uint* wref, uint x, uint y, uint* z, uint i) @local
macro @r3(&block, v, &wref, x, y, &z, i) @local
{
var w = *wref;
*z += (((w | x) & y) | (w & x)) + blk(block, i) + 0x8F1BBCDC + v.rotl(5);
*z += (((w | x) & y) | (w & x)) + @blk(*block, i) + 0x8F1BBCDC + v.rotl(5);
*wref = w.rotl(30);
}
macro r4(Long16* block, uint v, uint* wref, uint x, uint y, uint* z, uint i) @local
macro @r4(&block, v, &wref, x, y, &z, i) @local
{
var w = *wref;
*z += (w ^ x ^ y) + blk(block, i) + 0xCA62C1D6 + v.rotl(5);
*z += (w ^ x ^ y) + @blk(*block, i) + 0xCA62C1D6 + v.rotl(5);
*wref = w.rotl(30);
}
@@ -158,100 +158,100 @@ macro r4(Long16* block, uint v, uint* wref, uint x, uint y, uint* z, uint i) @lo
@param [&inout] state
@param [&in] buffer
*>
fn void sha1_transform(uint[5]* state, char* buffer) @local
fn void sha1_transform(uint* state, char* buffer) @local
{
Long16 block;
block.c[..] = buffer[:64];
uint a = (*state)[0];
uint b = (*state)[1];
uint c = (*state)[2];
uint d = (*state)[3];
uint e = (*state)[4];
r0(&block, a, &b, c, d, &e, 0);
r0(&block, e, &a, b, c, &d, 1);
r0(&block, d, &e, a, b, &c, 2);
r0(&block, c, &d, e, a, &b, 3);
r0(&block, b, &c, d, e, &a, 4);
r0(&block, a, &b, c, d, &e, 5);
r0(&block, e, &a, b, c, &d, 6);
r0(&block, d, &e, a, b, &c, 7);
r0(&block, c, &d, e, a, &b, 8);
r0(&block, b, &c, d, e, &a, 9);
r0(&block, a, &b, c, d, &e, 10);
r0(&block, e, &a, b, c, &d, 11);
r0(&block, d, &e, a, b, &c, 12);
r0(&block, c, &d, e, a, &b, 13);
r0(&block, b, &c, d, e, &a, 14);
r0(&block, a, &b, c, d, &e, 15);
r1(&block, e, &a, b, c, &d, 16);
r1(&block, d, &e, a, b, &c, 17);
r1(&block, c, &d, e, a, &b, 18);
r1(&block, b, &c, d, e, &a, 19);
r2(&block, a, &b, c, d, &e, 20);
r2(&block, e, &a, b, c, &d, 21);
r2(&block, d, &e, a, b, &c, 22);
r2(&block, c, &d, e, a, &b, 23);
r2(&block, b, &c, d, e, &a, 24);
r2(&block, a, &b, c, d, &e, 25);
r2(&block, e, &a, b, c, &d, 26);
r2(&block, d, &e, a, b, &c, 27);
r2(&block, c, &d, e, a, &b, 28);
r2(&block, b, &c, d, e, &a, 29);
r2(&block, a, &b, c, d, &e, 30);
r2(&block, e, &a, b, c, &d, 31);
r2(&block, d, &e, a, b, &c, 32);
r2(&block, c, &d, e, a, &b, 33);
r2(&block, b, &c, d, e, &a, 34);
r2(&block, a, &b, c, d, &e, 35);
r2(&block, e, &a, b, c, &d, 36);
r2(&block, d, &e, a, b, &c, 37);
r2(&block, c, &d, e, a, &b, 38);
r2(&block, b, &c, d, e, &a, 39);
r3(&block, a, &b, c, d, &e, 40);
r3(&block, e, &a, b, c, &d, 41);
r3(&block, d, &e, a, b, &c, 42);
r3(&block, c, &d, e, a, &b, 43);
r3(&block, b, &c, d, e, &a, 44);
r3(&block, a, &b, c, d, &e, 45);
r3(&block, e, &a, b, c, &d, 46);
r3(&block, d, &e, a, b, &c, 47);
r3(&block, c, &d, e, a, &b, 48);
r3(&block, b, &c, d, e, &a, 49);
r3(&block, a, &b, c, d, &e, 50);
r3(&block, e, &a, b, c, &d, 51);
r3(&block, d, &e, a, b, &c, 52);
r3(&block, c, &d, e, a, &b, 53);
r3(&block, b, &c, d, e, &a, 54);
r3(&block, a, &b, c, d, &e, 55);
r3(&block, e, &a, b, c, &d, 56);
r3(&block, d, &e, a, b, &c, 57);
r3(&block, c, &d, e, a, &b, 58);
r3(&block, b, &c, d, e, &a, 59);
r4(&block, a, &b, c, d, &e, 60);
r4(&block, e, &a, b, c, &d, 61);
r4(&block, d, &e, a, b, &c, 62);
r4(&block, c, &d, e, a, &b, 63);
r4(&block, b, &c, d, e, &a, 64);
r4(&block, a, &b, c, d, &e, 65);
r4(&block, e, &a, b, c, &d, 66);
r4(&block, d, &e, a, b, &c, 67);
r4(&block, c, &d, e, a, &b, 68);
r4(&block, b, &c, d, e, &a, 69);
r4(&block, a, &b, c, d, &e, 70);
r4(&block, e, &a, b, c, &d, 71);
r4(&block, d, &e, a, b, &c, 72);
r4(&block, c, &d, e, a, &b, 73);
r4(&block, b, &c, d, e, &a, 74);
r4(&block, a, &b, c, d, &e, 75);
r4(&block, e, &a, b, c, &d, 76);
r4(&block, d, &e, a, b, &c, 77);
r4(&block, c, &d, e, a, &b, 78);
r4(&block, b, &c, d, e, &a, 79);
(*state)[0] += a;
(*state)[1] += b;
(*state)[2] += c;
(*state)[3] += d;
(*state)[4] += e;
uint a = state[0];
uint b = state[1];
uint c = state[2];
uint d = state[3];
uint e = state[4];
@r0(block, a, b, c, d, e, 0);
@r0(block, e, a, b, c, d, 1);
@r0(block, d, e, a, b, c, 2);
@r0(block, c, d, e, a, b, 3);
@r0(block, b, c, d, e, a, 4);
@r0(block, a, b, c, d, e, 5);
@r0(block, e, a, b, c, d, 6);
@r0(block, d, e, a, b, c, 7);
@r0(block, c, d, e, a, b, 8);
@r0(block, b, c, d, e, a, 9);
@r0(block, a, b, c, d, e, 10);
@r0(block, e, a, b, c, d, 11);
@r0(block, d, e, a, b, c, 12);
@r0(block, c, d, e, a, b, 13);
@r0(block, b, c, d, e, a, 14);
@r0(block, a, b, c, d, e, 15);
@r1(block, e, a, b, c, d, 16);
@r1(block, d, e, a, b, c, 17);
@r1(block, c, d, e, a, b, 18);
@r1(block, b, c, d, e, a, 19);
@r2(block, a, b, c, d, e, 20);
@r2(block, e, a, b, c, d, 21);
@r2(block, d, e, a, b, c, 22);
@r2(block, c, d, e, a, b, 23);
@r2(block, b, c, d, e, a, 24);
@r2(block, a, b, c, d, e, 25);
@r2(block, e, a, b, c, d, 26);
@r2(block, d, e, a, b, c, 27);
@r2(block, c, d, e, a, b, 28);
@r2(block, b, c, d, e, a, 29);
@r2(block, a, b, c, d, e, 30);
@r2(block, e, a, b, c, d, 31);
@r2(block, d, e, a, b, c, 32);
@r2(block, c, d, e, a, b, 33);
@r2(block, b, c, d, e, a, 34);
@r2(block, a, b, c, d, e, 35);
@r2(block, e, a, b, c, d, 36);
@r2(block, d, e, a, b, c, 37);
@r2(block, c, d, e, a, b, 38);
@r2(block, b, c, d, e, a, 39);
@r3(block, a, b, c, d, e, 40);
@r3(block, e, a, b, c, d, 41);
@r3(block, d, e, a, b, c, 42);
@r3(block, c, d, e, a, b, 43);
@r3(block, b, c, d, e, a, 44);
@r3(block, a, b, c, d, e, 45);
@r3(block, e, a, b, c, d, 46);
@r3(block, d, e, a, b, c, 47);
@r3(block, c, d, e, a, b, 48);
@r3(block, b, c, d, e, a, 49);
@r3(block, a, b, c, d, e, 50);
@r3(block, e, a, b, c, d, 51);
@r3(block, d, e, a, b, c, 52);
@r3(block, c, d, e, a, b, 53);
@r3(block, b, c, d, e, a, 54);
@r3(block, a, b, c, d, e, 55);
@r3(block, e, a, b, c, d, 56);
@r3(block, d, e, a, b, c, 57);
@r3(block, c, d, e, a, b, 58);
@r3(block, b, c, d, e, a, 59);
@r4(block, a, b, c, d, e, 60);
@r4(block, e, a, b, c, d, 61);
@r4(block, d, e, a, b, c, 62);
@r4(block, c, d, e, a, b, 63);
@r4(block, b, c, d, e, a, 64);
@r4(block, a, b, c, d, e, 65);
@r4(block, e, a, b, c, d, 66);
@r4(block, d, e, a, b, c, 67);
@r4(block, c, d, e, a, b, 68);
@r4(block, b, c, d, e, a, 69);
@r4(block, a, b, c, d, e, 70);
@r4(block, e, a, b, c, d, 71);
@r4(block, d, e, a, b, c, 72);
@r4(block, c, d, e, a, b, 73);
@r4(block, b, c, d, e, a, 74);
@r4(block, a, b, c, d, e, 75);
@r4(block, e, a, b, c, d, 76);
@r4(block, d, e, a, b, c, 77);
@r4(block, c, d, e, a, b, 78);
@r4(block, b, c, d, e, a, 79);
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
state[4] += e;
a = b = c = d = e = 0;
block = {};
buffer[:64] = 0;
}

View File

@@ -19,11 +19,6 @@ fn File! open_path(Path path, String mode)
return from_handle(os::native_fopen(path.str_view(), mode));
}
fn bool exists(String file) => @pool()
{
return path::exists(path::temp_new(file)) ?? false;
}
fn File from_handle(CFile file)
{
return { .file = file };
@@ -111,7 +106,7 @@ fn void! File.close(&self) @inline @dynamic
}
<*
@require self.file != null
@require self.file
*>
fn bool File.eof(&self) @inline
{
@@ -128,22 +123,13 @@ fn usz! File.read(&self, char[] buffer) @dynamic
<*
@param [out] buffer
@require self.file != null `File must be initialized`
@require self.file `File must be initialized`
*>
fn usz! File.write(&self, char[] buffer) @dynamic
{
return os::native_fwrite(self.file, buffer);
}
fn Fd File.fd(self) @if(env::LIBC)
{
return libc::fileno(self.file);
}
fn bool File.isatty(self) @if(env::LIBC)
{
return libc::isatty(self.fd()) > 0;
}
fn char! File.read_byte(&self) @dynamic
{
@@ -175,8 +161,6 @@ fn char[]! load_buffer(String filename, char[] buffer)
}
fn char[]! load(Allocator allocator, String filename) => load_new(filename, allocator);
fn char[]! load_new(String filename, Allocator allocator = allocator::heap())
{
File file = open(filename, "rb")!;
@@ -193,15 +177,11 @@ fn char[]! load_new(String filename, Allocator allocator = allocator::heap())
return data[:len];
}
fn char[]! load_path_new(Path path, Allocator allocator = allocator::heap()) => load_new(path.str_view(), allocator);
fn char[]! load_temp(String filename)
{
return load_new(filename, allocator::temp());
}
fn char[]! load_path_temp(Path path) => load_temp(path.str_view());
fn void! save(String filename, char[] data)
{
File file = open(filename, "wb")!;
@@ -214,7 +194,7 @@ fn void! save(String filename, char[] data)
}
<*
@require self.file != null `File must be initialized`
@require self.file `File must be initialized`
*>
fn void! File.flush(&self) @dynamic
{

View File

@@ -145,10 +145,7 @@ fn usz! Formatter.print_with_function(&self, Printable arg)
return SearchResult.MISSING?;
}
fn usz! Formatter.out_unknown(&self, String category, any arg) @private
{
return self.out_substr("[") + self.out_substr(category) + self.out_substr(" type:") + self.ntoa((iptr)arg.type, false, 16) + self.out_substr(", addr:") + self.ntoa((iptr)arg.ptr, false, 16) + self.out_substr("]");
}
fn usz! Formatter.out_str(&self, any arg) @private
{
switch (arg.type.kindof)
@@ -198,17 +195,17 @@ fn usz! Formatter.out_str(&self, any arg) @private
switch (arg.type.kindof)
{
case ENUM:
usz i = types::any_to_enum_ordinal(arg, usz)!!;
usz i = types::any_to_int(arg, usz)!!;
assert(i < arg.type.names.len, "Illegal enum value found, numerical value was %d.", i);
return self.out_substr(arg.type.names[i]);
case STRUCT:
return self.out_unknown("struct", arg);
return self.out_substr("<struct>");
case UNION:
return self.out_unknown("union", arg);
return self.out_substr("<union>");
case BITSTRUCT:
return self.out_unknown("bitstruct", arg);
return self.out_substr("<bitstruct>");
case FUNC:
return self.out_unknown("function", arg);
return self.out_substr("<function>");
case DISTINCT:
if (arg.type == String.typeid)
{
@@ -241,9 +238,10 @@ fn usz! Formatter.out_str(&self, any arg) @private
self.width = width;
}
self.width = 0;
return self.out_substr("0x")! + self.ntoa_any(arg, 16);
self.out_substr("0x")!;
return self.ntoa_any(arg, 16);
case ARRAY:
// this is SomeType[?] so grab the "SomeType"
// this is SomeType[*] so grab the "SomeType"
PrintFlags flags = self.flags;
uint width = self.width;
defer
@@ -277,7 +275,7 @@ fn usz! Formatter.out_str(&self, any arg) @private
}
self.flags = {};
self.width = 0;
// this is SomeType[?] so grab the "SomeType"
// this is SomeType[*] so grab the "SomeType"
typeid inner = arg.type.inner;
usz size = inner.sizeof;
usz vlen = arg.type.len;
@@ -479,39 +477,6 @@ fn usz! Formatter.vprintf(&self, String format, any[] anys)
case 'c':
total_len += self.out_char(current)!;
continue;
case 'H':
self.flags.uppercase = true;
nextcase;
case 'h':
char[] out @noinit;
switch (current)
{
case char[]:
out = *current;
case ichar[]:
out = *(char[]*)current;
default:
if (current.type.kindof == ARRAY && (current.type.inner == char.typeid || current.type.inner == ichar.typeid))
{
out = ((char*)current.ptr)[:current.type.sizeof];
break;
}
total_len += self.out_substr("<INVALID>")!;
continue;
}
if (self.flags.left)
{
usz len = print_hex_chars(self, out, self.flags.uppercase)!;
total_len += len;
total_len += self.pad(' ', self.width, len)!;
continue;
}
if (self.width)
{
total_len += self.pad(' ', self.width, out.len * 2)!;
}
total_len += print_hex_chars(self, out, self.flags.uppercase)!;
continue;
case 's':
if (self.flags.left)
{
@@ -520,14 +485,11 @@ fn usz! Formatter.vprintf(&self, String format, any[] anys)
total_len += self.pad(' ', self.width, len)!;
continue;
}
if (self.width)
{
OutputFn out_fn = self.out_fn;
self.out_fn = (OutputFn)&out_null_fn;
usz len = self.out_str(current)!;
self.out_fn = out_fn;
total_len += self.pad(' ', self.width, len)!;
}
OutputFn out_fn = self.out_fn;
self.out_fn = (OutputFn)&out_null_fn;
usz len = self.out_str(current)!;
self.out_fn = out_fn;
total_len += self.pad(' ', self.width, len)!;
total_len += self.out_str(current)!;
continue;
case 'p':

View File

@@ -9,22 +9,6 @@ fault FormattingFault
BAD_FORMAT
}
fn usz! print_hex_chars(Formatter* f, char[] out, bool uppercase) @inline
{
char past_10 = (uppercase ? 'A' : 'a') - 10;
usz len = 0;
foreach (c : out)
{
char digit = c >> 4;
f.out(digit + (digit < 10 ? '0' : past_10))!;
len++;
digit = c & 0xf;
f.out(digit + (digit < 10 ? '0' : past_10))!;
len++;
}
return len;
}
macro Formatter.first_err(&self, anyfault f)
{
if (self.first_fault) return self.first_fault;
@@ -231,6 +215,7 @@ fn usz! Formatter.floatformat(&self, FloatFormatting formatting, double y) @priv
if (!self.flags.left) len += self.pad(' ', self.width, 3 + pl)!;
String s = self.flags.uppercase ? "INF" : "inf";
if (math::is_nan(y)) s = self.flags.uppercase ? "NAN" : "nan";
len += s.len;
if (pl) len += self.out(is_neg ? '-' : '+')!;
len += self.out_chars(s)!;
if (self.flags.left) len += self.pad(' ', self.width, 3 + pl)!;
@@ -621,10 +606,6 @@ fn usz! Formatter.ntoa_any(&self, any arg, uint base) @private
fn usz! Formatter.out_char(&self, any arg) @private
{
if (!arg.type.kindof.is_int())
{
return self.out_substr("<NOT CHAR>");
}
usz len = 1;
uint l = 1;
// pre padding

View File

@@ -227,14 +227,7 @@ fn void! out_putstream_fn(void* data, char c) @private
fn void! out_putchar_fn(void* data @unused, char c) @private
{
$if env::TESTING:
// HACK: this is used for the purpose of unit test output hijacking
File* stdout = io::stdout();
assert(stdout.file);
libc::fputc(c, stdout.file);
$else
libc::putchar(c);
$endif
libc::putchar(c);
}
<*
@@ -270,7 +263,7 @@ fn usz! printfn(String format, args...) @maydiscard
Formatter formatter;
formatter.init(&out_putchar_fn);
usz! len = formatter.vprintf(format, args);
out_putchar_fn(null, '\n')!;
putchar('\n');
io::stdout().flush()!;
return len + 1;
}

View File

@@ -5,48 +5,57 @@ import libc;
@require mode.len > 0
@require filename.len > 0
*>
fn void*! native_fopen(String filename, String mode) @inline => @pool()
fn void*! native_fopen(String filename, String mode) @inline
{
$if env::WIN32:
void* file = libc::_wfopen(filename.to_temp_wstring(), mode.to_temp_wstring())!;
$else
void* file = libc::fopen(filename.zstr_tcopy(), mode.zstr_tcopy());
$endif
return file ?: file_open_errno()?;
@pool()
{
$if env::WIN32:
void* file = libc::_wfopen(filename.to_temp_wstring(), mode.to_temp_wstring())!;
$else
void* file = libc::fopen(filename.zstr_tcopy(), mode.zstr_tcopy());
$endif
return file ?: file_open_errno()?;
};
}
fn void! native_remove(String filename) => @pool()
fn void! native_remove(String filename)
{
$if env::WIN32:
CInt result = libc::_wremove(filename.to_temp_wstring())!;
$else
CInt result = libc::remove(filename.zstr_tcopy());
$endif
if (result)
@pool()
{
switch (libc::errno())
$if env::WIN32:
CInt result = libc::_wremove(filename.to_temp_wstring())!;
$else
CInt result = libc::remove(filename.zstr_tcopy());
$endif
if (result)
{
case errno::ENOENT:
return IoError.FILE_NOT_FOUND?;
case errno::EACCES:
default:
return IoError.FILE_CANNOT_DELETE?;
switch (libc::errno())
{
case errno::ENOENT:
return IoError.FILE_NOT_FOUND?;
case errno::EACCES:
default:
return IoError.FILE_CANNOT_DELETE?;
}
}
}
};
}
<*
@require mode.len > 0
@require filename.len > 0
*>
fn void*! native_freopen(void* file, String filename, String mode) @inline => @pool()
fn void*! native_freopen(void* file, String filename, String mode) @inline
{
$if env::WIN32:
file = libc::_wfreopen(filename.to_temp_wstring(), mode.to_temp_wstring(), file)!;
$else
file = libc::freopen(filename.zstr_tcopy(), mode.zstr_tcopy(), file);
$endif
return file ?: file_open_errno()?;
@pool()
{
$if env::WIN32:
file = libc::_wfreopen(filename.to_temp_wstring(), mode.to_temp_wstring(), file)!;
$else
file = libc::freopen(filename.zstr_tcopy(), mode.zstr_tcopy(), file);
$endif
return file ?: file_open_errno()?;
};
}
fn void! native_fseek(void* file, isz offset, Seek seek_mode) @inline
@@ -68,7 +77,7 @@ fn usz! native_fwrite(CFile file, char[] buffer) @inline
fn void! native_fputc(CInt c, CFile stream) @inline
{
if (libc::fputc(c, stream) == libc::EOF) return IoError.EOF?;
if (!libc::fputc(c, stream)) return IoError.EOF?;
}
fn usz! native_fread(CFile file, char[] buffer) @inline

View File

@@ -1,50 +1,56 @@
module std::io::os;
import libc, std::os, std::io;
fn void! native_stat(Stat* stat, String path) @if(env::DARWIN || env::LINUX || env::BSD_FAMILY) => @pool()
fn void! native_stat(Stat* stat, String path) @if(env::DARWIN || env::LINUX || env::BSD_FAMILY)
{
$if env::DARWIN || env::LINUX || env::BSD_FAMILY:
int res = libc::stat(path.zstr_tcopy(), stat);
$else
unreachable("Stat unimplemented");
int res = 0;
$endif
if (res != 0)
@pool()
{
switch (libc::errno())
$if env::DARWIN || env::LINUX || env::BSD_FAMILY:
int res = libc::stat(path.zstr_tcopy(), stat);
$else
unreachable("Stat unimplemented");
int res = 0;
$endif
if (res != 0)
{
case errno::EBADF:
return IoError.FILE_NOT_VALID?;
case errno::EFAULT:
unreachable("Invalid stat");
case errno::EIO:
return IoError.GENERAL_ERROR?;
case errno::EACCES:
return IoError.NO_PERMISSION?;
case errno::ELOOP:
return IoError.NO_PERMISSION?;
case errno::ENAMETOOLONG:
return IoError.NAME_TOO_LONG?;
case errno::ENOENT:
return IoError.FILE_NOT_FOUND?;
case errno::ENOTDIR:
return IoError.FILE_NOT_DIR?;
case errno::EOVERFLOW:
return IoError.GENERAL_ERROR?;
default:
return IoError.UNKNOWN_ERROR?;
switch (libc::errno())
{
case errno::EBADF:
return IoError.FILE_NOT_VALID?;
case errno::EFAULT:
unreachable("Invalid stat");
case errno::EIO:
return IoError.GENERAL_ERROR?;
case errno::EACCES:
return IoError.NO_PERMISSION?;
case errno::ELOOP:
return IoError.NO_PERMISSION?;
case errno::ENAMETOOLONG:
return IoError.NAME_TOO_LONG?;
case errno::ENOENT:
return IoError.FILE_NOT_FOUND?;
case errno::ENOTDIR:
return IoError.FILE_NOT_DIR?;
case errno::EOVERFLOW:
return IoError.GENERAL_ERROR?;
default:
return IoError.UNKNOWN_ERROR?;
}
}
}
};
}
fn usz! native_file_size(String path) @if(env::WIN32) => @pool()
fn usz! native_file_size(String path) @if(env::WIN32)
{
Win32_FILE_ATTRIBUTE_DATA data;
win32::getFileAttributesExW(path.to_temp_wstring()!, Win32_GET_FILEEX_INFO_LEVELS.STANDARD, &data);
Win32_LARGE_INTEGER size;
size.lowPart = data.nFileSizeLow;
size.highPart = data.nFileSizeHigh;
return (usz)size.quadPart;
@pool()
{
Win32_FILE_ATTRIBUTE_DATA data;
win32::getFileAttributesExW(path.to_temp_wstring()!, Win32_GET_FILEEX_INFO_LEVELS.STANDARD, &data);
Win32_LARGE_INTEGER size;
size.lowPart = data.nFileSizeLow;
size.highPart = data.nFileSizeHigh;
return (usz)size.quadPart;
};
}
fn usz! native_file_size(String path) @if(!env::WIN32 && !env::DARWIN)

View File

@@ -4,7 +4,7 @@ import std::io, std::os;
fn PathList! native_ls(Path dir, bool no_dirs, bool no_symlinks, String mask, Allocator allocator)
{
PathList list;
list.init(allocator);
list.new_init(allocator: allocator);
DIRPtr directory = posix::opendir(dir.str_view() ? dir.as_zstr() : (ZString)".");
defer if (directory) posix::closedir(directory);
if (!directory) return (path::is_dir(dir) ? IoError.CANNOT_READ_DIR : IoError.FILE_NOT_DIR)?;
@@ -27,7 +27,7 @@ import std::time, std::os, std::io;
fn PathList! native_ls(Path dir, bool no_dirs, bool no_symlinks, String mask, Allocator allocator)
{
PathList list;
list.init(allocator);
list.new_init(allocator: allocator);
@pool(allocator)
{

View File

@@ -2,7 +2,7 @@ module std::io::os @if(env::POSIX);
import std::io, std::os, libc;
<*
@require dir.str_view().len > 0
@require dir.str_view()
*>
fn void! native_rmtree(Path dir)
{

View File

@@ -11,13 +11,16 @@ fn Path! native_temp_directory(Allocator allocator = allocator::heap()) @if(!env
return path::new("/tmp", allocator);
}
fn Path! native_temp_directory(Allocator allocator = allocator::heap()) @if(env::WIN32) => @pool(allocator)
fn Path! native_temp_directory(Allocator allocator = allocator::heap()) @if(env::WIN32)
{
Win32_DWORD len = win32::getTempPathW(0, null);
if (!len) return IoError.GENERAL_ERROR?;
Char16[] buff = mem::temp_alloc_array(Char16, len + (usz)1);
if (!win32::getTempPathW(len, buff)) return IoError.GENERAL_ERROR?;
return path::new(string::temp_from_utf16(buff[:len]), allocator);
@pool(allocator)
{
Win32_DWORD len = win32::getTempPathW(0, null);
if (!len) return IoError.GENERAL_ERROR?;
Char16[] buff = mem::temp_alloc_array(Char16, len + (usz)1);
if (!win32::getTempPathW(len, buff)) return IoError.GENERAL_ERROR?;
return path::new(string::temp_from_utf16(buff[:len]), allocator);
};
}
module std::io::os @if(env::NO_LIBC);

View File

@@ -29,9 +29,12 @@ enum PathEnv
POSIX
}
fn Path! new_cwd(Allocator allocator = allocator::heap()) => @pool(allocator)
fn Path! new_cwd(Allocator allocator = allocator::heap())
{
return new(os::getcwd(allocator::temp()), allocator);
@pool(allocator)
{
return new(os::getcwd(allocator::temp()), allocator);
};
}
fn Path! getcwd(Allocator allocator = allocator::heap()) @deprecated("Use new_cwd()")
@@ -161,9 +164,12 @@ 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()) => @pool(allocator)
fn Path! new_win32_wstring(WString path, Allocator allocator = allocator::heap())
{
return path::new(string::temp_from_wstring(path)!, allocator: allocator);
@pool(allocator)
{
return path::new(string::temp_from_wstring(path)!, allocator: allocator);
};
}
fn Path! new_windows(String path, Allocator allocator = allocator::heap())
@@ -274,7 +280,7 @@ fn Path! Path.new_absolute(self, Allocator allocator = allocator::heap())
};
$else
String cwd = os::getcwd(allocator::temp())!;
return (Path){ cwd, self.env }.new_append(path_str, allocator)!;
return Path { cwd, self.env }.new_append(path_str, allocator)!;
$endif
}
@@ -395,7 +401,7 @@ fn Path! Path.parent(self)
fn String! normalize(String path_str, PathEnv path_env = DEFAULT_PATH_ENV)
{
if (!path_str.len) return path_str;
if (!path_str.len) return "";
usz path_start = volume_name_len(path_str, path_env)!;
if (path_start > 0 && path_env == PathEnv.WIN32)
{
@@ -506,11 +512,7 @@ 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--;
if (path_str.len > len) path_str.ptr[len] = 0;
// Empty path after normalization -> "."
if (!len)
{
path_str[0] = '.';
return path_str[:1];
}
if (!len) return ".";
return path_str[:len];
}

View File

@@ -80,23 +80,7 @@ macro usz! read_all(stream, char[] buffer)
<*
@require @is_instream(stream)
*>
macro char[]! read_new_fully(stream, Allocator allocator = allocator::heap()) @deprecated("Use read_fully(mem)")
{
usz len = available(stream)!;
char* data = allocator::malloc_try(allocator, len)!;
defer catch allocator::free(allocator, data);
usz read = 0;
while (read < len)
{
read += stream.read(data[read:len - read])!;
}
return data[:len];
}
<*
@require @is_instream(stream)
*>
macro char[]! read_fully(Allocator allocator, stream)
macro char[]! read_new_fully(stream, Allocator allocator = allocator::heap())
{
usz len = available(stream)!;
char* data = allocator::malloc_try(allocator, len)!;
@@ -120,12 +104,7 @@ macro usz! write_all(stream, char[] buffer)
return n;
}
macro usz! @read_using_read_byte(&s, char[] buffer) @deprecated
{
return read_using_read_byte(*s, buffer);
}
macro usz! read_using_read_byte(s, char[] buffer)
macro usz! @read_using_read_byte(&s, char[] buffer)
{
usz len = 0;
foreach (&cptr : buffer)
@@ -142,26 +121,17 @@ macro usz! read_using_read_byte(s, char[] buffer)
return len;
}
macro void! write_byte_using_write(s, char c)
macro void! @write_byte_using_write(&s, char c)
{
char[1] buff = { c };
s.write(&buff)!;
(*s).write(&buff)!;
}
macro void! @write_byte_using_write(&s, char c) @deprecated
{
return write_byte_using_write(*s, c);
}
macro char! @read_byte_using_read(&s) @deprecated
{
return read_byte_using_read(*s);
}
macro char! read_byte_using_read(s)
macro char! @read_byte_using_read(&s)
{
char[1] buffer;
usz read = s.read(&buffer)!;
usz read = (*s).read(&buffer)!;
if (read != 1) return IoError.EOF?;
return buffer[0];
}
@@ -169,23 +139,13 @@ macro char! read_byte_using_read(s)
def ReadByteFn = fn char!();
macro usz! write_using_write_byte(s, char[] bytes)
macro usz! @write_using_write_byte(&s, char[] bytes)
{
foreach (c : bytes) s.write_byte(self, c)!;
return bytes.len;
}
macro usz! @write_using_write_byte(&s, char[] bytes) @deprecated
{
return write_using_write_byte(*s, bytes);
}
macro void! pushback_using_seek(s)
{
s.seek(-1, CURSOR)!;
}
macro void! @pushback_using_seek(&s) @deprecated
macro void! @pushback_using_seek(&s)
{
s.seek(-1, CURSOR)!;
}
@@ -197,12 +157,12 @@ fn usz! copy_to(InStream in, OutStream dst, char[] buffer = {})
if (&dst.read_to) return dst.read_to(in);
$switch (env::MEMORY_ENV)
$case NORMAL:
return copy_through_buffer(in, dst, &&(char[4096]){});
return copy_through_buffer(in, dst, &&char[4096]{});
$case SMALL:
return copy_through_buffer(in, dst, &&(char[1024]){});
return copy_through_buffer(in, dst, &&char[1024]{});
$case TINY:
$case NONE:
return copy_through_buffer(in, dst, &&(char[256]){});
return copy_through_buffer(in, dst, &&(char[256]{}));
$endswitch
}
@@ -224,7 +184,7 @@ macro usz! copy_through_buffer(InStream in, OutStream dst, char[] buffer) @local
}
}
const char[?] MAX_VARS @private = { [2] = 3, [4] = 5, [8] = 10 };
const char[*] MAX_VARS @private = { [2] = 3, [4] = 5, [8] = 10 };
<*
@require @is_instream(stream)

View File

@@ -16,42 +16,24 @@ 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(&self, Allocator allocator, usz max_read, usz initial_capacity = 16)
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);
self.grow(initial_capacity);
self.grow(initial_capacity)!;
return self;
}
<*
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()) @deprecated("Use init(mem)")
fn ByteBuffer*! ByteBuffer.temp_init(&self, usz max_read, usz initial_capacity = 16)
{
*self = { .allocator = allocator, .max_read = max_read };
initial_capacity = max(initial_capacity, 16);
self.grow(initial_capacity);
return self;
}
fn ByteBuffer* ByteBuffer.tinit(&self, usz max_read, usz initial_capacity = 16)
{
return self.init(allocator::temp(), max_read, initial_capacity);
}
fn ByteBuffer* ByteBuffer.temp_init(&self, usz max_read, usz initial_capacity = 16) @deprecated("Use tinit()")
{
return self.init(allocator::temp(), max_read, initial_capacity);
return self.new_init(max_read, initial_capacity, allocator::temp());
}
<*
@require buf.len > 0
@require self.bytes.len == 0 "Buffer already initialized."
*>
fn ByteBuffer* ByteBuffer.init_with_buffer(&self, char[] buf)
fn ByteBuffer*! ByteBuffer.init_with_buffer(&self, char[] buf)
{
*self = { .max_read = buf.len, .bytes = buf };
return self;
@@ -66,7 +48,7 @@ fn void ByteBuffer.free(&self)
fn usz! ByteBuffer.write(&self, char[] bytes) @dynamic
{
usz cap = self.bytes.len - self.write_idx;
if (cap < bytes.len) self.grow(bytes.len);
if (cap < bytes.len) self.grow(bytes.len)!;
self.bytes[self.write_idx:bytes.len] = bytes[..];
self.write_idx += bytes.len;
return bytes.len;
@@ -75,7 +57,7 @@ fn usz! ByteBuffer.write(&self, char[] bytes) @dynamic
fn void! ByteBuffer.write_byte(&self, char c) @dynamic
{
usz cap = self.bytes.len - self.write_idx;
if (cap == 0) self.grow(1);
if (cap == 0) self.grow(1)!;
self.bytes[self.write_idx] = c;
self.write_idx++;
}
@@ -146,10 +128,10 @@ fn usz! ByteBuffer.available(&self) @inline @dynamic
return self.write_idx - self.read_idx;
}
fn void ByteBuffer.grow(&self, usz n)
fn void! ByteBuffer.grow(&self, usz n)
{
n = math::next_power_of_2(n);
char* p = allocator::realloc(self.allocator, self.bytes, n);
char* p = allocator::realloc_aligned(self.allocator, self.bytes, n, alignment: char.alignof)!;
self.bytes = p[:n];
}

View File

@@ -14,19 +14,7 @@ struct ByteWriter (OutStream)
@require self.bytes.len == 0 "Init may not run on already initialized data"
@ensure (bool)allocator, self.index == 0
*>
fn ByteWriter* ByteWriter.new_init(&self, Allocator allocator = allocator::heap()) @deprecated("Use init(mem)")
{
*self = { .bytes = {}, .allocator = allocator };
return self;
}
<*
@param [&inout] self
@param [&inout] allocator
@require self.bytes.len == 0 "Init may not run on already initialized data"
@ensure (bool)allocator, self.index == 0
*>
fn ByteWriter* ByteWriter.init(&self, Allocator allocator)
fn ByteWriter* ByteWriter.new_init(&self, Allocator allocator = allocator::heap())
{
*self = { .bytes = {}, .allocator = allocator };
return self;
@@ -37,19 +25,9 @@ fn ByteWriter* ByteWriter.init(&self, Allocator allocator)
@require self.bytes.len == 0 "Init may not run on already initialized data"
@ensure self.index == 0
*>
fn ByteWriter* ByteWriter.tinit(&self)
fn ByteWriter* ByteWriter.temp_init(&self)
{
return self.init(allocator::temp()) @inline;
}
<*
@param [&inout] self
@require self.bytes.len == 0 "Init may not run on already initialized data"
@ensure self.index == 0
*>
fn ByteWriter* ByteWriter.temp_init(&self) @deprecated("Use tinit")
{
return self.init(allocator::temp()) @inline;
return self.new_init(allocator::temp()) @inline;
}
fn ByteWriter* ByteWriter.init_with_buffer(&self, char[] data)

View File

@@ -18,21 +18,7 @@ struct MultiReader (InStream)
@require self.readers.len == 0 "Init may not run on already initialized data"
@ensure self.index == 0
*>
fn MultiReader* MultiReader.new_init(&self, InStream... readers, Allocator allocator = allocator::heap()) @deprecated("Use init(mem)")
{
InStream []copy = allocator::new_array(allocator, InStream, readers.len);
copy[..] = readers[..];
*self = { .readers = copy, .allocator = allocator };
return self;
}
<*
@param [&inout] self
@param [&inout] allocator
@require self.readers.len == 0 "Init may not run on already initialized data"
@ensure self.index == 0
*>
fn MultiReader* MultiReader.init(&self, Allocator allocator, InStream... readers)
fn MultiReader* MultiReader.new_init(&self, InStream... readers, Allocator allocator = allocator::heap())
{
InStream []copy = allocator::new_array(allocator, InStream, readers.len);
copy[..] = readers[..];
@@ -45,19 +31,9 @@ fn MultiReader* MultiReader.init(&self, Allocator allocator, InStream... readers
@require self.readers.len == 0 "Init may not run on already initialized data"
@ensure self.index == 0
*>
fn MultiReader* MultiReader.temp_init(&self, InStream... readers) @deprecated("Use tinit()")
fn MultiReader* MultiReader.temp_init(&self, InStream... readers)
{
return self.init(allocator::temp(), ...readers);
}
<*
@param [&inout] self
@require self.readers.len == 0 "Init may not run on already initialized data"
@ensure self.index == 0
*>
fn MultiReader* MultiReader.tinit(&self, InStream... readers)
{
return self.init(allocator::temp(), ...readers);
return self.new_init(...readers, allocator: allocator::temp());
}
fn void MultiReader.free(&self)

View File

@@ -15,21 +15,7 @@ struct MultiWriter (OutStream)
@require writers.len > 0
@require self.writers.len == 0 "Init may not run on already initialized data"
*>
fn MultiWriter* MultiWriter.init(&self, Allocator allocator, OutStream... writers)
{
OutStream[] copy = allocator::new_array(allocator, OutStream, writers.len);
copy[..] = writers[..];
*self = { .writers = copy, .allocator = allocator };
return self;
}
<*
@param [&inout] self
@param [&inout] allocator
@require writers.len > 0
@require self.writers.len == 0 "Init may not run on already initialized data"
*>
fn MultiWriter* MultiWriter.new_init(&self, OutStream... writers, Allocator allocator = allocator::heap()) @deprecated("Use init(mem)")
fn MultiWriter* MultiWriter.new_init(&self, OutStream... writers, Allocator allocator = allocator::heap())
{
OutStream[] copy = allocator::new_array(allocator, OutStream, writers.len);
copy[..] = writers[..];
@@ -42,19 +28,9 @@ fn MultiWriter* MultiWriter.new_init(&self, OutStream... writers, Allocator allo
@require writers.len > 0
@require self.writers.len == 0 "Init may not run on already initialized data"
*>
fn MultiWriter* MultiWriter.temp_init(&self, OutStream... writers) @deprecated("Use tinit")
fn MultiWriter* MultiWriter.temp_init(&self, OutStream... writers)
{
return self.init(allocator::temp(), ...writers);
}
<*
@param [&inout] self
@require writers.len > 0
@require self.writers.len == 0 "Init may not run on already initialized data"
*>
fn MultiWriter* MultiWriter.tinit(&self, OutStream... writers)
{
return self.init(allocator::temp(), ...writers);
return self.new_init(...writers, allocator: allocator::temp());
}
fn void MultiWriter.free(&self)

View File

@@ -43,8 +43,7 @@ const CInt SIGINT = 2;
const CInt SIGQUIT = 3;
const CInt SIGILL = 4;
const CInt SIGTRAP = 5;
const CInt SIGABRT = 6;
const CInt SIGABTR @deprecated("use SIGABRT") = SIGABRT;
const CInt SIGABTR = 6;
const CInt SIGBUS = BSD_FLAVOR_SIG ? 10 : 7; // Or Mips
const CInt SIGFPE = 8;
const CInt SIGKILL = 9;
@@ -109,7 +108,6 @@ extern fn ZString getenv(ZString name);
extern fn ZString gets(char* buffer);
extern fn Tm* gmtime(Time_t* timer);
extern fn Tm* gmtime_r(Time_t *timer, Tm* buf) @if(!env::WIN32);
extern fn CInt isatty(Fd fd) @if(!env::WIN32);
extern fn CLong labs(CLong x);
extern fn LongDivResult ldiv(CLong number, CLong denom);
extern fn Tm* localtime(Time_t* timer);
@@ -167,12 +165,11 @@ extern fn double strtod(char* str, char** endptr);
extern fn float strtof(char* str, char** endptr);
extern fn ZString strtok(ZString str, ZString delim);
extern fn CLong strtol(char* str, char** endptr, CInt base);
extern fn CULong strtoul(char* str, char** endptr, CInt base);
extern fn CULong strtul(char* str, char** endptr, CInt base);
extern fn usz strxfrm(char* dest, ZString src, usz n);
extern fn CInt system(ZString str);
extern fn Time_t timegm(Tm *timeptr) @if(!env::WIN32);
extern fn ZString tmpnam(ZString str);
extern fn CFile tmpfile();
extern fn CInt ungetc(CInt c, CFile stream);
extern fn CInt unsetenv(ZString name);
extern fn isz write(Fd fd, void* buffer, usz count) @if(!env::WIN32);

View File

@@ -1,10 +1,5 @@
module libc @if(env::POSIX);
const CInt SHUT_RD = 0;
const CInt SHUT_WR = 1;
const CInt SHUT_RDWR = 2;
extern fn CInt shutdown(Fd sockfd, CInt how);
extern fn isz recv(Fd socket, void *buffer, usz length, CInt flags);
extern fn isz send(Fd socket, void *buffer, usz length, CInt flags);

View File

@@ -10,7 +10,6 @@ extern fn CInt _fseeki64(CFile, long, int); def fseek = _fseeki64;
extern fn CLong _ftelli64(CFile); def ftell = _ftelli64;
extern fn Errno _get_timezone(CLong *timezone);
extern fn Tm* _gmtime64_s(Tm* buf, Time_t *timer);
extern fn CInt _isatty(Fd fd); def isatty = _isatty;
extern fn Tm* _localtime64_s(Tm* buf, Time_t *timer);
extern fn Time_t _mkgmtime64(Tm* timeptr); def timegm = _mkgmtime64;
extern fn Time_t _mktime64(Tm *timeptr); def mktime = _mktime64;
@@ -24,11 +23,6 @@ extern fn CInt _wremove(WString);
extern fn int recv(Win32_SOCKET s, void* buf, int len, int flags);
extern fn int send(Win32_SOCKET s, void* buf, int len, int flags);
const CInt SD_RECEIVE = 0;
const CInt SD_SEND = 1;
const CInt SD_BOTH = 2;
extern fn CInt shutdown(Win32_SOCKET s, CInt how);
struct SystemInfo
{
union {
@@ -56,4 +50,4 @@ macro Tm* localtime_r(Time_t* timer, Tm* buf) => _localtime64_s(buf, timer);
macro CInt setjmp(JmpBuf* buffer) => _setjmp(buffer, null);
macro Tm* gmtime_r(Time_t* timer, Tm* buf) => _gmtime64_s(buf, timer);
macro isz read(Fd fd, void* buffer, usz buffer_size) => _read(fd, buffer, (CUInt)buffer_size);
macro isz write(Fd fd, void* buffer, usz count) => _write(fd, buffer, (CUInt)count);
macro isz write(Fd fd, void* buffer, usz count) => _write(fd, buffer, (CUInt)count);

View File

@@ -35,7 +35,7 @@ fn BigInt* BigInt.init(&self, int128 value)
len++;
}
assert(value < 0 || tmp == 0 || !self.is_negative());
assert(value >= 0 || tmp == -1 || self.is_negative());
assert(value > 0 || tmp == -1 || self.is_negative());
self.len = len;
self.reduce_len();
return self;
@@ -44,15 +44,16 @@ fn BigInt* BigInt.init(&self, int128 value)
fn BigInt* BigInt.init_with_u128(&self, uint128 value)
{
self.data[..] = 0;
uint128 tmp = value;
int128 tmp = value;
uint len = 0;
while (tmp != 0)
while (tmp != 0 && len < MAX_LEN)
{
self.data[len] = (uint)(tmp & 0xFFFFFFFF);
tmp >>= 32;
len++;
}
assert(!self.is_negative());
self.len = len;
assert(value == 0 || tmp == 0 || !self.is_negative());
self.len = max(len, 1);
return self;
}
@@ -63,18 +64,11 @@ fn BigInt* BigInt.init_with_u128(&self, uint128 value)
fn BigInt* BigInt.init_with_array(&self, uint[] values)
{
self.data[..] = 0;
if (values.len == 0)
{
self.len = 1;
return self;
}
self.len = values.len;
foreach_r(i, val : values)
{
self.data[values.len - 1 - i] = val;
values[values.len - 1 - i] = val;
}
while (self.len > 1 && self.data[self.len - 1] == 0)
{
@@ -98,9 +92,9 @@ fn BigInt*! BigInt.init_string_radix(&self, String value, int radix)
case '0'..'9':
pos_val -= '0';
case 'A'..'Z':
pos_val -= 'A' - 10;
pos_val -= 'A' + 10;
case 'a'..'z':
pos_val -= 'a' - 10;
pos_val -= 'a' + 10;
default:
return NumberConversion.MALFORMED_INTEGER?;
}
@@ -451,13 +445,13 @@ fn BigInt BigInt.shl(self, int shift)
return self;
}
macro bool BigInt.equals(&self, BigInt other)
macro bool BigInt.equals(&self, BigInt* &other) @safemacro
{
if (self.len != other.len) return false;
return self.data[:self.len] == other.data[:self.len];
}
macro bool BigInt.greater_than(&self, BigInt other)
macro bool BigInt.greater_than(&self, BigInt* &other) @safemacro
{
if (self.is_negative() && !other.is_negative()) return false;
if (!self.is_negative() && other.is_negative()) return true;
@@ -467,7 +461,7 @@ macro bool BigInt.greater_than(&self, BigInt other)
for (pos = len - 1; pos >= 0 && self.data[pos] == other.data[pos]; pos--);
return pos >= 0 && self.data[pos] > other.data[pos];
}
macro bool BigInt.less_than(&self, BigInt other)
macro bool BigInt.less_than(&self, BigInt* &other) @safemacro
{
if (self.is_negative() && !other.is_negative()) return true;
if (!self.is_negative() && other.is_negative()) return false;
@@ -491,14 +485,14 @@ fn bool BigInt.is_one(&self)
}
macro bool BigInt.greater_or_equal(&self, BigInt other)
macro bool BigInt.greater_or_equal(&self, BigInt* &other) @safemacro
{
return self.greater_than(other) || self.equals(other);
return self.greater_than(*other) || self.equals(*other);
}
macro bool BigInt.less_or_equal(&self, BigInt)
macro bool BigInt.less_or_equal(&self, BigInt* &other) @safemacro
{
return self.less_than(other) || self.equals(other);
return self.less_than(*other) || self.equals(*other);
}
fn BigInt BigInt.abs(&self)
@@ -526,12 +520,12 @@ fn String BigInt.to_string_with_radix(&self, int radix, Allocator allocator)
{
if (self.is_zero()) return "0".copy(allocator);
const char[?] CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const char[*] CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
@stack_mem(4100; Allocator mem)
{
BigInt a = *self;
DString str;
str.init(mem, 4096);
str.new_init(4096, allocator: mem);
bool negative = self.is_negative();
if (negative)
{

View File

@@ -92,13 +92,13 @@ fault MatrixError
def Complexf = Complex(<float>);
def Complex = Complex(<double>);
def COMPLEX_IDENTITY = complex::IDENTITY(<double>) @builtin;
def COMPLEXF_IDENTITY = complex::IDENTITY(<float>) @builtin;
def COMPLEX_IDENTITY = complex::IDENTITY(<double>);
def COMPLEXF_IDENTITY = complex::IDENTITY(<float>);
def Quaternionf = Quaternion(<float>);
def Quaternion = Quaternion(<double>);
def QUATERNION_IDENTITY = quaternion::IDENTITY(<double>) @builtin;
def QUATERNIONF_IDENTITY = quaternion::IDENTITY(<float>) @builtin;
def QUATERNION_IDENTITY = quaternion::IDENTITY(<double>);
def QUATERNIONF_IDENTITY = quaternion::IDENTITY(<float>);
def Matrix2f = Matrix2x2(<float>);
def Matrix2 = Matrix2x2(<double>);
@@ -106,17 +106,17 @@ def Matrix3f = Matrix3x3(<float>);
def Matrix3 = Matrix3x3(<double>);
def Matrix4f = Matrix4x4(<float>);
def Matrix4 = Matrix4x4(<double>);
def matrix4_ortho = matrix::ortho(<double>) @builtin;
def matrix4_perspective = matrix::perspective(<double>) @builtin;
def matrix4f_ortho = matrix::ortho(<float>) @builtin;
def matrix4f_perspective = matrix::perspective(<float>) @builtin;
def matrix4_ortho = matrix::ortho(<double>);
def matrix4_perspective = matrix::perspective(<double>);
def matrix4f_ortho = matrix::ortho(<float>);
def matrix4f_perspective = matrix::perspective(<float>);
def MATRIX2_IDENTITY = matrix::IDENTITY2(<double>) @builtin;
def MATRIX2F_IDENTITY = matrix::IDENTITY2(<float>) @builtin;
def MATRIX3_IDENTITY = matrix::IDENTITY3(<double>) @builtin;
def MATRIX3F_IDENTITY = matrix::IDENTITY3(<float>) @builtin;
def MATRIX4_IDENTITY = matrix::IDENTITY4(<double>) @builtin;
def MATRIX4F_IDENTITY = matrix::IDENTITY4(<float>) @builtin;
def MATRIX2_IDENTITY = matrix::IDENTITY2(<double>);
def MATRIX2F_IDENTITY = matrix::IDENTITY2(<float>);
def MATRIX3_IDENTITY = matrix::IDENTITY3(<double>);
def MATRIX3F_IDENTITY = matrix::IDENTITY3(<float>);
def MATRIX4_IDENTITY = matrix::IDENTITY4(<double>);
def MATRIX4F_IDENTITY = matrix::IDENTITY4(<float>);
<*
@@ -629,7 +629,7 @@ macro normalize(x) @private
@return "a vector of the same type as then/else"
*>
macro select(bool[<?>] mask, then_value, else_value)
macro select(bool[<*>] mask, then_value, else_value)
{
return $$select(mask, then_value, else_value);
}
@@ -647,35 +647,35 @@ macro float float.round(float x) => $$round(x);
macro float float.roundeven(float x) => $$roundeven(x);
macro float float.trunc(float x) => $$trunc(x);
macro float float[<?>].sum(float[<?>] x, float start = 0.0) => $$reduce_fadd(x, start);
macro float float[<?>].product(float[<?>] x, float start = 1.0) => $$reduce_fmul(x, start);
macro float float[<?>].max(float[<?>] x) => $$reduce_max(x);
macro float float[<?>].min(float[<?>] x) => $$reduce_min(x);
macro float[<?>] float[<?>].ceil(float[<?>] x) => $$ceil(x);
macro float[<?>] float[<?>].clamp(float[<?>] x, float[<?>] lower, float[<?>] upper) => $$max(lower, $$min(x, upper));
macro float[<?>] float[<?>].copysign(float[<?>] mag, float[<?>] sgn) => $$copysign(mag, sgn);
macro float[<?>] float[<?>].fma(float[<?>] a, float[<?>] b, float[<?>] c) => $$fma(a, b, c);
macro float[<?>] float[<?>].floor(float[<?>] x) => $$floor(x);
macro float[<?>] float[<?>].nearbyint(float[<?>] x) => $$nearbyint(x);
macro float[<?>] float[<?>].pow(float[<?>] x, exp) => pow(x, exp);
macro float[<?>] float[<?>].rint(float[<?>] x) => $$rint(x);
macro float[<?>] float[<?>].round(float[<?>] x) => $$round(x);
macro float[<?>] float[<?>].roundeven(float[<?>] x) => $$roundeven(x);
macro float[<?>] float[<?>].trunc(float[<?>] x) => $$trunc(x);
macro float float[<?>].dot(float[<?>] x, float[<?>] y) => (x * y).sum();
macro float float[<?>].length(float[<?>] x) => $$sqrt(x.dot(x));
macro float float[<?>].distance(float[<?>] x, float[<?>] y) => (x - y).length();
macro float[<?>] float[<?>].normalize(float[<?>] x) => normalize(x);
macro float[<?>] float[<?>].lerp(float[<?>] x, float[<?>] y, float amount) => lerp(x, y, amount);
macro float[<?>] float[<?>].reflect(float[<?>] x, float[<?>] y) => reflect(x, y);
macro bool float[<?>].equals(float[<?>] x, float[<?>] y) => equals_vec(x, y);
macro float float[<*>].sum(float[<*>] x, float start = 0.0) => $$reduce_fadd(x, start);
macro float float[<*>].product(float[<*>] x, float start = 1.0) => $$reduce_fmul(x, start);
macro float float[<*>].max(float[<*>] x) => $$reduce_max(x);
macro float float[<*>].min(float[<*>] x) => $$reduce_min(x);
macro float[<*>] float[<*>].ceil(float[<*>] x) => $$ceil(x);
macro float[<*>] float[<*>].clamp(float[<*>] x, float[<*>] lower, float[<*>] upper) => $$max(lower, $$min(x, upper));
macro float[<*>] float[<*>].copysign(float[<*>] mag, float[<*>] sgn) => $$copysign(mag, sgn);
macro float[<*>] float[<*>].fma(float[<*>] a, float[<*>] b, float[<*>] c) => $$fma(a, b, c);
macro float[<*>] float[<*>].floor(float[<*>] x) => $$floor(x);
macro float[<*>] float[<*>].nearbyint(float[<*>] x) => $$nearbyint(x);
macro float[<*>] float[<*>].pow(float[<*>] x, exp) => pow(x, exp);
macro float[<*>] float[<*>].rint(float[<*>] x) => $$rint(x);
macro float[<*>] float[<*>].round(float[<*>] x) => $$round(x);
macro float[<*>] float[<*>].roundeven(float[<*>] x) => $$roundeven(x);
macro float[<*>] float[<*>].trunc(float[<*>] x) => $$trunc(x);
macro float float[<*>].dot(float[<*>] x, float[<*>] y) => (x * y).sum();
macro float float[<*>].length(float[<*>] x) => $$sqrt(x.dot(x));
macro float float[<*>].distance(float[<*>] x, float[<*>] y) => (x - y).length();
macro float[<*>] float[<*>].normalize(float[<*>] x) => normalize(x);
macro float[<*>] float[<*>].lerp(float[<*>] x, float[<*>] y, float amount) => lerp(x, y, amount);
macro float[<*>] float[<*>].reflect(float[<*>] x, float[<*>] y) => reflect(x, y);
macro bool float[<*>].equals(float[<*>] x, float[<*>] y) => equals_vec(x, y);
macro bool[<?>] float[<?>].comp_lt(float[<?>] x, float[<?>] y) => $$veccomplt(x, y);
macro bool[<?>] float[<?>].comp_le(float[<?>] x, float[<?>] y) => $$veccomple(x, y);
macro bool[<?>] float[<?>].comp_eq(float[<?>] x, float[<?>] y) => $$veccompeq(x, y);
macro bool[<?>] float[<?>].comp_gt(float[<?>] x, float[<?>] y) => $$veccompgt(x, y);
macro bool[<?>] float[<?>].comp_ge(float[<?>] x, float[<?>] y) => $$veccompge(x, y);
macro bool[<?>] float[<?>].comp_ne(float[<?>] x, float[<?>] y) => $$veccompne(x, y);
macro bool[<*>] float[<*>].comp_lt(float[<*>] x, float[<*>] y) => $$veccomplt(x, y);
macro bool[<*>] float[<*>].comp_le(float[<*>] x, float[<*>] y) => $$veccomple(x, y);
macro bool[<*>] float[<*>].comp_eq(float[<*>] x, float[<*>] y) => $$veccompeq(x, y);
macro bool[<*>] float[<*>].comp_gt(float[<*>] x, float[<*>] y) => $$veccompgt(x, y);
macro bool[<*>] float[<*>].comp_ge(float[<*>] x, float[<*>] y) => $$veccompge(x, y);
macro bool[<*>] float[<*>].comp_ne(float[<*>] x, float[<*>] y) => $$veccompne(x, y);
macro double double.ceil(double x) => $$ceil(x);
macro double double.clamp(double x, double lower, double upper) => $$max(lower, $$min(x, upper));
@@ -690,208 +690,208 @@ macro double double.round(double x) => $$round(x);
macro double double.roundeven(double x) => $$roundeven(x);
macro double double.trunc(double x) => $$trunc(x);
macro double double[<?>].sum(double[<?>] x, double start = 0.0) => $$reduce_fadd(x, start);
macro double double[<?>].product(double[<?>] x, double start = 1.0) => $$reduce_fmul(x, start);
macro double double[<?>].max(double[<?>] x) => $$reduce_fmax(x);
macro double double[<?>].min(double[<?>] x) => $$reduce_fmin(x);
macro double[<?>] double[<?>].ceil(double[<?>] x) => $$ceil(x);
macro double[<?>] double[<?>].clamp(double[<?>] x, double[<?>] lower, double[<?>] upper) => $$max(lower, $$min(x, upper));
macro double[<?>] double[<?>].copysign(double[<?>] mag, double[<?>] sgn) => $$copysign(mag, sgn);
macro double[<?>] double[<?>].floor(double[<?>] x) => $$floor(x);
macro double[<?>] double[<?>].fma(double[<?>] a, double[<?>] b, double[<?>] c) => $$fma(a, b, c);
macro double[<?>] double[<?>].nearbyint(double[<?>] x) => $$nearbyint(x);
macro double[<?>] double[<?>].pow(double[<?>] x, exp) => pow(x, exp);
macro double[<?>] double[<?>].rint(double[<?>] x) => $$rint(x);
macro double[<?>] double[<?>].round(double[<?>] x) => $$round(x);
macro double[<?>] double[<?>].roundeven(double[<?>] x) => $$roundeven(x);
macro double[<?>] double[<?>].trunc(double[<?>] x) => $$trunc(x);
macro double double[<?>].dot(double[<?>] x, double[<?>] y) => (x * y).sum();
macro double double[<?>].length(double[<?>] x) => $$sqrt(x.dot(x));
macro double double[<?>].distance(double[<?>] x, double[<?>] y) => (x - y).length();
macro double[<?>] double[<?>].normalize(double[<?>] x) => normalize(x);
macro double[<?>] double[<?>].reflect(double[<?>] x, double[<?>] y) => reflect(x, y);
macro double[<?>] double[<?>].lerp(double[<?>] x, double[<?>] y, double amount) => lerp(x, y, amount);
macro bool double[<?>].equals(double[<?>] x, double[<?>] y) => equals_vec(x, y);
macro double double[<*>].sum(double[<*>] x, double start = 0.0) => $$reduce_fadd(x, start);
macro double double[<*>].product(double[<*>] x, double start = 1.0) => $$reduce_fmul(x, start);
macro double double[<*>].max(double[<*>] x) => $$reduce_fmax(x);
macro double double[<*>].min(double[<*>] x) => $$reduce_fmin(x);
macro double[<*>] double[<*>].ceil(double[<*>] x) => $$ceil(x);
macro double[<*>] double[<*>].clamp(double[<*>] x, double[<*>] lower, double[<*>] upper) => $$max(lower, $$min(x, upper));
macro double[<*>] double[<*>].copysign(double[<*>] mag, double[<*>] sgn) => $$copysign(mag, sgn);
macro double[<*>] double[<*>].floor(double[<*>] x) => $$floor(x);
macro double[<*>] double[<*>].fma(double[<*>] a, double[<*>] b, double[<*>] c) => $$fma(a, b, c);
macro double[<*>] double[<*>].nearbyint(double[<*>] x) => $$nearbyint(x);
macro double[<*>] double[<*>].pow(double[<*>] x, exp) => pow(x, exp);
macro double[<*>] double[<*>].rint(double[<*>] x) => $$rint(x);
macro double[<*>] double[<*>].round(double[<*>] x) => $$round(x);
macro double[<*>] double[<*>].roundeven(double[<*>] x) => $$roundeven(x);
macro double[<*>] double[<*>].trunc(double[<*>] x) => $$trunc(x);
macro double double[<*>].dot(double[<*>] x, double[<*>] y) => (x * y).sum();
macro double double[<*>].length(double[<*>] x) => $$sqrt(x.dot(x));
macro double double[<*>].distance(double[<*>] x, double[<*>] y) => (x - y).length();
macro double[<*>] double[<*>].normalize(double[<*>] x) => normalize(x);
macro double[<*>] double[<*>].reflect(double[<*>] x, double[<*>] y) => reflect(x, y);
macro double[<*>] double[<*>].lerp(double[<*>] x, double[<*>] y, double amount) => lerp(x, y, amount);
macro bool double[<*>].equals(double[<*>] x, double[<*>] y) => equals_vec(x, y);
macro bool[<?>] double[<?>].comp_lt(double[<?>] x, double[<?>] y) => $$veccomplt(x, y);
macro bool[<?>] double[<?>].comp_le(double[<?>] x, double[<?>] y) => $$veccomple(x, y);
macro bool[<?>] double[<?>].comp_eq(double[<?>] x, double[<?>] y) => $$veccompeq(x, y);
macro bool[<?>] double[<?>].comp_gt(double[<?>] x, double[<?>] y) => $$veccompgt(x, y);
macro bool[<?>] double[<?>].comp_ge(double[<?>] x, double[<?>] y) => $$veccompge(x, y);
macro bool[<?>] double[<?>].comp_ne(double[<?>] x, double[<?>] y) => $$veccompne(x, y);
macro bool[<*>] double[<*>].comp_lt(double[<*>] x, double[<*>] y) => $$veccomplt(x, y);
macro bool[<*>] double[<*>].comp_le(double[<*>] x, double[<*>] y) => $$veccomple(x, y);
macro bool[<*>] double[<*>].comp_eq(double[<*>] x, double[<*>] y) => $$veccompeq(x, y);
macro bool[<*>] double[<*>].comp_gt(double[<*>] x, double[<*>] y) => $$veccompgt(x, y);
macro bool[<*>] double[<*>].comp_ge(double[<*>] x, double[<*>] y) => $$veccompge(x, y);
macro bool[<*>] double[<*>].comp_ne(double[<*>] x, double[<*>] y) => $$veccompne(x, y);
macro bool[<?>] ichar[<?>].comp_lt(ichar[<?>] x, ichar[<?>] y) => $$veccomplt(x, y);
macro bool[<?>] ichar[<?>].comp_le(ichar[<?>] x, ichar[<?>] y) => $$veccomple(x, y);
macro bool[<?>] ichar[<?>].comp_eq(ichar[<?>] x, ichar[<?>] y) => $$veccompeq(x, y);
macro bool[<?>] ichar[<?>].comp_gt(ichar[<?>] x, ichar[<?>] y) => $$veccompgt(x, y);
macro bool[<?>] ichar[<?>].comp_ge(ichar[<?>] x, ichar[<?>] y) => $$veccompge(x, y);
macro bool[<?>] ichar[<?>].comp_ne(ichar[<?>] x, ichar[<?>] y) => $$veccompne(x, y);
macro bool[<*>] ichar[<*>].comp_lt(ichar[<*>] x, ichar[<*>] y) => $$veccomplt(x, y);
macro bool[<*>] ichar[<*>].comp_le(ichar[<*>] x, ichar[<*>] y) => $$veccomple(x, y);
macro bool[<*>] ichar[<*>].comp_eq(ichar[<*>] x, ichar[<*>] y) => $$veccompeq(x, y);
macro bool[<*>] ichar[<*>].comp_gt(ichar[<*>] x, ichar[<*>] y) => $$veccompgt(x, y);
macro bool[<*>] ichar[<*>].comp_ge(ichar[<*>] x, ichar[<*>] y) => $$veccompge(x, y);
macro bool[<*>] ichar[<*>].comp_ne(ichar[<*>] x, ichar[<*>] y) => $$veccompne(x, y);
macro ichar ichar[<?>].sum(ichar[<?>] x) => $$reduce_add(x);
macro ichar ichar[<?>].product(ichar[<?>] x) => $$reduce_mul(x);
macro ichar ichar[<?>].and(ichar[<?>] x) => $$reduce_and(x);
macro ichar ichar[<?>].or(ichar[<?>] x) => $$reduce_or(x);
macro ichar ichar[<?>].xor(ichar[<?>] x) => $$reduce_xor(x);
macro ichar ichar[<?>].max(ichar[<?>] x) => $$reduce_max(x);
macro ichar ichar[<?>].min(ichar[<?>] x) => $$reduce_min(x);
macro ichar ichar[<?>].dot(ichar[<?>] x, ichar[<?>] y) => (x * y).sum();
macro ichar ichar[<*>].sum(ichar[<*>] x) => $$reduce_add(x);
macro ichar ichar[<*>].product(ichar[<*>] x) => $$reduce_mul(x);
macro ichar ichar[<*>].and(ichar[<*>] x) => $$reduce_and(x);
macro ichar ichar[<*>].or(ichar[<*>] x) => $$reduce_or(x);
macro ichar ichar[<*>].xor(ichar[<*>] x) => $$reduce_xor(x);
macro ichar ichar[<*>].max(ichar[<*>] x) => $$reduce_max(x);
macro ichar ichar[<*>].min(ichar[<*>] x) => $$reduce_min(x);
macro ichar ichar[<*>].dot(ichar[<*>] x, ichar[<*>] y) => (x * y).sum();
macro bool[<?>] short[<?>].comp_lt(short[<?>] x, short[<?>] y) => $$veccomplt(x, y);
macro bool[<?>] short[<?>].comp_le(short[<?>] x, short[<?>] y) => $$veccomple(x, y);
macro bool[<?>] short[<?>].comp_eq(short[<?>] x, short[<?>] y) => $$veccompeq(x, y);
macro bool[<?>] short[<?>].comp_gt(short[<?>] x, short[<?>] y) => $$veccompgt(x, y);
macro bool[<?>] short[<?>].comp_ge(short[<?>] x, short[<?>] y) => $$veccompge(x, y);
macro bool[<?>] short[<?>].comp_ne(short[<?>] x, short[<?>] y) => $$veccompne(x, y);
macro bool[<*>] short[<*>].comp_lt(short[<*>] x, short[<*>] y) => $$veccomplt(x, y);
macro bool[<*>] short[<*>].comp_le(short[<*>] x, short[<*>] y) => $$veccomple(x, y);
macro bool[<*>] short[<*>].comp_eq(short[<*>] x, short[<*>] y) => $$veccompeq(x, y);
macro bool[<*>] short[<*>].comp_gt(short[<*>] x, short[<*>] y) => $$veccompgt(x, y);
macro bool[<*>] short[<*>].comp_ge(short[<*>] x, short[<*>] y) => $$veccompge(x, y);
macro bool[<*>] short[<*>].comp_ne(short[<*>] x, short[<*>] y) => $$veccompne(x, y);
macro short short[<?>].sum(short[<?>] x) => $$reduce_add(x);
macro short short[<?>].product(short[<?>] x) => $$reduce_mul(x);
macro short short[<?>].and(short[<?>] x) => $$reduce_and(x);
macro short short[<?>].or(short[<?>] x) => $$reduce_or(x);
macro short short[<?>].xor(short[<?>] x) => $$reduce_xor(x);
macro short short[<?>].max(short[<?>] x) => $$reduce_max(x);
macro short short[<?>].min(short[<?>] x) => $$reduce_min(x);
macro short short[<?>].dot(short[<?>] x, short[<?>] y) => (x * y).sum();
macro short short[<*>].sum(short[<*>] x) => $$reduce_add(x);
macro short short[<*>].product(short[<*>] x) => $$reduce_mul(x);
macro short short[<*>].and(short[<*>] x) => $$reduce_and(x);
macro short short[<*>].or(short[<*>] x) => $$reduce_or(x);
macro short short[<*>].xor(short[<*>] x) => $$reduce_xor(x);
macro short short[<*>].max(short[<*>] x) => $$reduce_max(x);
macro short short[<*>].min(short[<*>] x) => $$reduce_min(x);
macro short short[<*>].dot(short[<*>] x, short[<*>] y) => (x * y).sum();
macro bool[<?>] int[<?>].comp_lt(int[<?>] x, int[<?>] y) => $$veccomplt(x, y);
macro bool[<?>] int[<?>].comp_le(int[<?>] x, int[<?>] y) => $$veccomple(x, y);
macro bool[<?>] int[<?>].comp_eq(int[<?>] x, int[<?>] y) => $$veccompeq(x, y);
macro bool[<?>] int[<?>].comp_gt(int[<?>] x, int[<?>] y) => $$veccompgt(x, y);
macro bool[<?>] int[<?>].comp_ge(int[<?>] x, int[<?>] y) => $$veccompge(x, y);
macro bool[<?>] int[<?>].comp_ne(int[<?>] x, int[<?>] y) => $$veccompne(x, y);
macro bool[<*>] int[<*>].comp_lt(int[<*>] x, int[<*>] y) => $$veccomplt(x, y);
macro bool[<*>] int[<*>].comp_le(int[<*>] x, int[<*>] y) => $$veccomple(x, y);
macro bool[<*>] int[<*>].comp_eq(int[<*>] x, int[<*>] y) => $$veccompeq(x, y);
macro bool[<*>] int[<*>].comp_gt(int[<*>] x, int[<*>] y) => $$veccompgt(x, y);
macro bool[<*>] int[<*>].comp_ge(int[<*>] x, int[<*>] y) => $$veccompge(x, y);
macro bool[<*>] int[<*>].comp_ne(int[<*>] x, int[<*>] y) => $$veccompne(x, y);
macro int int[<?>].sum(int[<?>] x) => $$reduce_add(x);
macro int int[<?>].product(int[<?>] x) => $$reduce_mul(x);
macro int int[<?>].and(int[<?>] x) => $$reduce_and(x);
macro int int[<?>].or(int[<?>] x) => $$reduce_or(x);
macro int int[<?>].xor(int[<?>] x) => $$reduce_xor(x);
macro int int[<?>].max(int[<?>] x) => $$reduce_max(x);
macro int int[<?>].min(int[<?>] x) => $$reduce_min(x);
macro int int[<?>].dot(int[<?>] x, int[<?>] y) => (x * y).sum();
macro int int[<*>].sum(int[<*>] x) => $$reduce_add(x);
macro int int[<*>].product(int[<*>] x) => $$reduce_mul(x);
macro int int[<*>].and(int[<*>] x) => $$reduce_and(x);
macro int int[<*>].or(int[<*>] x) => $$reduce_or(x);
macro int int[<*>].xor(int[<*>] x) => $$reduce_xor(x);
macro int int[<*>].max(int[<*>] x) => $$reduce_max(x);
macro int int[<*>].min(int[<*>] x) => $$reduce_min(x);
macro int int[<*>].dot(int[<*>] x, int[<*>] y) => (x * y).sum();
macro bool[<?>] long[<?>].comp_lt(long[<?>] x, long[<?>] y) => $$veccomplt(x, y);
macro bool[<?>] long[<?>].comp_le(long[<?>] x, long[<?>] y) => $$veccomple(x, y);
macro bool[<?>] long[<?>].comp_eq(long[<?>] x, long[<?>] y) => $$veccompeq(x, y);
macro bool[<?>] long[<?>].comp_gt(long[<?>] x, long[<?>] y) => $$veccompgt(x, y);
macro bool[<?>] long[<?>].comp_ge(long[<?>] x, long[<?>] y) => $$veccompge(x, y);
macro bool[<?>] long[<?>].comp_ne(long[<?>] x, long[<?>] y) => $$veccompne(x, y);
macro long long[<?>].sum(long[<?>] x) => $$reduce_add(x);
macro long long[<?>].product(long[<?>] x) => $$reduce_mul(x);
macro long long[<?>].and(long[<?>] x) => $$reduce_and(x);
macro long long[<?>].or(long[<?>] x) => $$reduce_or(x);
macro long long[<?>].xor(long[<?>] x) => $$reduce_xor(x);
macro long long[<?>].max(long[<?>] x) => $$reduce_max(x);
macro long long[<?>].min(long[<?>] x) => $$reduce_min(x);
macro long long[<?>].dot(long[<?>] x, long[<?>] y) => (x * y).sum();
macro bool[<*>] long[<*>].comp_lt(long[<*>] x, long[<*>] y) => $$veccomplt(x, y);
macro bool[<*>] long[<*>].comp_le(long[<*>] x, long[<*>] y) => $$veccomple(x, y);
macro bool[<*>] long[<*>].comp_eq(long[<*>] x, long[<*>] y) => $$veccompeq(x, y);
macro bool[<*>] long[<*>].comp_gt(long[<*>] x, long[<*>] y) => $$veccompgt(x, y);
macro bool[<*>] long[<*>].comp_ge(long[<*>] x, long[<*>] y) => $$veccompge(x, y);
macro bool[<*>] long[<*>].comp_ne(long[<*>] x, long[<*>] y) => $$veccompne(x, y);
macro long long[<*>].sum(long[<*>] x) => $$reduce_add(x);
macro long long[<*>].product(long[<*>] x) => $$reduce_mul(x);
macro long long[<*>].and(long[<*>] x) => $$reduce_and(x);
macro long long[<*>].or(long[<*>] x) => $$reduce_or(x);
macro long long[<*>].xor(long[<*>] x) => $$reduce_xor(x);
macro long long[<*>].max(long[<*>] x) => $$reduce_max(x);
macro long long[<*>].min(long[<*>] x) => $$reduce_min(x);
macro long long[<*>].dot(long[<*>] x, long[<*>] y) => (x * y).sum();
macro bool[<?>] int128[<?>].comp_lt(int128[<?>] x, int128[<?>] y) => $$veccomplt(x, y);
macro bool[<?>] int128[<?>].comp_le(int128[<?>] x, int128[<?>] y) => $$veccomple(x, y);
macro bool[<?>] int128[<?>].comp_eq(int128[<?>] x, int128[<?>] y) => $$veccompeq(x, y);
macro bool[<?>] int128[<?>].comp_gt(int128[<?>] x, int128[<?>] y) => $$veccompgt(x, y);
macro bool[<?>] int128[<?>].comp_ge(int128[<?>] x, int128[<?>] y) => $$veccompge(x, y);
macro bool[<?>] int128[<?>].comp_ne(int128[<?>] x, int128[<?>] y) => $$veccompne(x, y);
macro int128 int128[<?>].sum(int128[<?>] x) => $$reduce_add(x);
macro int128 int128[<?>].product(int128[<?>] x) => $$reduce_mul(x);
macro int128 int128[<?>].and(int128[<?>] x) => $$reduce_and(x);
macro int128 int128[<?>].or(int128[<?>] x) => $$reduce_or(x);
macro int128 int128[<?>].xor(int128[<?>] x) => $$reduce_xor(x);
macro int128 int128[<?>].max(int128[<?>] x) => $$reduce_max(x);
macro int128 int128[<?>].min(int128[<?>] x) => $$reduce_min(x);
macro int128 int128[<?>].dot(int128[<?>] x, int128[<?>] y) => (x * y).sum();
macro bool[<*>] int128[<*>].comp_lt(int128[<*>] x, int128[<*>] y) => $$veccomplt(x, y);
macro bool[<*>] int128[<*>].comp_le(int128[<*>] x, int128[<*>] y) => $$veccomple(x, y);
macro bool[<*>] int128[<*>].comp_eq(int128[<*>] x, int128[<*>] y) => $$veccompeq(x, y);
macro bool[<*>] int128[<*>].comp_gt(int128[<*>] x, int128[<*>] y) => $$veccompgt(x, y);
macro bool[<*>] int128[<*>].comp_ge(int128[<*>] x, int128[<*>] y) => $$veccompge(x, y);
macro bool[<*>] int128[<*>].comp_ne(int128[<*>] x, int128[<*>] y) => $$veccompne(x, y);
macro int128 int128[<*>].sum(int128[<*>] x) => $$reduce_add(x);
macro int128 int128[<*>].product(int128[<*>] x) => $$reduce_mul(x);
macro int128 int128[<*>].and(int128[<*>] x) => $$reduce_and(x);
macro int128 int128[<*>].or(int128[<*>] x) => $$reduce_or(x);
macro int128 int128[<*>].xor(int128[<*>] x) => $$reduce_xor(x);
macro int128 int128[<*>].max(int128[<*>] x) => $$reduce_max(x);
macro int128 int128[<*>].min(int128[<*>] x) => $$reduce_min(x);
macro int128 int128[<*>].dot(int128[<*>] x, int128[<*>] y) => (x * y).sum();
macro bool[<?>] bool[<?>].comp_lt(bool[<?>] x, bool[<?>] y) => $$veccomplt(x, y);
macro bool[<?>] bool[<?>].comp_le(bool[<?>] x, bool[<?>] y) => $$veccomple(x, y);
macro bool[<?>] bool[<?>].comp_eq(bool[<?>] x, bool[<?>] y) => $$veccompeq(x, y);
macro bool[<?>] bool[<?>].comp_gt(bool[<?>] x, bool[<?>] y) => $$veccompgt(x, y);
macro bool[<?>] bool[<?>].comp_ge(bool[<?>] x, bool[<?>] y) => $$veccompge(x, y);
macro bool[<?>] bool[<?>].comp_ne(bool[<?>] x, bool[<?>] y) => $$veccompne(x, y);
macro bool[<*>] bool[<*>].comp_lt(bool[<*>] x, bool[<*>] y) => $$veccomplt(x, y);
macro bool[<*>] bool[<*>].comp_le(bool[<*>] x, bool[<*>] y) => $$veccomple(x, y);
macro bool[<*>] bool[<*>].comp_eq(bool[<*>] x, bool[<*>] y) => $$veccompeq(x, y);
macro bool[<*>] bool[<*>].comp_gt(bool[<*>] x, bool[<*>] y) => $$veccompgt(x, y);
macro bool[<*>] bool[<*>].comp_ge(bool[<*>] x, bool[<*>] y) => $$veccompge(x, y);
macro bool[<*>] bool[<*>].comp_ne(bool[<*>] x, bool[<*>] y) => $$veccompne(x, y);
macro bool bool[<?>].sum(bool[<?>] x) => $$reduce_add(x);
macro bool bool[<?>].product(bool[<?>] x) => $$reduce_mul(x);
macro bool bool[<?>].and(bool[<?>] x) => $$reduce_and(x);
macro bool bool[<?>].or(bool[<?>] x) => $$reduce_or(x);
macro bool bool[<?>].xor(bool[<?>] x) => $$reduce_xor(x);
macro bool bool[<?>].max(bool[<?>] x) => $$reduce_max(x);
macro bool bool[<?>].min(bool[<?>] x) => $$reduce_min(x);
macro bool bool[<*>].sum(bool[<*>] x) => $$reduce_add(x);
macro bool bool[<*>].product(bool[<*>] x) => $$reduce_mul(x);
macro bool bool[<*>].and(bool[<*>] x) => $$reduce_and(x);
macro bool bool[<*>].or(bool[<*>] x) => $$reduce_or(x);
macro bool bool[<*>].xor(bool[<*>] x) => $$reduce_xor(x);
macro bool bool[<*>].max(bool[<*>] x) => $$reduce_max(x);
macro bool bool[<*>].min(bool[<*>] x) => $$reduce_min(x);
macro bool[<?>] char[<?>].comp_lt(char[<?>] x, char[<?>] y) => $$veccomplt(x, y);
macro bool[<?>] char[<?>].comp_le(char[<?>] x, char[<?>] y) => $$veccomple(x, y);
macro bool[<?>] char[<?>].comp_eq(char[<?>] x, char[<?>] y) => $$veccompeq(x, y);
macro bool[<?>] char[<?>].comp_gt(char[<?>] x, char[<?>] y) => $$veccompgt(x, y);
macro bool[<?>] char[<?>].comp_ge(char[<?>] x, char[<?>] y) => $$veccompge(x, y);
macro bool[<?>] char[<?>].comp_ne(char[<?>] x, char[<?>] y) => $$veccompne(x, y);
macro bool[<*>] char[<*>].comp_lt(char[<*>] x, char[<*>] y) => $$veccomplt(x, y);
macro bool[<*>] char[<*>].comp_le(char[<*>] x, char[<*>] y) => $$veccomple(x, y);
macro bool[<*>] char[<*>].comp_eq(char[<*>] x, char[<*>] y) => $$veccompeq(x, y);
macro bool[<*>] char[<*>].comp_gt(char[<*>] x, char[<*>] y) => $$veccompgt(x, y);
macro bool[<*>] char[<*>].comp_ge(char[<*>] x, char[<*>] y) => $$veccompge(x, y);
macro bool[<*>] char[<*>].comp_ne(char[<*>] x, char[<*>] y) => $$veccompne(x, y);
macro char char[<?>].sum(char[<?>] x) => $$reduce_add(x);
macro char char[<?>].product(char[<?>] x) => $$reduce_mul(x);
macro char char[<?>].and(char[<?>] x) => $$reduce_and(x);
macro char char[<?>].or(char[<?>] x) => $$reduce_or(x);
macro char char[<?>].xor(char[<?>] x) => $$reduce_xor(x);
macro char char[<?>].max(char[<?>] x) => $$reduce_max(x);
macro char char[<?>].min(char[<?>] x) => $$reduce_min(x);
macro char char[<?>].dot(char[<?>] x, char[<?>] y) => (x * y).sum();
macro char char[<*>].sum(char[<*>] x) => $$reduce_add(x);
macro char char[<*>].product(char[<*>] x) => $$reduce_mul(x);
macro char char[<*>].and(char[<*>] x) => $$reduce_and(x);
macro char char[<*>].or(char[<*>] x) => $$reduce_or(x);
macro char char[<*>].xor(char[<*>] x) => $$reduce_xor(x);
macro char char[<*>].max(char[<*>] x) => $$reduce_max(x);
macro char char[<*>].min(char[<*>] x) => $$reduce_min(x);
macro char char[<*>].dot(char[<*>] x, char[<*>] y) => (x * y).sum();
macro bool[<?>] ushort[<?>].comp_lt(ushort[<?>] x, ushort[<?>] y) => $$veccomplt(x, y);
macro bool[<?>] ushort[<?>].comp_le(ushort[<?>] x, ushort[<?>] y) => $$veccomple(x, y);
macro bool[<?>] ushort[<?>].comp_eq(ushort[<?>] x, ushort[<?>] y) => $$veccompeq(x, y);
macro bool[<?>] ushort[<?>].comp_gt(ushort[<?>] x, ushort[<?>] y) => $$veccompgt(x, y);
macro bool[<?>] ushort[<?>].comp_ge(ushort[<?>] x, ushort[<?>] y) => $$veccompge(x, y);
macro bool[<?>] ushort[<?>].comp_ne(ushort[<?>] x, ushort[<?>] y) => $$veccompne(x, y);
macro bool[<*>] ushort[<*>].comp_lt(ushort[<*>] x, ushort[<*>] y) => $$veccomplt(x, y);
macro bool[<*>] ushort[<*>].comp_le(ushort[<*>] x, ushort[<*>] y) => $$veccomple(x, y);
macro bool[<*>] ushort[<*>].comp_eq(ushort[<*>] x, ushort[<*>] y) => $$veccompeq(x, y);
macro bool[<*>] ushort[<*>].comp_gt(ushort[<*>] x, ushort[<*>] y) => $$veccompgt(x, y);
macro bool[<*>] ushort[<*>].comp_ge(ushort[<*>] x, ushort[<*>] y) => $$veccompge(x, y);
macro bool[<*>] ushort[<*>].comp_ne(ushort[<*>] x, ushort[<*>] y) => $$veccompne(x, y);
macro ushort ushort[<?>].sum(ushort[<?>] x) => $$reduce_add(x);
macro ushort ushort[<?>].product(ushort[<?>] x) => $$reduce_mul(x);
macro ushort ushort[<?>].and(ushort[<?>] x) => $$reduce_and(x);
macro ushort ushort[<?>].or(ushort[<?>] x) => $$reduce_or(x);
macro ushort ushort[<?>].xor(ushort[<?>] x) => $$reduce_xor(x);
macro ushort ushort[<?>].max(ushort[<?>] x) => $$reduce_max(x);
macro ushort ushort[<?>].min(ushort[<?>] x) => $$reduce_min(x);
macro ushort ushort[<?>].dot(ushort[<?>] x, ushort[<?>] y) => (x * y).sum();
macro ushort ushort[<*>].sum(ushort[<*>] x) => $$reduce_add(x);
macro ushort ushort[<*>].product(ushort[<*>] x) => $$reduce_mul(x);
macro ushort ushort[<*>].and(ushort[<*>] x) => $$reduce_and(x);
macro ushort ushort[<*>].or(ushort[<*>] x) => $$reduce_or(x);
macro ushort ushort[<*>].xor(ushort[<*>] x) => $$reduce_xor(x);
macro ushort ushort[<*>].max(ushort[<*>] x) => $$reduce_max(x);
macro ushort ushort[<*>].min(ushort[<*>] x) => $$reduce_min(x);
macro ushort ushort[<*>].dot(ushort[<*>] x, ushort[<*>] y) => (x * y).sum();
macro bool[<?>] uint[<?>].comp_lt(uint[<?>] x, uint[<?>] y) => $$veccomplt(x, y);
macro bool[<?>] uint[<?>].comp_le(uint[<?>] x, uint[<?>] y) => $$veccomple(x, y);
macro bool[<?>] uint[<?>].comp_eq(uint[<?>] x, uint[<?>] y) => $$veccompeq(x, y);
macro bool[<?>] uint[<?>].comp_gt(uint[<?>] x, uint[<?>] y) => $$veccompgt(x, y);
macro bool[<?>] uint[<?>].comp_ge(uint[<?>] x, uint[<?>] y) => $$veccompge(x, y);
macro bool[<?>] uint[<?>].comp_ne(uint[<?>] x, uint[<?>] y) => $$veccompne(x, y);
macro bool[<*>] uint[<*>].comp_lt(uint[<*>] x, uint[<*>] y) => $$veccomplt(x, y);
macro bool[<*>] uint[<*>].comp_le(uint[<*>] x, uint[<*>] y) => $$veccomple(x, y);
macro bool[<*>] uint[<*>].comp_eq(uint[<*>] x, uint[<*>] y) => $$veccompeq(x, y);
macro bool[<*>] uint[<*>].comp_gt(uint[<*>] x, uint[<*>] y) => $$veccompgt(x, y);
macro bool[<*>] uint[<*>].comp_ge(uint[<*>] x, uint[<*>] y) => $$veccompge(x, y);
macro bool[<*>] uint[<*>].comp_ne(uint[<*>] x, uint[<*>] y) => $$veccompne(x, y);
macro uint uint[<?>].sum(uint[<?>] x) => $$reduce_add(x);
macro uint uint[<?>].product(uint[<?>] x) => $$reduce_mul(x);
macro uint uint[<?>].and(uint[<?>] x) => $$reduce_and(x);
macro uint uint[<?>].or(uint[<?>] x) => $$reduce_or(x);
macro uint uint[<?>].xor(uint[<?>] x) => $$reduce_xor(x);
macro uint uint[<?>].max(uint[<?>] x) => $$reduce_max(x);
macro uint uint[<?>].min(uint[<?>] x) => $$reduce_min(x);
macro uint uint[<?>].dot(uint[<?>] x, uint[<?>] y) => (x * y).sum();
macro uint uint[<*>].sum(uint[<*>] x) => $$reduce_add(x);
macro uint uint[<*>].product(uint[<*>] x) => $$reduce_mul(x);
macro uint uint[<*>].and(uint[<*>] x) => $$reduce_and(x);
macro uint uint[<*>].or(uint[<*>] x) => $$reduce_or(x);
macro uint uint[<*>].xor(uint[<*>] x) => $$reduce_xor(x);
macro uint uint[<*>].max(uint[<*>] x) => $$reduce_max(x);
macro uint uint[<*>].min(uint[<*>] x) => $$reduce_min(x);
macro uint uint[<*>].dot(uint[<*>] x, uint[<*>] y) => (x * y).sum();
macro bool[<?>] ulong[<?>].comp_lt(ulong[<?>] x, ulong[<?>] y) => $$veccomplt(x, y);
macro bool[<?>] ulong[<?>].comp_le(ulong[<?>] x, ulong[<?>] y) => $$veccomple(x, y);
macro bool[<?>] ulong[<?>].comp_eq(ulong[<?>] x, ulong[<?>] y) => $$veccompeq(x, y);
macro bool[<?>] ulong[<?>].comp_gt(ulong[<?>] x, ulong[<?>] y) => $$veccompgt(x, y);
macro bool[<?>] ulong[<?>].comp_ge(ulong[<?>] x, ulong[<?>] y) => $$veccompge(x, y);
macro bool[<?>] ulong[<?>].comp_ne(ulong[<?>] x, ulong[<?>] y) => $$veccompne(x, y);
macro bool[<*>] ulong[<*>].comp_lt(ulong[<*>] x, ulong[<*>] y) => $$veccomplt(x, y);
macro bool[<*>] ulong[<*>].comp_le(ulong[<*>] x, ulong[<*>] y) => $$veccomple(x, y);
macro bool[<*>] ulong[<*>].comp_eq(ulong[<*>] x, ulong[<*>] y) => $$veccompeq(x, y);
macro bool[<*>] ulong[<*>].comp_gt(ulong[<*>] x, ulong[<*>] y) => $$veccompgt(x, y);
macro bool[<*>] ulong[<*>].comp_ge(ulong[<*>] x, ulong[<*>] y) => $$veccompge(x, y);
macro bool[<*>] ulong[<*>].comp_ne(ulong[<*>] x, ulong[<*>] y) => $$veccompne(x, y);
macro ulong ulong[<?>].sum(ulong[<?>] x) => $$reduce_add(x);
macro ulong ulong[<?>].product(ulong[<?>] x) => $$reduce_mul(x);
macro ulong ulong[<?>].and(ulong[<?>] x) => $$reduce_and(x);
macro ulong ulong[<?>].or(ulong[<?>] x) => $$reduce_or(x);
macro ulong ulong[<?>].xor(ulong[<?>] x) => $$reduce_xor(x);
macro ulong ulong[<?>].max(ulong[<?>] x) => $$reduce_max(x);
macro ulong ulong[<?>].min(ulong[<?>] x) => $$reduce_min(x);
macro ulong ulong[<?>].dot(ulong[<?>] x, ulong[<?>] y) => (x * y).sum();
macro ulong ulong[<*>].sum(ulong[<*>] x) => $$reduce_add(x);
macro ulong ulong[<*>].product(ulong[<*>] x) => $$reduce_mul(x);
macro ulong ulong[<*>].and(ulong[<*>] x) => $$reduce_and(x);
macro ulong ulong[<*>].or(ulong[<*>] x) => $$reduce_or(x);
macro ulong ulong[<*>].xor(ulong[<*>] x) => $$reduce_xor(x);
macro ulong ulong[<*>].max(ulong[<*>] x) => $$reduce_max(x);
macro ulong ulong[<*>].min(ulong[<*>] x) => $$reduce_min(x);
macro ulong ulong[<*>].dot(ulong[<*>] x, ulong[<*>] y) => (x * y).sum();
macro bool[<?>] uint128[<?>].comp_lt(uint128[<?>] x, uint128[<?>] y) => $$veccomplt(x, y);
macro bool[<?>] uint128[<?>].comp_le(uint128[<?>] x, uint128[<?>] y) => $$veccomple(x, y);
macro bool[<?>] uint128[<?>].comp_eq(uint128[<?>] x, uint128[<?>] y) => $$veccompeq(x, y);
macro bool[<?>] uint128[<?>].comp_gt(uint128[<?>] x, uint128[<?>] y) => $$veccompgt(x, y);
macro bool[<?>] uint128[<?>].comp_ge(uint128[<?>] x, uint128[<?>] y) => $$veccompge(x, y);
macro bool[<?>] uint128[<?>].comp_ne(uint128[<?>] x, uint128[<?>] y) => $$veccompne(x, y);
macro bool[<*>] uint128[<*>].comp_lt(uint128[<*>] x, uint128[<*>] y) => $$veccomplt(x, y);
macro bool[<*>] uint128[<*>].comp_le(uint128[<*>] x, uint128[<*>] y) => $$veccomple(x, y);
macro bool[<*>] uint128[<*>].comp_eq(uint128[<*>] x, uint128[<*>] y) => $$veccompeq(x, y);
macro bool[<*>] uint128[<*>].comp_gt(uint128[<*>] x, uint128[<*>] y) => $$veccompgt(x, y);
macro bool[<*>] uint128[<*>].comp_ge(uint128[<*>] x, uint128[<*>] y) => $$veccompge(x, y);
macro bool[<*>] uint128[<*>].comp_ne(uint128[<*>] x, uint128[<*>] y) => $$veccompne(x, y);
macro uint128 uint128[<?>].sum(uint128[<?>] x) => $$reduce_add(x);
macro uint128 uint128[<?>].product(uint128[<?>] x) => $$reduce_mul(x);
macro uint128 uint128[<?>].and(uint128[<?>] x) => $$reduce_and(x);
macro uint128 uint128[<?>].or(uint128[<?>] x) => $$reduce_or(x);
macro uint128 uint128[<?>].xor(uint128[<?>] x) => $$reduce_xor(x);
macro uint128 uint128[<?>].max(uint128[<?>] x) => $$reduce_max(x);
macro uint128 uint128[<?>].min(uint128[<?>] x) => $$reduce_min(x);
macro uint128 uint128[<?>].dot(uint128[<?>] x, uint128[<?>] y) => (x * y).sum();
macro uint128 uint128[<*>].sum(uint128[<*>] x) => $$reduce_add(x);
macro uint128 uint128[<*>].product(uint128[<*>] x) => $$reduce_mul(x);
macro uint128 uint128[<*>].and(uint128[<*>] x) => $$reduce_and(x);
macro uint128 uint128[<*>].or(uint128[<*>] x) => $$reduce_or(x);
macro uint128 uint128[<*>].xor(uint128[<*>] x) => $$reduce_xor(x);
macro uint128 uint128[<*>].max(uint128[<*>] x) => $$reduce_max(x);
macro uint128 uint128[<*>].min(uint128[<*>] x) => $$reduce_min(x);
macro uint128 uint128[<*>].dot(uint128[<*>] x, uint128[<*>] y) => (x * y).sum();
macro char char.sat_add(char x, char y) => $$sat_add(x, y);
macro char char.sat_sub(char x, char y) => $$sat_sub(x, y);
@@ -1042,21 +1042,6 @@ macro uint double.high_word(double d) => (uint)(bitcast(d, ulong) >> 32);
macro uint double.low_word(double d) => (uint)bitcast(d, ulong);
macro uint float.word(float d) => bitcast(d, uint);
macro void double.set_high_word(double* d, uint u)
{
ulong rep = bitcast(*d, ulong);
rep = ((ulong)u << 32) | (rep & 0xffffffff);
*d = bitcast(rep, double);
}
macro void double.set_low_word(double* d, uint u)
{
ulong rep = bitcast(*d, ulong);
rep = (rep & 0xffffffff00000000) | (ulong)u;
*d = bitcast(rep, double);
}
macro void float.set_word(float* f, uint u) => *f = bitcast(u, float);
macro double scalbn(double x, int n) => _scalbn(x, n);
@@ -1178,49 +1163,49 @@ macro bool @is_same_vector_or_scalar(#vector_value, #vector_or_scalar) @private
@require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar`
@require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar`
*>
macro char[<?>] char[<?>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);
macro char[<*>] char[<*>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);
<*
@require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar`
@require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar`
*>
macro ichar[<?>] ichar[<?>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);
macro ichar[<*>] ichar[<*>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);
<*
@require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar`
@require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar`
*>
macro short[<?>] short[<?>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);
macro short[<*>] short[<*>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);
<*
@require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar`
@require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar`
*>
macro ushort[<?>] ushort[<?>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);
macro ushort[<*>] ushort[<*>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);
<*
@require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar`
@require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar`
*>
macro int[<?>] int[<?>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);
macro int[<*>] int[<*>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);
<*
@require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar`
@require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar`
*>
macro uint[<?>] uint[<?>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);
macro uint[<*>] uint[<*>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);
<*
@require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar`
@require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar`
*>
macro long[<?>] long[<?>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);
macro long[<*>] long[<*>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);
<*
@require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar`
@require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar`
*>
macro ulong[<?>] ulong[<?>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);
macro ulong[<*>] ulong[<*>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);
<*
@require types::is_int($typeof(a)) `The input must be an integer`

View File

@@ -11,17 +11,3 @@ fn double __roundeven(double d) @extern("roundeven") @weak @nostrip
// Slow implementation
return round(d / 2) * 2;
}
fn double __powidf2(double a, int b) @extern("__powidf2") @weak @nostrip
{
bool recip = b < 0;
double r = 1;
while (1)
{
if (b & 1) r *= a;
b /= 2;
if (b == 0) break;
a *= a;
}
return recip ? 1 / r : r;
}

View File

@@ -11,21 +11,21 @@ union Complex
const Complex IDENTITY = { 1, 0 };
const Complex IMAGINARY = { 0, 1 };
macro Complex Complex.add(self, Complex b) => { .v = self.v + b.v };
macro Complex Complex.add_each(self, Real b) => { .v = self.v + b };
macro Complex Complex.sub(self, Complex b) => { .v = self.v - b.v };
macro Complex Complex.sub_each(self, Real b) => { .v = self.v - b };
macro Complex Complex.scale(self, Real s) => { .v = self.v * s };
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 };
macro Complex Complex.sub_each(self, Real b) => Complex { .v = self.v - b };
macro Complex Complex.scale(self, Real s) => Complex { .v = self.v * s };
macro Complex Complex.mul(self, Complex b) => { self.r * b.r - self.c * b.c, self.r * b.c + b.r * self.c };
macro Complex Complex.div(self, Complex b)
{
Real div = b.v.dot(b.v);
return { (self.r * b.r + self.c * b.c) / div, (self.c * b.r - self.r * b.c) / div };
return Complex{ (self.r * b.r + self.c * b.c) / div, (self.c * b.r - self.r * b.c) / div };
}
macro Complex Complex.inverse(self)
{
Real sqr = self.v.dot(self.v);
return { self.r / sqr, -self.c / sqr };
return Complex{ self.r / sqr, -self.c / sqr };
}
macro Complex Complex.conjugate(self) => { .r = self.r, .c = -self.c };
macro Complex Complex.conjugate(self) => Complex { .r = self.r, .c = -self.c };
macro bool Complex.equals(self, Complex b) => self.v == b.v;

View File

@@ -420,19 +420,19 @@ const Matrix4x4 IDENTITY4 = { .m = { [0] = 1, [5] = 1, [10] = 1, [15] = 1 } };
macro matrix_component_mul(mat, val) @private
{
var $Type = Real[<$typeof(mat.m).len>];
return ($typeof(*mat)) { .m = val * ($Type)mat.m };
return $typeof(*mat) { .m = val * ($Type)mat.m };
}
macro matrix_add(mat, mat2) @private
{
var $Type = Real[<$typeof(mat.m).len>];
return ($typeof(*mat)) { .m = ($Type)mat.m + ($Type)mat2.m };
return $typeof(*mat) { .m = ($Type)mat.m + ($Type)mat2.m };
}
macro matrix_sub(mat, mat2) @private
{
var $Type = Real[<$typeof(mat.m).len>];
return ($typeof(*mat)) { .m = ($Type)mat.m - ($Type)mat2.m };
return $typeof(*mat) { .m = ($Type)mat.m - ($Type)mat2.m };
}
macro matrix_look_at($Type, eye, target, up) @private
@@ -441,7 +441,7 @@ macro matrix_look_at($Type, eye, target, up) @private
var vx = up.cross(vz).normalize();
var vy = vz.cross(vx);
return ($Type){
return $Type {
vx[0], vx[1], vx[2], - (Real)vx.dot(eye),
vy[0], vy[1], vy[2], - (Real)vy.dot(eye),
vz[0], vz[1], vz[2], - (Real)vz.dot(eye),

View File

@@ -6,12 +6,6 @@ union DoubleInternal
ulong i;
}
union FloatInternal
{
float f;
uint i;
}
// Based on the musl implementation
fn double fmod(double x, double y) @extern("fmod") @weak @nostrip
{
@@ -81,74 +75,4 @@ fn double fmod(double x, double y) @extern("fmod") @weak @nostrip
uxi |= (ulong)sx << 63;
ux.i = uxi;
return ux.f;
}
fn float fmodf(float x, float y) @extern("fmodf") @weak @nostrip
{
FloatInternal ux = { .f = x };
FloatInternal uy = { .f = y };
int ex = (int)((ux.i >> 23) & 0xff);
int ey = (int)((uy.i >> 23) & 0xff);
int sx = (int)(ux.i >> 31);
uint uxi = ux.i;
if (uy.i << 1 == 0 || math::is_nan(y) || ex == 0xff) return (x * y)/(x * y);
if (uxi << 1 <= uy.i << 1)
{
if (uxi << 1 == uy.i << 1) return 0 * x;
return x;
}
if (!ex)
{
for (uint i = uxi << 9; i >> 31 == 0; ex--, i <<= 1);
uxi <<= -ex + 1;
}
else
{
uxi &= -1U >> 9;
uxi |= 1U << 23;
}
if (!ey)
{
for (uint i = uy.i << 9; i >> 31 == 0; ey--, i <<= 1);
uy.i <<= -ey + 1;
}
else
{
uy.i &= -1U >> 9;
uy.i |= 1U << 23;
}
/* x mod y */
for (; ex > ey; ex--)
{
uint i = uxi - uy.i;
if (i >> 31 == 0)
{
if (i == 0) return 0 * x;
uxi = i;
}
uxi <<= 1;
}
uint i = uxi - uy.i;
if (i >> 31 == 0)
{
if (i == 0) return 0*x;
uxi = i;
}
for (; uxi>>23 == 0; uxi <<= 1, ex--);
/* scale result */
if (ex > 0)
{
uxi -= 1U << 23;
uxi |= (uint)ex << 23;
}
else
{
uxi >>= -ex + 1;
}
uxi |= (uint)sx << 31;
ux.i = uxi;
return ux.f;
}
}

View File

@@ -11,7 +11,7 @@ module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
* ====================================================
*/
const double[?] TAN_T = {
const double[*] TAN_T = {
3.33333333333334091986e-01, /* 3FD55555, 55555563 */
1.33333333333201242699e-01, /* 3FC11111, 1110FE7A */
5.39682539762260521377e-02, /* 3FABA1BA, 1BB341FE */
@@ -32,7 +32,7 @@ fn double __tan(double x, double y, int odd) @extern("__tan") @weak @nostrip
const double PIO4 = 7.85398163397448278999e-01; /* 3FE921FB, 54442D18 */
const double PIO4LO = 3.06161699786838301793e-17; /* 3C81A626, 33145C07 */
uint hx = x.high_word();
uint hx = (uint)(bitcast(x, ulong) >> 32);
bool big = (hx &0x7fffffff) >= 0x3FE59428; // |x| >= 0.6744
int sign @noinit;
if (big)
@@ -68,12 +68,12 @@ fn double __tan(double x, double y, int odd) @extern("__tan") @weak @nostrip
// -1.0/(x+r) has up to 2ulp error, so compute it accurately
// Clear low word
double w0 = w;
w0.set_low_word(0);
ulong d = bitcast(w, ulong) & 0xFFFF_FFFF_0000_0000;
double w0 = bitcast(d, double);
v = r - (w0 - x); // w0+v = r+x
double a = -1.0 / w;
double a0 = a;
a0.set_low_word(0);
d = bitcast(a, ulong) & 0xFFFF_FFFF_0000_0000;
double a0 = bitcast(d, double);
return a0 + a * (1.0 + a0 * w0 + a0 * v);
}

View File

@@ -16,7 +16,7 @@ module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
*/
// |tan(x)/x - t(x)| < 2**-25.5 (~[-2e-08, 2e-08]).
const double[?] TANDF = {
const double[*] TANDF = {
0x15554d3418c99f.0p-54, /* 0.333331395030791399758 */
0x1112fd38999f72.0p-55, /* 0.133392002712976742718 */
0x1b54c91d865afe.0p-57, /* 0.0533812378445670393523 */

View File

@@ -63,8 +63,12 @@ fn double _acos(double x) @weak @extern("acos") @nostrip
default:
double z = (1. - x) * 0.5;
double s = math::sqrt(z);
double df = s;
df.set_low_word(0);
double df @noinit;
{
ulong rep = bitcast(s, ulong);
rep &= 0xffffffff00000000;
df = bitcast(rep, double);
}
double c = (z - df * df) / (s + df);
double w = _r(z) * s + c;
return 2. * (df + w);
@@ -129,9 +133,12 @@ fn float _acosf(float x) @weak @extern("acosf") @nostrip
default:
float z = (1.f - x) * 0.5f;
float s = math::sqrt(z);
float df = s;
uint idf = df.word();
df.set_word(idf & 0xfffff000);
float df @noinit;
{
uint rep = bitcast(s, uint);
rep &= 0xfffff000;
df = bitcast(rep, float);
}
float c = (z - df * df) / (s + df);
float w = _r_f(z) * s + c;
return 2.f * (df + w);

View File

@@ -64,8 +64,12 @@ fn double _asin(double x) @weak @extern("asin") @nostrip
}
else
{
double f = s;
f.set_low_word(0);
double f @noinit;
{
ulong rep = bitcast(s, ulong);
rep &= 0xffffffff00000000;
f = bitcast(rep, double);
}
double c = (z - f * f) / (s + f);
x = 0.5 * PIO2_HI - (2. * s * r - (PIO2_LO - 2. * c) - (0.5 * PIO2_HI - 2. * f));
}

View File

@@ -12,21 +12,21 @@ module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
* ====================================================
*/
const double[?] ATANHI @private = {
const double[*] ATANHI @private = {
4.63647609000806093515e-01, /* atan(0.5)hi 0x3FDDAC67, 0x0561BB4F */
7.85398163397448278999e-01, /* atan(1.0)hi 0x3FE921FB, 0x54442D18 */
9.82793723247329054082e-01, /* atan(1.5)hi 0x3FEF730B, 0xD281F69B */
1.57079632679489655800e+00, /* atan(inf)hi 0x3FF921FB, 0x54442D18 */
};
const double[?] ATANLO @private = {
const double[*] ATANLO @private = {
2.26987774529616870924e-17, /* atan(0.5)lo 0x3C7A2B7F, 0x222F65E2 */
3.06161699786838301793e-17, /* atan(1.0)lo 0x3C81A626, 0x33145C07 */
1.39033110312309984516e-17, /* atan(1.5)lo 0x3C700788, 0x7AF0CBBD */
6.12323399573676603587e-17, /* atan(inf)lo 0x3C91A626, 0x33145C07 */
};
const double[?] AT @private = {
const double[*] AT @private = {
3.33333333333329318027e-01, /* 0x3FD55555, 0x5555550D */
-1.99999999998764832476e-01, /* 0xBFC99999, 0x9998EBC4 */
1.42857142725034663711e-01, /* 0x3FC24924, 0x920083FF */
@@ -116,21 +116,21 @@ fn double _atan(double x) @weak @extern("atan") @nostrip
* ====================================================
*/
const float[?] ATANHIF @private = {
const float[*] ATANHIF @private = {
4.6364760399e-01, /* atan(0.5)hi 0x3eed6338 */
7.8539812565e-01, /* atan(1.0)hi 0x3f490fda */
9.8279368877e-01, /* atan(1.5)hi 0x3f7b985e */
1.5707962513e+00, /* atan(inf)hi 0x3fc90fda */
};
const float[?] ATANLOF @private = {
const float[*] ATANLOF @private = {
5.0121582440e-09, /* atan(0.5)lo 0x31ac3769 */
3.7748947079e-08, /* atan(1.0)lo 0x33222168 */
3.4473217170e-08, /* atan(1.5)lo 0x33140fb4 */
7.5497894159e-08, /* atan(inf)lo 0x33a22168 */
};
const float[?] ATF @private = {
const float[*] ATF @private = {
3.3333328366e-01,
-1.9999158382e-01,
1.4253635705e-01,
@@ -217,21 +217,30 @@ fn float _atanf(float x) @weak @extern("atanf") @nostrip
const PI_LO @private = 1.2246467991473531772E-16; /* 0x3CA1A626, 0x33145C07 */
macro void extract_words(double d, uint* hi, uint* lo) @private
{
ulong rep = bitcast(d, ulong);
*hi = (uint)(rep >> 32);
*lo = (uint)rep;
}
fn double _atan2(double y, double x) @weak @extern("atan2") @nostrip
{
if (math::is_nan(x) || math::is_nan(y)) return x + y;
uint lx = x.low_word();
uint ix = x.high_word();
uint ly = y.low_word();
uint iy = y.high_word();
uint lx @noinit;
uint ix @noinit;
extract_words(x, &ix, &lx);
uint ly @noinit;
uint iy @noinit;
extract_words(y, &iy, &ly);
// x = 1.0
if ((ix - 0x3ff00000) | lx == 0) return _atan(y);
// 2*sign(x) + sign(y)
uint m = ((iy >> 31) & 1) | ((ix >> 30) & 2);
ix &= 0x7fffffff;
iy &= 0x7fffffff;
ix = ix & 0x7fffffff;
iy = iy & 0x7fffffff;
// when y = 0
if (iy | ly == 0)
@@ -304,8 +313,8 @@ const float PI_LO_F @private = -8.7422776573e-08; /* 0xb3bbbd2e */
fn float _atan2f(float y, float x) @weak @extern("atan2f") @nostrip
{
if (math::is_nan(x) || math::is_nan(y)) return x + y;
uint ix = x.word();
uint iy = y.word();
uint ix = bitcast(x, uint);
uint iy = bitcast(y, uint);
/* x=1.0 */
if (ix == 0x3f800000) return _atanf(y);
/* 2*sign(x)+sign(y) */

View File

@@ -1,95 +0,0 @@
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
/* origin: FreeBSD usr/src/lib/msun/src/e_atanh.c */
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunSoft, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
fn double _atanh(double x) @weak @extern("atanh") @nostrip
{
double t @noinit;
uint hx = x.high_word();
uint ix = hx & 0x7fffffff;
uint sign = hx >> 31;
switch
{
/* |x| >= 1 or nan */
case ix >= 0x3ff00000:
uint lx = x.low_word();
if ((ix - 0x3ff00000 | lx) == 0)
{
return sign ? -double.inf : double.inf;
}
return double.nan;
/* x<2**-28 */
case ix < 0x3e300000 && (1e300 + x) > 0.:
return x;
}
x.set_high_word(ix);
/* |x| < 0.5 */
if (ix < 0x3fe00000)
{
t = x + x;
t = 0.5 * _log1p(t + t * x / (1. - x));
}
else
{
t = 0.5 * _log1p((x + x) / (1. - x));
}
return sign ? -t : t;
}
/* origin: FreeBSD usr/src/lib/msun/src/e_atanhf.c */
/*
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
*/
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
fn float _atanhf(float x) @weak @extern("atanhf") @nostrip
{
float t @noinit;
uint hx = bitcast(x, uint);
uint ix = hx & 0x7fffffff;
uint sign = hx >> 31;
switch
{
/* |x| >= 1 or nan */
case ix >= 0x3f800000:
if (ix == 0x3f800000)
{
return sign ? -float.inf : float.inf;
}
return float.nan;
/* x<2**-28 */
case ix < 0x31800000 && (1e30 + x) > 0.f:
return x;
}
x.set_word(ix);
/* |x| < 0.5 */
if (ix < 0x3f000000)
{
t = x + x;
t = 0.5f * _log1pf(t + t * x / (1.f - x));
}
else
{
t = 0.5f * _log1pf((x + x) / (1.f - x));
}
return sign ? -t : t;
}

View File

@@ -2,7 +2,7 @@ module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
fn float _cosf(float x) @extern("cosf") @weak @nostrip
{
uint ix = x.word();
uint ix = bitcast(x, uint);
uint sign = ix >> 31;
ix &= 0x7fffffff;
@@ -54,7 +54,8 @@ fn float _cosf(float x) @extern("cosf") @weak @nostrip
fn double _cos(double x) @extern("cos") @weak @nostrip
{
// High word of x.
uint ix = x.high_word() & 0x7fffffff;
uint ix = (uint)(bitcast(x, ulong) >> 32);
ix &= 0x7fffffff;
switch
{

View File

@@ -1,60 +0,0 @@
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
const double EXP_LN2_HI = 6.93147180369123816490e-01;
const double EXP_LN2_LO = 1.90821492927058770002e-10;
const double EXP_INV_LN2 = 1.44269504088896338700e+00;
const double EXP_P1 = 1.66666666666666019037e-01;
const double EXP_P2 = -2.77777777770155933842e-03;
const double EXP_P3 = 6.61375632143793436117e-05;
const double EXP_P4 = -1.65339022054652515390e-06;
const double EXP_P5 = 4.13813679705723846039e-08;
/*--------------------------------------------*/
const float EXPF_LN2_HI = 6.9314575195e-01f;
const float EXPF_LN2_LO = 1.4286067653e-06f;
const float EXPF_INV_LN2 = 1.4426950216e+00f;
const float EXPF_P1 = 1.6666667163e-01f;
const float EXPF_P2 = -2.7777778450e-03f;
const float EXPF_P3 = 6.6137559770e-05f;
const float EXPF_P4 = -1.6533901999e-06f;
fn double exp(double x) @extern("exp")
{
if (x != x) return x;
if (x == double.inf) return double.inf;
if (x == -double.inf) return 0.0; // IEEE 754 spec
// Overflow threshold for exp (approx +709.78 for double)
if (x > 709.782712893384) return double.inf;
// Underflow threshold for exp (approx -745.13 for double)
if (x < -745.133219101941) return 0.0;
double px = x * EXP_INV_LN2;
double k = _floor(px + 0.5);
double r = x - k * EXP_LN2_HI - k * EXP_LN2_LO;
double r2 = r * r;
double p = r2 * (EXP_P1 + r2 * (EXP_P2 + r2 * (EXP_P3 + r2 * (EXP_P4 + r2 * EXP_P5))));
double exp_r = 1.0 + r + r * p;
return ldexp(exp_r, (int)k);
}
fn float expf(float x) @extern("expf")
{
if (x != x) return x;
if (x == float.inf) return float.inf;
if (x == -float.inf) return 0.0f; // IEEE 754 spec
// Overflow threshold (approx +88.72 for float)
if (x > 88.7228f) return float.inf;
// Underflow threshold (approx -103.97 for float)
if (x < -103.972084f) return 0.0f;
float px = x * EXPF_INV_LN2;
float k = _floorf(px + 0.5f);
float r = x - k * EXPF_LN2_HI - k * EXPF_LN2_LO;
float r2 = r * r;
float p = r2 * (EXPF_P1 + r2 * (EXPF_P2 + r2 * (EXPF_P3 + r2 * EXPF_P4)));
float exp_r = 1.0f + r + r * p;
return ldexpf(exp_r, (int)k);
}

View File

@@ -1,15 +0,0 @@
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
fn double _fabs(double x) @weak @extern("fabs") @nostrip
{
ulong ix = bitcast(x, ulong);
ix &= ~(1ul << 63);
return bitcast(ix, double);
}
fn float _fabsf(float x) @weak @extern("fabsf") @nostrip
{
uint ix = bitcast(x, uint);
ix &= 0x7fffffff;
return bitcast(ix, float);
}

View File

@@ -1,59 +0,0 @@
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
fn double frexp(double x, int* exp) @extern("frexp")
{
uint hx = x.high_word();
uint ix = hx & 0x7fffffff;
uint lx = x.low_word();
if (ix >= 0x7ff00000 || (ix | lx) == 0)
{
*exp = 0;
return x;
}
// exponent extraction and normalization
int e = (int)((ix >> 20) & 0x7ff);
if (e == 0)
{
// subnormal number
x *= 0x1p64;
hx = x.high_word();
e = (int)((hx >> 20) & 0x7ff) - 64;
}
*exp = e - 1022;
// set exponent to -1 (fraction in [0.5, 1))
hx = (hx & 0x800fffff) | 0x3fe00000;
{
ulong rep = ((ulong)hx << 32) | lx;
return bitcast(rep, double);
}
}
fn float frexpf(float x, int* exp) @extern("frexpf")
{
uint ix = x.word();
uint hx = ix & 0x7fffffff;
if (hx >= 0x7f800000 || hx == 0)
{
*exp = 0;
return x;
}
// exponent extraction and normalization
int e = (int)((hx >> 23) & 0xff);
if (e == 0)
{
// subnormal number
x *= 0x1p64f;
ix = x.word();
e = (int)((ix >> 23) & 0xff) - 64;
}
*exp = e - 126;
// set exponent to -1 (fraction in [0.5, 1))
ix = (ix & 0x807fffff) | 0x3f000000;
return bitcast(ix, float);
}

View File

@@ -1,67 +0,0 @@
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
fn double ldexp(double x, int exp) @extern("ldexp")
{
uint hx = x.high_word();
int hexp = (int)((hx & 0x7ff00000) >> 20);
if (hexp == 0x7ff) return x;
if (hexp == 0)
{
// subnormal number handling
x *= 0x1p64;
hx = x.high_word();
hexp = (int)((hx & 0x7ff00000) >> 20) - 64;
}
// new exponent calculation
hexp += exp;
if (hexp > 0x7fe) return x * double.inf;
if (hexp < 1)
{
x *= 0x1p-1022;
hexp += 1022;
if (hexp < 1) x *= 0x1p-1022;
return x;
}
// set new exponent
hx = ((ulong)hx & 0x800fffff) | ((ulong)hexp << 20);
{
ulong rep = ((ulong)hx << 32) | x.low_word();
return bitcast(rep, double);
}
}
fn float ldexpf(float x, int exp) @extern("ldexpf")
{
uint ix = x.word();
int hexp = (int)((ix & 0x7f800000) >> 23);
if (hexp == 0xff) return x;
if (hexp == 0)
{
// subnormal number handling
x *= 0x1p64f;
ix = x.word();
hexp = (int)((ix & 0x7f800000) >> 23) - 64;
}
// new exponent calculation
hexp += exp;
if (hexp > 0xfe) return x * float.inf;
if (hexp < 1)
{
x *= 0x1p-126f;
hexp += 126;
if (hexp < 1) x *= 0x1p-126f;
return x;
}
// set new exponent
ix = (ix & 0x807fffff) | (hexp << 23);
return bitcast(ix, float);
}

View File

@@ -1,86 +0,0 @@
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
const double LOG_LN2_HI = 6.93147180369123816490e-01;
const double LOG_LN2_LO = 1.90821492927058770002e-10;
const double LOG_L1 = 6.666666666666735130e-01;
const double LOG_L2 = 3.999999999940941908e-01;
const double LOG_L3 = 2.857142874366239149e-01;
const double LOG_L4 = 2.222219843214978396e-01;
const double LOG_L5 = 1.818357216161805012e-01;
const double LOG_L6 = 1.531383769920937332e-01;
/*--------------------------------------------*/
const float LOGF_LN2_HI = 6.9313812256e-01f;
const float LOGF_LN2_LO = 9.0580006145e-06f;
const float LOGF_L1 = 6.6666662693e-01f;
const float LOGF_L2 = 4.0000972152e-01f;
const float LOGF_L3 = 2.8498786688e-01f;
const float LOGF_L4 = 2.4279078841e-01f;
const double SQRT2 = 1.41421356237309504880;
const float SQRT2F = 1.41421356237309504880f;
fn double log(double x) @extern("log")
{
if (x != x) return x;
if (x < 0.0) return double.nan;
if (x == 0.0) return -double.inf;
if (x == double.inf) return double.inf;
int k;
double f = frexp(x, &k);
if (f < SQRT2 * 0.5)
{
f *= 2.0;
k--;
}
// polynomial approximation of log(1 + f), with f in [0, sqrt(2) - 1]
f -= 1.0;
double s = f / (2.0 + f);
double z = s * s;
double w = z * z;
// even-part polynomial terms (t1) and odd-part polynomial terms (t2)
double t1 = w * (LOG_L1 + w * (LOG_L3 + w * LOG_L5));
double t2 = z * (LOG_L2 + w * (LOG_L4 + w * LOG_L6));
double r = t1 + t2;
double hfsq = 0.5 * f * f;
return k * LOG_LN2_HI - ((hfsq - (s * (hfsq + r) + k * LOG_LN2_LO)) - f);
}
fn float logf(float x) @extern("logf")
{
if (x != x) return x;
if (x < 0.0f) return float.nan;
if (x == 0.0f) return -float.inf;
if (x == float.inf) return float.inf;
int k;
float f = frexpf(x, &k);
if (f < SQRT2F * 0.5f)
{
f *= 2.0f;
k--;
}
// polynomial approximation for log(1 + f)
f -= 1.0f;
float s = f / (2.0f + f);
float z = s * s;
float w = z * z;
/*
logf uses fewer terms in its polynomial approximation
compared to the double precision version because
single-precision floating point doesn't benefit from the additional terms.
LOGF_L1, ... ,LOGF_L4 provide sufficient accuracy for 32-bit float calculations.
*/
float t1 = w * (LOGF_L1 + w * LOGF_L3);
float t2 = z * (LOGF_L2 + w * LOGF_L4);
float r = t1 + t2;
float hfsq = 0.5f * f * f;
return k * LOGF_LN2_HI - ((hfsq - (s * (hfsq + r) + k * LOGF_LN2_LO)) - f);
}

View File

@@ -1,228 +0,0 @@
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
/* origin: FreeBSD /usr/src/lib/msun/src/s_log1p.c */
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
/* origin: musl libc /src/math/log1p.c */
/*
* ====================================================
* Copyright (c) 2005-2020 Rich Felker, et al.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* ====================================================
*/
const LN2_HI @local = 6.93147180369123816490e-01; /* 3fe62e42 fee00000 */
const LN2_LO @local = 1.90821492927058770002e-10; /* 3dea39ef 35793c76 */
const LG1 @local = 6.666666666666735130e-01; /* 3FE55555 55555593 */
const LG2 @local = 3.999999999940941908e-01; /* 3FD99999 9997FA04 */
const LG3 @local = 2.857142874366239149e-01; /* 3FD24924 94229359 */
const LG4 @local = 2.222219843214978396e-01; /* 3FCC71C5 1D8E78AF */
const LG5 @local = 1.818357216161805012e-01; /* 3FC74664 96CB03DE */
const LG6 @local = 1.531383769920937332e-01; /* 3FC39A09 D078C69F */
const LG7 @local = 1.479819860511658591e-01; /* 3FC2F112 DF3E5244 */
fn double _log1p(double x) @weak @extern("log1p") @nostrip
{
uint hx = x.high_word();
int k = 1;
double c @noinit;
double f @noinit;
switch
{
/* 1+x < sqrt(2)+ */
case hx < 0x3fda827a || hx >> 31 != 0:
switch
{
/* x <= -1.0 */
case hx >= 0xbff00000:
if (x == -1) return -double.inf;
return double.nan;
/* |x| < 2**-53 */
case hx << 1 < 0x3ca00000 << 1:
/* underflow if subnormal */
if ((hx & 0x7ff00000) == 0)
{
(float)@volatile_load(x);
}
return x;
/* sqrt(2)/2- <= 1+x < sqrt(2)+ */
case hx <= 0xbfd2bec4:
k = 0;
c = 0;
f = x;
}
case hx >= 0x7ff00000:
return x;
}
if (k)
{
double u = 1 + x;
uint hu = u.high_word();
hu += 0x3ff00000 - 0x3fe6a09e;
k = (int)(hu >> 20) - 0x3ff;
/* correction term ~ log(1+x)-log(u), avoid underflow in c/u */
if (k < 54)
{
c = (k >= 2) ? 1. - (u - x) : x - (u - 1.);
c /= u;
}
else
{
c = 0;
}
/* reduce u into [sqrt(2)/2, sqrt(2)] */
hu = (hu & 0x000fffff) + 0x3fe6a09e;
u = bitcast(((ulong)hu << 32) | (bitcast(u, ulong) & 0xffffffff) , double);
f = u - 1.;
}
double hfsq = 0.5 * f * f;
double s = f / (2. + f);
double z = s * s;
double w = z * z;
double t1 = w * (LG2 + w * (LG4 + w * LG6));
double t2 = z * (LG1 + w * (LG3 + w * (LG5 + w * LG7)));
double r = t1 + t2;
double dk = k;
return s * (hfsq + r) + (dk * LN2_LO + c) - hfsq + f + dk * LN2_HI;
}
/* origin: FreeBSD /usr/src/lib/msun/src/s_log1pf.c */
/*
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
*/
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
/* origin: musl libc /src/math/log1pf.c */
/*
* ====================================================
* Copyright (c) 2005-2020 Rich Felker, et al.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* ====================================================
*/
const float LN2_HI_F @local = 6.9313812256e-01; /* 0x3f317180 */
const float LN2_LO_F @local = 9.0580006145e-06; /* 0x3717f7d1 */
/* |(log(1+s)-log(1-s))/s - Lg(s)| < 2**-34.24 (~[-4.95e-11, 4.97e-11]). */
const float LG1_F @local = 0xaaaaaa.0p-24; /* 0.66666662693 */
const float LG2_F @local = 0xccce13.0p-25; /* 0.40000972152 */
const float LG3_F @local = 0x91e9ee.0p-25; /* 0.28498786688 */
const float LG4_F @local = 0xf89e26.0p-26; /* 0.24279078841 */
fn float _log1pf(float x) @weak @extern("log1pf") @nostrip
{
uint ix = x.word();
int k = 1;
float c @noinit;
float f @noinit;
switch
{
/* 1+x < sqrt(2)+ */
case ix < 0x3ed413d0 || ix >> 31 != 0:
switch
{
/* x <= -1.0 */
case ix >= 0xbf800000:
if (x == -1) return -float.inf;
return float.nan;
/* |x| < 2**-24 */
case ix << 1 < 0x33800000 << 1:
/* underflow if subnormal */
if ((ix & 0x7f800000) == 0)
{
float v = @volatile_load(x);
v = v * v;
}
return x;
/* sqrt(2)/2- <= 1+x < sqrt(2)+ */
case ix <= 0xbe95f619:
k = 0;
c = 0;
f = x;
}
case ix >= 0x7f800000:
return x;
}
if (k)
{
float u = 1 + x;
uint iu = u.word();
iu += 0x3f800000 - 0x3f3504f3;
k = (int)(iu >> 23) - 0x7f;
/* correction term ~ log(1+x)-log(u), avoid underflow in c/u */
if (k < 25)
{
c = (k >= 2) ? 1.f - (u - x) : x - (u - 1.f);
c /= u;
}
else
{
c = 0;
}
/* reduce u into [sqrt(2)/2, sqrt(2)] */
iu = (iu & 0x007fffff) + 0x3f3504f3;
f = bitcast(iu, float) - 1.f;
}
float hfsq = 0.5f * f * f;
float s = f / (2.f + f);
float z = s * s;
float w = z * z;
float t1 = w * (LG2_F + w * LG4_F);
float t2 = z * (LG1_F + w * LG3_F);
float r = t1 + t2;
float dk = k;
return s * (hfsq + r) + (dk * LN2_LO_F + c) - hfsq + f + dk * LN2_HI_F;
}

View File

@@ -1,109 +1,11 @@
module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
fn double pow(double x, double y) @extern("pow")
fn float powf_broken(float x, float f) @extern("powf") @weak @nostrip
{
if (x != x || y != y) return double.nan;
if (y == double.inf)
{
if (x == 1.0 || x == -1.0) return 1.0;
return (_fabs(x) < 1.0) ? 0.0 : double.inf;
}
if (y == -double.inf)
{
if (x == 1.0 || x == -1.0) return 1.0;
return (_fabs(x) < 1.0) ? double.inf : 0.0;
}
if (x == double.inf)
{
return (y < 0.0) ? 0.0 : double.inf;
}
if (x == -double.inf)
{
if (y != _floor(y)) return -double.nan;
if (y < 0.0) return 0.0;
return ((int)y & 1) ? -double.inf : double.inf;
}
if (y == 0.0) return 1.0;
if (x == 0.0)
{
if (y < 0.0) return double.inf;
if (y > 0.0) return 0.0;
return 1.0;
}
if (y == 1.0) return x;
if (x == 1.0) return 1.0;
if (x < 0.0)
{
if (y != _floor(y)) return double.nan;
return ((int)y & 1) ? -pow(-x, y) : pow(-x, y);
}
double result = exp(y * log(x));
if (result == double.inf || result == -double.inf)
{
return (y < 0.0) ? 0.0 : double.inf;
}
if (result == 0.0) return 0.0;
return result;
unreachable("'powf' not supported");
}
fn float powf(float x, float y) @extern("powf")
fn double pow_broken(double x, double y) @extern("pow") @weak @nostrip
{
if (x != x || y != y) return float.nan;
if (y == float.inf)
{
if (x == 1.0f || x == -1.0f) return 1.0f;
return (_fabsf(x) < 1.0f) ? 0.0f : float.inf;
}
if (y == -float.inf)
{
if (x == 1.0f || x == -1.0f) return 1.0f;
return (_fabsf(x) < 1.0f) ? float.inf : 0.0f;
}
if (x == float.inf)
{
return (y < 0.0f) ? 0.0f : float.inf;
}
if (x == -float.inf)
{
if (y != _floorf(y)) return float.nan;
if (y < 0.0f) return 0.0f;
return ((int)y & 1) ? -float.inf : float.inf;
}
if (y == 0.0f) return 1.0f;
if (x == 0.0f)
{
if (y < 0.0f) return float.inf;
if (y > 0.0f) return 0.0f;
return 1.0f;
}
if (y == 1.0f) return x;
if (x == 1.0f) return 1.0f;
if (x < 0.0f)
{
if (y != _floorf(y)) return float.nan;
return ((int)y & 1) ? -powf(-x, y) : powf(-x, y);
}
float result = expf(y * logf(x));
if (result == float.inf || result == -float.inf)
{
return (y < 0.0f) ? 0.0f : float.inf;
}
if (result == 0.0f) return 0.0f;
return result;
}
unreachable("'pow' not supported");
}

View File

@@ -94,9 +94,9 @@ fn int __rem_pio2f(float x, double *y)
* ====================================================
*/
const int[?] INIT_JK = {3,4,4,6}; /* initial value for jk */
const int[*] INIT_JK = {3,4,4,6}; /* initial value for jk */
const int[?] IPIO2 = {
const int[*] IPIO2 = {
0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62,
0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A,
0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129,
@@ -109,7 +109,7 @@ const int[?] IPIO2 = {
0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880,
0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B, };
const double[?] PIO2 = {
const double[*] PIO2 = {
1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */
7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */
5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */
@@ -238,7 +238,8 @@ fn int __rem_pio2_large(double* x, double* y, int e0, int nx, int prec)
{
/* add q[jz+1] to q[jz+k] */
f[jx + i] = (double)IPIO2[jv + i];
for (j = 0, fw = 0.0; j <= jx; j++) fw += x[j] * f[jx + i - j];
for (j = 0, fw = 0.0; j <= jx; j++)
fw += x[j] * f[jx + i - j];
q[i] = fw;
}
jz += k;
@@ -302,7 +303,8 @@ fn int __rem_pio2_large(double* x, double* y, int e0, int nx, int prec)
case 1:
case 2:
fw = 0.0;
for (int i = jz; i >= 0; i--) fw += fq[i];
for (int i = jz; i >= 0; i--)
fw += fq[i];
// TODO: drop excess precision here once double_t is used
fw = (double)fw;
y[0] = ih == 0 ? fw : -fw;
@@ -322,7 +324,8 @@ fn int __rem_pio2_large(double* x, double* y, int e0, int nx, int prec)
fq[i] += fq[i - 1] - fw;
fq[i - 1] = fw;
}
for (fw = 0.0, int i = jz; i >= 2; i--) fw += fq[i];
for (fw = 0.0, int i = jz; i >= 2; i--)
fw += fq[i];
if (ih == 0)
{
y[0] = fq[0];

View File

@@ -18,7 +18,7 @@ module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
fn float _sinf(float x) @weak @extern("sinf") @nostrip
{
uint ix = x.word();
uint ix = bitcast(x, uint);
int sign = ix >> 31;
ix &= 0x7fffffff;
switch
@@ -87,7 +87,8 @@ fn float _sinf(float x) @weak @extern("sinf") @nostrip
fn double sin(double x) @extern("sin") @weak @nostrip
{
// High word of x.
uint ix = x.high_word() & 0x7fffffff;
uint ix = (uint)(bitcast(x, ulong) >> 32);
ix &= 0x7fffffff;
switch
{
// |x| ~< pi/4

View File

@@ -18,7 +18,8 @@ module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
fn void sincosf(float x, float *sin, float *cos) @extern("__sincosf") @weak @nostrip
{
uint ix = x.word();
uint ix = bitcast(x, uint);
uint sign = ix >> 31;
ix &= 0x7fffffff;
@@ -107,7 +108,8 @@ fn void sincosf(float x, float *sin, float *cos) @extern("__sincosf") @weak @nos
fn void sincos(double x, double *sin, double *cos) @extern("__sincos") @weak @nostrip
{
// High word of x.
uint ix = x.high_word() & 0x7fffffff;
uint ix = (uint)(bitcast(x, ulong) >> 32);
ix &= 0x7fffffff;
// |x| ~< pi/4
switch

View File

@@ -14,7 +14,7 @@ module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
fn double tan(double x) @extern("tan") @weak @nostrip
{
uint ix = x.high_word();
uint ix = (uint)(bitcast(x, ulong) >> 32);
ix &= 0x7fffffff;
// |x| ~< pi/4
@@ -59,7 +59,7 @@ fn double tan(double x) @extern("tan") @weak @nostrip
fn float tanf(float x) @extern("tanf") @weak @nostrip
{
uint ix = x.word();
uint ix = bitcast(x, uint);
uint sign = ix >> 31;
ix &= 0x7fffffff;

View File

@@ -11,11 +11,11 @@ union Quaternion
const Quaternion IDENTITY = { 0, 0, 0, 1 };
macro Quaternion Quaternion.add(Quaternion a, Quaternion b) => { .v = a.v + b.v };
macro Quaternion Quaternion.add_each(Quaternion a, Real b) => { .v = a.v + b };
macro Quaternion Quaternion.sub(Quaternion a, Quaternion b) => { .v = a.v - b.v };
macro Quaternion Quaternion.sub_each(Quaternion a, Real b) => { .v = a.v - b };
macro Quaternion Quaternion.scale(Quaternion a, Real s) => { .v = a.v * s };
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 };
macro Quaternion Quaternion.sub_each(Quaternion a, Real b) => Quaternion { .v = a.v - b };
macro Quaternion Quaternion.scale(Quaternion a, Real s) => Quaternion { .v = a.v * s };
macro Quaternion Quaternion.normalize(Quaternion q) => { .v = q.v.normalize() };
macro Real Quaternion.length(Quaternion q) => q.v.length();
macro Quaternion Quaternion.lerp(Quaternion q1, Quaternion q2, Real amount) => { .v = q1.v.lerp(q2.v, amount) };
@@ -76,7 +76,7 @@ macro into_matrix(Quaternion* q, $Type) @private
var z = rotation.k;
var w = rotation.l;
return ($Type) {
return $Type {
1 - 2*y*y - 2*z*z, 2*x*y - 2*z*w, 2*x*z + 2*y*w, 0,
2*x*y + 2*z*w, 1 - 2*x*x - 2*z*z, 2*y*z - 2*x*w, 0,
2*x*z - 2*y*w, 2*y*z + 2*x*w , 1 - 2*x*x - 2*y*y, 0,

View File

@@ -145,7 +145,7 @@ macro transform2(v, mat) @private
macro transform3(v, mat) @private
{
return ($typeof(v)){
return $typeof(v) {
mat.m00 * v[0] + mat.m10 * v[1] + mat.m20 * v[2] + mat.m30,
mat.m01 * v[0] + mat.m11 * v[1] + mat.m21 * v[2] + mat.m31,
mat.m02 * v[0] + mat.m12 * v[1] + mat.m22 * v[2] + mat.m32
@@ -169,7 +169,7 @@ macro void ortho_normalize3(v1, v2) @private
macro rotate_by_quat3(v, q) @private
{
return ($typeof(v)){
return $typeof(v) {
v[0] * (q.i * q.i + q.l * q.l - q.j * q.j - q.k * q.k)
+ v[1] * (2 * q.i * q.j - 2 * q.l * q.k)
+ v[2] * (2 * q.i * q.k - 2 * q.l * q.j),
@@ -233,7 +233,7 @@ macro barycenter3(p, a, b, c) @private
var denom = d00 * d11 - d01 * d01;
var y = (d11 * d20 - d01 * d21) / denom;
var z = (d00 * d21 - d01 * d20) / denom;
return ($typeof(p)){ 1 - y - z, y, z };
return $typeof(p) { 1 - y - z, y, z };
}
macro refract3(v, n, r) @private

View File

@@ -86,7 +86,7 @@ fn char[8 * 4] entropy() @if(!env::WASM_NOLIBC)
hash(&entropy),
random_int,
hash(clock::now()),
hash(&DString.init),
hash(&DString.new_init),
hash(allocator::heap())
};
return bitcast(entropy_data, char[8 * 4]);

View File

@@ -257,13 +257,16 @@ fn bool InetAddress.is_multicast_link_local(InetAddress* addr)
return addr.ipv4.a == 224 && addr.ipv4.b == 0 && addr.ipv4.c == 0;
}
fn AddrInfo*! addrinfo(String host, uint port, AIFamily ai_family, AISockType ai_socktype) @if(os::SUPPORTS_INET) => @pool()
fn AddrInfo*! addrinfo(String host, uint port, AIFamily ai_family, AISockType ai_socktype) @if(os::SUPPORTS_INET)
{
ZString zhost = host.zstr_tcopy();
DString str = dstring::temp_with_capacity(32);
str.appendf("%d", port);
AddrInfo hints = { .ai_family = ai_family, .ai_socktype = ai_socktype };
AddrInfo* ai;
if (os::getaddrinfo(zhost, str.zstr_view(), &hints, &ai)) return NetError.ADDRINFO_FAILED?;
return ai;
@pool()
{
ZString zhost = host.zstr_tcopy();
DString str = dstring::temp_with_capacity(32);
str.appendf("%d", port);
AddrInfo hints = { .ai_family = ai_family, .ai_socktype = ai_socktype };
AddrInfo* ai;
if (os::getaddrinfo(zhost, str.zstr_view(), &hints, &ai)) return NetError.ADDRINFO_FAILED?;
return ai;
};
}

View File

@@ -94,4 +94,3 @@ const CShort POLLATTRIB = 0x0400; // file attributes may have changed
const CShort POLLNLINK = 0x0800; // (un)link/rename may have happened
const CShort POLLWRITE = 0x1000; // file's contents may have changed
const CInt MSG_PEEK = 0x0002;

View File

@@ -88,5 +88,3 @@ const CUShort POLLREMOVE = 0x1000;
const CUShort POLLRDHUP = 0x2000;
const CUShort POLLFREE = 0x4000;
const CUShort POLL_BUSY_LOOP = 0x8000;
const CInt MSG_PEEK = 0x0002;

View File

@@ -101,5 +101,3 @@ const CUShort POLLRDNORM = win32::POLLRDNORM;
const CUShort POLLRDBAND = win32::POLLRDBAND;
const CUShort POLLWRNORM = win32::POLLWRNORM;
const CUShort POLLWRBAND = win32::POLLWRBAND;
const int MSG_PEEK = 0x0002;

Some files were not shown because too many files have changed in this diff Show More