mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
058d637407 | ||
|
|
01335f6862 |
89
.github/workflows/main.yml
vendored
89
.github/workflows/main.yml
vendored
@@ -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,7 +51,7 @@ 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
|
||||
..\..\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_ir
|
||||
@@ -61,7 +61,7 @@ jobs:
|
||||
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,15 @@ 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: Compile run unit tests
|
||||
run: |
|
||||
cd test
|
||||
..\build\${{ matrix.build_type }}\c3c.exe compile-test unit -O1
|
||||
|
||||
- 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: Test python script
|
||||
run: |
|
||||
@@ -133,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 }}
|
||||
@@ -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,7 +162,7 @@ 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: |
|
||||
@@ -210,12 +209,12 @@ 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: |
|
||||
@@ -223,13 +222,13 @@ jobs:
|
||||
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: |
|
||||
@@ -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,17 +486,17 @@ 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: |
|
||||
@@ -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: |
|
||||
@@ -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,17 +670,17 @@ 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: |
|
||||
@@ -704,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
6
.gitignore
vendored
@@ -79,9 +79,3 @@ TAGS
|
||||
# 'nix build' resulting symlink
|
||||
result
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
|
||||
# tests
|
||||
/test/tmp/*
|
||||
/test/testrun
|
||||
|
||||
@@ -38,10 +38,10 @@ 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} -O3 -fno-exceptions")
|
||||
@@ -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
|
||||
|
||||
24
README.md
24
README.md
@@ -138,7 +138,7 @@ fn void main()
|
||||
|
||||
### Current status
|
||||
|
||||
The current stable version of the compiler is **version 0.6.6**.
|
||||
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.
|
||||
|
||||
@@ -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
12
flake.lock
generated
@@ -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": {
|
||||
|
||||
11
flake.nix
11
flake.nix
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
140
lib/std/bits.c3
140
lib/std/bits.c3
@@ -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);
|
||||
|
||||
@@ -117,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));
|
||||
}
|
||||
|
||||
@@ -6,9 +6,8 @@
|
||||
*>
|
||||
module std::collections::map(<Key, Value>);
|
||||
import std::math;
|
||||
import std::io @norecurse;
|
||||
|
||||
struct HashMap (Printable)
|
||||
struct HashMap
|
||||
{
|
||||
Entry*[] table;
|
||||
Allocator allocator;
|
||||
@@ -447,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;
|
||||
|
||||
@@ -45,7 +45,7 @@ fn LinkedList* LinkedList.temp_init(&self)
|
||||
}
|
||||
|
||||
<*
|
||||
@require self.allocator != null
|
||||
@require self.allocator
|
||||
*>
|
||||
macro void LinkedList.free_node(&self, Node* node) @private
|
||||
{
|
||||
@@ -200,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
|
||||
{
|
||||
@@ -296,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
|
||||
{
|
||||
|
||||
@@ -19,20 +19,6 @@ struct List (Printable)
|
||||
Type *entries;
|
||||
}
|
||||
|
||||
<*
|
||||
@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, usz initial_capacity = 16, Allocator allocator)
|
||||
{
|
||||
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"
|
||||
@@ -54,7 +40,7 @@ fn List* List.new_init(&self, usz initial_capacity = 16, Allocator allocator = a
|
||||
*>
|
||||
fn List* List.temp_init(&self, usz initial_capacity = 16)
|
||||
{
|
||||
return self.init(initial_capacity, allocator::temp()) @inline;
|
||||
return self.new_init(initial_capacity, allocator::temp()) @inline;
|
||||
}
|
||||
|
||||
<*
|
||||
@@ -234,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;
|
||||
}
|
||||
|
||||
@@ -342,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);
|
||||
@@ -440,7 +425,7 @@ macro void List.pre_free(&self) @private
|
||||
}
|
||||
|
||||
<*
|
||||
@require self.capacity > 0
|
||||
@require self.capacity
|
||||
*>
|
||||
macro void List.post_alloc(&self) @private
|
||||
{
|
||||
|
||||
@@ -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) @operator(construct)
|
||||
{
|
||||
return { .value = val, .has_value = true };
|
||||
}
|
||||
|
||||
fn Maybe Maybe.empty() @operator(construct)
|
||||
{
|
||||
return { };
|
||||
}
|
||||
|
||||
const Maybe EMPTY = { };
|
||||
|
||||
macro Type! Maybe.get(self)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
<*
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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());
|
||||
|
||||
|
||||
@@ -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();
|
||||
@@ -237,7 +238,7 @@ 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 $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
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -157,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([])
|
||||
{
|
||||
@@ -166,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(&[])
|
||||
{
|
||||
@@ -660,5 +660,5 @@ struct StringData @private
|
||||
Allocator allocator;
|
||||
usz len;
|
||||
usz capacity;
|
||||
char[?] chars;
|
||||
char[*] chars;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
@@ -1,322 +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 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;
|
||||
String current_test_name;
|
||||
TestFn setup_fn;
|
||||
TestFn teardown_fn;
|
||||
|
||||
char* error_buffer;
|
||||
usz error_buffer_capacity;
|
||||
File fake_stdout;
|
||||
File orig_stdout;
|
||||
File orig_stderr;
|
||||
}
|
||||
|
||||
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;
|
||||
libc::longjmp(&test_context.buf, 1);
|
||||
}
|
||||
|
||||
fn void mute_output() @local
|
||||
{
|
||||
if (!test_context.fake_stdout.file) return;
|
||||
assert(!test_context.orig_stderr.file);
|
||||
assert(!test_context.orig_stdout.file);
|
||||
|
||||
File* stdout = io::stdout();
|
||||
File* stderr = io::stderr();
|
||||
|
||||
test_context.orig_stderr = *stderr;
|
||||
test_context.orig_stdout = *stdout;
|
||||
|
||||
*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.fake_stdout.file)
|
||||
{
|
||||
return;
|
||||
}
|
||||
assert(test_context.orig_stderr.file);
|
||||
assert(test_context.orig_stdout.file);
|
||||
|
||||
File* stdout = io::stdout();
|
||||
File* stderr = io::stderr();
|
||||
|
||||
*stderr = test_context.orig_stderr;
|
||||
*stdout = test_context.orig_stdout;
|
||||
test_context.orig_stderr.file = null;
|
||||
test_context.orig_stdout.file = null;
|
||||
|
||||
usz log_size = test_context.fake_stdout.seek(0, Seek.CURSOR)!!;
|
||||
if (has_error)
|
||||
{
|
||||
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;
|
||||
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(),
|
||||
};
|
||||
for (int i = 1; i < args.len; i++)
|
||||
{
|
||||
switch (args[i])
|
||||
{
|
||||
case "breakpoint":
|
||||
context.breakpoint_on_assert = true;
|
||||
case "nosort":
|
||||
sort_tests = false;
|
||||
case "noansi":
|
||||
context.has_ansi_codes = false;
|
||||
case "useansi":
|
||||
context.has_ansi_codes = true;
|
||||
case "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):
|
||||
test_context.fake_stdout.file = libc::tmpfile();
|
||||
$endif
|
||||
if (test_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);
|
||||
io::printn(name);
|
||||
name.clear();
|
||||
foreach(unit : tests)
|
||||
{
|
||||
if (test_context.test_filter && !unit.name.contains(test_context.test_filter))
|
||||
{
|
||||
tests_skipped++;
|
||||
continue;
|
||||
}
|
||||
test_context.setup_fn = null;
|
||||
test_context.teardown_fn = null;
|
||||
test_context.current_test_name = unit.name;
|
||||
|
||||
defer name.clear();
|
||||
name.appendf("Testing %s ", unit.name);
|
||||
name.append_repeat('.', max_name - unit.name.len + 2);
|
||||
io::printf("%s ", name.str_view());
|
||||
TrackingAllocator mem;
|
||||
mem.init(allocator::heap());
|
||||
if (libc::setjmp(&context.buf) == 0)
|
||||
{
|
||||
mute_output();
|
||||
mem.clear();
|
||||
mem::@scoped(&mem)
|
||||
{
|
||||
$if(!$$OLD_TEST):
|
||||
unit.func();
|
||||
$else
|
||||
if (catch err = unit.func())
|
||||
{
|
||||
io::printf("[FAIL] Failed due to: %s", err);
|
||||
continue;
|
||||
}
|
||||
$endif
|
||||
};
|
||||
unmute_output(false); // all good, discard output
|
||||
if (mem.has_leaks())
|
||||
{
|
||||
io::print(test_context.has_ansi_codes ? "[\e[0;31mFAIL\e[0m]" : "[FAIL]");
|
||||
io::printn(" LEAKS DETECTED!");
|
||||
mem.print_report();
|
||||
}
|
||||
else
|
||||
{
|
||||
io::printfn(test_context.has_ansi_codes ? "[\e[0;32mPASS\e[0m]" : "[PASS]");
|
||||
tests_passed++;
|
||||
}
|
||||
if (test_context.teardown_fn)
|
||||
{
|
||||
test_context.teardown_fn();
|
||||
}
|
||||
}
|
||||
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: ",
|
||||
test_context.has_ansi_codes ? (n_failed ? "\e[0;31m" : "\e[0;32m") : "",
|
||||
n_failed ? "FAILED" : "PASSED",
|
||||
test_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 (test_context.fake_stdout.file) libc::fclose(test_context.fake_stdout.file);
|
||||
test_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()));
|
||||
}
|
||||
|
||||
@@ -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 = "";
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.new_init(allocator: 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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -106,7 +106,7 @@ fn void! File.close(&self) @inline @dynamic
|
||||
}
|
||||
|
||||
<*
|
||||
@require self.file != null
|
||||
@require self.file
|
||||
*>
|
||||
fn bool File.eof(&self) @inline
|
||||
{
|
||||
@@ -123,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
|
||||
{
|
||||
@@ -203,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
|
||||
{
|
||||
|
||||
@@ -195,7 +195,7 @@ 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:
|
||||
@@ -238,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
|
||||
@@ -274,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;
|
||||
@@ -476,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)
|
||||
{
|
||||
@@ -517,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':
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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())
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
|
||||
@@ -104,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)
|
||||
@@ -126,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];
|
||||
}
|
||||
@@ -153,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)!;
|
||||
}
|
||||
@@ -208,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)
|
||||
|
||||
@@ -16,15 +16,15 @@ 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.new_init(&self, usz max_read, usz initial_capacity = 16, Allocator allocator = allocator::heap())
|
||||
fn ByteBuffer*! ByteBuffer.new_init(&self, usz max_read, usz initial_capacity = 16, Allocator allocator = allocator::heap())
|
||||
{
|
||||
*self = { .allocator = allocator, .max_read = max_read };
|
||||
initial_capacity = max(initial_capacity, 16);
|
||||
self.grow(initial_capacity);
|
||||
self.grow(initial_capacity)!;
|
||||
return self;
|
||||
}
|
||||
|
||||
fn ByteBuffer* ByteBuffer.temp_init(&self, usz max_read, usz initial_capacity = 16)
|
||||
fn ByteBuffer*! ByteBuffer.temp_init(&self, usz max_read, usz initial_capacity = 16)
|
||||
{
|
||||
return self.new_init(max_read, initial_capacity, allocator::temp());
|
||||
}
|
||||
@@ -33,7 +33,7 @@ fn ByteBuffer* ByteBuffer.temp_init(&self, usz max_read, usz initial_capacity =
|
||||
@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;
|
||||
@@ -48,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;
|
||||
@@ -57,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++;
|
||||
}
|
||||
@@ -128,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];
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
@@ -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;
|
||||
@@ -92,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?;
|
||||
}
|
||||
@@ -445,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;
|
||||
@@ -461,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;
|
||||
@@ -485,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)
|
||||
@@ -520,7 +520,7 @@ 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;
|
||||
|
||||
@@ -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`
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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) */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -52,26 +52,23 @@ struct Poll
|
||||
PollEvents revents;
|
||||
}
|
||||
|
||||
<*
|
||||
@param [inout] polls
|
||||
@param timeout "duration to poll (clamped to CInt.max ms), or POLL_FOREVER."
|
||||
*>
|
||||
fn ulong! poll(Poll[] polls, Duration timeout)
|
||||
fn ulong! poll_ms(Poll[] polls, long timeout_ms)
|
||||
{
|
||||
return poll_ms(polls, timeout == POLL_FOREVER ? -1 : timeout.to_ms()) @inline;
|
||||
return poll(polls, time::ms(timeout_ms)) @inline;
|
||||
}
|
||||
|
||||
<*
|
||||
@param [inout] polls
|
||||
@param timeout_ms "duration to poll in ms or -1. Clamped to CInt.max"
|
||||
@param timeout "duration to poll."
|
||||
*>
|
||||
fn ulong! poll_ms(Poll[] polls, long timeout_ms)
|
||||
fn ulong! poll(Poll[] polls, Duration timeout)
|
||||
{
|
||||
if (timeout_ms > CInt.max) timeout_ms = CInt.max;
|
||||
long time_ms = timeout.to_ms();
|
||||
if (time_ms > CInt.max) time_ms = CInt.max;
|
||||
$if env::WIN32:
|
||||
CInt result = win32_WSAPoll((Win32_LPWSAPOLLFD)polls.ptr, (Win32_ULONG)polls.len, (CInt)timeout_ms);
|
||||
CInt result = win32_WSAPoll((Win32_LPWSAPOLLFD)polls.ptr, (Win32_ULONG)polls.len, (CInt)time_ms);
|
||||
$else
|
||||
CInt result = os::poll((Posix_pollfd*)polls.ptr, (Posix_nfds_t)polls.len, (CInt)timeout_ms);
|
||||
CInt result = os::poll((Posix_pollfd*)polls.ptr, (Posix_nfds_t)polls.len, (CInt)time_ms);
|
||||
$endif
|
||||
return result < 0 ? os::socket_error()? : (ulong)result;
|
||||
}
|
||||
@@ -132,7 +129,7 @@ $endif
|
||||
return (usz)n;
|
||||
}
|
||||
|
||||
fn char! Socket.read_byte(&self) @dynamic => io::read_byte_using_read(self);
|
||||
fn char! Socket.read_byte(&self) @dynamic => io::@read_byte_using_read(self);
|
||||
|
||||
fn usz! Socket.write(&self, char[] bytes) @dynamic
|
||||
{
|
||||
@@ -145,7 +142,7 @@ $endif
|
||||
return (usz)n;
|
||||
}
|
||||
|
||||
fn void! Socket.write_byte(&self, char byte) @dynamic => io::write_byte_using_write(self, byte);
|
||||
fn void! Socket.write_byte(&self, char byte) @dynamic => io::@write_byte_using_write(self, byte);
|
||||
|
||||
fn void! Socket.destroy(&self) @dynamic
|
||||
{
|
||||
@@ -155,29 +152,3 @@ fn void! Socket.close(&self) @inline @dynamic
|
||||
{
|
||||
self.sock.close()!;
|
||||
}
|
||||
|
||||
fn usz! Socket.peek(&self, char[] bytes) @dynamic
|
||||
{
|
||||
$if env::WIN32:
|
||||
isz n = libc::recv(self.sock, bytes.ptr, (int)bytes.len, os::MSG_PEEK);
|
||||
$else
|
||||
isz n = libc::recv(self.sock, bytes.ptr, bytes.len, os::MSG_PEEK);
|
||||
$endif
|
||||
if (n < 0) return os::socket_error()?;
|
||||
return (usz)n;
|
||||
}
|
||||
|
||||
enum SocketShutdownHow : (inline CInt native_value)
|
||||
{
|
||||
RECEIVE = @select(env::WIN32, libc::SD_RECEIVE, libc::SHUT_RD),
|
||||
SEND = @select(env::WIN32, libc::SD_SEND, libc::SHUT_WR),
|
||||
BOTH = @select(env::WIN32, libc::SD_BOTH, libc::SHUT_RDWR),
|
||||
}
|
||||
|
||||
fn void! Socket.shutdown(&self, SocketShutdownHow how)
|
||||
{
|
||||
if (libc::shutdown(self.sock, how) < 0)
|
||||
{
|
||||
return os::socket_error()?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,383 +0,0 @@
|
||||
module std::net::url;
|
||||
|
||||
import std::io, std::collections::map, std::collections::list;
|
||||
|
||||
fault UrlParsingResult
|
||||
{
|
||||
EMPTY,
|
||||
INVALID_SCHEME,
|
||||
INVALID_USER,
|
||||
INVALID_PASSWORD,
|
||||
INVALID_HOST,
|
||||
INVALID_PATH,
|
||||
INVALID_FRAGMENT,
|
||||
}
|
||||
|
||||
<*
|
||||
Represents the actual (decoded) Url.
|
||||
|
||||
An Url can be parsed from a String with `new_parse()` or `temp_parse()`. The
|
||||
parsed fields are decoded. The only field that is not decoded is `query`.
|
||||
To access the decoded query values, use `new_parse_query(query)`.
|
||||
|
||||
`Url.to_string()` will re-assemble the fields into a valid Url string with
|
||||
proper percent-encoded values.
|
||||
|
||||
If the Url struct fields are filled in manually, use the actual (un-encoded)
|
||||
values. To create a raw query string, initialize an `UrlQueryValues` map, use
|
||||
`UrlQueryValues.add()` to add the query parameters and, finally, call
|
||||
`UrlQueryValues.to_string()`.
|
||||
*>
|
||||
struct Url(Printable)
|
||||
{
|
||||
String scheme;
|
||||
String host;
|
||||
uint port;
|
||||
String username;
|
||||
String password;
|
||||
String path;
|
||||
String query;
|
||||
String fragment;
|
||||
|
||||
Allocator allocator;
|
||||
}
|
||||
|
||||
<*
|
||||
Parse a URL string into a Url struct.
|
||||
|
||||
@param [in] url_string
|
||||
@require url_string.len > 0 "the url_string must be len 1 or more"
|
||||
@return "the parsed Url"
|
||||
*>
|
||||
fn Url! temp_parse(String url_string) => new_parse(url_string, allocator::temp());
|
||||
|
||||
<*
|
||||
Parse a URL string into a Url struct.
|
||||
|
||||
@param [in] url_string
|
||||
@require url_string.len > 0 "the url_string must be len 1 or more"
|
||||
@return "the parsed Url"
|
||||
*>
|
||||
fn Url! new_parse(String url_string, Allocator allocator = allocator::heap())
|
||||
{
|
||||
url_string = url_string.trim();
|
||||
if (!url_string) return UrlParsingResult.EMPTY?;
|
||||
Url url = { .allocator = allocator };
|
||||
|
||||
// Parse scheme
|
||||
if (try pos = url_string.index_of("://"))
|
||||
{
|
||||
if (!pos) return UrlParsingResult.INVALID_SCHEME?;
|
||||
url.scheme = url_string[:pos].copy(allocator);
|
||||
url_string = url_string[url.scheme.len + 3 ..];
|
||||
}
|
||||
else if (try pos = url_string.index_of(":"))
|
||||
{
|
||||
// Handle schemes without authority like 'mailto:'
|
||||
if (!pos) return UrlParsingResult.INVALID_SCHEME?;
|
||||
url.scheme = url_string[:pos].copy(allocator);
|
||||
url.path = decode(url_string[pos + 1 ..], PATH, allocator) ?? UrlParsingResult.INVALID_PATH?!;
|
||||
return url;
|
||||
}
|
||||
|
||||
// Parse host, port
|
||||
if (url.scheme != "urn")
|
||||
{
|
||||
usz authority_end = url_string.index_of_chars("/?#") ?? url_string.len;
|
||||
String authority = url_string[:authority_end];
|
||||
|
||||
if (try user_info_end = authority.index_of_char('@'))
|
||||
{
|
||||
String userinfo = authority[:user_info_end];
|
||||
String username @noinit;
|
||||
String password;
|
||||
@pool(allocator)
|
||||
{
|
||||
String[] userpass = userinfo.tsplit(":", 2);
|
||||
username = userpass[0];
|
||||
if (!username.len) return UrlParsingResult.INVALID_USER?;
|
||||
url.host =
|
||||
|
||||
url.username = decode(username, HOST, allocator) ?? UrlParsingResult.INVALID_USER?!;
|
||||
if (userpass.len) url.password = decode(userpass[1], USERPASS, allocator) ?? UrlParsingResult.INVALID_PASSWORD?!;
|
||||
};
|
||||
authority = authority[userinfo.len + 1 ..];
|
||||
}
|
||||
|
||||
// Check for IPv6 address in square brackets
|
||||
String host;
|
||||
if (authority.starts_with("[") && authority.contains("]"))
|
||||
{
|
||||
usz ipv6_end = authority.index_of("]")!;
|
||||
host = authority[0 .. ipv6_end]; // Includes closing bracket
|
||||
if ((ipv6_end + 1) < authority.len && authority[.. ipv6_end] == ":")
|
||||
{
|
||||
url.port = authority[.. ipv6_end + 1].to_uint()!;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@pool(allocator)
|
||||
{
|
||||
String[] host_port = authority.tsplit(":", 2);
|
||||
if (host_port.len > 1)
|
||||
{
|
||||
host = host_port[0];
|
||||
url.port = host_port[1].to_uint()!;
|
||||
}
|
||||
else
|
||||
{
|
||||
host = authority;
|
||||
}
|
||||
};
|
||||
}
|
||||
url.host = decode(host, HOST, allocator) ?? UrlParsingResult.INVALID_HOST?!;
|
||||
url_string = url_string[authority_end ..];
|
||||
}
|
||||
|
||||
// Parse path
|
||||
usz! query_index = url_string.index_of_char('?');
|
||||
usz! fragment_index = url_string.index_of_char('#');
|
||||
|
||||
if (@ok(query_index) || @ok(fragment_index))
|
||||
{
|
||||
usz path_end = min(query_index ?? url_string.len, fragment_index ?? url_string.len);
|
||||
url.path = decode(url_string[:path_end], PATH, allocator) ?? UrlParsingResult.INVALID_PATH?!;
|
||||
url_string = url_string[path_end ..];
|
||||
}
|
||||
else
|
||||
{
|
||||
url.path = decode(url_string, PATH, allocator) ?? UrlParsingResult.INVALID_PATH?!;
|
||||
url_string = "";
|
||||
}
|
||||
|
||||
// Remove the path part from url for further parsing
|
||||
|
||||
|
||||
// Parse query
|
||||
if (url_string.starts_with("?"))
|
||||
{
|
||||
usz index = url_string.index_of_char('#') ?? url_string.len;
|
||||
url.query = url_string[1 .. index - 1].copy(allocator);
|
||||
url_string = url_string[index ..];
|
||||
}
|
||||
|
||||
// Parse fragment
|
||||
if (url_string.starts_with("#"))
|
||||
{
|
||||
url.fragment = decode(url_string[1..], FRAGMENT, allocator) ?? UrlParsingResult.INVALID_FRAGMENT?!;
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
<*
|
||||
Stringify a Url struct.
|
||||
|
||||
@param [in] self
|
||||
@param [inout] allocator
|
||||
@return "Url as a string"
|
||||
*>
|
||||
fn String Url.to_string(&self, Allocator allocator = allocator::heap()) @dynamic => @pool(allocator)
|
||||
{
|
||||
DString builder = dstring::temp_new();
|
||||
|
||||
// Add scheme if it exists
|
||||
if (self.scheme != "")
|
||||
{
|
||||
builder.append_chars(self.scheme);
|
||||
builder.append_char(':');
|
||||
if (self.host.len > 0) builder.append_chars("//");
|
||||
}
|
||||
|
||||
// Add username and password if they exist
|
||||
if (self.username != "")
|
||||
{
|
||||
String username = temp_encode(self.username, USERPASS);
|
||||
builder.append_chars(username);
|
||||
|
||||
if (self.password != "")
|
||||
{
|
||||
builder.append_char(':');
|
||||
|
||||
String password = temp_encode(self.password, USERPASS);
|
||||
builder.append_chars(password);
|
||||
}
|
||||
builder.append_char('@');
|
||||
}
|
||||
|
||||
// Add host
|
||||
String host = temp_encode(self.host, HOST);
|
||||
builder.append_chars(host);
|
||||
|
||||
// Add port
|
||||
if (self.port != 0)
|
||||
{
|
||||
builder.append_char(':');
|
||||
builder.appendf("%d", self.port);
|
||||
}
|
||||
|
||||
// Add path
|
||||
String path = temp_encode(self.path, PATH);
|
||||
builder.append_chars(path);
|
||||
|
||||
// Add query if it exists (note that `query` is expected to
|
||||
// be already properly encoded).
|
||||
if (self.query != "")
|
||||
{
|
||||
builder.append_char('?');
|
||||
builder.append_chars(self.query);
|
||||
}
|
||||
|
||||
// Add fragment if it exists
|
||||
if (self.fragment != "")
|
||||
{
|
||||
builder.append_char('#');
|
||||
|
||||
String fragment = temp_encode(self.fragment, FRAGMENT);
|
||||
builder.append_chars(fragment);
|
||||
}
|
||||
|
||||
return builder.copy_str(allocator);
|
||||
}
|
||||
|
||||
def UrlQueryValueList = List(<String>);
|
||||
|
||||
struct UrlQueryValues
|
||||
{
|
||||
inline HashMap(<String, UrlQueryValueList>) map;
|
||||
UrlQueryValueList key_order;
|
||||
}
|
||||
|
||||
<*
|
||||
Parse the query parameters of the Url into a UrlQueryValues map.
|
||||
|
||||
@param [in] query
|
||||
@return "a UrlQueryValues HashMap"
|
||||
*>
|
||||
fn UrlQueryValues temp_parse_query(String query) => parse_query(query, allocator::temp());
|
||||
|
||||
<*
|
||||
Parse the query parameters of the Url into a UrlQueryValues map.
|
||||
|
||||
@param [in] query
|
||||
@return "a UrlQueryValues HashMap"
|
||||
*>
|
||||
fn UrlQueryValues new_parse_query(String query) => parse_query(query, allocator::heap());
|
||||
|
||||
<*
|
||||
Parse the query parameters of the Url into a UrlQueryValues map.
|
||||
|
||||
@param [in] query
|
||||
@param [inout] allocator
|
||||
@return "a UrlQueryValues HashMap"
|
||||
*>
|
||||
fn UrlQueryValues parse_query(String query, Allocator allocator)
|
||||
{
|
||||
UrlQueryValues vals;
|
||||
vals.map.init(allocator);
|
||||
vals.key_order.new_init(allocator: allocator);
|
||||
|
||||
Splitter raw_vals = query.tokenize("&");
|
||||
while (try String rv = raw_vals.next())
|
||||
{
|
||||
@pool(allocator)
|
||||
{
|
||||
String[] parts = rv.tsplit("=", 2);
|
||||
String key = temp_decode(parts[0], QUERY) ?? parts[0];
|
||||
vals.add(key, parts.len == 1 ? key : (temp_decode(parts[1], QUERY) ?? parts[1]));
|
||||
};
|
||||
}
|
||||
return vals;
|
||||
}
|
||||
|
||||
<*
|
||||
Add copies of the key and value strings to the UrlQueryValues map. These
|
||||
copies are freed when the UrlQueryValues map is freed.
|
||||
|
||||
@param [in] self
|
||||
@param key
|
||||
@param value
|
||||
@return "a UrlQueryValues map"
|
||||
*>
|
||||
fn UrlQueryValues* UrlQueryValues.add(&self, String key, String value)
|
||||
{
|
||||
String value_copy = value.copy(self.allocator);
|
||||
if (try existing = self.get_ref(key))
|
||||
{
|
||||
existing.push(value_copy);
|
||||
}
|
||||
else
|
||||
{
|
||||
UrlQueryValueList new_list;
|
||||
new_list.new_init_with_array({ value_copy }, self.allocator);
|
||||
(*self)[key] = new_list;
|
||||
self.key_order.push(key.copy(self.allocator));
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
<*
|
||||
Stringify UrlQueryValues into an encoded query string.
|
||||
|
||||
@param [in] self
|
||||
@param [inout] allocator
|
||||
@return "a percent-encoded query string"
|
||||
*>
|
||||
fn String UrlQueryValues.to_string(&self, Allocator allocator = allocator::heap()) @dynamic => @pool(allocator)
|
||||
{
|
||||
DString builder = dstring::temp_new();
|
||||
|
||||
usz i;
|
||||
foreach (key: self.key_order)
|
||||
{
|
||||
String encoded_key = temp_encode(key, QUERY);
|
||||
|
||||
UrlQueryValueList! values = self.map.get(key);
|
||||
if (catch values) continue;
|
||||
|
||||
foreach (value: values)
|
||||
{
|
||||
if (i > 0) builder.append_char('&');
|
||||
|
||||
builder.append_chars(encoded_key);
|
||||
builder.append_char('=');
|
||||
|
||||
String encoded_value = temp_encode(value, QUERY);
|
||||
builder.append_chars(encoded_value);
|
||||
i++;
|
||||
}
|
||||
};
|
||||
|
||||
return builder.copy_str(allocator);
|
||||
}
|
||||
|
||||
fn void UrlQueryValues.free(&self)
|
||||
{
|
||||
self.map.@each(;String key, UrlQueryValueList values)
|
||||
{
|
||||
foreach (value: values) value.free(self.allocator);
|
||||
values.free();
|
||||
};
|
||||
self.map.free();
|
||||
|
||||
foreach (&key: self.key_order) key.free(self.allocator);
|
||||
self.key_order.free();
|
||||
}
|
||||
|
||||
<*
|
||||
Free an Url struct.
|
||||
|
||||
@param [in] self
|
||||
*>
|
||||
fn void Url.free(&self)
|
||||
{
|
||||
if (!self.allocator) return;
|
||||
self.scheme.free(self.allocator);
|
||||
self.host.free(self.allocator);
|
||||
self.username.free(self.allocator);
|
||||
self.password.free(self.allocator);
|
||||
self.path.free(self.allocator);
|
||||
self.query.free(self.allocator);
|
||||
self.fragment.free(self.allocator);
|
||||
}
|
||||
@@ -1,191 +0,0 @@
|
||||
<*
|
||||
This module section provides encoding and decoding functions for URL
|
||||
components according to RFC 3986.
|
||||
*>
|
||||
module std::net::url;
|
||||
import std::encoding::hex;
|
||||
|
||||
enum UrlEncodingMode : char (String allowed)
|
||||
{
|
||||
UNRESERVED = "-_.~", // section 2.3
|
||||
PATH = "$&+,/:;=@", // section 3.3
|
||||
HOST = "!$&'()*+,;=:[]", // section 3.2.2 (also include ':', '[', ']' for ipv6 hosts)
|
||||
USERPASS = ";:&=+$,", // section 3.2.1
|
||||
QUERY = "", // section 3.4
|
||||
FRAGMENT = "$&+,/:;=?@!()*", // section 4.1
|
||||
}
|
||||
|
||||
fault UrlDecodingError
|
||||
{
|
||||
INVALID_HEX
|
||||
}
|
||||
|
||||
<*
|
||||
Returns true if char c should be encoded according to RFC 3986.
|
||||
|
||||
@param c "Character to check if it should be encoded."
|
||||
@param mode "Url encoding mode."
|
||||
*>
|
||||
fn bool should_encode(char c, UrlEncodingMode mode) @private
|
||||
{
|
||||
// alphanumeric characters are allowed
|
||||
if (c.is_alnum()) return false;
|
||||
|
||||
// unreserved characters are allowed
|
||||
if (try UrlEncodingMode.UNRESERVED.allowed.index_of_char(c)) return false;
|
||||
|
||||
// some mode-specific characters are allowed
|
||||
if (try mode.allowed.index_of_char(c)) return false;
|
||||
|
||||
// everything else must be encoded
|
||||
return true;
|
||||
}
|
||||
|
||||
<*
|
||||
Calculate the length of the percent-encoded string.
|
||||
*>
|
||||
fn usz encode_len(String s, UrlEncodingMode mode) @inline
|
||||
{
|
||||
usz n;
|
||||
foreach (c: s)
|
||||
{
|
||||
if (!should_encode(c, mode)) continue;
|
||||
if (c != ' ' || mode != QUERY)
|
||||
{
|
||||
n++;
|
||||
}
|
||||
}
|
||||
return s.len + 2 * n;
|
||||
}
|
||||
|
||||
<*
|
||||
Encode the string s for a given encoding mode.
|
||||
Returned string must be freed.
|
||||
|
||||
@param s "String to encode"
|
||||
@param mode "Url encoding mode"
|
||||
@param [inout] allocator
|
||||
@return "Percent-encoded String"
|
||||
*>
|
||||
fn String encode(String s, UrlEncodingMode mode, Allocator allocator) => @pool(allocator)
|
||||
{
|
||||
usz n = encode_len(s, mode);
|
||||
DString builder = dstring::temp_with_capacity(n);
|
||||
|
||||
foreach(i, c: s)
|
||||
{
|
||||
switch
|
||||
{
|
||||
// encode spaces in queries
|
||||
case c == ' ' && mode == QUERY:
|
||||
builder.append_char('+');
|
||||
|
||||
// add encoded char
|
||||
case should_encode(c, mode):
|
||||
builder.append_char('%');
|
||||
String hex = hex::encode_temp(s[i:1]);
|
||||
builder.append(hex.temp_ascii_to_upper());
|
||||
|
||||
// use char, no encoding needed
|
||||
default:
|
||||
builder.append_char(c);
|
||||
}
|
||||
}
|
||||
|
||||
return builder.copy_str(allocator);
|
||||
}
|
||||
|
||||
<*
|
||||
Encode the string s for a given encoding mode.
|
||||
Returned string must be freed.
|
||||
|
||||
@param s "String to encode"
|
||||
@param mode "Url encoding mode"
|
||||
@return "Percent-encoded String"
|
||||
*>
|
||||
fn String new_encode(String s, UrlEncodingMode mode) => encode(s, mode, allocator::heap());
|
||||
|
||||
<*
|
||||
Encode string s for a given encoding mode, stored on the temp allocator.
|
||||
|
||||
@param s "String to encode"
|
||||
@param mode "Url encoding mode"
|
||||
@return "Percent-encoded String"
|
||||
*>
|
||||
fn String temp_encode(String s, UrlEncodingMode mode) => encode(s, mode, allocator::temp());
|
||||
|
||||
<*
|
||||
Calculate the length of the percent-decoded string.
|
||||
|
||||
@return! UrlDecodingError.INVALID_HEX
|
||||
*>
|
||||
fn usz! decode_len(String s, UrlEncodingMode mode) @inline
|
||||
{
|
||||
usz n;
|
||||
foreach (i, c: s)
|
||||
{
|
||||
if (c != '%') continue;
|
||||
if (i + 2 >= s.len || !s[i+1].is_xdigit() || !s[i+2].is_xdigit())
|
||||
{
|
||||
return UrlDecodingError.INVALID_HEX?;
|
||||
}
|
||||
n++;
|
||||
}
|
||||
return s.len - 2 * n;
|
||||
}
|
||||
|
||||
<*
|
||||
Decode string s for a given encoding mode.
|
||||
Returned string must be freed.
|
||||
|
||||
@param s "String to decode"
|
||||
@param mode "Url encoding mode"
|
||||
@param [inout] allocator
|
||||
@return "Percent-decoded String"
|
||||
*>
|
||||
fn String! decode(String s, UrlEncodingMode mode, Allocator allocator) => @pool(allocator)
|
||||
{
|
||||
usz n = decode_len(s, mode)!;
|
||||
DString builder = dstring::temp_with_capacity(n);
|
||||
|
||||
for (usz i = 0; i < s.len; i++)
|
||||
{
|
||||
switch (s[i])
|
||||
{
|
||||
// decode encoded char
|
||||
case '%':
|
||||
char[] hex = hex::decode_temp(s[i+1:2])!;
|
||||
builder.append(hex);
|
||||
i += 2;
|
||||
|
||||
// decode space when in queries
|
||||
case '+':
|
||||
builder.append_char((mode == QUERY) ? ' ' : '+');
|
||||
|
||||
// use char, no decoding needed
|
||||
default:
|
||||
builder.append_char(s[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return builder.copy_str(allocator);
|
||||
}
|
||||
|
||||
<*
|
||||
Decode string s for a given encoding mode.
|
||||
Returned string must be freed.
|
||||
|
||||
@param s "String to decode"
|
||||
@param mode "Url encoding mode"
|
||||
@return "Percent-decoded String"
|
||||
*>
|
||||
fn String! new_decode(String s, UrlEncodingMode mode) => decode(s, mode, allocator::heap());
|
||||
|
||||
<*
|
||||
Decode string s for a given encoding mode, stored on the temp allocator.
|
||||
|
||||
@param s "String to decode"
|
||||
@param mode "Url encoding mode"
|
||||
@return "Percent-decoded String"
|
||||
*>
|
||||
fn String! temp_decode(String s, UrlEncodingMode mode) => decode(s, mode, allocator::temp());
|
||||
@@ -9,9 +9,10 @@ import std::io::path, libc, std::os;
|
||||
@require name.len > 0
|
||||
@return! SearchResult.MISSING
|
||||
*>
|
||||
fn String! get_var(String name, Allocator allocator = allocator::heap()) => @pool(allocator)
|
||||
fn String! get_var(String name, Allocator allocator = allocator::heap())
|
||||
{
|
||||
|
||||
@pool(allocator)
|
||||
{
|
||||
$switch
|
||||
$case env::LIBC && !env::WIN32:
|
||||
ZString val = libc::getenv(name.zstr_tcopy());
|
||||
@@ -32,6 +33,7 @@ fn String! get_var(String name, Allocator allocator = allocator::heap()) => @poo
|
||||
$default:
|
||||
return "";
|
||||
$endswitch
|
||||
};
|
||||
}
|
||||
|
||||
fn String! get_var_temp(String name)
|
||||
@@ -44,8 +46,10 @@ fn String! get_var_temp(String name)
|
||||
@param [in] value
|
||||
@require name.len > 0
|
||||
*>
|
||||
fn bool set_var(String name, String value, bool overwrite = true) => @pool()
|
||||
fn bool set_var(String name, String value, bool overwrite = true)
|
||||
{
|
||||
@pool()
|
||||
{
|
||||
$switch
|
||||
$case env::WIN32:
|
||||
WString wname = name.to_temp_wstring()!!;
|
||||
@@ -57,10 +61,12 @@ fn bool set_var(String name, String value, bool overwrite = true) => @pool()
|
||||
// https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setenvironmentvariable
|
||||
return (win32::setEnvironmentVariableW(wname, value.to_temp_wstring()) ?? 1) == 0;
|
||||
$case env::LIBC && !env::WIN32:
|
||||
return libc::setenv(name.zstr_tcopy(), value.zstr_tcopy(), (int)overwrite) == 0;
|
||||
return libc::setenv(name.zstr_tcopy(), value.zstr_copy(), (int)overwrite) == 0;
|
||||
$default:
|
||||
return false;
|
||||
$endswitch
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
<*
|
||||
@@ -85,8 +91,10 @@ fn Path! get_config_dir(Allocator allocator = allocator::heap()) @deprecated("us
|
||||
<*
|
||||
Returns the current user's config directory.
|
||||
*>
|
||||
fn Path! new_get_config_dir(Allocator allocator = allocator::heap()) => @pool(allocator)
|
||||
fn Path! new_get_config_dir(Allocator allocator = allocator::heap())
|
||||
{
|
||||
@pool(allocator)
|
||||
{
|
||||
$if env::WIN32:
|
||||
return path::new(get_var_temp("AppData"), allocator);
|
||||
$else
|
||||
@@ -99,6 +107,7 @@ fn Path! new_get_config_dir(Allocator allocator = allocator::heap()) => @pool(al
|
||||
$endif
|
||||
return path::temp_new(s).new_append(DIR, allocator: allocator);
|
||||
$endif
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -106,8 +115,10 @@ fn Path! new_get_config_dir(Allocator allocator = allocator::heap()) => @pool(al
|
||||
@param [in] name
|
||||
@require name.len > 0
|
||||
*>
|
||||
fn bool clear_var(String name) => @pool()
|
||||
fn bool clear_var(String name)
|
||||
{
|
||||
@pool()
|
||||
{
|
||||
$switch
|
||||
$case env::WIN32:
|
||||
WString wname = name.to_temp_wstring()!!;
|
||||
@@ -117,6 +128,7 @@ fn bool clear_var(String name) => @pool()
|
||||
$default:
|
||||
return false;
|
||||
$endswitch
|
||||
};
|
||||
}
|
||||
|
||||
fn String! executable_path(Allocator allocator = allocator::heap()) @deprecated("use new_executable_path()")
|
||||
|
||||
@@ -204,8 +204,7 @@ fn void! backtrace_add_element(BacktraceList *list, void* addr, Allocator alloca
|
||||
return;
|
||||
}
|
||||
|
||||
@pool(allocator)
|
||||
{
|
||||
@pool(allocator) {
|
||||
Linux_Dl_info info;
|
||||
if (dladdr(addr, &info) == 0)
|
||||
{
|
||||
|
||||
@@ -5,12 +5,10 @@ distinct ObjcMethod = void*;
|
||||
distinct ObjcIvar = void*;
|
||||
distinct ObjcSelector = void*;
|
||||
def ObjcId = void*;
|
||||
def SendVoid = fn void*(void*, ObjcSelector);
|
||||
|
||||
fault ObjcFailure
|
||||
{
|
||||
CLASS_NOT_FOUND,
|
||||
UNKNOWN_EVENT
|
||||
CLASS_NOT_FOUND
|
||||
}
|
||||
|
||||
macro ZString ObjcClass.name(ObjcClass cls) => class_getName(cls);
|
||||
@@ -21,9 +19,6 @@ macro ObjcMethod ObjcClass.method(ObjcClass cls, ObjcSelector name) => class_get
|
||||
macro bool ObjcSelector.equals(ObjcSelector a, ObjcSelector b) => a == b;
|
||||
macro bool ObjcClass.equals(ObjcClass a, ObjcClass b) => a == b;
|
||||
|
||||
fn ObjcId alloc(ObjcClass cls) => objc::msg_send(cls, SendVoid, "alloc");
|
||||
fn void release(ObjcId id) => objc::msg_send(id, SendVoid, "release");
|
||||
|
||||
macro ObjcClass! class_by_name(ZString c)
|
||||
{
|
||||
ObjcClass cls = objc::lookUpClass(c);
|
||||
@@ -56,175 +51,3 @@ extern fn ObjcClass class_getSuperclass(ObjcClass cls);
|
||||
extern fn ObjcMethod class_getClassMethod(ObjcClass cls, ObjcSelector name);
|
||||
extern fn bool class_respondsToSelector(ObjcClass cls, ObjcSelector name);
|
||||
extern fn ObjcSelector sel_registerName(ZString str);
|
||||
extern fn bool class_addIvar(ObjcClass cls, ZString name, int size, double alignment, ZString types);
|
||||
extern fn bool class_addMethod(ObjcClass cls, ObjcSelector name, void* imp, ZString types);
|
||||
|
||||
extern fn ObjcIvar getInstanceVariable(ObjcId id, ZString name, void* outValue) @extern("object_getInstanceVariable");
|
||||
extern fn ObjcIvar setInstanceVariable(ObjcId id, ZString name, void* value) @extern("object_setInstanceVariable");
|
||||
extern fn ObjcClass allocateClassPair(ObjcClass cls, ZString name, uint extraBytes) @extern("objc_allocateClassPair");
|
||||
|
||||
enum StatusItemLength : (double val)
|
||||
{
|
||||
VARIABLE = -1.0,
|
||||
SQUARE = -2.0,
|
||||
}
|
||||
|
||||
enum ApplicationActivationPolicy : (int val)
|
||||
{
|
||||
REGULAR = 0,
|
||||
ACCESSORY = 1,
|
||||
PROHIBITED = 2,
|
||||
}
|
||||
|
||||
enum WindowStyleMask : (int val)
|
||||
{
|
||||
BORDERLESS = 0,
|
||||
TITLED = 1 << 0,
|
||||
CLOSABLE = 1 << 1,
|
||||
MINIATURIZABLE = 1 << 2,
|
||||
RESIZABLE = 1 << 3,
|
||||
TEXTURED_BACKGROUND = 1 << 8,
|
||||
UNIFIED_TITLE_AND_TOOLBAR = 1 << 12,
|
||||
FULL_SCREEN = 1 << 14,
|
||||
FULL_SIZE_CONTENT_VIEW = 1 << 15,
|
||||
UTILITY_WINDOW = 1 << 4,
|
||||
DOC_MODAL_WINDOW = 1 << 6,
|
||||
NONACTIVATING_PANEL = 1 << 7,
|
||||
HUD_WINDOW = 1 << 13
|
||||
}
|
||||
|
||||
enum BackingStore : (int val)
|
||||
{
|
||||
RETAINED = 0,
|
||||
NONRETAINED = 1,
|
||||
BUFFERED = 2
|
||||
}
|
||||
|
||||
enum EventType : (long val)
|
||||
{
|
||||
LEFT_MOUSE_DOWN = 1,
|
||||
LEFT_MOUSE_UP = 2,
|
||||
RIGHT_MOUSE_DOWN = 3,
|
||||
RIGHT_MOUSE_UP = 4,
|
||||
MOUSE_MOVED = 5,
|
||||
LEFT_MOUSE_DRAGGED = 6,
|
||||
RIGHT_MOUSE_DRAGGED = 7,
|
||||
MOUSE_ENTERED = 8,
|
||||
MOUSE_EXITED = 9,
|
||||
KEY_DOWN = 10,
|
||||
KEY_UP = 11,
|
||||
FLAGS_CHANGED = 12,
|
||||
APPKIT_DEFINED = 13,
|
||||
SYSTEM_DEFINED = 14,
|
||||
APPLICATION_DEFINED = 15,
|
||||
PERIODIC = 16,
|
||||
CURSOR_UPDATE = 17,
|
||||
SCROLL_WHEEL = 22,
|
||||
TABLET_POINT = 23,
|
||||
TABLET_PROXIMITY = 24,
|
||||
OTHER_MOUSE_DOWN = 25,
|
||||
OTHER_MOUSE_UP = 26,
|
||||
OTHER_MOUSE_DRAGGED = 27,
|
||||
GESTURE = 29,
|
||||
MAGNIFY = 30,
|
||||
SWIPE = 31,
|
||||
ROTATE = 18,
|
||||
BEGIN_GESTURE = 19,
|
||||
END_GESTURE = 20,
|
||||
SMART_MAGNIFY = 32,
|
||||
QUICK_LOOK = 33,
|
||||
PRESSURE = 34,
|
||||
DIRECT_TOUCH = 37,
|
||||
CHANGE_MODE = 38,
|
||||
}
|
||||
|
||||
fn EventType! event_type_from(int val)
|
||||
{
|
||||
switch(val)
|
||||
{
|
||||
case EventType.LEFT_MOUSE_DOWN.val: return LEFT_MOUSE_DOWN;
|
||||
case EventType.LEFT_MOUSE_UP.val: return LEFT_MOUSE_UP;
|
||||
case EventType.RIGHT_MOUSE_DOWN.val: return RIGHT_MOUSE_DOWN;
|
||||
case EventType.RIGHT_MOUSE_UP.val: return RIGHT_MOUSE_UP;
|
||||
case EventType.MOUSE_MOVED.val: return MOUSE_MOVED;
|
||||
case EventType.LEFT_MOUSE_DRAGGED.val: return LEFT_MOUSE_DRAGGED;
|
||||
case EventType.RIGHT_MOUSE_DRAGGED.val: return RIGHT_MOUSE_DRAGGED;
|
||||
case EventType.MOUSE_ENTERED.val: return MOUSE_ENTERED;
|
||||
case EventType.MOUSE_EXITED.val: return MOUSE_EXITED;
|
||||
case EventType.KEY_DOWN.val: return KEY_DOWN;
|
||||
case EventType.KEY_UP.val: return KEY_UP;
|
||||
case EventType.FLAGS_CHANGED.val: return FLAGS_CHANGED;
|
||||
case EventType.APPKIT_DEFINED.val: return APPKIT_DEFINED;
|
||||
case EventType.SYSTEM_DEFINED.val: return SYSTEM_DEFINED;
|
||||
case EventType.APPLICATION_DEFINED.val: return APPLICATION_DEFINED;
|
||||
case EventType.PERIODIC.val: return PERIODIC;
|
||||
case EventType.CURSOR_UPDATE.val: return CURSOR_UPDATE;
|
||||
case EventType.SCROLL_WHEEL.val: return SCROLL_WHEEL;
|
||||
case EventType.TABLET_POINT.val: return TABLET_POINT;
|
||||
case EventType.TABLET_PROXIMITY.val: return TABLET_PROXIMITY;
|
||||
case EventType.OTHER_MOUSE_DOWN.val: return OTHER_MOUSE_DOWN;
|
||||
case EventType.OTHER_MOUSE_UP.val: return OTHER_MOUSE_UP;
|
||||
case EventType.OTHER_MOUSE_DRAGGED.val: return OTHER_MOUSE_DRAGGED;
|
||||
case EventType.GESTURE.val: return GESTURE;
|
||||
case EventType.MAGNIFY.val: return MAGNIFY;
|
||||
case EventType.SWIPE.val: return SWIPE;
|
||||
case EventType.ROTATE.val: return ROTATE;
|
||||
case EventType.BEGIN_GESTURE.val: return BEGIN_GESTURE;
|
||||
case EventType.END_GESTURE.val: return END_GESTURE;
|
||||
case EventType.SMART_MAGNIFY.val: return SMART_MAGNIFY;
|
||||
case EventType.QUICK_LOOK.val: return QUICK_LOOK;
|
||||
case EventType.PRESSURE.val: return PRESSURE;
|
||||
case EventType.DIRECT_TOUCH.val: return DIRECT_TOUCH;
|
||||
case EventType.CHANGE_MODE.val: return CHANGE_MODE;
|
||||
default: return ObjcFailure.UNKNOWN_EVENT?;
|
||||
}
|
||||
}
|
||||
|
||||
enum EventMask : (long val)
|
||||
{
|
||||
LEFT_MOUSE_DOWN = 1 << EventType.LEFT_MOUSE_DOWN.val,
|
||||
LEFT_MOUSE_UP = 1 << EventType.LEFT_MOUSE_UP.val,
|
||||
RIGHT_MOUSE_DOWN = 1 << EventType.RIGHT_MOUSE_DOWN.val,
|
||||
RIGHT_MOUSE_UP = 1 << EventType.RIGHT_MOUSE_UP.val,
|
||||
MOUSE_MOVED = 1 << EventType.MOUSE_MOVED.val,
|
||||
LEFT_MOUSE_DRAGGED = 1 << EventType.LEFT_MOUSE_DRAGGED.val,
|
||||
RIGHT_MOUSE_DRAGGED = 1 << EventType.RIGHT_MOUSE_DRAGGED.val,
|
||||
MOUSE_ENTERED = 1 << EventType.MOUSE_ENTERED.val,
|
||||
MOUSE_EXITED = 1 << EventType.MOUSE_EXITED.val,
|
||||
KEY_DOWN = 1 << EventType.KEY_DOWN.val,
|
||||
KEY_UP = 1 << EventType.KEY_UP.val,
|
||||
FLAGS_CHANGED = 1 << EventType.FLAGS_CHANGED.val,
|
||||
APPKIT_DEFINED = 1 << EventType.APPKIT_DEFINED.val,
|
||||
SYSTEM_DEFINED = 1 << EventType.SYSTEM_DEFINED.val,
|
||||
APPLICATION_DEFINED = 1 << EventType.APPLICATION_DEFINED.val,
|
||||
PERIODIC = 1 << EventType.PERIODIC.val,
|
||||
CURSOR_UPDATE = 1 << EventType.CURSOR_UPDATE.val,
|
||||
SCROLL_WHEEL = 1 << EventType.SCROLL_WHEEL.val,
|
||||
TABLET_POINT = 1 << EventType.TABLET_POINT.val,
|
||||
TABLET_PROXIMITY = 1 << EventType.TABLET_PROXIMITY.val,
|
||||
OTHER_MOUSE_DOWN = 1 << EventType.OTHER_MOUSE_DOWN.val,
|
||||
OTHER_MOUSE_UP = 1 << EventType.OTHER_MOUSE_UP.val,
|
||||
OTHER_MOUSE_DRAGGED = 1 << EventType.OTHER_MOUSE_DRAGGED.val,
|
||||
GESTURE = 1 << EventType.GESTURE.val,
|
||||
MAGNIFY = 1 << EventType.MAGNIFY.val,
|
||||
SWIPE = 1 << EventType.SWIPE.val,
|
||||
ROTATE = 1 << EventType.ROTATE.val,
|
||||
BEGIN_GESTURE = 1 << EventType.BEGIN_GESTURE.val,
|
||||
END_GESTURE = 1 << EventType.END_GESTURE.val,
|
||||
SMART_MAGNIFY = 1L << EventType.SMART_MAGNIFY.val,
|
||||
DIRECT_TOUCH = 1L << EventType.DIRECT_TOUCH.val,
|
||||
ANY = long.max,
|
||||
}
|
||||
|
||||
enum EventModifierFlag : (int val)
|
||||
{
|
||||
CAPS_LOCK = 1 << 16,
|
||||
SHIFT = 1 << 17,
|
||||
CONTROL = 1 << 18,
|
||||
OPTION = 1 << 19,
|
||||
COMMAND = 1 << 20,
|
||||
NUMERIC_PAD = 1 << 21,
|
||||
FUNCTION = 1 << 23,
|
||||
HELP = 1 << 22,
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ struct Posix_dirent
|
||||
char[255+1] name @if(env::FREEBSD || env::OPENBSD);
|
||||
char[511+1] name @if(env::NETBSD);
|
||||
char[1024] name @if(env::DARWIN);
|
||||
char[?] name @if(!env::DARWIN && !env::BSD_FAMILY);
|
||||
char[*] name @if(!env::DARWIN && !env::BSD_FAMILY);
|
||||
}
|
||||
|
||||
extern fn int rmdir(ZString);
|
||||
|
||||
@@ -81,7 +81,6 @@ def Win32_LPVOID = void*;
|
||||
def Win32_LPWORD = Win32_WORD*;
|
||||
def Win32_LPWSTR = Win32_WCHAR*;
|
||||
def Win32_LRESULT = Win32_LONG_PTR;
|
||||
def Win32_NTSTATUS = Win32_LONG;
|
||||
def Win32_PBOOL = Win32_BOOL*;
|
||||
def Win32_PBOOLEAN = Win32_BOOLEAN*;
|
||||
def Win32_PBYTE = Win32_BYTE*;
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
// console
|
||||
|
||||
module std::os::win32 @if(env::WIN32);
|
||||
|
||||
struct Win32_KEY_EVENT_RECORD
|
||||
{
|
||||
Win32_BOOL bKeyDown;
|
||||
Win32_WORD wRepeatCount;
|
||||
Win32_WORD wVirtualKeyCode;
|
||||
Win32_WORD wVirtualScanCode;
|
||||
union uChar
|
||||
{
|
||||
Win32_WCHAR unicodeChar;
|
||||
Win32_CHAR asciiChar;
|
||||
}
|
||||
Win32_DWORD dwControlKeyState;
|
||||
}
|
||||
|
||||
struct Win32_COORD
|
||||
{
|
||||
Win32_SHORT x;
|
||||
Win32_SHORT y;
|
||||
}
|
||||
|
||||
struct Win32_MOUSE_EVENT_RECORD
|
||||
{
|
||||
Win32_COORD dwMousePosition;
|
||||
Win32_DWORD dwButtonState;
|
||||
Win32_DWORD dwControlKeyState;
|
||||
Win32_DWORD dwEventFlags;
|
||||
}
|
||||
|
||||
struct Win32_WINDOW_BUFFER_SIZE_RECORD
|
||||
{
|
||||
Win32_COORD dwSize;
|
||||
}
|
||||
|
||||
struct Win32_MENU_EVENT_RECORD
|
||||
{
|
||||
Win32_UINT dwCommandId;
|
||||
}
|
||||
|
||||
struct Win32_FOCUS_EVENT_RECORD
|
||||
{
|
||||
Win32_BOOL bSetFocus;
|
||||
}
|
||||
|
||||
struct Win32_INPUT_RECORD
|
||||
{
|
||||
Win32_WORD eventType;
|
||||
union event
|
||||
{
|
||||
Win32_KEY_EVENT_RECORD keyEvent;
|
||||
Win32_MOUSE_EVENT_RECORD mouseEvent;
|
||||
Win32_WINDOW_BUFFER_SIZE_RECORD windowBufferSizeEvent;
|
||||
Win32_MENU_EVENT_RECORD menuEvent;
|
||||
Win32_FOCUS_EVENT_RECORD focusEvent;
|
||||
}
|
||||
}
|
||||
|
||||
def Win32_PCOORD = Win32_COORD*;
|
||||
@@ -20,18 +20,6 @@ struct Win32_SIZE
|
||||
Win32_LONG cy;
|
||||
}
|
||||
|
||||
struct Win32_WSABUF
|
||||
{
|
||||
Win32_ULONG len;
|
||||
Win32_CHAR* buf;
|
||||
}
|
||||
|
||||
struct Win32_SOCKADDR
|
||||
{
|
||||
Win32_USHORT sa_family;
|
||||
Win32_CHAR[14]* sa_data;
|
||||
}
|
||||
|
||||
def Win32_PSIZE = Win32_SIZE*;
|
||||
def Win32_NPSIZE = Win32_SIZE*;
|
||||
def Win32_LPSIZE = Win32_SIZE*;
|
||||
@@ -43,9 +31,3 @@ def Win32_LPOINT = Win32_POINT*;
|
||||
def Win32_PRECT = Win32_RECT*;
|
||||
def Win32_NPRECT = Win32_RECT*;
|
||||
def Win32_LPRECT = Win32_RECT*;
|
||||
|
||||
def Win32_PWSABUF = Win32_WSABUF*;
|
||||
def Win32_LPWSABUF = Win32_WSABUF*;
|
||||
|
||||
def Win32_PSOCKADDR = Win32_SOCKADDR*;
|
||||
def Win32_LPSOCKADDR = Win32_SOCKADDR*;
|
||||
@@ -1,31 +0,0 @@
|
||||
module std::os::win32 @if(env::WIN32);
|
||||
|
||||
struct Win32_addrinfo
|
||||
{
|
||||
Win32_INT ai_flags;
|
||||
Win32_INT ai_family;
|
||||
Win32_INT ai_socktype;
|
||||
Win32_INT ai_protocol;
|
||||
Win32_SIZE_T ai_addrlen;
|
||||
Win32_CHAR* ai_canonname;
|
||||
Win32_SOCKADDR* ai_addr;
|
||||
Win32_ADDRINFO* ai_next;
|
||||
}
|
||||
|
||||
def Win32_ADDRINFO = Win32_addrinfo;
|
||||
def Win32_ADDRINFOA = Win32_ADDRINFO;
|
||||
def Win32_PADDRINFOA = Win32_ADDRINFO*;
|
||||
|
||||
struct Win32_addrinfoW {
|
||||
Win32_INT ai_flags;
|
||||
Win32_INT ai_family;
|
||||
Win32_INT ai_socktype;
|
||||
Win32_INT ai_protocol;
|
||||
Win32_SIZE_T ai_addrlen;
|
||||
Win32_PWSTR ai_canonname;
|
||||
Win32_SOCKADDR *ai_addr;
|
||||
Win32_addrinfo *ai_next;
|
||||
}
|
||||
|
||||
def Win32_ADDRINFOW = Win32_addrinfoW;
|
||||
def Win32_PADDRINFOW = Win32_addrinfoW*;
|
||||
@@ -3,7 +3,6 @@ module std::os::win32 @if(env::WIN32);
|
||||
// See https://github.com/wine-mirror/wine/blob/master/include/winsock2.h
|
||||
|
||||
distinct WSAError = int;
|
||||
|
||||
struct Win32_pollfd
|
||||
{
|
||||
Win32_SOCKET fd;
|
||||
@@ -14,99 +13,6 @@ def Win32_WSAPOLLFD = Win32_pollfd;
|
||||
def Win32_PWSAPOLLFD = Win32_WSAPOLLFD*;
|
||||
def Win32_LPWSAPOLLFD = Win32_WSAPOLLFD*;
|
||||
|
||||
struct Win32_InAddr
|
||||
{
|
||||
union
|
||||
{
|
||||
struct s_un_b
|
||||
{
|
||||
Win32_UCHAR s_b1;
|
||||
Win32_UCHAR s_b2;
|
||||
Win32_UCHAR s_b3;
|
||||
Win32_UCHAR s_b4;
|
||||
}
|
||||
struct s_un_w
|
||||
{
|
||||
Win32_USHORT s_w1;
|
||||
Win32_USHORT s_w2;
|
||||
}
|
||||
Win32_ULONG s_addr;
|
||||
}
|
||||
}
|
||||
|
||||
struct Win32_SOCKADDR_IN
|
||||
{
|
||||
Win32_SHORT sin_family;
|
||||
Win32_USHORT sin_port;
|
||||
Win32_InAddr sin_addr;
|
||||
Win32_CHAR[8]* sin_zero;
|
||||
}
|
||||
|
||||
const usz _SS_PAD1SIZE = 6;
|
||||
const usz _SS_PAD2SIZE = 112;
|
||||
|
||||
struct Win32_SOCKADDR_STORAGE
|
||||
{
|
||||
Win32_USHORT ss_family;
|
||||
Win32_CHAR[_SS_PAD1SIZE]* __ss_pad1;
|
||||
Win32_INT64 __ss_align;
|
||||
Win32_CHAR[_SS_PAD2SIZE]* __ss_pad2;
|
||||
}
|
||||
|
||||
def Win32_WSAOVERLAPPED = Win32_OVERLAPPED;
|
||||
def Win32_LPWSAOVERLAPPED = Win32_WSAOVERLAPPED*;
|
||||
|
||||
def Win32_LPWSAOVERLAPPED_COMPLETION_ROUTINE = fn void (
|
||||
Win32_DWORD dwError,
|
||||
Win32_DWORD cbTransferred,
|
||||
Win32_LPWSAOVERLAPPED
|
||||
lpOverlapped,
|
||||
Win32_DWORD dwFlags
|
||||
);
|
||||
|
||||
def Win32_LPFN_WSARECV = fn CInt(
|
||||
Win32_SOCKET socket,
|
||||
Win32_LPWSABUF buffers,
|
||||
Win32_DWORD buffer_count,
|
||||
Win32_LPDWORD bytes,
|
||||
Win32_LPDWORD flags,
|
||||
Win32_LPWSAOVERLAPPED overlapped,
|
||||
Win32_LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine
|
||||
);
|
||||
|
||||
def Win32_LPFN_WSARECVFROM = fn CInt(
|
||||
Win32_SOCKET socket,
|
||||
Win32_LPWSABUF buffers,
|
||||
Win32_DWORD buffer_count,
|
||||
Win32_LPDWORD bytes,
|
||||
Win32_LPDWORD flags,
|
||||
Win32_SOCKADDR* addr,
|
||||
Win32_LPINT addr_len,
|
||||
Win32_LPWSAOVERLAPPED overlapped,
|
||||
Win32_LPWSAOVERLAPPED_COMPLETION_ROUTINE completion_routine
|
||||
);
|
||||
|
||||
def Win32_LPFn_CONNECTEX = fn bool(
|
||||
Win32_SOCKET,
|
||||
Win32_SOCKADDR*,
|
||||
Win32_INT,
|
||||
Win32_PVOID,
|
||||
Win32_DWORD,
|
||||
Win32_LPDWORD,
|
||||
void*
|
||||
);
|
||||
|
||||
def Win32_LPFn_ACCEPTEX = fn bool(
|
||||
Win32_SOCKET,
|
||||
Win32_SOCKET,
|
||||
Win32_PVOID,
|
||||
Win32_DWORD,
|
||||
Win32_DWORD,
|
||||
Win32_DWORD,
|
||||
Win32_LPDWORD,
|
||||
void*
|
||||
);
|
||||
|
||||
const Win32_SHORT POLLERR = 0x0001;
|
||||
const Win32_SHORT POLLHUP = 0x0002;
|
||||
const Win32_SHORT POLLNVAL = 0x0004;
|
||||
|
||||
@@ -10,7 +10,7 @@ in [0, array.len) where x would be inserted or cmp(i) is true and cmp(j) is true
|
||||
macro usz binarysearch(list, x, cmp = EMPTY_MACRO_SLOT, context = EMPTY_MACRO_SLOT) @builtin
|
||||
{
|
||||
usz i;
|
||||
usz len = len_from_list(list);
|
||||
usz len = @len_from_list(list);
|
||||
var $no_cmp = @is_empty_macro_slot(cmp);
|
||||
var $has_context = @is_valid_macro_slot(context);
|
||||
for (usz j = len; i < j;)
|
||||
|
||||
@@ -10,7 +10,7 @@ Sort list using the counting sort algorithm.
|
||||
*>
|
||||
macro countingsort(list, key_fn = EMPTY_MACRO_SLOT) @builtin
|
||||
{
|
||||
usz len = sort::len_from_list(list);
|
||||
usz len = sort::@len_from_list(list);
|
||||
cs::csort(<$typeof(list), $typeof(key_fn)>)(list, 0, len, key_fn, ~((uint)0));
|
||||
}
|
||||
|
||||
|
||||
@@ -6,15 +6,10 @@ Sort list using the quick sort algorithm.
|
||||
@require @is_sortable(list) "The list must be indexable and support .len or .len()"
|
||||
@require @is_valid_cmp_fn(cmp, list, context) "Expected a comparison function which compares values"
|
||||
*>
|
||||
macro insertionsort(list, cmp = EMPTY_MACRO_SLOT, context = EMPTY_MACRO_SLOT) @builtin @safemacro
|
||||
macro insertionsort(list, cmp = EMPTY_MACRO_SLOT, context = EMPTY_MACRO_SLOT) @builtin
|
||||
{
|
||||
$if @typekind(list) == POINTER &&& (@typekind(*list) == ARRAY || @typekind(*list) == VECTOR):
|
||||
$typeof((*list)[0])[] list2 = list;
|
||||
is::isort(<$typeof(list2), $typeof(cmp), $typeof(context)>)(list2, 0, list.len, cmp, context);
|
||||
$else
|
||||
usz len = sort::len_from_list(list);
|
||||
is::isort(<$typeof(list), $typeof(cmp), $typeof(context)>)(list, 0, (isz)len, cmp, context);
|
||||
$endif
|
||||
usz len = sort::@len_from_list(list);
|
||||
is::isort(<$typeof(list), $typeof(cmp), $typeof(context)>)(list, 0, (isz)len, cmp, context);
|
||||
}
|
||||
|
||||
module std::sort::is(<Type, CmpFn, Context>);
|
||||
|
||||
@@ -9,13 +9,8 @@ Sort list using the quick sort algorithm.
|
||||
*>
|
||||
macro quicksort(list, cmp = EMPTY_MACRO_SLOT, context = EMPTY_MACRO_SLOT) @builtin
|
||||
{
|
||||
$if @typekind(list) == POINTER &&& (@typekind(*list) == ARRAY || @typekind(*list) == VECTOR):
|
||||
$typeof((*list)[0])[] list2 = list;
|
||||
qs::qsort(<$typeof(list2), $typeof(cmp), $typeof(context)>)(list2, 0, (isz)list.len - 1, cmp, context);
|
||||
$else
|
||||
usz len = sort::len_from_list(list);
|
||||
qs::qsort(<$typeof(list), $typeof(cmp), $typeof(context)>)(list, 0, (isz)len - 1, cmp, context);
|
||||
$endif
|
||||
usz len = sort::@len_from_list(list);
|
||||
qs::qsort(<$typeof(list), $typeof(cmp), $typeof(context)>)(list, 0, (isz)len - 1, cmp, context);
|
||||
}
|
||||
|
||||
<*
|
||||
@@ -29,7 +24,7 @@ list will be partially sorted.
|
||||
*>
|
||||
macro quickselect(list, isz k, cmp = EMPTY_MACRO_SLOT, context = EMPTY_MACRO_SLOT) @builtin
|
||||
{
|
||||
usz len = sort::len_from_list(list);
|
||||
usz len = sort::@len_from_list(list);
|
||||
return qs::qselect(<$typeof(list), $typeof(cmp), $typeof(context)>)(list, 0, (isz)len - 1, k, cmp, context);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
module std::sort;
|
||||
|
||||
macro usz @len_from_list(&list) @deprecated
|
||||
{
|
||||
return len_from_list(*list);
|
||||
}
|
||||
|
||||
macro usz len_from_list(list)
|
||||
macro usz @len_from_list(&list)
|
||||
{
|
||||
$if $defined(list.len()):
|
||||
return list.len();
|
||||
@@ -21,8 +16,6 @@ macro bool @is_sortable(#list)
|
||||
return false;
|
||||
$case !$defined(#list.len):
|
||||
return false;
|
||||
$case @typekind(#list) == VECTOR || @typekind(#list) == ARRAY:
|
||||
return false;
|
||||
$case $defined(&#list[0]) &&& !types::is_same($typeof(&#list[0]), $typeof(#list[0])*):
|
||||
return false;
|
||||
$default:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user