mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Compare commits
1 Commits
0.4stripun
...
v0.5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3bcc56e6fe |
164
.github/workflows/main.yml
vendored
164
.github/workflows/main.yml
vendored
@@ -7,7 +7,7 @@ on:
|
||||
branches: [ master ]
|
||||
|
||||
env:
|
||||
LLVM_RELEASE_VERSION: 16
|
||||
LLVM_RELEASE_VERSION: 15
|
||||
|
||||
jobs:
|
||||
|
||||
@@ -34,7 +34,6 @@ jobs:
|
||||
run: |
|
||||
cd resources
|
||||
..\build\${{ matrix.build_type }}\c3c.exe compile-run examples\hello_world_many.c3
|
||||
..\build\${{ matrix.build_type }}\c3c.exe compile-run examples\time.c3
|
||||
..\build\${{ matrix.build_type }}\c3c.exe compile-run examples\fannkuch-redux.c3
|
||||
..\build\${{ matrix.build_type }}\c3c.exe compile-run examples\contextfree\boolerr.c3
|
||||
..\build\${{ matrix.build_type }}\c3c.exe compile-run examples\load_world.c3
|
||||
@@ -102,7 +101,6 @@ jobs:
|
||||
run: |
|
||||
cd resources
|
||||
../build/c3c compile-run examples/hello_world_many.c3
|
||||
../build/c3c compile-run examples/time.c3
|
||||
../build/c3c compile-run examples/fannkuch-redux.c3
|
||||
../build/c3c compile-run examples/contextfree/boolerr.c3
|
||||
../build/c3c compile-run examples/load_world.c3
|
||||
@@ -129,7 +127,7 @@ jobs:
|
||||
|
||||
build-msys2-clang:
|
||||
runs-on: windows-latest
|
||||
#if: ${{ false }}
|
||||
if: ${{ false }}
|
||||
strategy:
|
||||
# Don't abort runners if a single one fails
|
||||
fail-fast: false
|
||||
@@ -157,7 +155,6 @@ jobs:
|
||||
run: |
|
||||
cd resources
|
||||
../build/c3c compile-run examples/hello_world_many.c3
|
||||
../build/c3c compile-run examples/time.c3
|
||||
../build/c3c compile-run examples/fannkuch-redux.c3
|
||||
../build/c3c compile-run examples/contextfree/boolerr.c3
|
||||
../build/c3c compile-run examples/load_world.c3
|
||||
@@ -184,7 +181,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
build_type: [Release, Debug]
|
||||
llvm_version: [16]
|
||||
llvm_version: [15, 16, 17]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@@ -221,28 +218,7 @@ jobs:
|
||||
- name: Compile and run some examples
|
||||
run: |
|
||||
cd resources
|
||||
../build/c3c compile examples/base64.c3
|
||||
../build/c3c compile examples/binarydigits.c3
|
||||
../build/c3c compile examples/brainfk.c3
|
||||
../build/c3c compile examples/factorial_macro.c3
|
||||
../build/c3c compile examples/fasta.c3
|
||||
../build/c3c compile examples/gameoflife.c3
|
||||
../build/c3c compile examples/hash.c3
|
||||
../build/c3c compile examples/levenshtein.c3
|
||||
../build/c3c compile examples/load_world.c3
|
||||
../build/c3c compile examples/map.c3
|
||||
../build/c3c compile examples/mandelbrot.c3
|
||||
../build/c3c compile examples/plus_minus.c3
|
||||
../build/c3c compile examples/nbodies.c3
|
||||
../build/c3c compile examples/spectralnorm.c3
|
||||
../build/c3c compile examples/swap.c3
|
||||
../build/c3c compile examples/contextfree/boolerr.c3
|
||||
../build/c3c compile examples/contextfree/dynscope.c3
|
||||
../build/c3c compile examples/contextfree/guess_number.c3
|
||||
../build/c3c compile examples/contextfree/multi.c3
|
||||
../build/c3c compile examples/contextfree/cleanup.c3
|
||||
../build/c3c compile-run examples/hello_world_many.c3
|
||||
../build/c3c compile-run examples/time.c3
|
||||
../build/c3c compile-run examples/fannkuch-redux.c3
|
||||
../build/c3c compile-run examples/contextfree/boolerr.c3
|
||||
../build/c3c compile-run examples/load_world.c3
|
||||
@@ -268,7 +244,7 @@ jobs:
|
||||
python3 src/tester.py ../build/c3c test_suite/
|
||||
|
||||
- name: bundle_output
|
||||
if: matrix.llvm_version == 16
|
||||
if: matrix.llvm_version == env.LLVM_RELEASE_VERSION
|
||||
run: |
|
||||
mkdir linux
|
||||
cp -r lib linux
|
||||
@@ -277,117 +253,12 @@ jobs:
|
||||
tar czf c3-linux-${{matrix.build_type}}.tar.gz linux
|
||||
|
||||
- name: upload artifacts
|
||||
if: matrix.llvm_version == 16
|
||||
if: matrix.llvm_version == env.LLVM_RELEASE_VERSION
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: c3-linux-${{matrix.build_type}}
|
||||
path: c3-linux-${{matrix.build_type}}.tar.gz
|
||||
|
||||
build-linux-ubuntu20:
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
# Don't abort runners if a single one fails
|
||||
fail-fast: false
|
||||
matrix:
|
||||
build_type: [Release, Debug]
|
||||
llvm_version: [16]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install common deps
|
||||
run: |
|
||||
sudo apt-get install zlib1g zlib1g-dev python3 ninja-build curl
|
||||
|
||||
- name: Install Clang ${{matrix.llvm_version}}
|
||||
run: |
|
||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
||||
if [[ "${{matrix.llvm_version}}" < 17 ]]; then
|
||||
sudo add-apt-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-${{matrix.llvm_version}} main"
|
||||
else
|
||||
sudo add-apt-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal main"
|
||||
fi
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y clang-${{matrix.llvm_version}} llvm-${{matrix.llvm_version}} llvm-${{matrix.llvm_version}}-dev lld-${{matrix.llvm_version}} liblld-${{matrix.llvm_version}}-dev
|
||||
sudo apt-get install -y libmlir-${{matrix.llvm_version}} libmlir-${{matrix.llvm_version}}-dev mlir-${{matrix.llvm_version}}-tools
|
||||
sudo apt-get install -y libpolly-${{matrix.llvm_version}}-dev
|
||||
- name: CMake
|
||||
run: |
|
||||
cmake -B build \
|
||||
-G Ninja \
|
||||
-DCMAKE_BUILD_TYPE=${{matrix.build_type}} \
|
||||
-DCMAKE_C_COMPILER=clang-${{matrix.llvm_version}} \
|
||||
-DCMAKE_CXX_COMPILER=clang++-${{matrix.llvm_version}} \
|
||||
-DCMAKE_LINKER=lld-link-${{matrix.llvm_version}} \
|
||||
-DCMAKE_OBJCOPY=llvm-objcopy-${{matrix.llvm_version}} \
|
||||
-DCMAKE_STRIP=llvm-strip-${{matrix.llvm_version}} \
|
||||
-DCMAKE_DLLTOOL=llvm-dlltool-${{matrix.llvm_version}} \
|
||||
-DC3_LLVM_VERSION=${{matrix.llvm_version}}
|
||||
cmake --build build
|
||||
|
||||
- name: Compile and run some examples
|
||||
run: |
|
||||
cd resources
|
||||
../build/c3c compile examples/base64.c3
|
||||
../build/c3c compile examples/binarydigits.c3
|
||||
../build/c3c compile examples/brainfk.c3
|
||||
../build/c3c compile examples/factorial_macro.c3
|
||||
../build/c3c compile examples/fasta.c3
|
||||
../build/c3c compile examples/gameoflife.c3
|
||||
../build/c3c compile examples/hash.c3
|
||||
../build/c3c compile examples/levenshtein.c3
|
||||
../build/c3c compile examples/load_world.c3
|
||||
../build/c3c compile examples/map.c3
|
||||
../build/c3c compile examples/mandelbrot.c3
|
||||
../build/c3c compile examples/plus_minus.c3
|
||||
../build/c3c compile examples/nbodies.c3
|
||||
../build/c3c compile examples/spectralnorm.c3
|
||||
../build/c3c compile examples/swap.c3
|
||||
../build/c3c compile examples/contextfree/boolerr.c3
|
||||
../build/c3c compile examples/contextfree/dynscope.c3
|
||||
../build/c3c compile examples/contextfree/guess_number.c3
|
||||
../build/c3c compile examples/contextfree/multi.c3
|
||||
../build/c3c compile examples/contextfree/cleanup.c3
|
||||
../build/c3c compile-run examples/hello_world_many.c3
|
||||
../build/c3c compile-run examples/time.c3
|
||||
../build/c3c compile-run examples/fannkuch-redux.c3
|
||||
../build/c3c compile-run examples/contextfree/boolerr.c3
|
||||
../build/c3c compile-run examples/load_world.c3
|
||||
|
||||
- name: Compile run unit tests
|
||||
run: |
|
||||
cd test
|
||||
../build/c3c compile-test unit -g1 --safe
|
||||
|
||||
- name: Build testproject
|
||||
run: |
|
||||
cd resources/testproject
|
||||
../../build/c3c run --debug-log
|
||||
|
||||
- name: Build testproject direct linker
|
||||
run: |
|
||||
cd resources/testproject
|
||||
../../build/c3c run --debug-log --forcelinker
|
||||
|
||||
- name: run compiler tests
|
||||
run: |
|
||||
cd test
|
||||
python3 src/tester.py ../build/c3c test_suite/
|
||||
|
||||
- name: bundle_output
|
||||
if: matrix.llvm_version == 16
|
||||
run: |
|
||||
mkdir linux
|
||||
cp -r lib linux
|
||||
cp msvc_build_libraries.py linux
|
||||
cp build/c3c linux
|
||||
tar czf c3-ubuntu-20-${{matrix.build_type}}.tar.gz linux
|
||||
|
||||
- name: upload artifacts
|
||||
if: matrix.llvm_version == 16
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: c3-ubuntu-20-${{matrix.build_type}}
|
||||
path: c3-ubuntu-20-${{matrix.build_type}}.tar.gz
|
||||
|
||||
build-mac:
|
||||
runs-on: macos-latest
|
||||
@@ -396,11 +267,12 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
build_type: [Release, Debug]
|
||||
llvm_version: [15, 16]
|
||||
llvm_version: [15]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Download LLVM
|
||||
run: |
|
||||
brew update
|
||||
brew install llvm@${{ matrix.llvm_version }} ninja curl
|
||||
echo "/usr/local/opt/llvm@${{ matrix.llvm_version }}/bin" >> $GITHUB_PATH
|
||||
TMP_PATH=$(xcrun --show-sdk-path)/user/include
|
||||
@@ -419,7 +291,6 @@ jobs:
|
||||
run: |
|
||||
cd resources
|
||||
../build/c3c compile-run examples/hello_world_many.c3
|
||||
../build/c3c compile-run examples/time.c3
|
||||
../build/c3c compile-run examples/fannkuch-redux.c3
|
||||
../build/c3c compile-run examples/contextfree/boolerr.c3
|
||||
../build/c3c compile-run examples/load_world.c3
|
||||
@@ -555,27 +426,6 @@ jobs:
|
||||
asset_name: c3-linux-debug.tar.gz
|
||||
asset_content_type: application/gzip
|
||||
|
||||
- name: upload ubuntu 20
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
|
||||
asset_path: c3-ubuntu-20-Release/c3-ubuntu-20-Release.tar.gz
|
||||
asset_name: c3-ubuntu-20.tar.gz
|
||||
asset_content_type: application/gzip
|
||||
|
||||
- name: upload ubuntu 20 debug
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
asset_path: c3-ubuntu-20-Debug/c3-ubuntu-20-Debug.tar.gz
|
||||
asset_name: c3-ubuntu-20-debug.tar.gz
|
||||
asset_content_type: application/gzip
|
||||
|
||||
- name: upload macos
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
|
||||
@@ -83,15 +83,15 @@ endif()
|
||||
|
||||
if(CMAKE_C_COMPILER_ID STREQUAL "MSVC")
|
||||
if (C3_LLVM_VERSION STREQUAL "auto")
|
||||
set(C3_LLVM_VERSION "16")
|
||||
set(C3_LLVM_VERSION "15")
|
||||
endif()
|
||||
FetchContent_Declare(
|
||||
LLVM_Windows
|
||||
URL https://github.com/c3lang/win-llvm/releases/download/llvm_16_0_2/llvm-16.0.2-windows-amd64-msvc17-libcmt.7z
|
||||
URL https://github.com/c3lang/win-llvm/releases/download/llvm_15_0_6/llvm-15.0.6-windows-amd64-msvc17-libcmt.7z
|
||||
)
|
||||
FetchContent_Declare(
|
||||
LLVM_Windows_debug
|
||||
URL https://github.com/c3lang/win-llvm/releases/download/llvm_16_0_2/llvm-16.0.2-windows-amd64-msvc17-libcmt-dbg.7z
|
||||
URL https://github.com/c3lang/win-llvm/releases/download/llvm_15_0_6/llvm-15.0.6-windows-amd64-msvc17-libcmt-dbg.7z
|
||||
)
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
message("Loading Windows LLVM debug libraries, this may take a while...")
|
||||
@@ -171,7 +171,12 @@ if (${LLVM_PACKAGE_VERSION} VERSION_GREATER_EQUAL 16)
|
||||
${LLD_WASM}
|
||||
${LLD_MINGW}
|
||||
${LLD_ELF}
|
||||
${LLD_DRIVER}
|
||||
${LLD_READER_WRITER}
|
||||
${LLD_LOONG}
|
||||
${LLD_MACHO}
|
||||
${LLD_YAML}
|
||||
${LLD_CORE}
|
||||
)
|
||||
else()
|
||||
set(lld_libs
|
||||
@@ -180,7 +185,11 @@ else()
|
||||
${LLD_WASM}
|
||||
${LLD_MINGW}
|
||||
${LLD_ELF}
|
||||
${LLD_DRIVER}
|
||||
${LLD_READER_WRITER}
|
||||
${LLD_MACHO}
|
||||
${LLD_YAML}
|
||||
${LLD_CORE}
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
15
README.md
15
README.md
@@ -54,7 +54,6 @@ fn void Stack.push(Stack* this, Type element)
|
||||
if (this.capacity == this.size)
|
||||
{
|
||||
this.capacity *= 2;
|
||||
if (this.capacity < 16) this.capacity = 16;
|
||||
this.elems = mem::realloc(this.elems, Type.sizeof * this.capacity);
|
||||
}
|
||||
this.elems[this.size++] = element;
|
||||
@@ -79,9 +78,9 @@ import stack;
|
||||
|
||||
// Define our new types, the first will implicitly create
|
||||
// a complete copy of the entire Stack module with "Type" set to "int"
|
||||
def IntStack = Stack<int>;
|
||||
define IntStack = Stack<int>;
|
||||
// The second creates another copy with "Type" set to "double"
|
||||
def DoubleStack = Stack<double>;
|
||||
define DoubleStack = Stack<double>;
|
||||
|
||||
// If we had added "define IntStack2 = Stack<int>"
|
||||
// no additional copy would have been made (since we already
|
||||
@@ -92,7 +91,7 @@ def DoubleStack = Stack<double>;
|
||||
// here is an example of importing libc's printf:
|
||||
extern fn int printf(char* format, ...);
|
||||
|
||||
fn void main()
|
||||
fn void test()
|
||||
{
|
||||
IntStack stack;
|
||||
// Note that C3 uses zero initialization by default
|
||||
@@ -112,12 +111,12 @@ fn void main()
|
||||
dstack.push(2.3);
|
||||
dstack.push(3.141);
|
||||
dstack.push(1.1235);
|
||||
// Prints pop: 1.123500
|
||||
// Prints pop: 1.1235
|
||||
printf("pop: %f\n", dstack.pop());
|
||||
}
|
||||
```
|
||||
|
||||
### In what ways does C3 differ from C?
|
||||
### In what ways do C3 differ from C?
|
||||
|
||||
- No mandatory header files
|
||||
- New semantic macro system
|
||||
@@ -139,7 +138,7 @@ fn void main()
|
||||
|
||||
The current version of the compiler is alpha release 0.4.
|
||||
|
||||
Design work on C3 is complete aside from fleshing out details, such as
|
||||
Design work on C3 complete aside from fleshing out details, such as
|
||||
inline asm. As the standard library work progresses, changes and improvements
|
||||
to the language will happen continuously.
|
||||
Follow the issues [here](https://github.com/c3lang/c3c/issues).
|
||||
@@ -312,4 +311,4 @@ Editor plugins can be found at https://github.com/c3lang/editor-plugins.
|
||||
2. Make sure that the test functions have the `@test` attribute.
|
||||
3. Run tests and see that they pass. (Recommended settings: `c3c compile-test --safe -g1 -O0 test/unit`.
|
||||
- in this example `test/unit/` is the relative path to the test directory, so adjust as required)
|
||||
4. Make a pull request for the new tests.
|
||||
4. Make a pull request for the new tests.
|
||||
@@ -8,35 +8,32 @@
|
||||
module std::collections::enumset<Enum>;
|
||||
|
||||
|
||||
const IS_CHAR_ARRAY = Enum.elements > 128;
|
||||
|
||||
$switch
|
||||
|
||||
$case (Enum.elements > 128):
|
||||
def EnumSetType @private = char[(Enum.elements + 7) / 8];
|
||||
|
||||
typedef EnumSetType @private = char[(Enum.elements + 7) / 8];
|
||||
const IS_CHAR_ARRAY = true;
|
||||
$case (Enum.elements > 64):
|
||||
def EnumSetType @private = uint128;
|
||||
|
||||
typedef EnumSetType @private = uint128;
|
||||
const IS_CHAR_ARRAY = false;
|
||||
$case (Enum.elements > 32 || $$C_INT_SIZE > 32):
|
||||
def EnumSetType @private = ulong;
|
||||
|
||||
typedef EnumSetType @private = ulong;
|
||||
const IS_CHAR_ARRAY = false;
|
||||
$case (Enum.elements > 16 || $$C_INT_SIZE > 16):
|
||||
def EnumSetType @private = uint;
|
||||
|
||||
typedef EnumSetType @private = uint;
|
||||
const IS_CHAR_ARRAY = false;
|
||||
$case (Enum.elements > 8 || $$C_INT_SIZE > 8):
|
||||
def EnumSetType @private = ushort;
|
||||
|
||||
typedef EnumSetType @private = ushort;
|
||||
const IS_CHAR_ARRAY = false;
|
||||
$default:
|
||||
def EnumSetType @private = char;
|
||||
|
||||
typedef EnumSetType @private = char;
|
||||
const IS_CHAR_ARRAY = false;
|
||||
$endswitch
|
||||
|
||||
def EnumSet = distinct EnumSetType;
|
||||
typedef EnumSet = distinct EnumSetType;
|
||||
|
||||
fn void EnumSet.add(EnumSet* this, Enum v)
|
||||
{
|
||||
$if IS_CHAR_ARRAY:
|
||||
$if (IS_CHAR_ARRAY)
|
||||
(*this)[v / 8] |= (char)(1u << (v % 8));
|
||||
$else
|
||||
*this = (EnumSet)((EnumSetType)*this | 1u << (EnumSetType)v);
|
||||
@@ -45,7 +42,7 @@ $endif
|
||||
|
||||
fn void EnumSet.clear(EnumSet* this)
|
||||
{
|
||||
$if IS_CHAR_ARRAY:
|
||||
$if (IS_CHAR_ARRAY)
|
||||
*this = {};
|
||||
$else
|
||||
*this = 0;
|
||||
@@ -54,7 +51,7 @@ $endif
|
||||
|
||||
fn bool EnumSet.remove(EnumSet* this, Enum v)
|
||||
{
|
||||
$if IS_CHAR_ARRAY:
|
||||
$if (IS_CHAR_ARRAY)
|
||||
if (!this.has(v) @inline) return false;
|
||||
(*this)[v / 8] &= (char)~(1 << (v % 8));
|
||||
return true;
|
||||
@@ -68,7 +65,7 @@ $endif
|
||||
|
||||
fn bool EnumSet.has(EnumSet* this, Enum v)
|
||||
{
|
||||
$if IS_CHAR_ARRAY:
|
||||
$if (IS_CHAR_ARRAY)
|
||||
return (bool)(((*this)[v / 8] << (v % 8)) & 0x01);
|
||||
$else
|
||||
return ((EnumSetType)*this & (1u << (EnumSetType)v)) != 0;
|
||||
@@ -77,7 +74,7 @@ $endif
|
||||
|
||||
fn void EnumSet.add_all(EnumSet* this, EnumSet s)
|
||||
{
|
||||
$if IS_CHAR_ARRAY:
|
||||
$if (IS_CHAR_ARRAY)
|
||||
foreach (i, c : s) (*this)[i] |= c;
|
||||
$else
|
||||
*this = (EnumSet)((EnumSetType)*this | (EnumSetType)s);
|
||||
@@ -86,7 +83,7 @@ $endif
|
||||
|
||||
fn void EnumSet.retain_all(EnumSet* this, EnumSet s)
|
||||
{
|
||||
$if IS_CHAR_ARRAY:
|
||||
$if (IS_CHAR_ARRAY)
|
||||
foreach (i, c : s) (*this)[i] &= c;
|
||||
$else
|
||||
*this = (EnumSet)((EnumSetType)*this & (EnumSetType)s);
|
||||
@@ -95,7 +92,7 @@ $endif
|
||||
|
||||
fn void EnumSet.remove_all(EnumSet* this, EnumSet s)
|
||||
{
|
||||
$if IS_CHAR_ARRAY:
|
||||
$if (IS_CHAR_ARRAY)
|
||||
foreach (i, c : s) (*this)[i] &= ~c;
|
||||
$else
|
||||
*this = (EnumSet)((EnumSetType)*this & ~(EnumSetType)s);
|
||||
@@ -104,7 +101,7 @@ $endif
|
||||
|
||||
fn EnumSet EnumSet.and_of(EnumSet* this, EnumSet s)
|
||||
{
|
||||
$if IS_CHAR_ARRAY:
|
||||
$if (IS_CHAR_ARRAY)
|
||||
EnumSet copy = *this;
|
||||
copy.retain_all(s);
|
||||
return copy;
|
||||
@@ -115,7 +112,7 @@ $endif
|
||||
|
||||
fn EnumSet EnumSet.or_of(EnumSet* this, EnumSet s)
|
||||
{
|
||||
$if IS_CHAR_ARRAY:
|
||||
$if (IS_CHAR_ARRAY)
|
||||
EnumSet copy = *this;
|
||||
copy.add_all(s);
|
||||
return copy;
|
||||
@@ -127,7 +124,7 @@ $endif
|
||||
|
||||
fn EnumSet EnumSet.diff_of(EnumSet* this, EnumSet s)
|
||||
{
|
||||
$if IS_CHAR_ARRAY:
|
||||
$if (IS_CHAR_ARRAY)
|
||||
EnumSet copy = *this;
|
||||
copy.remove_all(s);
|
||||
return copy;
|
||||
@@ -138,7 +135,7 @@ $endif
|
||||
|
||||
fn EnumSet EnumSet.xor_of(EnumSet* this, EnumSet s)
|
||||
{
|
||||
$if IS_CHAR_ARRAY:
|
||||
$if (IS_CHAR_ARRAY)
|
||||
EnumSet copy = *this;
|
||||
foreach (i, c : s) copy[i] ^= c;
|
||||
return copy;
|
||||
|
||||
@@ -87,13 +87,13 @@ fn Type! peek_last(LinkedList* list) => list.last() @inline;
|
||||
|
||||
fn Type! LinkedList.first(LinkedList *list)
|
||||
{
|
||||
if (!list._first) return IteratorResult.NO_MORE_ELEMENT?;
|
||||
if (!list._first) return IteratorResult.NO_MORE_ELEMENT!;
|
||||
return list._first.value;
|
||||
}
|
||||
|
||||
fn Type! LinkedList.last(LinkedList* list)
|
||||
{
|
||||
if (!list._last) return IteratorResult.NO_MORE_ELEMENT?;
|
||||
if (!list._last) return IteratorResult.NO_MORE_ELEMENT!;
|
||||
return list._last.value;
|
||||
}
|
||||
|
||||
@@ -240,7 +240,7 @@ fn bool LinkedList.remove_last_value(LinkedList* list, Type t)
|
||||
**/
|
||||
fn Type! LinkedList.pop(LinkedList* list)
|
||||
{
|
||||
if (!list._first) return IteratorResult.NO_MORE_ELEMENT?;
|
||||
if (!list._first) return IteratorResult.NO_MORE_ELEMENT!;
|
||||
defer list.unlink_first();
|
||||
return list._first.value;
|
||||
}
|
||||
@@ -250,7 +250,7 @@ fn Type! LinkedList.pop(LinkedList* list)
|
||||
**/
|
||||
fn void! LinkedList.remove_last(LinkedList* list)
|
||||
{
|
||||
if (!list._first) return IteratorResult.NO_MORE_ELEMENT?;
|
||||
if (!list._first) return IteratorResult.NO_MORE_ELEMENT!;
|
||||
list.unlink_last();
|
||||
}
|
||||
|
||||
@@ -259,7 +259,7 @@ fn void! LinkedList.remove_last(LinkedList* list)
|
||||
**/
|
||||
fn void! LinkedList.remove_first(LinkedList* list)
|
||||
{
|
||||
if (!list._first) return IteratorResult.NO_MORE_ELEMENT?;
|
||||
if (!list._first) return IteratorResult.NO_MORE_ELEMENT!;
|
||||
list.unlink_first();
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
module std::collections::list<Type>;
|
||||
import std::math;
|
||||
|
||||
def ElementPredicate = fn bool(Type *type);
|
||||
|
||||
struct List
|
||||
{
|
||||
usz size;
|
||||
@@ -81,56 +79,6 @@ fn void List.remove_at(List* list, usz index)
|
||||
list.size--;
|
||||
}
|
||||
|
||||
fn void List.add_all(List* list, List* other_list)
|
||||
{
|
||||
if (!other_list.size) return;
|
||||
list.reserve(other_list.size);
|
||||
foreach (&value : other_list)
|
||||
{
|
||||
list.entries[list.size++] = *value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn Type[] List.to_array(List* list, Allocator* using = mem::heap())
|
||||
{
|
||||
if (!list.size) return Type[] {};
|
||||
Type[] result = malloc(Type, list.size, .using = using);
|
||||
result[..] = list.entries[:list.size];
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the elements in a list.
|
||||
*
|
||||
* @param [&inout] list "The list to reverse"
|
||||
**/
|
||||
fn void List.reverse(List* list)
|
||||
{
|
||||
if (list.size < 2) return;
|
||||
usz half = list.size / 2U;
|
||||
usz end = list.size - 1;
|
||||
for (usz i = 0; i < half; i++)
|
||||
{
|
||||
@swap(list.entries[i], list.entries[end - i]);
|
||||
}
|
||||
}
|
||||
|
||||
fn Type[] List.array_view(List* list)
|
||||
{
|
||||
return list.entries[:list.size];
|
||||
}
|
||||
|
||||
fn void List.add_array(List* list, Type[] array)
|
||||
{
|
||||
if (!array.len) return;
|
||||
list.reserve(array.len);
|
||||
foreach (&value : array)
|
||||
{
|
||||
list.entries[list.size++] = *value;
|
||||
}
|
||||
}
|
||||
|
||||
fn void List.push_front(List* list, Type type) @inline
|
||||
{
|
||||
list.insert_at(0, type);
|
||||
@@ -204,47 +152,6 @@ fn void List.swap(List* list, usz i, usz j)
|
||||
@swap(list.entries[i], list.entries[j]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [&inout] list "The list to remove elements from"
|
||||
* @param filter "The function to determine if it should be removed or not"
|
||||
* @return "the number of deleted elements"
|
||||
**/
|
||||
fn usz List.remove_if(List* list, ElementPredicate filter)
|
||||
{
|
||||
usz size = list.size;
|
||||
for (usz i = size; i > 0; i--)
|
||||
{
|
||||
if (filter(&list.entries[i - 1])) continue;
|
||||
for (usz j = i; j < size; j++)
|
||||
{
|
||||
list.entries[j - 1] = list.entries[j];
|
||||
}
|
||||
list.size--;
|
||||
}
|
||||
return size - list.size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [&inout] list "The list to remove elements from"
|
||||
* @param selection "The function to determine if it should be kept or not"
|
||||
* @return "the number of deleted elements"
|
||||
**/
|
||||
fn usz List.retain_if(List* list, ElementPredicate selection)
|
||||
{
|
||||
usz size = list.size;
|
||||
for (usz i = size; i > 0; i--)
|
||||
{
|
||||
if (!selection(&list.entries[i - 1])) continue;
|
||||
for (usz j = i; j < size; j++)
|
||||
{
|
||||
list.entries[j - 1] = list.entries[j];
|
||||
}
|
||||
list.size--;
|
||||
}
|
||||
return size - list.size;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reserve at least min_capacity
|
||||
**/
|
||||
@@ -268,121 +175,11 @@ fn Type* List.get_ref(List* list, usz index) @operator(&[]) @inline
|
||||
return &list.entries[index];
|
||||
}
|
||||
|
||||
fn void List.ensure_capacity(List* list, usz added = 1) @inline @private
|
||||
|
||||
fn void List.ensure_capacity(List* list) @inline @private
|
||||
{
|
||||
usz new_size = list.size + added;
|
||||
if (list.capacity > new_size) return;
|
||||
|
||||
assert(new_size < usz.max / 2U);
|
||||
usz new_capacity = list.capacity ? 2U * list.capacity : 16U;
|
||||
while (new_size >= new_capacity) new_capacity *= 2U;
|
||||
list.reserve(new_capacity);
|
||||
if (list.capacity == list.size)
|
||||
{
|
||||
list.reserve(list.capacity ? 2 * list.capacity : 16);
|
||||
}
|
||||
}
|
||||
|
||||
// Functions for equatable types
|
||||
|
||||
$if types::is_equatable_type(Type):
|
||||
|
||||
fn usz! List.index_of(List* list, Type type)
|
||||
{
|
||||
foreach (i, v : list)
|
||||
{
|
||||
if (v == type) return i;
|
||||
}
|
||||
return SearchResult.MISSING?;
|
||||
}
|
||||
|
||||
fn usz! List.rindex_of(List* list, Type type)
|
||||
{
|
||||
foreach_r (i, v : list)
|
||||
{
|
||||
if (v == type) return i;
|
||||
}
|
||||
return SearchResult.MISSING?;
|
||||
}
|
||||
|
||||
fn bool List.equals(List* list, List other_list)
|
||||
{
|
||||
if (list.size != other_list.size) return false;
|
||||
foreach (i, v : list)
|
||||
{
|
||||
if (v != other_list.entries[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for presence of a value in a list.
|
||||
*
|
||||
* @param [&in] list "the list to find elements in"
|
||||
* @param value "The value to search for"
|
||||
* @return "True if the value is found, false otherwise"
|
||||
**/
|
||||
fn bool List.contains(List* list, Type value)
|
||||
{
|
||||
foreach (i, v : list)
|
||||
{
|
||||
if (v == value) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param [&inout] list "The list to remove elements from"
|
||||
* @param value "The value to remove"
|
||||
* @return "the number of deleted elements."
|
||||
**/
|
||||
fn usz List.remove(List* list, Type value)
|
||||
{
|
||||
usz size = list.size;
|
||||
for (usz i = size; i > 0; i--)
|
||||
{
|
||||
if (list.entries[i - 1] != value) continue;
|
||||
for (usz j = i; j < size; j++)
|
||||
{
|
||||
list.entries[j - 1] = list.entries[j];
|
||||
}
|
||||
list.size--;
|
||||
}
|
||||
return size - list.size;
|
||||
}
|
||||
|
||||
fn void List.remove_all(List* list, List* other_list)
|
||||
{
|
||||
if (!other_list.size) return;
|
||||
foreach (v : other_list) list.remove(v);
|
||||
}
|
||||
|
||||
|
||||
$endif
|
||||
|
||||
$if Type.kindof == POINTER:
|
||||
|
||||
/**
|
||||
* @param [&in] list
|
||||
* @return "The number non-null values in the list"
|
||||
**/
|
||||
fn usz List.compact_count(List* list)
|
||||
{
|
||||
usz vals = 0;
|
||||
foreach (v : list) if (v) vals++;
|
||||
return vals;
|
||||
}
|
||||
|
||||
fn usz List.compact(List* list)
|
||||
{
|
||||
usz size = list.size;
|
||||
for (usz i = size; i > 0; i--)
|
||||
{
|
||||
if (list.entries[i - 1]) continue;
|
||||
for (usz j = i; j < size; j++)
|
||||
{
|
||||
list.entries[j - 1] = list.entries[j];
|
||||
}
|
||||
list.size--;
|
||||
}
|
||||
return size - list.size;
|
||||
}
|
||||
|
||||
$endif
|
||||
@@ -45,17 +45,6 @@ fn void HashMap.tinit(HashMap* map, uint capacity = DEFAULT_INITIAL_CAPACITY, fl
|
||||
map.init(capacity, load_factor, mem::temp());
|
||||
}
|
||||
|
||||
/**
|
||||
* Has this hash map been initialized yet?
|
||||
*
|
||||
* @param [&in] map "The hash map we are testing"
|
||||
* @return "Returns true if it has been initialized, false otherwise"
|
||||
**/
|
||||
fn bool HashMap.is_initialized(HashMap* map)
|
||||
{
|
||||
return map.allocator != null;
|
||||
}
|
||||
|
||||
fn void HashMap.init_from_map(HashMap* map, HashMap* other_map, Allocator* using = mem::heap())
|
||||
{
|
||||
map.init(other_map.table.len, other_map.load_factor, using);
|
||||
@@ -74,24 +63,24 @@ fn bool HashMap.is_empty(HashMap* map) @inline
|
||||
|
||||
fn Value*! HashMap.get_ref(HashMap* map, Key key)
|
||||
{
|
||||
if (!map.count) return SearchResult.MISSING?;
|
||||
if (!map.count) return SearchResult.MISSING!;
|
||||
uint hash = rehash(key.hash());
|
||||
for (Entry *e = map.table[index_for(hash, map.table.len)]; e != null; e = e.next)
|
||||
{
|
||||
if (e.hash == hash && equals(key, e.key)) return &e.value;
|
||||
}
|
||||
return SearchResult.MISSING?;
|
||||
return SearchResult.MISSING!;
|
||||
}
|
||||
|
||||
fn Entry*! HashMap.get_entry(HashMap* map, Key key)
|
||||
{
|
||||
if (!map.count) return SearchResult.MISSING?;
|
||||
if (!map.count) return SearchResult.MISSING!;
|
||||
uint hash = rehash(key.hash());
|
||||
for (Entry *e = map.table[index_for(hash, map.table.len)]; e != null; e = e.next)
|
||||
{
|
||||
if (e.hash == hash && equals(key, e.key)) return e;
|
||||
}
|
||||
return SearchResult.MISSING?;
|
||||
return SearchResult.MISSING!;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -123,7 +112,7 @@ fn Value! HashMap.get(HashMap* map, Key key) @operator([])
|
||||
|
||||
fn bool HashMap.has_key(HashMap* map, Key key)
|
||||
{
|
||||
return @ok(map.get_ref(key));
|
||||
return try? map.get_ref(key);
|
||||
}
|
||||
|
||||
fn bool HashMap.set(HashMap* map, Key key, Value value) @operator([]=)
|
||||
@@ -149,7 +138,7 @@ fn bool HashMap.set(HashMap* map, Key key, Value value) @operator([]=)
|
||||
|
||||
fn void! HashMap.remove(HashMap* map, Key key) @maydiscard
|
||||
{
|
||||
if (!map.remove_entry_for_key(key)) return SearchResult.MISSING?;
|
||||
if (!map.remove_entry_for_key(key)) return SearchResult.MISSING!;
|
||||
}
|
||||
|
||||
fn void HashMap.clear(HashMap* map)
|
||||
@@ -216,7 +205,7 @@ fn Value[] HashMap.value_list(HashMap* map, Allocator* using = mem::heap())
|
||||
return list;
|
||||
}
|
||||
|
||||
$if types::is_equatable(Value):
|
||||
$if (types::is_equatable(Value))
|
||||
fn bool HashMap.has_value(HashMap* map, Value v)
|
||||
{
|
||||
if (!map.count) return false;
|
||||
|
||||
@@ -26,52 +26,56 @@ struct Object
|
||||
}
|
||||
}
|
||||
|
||||
static initialize
|
||||
{
|
||||
io::formatter_register_type(Object);
|
||||
}
|
||||
|
||||
fn void! Object.to_format(Object* o, Formatter* formatter) @dynamic
|
||||
fn void! Object.to_format(Object* o, Formatter* formatter)
|
||||
{
|
||||
switch (o.type)
|
||||
{
|
||||
case void:
|
||||
formatter.printf("{}")!;
|
||||
formatter.printf("{}")?;
|
||||
case void*:
|
||||
formatter.printf("null")!;
|
||||
formatter.printf("null")?;
|
||||
case String:
|
||||
formatter.printf(`"%s"`, o.s)!;
|
||||
formatter.printf(`"%s"`, o.s)?;
|
||||
case bool:
|
||||
formatter.printf(o.b ? "true" : "false")!;
|
||||
formatter.printf(o.b ? "true" : "false")?;
|
||||
case ObjectInternalList:
|
||||
formatter.printf("[")!;
|
||||
formatter.printf("[")?;
|
||||
foreach (i, ol : o.array)
|
||||
{
|
||||
formatter.printf(i == 0 ? " " : ", ")!;
|
||||
ol.to_format(formatter)!;
|
||||
formatter.printf(i == 0 ? " " : ", ")?;
|
||||
ol.to_format(formatter)?;
|
||||
}
|
||||
formatter.printf(" ]")!;
|
||||
formatter.printf(" ]")?;
|
||||
case ObjectInternalMap:
|
||||
formatter.printf("{")!;
|
||||
formatter.printf("{")?;
|
||||
@pool()
|
||||
{
|
||||
foreach (i, key : o.map.key_tlist())
|
||||
{
|
||||
formatter.printf(i == 0 ? " " : ", ")!;
|
||||
formatter.printf(`"%s": `, key)!;
|
||||
o.map.get(key).to_format(formatter)!;
|
||||
formatter.printf(i == 0 ? " " : ", ")?;
|
||||
formatter.printf(`"%s": `, key)?;
|
||||
o.map.get(key).to_format(formatter)?;
|
||||
}
|
||||
};
|
||||
formatter.printf(" }")!;
|
||||
formatter.printf(" }")?;
|
||||
default:
|
||||
switch (o.type.kindof)
|
||||
{
|
||||
case SIGNED_INT:
|
||||
formatter.printf("%d", o.i)!;
|
||||
formatter.printf("%d", o.i)?;
|
||||
case UNSIGNED_INT:
|
||||
formatter.printf("%d", (uint128)o.i)!;
|
||||
formatter.printf("%d", (uint128)o.i)?;
|
||||
case FLOAT:
|
||||
formatter.printf("%d", o.f)!;
|
||||
formatter.printf("%d", o.f)?;
|
||||
case ENUM:
|
||||
formatter.printf("%d", o.i)!;
|
||||
formatter.printf("%d", o.i)?;
|
||||
default:
|
||||
formatter.printf("<>")!;
|
||||
formatter.printf("<>")?;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -226,7 +230,7 @@ $switch
|
||||
$case $checks(String s = value):
|
||||
return new_string(value);
|
||||
$default:
|
||||
$error "Unsupported object type.";
|
||||
$assert(false, "Unsupported object type.");
|
||||
$endswitch
|
||||
|
||||
}
|
||||
@@ -262,7 +266,7 @@ macro Object* Object.append(Object* o, value)
|
||||
/**
|
||||
* @require o.is_keyable()
|
||||
**/
|
||||
fn Object*! Object.get(Object* o, String key) => o.is_empty() ? SearchResult.MISSING? : o.map.get(key);
|
||||
fn Object*! Object.get(Object* o, String key) => o.is_empty() ? SearchResult.MISSING! : o.map.get(key);
|
||||
|
||||
|
||||
fn bool Object.has_key(Object* o, String key) => o.is_map() && o.map.has_key(key);
|
||||
@@ -311,13 +315,13 @@ macro get_integer_value(Object* value, $Type)
|
||||
}
|
||||
if (value.is_string())
|
||||
{
|
||||
$if $Type.kindof == TypeKind.SIGNED_INT:
|
||||
return ($Type)value.s.to_int128();
|
||||
$if ($Type.kindof == TypeKind.SIGNED_INT)
|
||||
return ($Type)str::to_int128(value.s);
|
||||
$else
|
||||
return ($Type)value.s.to_uint128();
|
||||
return ($Type)str::to_uint128(value.s);
|
||||
$endif
|
||||
}
|
||||
if (!value.is_int()) return NumberConversion.MALFORMED_INTEGER?;
|
||||
if (!value.is_int()) return NumberConversion.MALFORMED_INTEGER!;
|
||||
return ($Type)value.i;
|
||||
}
|
||||
|
||||
@@ -366,7 +370,7 @@ fn uint128! Object.get_uint128_at(Object* o, usz index) => o.get_integer_at(uint
|
||||
**/
|
||||
fn String! Object.get_string(Object* o, String key)
|
||||
{
|
||||
Object* value = o.get(key)!;
|
||||
Object* value = o.get(key)?;
|
||||
assert(value.is_string());
|
||||
return value.s;
|
||||
}
|
||||
@@ -386,7 +390,7 @@ fn String Object.get_string_at(Object* o, usz index)
|
||||
**/
|
||||
macro String! Object.get_enum(Object* o, $EnumType, String key)
|
||||
{
|
||||
Object value = o.get(key)!;
|
||||
Object value = o.get(key)?;
|
||||
assert($EnumType.typeid == value.type);
|
||||
return ($EnumType)value.i;
|
||||
}
|
||||
@@ -406,7 +410,7 @@ macro String Object.get_enum_at(Object* o, $EnumType, usz index)
|
||||
**/
|
||||
fn bool! Object.get_bool(Object* o, String key)
|
||||
{
|
||||
Object* value = o.get(key)!;
|
||||
Object* value = o.get(key)?;
|
||||
assert(value.is_bool());
|
||||
return value.b;
|
||||
}
|
||||
@@ -427,7 +431,7 @@ fn bool Object.get_bool_at(Object* o, usz index)
|
||||
**/
|
||||
fn double! Object.get_float(Object* o, String key)
|
||||
{
|
||||
Object* value = o.get(key)!;
|
||||
Object* value = o.get(key)?;
|
||||
switch (value.type.kindof)
|
||||
{
|
||||
case SIGNED_INT:
|
||||
@@ -468,7 +472,7 @@ fn Object* Object.get_or_create_obj(Object* o, String key)
|
||||
return container;
|
||||
}
|
||||
|
||||
def ObjectInternalMap @private = HashMap<String, Object*>;
|
||||
def ObjectInternalList @private = List<Object*>;
|
||||
def ObjectInternalMapEntry @private = Entry<String, Object*>;
|
||||
typedef ObjectInternalMap @private = HashMap<String, Object*>;
|
||||
typedef ObjectInternalList @private = List<Object*>;
|
||||
typedef ObjectInternalMapEntry @private = Entry<String, Object*>;
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
module std::collections::priorityqueue<Type>;
|
||||
import std::collections::list;
|
||||
|
||||
def Heap = List<Type>;
|
||||
typedef Heap = List<Type>;
|
||||
|
||||
struct PriorityQueue
|
||||
{
|
||||
@@ -55,7 +55,7 @@ fn Type! PriorityQueue.pop(PriorityQueue* pq)
|
||||
{
|
||||
usz i = 0;
|
||||
usz len = pq.heap.len() @inline;
|
||||
if (!len) return IteratorResult.NO_MORE_ELEMENT?;
|
||||
if (!len) return IteratorResult.NO_MORE_ELEMENT!;
|
||||
usz newCount = len - 1;
|
||||
pq.heap.swap(0, newCount);
|
||||
while ((2 * i + 1) < newCount)
|
||||
@@ -84,7 +84,7 @@ fn Type! PriorityQueue.pop(PriorityQueue* pq)
|
||||
*/
|
||||
fn Type! PriorityQueue.peek(PriorityQueue* pq)
|
||||
{
|
||||
if (!pq.len()) return IteratorResult.NO_MORE_ELEMENT?;
|
||||
if (!pq.len()) return IteratorResult.NO_MORE_ELEMENT!;
|
||||
return pq.heap.get(0);
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ fn void*! arena_allocator_function(Allocator* data, usz size, usz alignment, usz
|
||||
assert(!old_pointer, "Unexpected old pointer for alloc.");
|
||||
if (!size) return null;
|
||||
alignment = alignment_for_allocation(alignment);
|
||||
void* mem = arena._alloc(size, alignment, offset)!;
|
||||
void* mem = arena._alloc(size, alignment, offset)?;
|
||||
if (clear) mem::clear(mem, size, mem::DEFAULT_MEM_ALIGNMENT);
|
||||
return mem;
|
||||
case ALIGNED_REALLOC:
|
||||
@@ -62,7 +62,7 @@ fn void*! arena_allocator_function(Allocator* data, usz size, usz alignment, usz
|
||||
if (!size) nextcase FREE;
|
||||
if (!old_pointer) nextcase ALLOC;
|
||||
alignment = alignment_for_allocation(alignment);
|
||||
return arena._realloc(old_pointer, size, alignment, offset)!;
|
||||
return arena._realloc(old_pointer, size, alignment, offset)?;
|
||||
case ALIGNED_FREE:
|
||||
case FREE:
|
||||
if (!old_pointer) return null;
|
||||
@@ -96,14 +96,14 @@ fn void*! arena_allocator_function(Allocator* data, usz size, usz alignment, usz
|
||||
fn void*! ArenaAllocator._alloc(ArenaAllocator* this, usz size, usz alignment, usz offset) @private
|
||||
{
|
||||
usz total_len = this.data.len;
|
||||
if (size > total_len) return AllocationFailure.CHUNK_TOO_LARGE?;
|
||||
if (size > total_len) return AllocationFailure.CHUNK_TOO_LARGE!;
|
||||
void* start_mem = this.data.ptr;
|
||||
void* unaligned_pointer_to_offset = start_mem + this.used + ArenaAllocatorHeader.sizeof + offset;
|
||||
void* aligned_pointer_to_offset = mem::aligned_pointer(unaligned_pointer_to_offset, alignment);
|
||||
usz end = (usz)(aligned_pointer_to_offset - this.data.ptr) + size - offset;
|
||||
if (end > total_len) return AllocationFailure.OUT_OF_MEMORY?;
|
||||
if (end > total_len) return AllocationFailure.OUT_OF_MEMORY!;
|
||||
this.used = end;
|
||||
void* mem = aligned_pointer_to_offset - offset;
|
||||
void *mem = aligned_pointer_to_offset - offset;
|
||||
ArenaAllocatorHeader* header = mem - ArenaAllocatorHeader.sizeof;
|
||||
header.size = size;
|
||||
return mem;
|
||||
@@ -123,7 +123,7 @@ fn void*! ArenaAllocator._realloc(ArenaAllocator* this, void *old_pointer, usz s
|
||||
{
|
||||
assert(old_pointer >= this.data.ptr, "Pointer originates from a different allocator.");
|
||||
usz total_len = this.data.len;
|
||||
if (size > total_len) return AllocationFailure.CHUNK_TOO_LARGE?;
|
||||
if (size > total_len) return AllocationFailure.CHUNK_TOO_LARGE!;
|
||||
ArenaAllocatorHeader* header = old_pointer - ArenaAllocatorHeader.sizeof;
|
||||
usz old_size = header.size;
|
||||
// Do last allocation and alignment match?
|
||||
@@ -136,14 +136,14 @@ fn void*! ArenaAllocator._realloc(ArenaAllocator* this, void *old_pointer, usz s
|
||||
else
|
||||
{
|
||||
usz new_used = this.used + size - old_size;
|
||||
if (new_used > total_len) return AllocationFailure.OUT_OF_MEMORY?;
|
||||
if (new_used > total_len) return AllocationFailure.OUT_OF_MEMORY!;
|
||||
this.used = new_used;
|
||||
}
|
||||
header.size = size;
|
||||
return old_pointer;
|
||||
}
|
||||
// Otherwise just allocate new memory.
|
||||
void* mem = this._alloc(size, alignment, offset)!;
|
||||
void* mem = this._alloc(size, alignment, offset)?;
|
||||
mem::copy(mem, old_pointer, old_size, mem::DEFAULT_MEM_ALIGNMENT, mem::DEFAULT_MEM_ALIGNMENT);
|
||||
return mem;
|
||||
}
|
||||
@@ -17,19 +17,19 @@ struct DynamicArenaAllocator
|
||||
* @require page_size >= 128
|
||||
* @require this != null
|
||||
**/
|
||||
fn void DynamicArenaAllocator.init(DynamicArenaAllocator* this, usz page_size, Allocator* using = mem::heap())
|
||||
fn void DynamicArenaAllocator.init(DynamicArenaAllocator* this, usz page_size, Allocator* backing_allocator = mem::heap())
|
||||
{
|
||||
this.function = &dynamic_arena_allocator_function;
|
||||
this.page = null;
|
||||
this.unused_page = null;
|
||||
this.page_size = page_size;
|
||||
this.backing_allocator = using;
|
||||
this.backing_allocator = backing_allocator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require this != null
|
||||
**/
|
||||
fn void DynamicArenaAllocator.free(DynamicArenaAllocator* this)
|
||||
fn void DynamicArenaAllocator.destroy(DynamicArenaAllocator* this)
|
||||
{
|
||||
DynamicArenaPage* page = this.page;
|
||||
while (page)
|
||||
@@ -67,7 +67,7 @@ struct DynamicArenaChunk @local
|
||||
* @require ptr && this
|
||||
* @require this.page `tried to free pointer on invalid allocator`
|
||||
*/
|
||||
fn void DynamicArenaAllocator.free_ptr(DynamicArenaAllocator* this, void* ptr) @private
|
||||
fn void DynamicArenaAllocator.free(DynamicArenaAllocator* this, void* ptr) @private
|
||||
{
|
||||
DynamicArenaPage* current_page = this.page;
|
||||
if (ptr == current_page.last_ptr)
|
||||
@@ -106,7 +106,7 @@ fn void*! DynamicArenaAllocator._realloc(DynamicArenaAllocator* this, void* old_
|
||||
current_page.used += add_size;
|
||||
return old_pointer;
|
||||
}
|
||||
void* new_mem = this._alloc(size, alignment, offset)!;
|
||||
void* new_mem = this._alloc(size, alignment, offset)?;
|
||||
mem::copy(new_mem, old_pointer, old_size, mem::DEFAULT_MEM_ALIGNMENT);
|
||||
return new_mem;
|
||||
}
|
||||
@@ -137,12 +137,12 @@ fn void*! DynamicArenaAllocator._alloc_new(DynamicArenaAllocator* this, usz size
|
||||
usz page_size = max(this.page_size, mem::aligned_offset(size + DynamicArenaChunk.sizeof + offset, alignment) - offset);
|
||||
|
||||
// Grab the page without alignment (we do it ourselves)
|
||||
void* mem = this.backing_allocator.alloc(page_size)!;
|
||||
void* mem = this.backing_allocator.alloc(page_size)?;
|
||||
DynamicArenaPage*! page = malloc(DynamicArenaPage, .using = this.backing_allocator);
|
||||
if (catch err = page)
|
||||
{
|
||||
free(mem, .using = this.backing_allocator);
|
||||
return err?;
|
||||
return err!;
|
||||
}
|
||||
page.memory = mem;
|
||||
void* mem_start = mem::aligned_pointer(mem + offset + DynamicArenaChunk.sizeof, alignment) - offset;
|
||||
@@ -213,7 +213,7 @@ fn void*! dynamic_arena_allocator_function(Allocator* data, usz size, usz alignm
|
||||
case ALIGNED_CALLOC:
|
||||
assert(!old_pointer, "Unexpected no old pointer for calloc.");
|
||||
if (!size) return null;
|
||||
void* mem = allocator._alloc(size, alignment, offset)!;
|
||||
void* mem = allocator._alloc(size, alignment, offset)?;
|
||||
mem::clear(mem, size, mem::DEFAULT_MEM_ALIGNMENT);
|
||||
return mem;
|
||||
case ALLOC:
|
||||
@@ -226,16 +226,16 @@ fn void*! dynamic_arena_allocator_function(Allocator* data, usz size, usz alignm
|
||||
if (!size)
|
||||
{
|
||||
if (!old_pointer) return null;
|
||||
allocator.free_ptr(old_pointer);
|
||||
allocator.free(old_pointer);
|
||||
return null;
|
||||
}
|
||||
if (!old_pointer) return allocator._alloc(size, alignment, offset);
|
||||
void* mem = allocator._realloc(old_pointer, size, alignment, offset)!;
|
||||
void* mem = allocator._realloc(old_pointer, size, alignment, offset)?;
|
||||
return mem;
|
||||
case ALIGNED_FREE:
|
||||
case FREE:
|
||||
if (!old_pointer) return null;
|
||||
allocator.free_ptr(old_pointer);
|
||||
allocator.free(old_pointer);
|
||||
return null;
|
||||
case MARK:
|
||||
unreachable("Tried to mark a dynamic arena");
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
module std::core::mem::allocator;
|
||||
|
||||
def MemoryAllocFn = fn char[]!(usz);
|
||||
typedef MemoryAllocFn = fn char[]!(usz);
|
||||
|
||||
struct SimpleHeapAllocator
|
||||
{
|
||||
@@ -51,9 +51,9 @@ fn void*! simple_heap_allocator_function(Allocator* this, usz size, usz alignmen
|
||||
if (!old_pointer) nextcase CALLOC;
|
||||
return heap._realloc(old_pointer, size);
|
||||
case RESET:
|
||||
return AllocationFailure.UNSUPPORTED_OPERATION?;
|
||||
return AllocationFailure.UNSUPPORTED_OPERATION!;
|
||||
case ALIGNED_FREE:
|
||||
@aligned_free(heap._free, old_pointer)!;
|
||||
@aligned_free(heap._free, old_pointer)?;
|
||||
return null;
|
||||
case FREE:
|
||||
heap._free(old_pointer);
|
||||
@@ -71,7 +71,7 @@ fn void*! SimpleHeapAllocator._realloc(SimpleHeapAllocator* this, void* old_poin
|
||||
// Find the block header.
|
||||
Header* block = (Header*)old_pointer - 1;
|
||||
if (block.size >= bytes) return old_pointer;
|
||||
void* new = this._alloc(bytes)!;
|
||||
void* new = this._alloc(bytes)?;
|
||||
usz max_to_copy = math::min(block.size, bytes);
|
||||
mem::copy(new, old_pointer, max_to_copy);
|
||||
this._free(old_pointer);
|
||||
@@ -80,7 +80,7 @@ fn void*! SimpleHeapAllocator._realloc(SimpleHeapAllocator* this, void* old_poin
|
||||
|
||||
fn void*! SimpleHeapAllocator._calloc(SimpleHeapAllocator* this, usz bytes) @local
|
||||
{
|
||||
void* data = this._alloc(bytes)!;
|
||||
void* data = this._alloc(bytes)?;
|
||||
mem::clear(data, bytes, mem::DEFAULT_MEM_ALIGNMENT);
|
||||
return data;
|
||||
}
|
||||
@@ -90,7 +90,7 @@ fn void*! SimpleHeapAllocator._alloc(SimpleHeapAllocator* this, usz bytes) @loca
|
||||
usz aligned_bytes = mem::aligned_offset(bytes, mem::DEFAULT_MEM_ALIGNMENT);
|
||||
if (!this.free_list)
|
||||
{
|
||||
this.add_block(aligned_bytes)!;
|
||||
this.add_block(aligned_bytes)?;
|
||||
}
|
||||
|
||||
Header* current = this.free_list;
|
||||
@@ -130,14 +130,14 @@ fn void*! SimpleHeapAllocator._alloc(SimpleHeapAllocator* this, usz bytes) @loca
|
||||
current = current.next;
|
||||
}
|
||||
}
|
||||
this.add_block(aligned_bytes)!;
|
||||
this.add_block(aligned_bytes)?;
|
||||
return this.alloc(aligned_bytes);
|
||||
}
|
||||
|
||||
fn void! SimpleHeapAllocator.add_block(SimpleHeapAllocator* this, usz aligned_bytes) @local
|
||||
{
|
||||
assert(mem::aligned_offset(aligned_bytes, mem::DEFAULT_MEM_ALIGNMENT) == aligned_bytes);
|
||||
char[] result = this.alloc_fn(aligned_bytes + Header.sizeof)!;
|
||||
char[] result = this.alloc_fn(aligned_bytes + Header.sizeof)?;
|
||||
Header* new_block = (Header*)result.ptr;
|
||||
new_block.size = result.len - Header.sizeof;
|
||||
new_block.next = null;
|
||||
|
||||
@@ -18,7 +18,7 @@ fn void*! null_allocator_fn(Allocator* this, usz bytes, usz alignment, usz offse
|
||||
case ALIGNED_ALLOC:
|
||||
case ALIGNED_REALLOC:
|
||||
case ALIGNED_CALLOC:
|
||||
return AllocationFailure.OUT_OF_MEMORY?;
|
||||
return AllocationFailure.OUT_OF_MEMORY!;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
@@ -37,8 +37,8 @@ struct AlignedBlock
|
||||
macro void*! @aligned_alloc(#alloc_fn, usz bytes, usz alignment, usz offset)
|
||||
{
|
||||
usz header = mem::aligned_offset(AlignedBlock.sizeof + offset, alignment) - offset;
|
||||
$if $checks(#alloc_fn(bytes)!):
|
||||
void* data = #alloc_fn(header + bytes)!;
|
||||
$if ($checks(#alloc_fn(bytes)?))
|
||||
void* data = #alloc_fn(header + bytes)?;
|
||||
$else
|
||||
void* data = #alloc_fn(header + bytes);
|
||||
$endif
|
||||
@@ -56,8 +56,8 @@ macro void*! @aligned_alloc(#alloc_fn, usz bytes, usz alignment, usz offset)
|
||||
macro void*! @aligned_calloc(#calloc_fn, usz bytes, usz alignment, usz offset)
|
||||
{
|
||||
usz header = mem::aligned_offset(AlignedBlock.sizeof + offset, alignment) - offset;
|
||||
$if $checks(#calloc_fn(bytes)!):
|
||||
void* data = #calloc_fn(header + bytes)!;
|
||||
$if ($checks(#calloc_fn(bytes)?))
|
||||
void* data = #calloc_fn(header + bytes)?;
|
||||
$else
|
||||
void* data = #calloc_fn(header + bytes);
|
||||
$endif
|
||||
@@ -76,10 +76,10 @@ macro void*! @aligned_realloc(#calloc_fn, #free_fn, void* old_pointer, usz bytes
|
||||
{
|
||||
AlignedBlock* desc = (AlignedBlock*)old_pointer - 1;
|
||||
void* data_start = desc.start;
|
||||
void* new_data = @aligned_calloc(#calloc_fn, bytes, alignment, offset)!;
|
||||
void* new_data = @aligned_calloc(#calloc_fn, bytes, alignment, offset)?;
|
||||
mem::copy(new_data, old_pointer, desc.len > bytes ? desc.len : bytes, mem::DEFAULT_MEM_ALIGNMENT, mem::DEFAULT_MEM_ALIGNMENT);
|
||||
$if $checks(#free_fn(data_start)!):
|
||||
#free_fn(data_start)!;
|
||||
$if ($checks(#free_fn(data_start)?))
|
||||
#free_fn(data_start)?;
|
||||
$else
|
||||
#free_fn(data_start);
|
||||
$endif
|
||||
@@ -89,8 +89,8 @@ macro void*! @aligned_realloc(#calloc_fn, #free_fn, void* old_pointer, usz bytes
|
||||
macro void! @aligned_free(#free_fn, void* old_pointer)
|
||||
{
|
||||
AlignedBlock* desc = (AlignedBlock*)old_pointer - 1;
|
||||
$if $checks(#free_fn(desc.start)!):
|
||||
#free_fn(desc.start)!;
|
||||
$if ($checks(#free_fn(desc.start)?))
|
||||
#free_fn(desc.start)?;
|
||||
$else
|
||||
#free_fn(desc.start);
|
||||
$endif
|
||||
@@ -121,7 +121,7 @@ fn void*! libc_allocator_fn(Allocator* unused, usz bytes, usz alignment, usz off
|
||||
if (!old_pointer) nextcase CALLOC;
|
||||
data = libc::realloc(old_pointer, bytes);
|
||||
case RESET:
|
||||
return AllocationFailure.UNSUPPORTED_OPERATION?;
|
||||
return AllocationFailure.UNSUPPORTED_OPERATION!;
|
||||
case ALIGNED_FREE:
|
||||
@aligned_free(libc::free, old_pointer)!!;
|
||||
return null;
|
||||
@@ -131,6 +131,6 @@ fn void*! libc_allocator_fn(Allocator* unused, usz bytes, usz alignment, usz off
|
||||
default:
|
||||
unreachable();
|
||||
}
|
||||
if (!data) return AllocationFailure.OUT_OF_MEMORY?;
|
||||
if (!data) return AllocationFailure.OUT_OF_MEMORY!;
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -111,16 +111,16 @@ fn void*! on_stack_allocator_function(Allocator* data, usz size, usz alignment,
|
||||
on_stack_allocator_remove_chunk(allocator, old_pointer);
|
||||
if (kind == AllocationKind.ALIGNED_FREE)
|
||||
{
|
||||
allocator.backing_allocator.free_aligned(old_pointer)!;
|
||||
allocator.backing_allocator.free_aligned(old_pointer)?;
|
||||
}
|
||||
else
|
||||
{
|
||||
allocator.backing_allocator.free(old_pointer)!;
|
||||
allocator.backing_allocator.free(old_pointer)?;
|
||||
}
|
||||
return null;
|
||||
case MARK:
|
||||
case RESET:
|
||||
return AllocationFailure.UNSUPPORTED_OPERATION?;
|
||||
return AllocationFailure.UNSUPPORTED_OPERATION!;
|
||||
}
|
||||
unreachable();
|
||||
}
|
||||
@@ -175,14 +175,14 @@ fn void*! on_stack_allocator_realloc(OnStackAllocator* a, void* old_pointer, usz
|
||||
assert(chunk, "Tried to realloc pointer not belonging to the allocator");
|
||||
if (aligned)
|
||||
{
|
||||
return chunk.data = a.backing_allocator.realloc_aligned(old_pointer, size, alignment, offset)!;
|
||||
return chunk.data = a.backing_allocator.realloc_aligned(old_pointer, size, alignment, offset)?;
|
||||
}
|
||||
return chunk.data = a.backing_allocator.realloc(old_pointer, size)!;
|
||||
return chunk.data = a.backing_allocator.realloc(old_pointer, size)?;
|
||||
}
|
||||
|
||||
OnStackAllocatorHeader* header = old_pointer - OnStackAllocatorHeader.sizeof;
|
||||
usz old_size = header.size;
|
||||
void* mem = on_stack_allocator_alloc(a, size, alignment, offset, true, aligned)!;
|
||||
void* mem = on_stack_allocator_alloc(a, size, alignment, offset, true, aligned)?;
|
||||
mem::copy(mem, old_pointer, old_size, mem::DEFAULT_MEM_ALIGNMENT, mem::DEFAULT_MEM_ALIGNMENT);
|
||||
return mem;
|
||||
}
|
||||
@@ -209,7 +209,7 @@ fn void*! on_stack_allocator_alloc(OnStackAllocator* a, usz size, usz alignment,
|
||||
|
||||
if (end > total_len)
|
||||
{
|
||||
OnStackAllocatorExtraChunk* chunk = backing_allocator.alloc(OnStackAllocatorExtraChunk.sizeof)!;
|
||||
OnStackAllocatorExtraChunk* chunk = backing_allocator.alloc(OnStackAllocatorExtraChunk.sizeof)?;
|
||||
defer catch backing_allocator.free(chunk)!!;
|
||||
defer try a.chunk = chunk;
|
||||
*chunk = { .prev = a.chunk, .is_aligned = aligned };
|
||||
@@ -217,13 +217,13 @@ fn void*! on_stack_allocator_alloc(OnStackAllocator* a, usz size, usz alignment,
|
||||
switch
|
||||
{
|
||||
case !aligned && !clear:
|
||||
data = backing_allocator.alloc(size)!;
|
||||
data = backing_allocator.alloc(size)?;
|
||||
case aligned && !clear:
|
||||
data = backing_allocator.alloc_aligned(size, alignment, offset)!;
|
||||
data = backing_allocator.alloc_aligned(size, alignment, offset)?;
|
||||
case !aligned && clear:
|
||||
data = backing_allocator.calloc(size)!;
|
||||
data = backing_allocator.calloc(size)?;
|
||||
case aligned && clear:
|
||||
data = backing_allocator.calloc_aligned(size, alignment, offset)!;
|
||||
data = backing_allocator.calloc_aligned(size, alignment, offset)?;
|
||||
}
|
||||
return chunk.data = data;
|
||||
}
|
||||
|
||||
@@ -37,12 +37,12 @@ macro bool TempAllocatorPage.is_aligned(TempAllocatorPage* page) => page.size &
|
||||
/**
|
||||
* @require size >= 16
|
||||
**/
|
||||
fn TempAllocator*! new_temp(usz size, Allocator* using)
|
||||
fn TempAllocator*! new_temp(usz size, Allocator* backing_allocator)
|
||||
{
|
||||
TempAllocator* allocator = malloc_checked(TempAllocator, .using = using, .end_padding = size)!;
|
||||
TempAllocator* allocator = malloc_checked(TempAllocator, .using = backing_allocator, .end_padding = size)?;
|
||||
allocator.last_page = null;
|
||||
allocator.function = &temp_allocator_function;
|
||||
allocator.backing_allocator = using;
|
||||
allocator.backing_allocator = backing_allocator;
|
||||
allocator.used = 0;
|
||||
allocator.capacity = size;
|
||||
return allocator;
|
||||
@@ -75,12 +75,12 @@ fn void*! temp_allocator_function(Allocator* data, usz size, usz alignment, usz
|
||||
case FREE:
|
||||
case ALIGNED_FREE:
|
||||
if (!old_pointer) return null;
|
||||
arena._free(old_pointer)!;
|
||||
arena._free(old_pointer)?;
|
||||
return null;
|
||||
case MARK:
|
||||
return (void*)(uptr)arena.used;
|
||||
case RESET:
|
||||
arena._reset(size)!;
|
||||
arena._reset(size)?;
|
||||
return null;
|
||||
}
|
||||
unreachable();
|
||||
@@ -103,7 +103,7 @@ fn void! TempAllocator._reset(TempAllocator* this, usz mark) @local
|
||||
{
|
||||
TempAllocatorPage *to_free = last_page;
|
||||
last_page = last_page.prev_page;
|
||||
this._free_page(to_free)!;
|
||||
this._free_page(to_free)?;
|
||||
}
|
||||
this.last_page = last_page;
|
||||
this.used = mark;
|
||||
@@ -131,15 +131,15 @@ fn void*! TempAllocator._realloc_page(TempAllocator* this, TempAllocatorPage* pa
|
||||
*pointer_to_prev = page.prev_page;
|
||||
usz page_size = page.pagesize();
|
||||
// Clear on size > original size.
|
||||
void* data = this._alloc(size, alignment, offset, false)!;
|
||||
void* data = this._alloc(size, alignment, offset, false)?;
|
||||
mem::copy(data, &page.data[0], page_size, mem::DEFAULT_MEM_ALIGNMENT, mem::DEFAULT_MEM_ALIGNMENT);
|
||||
if (page.is_aligned())
|
||||
{
|
||||
this.backing_allocator.free_aligned(real_pointer)!;
|
||||
this.backing_allocator.free_aligned(real_pointer)?;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.backing_allocator.free(real_pointer)!;
|
||||
this.backing_allocator.free(real_pointer)?;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
@@ -156,7 +156,7 @@ fn void*! TempAllocator._realloc(TempAllocator* this, void* pointer, usz size, u
|
||||
}
|
||||
|
||||
// TODO optimize last allocation
|
||||
TempAllocatorChunk* data = this._alloc(size, alignment, offset, size > chunk.size)!;
|
||||
TempAllocatorChunk* data = this._alloc(size, alignment, offset, size > chunk.size)?;
|
||||
mem::copy(data, pointer, chunk.size, mem::DEFAULT_MEM_ALIGNMENT, mem::DEFAULT_MEM_ALIGNMENT);
|
||||
|
||||
return data;
|
||||
@@ -200,11 +200,11 @@ fn void*! TempAllocator._alloc(TempAllocator* this, usz size, usz alignment, usz
|
||||
usz total_alloc_size = TempAllocatorPage.sizeof + size;
|
||||
if (clear)
|
||||
{
|
||||
page = this.backing_allocator.calloc_aligned(total_alloc_size, alignment, TempAllocatorPage.sizeof + offset)!;
|
||||
page = this.backing_allocator.calloc_aligned(total_alloc_size, alignment, TempAllocatorPage.sizeof + offset)?;
|
||||
}
|
||||
else
|
||||
{
|
||||
page = this.backing_allocator.alloc_aligned(total_alloc_size, alignment, TempAllocatorPage.sizeof + offset)!;
|
||||
page = this.backing_allocator.alloc_aligned(total_alloc_size, alignment, TempAllocatorPage.sizeof + offset)?;
|
||||
}
|
||||
page.start = page;
|
||||
page.size = size | PAGE_IS_ALIGNED;
|
||||
@@ -214,7 +214,7 @@ fn void*! TempAllocator._alloc(TempAllocator* this, usz size, usz alignment, usz
|
||||
// Here we might need to pad
|
||||
usz padded_header_size = mem::aligned_offset(TempAllocatorPage.sizeof, mem::DEFAULT_MEM_ALIGNMENT);
|
||||
usz total_alloc_size = padded_header_size + size;
|
||||
void* alloc = (clear ? this.backing_allocator.calloc(total_alloc_size) : this.backing_allocator.alloc(total_alloc_size))!;
|
||||
void* alloc = (clear ? this.backing_allocator.calloc(total_alloc_size) : this.backing_allocator.alloc(total_alloc_size))?;
|
||||
|
||||
// Find the page.
|
||||
page = alloc + padded_header_size - TempAllocatorPage.sizeof;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
module std::core::mem::allocator;
|
||||
import std::collections::map;
|
||||
|
||||
def PtrMap = HashMap<uptr, usz>;
|
||||
typedef PtrMap = HashMap<uptr, usz>;
|
||||
|
||||
// A simple tracking allocator.
|
||||
// It tracks allocations using a hash map but
|
||||
@@ -24,10 +24,10 @@ struct TrackingAllocator
|
||||
*
|
||||
* @require this != null
|
||||
**/
|
||||
fn void TrackingAllocator.init(TrackingAllocator* this, Allocator* using)
|
||||
fn void TrackingAllocator.init(TrackingAllocator* this, Allocator* allocator)
|
||||
{
|
||||
*this = { .inner_allocator = using, .allocator.function = &tracking_allocator_fn };
|
||||
this.map.init(.using = using);
|
||||
*this = { .inner_allocator = allocator, .allocator.function = &tracking_allocator_fn };
|
||||
this.map.init(.using = allocator);
|
||||
}
|
||||
|
||||
fn void TrackingAllocator.free(TrackingAllocator* this)
|
||||
@@ -43,7 +43,7 @@ fn void TrackingAllocator.free(TrackingAllocator* this)
|
||||
fn void*! tracking_allocator_fn(Allocator* data, usz size, usz alignment, usz offset, void* old_pointer, AllocationKind kind) @private
|
||||
{
|
||||
TrackingAllocator* this = (TrackingAllocator*)data;
|
||||
void* result = this.inner_allocator.function(this.inner_allocator, size, alignment, offset, old_pointer, kind)!;
|
||||
void* result = this.inner_allocator.function(this.inner_allocator, size, alignment, offset, old_pointer, kind)?;
|
||||
switch (kind)
|
||||
{
|
||||
case CALLOC:
|
||||
|
||||
@@ -1,50 +1,9 @@
|
||||
module std::core::array;
|
||||
|
||||
/**
|
||||
* @param [in] array
|
||||
* @param [in] element
|
||||
* @return "the first index of the element"
|
||||
* @return! SearchResult.MISSING
|
||||
**/
|
||||
macro index_of(array, element)
|
||||
{
|
||||
foreach (i, &e : array)
|
||||
{
|
||||
if (*e == element) return i;
|
||||
}
|
||||
return SearchResult.MISSING?;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [in] array
|
||||
* @param [in] element
|
||||
* @return "the last index of the element"
|
||||
* @return! SearchResult.MISSING
|
||||
**/
|
||||
macro rindex_of(array, element)
|
||||
{
|
||||
foreach_r (i, &e : array)
|
||||
{
|
||||
if (*e == element) return i;
|
||||
}
|
||||
return SearchResult.MISSING?;
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenate two arrays or subarrays, returning a subarray containing the concatenation of them.
|
||||
*
|
||||
* @param [in] arr1
|
||||
* @param [in] arr2
|
||||
* @param [&inout] using "The allocator to use, default is the heap allocator"
|
||||
* @require @typekind(arr1) == SUBARRAY || @typekind(arr1) == ARRAY
|
||||
* @require @typekind(arr2) == SUBARRAY || @typekind(arr2) == ARRAY
|
||||
* @require @typeis(arr1[0], $typeof(arr2[0])) "Arrays must have the same type"
|
||||
* @ensure result.len == arr1.len + arr2.len
|
||||
**/
|
||||
macro concat(arr1, arr2, Allocator* using = mem::heap())
|
||||
macro tconcat(arr1, arr2)
|
||||
{
|
||||
var $Type = $typeof(arr1[0]);
|
||||
$Type[] result = malloc($Type, arr1.len + arr2.len, .using = using);
|
||||
$Type[] result = array::talloc($Type, arr1.len + arr2.len);
|
||||
if (arr1.len > 0)
|
||||
{
|
||||
mem::copy(result.ptr, &arr1[0], arr1.len * $Type.sizeof, $Type.alignof, $Type.alignof);
|
||||
@@ -56,15 +15,26 @@ macro concat(arr1, arr2, Allocator* using = mem::heap())
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Concatenate two arrays or subarrays, returning a subarray containing the concatenation of them,
|
||||
* allocated using the temp allocator.
|
||||
*
|
||||
* @param [in] arr1
|
||||
* @param [in] arr2
|
||||
* @require @typekind(arr1) == SUBARRAY || @typekind(arr1) == ARRAY
|
||||
* @require @typekind(arr2) == SUBARRAY || @typekind(arr2) == ARRAY
|
||||
* @require @typeis(arr1[0], $typeof(arr2[0])) "Arrays must have the same type"
|
||||
* @ensure result.len == arr1.len + arr2.len
|
||||
**/
|
||||
macro tconcat(arr1, arr2) => concat(arr1, arr2, mem::temp());
|
||||
macro index_of(array, element)
|
||||
{
|
||||
foreach (i, &e : array)
|
||||
{
|
||||
if (*e == element) return i;
|
||||
}
|
||||
return SearchResult.MISSING!;
|
||||
}
|
||||
|
||||
macro concat(arr1, arr2)
|
||||
{
|
||||
var $Type = $typeof(arr1[0]);
|
||||
$Type[] result = array::alloc($Type, arr1.len + arr2.len);
|
||||
if (arr1.len > 0)
|
||||
{
|
||||
mem::copy(result.ptr, &arr1[0], arr1.len * $Type.sizeof, $Type.alignof, $Type.alignof);
|
||||
}
|
||||
if (arr2.len > 0)
|
||||
{
|
||||
mem::copy(&result[arr1.len], &arr2[0], arr2.len * $Type.sizeof, $Type.alignof, $Type.alignof);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -1,12 +1,5 @@
|
||||
// Copyright (c) 2023 Christoffer Lerno and contributors. 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::bitorder;
|
||||
|
||||
// This module contains types of different endianness.
|
||||
// *BE types represent big-endian types
|
||||
// *LE types represent little-endian types.
|
||||
|
||||
bitstruct ShortBE : short @bigendian
|
||||
{
|
||||
short val : 0..15;
|
||||
|
||||
@@ -5,26 +5,17 @@ module std::core::builtin;
|
||||
import libc;
|
||||
import std::hash;
|
||||
|
||||
/**
|
||||
* Use `IteratorResult` when reading the end of an iterator, or accessing a result out of bounds.
|
||||
**/
|
||||
fault IteratorResult
|
||||
{
|
||||
NO_MORE_ELEMENT
|
||||
}
|
||||
|
||||
/**
|
||||
* Use `SearchResult` when trying to return a value from some collection but the element is missing.
|
||||
**/
|
||||
fault SearchResult
|
||||
{
|
||||
MISSING
|
||||
}
|
||||
|
||||
/**
|
||||
* Use `CastResult` when an attempt at conversion fails.
|
||||
**/
|
||||
fault CastResult
|
||||
fault VarCastResult
|
||||
{
|
||||
TYPE_MISMATCH
|
||||
}
|
||||
@@ -42,9 +33,6 @@ macro void @scope(&variable; @body) @builtin
|
||||
@body();
|
||||
}
|
||||
|
||||
/**
|
||||
* Swap two variables
|
||||
**/
|
||||
macro void @swap(&a, &b) @builtin
|
||||
{
|
||||
var temp = a;
|
||||
@@ -53,17 +41,15 @@ macro void @swap(&a, &b) @builtin
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an `any` type to a type, returning an failure if there is a type mismatch.
|
||||
* Convert a variant type to a type, returning an failure if there is a type mismatch.
|
||||
*
|
||||
* @param v `the any to convert to the given type.`
|
||||
* @param v `the variant to convert to the given type.`
|
||||
* @param $Type `the type to convert to`
|
||||
* @return `The any.ptr converted to its type.`
|
||||
* @ensure @typeis(return, $Type*)
|
||||
* @return! CastResult.TYPE_MISMATCH
|
||||
* @return `The variant.ptr converted to its type.`
|
||||
**/
|
||||
macro anycast(any v, $Type) @builtin
|
||||
macro varcast(variant v, $Type) @builtin
|
||||
{
|
||||
if (v.type != $Type.typeid) return CastResult.TYPE_MISMATCH?;
|
||||
if (v.type != $Type.typeid) return VarCastResult.TYPE_MISMATCH!;
|
||||
return ($Type*)v.ptr;
|
||||
}
|
||||
|
||||
@@ -78,24 +64,22 @@ struct CallstackElement
|
||||
fn void default_panic(String message, String file, String function, uint line)
|
||||
{
|
||||
CallstackElement* stack = $$stacktrace();
|
||||
$if $defined(io::stderr) && $defined(File.printf):
|
||||
$if ($defined(libc::stderr) && $defined(libc::fprintf))
|
||||
|
||||
if (stack) stack = stack.prev;
|
||||
if (stack)
|
||||
{
|
||||
(void)io::stderr().print("\nERROR: '");
|
||||
(void)io::stderr().print(message);
|
||||
(void)io::stderr().printn("'");
|
||||
libc::fprintf(libc::stderr(), "\nERROR: '%.*s'\n", (int)message.len, message.ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
(void)io::stderr().print("\nERROR: '");
|
||||
(void)io::stderr().print(message);
|
||||
(void)io::stderr().printfn("', in function %s (%s:%d)", function, file, line);
|
||||
libc::fprintf(libc::stderr(), "\nERROR: '%.*s', function %.*s (%.*s:%d)\n",
|
||||
(int)message.len, message.ptr, (int)function.len, function.ptr, (int)file.len, file.ptr, line);
|
||||
}
|
||||
while (stack)
|
||||
{
|
||||
(void)io::stderr().printfn(" in function %s (%s:%d)", stack.function, stack.file, stack.line);
|
||||
libc::fprintf(libc::stderr(), " at function %.*s (%.*s:%u)\n", (int)stack.function.len, stack.function.ptr,
|
||||
(int)stack.file.len, stack.file.ptr, stack.line);
|
||||
if (stack == stack.prev) break;
|
||||
stack = stack.prev;
|
||||
}
|
||||
@@ -104,117 +88,66 @@ fn void default_panic(String message, String file, String function, uint line)
|
||||
$$trap();
|
||||
}
|
||||
|
||||
def PanicFn = fn void(String message, String file, String function, uint line);
|
||||
typedef PanicFn = fn void(String message, String file, String function, uint line);
|
||||
|
||||
PanicFn panic = &default_panic;
|
||||
|
||||
fn void panicf(String fmt, String file, String function, uint line, args...)
|
||||
macro void unreachable($string = "Unreachable statement reached.") @builtin @noreturn
|
||||
{
|
||||
@stack_mem(512; Allocator* mem)
|
||||
{
|
||||
DString s;
|
||||
s.init(.using = mem);
|
||||
s.printf(fmt, ...args);
|
||||
panic(s.str(), file, function, line);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the path as unreachable. This will panic in safe mode, and in fast will simply be assumed
|
||||
* never happens.
|
||||
* @param [in] string "The panic message or format string"
|
||||
**/
|
||||
macro void unreachable(String string = "Unreachable statement reached.", ...) @builtin @noreturn
|
||||
{
|
||||
panicf(string, $$FILE, $$FUNC, $$LINE, $vasplat());
|
||||
panic($string, $$FILE, $$FUNC, $$LINE);
|
||||
$$unreachable();
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the path as unsupported, this is similar to unreachable.
|
||||
* @param [in] string "The error message"
|
||||
**/
|
||||
macro void unsupported(String string = "Unsupported function invoked") @builtin @noreturn
|
||||
{
|
||||
panicf(string, $$FILE, $$FUNC, $$LINE, $vasplat());
|
||||
$$unreachable();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param expr "the expression to cast"
|
||||
* @param $Type "the type to cast to"
|
||||
*
|
||||
* @require $sizeof(expr) == $Type.sizeof "Cannot bitcast between types of different size."
|
||||
* @ensure @typeis(result, $Type)
|
||||
**/
|
||||
macro bitcast(expr, $Type) @builtin
|
||||
{
|
||||
usz $size = $sizeof(expr);
|
||||
var $size = (usz)($sizeof(expr));
|
||||
$assert($size == $Type.sizeof, "Cannot bitcast between types of different size.");
|
||||
$Type x @noinit;
|
||||
mem::copy(&x, &expr, $size, $Type.alignof, $alignof(expr));
|
||||
return x;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $Type `The type of the enum`
|
||||
* @param [in] enum_name `The name of the enum to search for`
|
||||
* @require $Type.kindof == ENUM `Only enums may be used`
|
||||
* @ensure @typeis(return, $Type)
|
||||
* @return! SearchResult.MISSING
|
||||
* @require $Type.kindof == TypeKind.ENUM `Only enums may be used`
|
||||
**/
|
||||
macro enum_by_name($Type, String enum_name) @builtin
|
||||
{
|
||||
typeid x = $Type.typeid;
|
||||
foreach (i, name : x.names)
|
||||
{
|
||||
if (name == enum_name) return ($Type)i;
|
||||
if (str::compare(name, enum_name)) return ($Type)i;
|
||||
}
|
||||
return SearchResult.MISSING?;
|
||||
return SearchResult.MISSING!;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark an expression as likely to be true
|
||||
*
|
||||
* @param #value "expression to be marked likely"
|
||||
* @param $probability "in the range 0 - 1"
|
||||
* @require $probability >= 0 && $probability <= 1.0
|
||||
**/
|
||||
macro bool @likely(bool #value, $probability = 1.0) @builtin
|
||||
macro bool @likely(bool value, $probability = 1.0) @builtin
|
||||
{
|
||||
$if $probability == 1.0:
|
||||
return $$expect(#value, true);
|
||||
$else
|
||||
return $$expect_with_probability(#value, true, $probability);
|
||||
$endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark an expression as unlikely to be true
|
||||
*
|
||||
* @param #value "expression to be marked unlikely"
|
||||
* @param $probability "in the range 0 - 1"
|
||||
* @require $probability >= 0 && $probability <= 1.0
|
||||
**/
|
||||
macro bool @unlikely(bool #value, $probability = 1.0) @builtin
|
||||
{
|
||||
$if $probability == 1.0:
|
||||
return $$expect(#value, false);
|
||||
$else
|
||||
return $$expect_with_probability(#value, false, $probability);
|
||||
$endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @require values::@is_int(#value) || values::@is_bool(#value)
|
||||
* @checked $typeof(#value) a = expected
|
||||
* @require $probability >= 0 && $probability <= 1.0
|
||||
**/
|
||||
macro @expect(#value, expected, $probability = 1.0) @builtin
|
||||
{
|
||||
$if $probability == 1.0:
|
||||
return $$expect(#value, ($typeof(#value))expected);
|
||||
$if ($probability == 1.0)
|
||||
return $$expect(value, true);
|
||||
$else
|
||||
return $$expect_with_probability(#value, expected, $probability);
|
||||
return $$expect_with_probability(value, true, $probability);
|
||||
$endif
|
||||
}
|
||||
|
||||
macro bool @unlikely(bool value, $probability = 1.0) @builtin
|
||||
{
|
||||
$if ($probability == 1.0)
|
||||
return $$expect(value, false);
|
||||
$else
|
||||
return $$expect_with_probability(value, false, $probability);
|
||||
$endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @require values::@is_int(value) || values::@is_bool(value)
|
||||
* @checked $typeof(value) a = expected
|
||||
**/
|
||||
macro @expect(value, expected, $probability = 1.0) @builtin
|
||||
{
|
||||
$if ($probability == 1.0)
|
||||
return $$expect(value, ($typeof(value))expected);
|
||||
$else
|
||||
return $$expect_with_probability(value, expected, $probability);
|
||||
$endif
|
||||
}
|
||||
|
||||
@@ -262,18 +195,6 @@ macro bool @convertible(#expr, $To) @builtin
|
||||
return $checks($To x = #expr);
|
||||
}
|
||||
|
||||
macro anyfault @catchof(#expr) @builtin
|
||||
{
|
||||
if (catch f = #expr) return f;
|
||||
return anyfault {};
|
||||
}
|
||||
|
||||
macro bool @ok(#expr) @builtin
|
||||
{
|
||||
if (catch #expr) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
macro uint int.hash(int i) => i;
|
||||
macro uint uint.hash(uint i) => i;
|
||||
macro uint short.hash(short s) => s;
|
||||
@@ -282,9 +203,7 @@ 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 typeid.hash(typeid t) => (uint)(((uptr)t >> 32) ^ (uptr)t);
|
||||
macro uint String.hash(String c) => (uint)fnv32a::encode(c);
|
||||
macro uint char[].hash(char[] c) => (uint)fnv32a::encode(c);
|
||||
@@ -82,7 +82,7 @@ $endswitch
|
||||
|
||||
macro min(x, ...) @builtin
|
||||
{
|
||||
$if $vacount == 1:
|
||||
$if ($vacount == 1)
|
||||
return less(x, $vaarg(0)) ? x : $vaarg(0);
|
||||
$else
|
||||
var result = x;
|
||||
@@ -98,7 +98,7 @@ macro min(x, ...) @builtin
|
||||
|
||||
macro max(x, ...) @builtin
|
||||
{
|
||||
$if $vacount == 1:
|
||||
$if ($vacount == 1)
|
||||
return greater(x, $vaarg(0)) ? x : $vaarg(0);
|
||||
$else
|
||||
var result = x;
|
||||
|
||||
@@ -8,80 +8,80 @@ const C_LONG_SIZE = $$C_LONG_SIZE;
|
||||
const C_SHORT_SIZE = $$C_SHORT_SIZE;
|
||||
const C_LONG_LONG_SIZE = $$C_LONG_LONG_SIZE;
|
||||
|
||||
$assert C_SHORT_SIZE < 32;
|
||||
$assert C_INT_SIZE < 128;
|
||||
$assert C_LONG_SIZE < 128;
|
||||
$assert C_LONG_LONG_SIZE <= 128;
|
||||
$assert C_SHORT_SIZE <= C_INT_SIZE;
|
||||
$assert C_INT_SIZE <= C_LONG_SIZE;
|
||||
$assert C_LONG_SIZE <= C_LONG_LONG_SIZE;
|
||||
$assert (C_SHORT_SIZE < 32);
|
||||
$assert (C_INT_SIZE < 128);
|
||||
$assert (C_LONG_SIZE < 128);
|
||||
$assert (C_LONG_LONG_SIZE <= 128);
|
||||
$assert (C_SHORT_SIZE <= C_INT_SIZE);
|
||||
$assert (C_INT_SIZE <= C_LONG_SIZE);
|
||||
$assert (C_LONG_SIZE <= C_LONG_LONG_SIZE);
|
||||
|
||||
$switch ($$C_INT_SIZE)
|
||||
$case 64:
|
||||
def CInt = long;
|
||||
def CUInt = ulong;
|
||||
typedef CInt = long;
|
||||
typedef CUInt = ulong;
|
||||
$case 32:
|
||||
def CInt = int;
|
||||
def CUInt = uint;
|
||||
typedef CInt = int;
|
||||
typedef CUInt = uint;
|
||||
$case 16:
|
||||
def CInt = short;
|
||||
def CUInt = ushort;
|
||||
typedef CInt = short;
|
||||
typedef CUInt = ushort;
|
||||
$default:
|
||||
$error "Invalid C int size";
|
||||
$assert(false, "Invalid C int size");
|
||||
$endswitch
|
||||
|
||||
$switch ($$C_LONG_SIZE)
|
||||
$case 64:
|
||||
def CLong = long;
|
||||
def CULong = ulong;
|
||||
typedef CLong = long;
|
||||
typedef CULong = ulong;
|
||||
$case 32:
|
||||
def CLong = int;
|
||||
def CULong = uint;
|
||||
typedef CLong = int;
|
||||
typedef CULong = uint;
|
||||
$case 16:
|
||||
def CLong = short;
|
||||
def CULong = ushort;
|
||||
typedef CLong = short;
|
||||
typedef CULong = ushort;
|
||||
$default:
|
||||
$error "Invalid C long size";
|
||||
$assert(false, "Invalid C long size");
|
||||
$endswitch
|
||||
|
||||
$switch ($$C_SHORT_SIZE)
|
||||
$case 32:
|
||||
def CShort = int;
|
||||
def CUShort = uint;
|
||||
typedef CShort = int;
|
||||
typedef CUShort = uint;
|
||||
$case 16:
|
||||
def CShort = short;
|
||||
def CUShort = ushort;
|
||||
typedef CShort = short;
|
||||
typedef CUShort = ushort;
|
||||
$case 8:
|
||||
def CShort = ichar;
|
||||
def CUShort = char;
|
||||
typedef CShort = ichar;
|
||||
typedef CUShort = char;
|
||||
$default:
|
||||
$error "Invalid C short size";
|
||||
$assert(false, "Invalid C short size");
|
||||
$endswitch
|
||||
|
||||
$switch ($$C_LONG_LONG_SIZE)
|
||||
$case 128:
|
||||
def CLongLong = int128;
|
||||
def CULongLong = uint128;
|
||||
typedef CLongLong = int128;
|
||||
typedef CULongLong = uint128;
|
||||
$case 64:
|
||||
def CLongLong = long;
|
||||
def CULongLong = ulong;
|
||||
typedef CLongLong = long;
|
||||
typedef CULongLong = ulong;
|
||||
$case 32:
|
||||
def CLongLong = int;
|
||||
def CULongLong = uint;
|
||||
typedef CLongLong = int;
|
||||
typedef CULongLong = uint;
|
||||
$case 16:
|
||||
def CLongLong = short;
|
||||
def CULongLong = ushort;
|
||||
typedef CLongLong = short;
|
||||
typedef CULongLong = ushort;
|
||||
$default:
|
||||
$error "Invalid C long long size";
|
||||
$assert(false, "Invalid C long long size");
|
||||
$endswitch
|
||||
|
||||
|
||||
|
||||
def CSChar = ichar;
|
||||
def CUChar = char;
|
||||
typedef CSChar = ichar;
|
||||
typedef CUChar = char;
|
||||
|
||||
$if $$C_CHAR_IS_SIGNED:
|
||||
def CChar = ichar;
|
||||
$if ($$C_CHAR_IS_SIGNED)
|
||||
typedef CChar = ichar;
|
||||
$else
|
||||
def CChar = char;
|
||||
typedef CChar = char;
|
||||
$endif
|
||||
|
||||
@@ -16,25 +16,25 @@ const uint UTF16_SURROGATE_HIGH_VALUE @private = 0xD800;
|
||||
**/
|
||||
fn usz! char32_to_utf8(Char32 c, char* output, usz available)
|
||||
{
|
||||
if (!available) return UnicodeResult.CONVERSION_FAILED?;
|
||||
if (!available) return UnicodeResult.CONVERSION_FAILED!;
|
||||
switch (true)
|
||||
{
|
||||
case c <= 0x7f:
|
||||
output[0] = (char)c;
|
||||
return 1;
|
||||
case c <= 0x7ff:
|
||||
if (available < 2) return UnicodeResult.CONVERSION_FAILED?;
|
||||
if (available < 2) return UnicodeResult.CONVERSION_FAILED!;
|
||||
output[0] = (char)(0xC0 | c >> 6);
|
||||
output[1] = (char)(0x80 | (c & 0x3F));
|
||||
return 2;
|
||||
case c <= 0xffff:
|
||||
if (available < 3) return UnicodeResult.CONVERSION_FAILED?;
|
||||
if (available < 3) return UnicodeResult.CONVERSION_FAILED!;
|
||||
output[0] = (char)(0xE0 | c >> 12);
|
||||
output[1] = (char)(0x80 | (c >> 6 & 0x3F));
|
||||
output[2] = (char)(0x80 | (c & 0x3F));
|
||||
return 3;
|
||||
case c <= 0x10ffff:
|
||||
if (available < 4) return UnicodeResult.CONVERSION_FAILED?;
|
||||
if (available < 4) return UnicodeResult.CONVERSION_FAILED!;
|
||||
output[0] = (char)(0xF0 | c >> 18);
|
||||
output[1] = (char)(0x80 | (c >> 12 & 0x3F));
|
||||
output[2] = (char)(0x80 | (c >> 6 & 0x3F));
|
||||
@@ -42,7 +42,7 @@ fn usz! char32_to_utf8(Char32 c, char* output, usz available)
|
||||
return 4;
|
||||
default:
|
||||
// 0x10FFFF and above is not defined.
|
||||
return UnicodeResult.CONVERSION_FAILED?;
|
||||
return UnicodeResult.CONVERSION_FAILED!;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,15 +84,15 @@ fn void! char16_to_utf8_unsafe(Char16 *ptr, usz *available, char** output)
|
||||
return;
|
||||
}
|
||||
// Low surrogate first is an error
|
||||
if (high & UTF16_SURROGATE_MASK != UTF16_SURROGATE_HIGH_VALUE) return UnicodeResult.INVALID_UTF16?;
|
||||
if (high & UTF16_SURROGATE_MASK != UTF16_SURROGATE_HIGH_VALUE) return UnicodeResult.INVALID_UTF16!;
|
||||
|
||||
// Unmatched high surrogate is an error
|
||||
if (*available == 1) return UnicodeResult.INVALID_UTF16?;
|
||||
if (*available == 1) return UnicodeResult.INVALID_UTF16!;
|
||||
|
||||
Char16 low = ptr[1];
|
||||
|
||||
// Unmatched high surrogate, invalid
|
||||
if (low & UTF16_SURROGATE_MASK != UTF16_SURROGATE_LOW_VALUE) return UnicodeResult.INVALID_UTF16?;
|
||||
if (low & UTF16_SURROGATE_MASK != UTF16_SURROGATE_LOW_VALUE) return UnicodeResult.INVALID_UTF16!;
|
||||
|
||||
// The high bits of the codepoint are the value bits of the high surrogate
|
||||
// The low bits of the codepoint are the value bits of the low surrogate
|
||||
@@ -134,7 +134,7 @@ fn void char32_to_utf8_unsafe(Char32 c, char** output)
|
||||
fn Char32! utf8_to_char32(char* ptr, usz* size)
|
||||
{
|
||||
usz max_size = *size;
|
||||
if (max_size < 1) return UnicodeResult.INVALID_UTF8?;
|
||||
if (max_size < 1) return UnicodeResult.INVALID_UTF8!;
|
||||
char c = (ptr++)[0];
|
||||
|
||||
if ((c & 0x80) == 0)
|
||||
@@ -144,40 +144,40 @@ fn Char32! utf8_to_char32(char* ptr, usz* size)
|
||||
}
|
||||
if ((c & 0xE0) == 0xC0)
|
||||
{
|
||||
if (max_size < 2) return UnicodeResult.INVALID_UTF8?;
|
||||
if (max_size < 2) return UnicodeResult.INVALID_UTF8!;
|
||||
*size = 2;
|
||||
Char32 uc = (c & 0x1F) << 6;
|
||||
c = *ptr;
|
||||
// Overlong sequence or invalid second.
|
||||
if (!uc || c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8?;
|
||||
if (!uc || c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8!;
|
||||
return uc + c & 0x3F;
|
||||
}
|
||||
if ((c & 0xF0) == 0xE0)
|
||||
{
|
||||
if (max_size < 3) return UnicodeResult.INVALID_UTF8?;
|
||||
if (max_size < 3) return UnicodeResult.INVALID_UTF8!;
|
||||
*size = 3;
|
||||
Char32 uc = (c & 0x0F) << 12;
|
||||
c = ptr++[0];
|
||||
if (c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8?;
|
||||
if (c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8!;
|
||||
uc += (c & 0x3F) << 6;
|
||||
c = ptr++[0];
|
||||
// Overlong sequence or invalid last
|
||||
if (!uc || c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8?;
|
||||
if (!uc || c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8!;
|
||||
return uc + c & 0x3F;
|
||||
}
|
||||
if (max_size < 4) return UnicodeResult.INVALID_UTF8?;
|
||||
if ((c & 0xF8) != 0xF0) return UnicodeResult.INVALID_UTF8?;
|
||||
if (max_size < 4) return UnicodeResult.INVALID_UTF8!;
|
||||
if ((c & 0xF8) != 0xF0) return UnicodeResult.INVALID_UTF8!;
|
||||
*size = 4;
|
||||
Char32 uc = (c & 0x07) << 18;
|
||||
c = ptr++[0];
|
||||
if (c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8?;
|
||||
if (c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8!;
|
||||
uc += (c & 0x3F) << 12;
|
||||
c = ptr++[0];
|
||||
if (c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8?;
|
||||
if (c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8!;
|
||||
uc += (c & 0x3F) << 6;
|
||||
c = ptr++[0];
|
||||
// Overlong sequence or invalid last
|
||||
if (!uc || c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8?;
|
||||
if (!uc || c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8!;
|
||||
return uc + c & 0x3F;
|
||||
}
|
||||
|
||||
@@ -303,7 +303,7 @@ fn usz! utf32to8(Char32[] utf32, String utf8_buffer)
|
||||
char* ptr = utf8_buffer.ptr;
|
||||
foreach (Char32 uc : utf32)
|
||||
{
|
||||
usz used = char32_to_utf8(uc, ptr, len) @inline!;
|
||||
usz used = char32_to_utf8(uc, ptr, len) @inline?;
|
||||
len -= used;
|
||||
ptr += used;
|
||||
}
|
||||
@@ -327,9 +327,9 @@ fn usz! utf8to32(String utf8, Char32[] utf32_buffer)
|
||||
usz buf_len = utf32_buffer.len;
|
||||
for (usz i = 0; i < len;)
|
||||
{
|
||||
if (len32 == buf_len) return UnicodeResult.CONVERSION_FAILED?;
|
||||
if (len32 == buf_len) return UnicodeResult.CONVERSION_FAILED!;
|
||||
usz width = len - i;
|
||||
Char32 uc = utf8_to_char32(&utf8[i], &width) @inline!;
|
||||
Char32 uc = utf8_to_char32(&utf8[i], &width) @inline?;
|
||||
i += width;
|
||||
ptr[len32++] = uc;
|
||||
}
|
||||
@@ -352,7 +352,7 @@ fn void! utf16to8_unsafe(Char16[] utf16, char* utf8_buffer)
|
||||
for (usz i = 0; i < len16;)
|
||||
{
|
||||
usz available = len16 - i;
|
||||
char16_to_utf8_unsafe(&utf16[i], &available, &utf8_buffer) @inline!;
|
||||
char16_to_utf8_unsafe(&utf16[i], &available, &utf8_buffer) @inline?;
|
||||
i += available;
|
||||
}
|
||||
}
|
||||
@@ -371,7 +371,7 @@ fn void! utf8to32_unsafe(String utf8, Char32* utf32_buffer)
|
||||
for (usz i = 0; i < len;)
|
||||
{
|
||||
usz width = len - i;
|
||||
Char32 uc = utf8_to_char32(&utf8[i], &width) @inline!;
|
||||
Char32 uc = utf8_to_char32(&utf8[i], &width) @inline?;
|
||||
i += width;
|
||||
(utf32_buffer++)[0] = uc;
|
||||
}
|
||||
@@ -391,7 +391,7 @@ fn void! utf8to16_unsafe(String utf8, Char16* utf16_buffer)
|
||||
for (usz i = 0; i < len;)
|
||||
{
|
||||
usz width = len - i;
|
||||
Char32 uc = utf8_to_char32(&utf8[i], &width) @inline!;
|
||||
Char32 uc = utf8_to_char32(&utf8[i], &width) @inline?;
|
||||
char32_to_utf16_unsafe(uc, &utf16_buffer) @inline;
|
||||
i += width;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module std::core::dstring;
|
||||
|
||||
def DString = distinct void*;
|
||||
typedef DString = distinct void*;
|
||||
|
||||
const usz MIN_CAPACITY @private = 16;
|
||||
|
||||
@@ -261,7 +261,7 @@ fn void DString.append_chars(DString* this, String str)
|
||||
|
||||
fn Char32[] DString.copy_utf32(DString* this, Allocator* using = mem::heap())
|
||||
{
|
||||
return this.str().to_utf32(using) @inline!!;
|
||||
return str::utf8to32(this.str(), using) @inline!!;
|
||||
}
|
||||
|
||||
fn void DString.append_string(DString* this, DString str)
|
||||
@@ -308,7 +308,7 @@ macro void DString.append(DString* str, value)
|
||||
$case @convertible(value, String):
|
||||
str.append_chars(value);
|
||||
$default:
|
||||
$error "Unsupported type for append – use printf instead.";
|
||||
$assert(false, "Unsupported type for append – use printf instead.");
|
||||
$endswitch
|
||||
$endswitch
|
||||
}
|
||||
@@ -325,7 +325,7 @@ fn usz! DString.printfn(DString* str, String format, args...) @maydiscard
|
||||
{
|
||||
Formatter formatter;
|
||||
formatter.init(&out_string_append_fn, str);
|
||||
usz len = formatter.vprintf(format, args)!;
|
||||
usz len = formatter.vprintf(format, args)?;
|
||||
str.append('\n');
|
||||
return len + 1;
|
||||
}
|
||||
@@ -350,7 +350,7 @@ fn DString new_join(String[] s, String joiner, Allocator* using = mem::heap())
|
||||
|
||||
fn void! out_string_append_fn(char c, void* data) @private
|
||||
{
|
||||
DString* s = data;
|
||||
DynString* s = data;
|
||||
s.append_char(c);
|
||||
}
|
||||
|
||||
@@ -380,11 +380,11 @@ fn usz! DString.read_from_stream(DString* string, Stream* reader)
|
||||
if (reader.supports_available())
|
||||
{
|
||||
usz total_read = 0;
|
||||
while (usz available = reader.available()!)
|
||||
while (usz available = reader.available()?)
|
||||
{
|
||||
string.reserve(available);
|
||||
StringData* data = string.data();
|
||||
usz len = reader.read(data.chars[data.len..(data.capacity - 1)])!;
|
||||
usz len = reader.read(data.chars[data.len..(data.capacity - 1)])?;
|
||||
total_read += len;
|
||||
data.len += len;
|
||||
}
|
||||
@@ -397,7 +397,7 @@ fn usz! DString.read_from_stream(DString* string, Stream* reader)
|
||||
string.reserve(16);
|
||||
StringData* data = string.data();
|
||||
// Read into the rest of the buffer
|
||||
usz read = reader.read(data.chars[data.len..(data.capacity - 1)])!;
|
||||
usz read = reader.read(data.chars[data.len..(data.capacity - 1)])?;
|
||||
data.len += read;
|
||||
// Ok, we reached the end.
|
||||
if (read < 16) return total_read;
|
||||
|
||||
@@ -32,7 +32,7 @@ enum OsType
|
||||
KFREEBSD,
|
||||
LINUX,
|
||||
PS3,
|
||||
MACOS,
|
||||
MACOSX,
|
||||
NETBSD,
|
||||
OPENBSD,
|
||||
SOLARIS,
|
||||
@@ -130,14 +130,14 @@ const MemoryEnvironment MEMORY_ENV = (MemoryEnvironment)$$MEMORY_ENVIRONMENT;
|
||||
|
||||
macro bool os_is_win32()
|
||||
{
|
||||
return OS_TYPE == WIN32;
|
||||
return OS_TYPE == OsType.WIN32;
|
||||
}
|
||||
|
||||
macro bool os_is_darwin()
|
||||
{
|
||||
$switch (OS_TYPE)
|
||||
$case IOS:
|
||||
$case MACOS:
|
||||
$case MACOSX:
|
||||
$case TVOS:
|
||||
$case WATCHOS:
|
||||
return true;
|
||||
@@ -150,7 +150,7 @@ macro bool os_is_posix()
|
||||
{
|
||||
$switch (OS_TYPE)
|
||||
$case IOS:
|
||||
$case MACOS:
|
||||
$case MACOSX:
|
||||
$case NETBSD:
|
||||
$case LINUX:
|
||||
$case KFREEBSD:
|
||||
@@ -177,11 +177,11 @@ macro bool os_is_posix()
|
||||
**/
|
||||
fn String! get_var(String name)
|
||||
{
|
||||
$if COMPILER_LIBC_AVAILABLE && !os_is_win32():
|
||||
$if (COMPILER_LIBC_AVAILABLE && OS_TYPE != OsType.WIN32)
|
||||
@pool()
|
||||
{
|
||||
ZString val = libc::getenv(name.zstr_tcopy());
|
||||
return val ? val.as_str() : SearchResult.MISSING?;
|
||||
return val ? val.as_str() : SearchResult.MISSING!;
|
||||
};
|
||||
$else
|
||||
return "";
|
||||
@@ -196,7 +196,7 @@ $endif
|
||||
**/
|
||||
fn void set_var(String name, String value, bool overwrite = true)
|
||||
{
|
||||
$if COMPILER_LIBC_AVAILABLE && !os_is_win32():
|
||||
$if (COMPILER_LIBC_AVAILABLE && OS_TYPE != OsType.WIN32)
|
||||
@pool()
|
||||
{
|
||||
if (libc::setenv(name.zstr_tcopy(), value.zstr_copy(), (int)overwrite))
|
||||
@@ -213,7 +213,7 @@ $endif
|
||||
**/
|
||||
fn void clear_var(String name)
|
||||
{
|
||||
$if COMPILER_LIBC_AVAILABLE && !os_is_win32():
|
||||
$if (COMPILER_LIBC_AVAILABLE && OS_TYPE != OsType.WIN32)
|
||||
@pool()
|
||||
{
|
||||
if (libc::unsetenv(name.zstr_tcopy()))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module std::core::string;
|
||||
module std::core::str;
|
||||
import std::math;
|
||||
|
||||
// Float parsing based on code in Musl floatscan.c by Rich Felker.
|
||||
@@ -64,7 +64,7 @@ macro double! decfloat(char[] chars, int $bits, int $emin, int sign)
|
||||
got_rad = true;
|
||||
if (index == last_char)
|
||||
{
|
||||
if (!got_digit) return NumberConversion.MALFORMED_FLOAT?;
|
||||
if (!got_digit) return NumberConversion.MALFORMED_FLOAT!;
|
||||
return sign * 0.0;
|
||||
}
|
||||
if (index != last_char && (c = chars[++index]) == '0')
|
||||
@@ -83,7 +83,7 @@ macro double! decfloat(char[] chars, int $bits, int $emin, int sign)
|
||||
switch
|
||||
{
|
||||
case c == '.':
|
||||
if (got_rad) return NumberConversion.MALFORMED_FLOAT?;
|
||||
if (got_rad) return NumberConversion.MALFORMED_FLOAT!;
|
||||
got_rad = true;
|
||||
lrp = dc;
|
||||
case k < KMAX - 3:
|
||||
@@ -113,24 +113,24 @@ macro double! decfloat(char[] chars, int $bits, int $emin, int sign)
|
||||
c = chars[++index];
|
||||
}
|
||||
if (!got_rad) lrp = dc;
|
||||
if (!got_digit) return NumberConversion.MALFORMED_FLOAT?;
|
||||
if (!got_digit) return NumberConversion.MALFORMED_FLOAT!;
|
||||
if ((c | 32) == 'e')
|
||||
{
|
||||
if (last_char == index) return NumberConversion.MALFORMED_FLOAT?;
|
||||
long e10 = String.to_long((String)chars[index + 1..]) ?? NumberConversion.MALFORMED_FLOAT?!;
|
||||
if (last_char == index) return NumberConversion.MALFORMED_FLOAT!;
|
||||
long e10 = str::to_long((String)chars[index + 1..]) ?? NumberConversion.MALFORMED_FLOAT!?;
|
||||
lrp += e10;
|
||||
}
|
||||
else if (index != last_char)
|
||||
{
|
||||
return NumberConversion.MALFORMED_FLOAT?;
|
||||
return NumberConversion.MALFORMED_FLOAT!;
|
||||
}
|
||||
// Handle zero specially to avoid nasty special cases later
|
||||
if (!x[0]) return sign * 0.0;
|
||||
|
||||
// Optimize small integers (w/no exponent) and over/under-flow
|
||||
if (lrp == dc && dc < 10 && ($bits > 30 || (ulong)x[0] >> $bits == 0)) return sign * (double)x[0];
|
||||
if (lrp > - $emin / 2) return NumberConversion.FLOAT_OUT_OF_RANGE?;
|
||||
if (lrp < $emin - 2 * math::DOUBLE_MANT_DIG) return NumberConversion.FLOAT_OUT_OF_RANGE?;
|
||||
if (lrp > - $emin / 2) return NumberConversion.FLOAT_OUT_OF_RANGE!;
|
||||
if (lrp < $emin - 2 * math::DOUBLE_MANT_DIG) return NumberConversion.FLOAT_OUT_OF_RANGE!;
|
||||
|
||||
// Align incomplete final B1B digit
|
||||
if (j)
|
||||
@@ -320,7 +320,7 @@ macro double! decfloat(char[] chars, int $bits, int $emin, int sign)
|
||||
y *= 0.5;
|
||||
e2++;
|
||||
}
|
||||
if (e2 + math::DOUBLE_MANT_DIG > emax || (denormal && frac)) return NumberConversion.MALFORMED_FLOAT?;
|
||||
if (e2 + math::DOUBLE_MANT_DIG > emax || (denormal && frac)) return NumberConversion.MALFORMED_FLOAT!;
|
||||
}
|
||||
return math::scalbn(y, e2);
|
||||
}
|
||||
@@ -351,7 +351,7 @@ macro double! hexfloat(char[] chars, int $bits, int $emin, int sign)
|
||||
got_rad = true;
|
||||
if (index == last_char)
|
||||
{
|
||||
if (!got_digit) return NumberConversion.MALFORMED_FLOAT?;
|
||||
if (!got_digit) return NumberConversion.MALFORMED_FLOAT!;
|
||||
return sign * 0.0;
|
||||
}
|
||||
if (index != last_char && (c = chars[++index]) == '0')
|
||||
@@ -369,7 +369,7 @@ macro double! hexfloat(char[] chars, int $bits, int $emin, int sign)
|
||||
{
|
||||
if (c == '.')
|
||||
{
|
||||
if (got_rad) return NumberConversion.MALFORMED_FLOAT?;
|
||||
if (got_rad) return NumberConversion.MALFORMED_FLOAT!;
|
||||
got_rad = true;
|
||||
rp = dc;
|
||||
}
|
||||
@@ -396,20 +396,20 @@ macro double! hexfloat(char[] chars, int $bits, int $emin, int sign)
|
||||
if (index == last_char) break;
|
||||
c = chars[++index];
|
||||
}
|
||||
if (!got_digit) return NumberConversion.MALFORMED_FLOAT?;
|
||||
if (!got_digit) return NumberConversion.MALFORMED_FLOAT!;
|
||||
if (!got_rad) rp = dc;
|
||||
for (; dc < 8; dc++) x *= 16;
|
||||
|
||||
long e2;
|
||||
if ((c | 32) == 'p')
|
||||
{
|
||||
long e2val = String.to_long((String)chars[index + 1..]) ?? (NumberConversion.MALFORMED_FLOAT?)!;
|
||||
long e2val = str::to_long((String)chars[index + 1..]) ?? NumberConversion.MALFORMED_FLOAT!?;
|
||||
e2 = e2val;
|
||||
}
|
||||
e2 += 4 * rp - 32;
|
||||
if (!x) return sign * 0.0;
|
||||
if (e2 > -$emin) return NumberConversion.FLOAT_OUT_OF_RANGE?;
|
||||
if (e2 < $emin - 2 * math::DOUBLE_MANT_DIG) return NumberConversion.FLOAT_OUT_OF_RANGE?;
|
||||
if (e2 > -$emin) return NumberConversion.FLOAT_OUT_OF_RANGE!;
|
||||
if (e2 < $emin - 2 * math::DOUBLE_MANT_DIG) return NumberConversion.FLOAT_OUT_OF_RANGE!;
|
||||
|
||||
while (x < 0x80000000)
|
||||
{
|
||||
@@ -444,12 +444,12 @@ macro double! hexfloat(char[] chars, int $bits, int $emin, int sign)
|
||||
}
|
||||
y = bias + sign * (double)x + sign * y;
|
||||
y -= bias;
|
||||
if (!y) return NumberConversion.FLOAT_OUT_OF_RANGE?;
|
||||
if (!y) return NumberConversion.FLOAT_OUT_OF_RANGE!;
|
||||
|
||||
return math::scalbn(y, (int)e2);
|
||||
}
|
||||
|
||||
macro String.to_real(String chars, $Type) @private
|
||||
macro floatparse(String chars, $Type) @private
|
||||
{
|
||||
int sign = 1;
|
||||
$switch ($Type)
|
||||
@@ -460,13 +460,13 @@ macro String.to_real(String chars, $Type) @private
|
||||
const int BITS = math::DOUBLE_MANT_DIG;
|
||||
const int EMIN = math::DOUBLE_MIN_EXP - BITS;
|
||||
$case float128:
|
||||
$error "Not yet supported";
|
||||
$assert(false, "Not yet supported");
|
||||
$default:
|
||||
$error "Unexpected type";
|
||||
$assert(false, "Unexpected type");
|
||||
$endswitch
|
||||
|
||||
while (chars.len && chars[0] == ' ') chars = chars[1..];
|
||||
if (!chars.len) return NumberConversion.MALFORMED_FLOAT?;
|
||||
if (!chars.len) return NumberConversion.MALFORMED_FLOAT!;
|
||||
switch (chars[0])
|
||||
{
|
||||
case '-':
|
||||
@@ -91,7 +91,7 @@ fn bool ptr_is_aligned(void* ptr, usz alignment) @inline
|
||||
|
||||
macro void clear(void* dst, usz len, usz $dst_align = 0, bool $is_volatile = false, bool $inlined = false)
|
||||
{
|
||||
$if $inlined:
|
||||
$if ($inlined)
|
||||
$$memset_inline(dst, (char)0, len, $is_volatile, $dst_align);
|
||||
$else
|
||||
$$memset(dst, (char)0, len, $is_volatile, $dst_align);
|
||||
@@ -100,7 +100,7 @@ macro void clear(void* dst, usz len, usz $dst_align = 0, bool $is_volatile = fal
|
||||
|
||||
macro void copy(void* dst, void* src, usz len, usz $dst_align = 0, usz $src_align = 0, bool $is_volatile = false, bool $inlined = false)
|
||||
{
|
||||
$if $inlined:
|
||||
$if ($inlined)
|
||||
$$memcpy_inline(dst, src, len, $is_volatile, $dst_align, $src_align);
|
||||
$else
|
||||
$$memcpy(dst, src, len, $is_volatile, $dst_align, $src_align);
|
||||
@@ -114,7 +114,7 @@ macro void move(void* dst, void* src, usz len, usz $dst_align = 0, usz $src_alig
|
||||
|
||||
macro void set(void* dst, char val, usz len, usz $dst_align = 0, bool $is_volatile = false, bool $inlined = false)
|
||||
{
|
||||
$if $inlined:
|
||||
$if ($inlined)
|
||||
$$memset_inline(dst, val, len, $is_volatile, $dst_align);
|
||||
$else
|
||||
$$memset(dst, val, len, $is_volatile, $dst_align);
|
||||
@@ -130,12 +130,12 @@ macro void set(void* dst, char val, usz len, usz $dst_align = 0, bool $is_volati
|
||||
**/
|
||||
macro bool equals(a, b, isz len = -1, usz $align = 0)
|
||||
{
|
||||
$if !$align:
|
||||
$if (!$align)
|
||||
$align = $typeof(a[0]).alignof;
|
||||
$endif
|
||||
void* x @noinit;
|
||||
void* y @noinit;
|
||||
$if values::@inner_kind(a) == TypeKind.SUBARRAY:
|
||||
$if (values::@inner_kind(a) == TypeKind.SUBARRAY)
|
||||
len = a.len;
|
||||
if (len != b.len) return false;
|
||||
x = a.ptr;
|
||||
@@ -206,10 +206,10 @@ macro malloc(..., Allocator* using = mem::heap(), usz end_padding = 0) @builtin
|
||||
**/
|
||||
macro malloc_checked(..., Allocator* using = mem::heap(), usz end_padding = 0) @builtin
|
||||
{
|
||||
$if $checks($vatype(0).sizeof):
|
||||
$if ($checks($vatype(0).sizeof))
|
||||
var $Type = $vatype(0);
|
||||
$assert !type_alloc_must_be_aligned($vatype(0)) : "Type must be allocated with malloc_aligned";
|
||||
$if $vacount == 2:
|
||||
$assert(!type_alloc_must_be_aligned($vatype(0)), "Type must be allocated with malloc_aligned");
|
||||
$if ($vacount == 2)
|
||||
usz size = $vaarg(1);
|
||||
return (($Type*)using.alloc($Type.sizeof * size + end_padding))[:size];
|
||||
$else
|
||||
@@ -228,9 +228,9 @@ macro malloc_checked(..., Allocator* using = mem::heap(), usz end_padding = 0) @
|
||||
**/
|
||||
macro malloc_aligned(..., usz alignment = 0, usz end_padding = 0, Allocator* using = mem::heap()) @builtin
|
||||
{
|
||||
$if $checks($vatype(0).sizeof):
|
||||
$if ($checks($vatype(0).sizeof))
|
||||
var $Type = $vatype(0);
|
||||
$if $vacount == 2:
|
||||
$if ($vacount == 2)
|
||||
usz size = $vaarg(1);
|
||||
return (($Type*)using.alloc_aligned($Type.sizeof * size + end_padding, alignment))[:size];
|
||||
$else
|
||||
@@ -241,6 +241,10 @@ macro malloc_aligned(..., usz alignment = 0, usz end_padding = 0, Allocator* usi
|
||||
$endif
|
||||
}
|
||||
|
||||
macro alloc($Type) @deprecated => malloc($Type);
|
||||
|
||||
macro char[] alloc_bytes(usz bytes) @deprecated => malloc(char, bytes);
|
||||
|
||||
/**
|
||||
* @require $vacount > 0 && $vacount < 3 "Expected size, type, or type + len"
|
||||
* @require $vacount != 2 || $checks($vatype(0).sizeof) "Expected 'malloc(Foo, 12)'"
|
||||
@@ -256,10 +260,10 @@ macro calloc(..., Allocator* using = mem::heap(), usz end_padding = 0) @builtin
|
||||
**/
|
||||
macro calloc_checked(..., Allocator* using = mem::heap(), usz end_padding = 0) @builtin
|
||||
{
|
||||
$if $checks($vatype(0).sizeof):
|
||||
$if ($checks($vatype(0).sizeof))
|
||||
var $Type = $vatype(0);
|
||||
$assert !type_alloc_must_be_aligned($vatype(0)) : "Type must be allocated with calloc_aligned";
|
||||
$if $vacount == 2:
|
||||
$assert(!type_alloc_must_be_aligned($vatype(0)), "Type must be allocated with calloc_aligned");
|
||||
$if ($vacount == 2)
|
||||
usz size = $vaarg(1);
|
||||
return (($Type*)using.calloc($Type.sizeof * size + end_padding))[:size];
|
||||
$else
|
||||
@@ -278,9 +282,9 @@ macro calloc_checked(..., Allocator* using = mem::heap(), usz end_padding = 0) @
|
||||
**/
|
||||
macro calloc_aligned(..., usz alignment = 0, Allocator* using = mem::heap(), usz end_padding = 0) @builtin
|
||||
{
|
||||
$if $checks($vatype(0).sizeof):
|
||||
$if ($checks($vatype(0).sizeof))
|
||||
var $Type = $vatype(0);
|
||||
$if $vacount == 2:
|
||||
$if ($vacount == 2)
|
||||
usz size = $vaarg(1);
|
||||
return (($Type*)using.calloc_aligned($Type.sizeof * size + end_padding, alignment))[:size];
|
||||
$else
|
||||
@@ -325,15 +329,17 @@ macro void @scoped(Allocator* using; @body())
|
||||
@body();
|
||||
}
|
||||
|
||||
macro talloc($Type) @builtin @deprecated => tmalloc($Type);
|
||||
|
||||
/**
|
||||
* @require $vacount > 0 && $vacount < 3 "Expected size, type, or type + len"
|
||||
* @require $vacount != 2 || $checks($vatype(0).sizeof) "Expected 'malloc(Foo, 12)'"
|
||||
**/
|
||||
macro tmalloc(..., usz end_padding = 0, usz alignment = DEFAULT_MEM_ALIGNMENT) @builtin
|
||||
{
|
||||
$if $checks($vatype(0).sizeof):
|
||||
$if ($checks($vatype(0).sizeof))
|
||||
var $Type = $vatype(0);
|
||||
$if $vacount == 2:
|
||||
$if ($vacount == 2)
|
||||
usz size = $vaarg(1);
|
||||
return (($Type*)temp().alloc_aligned($Type.sizeof * size + end_padding, alignment))[:size]!!;
|
||||
$else
|
||||
@@ -350,9 +356,9 @@ macro tmalloc(..., usz end_padding = 0, usz alignment = DEFAULT_MEM_ALIGNMENT) @
|
||||
**/
|
||||
macro tcalloc(..., usz end_padding = 0, usz alignment = mem::DEFAULT_MEM_ALIGNMENT) @builtin
|
||||
{
|
||||
$if $checks($vatype(0).sizeof):
|
||||
$if ($checks($vatype(0).sizeof))
|
||||
var $Type = $vatype(0);
|
||||
$if $vacount == 2:
|
||||
$if ($vacount == 2)
|
||||
usz size = $vaarg(1);
|
||||
return (($Type*)temp().calloc_aligned($Type.sizeof * size + end_padding, alignment))[:size]!!;
|
||||
$else
|
||||
@@ -411,7 +417,7 @@ macro TempAllocator* temp()
|
||||
macro Allocator* current_allocator() => thread_allocator;
|
||||
macro Allocator* heap() => thread_allocator;
|
||||
|
||||
$if !env::COMPILER_LIBC_AVAILABLE && env::ARCH_TYPE == ArchType.WASM32 || env::ARCH_TYPE == ArchType.WASM64:
|
||||
$if (!env::COMPILER_LIBC_AVAILABLE && env::ARCH_TYPE == ArchType.WASM32 || env::ARCH_TYPE == ArchType.WASM64)
|
||||
|
||||
SimpleHeapAllocator wasm_allocator @private;
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ const DEFAULT_SIZE_PREFIX_ALIGNMENT = usz.alignof;
|
||||
const Allocator* NULL_ALLOCATOR = &_NULL_ALLOCATOR;
|
||||
const Allocator* LIBC_ALLOCATOR = &_SYSTEM_ALLOCATOR;
|
||||
|
||||
def AllocatorFunction = fn void*!(Allocator* allocator, usz new_size, usz alignment, usz offset, void* old_pointer, AllocationKind kind);
|
||||
typedef AllocatorFunction = fn void*!(Allocator* allocator, usz new_size, usz alignment, usz offset, void* old_pointer, AllocationKind kind);
|
||||
|
||||
struct Allocator
|
||||
{
|
||||
@@ -83,12 +83,12 @@ fn void*! Allocator.calloc_aligned(Allocator* allocator, usz size, usz alignment
|
||||
|
||||
fn void! Allocator.free(Allocator* allocator, void* old_pointer) @inline
|
||||
{
|
||||
allocator.function(allocator, 0, 0, 0, old_pointer, FREE)!;
|
||||
allocator.function(allocator, 0, 0, 0, old_pointer, FREE)?;
|
||||
}
|
||||
|
||||
fn void! Allocator.free_aligned(Allocator* allocator, void* old_pointer) @inline
|
||||
{
|
||||
allocator.function(allocator, 0, 0, 0, old_pointer, ALIGNED_FREE)!;
|
||||
allocator.function(allocator, 0, 0, 0, old_pointer, ALIGNED_FREE)?;
|
||||
}
|
||||
|
||||
fn void Allocator.reset(Allocator* allocator, usz mark = 0)
|
||||
|
||||
31
lib/std/core/mem_array.c3
Normal file
31
lib/std/core/mem_array.c3
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2021-2023 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::mem::array;
|
||||
|
||||
/**
|
||||
* @require usz.max / elements > $Type.sizeof
|
||||
**/
|
||||
macro alloc($Type, usz elements) @deprecated => malloc($Type, elements);
|
||||
|
||||
/**
|
||||
* @require usz.max / elements > $Type.sizeof
|
||||
**/
|
||||
macro talloc($Type, usz elements) @deprecated => tmalloc($Type, elements);
|
||||
|
||||
/**
|
||||
* @require (usz.max / elements > $Type.sizeof)
|
||||
**/
|
||||
macro make($Type, usz elements, Allocator* using = mem::heap()) @deprecated
|
||||
{
|
||||
return calloc($Type, elements, .using = using);
|
||||
}
|
||||
|
||||
/**
|
||||
* @require (usz.max / elements > $Type.sizeof)
|
||||
**/
|
||||
macro tmake($Type, usz elements) @deprecated
|
||||
{
|
||||
return tcalloc($Type, elements);
|
||||
}
|
||||
@@ -25,7 +25,7 @@ fn char[]! WasmMemory.allocate_block(WasmMemory* this, usz bytes)
|
||||
}
|
||||
|
||||
usz blocks_required = (bytes_required + WASM_BLOCK_SIZE + 1) / WASM_BLOCK_SIZE;
|
||||
if ($$wasm_memory_grow(0, blocks_required) == -1) return AllocationFailure.OUT_OF_MEMORY?;
|
||||
if ($$wasm_memory_grow(0, blocks_required) == -1) return AllocationFailure.OUT_OF_MEMORY!;
|
||||
this.allocation = $$wasm_memory_size(0) * WASM_BLOCK_SIZE;
|
||||
defer this.use += bytes;
|
||||
return ((char*)this.use)[:bytes];
|
||||
|
||||
@@ -7,11 +7,7 @@ macro usz _strlen(ptr) @private
|
||||
return len;
|
||||
}
|
||||
|
||||
macro int @main_to_err_main(#m, int, char**)
|
||||
{
|
||||
if (catch #m()) return 1;
|
||||
return 0;
|
||||
}
|
||||
macro int @main_to_err_main(#m, int, char**) => catch? #m() ? 1 : 0;
|
||||
macro int @main_to_int_main(#m, int, char**) => #m();
|
||||
macro int @main_to_void_main(#m, int, char**)
|
||||
{
|
||||
@@ -36,8 +32,7 @@ macro int @main_to_err_main_args(#m, int argc, char** argv)
|
||||
{
|
||||
String[] list = args_to_strings(argc, argv);
|
||||
defer free(list.ptr);
|
||||
if (catch #m(list)) return 1;
|
||||
return 0;
|
||||
return catch? #m(list) ? 1 : 0;
|
||||
}
|
||||
|
||||
macro int @main_to_int_main_args(#m, int argc, char** argv)
|
||||
@@ -55,7 +50,7 @@ macro int @main_to_void_main_args(#m, int argc, char** argv)
|
||||
return 0;
|
||||
}
|
||||
|
||||
$if env::os_is_win32():
|
||||
$if (env::OS_TYPE == OsType.WIN32)
|
||||
|
||||
extern fn Char16** _win_command_line_to_argv_w(ushort* cmd_line, int* argc_ptr) @extern("CommandLineToArgvW");
|
||||
|
||||
@@ -84,11 +79,7 @@ macro void release_wargs(String[] list) @private
|
||||
free(list.ptr);
|
||||
}
|
||||
|
||||
macro int @win_to_err_main_noargs(#m, void* handle, Char16* cmd_line, int show_cmd)
|
||||
{
|
||||
if (catch #m()) return 1;
|
||||
return 0;
|
||||
}
|
||||
macro int @win_to_err_main_noargs(#m, void* handle, Char16* cmd_line, int show_cmd) => catch? #m() ? 1 : 0;
|
||||
macro int @win_to_int_main_noargs(#m, void* handle, Char16* cmd_line, int show_cmd) => #m();
|
||||
macro int @win_to_void_main_noargs(#m, void* handle, Char16* cmd_line, int show_cmd)
|
||||
{
|
||||
@@ -100,8 +91,7 @@ macro int @win_to_err_main_args(#m, void* handle, Char16* cmd_line, int show_cmd
|
||||
{
|
||||
String[] args = win_command_line_to_strings(cmd_line);
|
||||
defer release_wargs(args);
|
||||
if (catch #m(args)) return 1;
|
||||
return 0;
|
||||
return catch? #m(args) ? 1 : 0;
|
||||
}
|
||||
|
||||
macro int @win_to_int_main_args(#m, void* handle, Char16* cmd_line, int show_cmd)
|
||||
@@ -123,8 +113,7 @@ macro int @win_to_err_main(#m, void* handle, Char16* cmd_line, int show_cmd)
|
||||
{
|
||||
String[] args = win_command_line_to_strings(cmd_line);
|
||||
defer release_wargs(args);
|
||||
if (catch #m(handle, args, show_cmd)) return 1;
|
||||
return 0;
|
||||
return catch? #m(handle, args, show_cmd) ? 1 : 0;
|
||||
}
|
||||
|
||||
macro int @win_to_int_main(#m, void* handle, Char16* cmd_line, int show_cmd)
|
||||
@@ -146,8 +135,7 @@ macro int @wmain_to_err_main_args(#m, int argc, Char16** argv)
|
||||
{
|
||||
String[] args = wargs_strings(argc, argv);
|
||||
defer release_wargs(args);
|
||||
if (catch #m(args)) return 1;
|
||||
return 1;
|
||||
return catch? #m(args) ? 1 : 0;
|
||||
}
|
||||
|
||||
macro int @wmain_to_int_main_args(#m, int argc, Char16** argv)
|
||||
|
||||
@@ -9,13 +9,26 @@ struct VirtualAny
|
||||
typeid type_id;
|
||||
}
|
||||
|
||||
struct VirtualContainer
|
||||
{
|
||||
void* ptr;
|
||||
void* impl_ptr;
|
||||
}
|
||||
|
||||
struct SubArrayContainer
|
||||
{
|
||||
void* ptr;
|
||||
usz len;
|
||||
}
|
||||
|
||||
def TestFn = fn void!();
|
||||
struct VarArrayHeader
|
||||
{
|
||||
usz size;
|
||||
usz capacity;
|
||||
void *allocator;
|
||||
}
|
||||
|
||||
typedef TestFn = fn void!();
|
||||
|
||||
struct TestRunner
|
||||
{
|
||||
@@ -35,13 +48,10 @@ fn TestRunner test_runner_create()
|
||||
import libc;
|
||||
|
||||
TestRunner* current_runner @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("\n Error: %s", message);
|
||||
io::printfn(" - in %s %s:%s.\n", function, file, line);
|
||||
libc::longjmp(¤t_runner.buf, 1);
|
||||
}
|
||||
@@ -88,7 +98,7 @@ fn bool __run_default_test_runner()
|
||||
return test_runner_create().run();
|
||||
}
|
||||
|
||||
$if !env::COMPILER_LIBC_AVAILABLE && env::ARCH_TYPE == ArchType.WASM32 || env::ARCH_TYPE == ArchType.WASM64:
|
||||
$if (!env::COMPILER_LIBC_AVAILABLE && env::ARCH_TYPE == ArchType.WASM32 || env::ARCH_TYPE == ArchType.WASM64)
|
||||
|
||||
extern fn void __wasm_call_ctors();
|
||||
fn void wasm_initialize() @extern("_initialize") @wasm
|
||||
|
||||
259
lib/std/core/str.c3
Normal file
259
lib/std/core/str.c3
Normal file
@@ -0,0 +1,259 @@
|
||||
module std::core::str;
|
||||
|
||||
fn VarString join(String[] s, String joiner)
|
||||
{
|
||||
if (!s.len) return (VarString)null;
|
||||
usz total_size = joiner.len * s.len;
|
||||
foreach (String* &str : s)
|
||||
{
|
||||
total_size += str.len;
|
||||
}
|
||||
VarString res = string::new_with_capacity(total_size);
|
||||
res.append(s[0]);
|
||||
foreach (String* &str : s[1..])
|
||||
{
|
||||
res.append(joiner);
|
||||
res.append(*str);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
macro bool char_in_set(char c, String set)
|
||||
{
|
||||
foreach (ch : set)
|
||||
{
|
||||
if (ch == c) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
macro char_is_space_tab(char c) @private
|
||||
{
|
||||
return c == ' ' || c == '\t';
|
||||
}
|
||||
|
||||
macro to_integer($Type, String string) @private
|
||||
{
|
||||
usz len = string.len;
|
||||
usz index = 0;
|
||||
char* ptr = string.ptr;
|
||||
while (index < len && char_is_space_tab(ptr[index])) index++;
|
||||
if (len == index) return NumberConversion.EMPTY_STRING!;
|
||||
bool is_negative;
|
||||
switch (string[index])
|
||||
{
|
||||
case '-':
|
||||
if ($Type.min == 0) return NumberConversion.NEGATIVE_VALUE!;
|
||||
is_negative = true;
|
||||
index++;
|
||||
case '+':
|
||||
index++;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (len == index) return NumberConversion.MALFORMED_INTEGER!;
|
||||
$Type base = 10;
|
||||
if (string[index] == '0')
|
||||
{
|
||||
index++;
|
||||
if (index == len) return ($Type)0;
|
||||
switch (string[index])
|
||||
{
|
||||
case 'x':
|
||||
case 'X':
|
||||
base = 16;
|
||||
index++;
|
||||
case 'b':
|
||||
case 'B':
|
||||
base = 2;
|
||||
index++;
|
||||
case 'o':
|
||||
case 'O':
|
||||
base = 8;
|
||||
index++;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (len == index) return NumberConversion.MALFORMED_INTEGER!;
|
||||
}
|
||||
$Type value = 0;
|
||||
while (index != len)
|
||||
{
|
||||
char c = {|
|
||||
char ch = string[index++];
|
||||
if (base != 16 || ch < 'A') return (char)(ch - '0');
|
||||
if (ch <= 'F') return (char)(ch - 'A');
|
||||
if (ch < 'a') return NumberConversion.MALFORMED_INTEGER!;
|
||||
if (ch > 'f') return NumberConversion.MALFORMED_INTEGER!;
|
||||
return (char)(ch - 'a');
|
||||
|}?;
|
||||
if (c >= base) return NumberConversion.MALFORMED_INTEGER!;
|
||||
value = {|
|
||||
if (is_negative)
|
||||
{
|
||||
$Type new_value = value * base - c;
|
||||
if (new_value > value) return NumberConversion.INTEGER_OVERFLOW!;
|
||||
return new_value;
|
||||
}
|
||||
$Type new_value = value * base + c;
|
||||
if (new_value < value) return NumberConversion.INTEGER_OVERFLOW!;
|
||||
return new_value;
|
||||
|}?;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
fn float! to_float(String string) => floatparse(string, float);
|
||||
fn double! to_double(String string) => floatparse(string, double);
|
||||
fn int128! to_int128(String string) => to_integer(int128, string);
|
||||
fn long! to_long(String string) => to_integer(long, string);
|
||||
fn int! to_int(String string) => to_integer(int, string);
|
||||
fn short! to_short(String string) => to_integer(short, string);
|
||||
fn ichar! to_ichar(String string) => to_integer(ichar, string);
|
||||
|
||||
fn uint128! to_uint128(String str) => to_integer(uint128, str);
|
||||
fn ulong! to_ulong(String str) => to_integer(ulong, str);
|
||||
fn uint! to_uint(String str) => to_integer(uint, str);
|
||||
fn ushort! to_ushort(String str) => to_integer(ushort, str);
|
||||
fn char! to_uchar(String str) => to_integer(char, str);
|
||||
|
||||
fn String trim(String string, String to_trim = "\t\n\r ") @deprecated => string.trim(to_trim);
|
||||
|
||||
fn bool starts_with(String s, String needle) @deprecated => s.starts_with(needle);
|
||||
|
||||
fn String[] tsplit(String s, String needle) @deprecated => s.split(needle, .using = mem::temp()) @inline;
|
||||
fn String[] split(String s, String needle, Allocator* using = mem::heap()) @deprecated => s.split(needle, .using = using);
|
||||
fn usz! rindex_of(String s, String needle) @deprecated => s.rindex_of(needle);
|
||||
fn usz! index_of(String s, String needle) @deprecated => s.index_of(needle);
|
||||
|
||||
fn ZString String.zstrcopy(String s, Allocator* using = mem::heap()) @deprecated => s.zstr_copy(using);
|
||||
fn ZString String.zstrtcopy(String s) @deprecated => s.zstr_tcopy();
|
||||
|
||||
fn ZString copy_zstring(String s, Allocator* using = mem::heap()) @deprecated => s.zstr_copy(using);
|
||||
fn String copyz(String s, Allocator* using = mem::heap()) @deprecated => s.copy(using);
|
||||
fn ZString tcopy_zstring(String s) @deprecated => s.zstr_tcopy();
|
||||
|
||||
fn bool compare(String a, String b)
|
||||
{
|
||||
if (a.len != b.len) return false;
|
||||
foreach (i, c : a)
|
||||
{
|
||||
if (c != b[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
fault UnicodeResult
|
||||
{
|
||||
INVALID_UTF8,
|
||||
INVALID_UTF16,
|
||||
CONVERSION_FAILED,
|
||||
}
|
||||
|
||||
fn usz utf8_codepoints(String utf8)
|
||||
{
|
||||
usz len = 0;
|
||||
foreach (char c : utf8)
|
||||
{
|
||||
if (c & 0xC0 != 0x80) len++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
fn Char32[]! utf8to32(String utf8, Allocator* using = mem::heap())
|
||||
{
|
||||
usz codepoints = conv::utf8_codepoints(utf8);
|
||||
Char32* data = malloc_checked(Char32, codepoints + 1, .using = using)?;
|
||||
conv::utf8to32_unsafe(utf8, data)?;
|
||||
data[codepoints] = 0;
|
||||
return data[:codepoints];
|
||||
}
|
||||
|
||||
fn String utf32to8(Char32[] utf32, Allocator* using = mem::heap())
|
||||
{
|
||||
usz len = conv::utf8len_for_utf32(utf32);
|
||||
char* data = malloc_checked(len + 1, .using = using)!!;
|
||||
conv::utf32to8_unsafe(utf32, data);
|
||||
data[len] = 0;
|
||||
return (String)data[:len];
|
||||
}
|
||||
|
||||
fn Char16[]! utf8to16(String utf8, Allocator* using = mem::heap())
|
||||
{
|
||||
usz len16 = conv::utf16len_for_utf8(utf8);
|
||||
Char16* data = malloc_checked(Char16, len16 + 1, .using = using)?;
|
||||
conv::utf8to16_unsafe(utf8, data)?;
|
||||
data[len16] = 0;
|
||||
return data[:len16];
|
||||
}
|
||||
|
||||
|
||||
fn String! utf16to8(Char16[] utf16, Allocator* using = mem::heap())
|
||||
{
|
||||
usz len = conv::utf8len_for_utf16(utf16);
|
||||
char* data = malloc_checked(len + 1, .using = using)?;
|
||||
conv::utf16to8_unsafe(utf16, data)?;
|
||||
data[len] = 0;
|
||||
return (String)data[:len];
|
||||
}
|
||||
|
||||
fn String copy(String s, Allocator* using = mem::heap()) @deprecated
|
||||
{
|
||||
usz len = s.len;
|
||||
ZString str_copy = s.zstr_copy(using) @inline;
|
||||
return (String)str_copy[:len];
|
||||
}
|
||||
|
||||
fn String tcopy(String s) @deprecated
|
||||
{
|
||||
usz len = s.len;
|
||||
ZString str_copy = s.zstr_tcopy() @inline;
|
||||
return (String)str_copy[:len];
|
||||
}
|
||||
|
||||
fn String tconcat(String s1, String s2)
|
||||
{
|
||||
usz full_len = s1.len + s2.len;
|
||||
char* str = tmalloc(full_len + 1);
|
||||
usz s1_len = s1.len;
|
||||
mem::copy(str, s1.ptr, s1_len);
|
||||
mem::copy(str + s1_len, s2.ptr, s2.len);
|
||||
str[full_len] = 0;
|
||||
return (String)str[:full_len];
|
||||
}
|
||||
|
||||
fn String concat(String s1, String s2)
|
||||
{
|
||||
usz full_len = s1.len + s2.len;
|
||||
char* str = malloc(full_len + 1);
|
||||
usz s1_len = s1.len;
|
||||
mem::copy(str, s1.ptr, s1_len);
|
||||
mem::copy(str + s1_len, s2.ptr, s2.len);
|
||||
str[full_len] = 0;
|
||||
return (String)str[:full_len];
|
||||
}
|
||||
|
||||
fn String ZString.as_str(ZString str)
|
||||
{
|
||||
return (String)((char*)str)[:str.len()];
|
||||
}
|
||||
|
||||
fn usz ZString.char_len(ZString str)
|
||||
{
|
||||
usz len = 0;
|
||||
char* ptr = (char*)str;
|
||||
while (char c = ptr++[0])
|
||||
{
|
||||
if (c & 0xC0 != 0x80) len++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
fn usz ZString.len(ZString str)
|
||||
{
|
||||
usz len = 0;
|
||||
char* ptr = (char*)str;
|
||||
while (char c = ptr++[0]) len++;
|
||||
return len;
|
||||
}
|
||||
|
||||
@@ -1,16 +1,8 @@
|
||||
module std::core::string;
|
||||
import std::ascii;
|
||||
|
||||
def ZString = distinct inline char*;
|
||||
def Char32 = uint;
|
||||
def Char16 = ushort;
|
||||
|
||||
fault UnicodeResult
|
||||
{
|
||||
INVALID_UTF8,
|
||||
INVALID_UTF16,
|
||||
CONVERSION_FAILED,
|
||||
}
|
||||
typedef ZString = distinct inline char*;
|
||||
typedef Char32 = uint;
|
||||
typedef Char16 = ushort;
|
||||
|
||||
const uint SURROGATE_OFFSET @private = 0x10000;
|
||||
const uint SURROGATE_GENERIC_MASK @private = 0xF800;
|
||||
@@ -55,31 +47,6 @@ macro bool char_in_set(char c, String set)
|
||||
return false;
|
||||
}
|
||||
|
||||
fn String join(String[] s, String joiner, Allocator* using = mem::heap())
|
||||
{
|
||||
if (!s)
|
||||
{
|
||||
return (String)(calloc(char, 2, .using = using)[:0]);
|
||||
}
|
||||
|
||||
usz total_size = joiner.len * s.len;
|
||||
foreach (String* &str : s)
|
||||
{
|
||||
total_size += str.len;
|
||||
}
|
||||
@stack_mem(256; Allocator* mem)
|
||||
{
|
||||
DString res = dstring::new_with_capacity(total_size, .using = mem);
|
||||
res.append(s[0]);
|
||||
foreach (String* &str : s[1..])
|
||||
{
|
||||
res.append(joiner);
|
||||
res.append(*str);
|
||||
}
|
||||
return res.copy_str(using);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [in] string
|
||||
* @param [in] to_trim
|
||||
@@ -161,7 +128,7 @@ fn String[] String.split(String s, String needle, usz max = 0, Allocator* using
|
||||
bool no_more = false;
|
||||
while (!no_more)
|
||||
{
|
||||
usz! index = i == max - 1 ? SearchResult.MISSING? : s.index_of(needle);
|
||||
usz! index = i == max - 1 ? SearchResult.MISSING! : s.index_of(needle);
|
||||
String res @noinit;
|
||||
if (try index)
|
||||
{
|
||||
@@ -196,11 +163,6 @@ fn String[] String.tsplit(String s, String needle, usz max = 0)
|
||||
return s.split(needle, max, mem::temp()) @inline;
|
||||
}
|
||||
|
||||
fn bool String.contains(String s, String needle)
|
||||
{
|
||||
return @ok(s.index_of(needle));
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the index of the first incidence of a string.
|
||||
*
|
||||
@@ -208,9 +170,7 @@ fn bool String.contains(String s, String needle)
|
||||
* @param [in] needle
|
||||
* @pure
|
||||
* @ensure return < s.len
|
||||
* @require needle.len > 0 : "The needle must be len 1 or more"
|
||||
* @return "the index of the needle"
|
||||
* @return! SearchResult.MISSING "if the needle cannot be found"
|
||||
* @require needle.len > 0 "The needle must be len 1 or more"
|
||||
**/
|
||||
fn usz! String.index_of(String s, String needle)
|
||||
{
|
||||
@@ -234,7 +194,7 @@ fn usz! String.index_of(String s, String needle)
|
||||
search = needle[0];
|
||||
}
|
||||
}
|
||||
return SearchResult.MISSING?;
|
||||
return SearchResult.MISSING!;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -245,8 +205,6 @@ fn usz! String.index_of(String s, String needle)
|
||||
* @pure
|
||||
* @ensure return < s.len
|
||||
* @require needle.len > 0 "The needle must be len 1 or more"
|
||||
* @return "the index of the needle"
|
||||
* @return! SearchResult.MISSING "if the needle cannot be found"
|
||||
**/
|
||||
fn usz! String.rindex_of(String s, String needle)
|
||||
{
|
||||
@@ -270,34 +228,9 @@ fn usz! String.rindex_of(String s, String needle)
|
||||
search = needle[^1];
|
||||
}
|
||||
}
|
||||
return SearchResult.MISSING?;
|
||||
return SearchResult.MISSING!;
|
||||
}
|
||||
|
||||
fn String ZString.as_str(ZString str)
|
||||
{
|
||||
return (String)((char*)str)[:str.len()];
|
||||
}
|
||||
|
||||
fn usz ZString.char_len(ZString str)
|
||||
{
|
||||
usz len = 0;
|
||||
char* ptr = (char*)str;
|
||||
while (char c = ptr++[0])
|
||||
{
|
||||
if (c & 0xC0 != 0x80) len++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
fn usz ZString.len(ZString str)
|
||||
{
|
||||
usz len = 0;
|
||||
char* ptr = (char*)str;
|
||||
while (char c = ptr++[0]) len++;
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
fn ZString String.zstr_copy(String s, Allocator* using = mem::heap())
|
||||
{
|
||||
usz len = s.len;
|
||||
@@ -337,178 +270,23 @@ fn String String.tcopy(String s) => s.copy(mem::temp()) @inline;
|
||||
fn String ZString.copy(ZString z, Allocator* using = mem::heap()) => z.as_str().copy(using) @inline;
|
||||
fn String ZString.tcopy(ZString z) => z.as_str().copy(mem::temp()) @inline;
|
||||
|
||||
/**
|
||||
* Convert an UTF-8 string to UTF-16
|
||||
* @return "The UTF-16 string as a slice, allocated using the given allocator"
|
||||
* @return! UnicodeResult.INVALID_UTF8 "If the string contained an invalid UTF-8 sequence"
|
||||
* @return! AllocationFailure "If allocation of the string fails"
|
||||
**/
|
||||
fn Char16[]! String.to_utf16(String s, Allocator* using = mem::heap())
|
||||
{
|
||||
usz len16 = conv::utf16len_for_utf8(s);
|
||||
Char16* data = malloc_checked(Char16, len16 + 1, .using = using)!;
|
||||
conv::utf8to16_unsafe(s, data)!;
|
||||
Char16* data = malloc_checked(Char16, len16 + 1, .using = using)?;
|
||||
conv::utf8to16_unsafe(s, data)?;
|
||||
data[len16] = 0;
|
||||
return data[:len16];
|
||||
}
|
||||
|
||||
fn Char32[]! String.to_utf32(String s, Allocator* using = mem::heap())
|
||||
{
|
||||
usz codepoints = conv::utf8_codepoints(s);
|
||||
Char32* data = malloc_checked(Char32, codepoints + 1, .using = using)!;
|
||||
conv::utf8to32_unsafe(s, data)!;
|
||||
data[codepoints] = 0;
|
||||
return data[:codepoints];
|
||||
}
|
||||
|
||||
fn void String.convert_ascii_to_lower(String s)
|
||||
{
|
||||
foreach (&c : s) if (*c >= 'A' && *c <= 'Z') *c += 'a' - 'A';
|
||||
}
|
||||
|
||||
fn String String.ascii_to_lower(String s, Allocator* using = mem::heap())
|
||||
{
|
||||
String copy = s.copy(using);
|
||||
copy.convert_ascii_to_lower();
|
||||
return copy;
|
||||
}
|
||||
|
||||
fn void String.convert_ascii_to_upper(String s)
|
||||
{
|
||||
foreach (&c : s) if (*c >= 'a' && *c <= 'z') *c -= 'a' - 'A';
|
||||
}
|
||||
|
||||
fn String String.ascii_to_upper(String s, Allocator* using = mem::heap())
|
||||
{
|
||||
String copy = s.copy(using);
|
||||
copy.convert_ascii_to_upper();
|
||||
return copy;
|
||||
}
|
||||
|
||||
fn String! from_utf32(Char32[] utf32, Allocator* using = mem::heap())
|
||||
{
|
||||
usz len = conv::utf8len_for_utf32(utf32);
|
||||
char* data = malloc_checked(len + 1, .using = using)!;
|
||||
defer catch free(data, .using = using);
|
||||
conv::utf32to8_unsafe(utf32, data);
|
||||
data[len] = 0;
|
||||
return (String)data[:len];
|
||||
}
|
||||
|
||||
fn String! from_utf16(Char16[] utf16, Allocator* using = mem::heap())
|
||||
{
|
||||
usz len = conv::utf8len_for_utf16(utf16);
|
||||
char* data = malloc_checked(len + 1, .using = using)!;
|
||||
defer catch free(data, .using = using);
|
||||
conv::utf16to8_unsafe(utf16, data)!;
|
||||
char* data = malloc_checked(len + 1, .using = using)?;
|
||||
conv::utf16to8_unsafe(utf16, data)?;
|
||||
data[len] = 0;
|
||||
return (String)data[:len];
|
||||
}
|
||||
|
||||
fn String! from_zutf16(Char16* utf16_pointer, Allocator* using = mem::heap())
|
||||
{
|
||||
usz utf16_len;
|
||||
while (utf16_pointer[utf16_len] != 0) utf16_len++;
|
||||
Char16[] utf16 = utf16_pointer[:utf16_len];
|
||||
return from_utf16(utf16, using);
|
||||
}
|
||||
|
||||
fn usz String.utf8_codepoints(String s)
|
||||
{
|
||||
usz len = 0;
|
||||
foreach (char c : s)
|
||||
{
|
||||
if (c & 0xC0 != 0x80) len++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
macro String.to_integer(String string, $Type)
|
||||
{
|
||||
usz len = string.len;
|
||||
usz index = 0;
|
||||
char* ptr = string.ptr;
|
||||
while (index < len && ascii::is_blank_m(ptr[index])) index++;
|
||||
if (len == index) return NumberConversion.EMPTY_STRING?;
|
||||
bool is_negative;
|
||||
switch (string[index])
|
||||
{
|
||||
case '-':
|
||||
if ($Type.min == 0) return NumberConversion.NEGATIVE_VALUE?;
|
||||
is_negative = true;
|
||||
index++;
|
||||
case '+':
|
||||
index++;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (len == index) return NumberConversion.MALFORMED_INTEGER?;
|
||||
$Type base = 10;
|
||||
if (string[index] == '0')
|
||||
{
|
||||
index++;
|
||||
if (index == len) return ($Type)0;
|
||||
switch (string[index])
|
||||
{
|
||||
case 'x':
|
||||
case 'X':
|
||||
base = 16;
|
||||
index++;
|
||||
case 'b':
|
||||
case 'B':
|
||||
base = 2;
|
||||
index++;
|
||||
case 'o':
|
||||
case 'O':
|
||||
base = 8;
|
||||
index++;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (len == index) return NumberConversion.MALFORMED_INTEGER?;
|
||||
}
|
||||
$Type value = 0;
|
||||
while (index != len)
|
||||
{
|
||||
char c = {|
|
||||
char ch = string[index++];
|
||||
if (base != 16 || ch < 'A') return (char)(ch - '0');
|
||||
if (ch <= 'F') return (char)(ch - 'A');
|
||||
if (ch < 'a') return NumberConversion.MALFORMED_INTEGER?;
|
||||
if (ch > 'f') return NumberConversion.MALFORMED_INTEGER?;
|
||||
return (char)(ch - 'a');
|
||||
|}!;
|
||||
if (c >= base) return NumberConversion.MALFORMED_INTEGER?;
|
||||
value = {|
|
||||
if (is_negative)
|
||||
{
|
||||
$Type new_value = value * base - c;
|
||||
if (new_value > value) return NumberConversion.INTEGER_OVERFLOW?;
|
||||
return new_value;
|
||||
}
|
||||
$Type new_value = value * base + c;
|
||||
if (new_value < value) return NumberConversion.INTEGER_OVERFLOW?;
|
||||
return new_value;
|
||||
|}!;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
fn Char16[]! String.to_temp_utf16(String s) => s.to_utf16(mem::temp());
|
||||
|
||||
fn int128! String.to_int128(String s) => s.to_integer(int128);
|
||||
fn long! String.to_long(String s) => s.to_integer(long);
|
||||
fn int! String.to_int(String s) => s.to_integer(int);
|
||||
fn short! String.to_short(String s) => s.to_integer(short);
|
||||
fn ichar! String.to_ichar(String s) => s.to_integer(ichar);
|
||||
|
||||
fn uint128! String.to_uint128(String s) => s.to_integer(uint128);
|
||||
fn ulong! String.to_ulong(String s) => s.to_integer(ulong);
|
||||
fn uint! String.to_uint(String s) => s.to_integer(uint);
|
||||
fn ushort! String.to_ushort(String s) => s.to_integer(ushort);
|
||||
fn char! String.to_uchar(String s) => s.to_integer(char);
|
||||
|
||||
fn double! String.to_double(String s) => s.to_real(double);
|
||||
fn float! String.to_float(String s) => s.to_real(float);
|
||||
|
||||
@@ -15,9 +15,9 @@ fn Char32! StringIterator.next(StringIterator* this)
|
||||
{
|
||||
usz len = this.utf8.len;
|
||||
usz current = this.current;
|
||||
if (current >= len) return IteratorResult.NO_MORE_ELEMENT?;
|
||||
if (current >= len) return IteratorResult.NO_MORE_ELEMENT!;
|
||||
usz read = (len - current < 4 ? len - current : 4);
|
||||
Char32 res = conv::utf8_to_char32(&this.utf8[current], &read)!;
|
||||
Char32 res = conv::utf8_to_char32(&this.utf8[current], &read)?;
|
||||
this.current += read;
|
||||
return res;
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
module std::core::types;
|
||||
import libc;
|
||||
|
||||
@@ -11,63 +10,63 @@ fault ConversionResult
|
||||
/**
|
||||
* @require $Type.kindof.is_int() || $Type.kindof == TypeKind.ENUM "Argument was not an integer"
|
||||
**/
|
||||
macro any_to_int(any v, $Type)
|
||||
macro variant_to_int(variant v, $Type)
|
||||
{
|
||||
typeid any_type = v.type;
|
||||
TypeKind kind = any_type.kindof;
|
||||
typeid variant_type = v.type;
|
||||
TypeKind kind = variant_type.kindof;
|
||||
if (kind == TypeKind.ENUM)
|
||||
{
|
||||
any_type = any_type.inner;
|
||||
kind = any_type.kindof;
|
||||
variant_type = variant_type.inner;
|
||||
kind = variant_type.kindof;
|
||||
}
|
||||
bool is_mixed_signed = $Type.kindof != any_type.kindof;
|
||||
bool is_mixed_signed = $Type.kindof != variant_type.kindof;
|
||||
$Type max = $Type.max;
|
||||
$Type min = $Type.min;
|
||||
switch (any_type)
|
||||
switch (variant_type)
|
||||
{
|
||||
case ichar:
|
||||
ichar c = *(char*)v.ptr;
|
||||
if (is_mixed_signed && c < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE?;
|
||||
if (is_mixed_signed && c < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE!;
|
||||
return ($Type)c;
|
||||
case short:
|
||||
short s = *(short*)v.ptr;
|
||||
if (is_mixed_signed && s < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE?;
|
||||
if (s > max || s < min) return ConversionResult.VALUE_OUT_OF_RANGE?;
|
||||
if (is_mixed_signed && s < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE!;
|
||||
if (s > max || s < min) return ConversionResult.VALUE_OUT_OF_RANGE!;
|
||||
return ($Type)s;
|
||||
case int:
|
||||
int i = *(int*)v.ptr;
|
||||
if (is_mixed_signed && i < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE?;
|
||||
if (i > max || i < min) return ConversionResult.VALUE_OUT_OF_RANGE?;
|
||||
if (is_mixed_signed && i < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE!;
|
||||
if (i > max || i < min) return ConversionResult.VALUE_OUT_OF_RANGE!;
|
||||
return ($Type)i;
|
||||
case long:
|
||||
long l = *(long*)v.ptr;
|
||||
if (is_mixed_signed && l < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE?;
|
||||
if (l > max || l < min) return ConversionResult.VALUE_OUT_OF_RANGE?;
|
||||
if (is_mixed_signed && l < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE!;
|
||||
if (l > max || l < min) return ConversionResult.VALUE_OUT_OF_RANGE!;
|
||||
return ($Type)l;
|
||||
case int128:
|
||||
int128 i = *(int128*)v.ptr;
|
||||
if (is_mixed_signed && i < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE?;
|
||||
if (i > max || i < min) return ConversionResult.VALUE_OUT_OF_RANGE?;
|
||||
if (is_mixed_signed && i < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE!;
|
||||
if (i > max || i < min) return ConversionResult.VALUE_OUT_OF_RANGE!;
|
||||
return ($Type)i;
|
||||
case char:
|
||||
char c = *(char*)v.ptr;
|
||||
if (c > max) return ConversionResult.VALUE_OUT_OF_RANGE?;
|
||||
if (c > max) return ConversionResult.VALUE_OUT_OF_RANGE!;
|
||||
return ($Type)c;
|
||||
case ushort:
|
||||
ushort s = *(ushort*)v.ptr;
|
||||
if (s > max || s < min) return ConversionResult.VALUE_OUT_OF_RANGE?;
|
||||
if (s > max || s < min) return ConversionResult.VALUE_OUT_OF_RANGE!;
|
||||
return ($Type)s;
|
||||
case uint:
|
||||
uint i = *(uint*)v.ptr;
|
||||
if (i > max || i < min) return ConversionResult.VALUE_OUT_OF_RANGE?;
|
||||
if (i > max || i < min) return ConversionResult.VALUE_OUT_OF_RANGE!;
|
||||
return ($Type)i;
|
||||
case ulong:
|
||||
ulong l = *(ulong*)v.ptr;
|
||||
if (l > max || l < min) return ConversionResult.VALUE_OUT_OF_RANGE?;
|
||||
if (l > max || l < min) return ConversionResult.VALUE_OUT_OF_RANGE!;
|
||||
return ($Type)l;
|
||||
case uint128:
|
||||
uint128 i = *(uint128*)v.ptr;
|
||||
if (i > max || i < min) return ConversionResult.VALUE_OUT_OF_RANGE?;
|
||||
if (i > max || i < min) return ConversionResult.VALUE_OUT_OF_RANGE!;
|
||||
return ($Type)i;
|
||||
default:
|
||||
unreachable();
|
||||
@@ -77,7 +76,7 @@ macro any_to_int(any v, $Type)
|
||||
macro bool is_numerical($Type)
|
||||
{
|
||||
var $kind = $Type.kindof;
|
||||
$if $kind == TypeKind.DISTINCT:
|
||||
$if ($kind == TypeKind.DISTINCT)
|
||||
return is_numerical($Type.inner);
|
||||
$else
|
||||
return $kind == TypeKind.SIGNED_INT || $kind == TypeKind.UNSIGNED_INT || $kind == TypeKind.FLOAT
|
||||
@@ -98,7 +97,7 @@ macro bool is_indexable($Type)
|
||||
macro bool is_comparable($Type)
|
||||
{
|
||||
var $kind = $Type.kindof;
|
||||
$if $kind == TypeKind.DISTINCT:
|
||||
$if ($kind == TypeKind.DISTINCT)
|
||||
return is_comparable($Type.inner);
|
||||
$else
|
||||
return $kind == TypeKind.SIGNED_INT || $kind == TypeKind.UNSIGNED_INT || $kind == TypeKind.FLOAT
|
||||
@@ -162,7 +161,7 @@ macro bool is_vector($Type)
|
||||
|
||||
macro TypeKind inner_kind($Type)
|
||||
{
|
||||
$if $Type.kindof == TypeKind.DISTINCT:
|
||||
$if ($Type.kindof == TypeKind.DISTINCT)
|
||||
return inner_kind($typefrom($Type.inner));
|
||||
$else
|
||||
return $Type.kindof;
|
||||
@@ -182,11 +181,11 @@ macro bool is_same($TypeA, $TypeB)
|
||||
macro bool @has_same(#a, #b, ...)
|
||||
{
|
||||
var $type_a = $typeof(#a).typeid;
|
||||
$if $type_a != $typeof(#b).typeid:
|
||||
$if ($type_a != $typeof(#b).typeid)
|
||||
return false;
|
||||
$endif
|
||||
$for (var $i = 0; $i < $vacount; $i++)
|
||||
$if $typeof($vaexpr($i)).typeid != $type_a:
|
||||
$if ($typeof($vaexpr($i)).typeid != $type_a)
|
||||
return false;
|
||||
$endif
|
||||
$endfor
|
||||
@@ -213,30 +212,25 @@ macro bool is_promotable_to_float($Type) => types::is_float($Type) || types::is_
|
||||
|
||||
macro bool is_same_vector_type($Type1, $Type2)
|
||||
{
|
||||
$if $Type1.kindof != TypeKind.VECTOR:
|
||||
$if ($Type1.kindof != TypeKind.VECTOR)
|
||||
return $Type2.kindof != TypeKind.VECTOR;
|
||||
$else
|
||||
return $Type1.inner == $Type2.inner && $Type1.len == $Type2.len;
|
||||
$endif
|
||||
}
|
||||
|
||||
macro bool is_equatable_type($Type)
|
||||
{
|
||||
$if $defined($Type.less) || $defined($Type.compare_to) || $defined($Type.equals):
|
||||
return true;
|
||||
$else
|
||||
return is_equatable($Type);
|
||||
$endif
|
||||
}
|
||||
|
||||
macro bool is_equatable_value(value)
|
||||
{
|
||||
return is_equatable_type($typeof(value));
|
||||
$if ($defined(value.less) || $defined(value.compare_to) || $defined(value.equals))
|
||||
return true;
|
||||
$else
|
||||
return is_equatable($typeof(value));
|
||||
$endif
|
||||
}
|
||||
|
||||
macro bool is_comparable_value(value)
|
||||
{
|
||||
$if $defined(value.less) || $defined(value.compare_to):
|
||||
$if ($defined(value.less) || $defined(value.compare_to))
|
||||
return true;
|
||||
$else
|
||||
return is_comparable($typeof(value));
|
||||
@@ -251,8 +245,8 @@ enum TypeKind : char
|
||||
UNSIGNED_INT,
|
||||
FLOAT,
|
||||
TYPEID,
|
||||
ANYFAULT,
|
||||
ANY,
|
||||
ANYERR,
|
||||
VARIANT,
|
||||
ENUM,
|
||||
FAULT,
|
||||
STRUCT,
|
||||
|
||||
@@ -12,7 +12,7 @@ macro bool @is_promotable_to_float(#value) => types::is_promotable_to_float($typ
|
||||
macro bool @is_same_vector_type(#value1, #value2) => types::is_same_vector_type($typeof(#value1), $typeof(#value2));
|
||||
macro promote_int(x)
|
||||
{
|
||||
$if @is_int(x):
|
||||
$if (@is_int(x))
|
||||
return (double)x;
|
||||
$else
|
||||
return x;
|
||||
@@ -20,4 +20,3 @@ macro promote_int(x)
|
||||
}
|
||||
|
||||
macro TypeKind @inner_kind(#value) => types::inner_kind($typeof(#value));
|
||||
|
||||
|
||||
327
lib/std/core/varstring.c3
Normal file
327
lib/std/core/varstring.c3
Normal file
@@ -0,0 +1,327 @@
|
||||
module std::core::string;
|
||||
import libc;
|
||||
|
||||
typedef VarString = distinct void*;
|
||||
typedef DynStr = VarString;
|
||||
typedef DynString = VarString;
|
||||
typedef VString = VarString;
|
||||
typedef Text = VarString;
|
||||
|
||||
const usz MIN_CAPACITY = 16;
|
||||
|
||||
fn VarString new_with_capacity(usz capacity, Allocator* allocator = mem::heap())
|
||||
{
|
||||
if (capacity < MIN_CAPACITY) capacity = MIN_CAPACITY;
|
||||
StringData* data = malloc(StringData, 1, .using = allocator, .end_padding = capacity);
|
||||
data.allocator = allocator;
|
||||
data.len = 0;
|
||||
data.capacity = capacity;
|
||||
return (VarString)data;
|
||||
}
|
||||
|
||||
fn VarString new(String c)
|
||||
{
|
||||
usz len = c.len;
|
||||
VarString str = new_with_capacity(len);
|
||||
StringData* data = str.data();
|
||||
if (len)
|
||||
{
|
||||
data.len = len;
|
||||
mem::copy(&data.chars, c.ptr, len);
|
||||
}
|
||||
return (VarString)data;
|
||||
}
|
||||
|
||||
fn ZString VarString.zstr(VarString str)
|
||||
{
|
||||
StringData* data = str.data();
|
||||
if (!data) return (ZString)"";
|
||||
if (data.capacity == data.len)
|
||||
{
|
||||
str.reserve(1);
|
||||
data.chars[data.len] = 0;
|
||||
}
|
||||
else if (data.chars[data.len] != 0)
|
||||
{
|
||||
data.chars[data.len] = 0;
|
||||
}
|
||||
return (ZString)&data.chars[0];
|
||||
}
|
||||
|
||||
fn usz VarString.capacity(VarString this)
|
||||
{
|
||||
if (!this) return 0;
|
||||
return this.data().capacity;
|
||||
}
|
||||
|
||||
fn usz VarString.len(VarString this)
|
||||
{
|
||||
if (!this) return 0;
|
||||
return this.data().len;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require new_size <= this.len()
|
||||
*/
|
||||
fn void VarString.chop(VarString this, usz new_size)
|
||||
{
|
||||
if (!this) return;
|
||||
this.data().len = new_size;
|
||||
}
|
||||
|
||||
fn String VarString.str(VarString str)
|
||||
{
|
||||
StringData* data = (StringData*)str;
|
||||
if (!data) return "";
|
||||
return (String)data.chars[:data.len];
|
||||
}
|
||||
|
||||
fn void VarString.append_utf32(VarString* str, Char32[] chars)
|
||||
{
|
||||
str.reserve(chars.len);
|
||||
foreach (Char32 c : chars)
|
||||
{
|
||||
str.append_char32(c);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @require index < str.len()
|
||||
**/
|
||||
fn void VarString.set(VarString str, usz index, char c)
|
||||
{
|
||||
str.data().chars[index] = c;
|
||||
}
|
||||
|
||||
fn void VarString.append_repeat(VarString* str, char c, usz times)
|
||||
{
|
||||
if (times == 0) return;
|
||||
str.reserve(times);
|
||||
StringData* data = str.data();
|
||||
for (usz i = 0; i < times; i++)
|
||||
{
|
||||
data.chars[data.len++] = c;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @require c <= 0x10ffff
|
||||
*/
|
||||
fn void VarString.append_char32(VarString* str, Char32 c)
|
||||
{
|
||||
if (c < 0x7f)
|
||||
{
|
||||
str.reserve(1);
|
||||
StringData* data = str.data();
|
||||
data.chars[data.len++] = (char)c;
|
||||
return;
|
||||
}
|
||||
if (c < 0x7ff)
|
||||
{
|
||||
str.reserve(2);
|
||||
StringData* data = str.data();
|
||||
data.chars[data.len++] = (char)(0xC0 | c >> 6);
|
||||
data.chars[data.len++] = (char)(0x80 | (c & 0x3F));
|
||||
return;
|
||||
}
|
||||
if (c < 0xffff)
|
||||
{
|
||||
str.reserve(3);
|
||||
StringData* data = str.data();
|
||||
data.chars[data.len++] = (char)(0xE0 | c >> 12);
|
||||
data.chars[data.len++] = (char)(0x80 | (c >> 6 & 0x3F));
|
||||
data.chars[data.len++] = (char)(0x80 | (c & 0x3F));
|
||||
return;
|
||||
}
|
||||
str.reserve(4);
|
||||
StringData* data = str.data();
|
||||
data.chars[data.len++] = (char)(0xF0 | c >> 18);
|
||||
data.chars[data.len++] = (char)(0x80 | (c >> 12 & 0x3F));
|
||||
data.chars[data.len++] = (char)(0x80 | (c >> 6 & 0x3F));
|
||||
data.chars[data.len++] = (char)(0x80 | (c & 0x3F));
|
||||
}
|
||||
|
||||
fn VarString VarString.tcopy(VarString* str) => str.copy(mem::temp());
|
||||
|
||||
fn VarString VarString.copy(VarString* str, Allocator* allocator = null)
|
||||
{
|
||||
if (!str)
|
||||
{
|
||||
if (allocator) return new_with_capacity(0, allocator);
|
||||
return (VarString)null;
|
||||
}
|
||||
if (!allocator) allocator = mem::heap();
|
||||
StringData* data = str.data();
|
||||
VarString new_string = new_with_capacity(data.capacity, allocator);
|
||||
mem::copy((char*)new_string.data(), (char*)data, StringData.sizeof + data.len);
|
||||
return new_string;
|
||||
}
|
||||
|
||||
fn ZString VarString.copy_zstr(VarString* str, Allocator* allocator = mem::heap())
|
||||
{
|
||||
usz str_len = str.len();
|
||||
if (!str_len)
|
||||
{
|
||||
return (ZString)calloc(1, .using = allocator);
|
||||
}
|
||||
char* zstr = malloc(str_len + 1, .using = allocator);
|
||||
StringData* data = str.data();
|
||||
mem::copy(zstr, &data.chars, str_len);
|
||||
zstr[str_len] = 0;
|
||||
return (ZString)zstr;
|
||||
}
|
||||
|
||||
fn String VarString.copy_str(VarString* str, Allocator* allocator = mem::heap())
|
||||
{
|
||||
return (String)str.copy_zstr(allocator)[:str.len()];
|
||||
}
|
||||
|
||||
fn String VarString.tcopy_str(VarString* str) => str.copy_str(mem::temp()) @inline;
|
||||
|
||||
fn bool VarString.equals(VarString str, VarString other_string)
|
||||
{
|
||||
StringData *str1 = str.data();
|
||||
StringData *str2 = other_string.data();
|
||||
if (str1 == str2) return true;
|
||||
if (!str1) return str2.len == 0;
|
||||
if (!str2) return str1.len == 0;
|
||||
usz str1_len = str1.len;
|
||||
if (str1_len != str2.len) return false;
|
||||
for (int i = 0; i < str1_len; i++)
|
||||
{
|
||||
if (str1.chars[i] != str2.chars[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
fn void VarString.destroy(VarString* str)
|
||||
{
|
||||
if (!*str) return;
|
||||
StringData* data = str.data();
|
||||
if (!data) return;
|
||||
free(data, .using = data.allocator);
|
||||
*str = (VarString)null;
|
||||
}
|
||||
|
||||
fn bool VarString.less(VarString str, VarString other_string)
|
||||
{
|
||||
StringData* str1 = str.data();
|
||||
StringData* str2 = other_string.data();
|
||||
if (str1 == str2) return false;
|
||||
if (!str1) return str2.len != 0;
|
||||
if (!str2) return str1.len == 0;
|
||||
usz str1_len = str1.len;
|
||||
usz str2_len = str2.len;
|
||||
if (str1_len != str2_len) return str1_len < str2_len;
|
||||
for (int i = 0; i < str1_len; i++)
|
||||
{
|
||||
if (str1.chars[i] >= str2.chars[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
fn void VarString.append_chars(VarString* this, String str)
|
||||
{
|
||||
usz other_len = str.len;
|
||||
if (!other_len) return;
|
||||
if (!*this)
|
||||
{
|
||||
*this = new(str);
|
||||
return;
|
||||
}
|
||||
this.reserve(other_len);
|
||||
StringData* data = (StringData*)*this;
|
||||
mem::copy(&data.chars[data.len], str.ptr, other_len);
|
||||
data.len += other_len;
|
||||
}
|
||||
|
||||
fn Char32[] VarString.copy_utf32(VarString* this, Allocator* allocator = mem::heap())
|
||||
{
|
||||
return str::utf8to32(this.str(), allocator) @inline!!;
|
||||
}
|
||||
|
||||
fn void VarString.append_string(VarString* this, VarString str)
|
||||
{
|
||||
StringData* other = (StringData*)str;
|
||||
if (!other) return;
|
||||
this.append(str.str());
|
||||
}
|
||||
|
||||
fn void VarString.clear(VarString* str)
|
||||
{
|
||||
str.data().len = 0;
|
||||
}
|
||||
|
||||
fn void VarString.append_char(VarString* str, char c)
|
||||
{
|
||||
if (!*str)
|
||||
{
|
||||
*str = new_with_capacity(MIN_CAPACITY);
|
||||
}
|
||||
str.reserve(1);
|
||||
StringData* data = (StringData*)*str;
|
||||
data.chars[data.len++] = c;
|
||||
}
|
||||
|
||||
|
||||
macro void VarString.append(VarString* str, value)
|
||||
{
|
||||
var $Type = $typeof(value);
|
||||
$switch ($Type)
|
||||
$case char:
|
||||
$case ichar:
|
||||
str.append_char(value);
|
||||
$case VarString:
|
||||
str.append_string(value);
|
||||
$case String:
|
||||
str.append_chars(value);
|
||||
$case Char32:
|
||||
str.append_char32(value);
|
||||
$default:
|
||||
$switch
|
||||
$case @convertible(value, Char32):
|
||||
str.append_char32(value);
|
||||
$case @convertible(value, String):
|
||||
str.append_chars(value);
|
||||
$default:
|
||||
$assert(false, "Unsupported type for append – use printf instead.");
|
||||
$endswitch
|
||||
$endswitch
|
||||
}
|
||||
|
||||
|
||||
fn StringData* VarString.data(VarString str) @inline @private
|
||||
{
|
||||
return (StringData*)str;
|
||||
}
|
||||
|
||||
fn void VarString.reserve(VarString* str, usz addition) @private
|
||||
{
|
||||
StringData* data = str.data();
|
||||
if (!data)
|
||||
{
|
||||
*str = string::new_with_capacity(addition);
|
||||
return;
|
||||
}
|
||||
usz len = data.len + addition;
|
||||
if (data.capacity >= len) return;
|
||||
usz new_capacity = data.capacity *= 2;
|
||||
if (new_capacity < MIN_CAPACITY) new_capacity = MIN_CAPACITY;
|
||||
*str = (VarString)realloc(data, StringData.sizeof + new_capacity, .using = data.allocator);
|
||||
}
|
||||
|
||||
fn VarString VarString.new_concat(VarString a, VarString b, Allocator* allocator = mem::heap())
|
||||
{
|
||||
VarString string = new_with_capacity(a.len() + b.len(), allocator);
|
||||
string.append(a);
|
||||
string.append(b);
|
||||
return string;
|
||||
}
|
||||
|
||||
struct StringData @private
|
||||
{
|
||||
Allocator* allocator;
|
||||
usz len;
|
||||
usz capacity;
|
||||
char[*] chars;
|
||||
}
|
||||
@@ -32,7 +32,7 @@ struct JsonParser
|
||||
DString last_string;
|
||||
double last_number;
|
||||
char current;
|
||||
anyfault current_err;
|
||||
anyerr current_err;
|
||||
bool skip_comments;
|
||||
bool reached_end;
|
||||
}
|
||||
@@ -61,13 +61,13 @@ fn Object*! JsonParser.parse_from_token(JsonParser* this, JsonTokenType token)
|
||||
case COMMA:
|
||||
case RBRACE:
|
||||
case RBRACKET:
|
||||
case COLON: return JsonParsingError.UNEXPECTED_CHARACTER?;
|
||||
case COLON: return JsonParsingError.UNEXPECTED_CHARACTER!;
|
||||
case STRING: return object::new_string(this.last_string.str(), this.allocator);
|
||||
case NUMBER: return object::new_float(this.last_number, this.allocator);
|
||||
case TRUE: return object::new_bool(true);
|
||||
case FALSE: return object::new_bool(false);
|
||||
case NULL: return object::new_null();
|
||||
case EOF: return JsonParsingError.EOF?;
|
||||
case EOF: return JsonParsingError.EOF!;
|
||||
}
|
||||
unreachable();
|
||||
}
|
||||
@@ -85,17 +85,17 @@ fn JsonTokenType! JsonParser.lex_number(JsonParser* this, char c)
|
||||
if (negate)
|
||||
{
|
||||
t.append(c);
|
||||
c = this.read_next()!;
|
||||
c = this.read_next()?;
|
||||
}
|
||||
while (c >= '0' && c <= '9')
|
||||
{
|
||||
t.append(c);
|
||||
c = this.read_next()!;
|
||||
c = this.read_next()?;
|
||||
}
|
||||
if (c == '.')
|
||||
{
|
||||
t.append(c);
|
||||
while (c = this.read_next()!, c >= '0' && c <= '9')
|
||||
while (c = this.read_next()?, c >= '0' && c <= '9')
|
||||
{
|
||||
t.append(c);
|
||||
}
|
||||
@@ -103,24 +103,24 @@ fn JsonTokenType! JsonParser.lex_number(JsonParser* this, char c)
|
||||
if ((c | 32) == 'e')
|
||||
{
|
||||
t.append(c);
|
||||
c = this.read_next()!;
|
||||
c = this.read_next()?;
|
||||
switch (c)
|
||||
{
|
||||
case '-':
|
||||
case '+':
|
||||
t.append(c);
|
||||
c = this.read_next()!;
|
||||
c = this.read_next()?;
|
||||
}
|
||||
if (c < '0' || c > '9') return JsonParsingError.INVALID_NUMBER?;
|
||||
if (c < '0' || c > '9') return JsonParsingError.INVALID_NUMBER!;
|
||||
while (c >= '0' && c <= '9')
|
||||
{
|
||||
t.append(c);
|
||||
c = this.read_next()!;
|
||||
c = this.read_next()?;
|
||||
}
|
||||
}
|
||||
this.pushback();
|
||||
double! d = t.str().to_double() ?? JsonParsingError.INVALID_NUMBER?;
|
||||
this.last_number = d!;
|
||||
double! d = str::to_double(t.str()) ?? JsonParsingError.INVALID_NUMBER!;
|
||||
this.last_number = d?;
|
||||
return NUMBER;
|
||||
};
|
||||
}
|
||||
@@ -128,30 +128,30 @@ fn JsonTokenType! JsonParser.lex_number(JsonParser* this, char c)
|
||||
fn Object*! JsonParser.parse_map(JsonParser* this)
|
||||
{
|
||||
Object* map = object::new_obj(this.allocator);
|
||||
JsonTokenType token = this.advance()!;
|
||||
JsonTokenType token = this.advance()?;
|
||||
defer catch map.free();
|
||||
|
||||
DString temp_key = dstring::new_with_capacity(32, this.allocator);
|
||||
defer temp_key.free();
|
||||
while (token != JsonTokenType.RBRACE)
|
||||
{
|
||||
if (token != JsonTokenType.STRING) return JsonParsingError.UNEXPECTED_CHARACTER?;
|
||||
if (token != JsonTokenType.STRING) return JsonParsingError.UNEXPECTED_CHARACTER!;
|
||||
DString string = this.last_string;
|
||||
if (map.has_key(string.str())) return JsonParsingError.DUPLICATE_MEMBERS?;
|
||||
if (map.has_key(string.str())) return JsonParsingError.DUPLICATE_MEMBERS!;
|
||||
// Copy the key to our temp holder. We do this to work around the issue
|
||||
// if the temp allocator should be used as the default allocator.
|
||||
temp_key.clear();
|
||||
temp_key.append(string);
|
||||
this.parse_expected(COLON)!;
|
||||
Object* element = this.parse_any()!;
|
||||
this.parse_expected(COLON)?;
|
||||
Object* element = this.parse_any()?;
|
||||
map.set(temp_key.str(), element);
|
||||
token = this.advance()!;
|
||||
token = this.advance()?;
|
||||
if (token == JsonTokenType.COMMA)
|
||||
{
|
||||
token = this.advance()!;
|
||||
token = this.advance()?;
|
||||
continue;
|
||||
}
|
||||
if (token != JsonTokenType.RBRACE) return JsonParsingError.UNEXPECTED_CHARACTER?;
|
||||
if (token != JsonTokenType.RBRACE) return JsonParsingError.UNEXPECTED_CHARACTER!;
|
||||
}
|
||||
return map;
|
||||
}
|
||||
@@ -160,18 +160,18 @@ fn Object*! JsonParser.parse_array(JsonParser* this)
|
||||
{
|
||||
Object* list = object::new_obj(this.allocator);
|
||||
defer catch list.free();
|
||||
JsonTokenType token = this.advance()!;
|
||||
JsonTokenType token = this.advance()?;
|
||||
while (token != JsonTokenType.RBRACKET)
|
||||
{
|
||||
Object* element = this.parse_from_token(token)!;
|
||||
Object* element = this.parse_from_token(token)?;
|
||||
list.append(element);
|
||||
token = this.advance()!;
|
||||
token = this.advance()?;
|
||||
if (token == JsonTokenType.COMMA)
|
||||
{
|
||||
token = this.advance()!;
|
||||
token = this.advance()?;
|
||||
continue;
|
||||
}
|
||||
if (token != JsonTokenType.RBRACKET) return JsonParsingError.UNEXPECTED_CHARACTER?;
|
||||
if (token != JsonTokenType.RBRACKET) return JsonParsingError.UNEXPECTED_CHARACTER!;
|
||||
}
|
||||
return list;
|
||||
}
|
||||
@@ -191,7 +191,7 @@ fn char! JsonParser.read_next(JsonParser* this)
|
||||
this.reached_end = true;
|
||||
return '\0';
|
||||
default:
|
||||
return err?;
|
||||
return err!;
|
||||
}
|
||||
if (c == 0)
|
||||
{
|
||||
@@ -204,7 +204,7 @@ fn JsonTokenType! JsonParser.advance(JsonParser* this)
|
||||
{
|
||||
char c;
|
||||
// Skip whitespace
|
||||
while WS: (c = this.read_next()!)
|
||||
while WS: (c = this.read_next()?)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
@@ -218,7 +218,7 @@ fn JsonTokenType! JsonParser.advance(JsonParser* this)
|
||||
continue;
|
||||
case '/':
|
||||
if (!this.skip_comments) break;
|
||||
c = this.read_next()!;
|
||||
c = this.read_next()?;
|
||||
if (c != '*')
|
||||
{
|
||||
this.pushback();
|
||||
@@ -227,12 +227,12 @@ fn JsonTokenType! JsonParser.advance(JsonParser* this)
|
||||
while COMMENT: (1)
|
||||
{
|
||||
// Skip to */
|
||||
while (c = this.read_next()!)
|
||||
while (c = this.read_next()?)
|
||||
{
|
||||
if (c == '\n') this.line++;
|
||||
if (c != '*') continue;
|
||||
// Skip through all the '*'
|
||||
while (c = this.read_next()!)
|
||||
while (c = this.read_next()?)
|
||||
{
|
||||
if (c == '\n') this.line++;
|
||||
if (c != '*') break;
|
||||
@@ -248,7 +248,7 @@ fn JsonTokenType! JsonParser.advance(JsonParser* this)
|
||||
switch (c)
|
||||
{
|
||||
case '\0':
|
||||
return IoError.EOF?;
|
||||
return IoError.EOF!;
|
||||
case '{':
|
||||
return LBRACE;
|
||||
case '}':
|
||||
@@ -267,16 +267,16 @@ fn JsonTokenType! JsonParser.advance(JsonParser* this)
|
||||
case '0'..'9':
|
||||
return this.lex_number(c);
|
||||
case 't':
|
||||
this.match("rue")!;
|
||||
this.match("rue")?;
|
||||
return TRUE;
|
||||
case 'f':
|
||||
this.match("alse")!;
|
||||
this.match("alse")?;
|
||||
return FALSE;
|
||||
case 'n':
|
||||
this.match("ull")!;
|
||||
this.match("ull")?;
|
||||
return NULL;
|
||||
default:
|
||||
return JsonParsingError.UNEXPECTED_CHARACTER?;
|
||||
return JsonParsingError.UNEXPECTED_CHARACTER!;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -284,14 +284,14 @@ fn void! JsonParser.match(JsonParser* this, String str)
|
||||
{
|
||||
foreach (c : str)
|
||||
{
|
||||
char l = this.read_next()!;
|
||||
if (l != c) return JsonParsingError.UNEXPECTED_CHARACTER?;
|
||||
char l = this.read_next()?;
|
||||
if (l != c) return JsonParsingError.UNEXPECTED_CHARACTER!;
|
||||
}
|
||||
}
|
||||
|
||||
fn void! JsonParser.parse_expected(JsonParser* this, JsonTokenType token) @local
|
||||
{
|
||||
if (this.advance()! != token) return JsonParsingError.UNEXPECTED_CHARACTER?;
|
||||
if (this.advance()? != token) return JsonParsingError.UNEXPECTED_CHARACTER!;
|
||||
}
|
||||
|
||||
fn JsonTokenType! JsonParser.lex_string(JsonParser *this)
|
||||
@@ -299,13 +299,13 @@ fn JsonTokenType! JsonParser.lex_string(JsonParser *this)
|
||||
this.last_string.clear();
|
||||
while LOOP: (1)
|
||||
{
|
||||
char c = this.read_next()!;
|
||||
char c = this.read_next()?;
|
||||
switch (c)
|
||||
{
|
||||
case '\0':
|
||||
return JsonParsingError.EOF?;
|
||||
return JsonParsingError.EOF!;
|
||||
case 1..31:
|
||||
return JsonParsingError.UNEXPECTED_CHARACTER?;
|
||||
return JsonParsingError.UNEXPECTED_CHARACTER!;
|
||||
case '"':
|
||||
break LOOP;
|
||||
case '\\':
|
||||
@@ -314,13 +314,13 @@ fn JsonTokenType! JsonParser.lex_string(JsonParser *this)
|
||||
this.last_string.append(c);
|
||||
continue;
|
||||
}
|
||||
c = this.read_next()!;
|
||||
c = this.read_next()?;
|
||||
switch (c)
|
||||
{
|
||||
case '\0':
|
||||
return JsonParsingError.EOF?;
|
||||
return JsonParsingError.EOF!;
|
||||
case 1..31:
|
||||
return JsonParsingError.UNEXPECTED_CHARACTER?;
|
||||
return JsonParsingError.UNEXPECTED_CHARACTER!;
|
||||
case '"':
|
||||
case '\\':
|
||||
case '/':
|
||||
@@ -339,14 +339,14 @@ fn JsonTokenType! JsonParser.lex_string(JsonParser *this)
|
||||
uint val;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
c = this.read_next()!;
|
||||
if (!c.is_xdigit()) return JsonParsingError.INVALID_ESCAPE_SEQUENCE?;
|
||||
c = this.read_next()?;
|
||||
if (!c.is_xdigit()) return JsonParsingError.INVALID_ESCAPE_SEQUENCE!;
|
||||
val = val << 4 + (c > '9' ? (c | 32) - 'a' + 10 : c - '0');
|
||||
}
|
||||
this.last_string.append_char32(val);
|
||||
continue;
|
||||
default:
|
||||
return JsonParsingError.INVALID_ESCAPE_SEQUENCE?;
|
||||
return JsonParsingError.INVALID_ESCAPE_SEQUENCE!;
|
||||
}
|
||||
}
|
||||
return STRING;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// a copy of which can be found in the LICENSE_STDLIB file.
|
||||
module std::hash::fnv32a;
|
||||
|
||||
def Fnv32a = distinct uint;
|
||||
typedef Fnv32a = distinct uint;
|
||||
|
||||
const FNV32A_START @private = 0x811c9dc5;
|
||||
const FNV32A_MUL @private = 0x01000193;
|
||||
|
||||
@@ -96,7 +96,7 @@ macro @blk(&block, i) @local
|
||||
|
||||
macro @blk0(&block, i) @local
|
||||
{
|
||||
$if env::BIG_ENDIAN:
|
||||
$if (env::BIG_ENDIAN)
|
||||
return block.l[i];
|
||||
$else
|
||||
return block.l[i] = (block.l[i].rotl(24) & 0xFF00FF00)
|
||||
|
||||
@@ -25,7 +25,6 @@ fault IoError
|
||||
FILE_IS_PIPE,
|
||||
FILE_EOF,
|
||||
INCOMPLETE_WRITE,
|
||||
BUSY,
|
||||
NO_PERMISSION,
|
||||
OUT_OF_SPACE,
|
||||
INVALID_PUSHBACK,
|
||||
@@ -40,7 +39,6 @@ fault IoError
|
||||
NOT_SEEKABLE,
|
||||
NAME_TOO_LONG,
|
||||
WOULD_BLOCK,
|
||||
DIR_NOT_EMPTY,
|
||||
INTERRUPTED,
|
||||
GENERAL_ERROR,
|
||||
UNKNOWN_ERROR,
|
||||
@@ -57,16 +55,18 @@ macro void print(x)
|
||||
var $Type = $typeof(x);
|
||||
$switch ($Type)
|
||||
$case String:
|
||||
(void)stdout().print(x);
|
||||
catch? stdout().print(x);
|
||||
$case ZString:
|
||||
(void)stdout().print(x.as_str());
|
||||
catch? stdout().print(x.as_str());
|
||||
$case DString:
|
||||
(void)stdout().print(x.str());
|
||||
catch? stdout().print(x.str());
|
||||
$case VarString:
|
||||
catch? stdout().print(x.str());
|
||||
$default:
|
||||
$if @convertible(x, String):
|
||||
(void)stdout().print((String)x);
|
||||
$if (@convertible(x, String))
|
||||
catch? stdout().print((String)x);
|
||||
$else
|
||||
(void)stdout().printf("%s", x);
|
||||
catch? stdout().printf("%s", x);
|
||||
$endif
|
||||
$endswitch
|
||||
}
|
||||
@@ -76,20 +76,24 @@ macro void printn(x = "")
|
||||
var $Type = $typeof(x);
|
||||
$switch ($Type)
|
||||
$case String:
|
||||
(void)stdout().printn(x);
|
||||
catch? stdout().printn(x);
|
||||
$case ZString:
|
||||
(void)stdout().printn(x.as_str());
|
||||
catch? stdout().printn(x.as_str());
|
||||
$case DString:
|
||||
(void)stdout().printn(x.str());
|
||||
catch? stdout().printn(x.str());
|
||||
$case VarString:
|
||||
catch? stdout().printn(x.str());
|
||||
$default:
|
||||
$if @convertible(x, String):
|
||||
(void)stdout().printn((String)x);
|
||||
$if (@convertible(x, String))
|
||||
catch? stdout().printn((String)x);
|
||||
$else
|
||||
(void)stdout().printfn("%s", x);
|
||||
catch? stdout().printfn("%s", x);
|
||||
$endif
|
||||
$endswitch
|
||||
}
|
||||
|
||||
macro void println(x = "") @deprecated => printn(x);
|
||||
|
||||
fn File stdout()
|
||||
{
|
||||
return { libc::stdout() };
|
||||
|
||||
@@ -6,9 +6,9 @@ fn File! open(String filename, String mode)
|
||||
return { .file = os::native_fopen(filename, mode) };
|
||||
}
|
||||
|
||||
fn File! open_path(Path path, String mode)
|
||||
fn void! File.open(File* file, String filename, String mode) @deprecated
|
||||
{
|
||||
return { .file = os::native_fopen(path.as_str(), mode) };
|
||||
file.file = os::native_fopen(filename, mode)?;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -16,7 +16,7 @@ fn File! open_path(Path path, String mode)
|
||||
**/
|
||||
fn void! File.reopen(File* file, String filename, String mode)
|
||||
{
|
||||
file.file = os::native_freopen(file.file, filename, mode)!;
|
||||
file.file = os::native_freopen(file.file, filename, mode)?;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -24,7 +24,7 @@ fn void! File.reopen(File* file, String filename, String mode)
|
||||
**/
|
||||
fn usz! File.seek(File file, isz offset, Seek seek_mode = Seek.SET)
|
||||
{
|
||||
os::native_fseek(file.file, offset, seek_mode)!;
|
||||
os::native_fseek(file.file, offset, seek_mode)?;
|
||||
return os::native_ftell(file.file);
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ fn void! File.memopen(File* file, char[] data, String mode)
|
||||
*/
|
||||
fn void! File.putc(File *file, char c)
|
||||
{
|
||||
if (!libc::fputc(c, file.file)) return IoError.FILE_EOF?;
|
||||
if (!libc::fputc(c, file.file)) return IoError.FILE_EOF!;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -63,8 +63,8 @@ fn void! File.close(File *file) @inline
|
||||
switch (libc::errno())
|
||||
{
|
||||
case errno::ECONNRESET:
|
||||
case errno::EBADF: return IoError.FILE_NOT_VALID?;
|
||||
case errno::EINTR: return IoError.INTERRUPTED?;
|
||||
case errno::EBADF: return IoError.FILE_NOT_VALID!;
|
||||
case errno::EINTR: return IoError.INTERRUPTED!;
|
||||
case errno::EDQUOT:
|
||||
case errno::EFAULT:
|
||||
case errno::EAGAIN:
|
||||
@@ -72,8 +72,8 @@ fn void! File.close(File *file) @inline
|
||||
case errno::ENETDOWN:
|
||||
case errno::ENETUNREACH:
|
||||
case errno::ENOSPC:
|
||||
case errno::EIO: return IoError.INCOMPLETE_WRITE?;
|
||||
default: return IoError.UNKNOWN_ERROR?;
|
||||
case errno::EIO: return IoError.INCOMPLETE_WRITE!;
|
||||
default: return IoError.UNKNOWN_ERROR!;
|
||||
}
|
||||
}
|
||||
file.file = null;
|
||||
@@ -109,10 +109,10 @@ fn usz! File.write(File file, char[] buffer)
|
||||
* @param [&in] file
|
||||
* @require file.file `File must be initialized`
|
||||
*/
|
||||
fn usz! File.printn(File file, String string = "")
|
||||
fn usz! File.printn(File file, String string)
|
||||
{
|
||||
usz len = file.print(string)!;
|
||||
if (!libc::putc('\n', file.file)) return IoError.UNKNOWN_ERROR?;
|
||||
usz len = file.print(string)?;
|
||||
if (!libc::putc('\n', file.file)) return IoError.UNKNOWN_ERROR!;
|
||||
return len + 1;
|
||||
}
|
||||
|
||||
@@ -123,10 +123,12 @@ fn usz! File.printn(File file, String string = "")
|
||||
fn usz! File.print(File file, String string)
|
||||
{
|
||||
usz len = string.len;
|
||||
if (len != file.write((char[])string)!) return IoError.UNKNOWN_ERROR?;
|
||||
if (len != file.write((char[])string)?) return IoError.UNKNOWN_ERROR!;
|
||||
return len;
|
||||
}
|
||||
|
||||
fn usz! File.println(File file, String string) @deprecated => file.printn(string);
|
||||
|
||||
/**
|
||||
* @param [&in] file
|
||||
* @require file.file `File must be initialized`
|
||||
@@ -157,7 +159,7 @@ fn String File.tgetline(File* file)
|
||||
fn char! File.getc(File* file)
|
||||
{
|
||||
int c = libc::fgetc(file.file);
|
||||
if (c == -1) return IoError.FILE_EOF?;
|
||||
if (c == -1) return IoError.FILE_EOF!;
|
||||
return (char)c;
|
||||
}
|
||||
|
||||
|
||||
@@ -6,17 +6,17 @@ const char[16] XDIGITS_L = "0123456789abcdef";
|
||||
fn void! Formatter.left_adjust(Formatter* this, usz len) @local
|
||||
{
|
||||
if (!this.flags.left) return;
|
||||
for (usz l = len; l < this.width; l++) this.out(' ')!;
|
||||
for (usz l = len; l < this.width; l++) this.out(' ')?;
|
||||
}
|
||||
|
||||
fn void! Formatter.right_adjust(Formatter* this, usz len) @local
|
||||
{
|
||||
if (this.flags.left) return;
|
||||
for (usz l = len; l < this.width; l++) this.out(' ')!;
|
||||
for (usz l = len; l < this.width; l++) this.out(' ')?;
|
||||
}
|
||||
|
||||
|
||||
fn uint128! int_from_any(any arg, bool *is_neg) @private
|
||||
fn uint128! int_from_variant(variant arg, bool *is_neg) @private
|
||||
{
|
||||
*is_neg = false;
|
||||
if (arg.type.kindof == TypeKind.POINTER)
|
||||
@@ -25,7 +25,7 @@ fn uint128! int_from_any(any arg, bool *is_neg) @private
|
||||
}
|
||||
if (arg.type.kindof == TypeKind.DISTINCT)
|
||||
{
|
||||
return int_from_any(any { arg.ptr, arg.type.inner }, is_neg);
|
||||
return int_from_variant(variant { arg.ptr, arg.type.inner }, is_neg);
|
||||
}
|
||||
switch (arg)
|
||||
{
|
||||
@@ -63,21 +63,21 @@ fn uint128! int_from_any(any arg, bool *is_neg) @private
|
||||
double d = *arg;
|
||||
return (uint128)((*is_neg = d < 0) ? -d : d);
|
||||
default:
|
||||
return PrintFault.INVALID_ARGUMENT_TYPE?;
|
||||
return PrintFault.INVALID_ARGUMENT_TYPE!;
|
||||
}
|
||||
}
|
||||
|
||||
fn FloatType! float_from_any(any arg) @private
|
||||
fn FloatType! float_from_variant(variant arg) @private
|
||||
{
|
||||
$if env::F128_SUPPORT:
|
||||
$if (env::F128_SUPPORT)
|
||||
if (arg.type == float128.typeid) return (FloatType)*((float128*)arg.ptr);
|
||||
$endif
|
||||
$if env::F16_SUPPORT:
|
||||
$if (env::F16_SUPPORT)
|
||||
if (arg.type == float16.typeid) return *((float16*)arg.ptr);
|
||||
$endif
|
||||
if (arg.type.kindof == TypeKind.DISTINCT)
|
||||
{
|
||||
return float_from_any(any { arg.ptr, arg.type.inner });
|
||||
return float_from_variant(variant { arg.ptr, arg.type.inner });
|
||||
}
|
||||
switch (arg)
|
||||
{
|
||||
@@ -108,7 +108,7 @@ fn FloatType! float_from_any(any arg) @private
|
||||
case double:
|
||||
return (FloatType)*arg;
|
||||
default:
|
||||
return PrintFault.INVALID_ARGUMENT_TYPE?;
|
||||
return PrintFault.INVALID_ARGUMENT_TYPE!;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ fn void! Formatter.out_substr(Formatter *this, String str) @private
|
||||
usz l = conv::utf8_codepoints(str);
|
||||
uint prec = this.prec;
|
||||
if (this.flags.precision && l < prec) l = prec;
|
||||
this.right_adjust(' ')!;
|
||||
this.right_adjust(' ')?;
|
||||
usz index = 0;
|
||||
usz chars = str.len;
|
||||
char* ptr = str.ptr;
|
||||
@@ -150,7 +150,7 @@ fn void! Formatter.out_substr(Formatter *this, String str) @private
|
||||
char c = ptr[index];
|
||||
// Break if we have precision set and we ran out...
|
||||
if (c & 0xC0 != 0x80 && this.flags.precision && !prec--) break;
|
||||
this.out(c)!;
|
||||
this.out(c)?;
|
||||
index++;
|
||||
}
|
||||
return this.left_adjust(l);
|
||||
@@ -158,7 +158,7 @@ fn void! Formatter.out_substr(Formatter *this, String str) @private
|
||||
|
||||
fn void! Formatter.pad(Formatter* this, char c, isz width, isz len) @inline
|
||||
{
|
||||
for (isz i = len; i < width; i++) this.out(c)!;
|
||||
for (isz i = len; i < width; i++) this.out(c)?;
|
||||
}
|
||||
|
||||
fn char* fmt_u(uint128 x, char* s)
|
||||
@@ -170,7 +170,7 @@ fn char* fmt_u(uint128 x, char* s)
|
||||
|
||||
fn void! Formatter.out_chars(Formatter* this, char[] s)
|
||||
{
|
||||
foreach (c : s) this.out(c)!;
|
||||
foreach (c : s) this.out(c)?;
|
||||
}
|
||||
|
||||
enum FloatFormatting
|
||||
@@ -203,12 +203,12 @@ fn void! Formatter.floatformat(Formatter* this, FloatFormatting formatting, doub
|
||||
if (!math::is_finite(y))
|
||||
{
|
||||
// Add padding
|
||||
if (!this.flags.left) this.pad(' ', this.width, 3 + pl)!;
|
||||
if (!this.flags.left) this.pad(' ', this.width, 3 + pl)?;
|
||||
String s = this.flags.uppercase ? "INF" : "inf";
|
||||
if (y != y) this.flags.uppercase ? "NAN" : "nan";
|
||||
if (pl) this.out(is_neg ? '-' : '+')!;
|
||||
this.out_chars(s)!;
|
||||
if (this.flags.left) this.pad(' ', this.width, 3 + pl)!;
|
||||
if (pl) this.out(is_neg ? '-' : '+')?;
|
||||
this.out_chars(s)?;
|
||||
if (this.flags.left) this.pad(' ', this.width, 3 + pl)?;
|
||||
return;
|
||||
}
|
||||
// Rescale
|
||||
@@ -260,18 +260,18 @@ fn void! Formatter.floatformat(Formatter* this, FloatFormatting formatting, doub
|
||||
} while (y);
|
||||
isz outlen = s - buf;
|
||||
isz explen = ebuf - estr;
|
||||
if (p > int.max - 2 - explen - pl) return PrintFault.INTERNAL_BUFFER_EXCEEDED?;
|
||||
if (p > int.max - 2 - explen - pl) return PrintFault.INTERNAL_BUFFER_EXCEEDED!;
|
||||
usz l = p && outlen - 2 < p
|
||||
? p + 2 + explen
|
||||
: outlen + explen;
|
||||
if (!this.flags.left && !this.flags.zeropad) this.pad(' ', this.width, pl + l)!;
|
||||
if (is_neg || this.flags.plus) this.out(is_neg ? '-' : '+')!;
|
||||
this.out_chars(this.flags.uppercase ? "0X" : "0x")!;
|
||||
if (this.flags.zeropad) this.pad('0', this.width, pl + l)!;
|
||||
this.out_chars(buf[:outlen])!;
|
||||
this.pad('0', l - outlen - explen, 0)!;
|
||||
this.out_chars(estr[:explen])!;
|
||||
if (this.flags.left) this.pad(' ', this.width, pl + l)!;
|
||||
if (!this.flags.left && !this.flags.zeropad) this.pad(' ', this.width, pl + l)?;
|
||||
if (is_neg || this.flags.plus) this.out(is_neg ? '-' : '+')?;
|
||||
this.out_chars(this.flags.uppercase ? "0X" : "0x")?;
|
||||
if (this.flags.zeropad) this.pad('0', this.width, pl + l)?;
|
||||
this.out_chars(buf[:outlen])?;
|
||||
this.pad('0', l - outlen - explen, 0)?;
|
||||
this.out_chars(estr[:explen])?;
|
||||
if (this.flags.left) this.pad(' ', this.width, pl + l)?;
|
||||
return;
|
||||
}
|
||||
if (p < 0) p = 6;
|
||||
@@ -427,12 +427,12 @@ fn void! Formatter.floatformat(Formatter* this, FloatFormatting formatting, doub
|
||||
}
|
||||
}
|
||||
}
|
||||
if (p > int.max - 1 - (isz)(p || this.flags.hash)) return PrintFault.INTERNAL_BUFFER_EXCEEDED?;
|
||||
if (p > int.max - 1 - (isz)(p || this.flags.hash)) return PrintFault.INTERNAL_BUFFER_EXCEEDED!;
|
||||
int l = (int)(1 + p + (isz)(p || this.flags.hash));
|
||||
char* estr @noinit;
|
||||
if (formatting == FLOAT)
|
||||
{
|
||||
if (e > int.max - l) return PrintFault.INTERNAL_BUFFER_EXCEEDED?;
|
||||
if (e > int.max - l) return PrintFault.INTERNAL_BUFFER_EXCEEDED!;
|
||||
if (e > 0) l += e;
|
||||
}
|
||||
else
|
||||
@@ -441,13 +441,13 @@ fn void! Formatter.floatformat(Formatter* this, FloatFormatting formatting, doub
|
||||
while (ebuf - estr < 2) (--estr)[0] = '0';
|
||||
*--estr = (e < 0 ? '-' : '+');
|
||||
*--estr = this.flags.uppercase ? 'E' : 'e';
|
||||
if (ebuf - estr > (isz)int.max - l) return PrintFault.INTERNAL_BUFFER_EXCEEDED?;
|
||||
if (ebuf - estr > (isz)int.max - l) return PrintFault.INTERNAL_BUFFER_EXCEEDED!;
|
||||
l += (int)(ebuf - estr);
|
||||
}
|
||||
if (l > int.max - pl) return PrintFault.INTERNAL_BUFFER_EXCEEDED?;
|
||||
if (!this.flags.left && !this.flags.zeropad) this.pad(' ', this.width, pl + l)!;
|
||||
if (is_neg || this.flags.plus) this.out(is_neg ? '-' : '+')!;
|
||||
if (this.flags.zeropad) this.pad('0', this.width, pl + l)!;
|
||||
if (l > int.max - pl) return PrintFault.INTERNAL_BUFFER_EXCEEDED!;
|
||||
if (!this.flags.left && !this.flags.zeropad) this.pad(' ', this.width, pl + l)?;
|
||||
if (is_neg || this.flags.plus) this.out(is_neg ? '-' : '+')?;
|
||||
if (this.flags.zeropad) this.pad('0', this.width, pl + l)?;
|
||||
if (formatting == FLOAT)
|
||||
{
|
||||
if (a > r) a = r;
|
||||
@@ -462,16 +462,16 @@ fn void! Formatter.floatformat(Formatter* this, FloatFormatting formatting, doub
|
||||
case s == buf + 9:
|
||||
*--s = '0';
|
||||
}
|
||||
this.out_chars(s[:buf + 9 - s])!;
|
||||
this.out_chars(s[:buf + 9 - s])?;
|
||||
}
|
||||
if (p || this.flags.hash) this.out('.')!;
|
||||
if (p || this.flags.hash) this.out('.')?;
|
||||
for (; d < z && p > 0; d++, p -= 9)
|
||||
{
|
||||
char* s = fmt_u(*d, buf + 9);
|
||||
while (s > buf) *--s = '0';
|
||||
this.out_chars(s[:math::min((isz)9, p)])!;
|
||||
this.out_chars(s[:math::min((isz)9, p)])?;
|
||||
}
|
||||
this.pad('0', p + 9, 9)!;
|
||||
this.pad('0', p + 9, 9)?;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -486,17 +486,17 @@ fn void! Formatter.floatformat(Formatter* this, FloatFormatting formatting, doub
|
||||
}
|
||||
else
|
||||
{
|
||||
this.out(s++[0])!;
|
||||
if (p > 0 || this.flags.hash) this.out('.')!;
|
||||
this.out(s++[0])?;
|
||||
if (p > 0 || this.flags.hash) this.out('.')?;
|
||||
}
|
||||
this.out_chars(s[:math::min(buf + 9 - s, p)])!;
|
||||
this.out_chars(s[:math::min(buf + 9 - s, p)])?;
|
||||
p -= buf + 9 - s;
|
||||
}
|
||||
this.pad('0', p + 18, 18)!;
|
||||
this.out_chars(estr[:ebuf - estr])!;
|
||||
this.pad('0', p + 18, 18)?;
|
||||
this.out_chars(estr[:ebuf - estr])?;
|
||||
}
|
||||
|
||||
if (this.flags.left) this.pad(' ', this.width, pl + l)!;
|
||||
if (this.flags.left) this.pad(' ', this.width, pl + l)?;
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -515,7 +515,7 @@ fn void! Formatter.ntoa(Formatter* this, uint128 value, bool negative, uint base
|
||||
char past_10 = (this.flags.uppercase ? 'A' : 'a') - 10;
|
||||
do
|
||||
{
|
||||
if (len >= PRINTF_NTOA_BUFFER_SIZE) return PrintFault.INTERNAL_BUFFER_EXCEEDED?;
|
||||
if (len >= PRINTF_NTOA_BUFFER_SIZE) return PrintFault.INTERNAL_BUFFER_EXCEEDED!;
|
||||
char digit = (char)(value % base);
|
||||
buf[len++] = digit + (digit < 10 ? '0' : past_10);
|
||||
value /= base;
|
||||
@@ -533,12 +533,12 @@ fn void! Formatter.ntoa_format(Formatter* this, String buf, usz len, bool negati
|
||||
if (this.width && this.flags.zeropad && (negative || this.flags.plus || this.flags.space)) this.width--;
|
||||
while (len < this.prec)
|
||||
{
|
||||
if (len >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED?;
|
||||
if (len >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED!;
|
||||
buf[len++] = '0';
|
||||
}
|
||||
while (this.flags.zeropad && len < this.width)
|
||||
{
|
||||
if (len >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED?;
|
||||
if (len >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED!;
|
||||
buf[len++] = '0';
|
||||
}
|
||||
}
|
||||
@@ -553,7 +553,7 @@ fn void! Formatter.ntoa_format(Formatter* this, String buf, usz len, bool negati
|
||||
}
|
||||
if (base != 10)
|
||||
{
|
||||
if (len + 1 >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED?;
|
||||
if (len + 1 >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED!;
|
||||
switch (base)
|
||||
{
|
||||
case 16:
|
||||
@@ -572,13 +572,13 @@ fn void! Formatter.ntoa_format(Formatter* this, String buf, usz len, bool negati
|
||||
switch (true)
|
||||
{
|
||||
case negative:
|
||||
if (len >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED?;
|
||||
if (len >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED!;
|
||||
buf[len++] = '-';
|
||||
case this.flags.plus:
|
||||
if (len >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED?;
|
||||
if (len >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED!;
|
||||
buf[len++] = '+';
|
||||
case this.flags.space:
|
||||
if (len >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED?;
|
||||
if (len >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED!;
|
||||
buf[len++] = ' ';
|
||||
}
|
||||
if (!len) return;
|
||||
@@ -586,36 +586,36 @@ fn void! Formatter.ntoa_format(Formatter* this, String buf, usz len, bool negati
|
||||
}
|
||||
|
||||
|
||||
fn void! Formatter.ntoa_any(Formatter* this, any arg, uint base) @private
|
||||
fn void! Formatter.ntoa_variant(Formatter* this, variant arg, uint base) @private
|
||||
{
|
||||
bool is_neg;
|
||||
uint128 val = int_from_any(arg, &is_neg)!!;
|
||||
uint128 val = int_from_variant(arg, &is_neg)!!;
|
||||
return this.ntoa(val, is_neg, base) @inline;
|
||||
}
|
||||
|
||||
fn void! Formatter.out_char(Formatter* this, any arg) @private
|
||||
fn void! Formatter.out_char(Formatter* this, variant arg) @private
|
||||
{
|
||||
uint l = 1;
|
||||
// pre padding
|
||||
this.right_adjust(l)!;
|
||||
this.right_adjust(l)?;
|
||||
// char output
|
||||
Char32 c = types::any_to_int(arg, uint) ?? 0xFFFD;
|
||||
Char32 c = types::variant_to_int(arg, uint) ?? 0xFFFD;
|
||||
switch (true)
|
||||
{
|
||||
case c < 0x7f:
|
||||
this.out((char)c)!;
|
||||
this.out((char)c)?;
|
||||
case c < 0x7ff:
|
||||
this.out((char)(0xC0 | c >> 6))!;
|
||||
this.out((char)(0x80 | (c & 0x3F)))!;
|
||||
this.out((char)(0xC0 | c >> 6))?;
|
||||
this.out((char)(0x80 | (c & 0x3F)))?;
|
||||
case c < 0xffff:
|
||||
this.out((char)(0xE0 | c >> 12))!;
|
||||
this.out((char)(0x80 | (c >> 6 & 0x3F)))!;
|
||||
this.out((char)(0x80 | (c & 0x3F)))!;
|
||||
this.out((char)(0xE0 | c >> 12))?;
|
||||
this.out((char)(0x80 | (c >> 6 & 0x3F)))?;
|
||||
this.out((char)(0x80 | (c & 0x3F)))?;
|
||||
default:
|
||||
this.out((char)(0xF0 | c >> 18))!;
|
||||
this.out((char)(0x80 | (c >> 12 & 0x3F)))!;
|
||||
this.out((char)(0x80 | (c >> 6 & 0x3F)))!;
|
||||
this.out((char)(0x80 | (c & 0x3F)))!;
|
||||
this.out((char)(0xF0 | c >> 18))?;
|
||||
this.out((char)(0x80 | (c >> 12 & 0x3F)))?;
|
||||
this.out((char)(0x80 | (c >> 6 & 0x3F)))?;
|
||||
this.out((char)(0x80 | (c & 0x3F)))?;
|
||||
}
|
||||
return this.left_adjust(l);
|
||||
}
|
||||
@@ -630,11 +630,11 @@ fn void! Formatter.out_reverse(Formatter* this, char[] buf) @private
|
||||
{
|
||||
for (usz i = len; i < this.width; i++)
|
||||
{
|
||||
this.out(' ')!;
|
||||
this.out(' ')?;
|
||||
}
|
||||
}
|
||||
// reverse string
|
||||
while (len) this.out(buf[--len])!;
|
||||
while (len) this.out(buf[--len])?;
|
||||
|
||||
// append pad spaces up to given width
|
||||
return this.left_adjust(this.idx - buffer_start_idx);
|
||||
@@ -643,25 +643,25 @@ fn void! Formatter.out_reverse(Formatter* this, char[] buf) @private
|
||||
fn void! printf_advance_format(usz format_len, usz *index_ptr) @inline @private
|
||||
{
|
||||
usz val = ++(*index_ptr);
|
||||
if (val >= format_len) return FormattingFault.UNTERMINATED_FORMAT?;
|
||||
if (val >= format_len) return FormattingFault.UNTERMINATED_FORMAT!;
|
||||
}
|
||||
|
||||
fn any! next_any(any* args_ptr, usz args_len, usz* arg_index_ptr) @inline @private
|
||||
fn variant! next_variant(variant* args_ptr, usz args_len, usz* arg_index_ptr) @inline @private
|
||||
{
|
||||
if (*arg_index_ptr >= args_len) return FormattingFault.MISSING_ARG?;
|
||||
if (*arg_index_ptr >= args_len) return FormattingFault.MISSING_ARG!;
|
||||
return args_ptr[(*arg_index_ptr)++];
|
||||
}
|
||||
|
||||
fn int! printf_parse_format_field(
|
||||
any* args_ptr, usz args_len, usz* args_index_ptr,
|
||||
variant* args_ptr, usz args_len, usz* args_index_ptr,
|
||||
char* format_ptr, usz format_len, usz* index_ptr) @inline @private
|
||||
{
|
||||
char c = format_ptr[*index_ptr];
|
||||
if (c >= '0' && c <= '9') return simple_atoi(format_ptr, format_len, index_ptr);
|
||||
if (c != '*') return 0;
|
||||
printf_advance_format(format_len, index_ptr)!;
|
||||
any val = next_any(args_ptr, args_len, args_index_ptr)!;
|
||||
if (!val.type.kindof.is_int()) return FormattingFault.INVALID_WIDTH_ARG?;
|
||||
uint! intval = types::any_to_int(val, int);
|
||||
return intval ?? FormattingFault.INVALID_WIDTH_ARG?;
|
||||
printf_advance_format(format_len, index_ptr)?;
|
||||
variant val = next_variant(args_ptr, args_len, args_index_ptr)?;
|
||||
if (!val.type.kindof.is_int()) return FormattingFault.INVALID_WIDTH_ARG!;
|
||||
uint! intval = types::variant_to_int(val, int);
|
||||
return intval ?? FormattingFault.INVALID_WIDTH_ARG!;
|
||||
}
|
||||
|
||||
@@ -21,11 +21,10 @@ fault FormattingFault
|
||||
INVALID_FORMAT_TYPE,
|
||||
}
|
||||
|
||||
def OutputFn = fn void!(char c, void* buffer);
|
||||
def FloatType = double;
|
||||
|
||||
fn String any.to_string(void* value, Allocator *using) @interface;
|
||||
fn void! any.to_format(void* value, Formatter* formatter) @interface;
|
||||
typedef OutputFn = fn void!(char c, void* buffer);
|
||||
typedef ToStringFunction = fn String(void* value, Allocator *using);
|
||||
typedef ToFormatFunction = fn void!(void* value, Formatter* formatter);
|
||||
typedef FloatType = double;
|
||||
|
||||
fn usz! printf(String format, args...) @maydiscard
|
||||
{
|
||||
@@ -34,21 +33,39 @@ fn usz! printf(String format, args...) @maydiscard
|
||||
return formatter.vprintf(format, args);
|
||||
}
|
||||
|
||||
define printfln = printfn;
|
||||
|
||||
fn usz! printfn(String format, args...) @maydiscard
|
||||
{
|
||||
Formatter formatter;
|
||||
formatter.init(&out_putchar_fn);
|
||||
usz len = formatter.vprintf(format, args)!;
|
||||
usz len = formatter.vprintf(format, args)?;
|
||||
putchar('\n');
|
||||
return len + 1;
|
||||
}
|
||||
|
||||
fn usz! VarString.printf(VarString* str, String format, args...) @maydiscard
|
||||
{
|
||||
Formatter formatter;
|
||||
formatter.init(&out_string_append_fn, str);
|
||||
return formatter.vprintf(format, args);
|
||||
}
|
||||
|
||||
fn usz! VarString.printfn(VarString* str, String format, args...) @maydiscard
|
||||
{
|
||||
Formatter formatter;
|
||||
formatter.init(&out_string_append_fn, str);
|
||||
usz len = formatter.vprintf(format, args)?;
|
||||
str.append('\n');
|
||||
return len + 1;
|
||||
}
|
||||
|
||||
fn char[]! bprintf(char[] buffer, String format, args...) @maydiscard
|
||||
{
|
||||
Formatter formatter;
|
||||
BufferData data = { .buffer = buffer };
|
||||
formatter.init(&out_buffer_fn, &data);
|
||||
usz size = formatter.vprintf(format, args)!;
|
||||
usz size = formatter.vprintf(format, args)?;
|
||||
return buffer[:data.written];
|
||||
}
|
||||
|
||||
@@ -56,15 +73,15 @@ fn usz! File.printf(File file, String format, args...) @maydiscard
|
||||
{
|
||||
Formatter formatter;
|
||||
formatter.init(&out_fputchar_fn, &file);
|
||||
return formatter.vprintf(format, args)!;
|
||||
return formatter.vprintf(format, args)?;
|
||||
}
|
||||
|
||||
fn usz! File.printfn(File file, String format, args...) @maydiscard
|
||||
{
|
||||
Formatter formatter;
|
||||
formatter.init(&out_fputchar_fn, &file);
|
||||
usz len = formatter.vprintf(format, args)!;
|
||||
file.putc('\n')!;
|
||||
usz len = formatter.vprintf(format, args)?;
|
||||
file.putc('\n')?;
|
||||
file.flush();
|
||||
return len + 1;
|
||||
}
|
||||
@@ -103,14 +120,49 @@ fn void Formatter.init(Formatter* this, OutputFn out_fn, void* data = null)
|
||||
*this = { .data = data, .out_fn = out_fn};
|
||||
}
|
||||
|
||||
fn void! Formatter.out(Formatter* this, char c) @private
|
||||
/**
|
||||
* @require $checks($Type a, a.to_string()) || $checks($Type a, a.to_format(&&Formatter{})) "Expected a type with 'to_string' or 'to_format' defined"
|
||||
* @require !$checks($Type a, a.to_string()) || $checks($Type a, a.to_string(&&Allocator{})) "Expected 'to_string' to take an allocator as argument."
|
||||
* @require !$checks($Type a, a.to_format(&&Formatter{})) || $checks($Type a, Formatter b, a.to_format(&b)) "Expected 'to_format' to take a Formatter as argument."
|
||||
*/
|
||||
macro void formatter_register_type($Type)
|
||||
{
|
||||
this.out_fn(c, this.data)!;
|
||||
$if ($checks($Type a, a.to_format(&&Formatter {})))
|
||||
if (!toformat_functions.table.len)
|
||||
{
|
||||
toformat_functions.init(64);
|
||||
}
|
||||
toformat_functions.set($Type.typeid, (ToFormatFunction)&$Type.to_format);
|
||||
$else
|
||||
if (!tostring_functions.table.len)
|
||||
{
|
||||
tostring_functions.init(64);
|
||||
}
|
||||
tostring_functions.set($Type.typeid, (ToStringFunction)&$Type.to_string);
|
||||
$endif
|
||||
}
|
||||
|
||||
macro bool! Formatter.print_with_function(Formatter* this, any arg)
|
||||
|
||||
static initialize @priority(101)
|
||||
{
|
||||
if (&arg.to_format)
|
||||
if (!toformat_functions.table.len)
|
||||
{
|
||||
toformat_functions.init(64);
|
||||
}
|
||||
if (!tostring_functions.table.len)
|
||||
{
|
||||
tostring_functions.init(64);
|
||||
}
|
||||
}
|
||||
|
||||
fn void! Formatter.out(Formatter* this, char c) @private
|
||||
{
|
||||
this.out_fn(c, this.data)?;
|
||||
}
|
||||
|
||||
macro bool! Formatter.print_with_function(Formatter* this, variant arg)
|
||||
{
|
||||
if (try to_format = toformat_functions.get(arg.type))
|
||||
{
|
||||
PrintFlags old = this.flags;
|
||||
uint old_width = this.width;
|
||||
@@ -121,10 +173,10 @@ macro bool! Formatter.print_with_function(Formatter* this, any arg)
|
||||
this.width = old_width;
|
||||
this.prec = old_prec;
|
||||
}
|
||||
arg.to_format(this)!;
|
||||
to_format(arg.ptr, this)?;
|
||||
return true;
|
||||
}
|
||||
if (&arg.to_string)
|
||||
}
|
||||
if (try to_string = tostring_functions.get(arg.type))
|
||||
{
|
||||
PrintFlags old = this.flags;
|
||||
uint old_width = this.width;
|
||||
@@ -137,92 +189,96 @@ macro bool! Formatter.print_with_function(Formatter* this, any arg)
|
||||
}
|
||||
@pool()
|
||||
{
|
||||
this.out_substr(arg.to_string(mem::temp()))!;
|
||||
this.out_substr(to_string(arg.ptr, mem::temp()))?;
|
||||
return true;
|
||||
};
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
fn void! Formatter.out_str(Formatter* this, any arg) @private
|
||||
fn void! Formatter.out_str(Formatter* this, variant arg) @private
|
||||
{
|
||||
switch (arg.type.kindof)
|
||||
{
|
||||
case TYPEID:
|
||||
return this.out_substr("typeid");
|
||||
return this.out_substr("<typeid>");
|
||||
case VOID:
|
||||
return this.out_substr("void");
|
||||
case ANYFAULT:
|
||||
case ANYERR:
|
||||
case FAULT:
|
||||
return this.out_substr((*(anyfault*)arg.ptr).nameof);
|
||||
case ANY:
|
||||
return this.out_str(*(any*)arg);
|
||||
return this.out_substr((*(anyerr*)arg.ptr).nameof);
|
||||
case VARIANT:
|
||||
return this.out_str(*(variant*)arg);
|
||||
case ENUM:
|
||||
if (this.print_with_function(arg)!) return;
|
||||
return this.out_substr(arg.type.names[types::any_to_int(arg, usz)!!]);
|
||||
if (this.print_with_function(arg)?) return;
|
||||
return this.out_substr(arg.type.names[types::variant_to_int(arg, usz)!!]);
|
||||
case STRUCT:
|
||||
if (this.print_with_function(arg)!) return;
|
||||
if (this.print_with_function(arg)?) return;
|
||||
return this.out_substr("<struct>");
|
||||
case UNION:
|
||||
if (this.print_with_function(arg)!) return;
|
||||
if (this.print_with_function(arg)?) return;
|
||||
return this.out_substr("<union>");
|
||||
case BITSTRUCT:
|
||||
if (this.print_with_function(arg)!) return;
|
||||
if (this.print_with_function(arg)?) return;
|
||||
return this.out_substr("<bitstruct>");
|
||||
case FUNC:
|
||||
if (this.print_with_function(arg)!) return;
|
||||
if (this.print_with_function(arg)?) return;
|
||||
return this.out_substr("<function>");
|
||||
case OPTIONAL:
|
||||
unreachable();
|
||||
case DISTINCT:
|
||||
if (this.print_with_function(arg)!) return;
|
||||
if (this.print_with_function(arg)?) return;
|
||||
if (arg.type == VarString.typeid)
|
||||
{
|
||||
return this.out_substr(((VarString*)arg).str());
|
||||
}
|
||||
if (arg.type == DString.typeid)
|
||||
{
|
||||
return this.out_substr(((DString*)arg).str());
|
||||
}
|
||||
return this.out_str(any { arg.ptr, arg.type.inner });
|
||||
return this.out_str(variant { arg.ptr, arg.type.inner });
|
||||
case POINTER:
|
||||
if (this.print_with_function(arg)!) return;
|
||||
return this.ntoa_any(arg, 16);
|
||||
if (this.print_with_function(arg)?) return;
|
||||
return this.ntoa_variant(arg, 16);
|
||||
case SIGNED_INT:
|
||||
case UNSIGNED_INT:
|
||||
return this.ntoa_any(arg, 10);
|
||||
return this.ntoa_variant(arg, 10);
|
||||
case FLOAT:
|
||||
return this.ftoa(float_from_any(arg)!!);
|
||||
return this.ftoa(float_from_variant(arg)!!);
|
||||
case ARRAY:
|
||||
if (this.print_with_function(arg)!) return;
|
||||
if (this.print_with_function(arg)?) return;
|
||||
// this is SomeType[*] so grab the "SomeType"
|
||||
typeid inner = arg.type.inner;
|
||||
usz size = inner.sizeof;
|
||||
usz len = arg.type.len;
|
||||
// Pretend this is a String
|
||||
void* ptr = (void*)arg.ptr;
|
||||
this.out('[')!;
|
||||
this.out('[')?;
|
||||
for (usz i = 0; i < len; i++)
|
||||
{
|
||||
if (i != 0) this.out_substr(", ")!;
|
||||
this.out_str(any { ptr, inner })!;
|
||||
if (i != 0) this.out_substr(", ")?;
|
||||
this.out_str(variant { ptr, inner })?;
|
||||
ptr += size;
|
||||
}
|
||||
return this.out(']');
|
||||
case VECTOR:
|
||||
if (this.print_with_function(arg)!) return;
|
||||
if (this.print_with_function(arg)?) return;
|
||||
// this is SomeType[*] so grab the "SomeType"
|
||||
typeid inner = arg.type.inner;
|
||||
usz size = inner.sizeof;
|
||||
usz len = arg.type.len;
|
||||
// Pretend this is a String
|
||||
void* ptr = (void*)arg.ptr;
|
||||
this.out_substr("[<")!;
|
||||
this.out_substr("[<")?;
|
||||
for (usz i = 0; i < len; i++)
|
||||
{
|
||||
if (i != 0) this.out_substr(", ")!;
|
||||
this.out_str(any { ptr, inner })!;
|
||||
if (i != 0) this.out_substr(", ")?;
|
||||
this.out_str(variant { ptr, inner })?;
|
||||
ptr += size;
|
||||
}
|
||||
return this.out_substr(">]");
|
||||
case SUBARRAY:
|
||||
if (this.print_with_function(arg)!) return;
|
||||
if (this.print_with_function(arg)?) return;
|
||||
// this is SomeType[] so grab the "SomeType"
|
||||
typeid inner = arg.type.inner;
|
||||
if (inner == char.typeid)
|
||||
@@ -234,18 +290,25 @@ fn void! Formatter.out_str(Formatter* this, any arg) @private
|
||||
String* temp = (void*)arg.ptr;
|
||||
void* ptr = (void*)temp.ptr;
|
||||
usz len = temp.len;
|
||||
this.out('[')!;
|
||||
this.out('[')?;
|
||||
for (usz i = 0; i < len; i++)
|
||||
{
|
||||
if (i != 0) this.out_substr(", ")!;
|
||||
this.out_str(any { ptr, inner })!;
|
||||
if (i != 0) this.out_substr(", ")?;
|
||||
this.out_str(variant { ptr, inner })?;
|
||||
ptr += size;
|
||||
}
|
||||
this.out(']')!;
|
||||
this.out(']')?;
|
||||
case BOOL:
|
||||
return this.out_substr(*(bool*)arg.ptr ? "true" : "false");
|
||||
if (*(bool*)arg.ptr)
|
||||
{
|
||||
return this.out_substr("true");
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.out_substr("false");
|
||||
}
|
||||
default:
|
||||
if (this.print_with_function(arg)!) return;
|
||||
if (this.print_with_function(arg)?) return;
|
||||
return this.out_substr("Invalid type");
|
||||
}
|
||||
}
|
||||
@@ -255,7 +318,7 @@ fn void! Formatter.out_str(Formatter* this, any arg) @private
|
||||
fn void! out_buffer_fn(char c, void *data) @private
|
||||
{
|
||||
BufferData *buffer_data = data;
|
||||
if (buffer_data.written >= buffer_data.buffer.len) return PrintFault.BUFFER_EXCEEDED?;
|
||||
if (buffer_data.written >= buffer_data.buffer.len) return PrintFault.BUFFER_EXCEEDED!;
|
||||
buffer_data.buffer[buffer_data.written++] = c;
|
||||
}
|
||||
|
||||
@@ -271,9 +334,16 @@ fn void! out_putchar_fn(char c, void* data @unused) @private
|
||||
fn void! out_fputchar_fn(char c, void* data) @private
|
||||
{
|
||||
File* f = data;
|
||||
f.putc(c)!;
|
||||
f.putc(c)?;
|
||||
}
|
||||
|
||||
fn void! out_string_append_fn(char c, void* data) @private
|
||||
{
|
||||
VarString* s = data;
|
||||
s.append_char(c);
|
||||
}
|
||||
|
||||
|
||||
struct BufferData @private
|
||||
{
|
||||
char[] buffer;
|
||||
@@ -281,7 +351,7 @@ struct BufferData @private
|
||||
}
|
||||
|
||||
|
||||
fn usz! Formatter.vprintf(Formatter* this, String format, any[] anys)
|
||||
fn usz! Formatter.vprintf(Formatter* this, String format, variant[] variants)
|
||||
{
|
||||
if (!this.out_fn)
|
||||
{
|
||||
@@ -297,15 +367,15 @@ fn usz! Formatter.vprintf(Formatter* this, String format, any[] anys)
|
||||
if (c != '%')
|
||||
{
|
||||
// no
|
||||
this.out(c)!;
|
||||
this.out(c)?;
|
||||
continue;
|
||||
}
|
||||
i++;
|
||||
if (i >= format_len) return PrintFault.INVALID_FORMAT_STRING?;
|
||||
if (i >= format_len) return PrintFault.INVALID_FORMAT_STRING!;
|
||||
c = format[i];
|
||||
if (c == '%')
|
||||
{
|
||||
this.out(c)!;
|
||||
this.out(c)?;
|
||||
continue;
|
||||
}
|
||||
// evaluate flags
|
||||
@@ -321,11 +391,11 @@ fn usz! Formatter.vprintf(Formatter* this, String format, any[] anys)
|
||||
case '#': this.flags.hash = true;
|
||||
default: break FLAG_EVAL;
|
||||
}
|
||||
if (++i >= format_len) return PrintFault.INVALID_FORMAT_STRING?;
|
||||
if (++i >= format_len) return PrintFault.INVALID_FORMAT_STRING!;
|
||||
c = format[i];
|
||||
}
|
||||
// evaluate width field
|
||||
int w = printf_parse_format_field(anys.ptr, anys.len, &variant_index, format.ptr, format.len, &i)!;
|
||||
int w = printf_parse_format_field(variants.ptr, variants.len, &variant_index, format.ptr, format.len, &i)?;
|
||||
c = format[i];
|
||||
if (w < 0)
|
||||
{
|
||||
@@ -338,16 +408,16 @@ fn usz! Formatter.vprintf(Formatter* this, String format, any[] anys)
|
||||
if (c == '.')
|
||||
{
|
||||
this.flags.precision = true;
|
||||
if (++i >= format_len) return PrintFault.INVALID_FORMAT_STRING?;
|
||||
int prec = printf_parse_format_field(anys.ptr, anys.len, &variant_index, format.ptr, format.len, &i)!;
|
||||
if (++i >= format_len) return PrintFault.INVALID_FORMAT_STRING!;
|
||||
int prec = printf_parse_format_field(variants.ptr, variants.len, &variant_index, format.ptr, format.len, &i)?;
|
||||
this.prec = prec < 0 ? 0 : prec;
|
||||
c = format[i];
|
||||
}
|
||||
|
||||
// evaluate specifier
|
||||
uint base = 0;
|
||||
if (variant_index >= anys.len) return PrintFault.MISSING_ARG?;
|
||||
any current = anys[variant_index++];
|
||||
if (variant_index >= variants.len) return PrintFault.MISSING_ARG!;
|
||||
variant current = variants[variant_index++];
|
||||
switch (c)
|
||||
{
|
||||
case 'd':
|
||||
@@ -372,38 +442,38 @@ fn usz! Formatter.vprintf(Formatter* this, String format, any[] anys)
|
||||
this.flags.uppercase = true;
|
||||
nextcase;
|
||||
case 'a':
|
||||
this.atoa(float_from_any(current)!!)!;
|
||||
this.atoa(float_from_variant(current)!!)?;
|
||||
continue;
|
||||
case 'F' :
|
||||
this.flags.uppercase = true;
|
||||
nextcase;
|
||||
case 'f':
|
||||
this.ftoa(float_from_any(current)!!)!;
|
||||
this.ftoa(float_from_variant(current)!!)?;
|
||||
continue;
|
||||
case 'E':
|
||||
this.flags.uppercase = true;
|
||||
nextcase;
|
||||
case 'e':
|
||||
this.etoa(float_from_any(current)!!)!;
|
||||
this.etoa(float_from_variant(current)!!)?;
|
||||
continue;
|
||||
case 'G':
|
||||
this.flags.uppercase = true;
|
||||
nextcase;
|
||||
case 'g':
|
||||
this.gtoa(float_from_any(current)!!)!;
|
||||
this.gtoa(float_from_variant(current)!!)?;
|
||||
continue;
|
||||
case 'c':
|
||||
this.out_char(current)!;
|
||||
this.out_char(current)?;
|
||||
continue;
|
||||
case 's':
|
||||
this.out_str(current)!;
|
||||
this.out_str(current)?;
|
||||
continue;
|
||||
case 'p':
|
||||
this.flags.zeropad = true;
|
||||
this.flags.hash = true;
|
||||
base = 16;
|
||||
default:
|
||||
return PrintFault.INVALID_FORMAT_STRING?;
|
||||
return PrintFault.INVALID_FORMAT_STRING!;
|
||||
}
|
||||
if (base != 10)
|
||||
{
|
||||
@@ -414,9 +484,9 @@ fn usz! Formatter.vprintf(Formatter* this, String format, any[] anys)
|
||||
if (this.flags.precision) this.flags.zeropad = false;
|
||||
|
||||
bool is_neg;
|
||||
uint128 v = int_from_any(current, &is_neg)!!;
|
||||
uint128 v = int_from_variant(current, &is_neg)!!;
|
||||
|
||||
this.ntoa(v, is_neg, base)!;
|
||||
this.ntoa(v, is_neg, base)?;
|
||||
}
|
||||
// termination
|
||||
// out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen);
|
||||
@@ -425,3 +495,8 @@ fn usz! Formatter.vprintf(Formatter* this, String format, any[] anys)
|
||||
return this.idx;
|
||||
}
|
||||
|
||||
typedef StringFunctionMap @private = HashMap<typeid, ToStringFunction>;
|
||||
typedef FormatterFunctionMap @private = HashMap<typeid, ToFormatFunction>;
|
||||
|
||||
FormatterFunctionMap toformat_functions @private;
|
||||
StringFunctionMap tostring_functions @private;
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
module std::io;
|
||||
|
||||
def CloseStreamFn = fn void!(Stream*);
|
||||
def FlushStreamFn = fn void!(Stream*);
|
||||
def SeekStreamFn = fn usz!(Stream*, isz offset, Seek seek);
|
||||
def LenStreamFn = fn usz(Stream*);
|
||||
def AvailableStreamFn = fn usz(Stream*);
|
||||
def ReadStreamFn = fn usz!(Stream*, char[] bytes);
|
||||
def ReadFromStreamFn = fn usz!(Stream*, Stream*);
|
||||
def ReadByteStreamFn = fn char!(Stream*);
|
||||
def PushbackByteStreamFn = fn void!(Stream*);
|
||||
def WriteStreamFn = fn usz!(Stream*, char[] bytes);
|
||||
def WriteToStreamFn = fn usz!(Stream*, Stream* out);
|
||||
def WriteByteStreamFn = fn void!(Stream*, char c);
|
||||
def DestroyStreamFn = fn void!(Stream*);
|
||||
typedef CloseStreamFn = fn void!(Stream*);
|
||||
typedef FlushStreamFn = fn void!(Stream*);
|
||||
typedef SeekStreamFn = fn usz!(Stream*, isz offset, Seek seek);
|
||||
typedef LenStreamFn = fn usz(Stream*);
|
||||
typedef AvailableStreamFn = fn usz(Stream*);
|
||||
typedef ReadStreamFn = fn usz!(Stream*, char[] bytes);
|
||||
typedef ReadFromStreamFn = fn usz!(Stream*, Stream*);
|
||||
typedef ReadByteStreamFn = fn char!(Stream*);
|
||||
typedef PushbackByteStreamFn = fn void!(Stream*);
|
||||
typedef WriteStreamFn = fn usz!(Stream*, char[] bytes);
|
||||
typedef WriteToStreamFn = fn usz!(Stream*, Stream* out);
|
||||
typedef WriteByteStreamFn = fn void!(Stream*, char c);
|
||||
typedef DestroyStreamFn = fn void!(Stream*);
|
||||
|
||||
struct StreamInterface
|
||||
{
|
||||
@@ -60,7 +60,7 @@ fn void! Stream.close(Stream* s) @inline @maydiscard
|
||||
fn usz! Stream.seek(Stream* s, isz offset, Seek seek) @inline
|
||||
{
|
||||
if (SeekStreamFn func = s.fns.seek_fn) return func(s, offset, seek);
|
||||
return IoError.NOT_SEEKABLE?;
|
||||
return IoError.NOT_SEEKABLE!;
|
||||
}
|
||||
|
||||
fn usz! Stream.available(Stream* s) @inline
|
||||
@@ -68,12 +68,12 @@ fn usz! Stream.available(Stream* s) @inline
|
||||
if (AvailableStreamFn func = s.fns.available_fn) return func(s);
|
||||
if (SeekStreamFn func = s.fns.seek_fn)
|
||||
{
|
||||
usz curr = func(s, 0, Seek.CURSOR)!;
|
||||
usz len = func(s, 0, Seek.END)!;
|
||||
func(s, curr, Seek.SET)!;
|
||||
usz curr = func(s, 0, Seek.CURSOR)?;
|
||||
usz len = func(s, 0, Seek.END)?;
|
||||
func(s, curr, Seek.SET)?;
|
||||
return len - curr;
|
||||
}
|
||||
return IoError.NOT_SEEKABLE?;
|
||||
return IoError.NOT_SEEKABLE!;
|
||||
}
|
||||
|
||||
fn usz! Stream.read(Stream* s, char[] buffer)
|
||||
@@ -88,19 +88,19 @@ fn usz! Stream.read(Stream* s, char[] buffer)
|
||||
if (catch err = c)
|
||||
{
|
||||
case IoError.EOF: return len;
|
||||
default: return err?;
|
||||
default: return err!;
|
||||
}
|
||||
*cptr = c;
|
||||
len++;
|
||||
}
|
||||
}
|
||||
return IoError.UNSUPPORTED_OPERATION?;
|
||||
return IoError.UNSUPPORTED_OPERATION!;
|
||||
}
|
||||
|
||||
fn char! Stream.read_byte(Stream* s) @inline
|
||||
{
|
||||
if (ReadByteStreamFn func = s.fns.read_byte_fn) return func(s);
|
||||
return IoError.UNSUPPORTED_OPERATION?;
|
||||
return IoError.UNSUPPORTED_OPERATION!;
|
||||
}
|
||||
|
||||
fn usz! Stream.write(Stream* s, char[] bytes) @inline
|
||||
@@ -108,34 +108,34 @@ fn usz! Stream.write(Stream* s, char[] bytes) @inline
|
||||
if (WriteStreamFn func = s.fns.write_fn) return func(s, bytes);
|
||||
if (WriteByteStreamFn func = s.fns.write_byte_fn)
|
||||
{
|
||||
foreach (c : bytes) func(s, c)!;
|
||||
foreach (c : bytes) func(s, c)?;
|
||||
return bytes.len;
|
||||
}
|
||||
return IoError.UNSUPPORTED_OPERATION?;
|
||||
return IoError.UNSUPPORTED_OPERATION!;
|
||||
}
|
||||
|
||||
fn void! Stream.write_byte(Stream* s, char b) @inline
|
||||
{
|
||||
if (WriteByteStreamFn func = s.fns.write_byte_fn) return func(s, b);
|
||||
return IoError.UNSUPPORTED_OPERATION?;
|
||||
return IoError.UNSUPPORTED_OPERATION!;
|
||||
}
|
||||
|
||||
fn usz! Stream.write_to(Stream* s, Stream* to) @inline
|
||||
{
|
||||
if (WriteToStreamFn func = s.fns.write_stream_fn) return func(s, to);
|
||||
return IoError.UNSUPPORTED_OPERATION?;
|
||||
return IoError.UNSUPPORTED_OPERATION!;
|
||||
}
|
||||
|
||||
fn usz! Stream.read_from(Stream* s, Stream* from) @inline
|
||||
{
|
||||
if (ReadFromStreamFn func = s.fns.read_stream_fn) return func(s, from);
|
||||
return IoError.UNSUPPORTED_OPERATION?;
|
||||
return IoError.UNSUPPORTED_OPERATION!;
|
||||
}
|
||||
|
||||
fn void! Stream.flush(Stream* s) @inline @maydiscard
|
||||
{
|
||||
if (FlushStreamFn func = s.fns.flush_fn) return func(s);
|
||||
return IoError.UNSUPPORTED_OPERATION?;
|
||||
return IoError.UNSUPPORTED_OPERATION!;
|
||||
}
|
||||
|
||||
fn usz! Stream.len(Stream* s) @inline
|
||||
@@ -143,12 +143,12 @@ fn usz! Stream.len(Stream* s) @inline
|
||||
if (LenStreamFn func = s.fns.len_fn) return func(s);
|
||||
if (SeekStreamFn func = s.fns.seek_fn)
|
||||
{
|
||||
usz curr = func(s, 0, Seek.CURSOR)!;
|
||||
usz len = func(s, 0, Seek.END)!;
|
||||
func(s, curr, Seek.SET)!;
|
||||
usz curr = func(s, 0, Seek.CURSOR)?;
|
||||
usz len = func(s, 0, Seek.END)?;
|
||||
func(s, curr, Seek.SET)?;
|
||||
return len;
|
||||
}
|
||||
return IoError.NOT_SEEKABLE?;
|
||||
return IoError.NOT_SEEKABLE!;
|
||||
}
|
||||
|
||||
fn void! Stream.pushback_byte(Stream* s) @inline
|
||||
@@ -156,13 +156,13 @@ fn void! Stream.pushback_byte(Stream* s) @inline
|
||||
if (PushbackByteStreamFn func = s.fns.pushback_byte_fn) return func(s);
|
||||
if (SeekStreamFn func = s.fns.seek_fn)
|
||||
{
|
||||
func(s, -1, CURSOR)!;
|
||||
func(s, -1, CURSOR)?;
|
||||
return;
|
||||
}
|
||||
return IoError.UNSUPPORTED_OPERATION?;
|
||||
return IoError.UNSUPPORTED_OPERATION!;
|
||||
}
|
||||
|
||||
fn void! Stream.write_string(Stream* s, String str) @inline => (void)(s.write((char[])str)!);
|
||||
fn void! Stream.write_string(Stream* s, String str) @inline => (void)(s.write((char[])str)?);
|
||||
|
||||
fn usz! Stream.copy_to(Stream* s, Stream* dst, char[] buffer = {})
|
||||
{
|
||||
@@ -195,11 +195,11 @@ macro usz! copy_through_buffer(Stream* s, Stream* dst, char[] buffer) @local
|
||||
if (catch err = len)
|
||||
{
|
||||
case IoError.EOF: return total_copied;
|
||||
default: return err?;
|
||||
default: return err!;
|
||||
}
|
||||
if (!len) return total_copied;
|
||||
usz written = dst.write(buffer[:len])!;
|
||||
usz written = dst.write(buffer[:len])?;
|
||||
total_copied += len;
|
||||
if (written != len) return IoError.INCOMPLETE_WRITE?;
|
||||
if (written != len) return IoError.INCOMPLETE_WRITE!;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,42 +3,41 @@ import libc;
|
||||
|
||||
|
||||
$switch
|
||||
|
||||
$case env::COMPILER_LIBC_AVAILABLE && env::os_is_posix():
|
||||
|
||||
macro void! native_chdir(Path p)
|
||||
{
|
||||
if (posix::chdir(p.as_zstr()))
|
||||
{
|
||||
switch (libc::errno())
|
||||
{
|
||||
case errno::EACCES: return IoError.NO_PERMISSION?;
|
||||
case errno::ENAMETOOLONG: return IoError.NAME_TOO_LONG?;
|
||||
case errno::ENOTDIR: return IoError.FILE_NOT_DIR?;
|
||||
case errno::ENOENT: return IoError.FILE_NOT_FOUND?;
|
||||
case errno::ELOOP: return IoError.SYMLINK_FAILED?;
|
||||
default: return IoError.GENERAL_ERROR?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$case env::COMPILER_LIBC_AVAILABLE && env::os_is_win32():
|
||||
|
||||
macro void! native_chdir(Path path)
|
||||
{
|
||||
@pool()
|
||||
{
|
||||
// TODO improve with better error handling.
|
||||
if (win32::win32_SetCurrentDirectoryW(path.as_str().to_temp_utf16()!!)) return;
|
||||
};
|
||||
return IoError.GENERAL_ERROR?;
|
||||
}
|
||||
|
||||
$default:
|
||||
$case !env::COMPILER_LIBC_AVAILABLE:
|
||||
|
||||
fn void! native_chdir(Path path)
|
||||
{
|
||||
unreachable("'getcwd' not available");
|
||||
}
|
||||
|
||||
$case env::os_is_win32():
|
||||
|
||||
macro void! native_chdir(Path path)
|
||||
{
|
||||
@pool()
|
||||
{
|
||||
if (files::win32_SetCurrentDirectoryW(path.as_str().to_temp_utf16()!!)) return;
|
||||
};
|
||||
return IoError.GENERAL_ERROR!;
|
||||
}
|
||||
|
||||
$default:
|
||||
|
||||
extern fn int _chdir(ZString) @extern("chdir");
|
||||
macro void! native_chdir(Path p)
|
||||
{
|
||||
if (_chdir((ZString)p.as_str()))
|
||||
{
|
||||
switch (libc::errno())
|
||||
{
|
||||
case errno::EACCES: return IoError.NO_PERMISSION!;
|
||||
case errno::ENAMETOOLONG: return IoError.NAME_TOO_LONG!;
|
||||
case errno::ENOTDIR: return IoError.FILE_NOT_DIR!;
|
||||
case errno::ENOENT: return IoError.FILE_NOT_FOUND!;
|
||||
case errno::ELOOP: return IoError.SYMLINK_FAILED!;
|
||||
default: return IoError.GENERAL_ERROR!;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$endswitch
|
||||
@@ -1,33 +1,33 @@
|
||||
module std::io::os;
|
||||
import libc;
|
||||
|
||||
def FopenFn = fn void*!(String, String);
|
||||
def FreopenFn = fn void*!(void*, String, String);
|
||||
def FcloseFn = fn void!(void*);
|
||||
def FseekFn = fn void!(void*, isz, Seek);
|
||||
def FtellFn = fn usz!(void*);
|
||||
def FwriteFn = fn usz!(void*, char[] buffer);
|
||||
def FreadFn = fn usz!(void*, char[] buffer);
|
||||
typedef FopenFn = fn void*!(String, String);
|
||||
typedef FreopenFn = fn void*!(void*, String, String);
|
||||
typedef FcloseFn = fn void!(void*);
|
||||
typedef FseekFn = fn void!(void*, isz, Seek);
|
||||
typedef FtellFn = fn usz!(void*);
|
||||
typedef FwriteFn = fn usz!(void*, char[] buffer);
|
||||
typedef FreadFn = fn usz!(void*, char[] buffer);
|
||||
|
||||
$if !$defined(native_fopen_fn):
|
||||
$if (!$defined(native_fopen_fn))
|
||||
FopenFn native_fopen_fn @weak;
|
||||
$endif
|
||||
$if !$defined(native_fclose_fn):
|
||||
$if (!$defined(native_fclose_fn))
|
||||
FcloseFn native_fclose_fn @weak;
|
||||
$endif
|
||||
$if !$defined(native_freopen_fn):
|
||||
$if (!$defined(native_freopen_fn))
|
||||
FreopenFn native_freopen_fn @weak;
|
||||
$endif
|
||||
$if !$defined(native_fseek_fn):
|
||||
$if (!$defined(native_fseek_fn))
|
||||
FseekFn native_fseek_fn @weak;
|
||||
$endif
|
||||
$if !$defined(native_ftell_fn):
|
||||
$if (!$defined(native_ftell_fn))
|
||||
FtellFn native_ftell_fn @weak;
|
||||
$endif
|
||||
$if !$defined(native_fwrite_fn):
|
||||
$if (!$defined(native_fwrite_fn))
|
||||
FwriteFn native_fwrite_fn @weak;
|
||||
$endif
|
||||
$if !$defined(native_fread_fn):
|
||||
$if (!$defined(native_fread_fn))
|
||||
FreadFn native_fread_fn @weak;
|
||||
$endif
|
||||
|
||||
@@ -38,18 +38,18 @@ $endif
|
||||
**/
|
||||
fn void*! native_fopen(String filename, String mode) @inline
|
||||
{
|
||||
$if !env::COMPILER_LIBC_AVAILABLE:
|
||||
$if (!env::COMPILER_LIBC_AVAILABLE)
|
||||
if (native_fopen_fn) return native_fopen_fn(filename, mode);
|
||||
unreachable("Tried to call fopen without support.");
|
||||
$else
|
||||
@pool()
|
||||
{
|
||||
$if env::os_is_win32():
|
||||
void* file = (CFile)_wfopen(filename.to_temp_utf16(), filename.to_temp_utf16())!;
|
||||
$if (env::os_is_win32())
|
||||
void* file = (CFile)_wfopen(filename.to_temp_utf16(), filename.to_temp_utf16())?;
|
||||
$else
|
||||
void* file = libc::fopen(filename.zstr_tcopy(), mode.zstr_tcopy());
|
||||
$endif
|
||||
return file ?: file_open_errno()?;
|
||||
return file ?: file_open_errno()!;
|
||||
};
|
||||
$endif
|
||||
}
|
||||
@@ -60,56 +60,56 @@ $endif
|
||||
**/
|
||||
fn void*! native_freopen(void* file, String filename, String mode) @inline
|
||||
{
|
||||
$if !env::COMPILER_LIBC_AVAILABLE:
|
||||
$if (!env::COMPILER_LIBC_AVAILABLE)
|
||||
if (native_freopen_fn) return native_freopen_fn(file, filename, mode);
|
||||
unreachable("Tried to call freopen without support.");
|
||||
$else
|
||||
@pool()
|
||||
{
|
||||
$if env::os_is_win32():
|
||||
file = _wfreopen(filename.to_temp_utf16(), mode.to_temp_utf16(), file)!;
|
||||
$if (env::os_is_win32())
|
||||
file = _wfreopen(filename.to_temp_utf16(), mode.to_temp_utf16(), file)?;
|
||||
$else
|
||||
file = libc::freopen(filename.zstr_tcopy(), mode.zstr_tcopy(), file);
|
||||
$endif
|
||||
return file ?: file_open_errno()?;
|
||||
return file ?: file_open_errno()!;
|
||||
};
|
||||
$endif
|
||||
}
|
||||
|
||||
fn void! native_fseek(void* file, isz offset, Seek seek_mode) @inline
|
||||
{
|
||||
$if !env::COMPILER_LIBC_AVAILABLE:
|
||||
$if (!env::COMPILER_LIBC_AVAILABLE)
|
||||
if (native_fseek_fn) return native_fseek_fn(file, offset, seek_mode);
|
||||
unreachable("Tried to call fseek without support.");
|
||||
$else
|
||||
$if env::os_is_win32():
|
||||
$if (env::os_is_win32())
|
||||
bool success = _fseeki64(file, (long)offset, (int)seek_mode) == 0;
|
||||
$else
|
||||
bool success = libc::fseek(file, (SeekIndex)offset, (CInt)seek_mode) == 0;
|
||||
$endif
|
||||
if (!success) return file_seek_errno()?;
|
||||
if (!success) return file_seek_errno()!;
|
||||
$endif
|
||||
}
|
||||
|
||||
fn usz! native_ftell(CFile file) @inline
|
||||
{
|
||||
$if !env::COMPILER_LIBC_AVAILABLE:
|
||||
$if (!env::COMPILER_LIBC_AVAILABLE)
|
||||
if (native_ftell_fn) return native_ftell_fn(file);
|
||||
unreachable("Tried to call ftell without support.");
|
||||
$else
|
||||
$if env::os_is_win32():
|
||||
$if (env::os_is_win32())
|
||||
long index = _ftelli64(file);
|
||||
return index >= 0 ? index : file_seek_errno()?;
|
||||
return index >= 0 ? index : file_seek_errno()!;
|
||||
$else
|
||||
SeekIndex index = libc::ftell(file);
|
||||
return index >= 0 ? index : file_seek_errno()?;
|
||||
return index >= 0 ? index : file_seek_errno()!;
|
||||
$endif
|
||||
$endif
|
||||
}
|
||||
|
||||
fn usz! native_fwrite(CFile file, char[] buffer) @inline
|
||||
{
|
||||
$if !env::COMPILER_LIBC_AVAILABLE:
|
||||
$if (!env::COMPILER_LIBC_AVAILABLE)
|
||||
if (native_fwrite_fn) return native_fwrite_fn(file, buffer);
|
||||
unreachable("Tried to call fwrite without support.");
|
||||
$else
|
||||
@@ -119,7 +119,7 @@ $endif
|
||||
|
||||
fn usz! native_fread(CFile file, char[] buffer) @inline
|
||||
{
|
||||
$if !env::COMPILER_LIBC_AVAILABLE:
|
||||
$if (!env::COMPILER_LIBC_AVAILABLE)
|
||||
if (native_fread_fn) return native_fread_fn(file, buffer);
|
||||
unreachable("Tried to call fread without support.");
|
||||
$else
|
||||
@@ -127,7 +127,7 @@ $else
|
||||
$endif
|
||||
}
|
||||
|
||||
macro anyfault file_open_errno() @local
|
||||
macro anyerr file_open_errno() @local
|
||||
{
|
||||
switch (libc::errno())
|
||||
{
|
||||
@@ -155,7 +155,7 @@ macro anyfault file_open_errno() @local
|
||||
}
|
||||
}
|
||||
|
||||
macro anyfault file_seek_errno() @local
|
||||
macro anyerr file_seek_errno() @local
|
||||
{
|
||||
switch (libc::errno())
|
||||
{
|
||||
@@ -175,13 +175,13 @@ macro anyfault file_seek_errno() @local
|
||||
}
|
||||
|
||||
// Win functions
|
||||
$if env::os_is_win32():
|
||||
$if (env::os_is_win32())
|
||||
extern fn void* _wfopen(Char16*, Char16*) @local;
|
||||
extern fn void* _wfreopen(Char16*, Char16*, CFile) @local;
|
||||
extern fn int _fseeki64(CFile, long, int) @local;
|
||||
extern fn long _ftelli64(CFile) @local;
|
||||
$endif
|
||||
|
||||
$if env::os_is_posix():
|
||||
$if (env::os_is_posix())
|
||||
extern fn CInt access(ZString path, CInt mode);
|
||||
$endif
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
module std::io::file::os;
|
||||
import libc;
|
||||
|
||||
$if env::os_is_darwin():
|
||||
$if (env::os_is_darwin())
|
||||
|
||||
|
||||
struct DarwinTimespec @private
|
||||
{
|
||||
@@ -43,26 +44,26 @@ const S_IFSOCK = 0o140000; // socket
|
||||
fn usz! native_file_size(String path)
|
||||
{
|
||||
Darwin64Stat stat;
|
||||
read_stat(&stat, path)!;
|
||||
read_stat(&stat, path)?;
|
||||
return stat.st_size;
|
||||
}
|
||||
|
||||
fn bool native_file_or_dir_exists(String path)
|
||||
{
|
||||
Darwin64Stat stat;
|
||||
return @ok(read_stat(&stat, path));
|
||||
return try? read_stat(&stat, path);
|
||||
}
|
||||
|
||||
fn bool native_is_file(String path)
|
||||
{
|
||||
Darwin64Stat stat;
|
||||
return @ok(read_stat(&stat, path)) && stat.st_mode & S_IFREG;
|
||||
return try? read_stat(&stat, path) && (stat.st_mode & S_IFREG);
|
||||
}
|
||||
|
||||
fn bool native_is_dir(String path)
|
||||
{
|
||||
Darwin64Stat stat;
|
||||
return @ok(read_stat(&stat, path)) && stat.st_mode & S_IFDIR;
|
||||
return try? read_stat(&stat, path) && (stat.st_mode & S_IFDIR);
|
||||
}
|
||||
|
||||
fn void! read_stat(Darwin64Stat* stat, String path) @local
|
||||
@@ -75,25 +76,25 @@ fn void! read_stat(Darwin64Stat* stat, String path) @local
|
||||
switch (libc::errno())
|
||||
{
|
||||
case errno::EBADF:
|
||||
return IoError.FILE_NOT_VALID?;
|
||||
return IoError.FILE_NOT_VALID!;
|
||||
case errno::EFAULT:
|
||||
unreachable("Invalid stat");
|
||||
case errno::EIO:
|
||||
return IoError.GENERAL_ERROR?;
|
||||
return IoError.GENERAL_ERROR!;
|
||||
case errno::EACCES:
|
||||
return IoError.NO_PERMISSION?;
|
||||
return IoError.NO_PERMISSION!;
|
||||
case errno::ELOOP:
|
||||
return IoError.NO_PERMISSION?;
|
||||
return IoError.NO_PERMISSION!;
|
||||
case errno::ENAMETOOLONG:
|
||||
return IoError.NAME_TOO_LONG?;
|
||||
return IoError.NAME_TOO_LONG!;
|
||||
case errno::ENOENT:
|
||||
return IoError.FILE_NOT_FOUND?;
|
||||
return IoError.FILE_NOT_FOUND!;
|
||||
case errno::ENOTDIR:
|
||||
return IoError.FILE_NOT_DIR?;
|
||||
return IoError.FILE_NOT_DIR!;
|
||||
case errno::EOVERFLOW:
|
||||
return IoError.GENERAL_ERROR?;
|
||||
return IoError.GENERAL_ERROR!;
|
||||
default:
|
||||
return IoError.UNKNOWN_ERROR?;
|
||||
return IoError.UNKNOWN_ERROR!;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
module std::io::file::os;
|
||||
|
||||
// native_temp_directory, for non Win32
|
||||
$if !env::os_is_win32():
|
||||
$if (!env::os_is_win32())
|
||||
|
||||
fn Path! native_temp_directory(Allocator* using = mem::heap())
|
||||
{
|
||||
@@ -13,11 +13,10 @@ fn Path! native_temp_directory(Allocator* using = mem::heap())
|
||||
return path::new("/tmp", using);
|
||||
}
|
||||
|
||||
$if env::COMPILER_LIBC_AVAILABLE:
|
||||
$if (env::COMPILER_LIBC_AVAILABLE)
|
||||
|
||||
extern fn void* opendir(ZString);
|
||||
extern fn void closedir(void*);
|
||||
extern fn int remove(ZString);
|
||||
|
||||
const DT_UNKNOWN = 0;
|
||||
const DT_FIFO = 1;
|
||||
@@ -35,7 +34,7 @@ fn PathList! native_readdir(Path dir, bool no_dirs, bool no_symlinks, String mas
|
||||
list.init(.using = using);
|
||||
void* directory = opendir(dir.as_str() ? dir.as_zstr() : (ZString)".");
|
||||
defer if (directory) closedir(directory);
|
||||
if (!directory) return (path::is_dir(dir) ? IoError.CANNOT_READ_DIR : IoError.FILE_NOT_DIR)?;
|
||||
if (!directory) return (path::is_dir(dir) ? IoError.CANNOT_READ_DIR : IoError.FILE_NOT_DIR)!;
|
||||
NativeDirentry* entry;
|
||||
while ((entry = readdir(directory)))
|
||||
{
|
||||
@@ -49,51 +48,20 @@ fn PathList! native_readdir(Path dir, bool no_dirs, bool no_symlinks, String mas
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require dir.as_str()
|
||||
**/
|
||||
fn void! native_rmtree(Path dir)
|
||||
{
|
||||
void* directory = opendir(dir.as_zstr());
|
||||
defer if (directory) closedir(directory);
|
||||
if (!directory) return path::is_dir(dir) ? IoError.CANNOT_READ_DIR? : IoError.FILE_NOT_DIR?;
|
||||
NativeDirentry* entry;
|
||||
while ((entry = readdir(directory)))
|
||||
{
|
||||
@pool()
|
||||
{
|
||||
String name = ((ZString)&entry.name).as_str();
|
||||
if (!name || name == "." || name == "..") continue;
|
||||
Path new_path = dir.tappend(name)!;
|
||||
if (entry.type == DT_DIR)
|
||||
{
|
||||
native_rmtree(new_path)!;
|
||||
continue;
|
||||
}
|
||||
if (remove(new_path.as_zstr()))
|
||||
{
|
||||
// TODO improve
|
||||
return IoError.GENERAL_ERROR?;
|
||||
}
|
||||
};
|
||||
}
|
||||
os::native_rmdir(dir)!;
|
||||
}
|
||||
|
||||
$endif
|
||||
|
||||
$endif
|
||||
|
||||
$if !env::os_is_darwin() && !env::os_is_win32():
|
||||
$if (!env::os_is_darwin() && !env::os_is_win32())
|
||||
|
||||
fn usz! native_file_size(String path)
|
||||
{
|
||||
File f = file::open(path, "r")!;
|
||||
File f = file::open(path, "r")?;
|
||||
defer (void)f.close();
|
||||
return f.seek(0, Seek.END)!;
|
||||
return f.seek(0, Seek.END)?;
|
||||
}
|
||||
|
||||
$if env::os_is_posix() && env::COMPILER_LIBC_AVAILABLE:
|
||||
$if (env::os_is_posix() && env::COMPILER_LIBC_AVAILABLE)
|
||||
|
||||
fn bool native_file_or_dir_exists(String path)
|
||||
{
|
||||
@@ -107,7 +75,7 @@ fn bool native_is_file(String path)
|
||||
{
|
||||
File! f = file::open(path, "r");
|
||||
defer (void)f.close();
|
||||
return @ok(f);
|
||||
return try? f;
|
||||
}
|
||||
|
||||
fn bool native_is_dir(String path)
|
||||
@@ -138,16 +106,10 @@ $endif
|
||||
|
||||
$switch (env::OS_TYPE)
|
||||
$case IOS:
|
||||
$case MACOS:
|
||||
$case MACOSX:
|
||||
$case TVOS:
|
||||
$case WATCHOS:
|
||||
|
||||
$if env::ARCH_TYPE == X86_64:
|
||||
extern fn NativeDirentry* readdir(void*) @extern("readdir$INODE64");
|
||||
$else
|
||||
extern fn NativeDirentry* readdir(void*) @extern("readdir");
|
||||
$endif
|
||||
|
||||
struct NativeDirentry
|
||||
{
|
||||
usz ino;
|
||||
|
||||
@@ -1,38 +1,15 @@
|
||||
module std::io::file::os;
|
||||
import std::os::win32;
|
||||
import std::os::win32::files;
|
||||
|
||||
$if env::os_is_win32():
|
||||
|
||||
const Win32_DWORD FILE_ATTRIBUTE_READONLY = 0x01;
|
||||
const Win32_DWORD FILE_ATTRIBUTE_HIDDEN = 0x02;
|
||||
const Win32_DWORD FILE_ATTRIBUTE_SYSTEM = 0x04;
|
||||
const Win32_DWORD FILE_ATTRIBUTE_DIRECTORY = 0x10;
|
||||
const Win32_DWORD FILE_ATTRIBUTE_ARCHIVE = 0x20;
|
||||
const Win32_DWORD FILE_ATTRIBUTE_DEVICE = 0x40;
|
||||
const Win32_DWORD FILE_ATTRIBUTE_NORMAL = 0x80;
|
||||
const Win32_DWORD FILE_ATTRIBUTE_TEMPORARY = 0x100;
|
||||
const Win32_DWORD FILE_ATTRIBUTE_SPARSE_FILE = 0x200;
|
||||
const Win32_DWORD FILE_ATTRIBUTE_REPARSE_POINT = 0x400;
|
||||
const Win32_DWORD FILE_ATTRIBUTE_COMPRESSED = 0x800;
|
||||
const Win32_DWORD FILE_ATTRIBUTE_OFFLINE = 0x1000;
|
||||
const Win32_DWORD FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000;
|
||||
const Win32_DWORD FILE_ATTRIBUTE_ENCRYPTED = 0x4000;
|
||||
const Win32_DWORD FILE_ATTRIBUTE_INTEGRITY_STREAM = 0x8000;
|
||||
const Win32_DWORD FILE_ATTRIBUTE_VIRTUAL = 0x10000;
|
||||
const Win32_DWORD FILE_ATTRIBUTE_NO_SCRUB_DATA = 0x20000;
|
||||
const Win32_DWORD FILE_ATTRIBUTE_EA = 0x40000;
|
||||
const Win32_DWORD FILE_ATTRIBUTE_PINNED = 0x80000;
|
||||
const Win32_DWORD FILE_ATTRIBUTE_UNPINNED = 0x100000;
|
||||
const Win32_DWORD FILE_ATTRIBUTE_RECALL_ON_OPEN = 0x40000;
|
||||
const Win32_DWORD FILE_ATTRIBUTE_RECALL_ON_DATA_ACCESS = 0x400000;
|
||||
$if (env::os_is_win32())
|
||||
|
||||
fn usz! native_file_size(String path)
|
||||
{
|
||||
@pool()
|
||||
{
|
||||
Char16[] path16 = path.to_temp_utf16()!;
|
||||
Char16[] path16 = path.to_temp_utf16()?;
|
||||
Win32_FILE_ATTRIBUTE_DATA data;
|
||||
win32::win32_GetFileAttributesExW(path16, Win32_GET_FILEEX_INFO_LEVELS.STANDARD, &data);
|
||||
files::win32_GetFileAttributesExW(path16, Win32_GET_FILEEX_INFO_LEVELS.STANDARD, &data);
|
||||
Win32_LARGE_INTEGER size;
|
||||
size.lowPart = data.nFileSizeLow;
|
||||
size.highPart = data.nFileSizeHigh;
|
||||
@@ -44,7 +21,7 @@ fn bool native_file_or_dir_exists(String path)
|
||||
{
|
||||
@pool()
|
||||
{
|
||||
return (bool)win32::win32_PathFileExistsW(path.to_temp_utf16()) ?? false;
|
||||
return (bool)files::win32_PathFileExistsW(path.to_temp_utf16()) ?? false;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -53,7 +30,7 @@ fn bool native_is_file(String path)
|
||||
{
|
||||
File! f = file::open(path, "r");
|
||||
defer (void)f.close();
|
||||
return @ok(f);
|
||||
return try? f;
|
||||
}
|
||||
|
||||
fn bool native_is_dir(String path)
|
||||
@@ -61,41 +38,14 @@ fn bool native_is_dir(String path)
|
||||
return native_file_or_dir_exists(path) && !native_is_file(path);
|
||||
}
|
||||
|
||||
fn void! native_rmtree(Path path)
|
||||
{
|
||||
Win32_WIN32_FIND_DATAW find_data;
|
||||
|
||||
String s = path.as_str().tconcat("\\*");
|
||||
Win32_HANDLE find = win32::win32_FindFirstFileW(s.to_utf16(mem::temp()), &find_data)!;
|
||||
|
||||
if (find == win32::INVALID_HANDLE_VALUE) return IoError.CANNOT_READ_DIR?;
|
||||
|
||||
defer win32::win32_FindClose(find);
|
||||
do
|
||||
{
|
||||
String filename = string::from_zutf16(&find_data.cFileName, mem::temp())!;
|
||||
if (filename == "." || filename == "..") continue;
|
||||
Path file_path = path.tappend(filename)!;
|
||||
if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
||||
{
|
||||
native_rmtree(file_path)!;
|
||||
}
|
||||
else
|
||||
{
|
||||
win32::win32_DeleteFileW(file_path.as_str().to_utf16(mem::temp()));
|
||||
}
|
||||
} while (win32::win32_FindNextFileW(find, &find_data) != 0);
|
||||
os::native_rmdir(path)!;
|
||||
}
|
||||
|
||||
fn Path! native_temp_directory(Allocator* using = mem::heap())
|
||||
{
|
||||
@stack_mem(256; Allocator* mem)
|
||||
{
|
||||
Win32_DWORD len = win32::win32_GetTempPathW(0, null);
|
||||
if (!len) return IoError.GENERAL_ERROR?;
|
||||
Win32_DWORD len = files::win32_GetTempPathW(0, null);
|
||||
if (!len) return IoError.GENERAL_ERROR!;
|
||||
Char16[] buff = malloc(Char16, len + 1, .using = mem);
|
||||
if (!win32::win32_GetTempPathW(len, buff)) return IoError.GENERAL_ERROR?;
|
||||
if (!files::win32_GetTempPathW(len, buff)) return IoError.GENERAL_ERROR!;
|
||||
return path::new(string::from_utf16(buff[:len], .using = mem), using);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2,50 +2,53 @@ module std::io::os;
|
||||
import libc;
|
||||
|
||||
$switch
|
||||
|
||||
$case env::COMPILER_LIBC_AVAILABLE && env::os_is_win32():
|
||||
|
||||
macro String! getcwd(Allocator* using = mem::heap())
|
||||
{
|
||||
const DEFAULT_BUFFER = 256;
|
||||
Char16[DEFAULT_BUFFER] buffer;
|
||||
Char16 *res = win32::_wgetcwd(&buffer, DEFAULT_BUFFER);
|
||||
bool free = false;
|
||||
defer if (free) libc::free(res);
|
||||
if (!res)
|
||||
{
|
||||
if (libc::errno() != errno::ERANGE) return IoError.GENERAL_ERROR?;
|
||||
res = win32::_wgetcwd(null, 0);
|
||||
free = true;
|
||||
}
|
||||
Char16[] str16 = res[:win32::wcslen(res)];
|
||||
return string::from_utf16(str16, using);
|
||||
}
|
||||
|
||||
$case env::COMPILER_LIBC_AVAILABLE && env::os_is_posix():
|
||||
|
||||
macro String! getcwd(Allocator* using = mem::heap())
|
||||
{
|
||||
const usz DEFAULT_BUFFER = 256;
|
||||
char[DEFAULT_BUFFER] buffer;
|
||||
ZString res = posix::getcwd(&buffer, DEFAULT_BUFFER);
|
||||
bool free = false;
|
||||
if (!res)
|
||||
{
|
||||
// Improve error
|
||||
if (libc::errno() != errno::ERANGE) return IoError.GENERAL_ERROR?;
|
||||
res = posix::getcwd(null, 0);
|
||||
free = true;
|
||||
}
|
||||
defer if (free) libc::free((void*)res);
|
||||
return res.copy(using);
|
||||
}
|
||||
|
||||
$default:
|
||||
$case !env::COMPILER_LIBC_AVAILABLE:
|
||||
|
||||
fn String! getcwd(Allocator* using = mem::heap())
|
||||
{
|
||||
unreachable("'getcwd' not available");
|
||||
}
|
||||
|
||||
$case env::os_is_win32():
|
||||
|
||||
extern fn Char16* _wgetcwd(Char16* buffer, int maxlen);
|
||||
extern fn usz wcslen(Char16* str);
|
||||
|
||||
macro String! getcwd(Allocator* using = mem::heap())
|
||||
{
|
||||
const DEFAULT_BUFFER = 256;
|
||||
Char16[DEFAULT_BUFFER] buffer;
|
||||
Char16 *res = _wgetcwd(&buffer, DEFAULT_BUFFER);
|
||||
bool free = false;
|
||||
defer if (free) libc::free(res);
|
||||
if (!res)
|
||||
{
|
||||
if (libc::errno() != errno::ERANGE) return IoError.GENERAL_ERROR!;
|
||||
res = _wgetcwd(null, 0);
|
||||
free = true;
|
||||
}
|
||||
Char16[] str16 = res[:wcslen(res)];
|
||||
return str::utf16to8(str16, using);
|
||||
}
|
||||
|
||||
$default:
|
||||
|
||||
extern fn ZString _getcwd(char* pwd, usz len) @extern("getcwd");
|
||||
macro String! getcwd(Allocator* using = mem::heap())
|
||||
{
|
||||
const usz DEFAULT_BUFFER = 256;
|
||||
char[DEFAULT_BUFFER] buffer;
|
||||
ZString res = _getcwd(&buffer, DEFAULT_BUFFER);
|
||||
bool free = false;
|
||||
if (!res)
|
||||
{
|
||||
// Improve error
|
||||
if (libc::errno() != errno::ERANGE) return IoError.GENERAL_ERROR!;
|
||||
res = _getcwd(null, 0);
|
||||
free = true;
|
||||
}
|
||||
defer if (free) libc::free((void*)res);
|
||||
return res.copy(using);
|
||||
}
|
||||
|
||||
$endswitch
|
||||
@@ -1,63 +0,0 @@
|
||||
module std::io::os;
|
||||
import libc;
|
||||
import std::io::path;
|
||||
import std::os::win32;
|
||||
import std::os::posix;
|
||||
|
||||
$switch
|
||||
$case env::COMPILER_LIBC_AVAILABLE && env::os_is_posix():
|
||||
|
||||
macro bool! native_mkdir(Path path, MkdirPermissions permissions)
|
||||
{
|
||||
if (!posix::mkdir(path.as_zstr(), permissions == NORMAL ? 0o777 : 0o700)) return true;
|
||||
switch (libc::errno())
|
||||
{
|
||||
case errno::EACCES:
|
||||
case errno::EPERM:
|
||||
case errno::EROFS:
|
||||
case errno::EFAULT: return IoError.NO_PERMISSION?;
|
||||
case errno::ENAMETOOLONG: return IoError.NAME_TOO_LONG?;
|
||||
case errno::EDQUOT:
|
||||
case errno::ENOSPC: return IoError.OUT_OF_SPACE?;
|
||||
case errno::EISDIR:
|
||||
case errno::EEXIST: return false;
|
||||
case errno::ELOOP: return IoError.SYMLINK_FAILED?;
|
||||
case errno::ENOTDIR: return IoError.FILE_NOT_FOUND?;
|
||||
default: return IoError.GENERAL_ERROR?;
|
||||
}
|
||||
}
|
||||
|
||||
$case env::COMPILER_LIBC_AVAILABLE && env::os_is_win32():
|
||||
|
||||
macro bool! native_mkdir(Path path, MkdirPermissions permissions)
|
||||
{
|
||||
@pool()
|
||||
{
|
||||
// TODO security attributes
|
||||
if (win32::win32_CreateDirectoryW(path.as_str().to_temp_utf16()!!, null)) return true;
|
||||
switch (win32::win32_GetLastError())
|
||||
{
|
||||
case win32::ERROR_ACCESS_DENIED:
|
||||
return IoError.NO_PERMISSION?;
|
||||
case win32::ERROR_DISK_FULL:
|
||||
return IoError.OUT_OF_SPACE?;
|
||||
case win32::ERROR_ALREADY_EXISTS:
|
||||
return false;
|
||||
case win32::ERROR_PATH_NOT_FOUND:
|
||||
return IoError.FILE_NOT_FOUND?;
|
||||
default:
|
||||
return IoError.GENERAL_ERROR?;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
$default:
|
||||
|
||||
fn bool! native_mkdir(Path path, MkdirPermissions permissions)
|
||||
{
|
||||
unreachable("'mkdir' not available");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
$endswitch
|
||||
@@ -1,61 +0,0 @@
|
||||
module std::io::os;
|
||||
import libc;
|
||||
import std::io::path;
|
||||
import std::os::win32;
|
||||
import std::os::posix;
|
||||
|
||||
$switch
|
||||
|
||||
$case env::COMPILER_LIBC_AVAILABLE && env::os_is_posix():
|
||||
|
||||
macro bool! native_rmdir(Path path)
|
||||
{
|
||||
if (!posix::rmdir(path.as_zstr())) return true;
|
||||
switch (libc::errno())
|
||||
{
|
||||
case errno::EBUSY: return IoError.BUSY?;
|
||||
case errno::EACCES:
|
||||
case errno::EPERM:
|
||||
case errno::EROFS:
|
||||
case errno::EFAULT: return IoError.NO_PERMISSION?;
|
||||
case errno::ENAMETOOLONG: return IoError.NAME_TOO_LONG?;
|
||||
case errno::ENOTDIR:
|
||||
case errno::ENOENT: return false;
|
||||
case errno::ENOTEMPTY: return IoError.DIR_NOT_EMPTY?;
|
||||
case errno::ELOOP: return IoError.SYMLINK_FAILED?;
|
||||
default: return IoError.GENERAL_ERROR?;
|
||||
}
|
||||
}
|
||||
|
||||
$case env::COMPILER_LIBC_AVAILABLE && env::os_is_win32():
|
||||
|
||||
macro bool! native_rmdir(Path path)
|
||||
{
|
||||
@pool()
|
||||
{
|
||||
if (win32::win32_RemoveDirectoryW(path.as_str().to_temp_utf16()!!)) return true;
|
||||
switch (win32::win32_GetLastError())
|
||||
{
|
||||
case win32::ERROR_ACCESS_DENIED:
|
||||
return IoError.NO_PERMISSION?;
|
||||
case win32::ERROR_CURRENT_DIRECTORY:
|
||||
return IoError.BUSY?;
|
||||
case win32::ERROR_DIR_NOT_EMPTY:
|
||||
return IoError.DIR_NOT_EMPTY?;
|
||||
case win32::ERROR_DIRECTORY:
|
||||
case win32::ERROR_PATH_NOT_FOUND:
|
||||
return false;
|
||||
default:
|
||||
return IoError.GENERAL_ERROR?;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
$default:
|
||||
|
||||
fn bool! native_rmdir(Path path)
|
||||
{
|
||||
unreachable("'rmdir' not available");
|
||||
}
|
||||
|
||||
$endswitch
|
||||
@@ -6,7 +6,7 @@ const char PREFERRED_SEPARATOR_WIN32 = '\\';
|
||||
const char PREFERRED_SEPARATOR_POSIX = '/';
|
||||
const char PREFERRED_SEPARATOR = env::os_is_win32() ? PREFERRED_SEPARATOR_WIN32 : PREFERRED_SEPARATOR_POSIX;
|
||||
|
||||
def PathList = List<Path>;
|
||||
typedef PathList = List<Path>;
|
||||
|
||||
fault PathResult
|
||||
{
|
||||
@@ -58,51 +58,6 @@ macro bool is_win32_separator(char c)
|
||||
return c == '/' || c == '\\';
|
||||
}
|
||||
|
||||
fn Path[]! ls(Path path)
|
||||
{
|
||||
unreachable();
|
||||
}
|
||||
|
||||
enum MkdirPermissions
|
||||
{
|
||||
NORMAL,
|
||||
USER_ONLY,
|
||||
USER_AND_ADMIN
|
||||
}
|
||||
|
||||
|
||||
|
||||
fn bool! mkdir(Path path, bool recursive = false, MkdirPermissions permissions = NORMAL)
|
||||
{
|
||||
if (!path.path_string.len) return PathResult.INVALID_PATH?;
|
||||
if (is_dir(path)) return false;
|
||||
if (exists(path)) return IoError.FILE_NOT_DIR?;
|
||||
|
||||
if (recursive)
|
||||
{
|
||||
if (try parent = path.parent()) mkdir(parent, true, permissions)!;
|
||||
}
|
||||
if (!is_dir(path.parent()) ?? false) return IoError.CANNOT_READ_DIR?;
|
||||
|
||||
return os::native_mkdir(path, permissions);
|
||||
}
|
||||
|
||||
fn bool! rmdir(Path path)
|
||||
{
|
||||
if (!path.path_string.len) return PathResult.INVALID_PATH?;
|
||||
return os::native_rmdir(path);
|
||||
}
|
||||
|
||||
fn void! rmtree(Path path)
|
||||
{
|
||||
if (!path.path_string.len) return PathResult.INVALID_PATH?;
|
||||
$if $defined(os::native_rmtree):
|
||||
return os::native_rmtree(path);
|
||||
$else
|
||||
assert(false, "rmtree is not available");
|
||||
$endif
|
||||
}
|
||||
|
||||
fn Path! new(String path, Allocator* using = mem::heap(), PathEnv path_env = DEFAULT_PATH_ENV)
|
||||
{
|
||||
return { normalize(path.copy(using), path_env), path_env };
|
||||
@@ -132,7 +87,7 @@ fn bool Path.equals(Path p1, Path p2)
|
||||
**/
|
||||
fn Path! Path.append(Path path, String filename, Allocator* using = mem::heap())
|
||||
{
|
||||
if (!path.path_string.len) return new(filename, using, path.env)!;
|
||||
if (!path.path_string.len) return new(filename, using, path.env)?;
|
||||
assert(!is_separator(path.path_string[^1], path.env));
|
||||
|
||||
@stack_mem(256; Allocator* mem)
|
||||
@@ -179,9 +134,9 @@ fn String Path.dirname(Path path)
|
||||
fn String! Path.extension(Path path)
|
||||
{
|
||||
String basename = path.basename();
|
||||
usz index = basename.rindex_of(".")!;
|
||||
usz index = basename.rindex_of(".")?;
|
||||
// Plain ".foo" does not have an
|
||||
if (index == 0) return SearchResult.MISSING?;
|
||||
if (index == 0) return SearchResult.MISSING!;
|
||||
if (index == basename.len) return "";
|
||||
return basename[index + 1..];
|
||||
}
|
||||
@@ -211,9 +166,9 @@ fn usz! volume_name_len(String path, PathEnv path_env) @local
|
||||
{
|
||||
char c = path[i];
|
||||
if (is_win32_separator(c)) return i;
|
||||
if (is_reserved_win32_path_char(c)) return PathResult.INVALID_PATH?;
|
||||
if (is_reserved_win32_path_char(c)) return PathResult.INVALID_PATH!;
|
||||
}
|
||||
return PathResult.INVALID_PATH?;
|
||||
return PathResult.INVALID_PATH!;
|
||||
case 'A'..'Z':
|
||||
case 'a'..'z':
|
||||
return path[1] == ':' ? 2 : 0;
|
||||
@@ -224,7 +179,7 @@ fn usz! volume_name_len(String path, PathEnv path_env) @local
|
||||
|
||||
fn Path! Path.parent(Path path)
|
||||
{
|
||||
if (path.path_string.len == 1 && is_separator(path.path_string[0], path.env)) return PathResult.NO_PARENT?;
|
||||
if (path.path_string.len == 1 && is_separator(path.path_string[0], path.env)) return PathResult.NO_PARENT!;
|
||||
foreach_r(i, c : path.path_string)
|
||||
{
|
||||
if (is_separator(c, path.env))
|
||||
@@ -232,13 +187,13 @@ fn Path! Path.parent(Path path)
|
||||
return { path.path_string[:i], path.env };
|
||||
}
|
||||
}
|
||||
return PathResult.NO_PARENT?;
|
||||
return PathResult.NO_PARENT!;
|
||||
}
|
||||
|
||||
fn String! normalize(String path_str, PathEnv path_env = DEFAULT_PATH_ENV)
|
||||
{
|
||||
if (!path_str.len) return path_str;
|
||||
usz path_start = volume_name_len(path_str, path_env)!;
|
||||
usz path_start = volume_name_len(path_str, path_env)?;
|
||||
usz path_len = path_str.len;
|
||||
if (path_start == path_len) return path_str;
|
||||
char path_separator = path_env == PathEnv.WIN32 ? PREFERRED_SEPARATOR_WIN32 : PREFERRED_SEPARATOR_POSIX;
|
||||
@@ -270,7 +225,7 @@ fn String! normalize(String path_str, PathEnv path_env = DEFAULT_PATH_ENV)
|
||||
|
||||
// The rest are names of the path elements, so check that the
|
||||
// characters are valid.
|
||||
if (is_reserved_path_char(c, path_env)) return PathResult.INVALID_PATH?;
|
||||
if (is_reserved_path_char(c, path_env)) return PathResult.INVALID_PATH!;
|
||||
|
||||
// If we have '.' after a separator
|
||||
if (c == '.' && previous_was_separator)
|
||||
@@ -296,7 +251,7 @@ fn String! normalize(String path_str, PathEnv path_env = DEFAULT_PATH_ENV)
|
||||
continue;
|
||||
case 2:
|
||||
// This is an error: /a/../..
|
||||
if (len == path_start && has_root) return PathResult.INVALID_PATH?;
|
||||
if (len == path_start && has_root) return PathResult.INVALID_PATH!;
|
||||
|
||||
// If this .. at the start, or after ../? If so, we just copy ..
|
||||
if (len == path_start ||
|
||||
|
||||
@@ -19,7 +19,7 @@ fn Stream ByteReader.as_stream(ByteReader* reader)
|
||||
|
||||
fn usz! ByteReader.read(ByteReader* reader, char[] bytes)
|
||||
{
|
||||
if (reader.index >= reader.bytes.len) return IoError.EOF?;
|
||||
if (reader.index >= reader.bytes.len) return IoError.EOF!;
|
||||
usz len = math::min(reader.bytes.len - reader.index, bytes.len);
|
||||
if (len == 0) return 0;
|
||||
mem::copy(bytes.ptr, &reader.bytes[reader.index], len);
|
||||
@@ -29,13 +29,13 @@ fn usz! ByteReader.read(ByteReader* reader, char[] bytes)
|
||||
|
||||
fn char! ByteReader.read_byte(ByteReader* reader)
|
||||
{
|
||||
if (reader.index >= reader.bytes.len) return IoError.EOF?;
|
||||
if (reader.index >= reader.bytes.len) return IoError.EOF!;
|
||||
return reader.bytes[reader.index++];
|
||||
}
|
||||
|
||||
fn void! ByteReader.pushback_byte(ByteReader* reader)
|
||||
{
|
||||
if (!reader.index) return IoError.INVALID_PUSHBACK?;
|
||||
if (!reader.index) return IoError.INVALID_PUSHBACK!;
|
||||
reader.index--;
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ fn usz! ByteReader.seek(ByteReader* reader, isz offset, Seek seek)
|
||||
case CURSOR: new_index = reader.index + offset;
|
||||
case END: new_index = reader.bytes.len + offset;
|
||||
}
|
||||
if (new_index < 0) return IoError.INVALID_POSITION?;
|
||||
if (new_index < 0) return IoError.INVALID_POSITION!;
|
||||
reader.index = new_index;
|
||||
return new_index;
|
||||
}
|
||||
@@ -56,7 +56,7 @@ fn usz! ByteReader.seek(ByteReader* reader, isz offset, Seek seek)
|
||||
fn usz! ByteReader.write_stream(ByteReader* reader, Stream* writer)
|
||||
{
|
||||
if (reader.index >= reader.bytes.len) return 0;
|
||||
usz written = writer.write(reader.bytes[reader.index..])!;
|
||||
usz written = writer.write(reader.bytes[reader.index..])?;
|
||||
reader.index += written;
|
||||
assert(reader.index <= reader.bytes.len);
|
||||
return written;
|
||||
|
||||
@@ -52,16 +52,16 @@ fn String ByteWriter.as_str(ByteWriter* writer)
|
||||
fn void! ByteWriter.ensure_capacity(ByteWriter* writer, usz len) @inline
|
||||
{
|
||||
if (writer.bytes.len > len) return;
|
||||
if (!writer.allocator) return IoError.OUT_OF_SPACE?;
|
||||
if (!writer.allocator) return IoError.OUT_OF_SPACE!;
|
||||
if (len < 16) len = 16;
|
||||
usz new_capacity = math::next_power_of_2(len);
|
||||
char* new_ptr = realloc_checked(writer.bytes.ptr, new_capacity, .using = writer.allocator)!;
|
||||
char* new_ptr = realloc_checked(writer.bytes.ptr, new_capacity, .using = writer.allocator)?;
|
||||
writer.bytes = new_ptr[:new_capacity];
|
||||
}
|
||||
|
||||
fn usz! ByteWriter.write(ByteWriter* writer, char[] bytes)
|
||||
{
|
||||
writer.ensure_capacity(writer.index + bytes.len)!;
|
||||
writer.ensure_capacity(writer.index + bytes.len)?;
|
||||
mem::copy(&writer.bytes[writer.index], bytes.ptr, bytes.len);
|
||||
writer.index += bytes.len;
|
||||
return bytes.len;
|
||||
@@ -69,7 +69,7 @@ fn usz! ByteWriter.write(ByteWriter* writer, char[] bytes)
|
||||
|
||||
fn void! ByteWriter.write_byte(ByteWriter* writer, char c)
|
||||
{
|
||||
writer.ensure_capacity(writer.index + 1)!;
|
||||
writer.ensure_capacity(writer.index + 1)?;
|
||||
writer.bytes[writer.index++] = c;
|
||||
}
|
||||
|
||||
@@ -82,10 +82,10 @@ fn usz! ByteWriter.read_from(ByteWriter* writer, Stream* reader)
|
||||
if (reader.supports_available())
|
||||
{
|
||||
usz total_read = 0;
|
||||
while (usz available = reader.available()!)
|
||||
while (usz available = reader.available()?)
|
||||
{
|
||||
writer.ensure_capacity(writer.index + available)!;
|
||||
usz len = reader.read(writer.bytes[writer.index..])!;
|
||||
writer.ensure_capacity(writer.index + available)?;
|
||||
usz len = reader.read(writer.bytes[writer.index..])?;
|
||||
total_read += len;
|
||||
writer.index += len;
|
||||
}
|
||||
@@ -99,10 +99,10 @@ fn usz! ByteWriter.read_from(ByteWriter* writer, Stream* reader)
|
||||
// Less than 16 bytes? Double the capacity
|
||||
if (len_to_read < 16)
|
||||
{
|
||||
writer.ensure_capacity(writer.bytes.len * 2)!;
|
||||
writer.ensure_capacity(writer.bytes.len * 2)?;
|
||||
}
|
||||
// Read into the rest of the buffer
|
||||
usz read = reader.read(writer.bytes[writer.index..])!;
|
||||
usz read = reader.read(writer.bytes[writer.index..])?;
|
||||
writer.index += read;
|
||||
// Ok, we reached the end.
|
||||
if (read < len_to_read) return total_read;
|
||||
|
||||
@@ -31,11 +31,11 @@ fn void errno_set(Errno e)
|
||||
os::errno_set((int)e);
|
||||
}
|
||||
|
||||
def TerminateFunction = fn void();
|
||||
def CompareFunction = fn int(void*, void*);
|
||||
def JmpBuf = uptr[$$JMP_BUF_SIZE];
|
||||
typedef TerminateFunction = fn void();
|
||||
typedef CompareFunction = fn int(void*, void*);
|
||||
typedef JmpBuf = uptr[$$JMP_BUF_SIZE];
|
||||
|
||||
$if env::COMPILER_LIBC_AVAILABLE:
|
||||
$if (env::COMPILER_LIBC_AVAILABLE)
|
||||
|
||||
extern fn double atof(char* str);
|
||||
extern fn int atoi(char* str);
|
||||
@@ -59,7 +59,7 @@ extern fn int rand();
|
||||
extern fn void srand(uint seed);
|
||||
|
||||
extern fn void longjmp(JmpBuf* buffer, CInt value);
|
||||
$if env::os_is_win32():
|
||||
$if (env::OS_TYPE == OsType.WIN32)
|
||||
// TODO win32 aarch64
|
||||
extern fn CInt _setjmp(void* frameptr, JmpBuf* buffer);
|
||||
macro CInt setjmp(JmpBuf* buffer) => _setjmp($$frameaddress(), buffer);
|
||||
@@ -148,11 +148,11 @@ $endif
|
||||
|
||||
// stdio
|
||||
|
||||
def Fpos = long;
|
||||
def CFile = void*;
|
||||
typedef Fpos = long;
|
||||
typedef CFile = void*;
|
||||
|
||||
$switch
|
||||
$case env::COMPILER_LIBC_AVAILABLE && env::OS_TYPE == LINUX:
|
||||
$case env::COMPILER_LIBC_AVAILABLE && env::OS_TYPE == OsType.LINUX:
|
||||
extern CFile __stdin @extern("stdin");
|
||||
extern CFile __stdout @extern("stdout");
|
||||
extern CFile __stderr @extern("stderr");
|
||||
@@ -162,7 +162,7 @@ $case env::COMPILER_LIBC_AVAILABLE && env::OS_TYPE == LINUX:
|
||||
macro CFile stdin() { return __stdin; }
|
||||
macro CFile stdout() { return __stdout; }
|
||||
macro CFile stderr() { return __stderr; }
|
||||
$case env::COMPILER_LIBC_AVAILABLE && env::os_is_darwin():
|
||||
$case env::COMPILER_LIBC_AVAILABLE && env::OS_TYPE == OsType.MACOSX:
|
||||
extern CFile __stdinp;
|
||||
extern CFile __stdoutp;
|
||||
extern CFile __stderrp;
|
||||
@@ -171,7 +171,7 @@ $case env::COMPILER_LIBC_AVAILABLE && env::os_is_darwin():
|
||||
macro CFile stdin() { return __stdinp; }
|
||||
macro CFile stdout() { return __stdoutp; }
|
||||
macro CFile stderr() { return __stderrp; }
|
||||
$case env::COMPILER_LIBC_AVAILABLE && env::os_is_win32():
|
||||
$case env::COMPILER_LIBC_AVAILABLE && env::OS_TYPE == OsType.WIN32:
|
||||
extern fn CFile __acrt_iob_func(CInt c);
|
||||
extern fn usz _msize(void* ptr);
|
||||
macro usz malloc_size(void* ptr) { return _msize(ptr); }
|
||||
@@ -185,9 +185,9 @@ $default:
|
||||
$endswitch
|
||||
|
||||
const HAS_MALLOC_SIZE =
|
||||
env::OS_TYPE == LINUX
|
||||
|| env::os_is_win32()
|
||||
|| env::os_is_darwin();
|
||||
env::OS_TYPE == OsType.LINUX
|
||||
|| env::OS_TYPE == OsType.WIN32
|
||||
|| env::OS_TYPE == OsType.MACOSX;
|
||||
|
||||
// The following needs to be set per arch+os
|
||||
// For now I have simply pulled the defaults from MacOS
|
||||
@@ -202,10 +202,10 @@ const int EOF = -1;
|
||||
const int FOPEN_MAX = 20;
|
||||
const int FILENAME_MAX = 1024;
|
||||
|
||||
def Errno = distinct CInt;
|
||||
def SeekIndex = CLong;
|
||||
typedef Errno = distinct CInt;
|
||||
typedef SeekIndex = CLong;
|
||||
|
||||
$if env::COMPILER_LIBC_AVAILABLE:
|
||||
$if (env::COMPILER_LIBC_AVAILABLE)
|
||||
|
||||
extern fn int fclose(CFile stream);
|
||||
extern fn void clearerr(CFile stream);
|
||||
@@ -320,7 +320,9 @@ $endif
|
||||
|
||||
// time.h
|
||||
|
||||
struct TmCommon @private
|
||||
typedef TimeOffset = CLong;
|
||||
|
||||
struct Tm
|
||||
{
|
||||
int tm_sec; /* seconds after the minute [0-60] */
|
||||
int tm_min; /* minutes after the hour [0-59] */
|
||||
@@ -331,108 +333,41 @@ struct TmCommon @private
|
||||
int tm_wday; /* days since Sunday [0-6] */
|
||||
int tm_yday; /* days since January 1 [0-365] */
|
||||
int tm_isdst; /* Daylight Savings Time flag */
|
||||
}
|
||||
|
||||
|
||||
$switch (env::OS_TYPE)
|
||||
|
||||
$case WIN32:
|
||||
|
||||
def Tm = TmCommon;
|
||||
|
||||
$case WASI:
|
||||
|
||||
def TimeOffset = int;
|
||||
struct Tm
|
||||
{
|
||||
inline TmCommon common;
|
||||
TimeOffset tm_gmtoff; /* offset from UTC in seconds */
|
||||
char *tm_zone; /* timezone abbreviation */
|
||||
int tm_nsec;
|
||||
}
|
||||
|
||||
$case MACOS:
|
||||
$case IOS:
|
||||
$case TVOS:
|
||||
$case WATCHOS:
|
||||
$case OPENBSD:
|
||||
$case FREEBSD:
|
||||
$default:
|
||||
|
||||
def TimeOffset = CLong;
|
||||
struct Tm
|
||||
{
|
||||
inline TmCommon common;
|
||||
TimeOffset tm_gmtoff; /* offset from UTC in seconds */
|
||||
char *tm_zone; /* timezone abbreviation */
|
||||
}
|
||||
|
||||
$endswitch
|
||||
|
||||
|
||||
$if env::os_is_win32():
|
||||
|
||||
struct TimeSpec
|
||||
{
|
||||
Time_t s;
|
||||
Time s;
|
||||
ulong ns;
|
||||
}
|
||||
|
||||
def Time_t = long;
|
||||
def Clock_t = ulong;
|
||||
|
||||
$else
|
||||
|
||||
struct TimeSpec
|
||||
{
|
||||
Time_t s;
|
||||
CLong ns;
|
||||
}
|
||||
|
||||
def Time_t = CLong;
|
||||
def Clock_t = CULong;
|
||||
|
||||
$endif
|
||||
|
||||
const int TIME_UTC = 1;
|
||||
|
||||
|
||||
extern fn int timespec_get(TimeSpec* ts, int base);
|
||||
extern fn int nanosleep(TimeSpec* req, TimeSpec* remaining);
|
||||
|
||||
// Likely wrong, must be per platform.
|
||||
const CLOCKS_PER_SEC = 1000000;
|
||||
|
||||
// Time also needs to be per platform
|
||||
typedef Time = long;
|
||||
typedef Clock = ulong;
|
||||
|
||||
extern fn ZString asctime(Tm *timeptr);
|
||||
extern fn Clock_t clock();
|
||||
extern fn ZString ctime(Time_t *timer);
|
||||
extern fn double difftime(Time_t time1, Time_t time2);
|
||||
extern fn Tm* gmtime(Time_t *timer);
|
||||
|
||||
extern fn Tm* localtime(Time_t *timer);
|
||||
|
||||
$if env::os_is_win32():
|
||||
extern fn Tm* _gmtime64_s(Tm* buf, Time_t *timer);
|
||||
extern fn Tm* _localtime64_s(Tm* buf, Time_t *timer);
|
||||
extern fn void _get_timezone(CLong *timezone);
|
||||
|
||||
macro Tm* gmtime_r(Time_t *timer, Tm* buf) => _gmtime64_s(buf, timer);
|
||||
macro Tm* localtime_r(Time_t *timer, Tm* buf) => _localtime64_s(buf, timer);
|
||||
|
||||
extern fn Time_t mktime(Tm *timeptr) @extern("_mktime64");
|
||||
extern fn Time_t timegm(Tm *timeptr) @extern("_mkgmtime64");
|
||||
$else
|
||||
extern fn Tm* gmtime_r(Time_t *timer, Tm* buf);
|
||||
extern fn Tm* localtime_r(Time_t *timer, Tm* buf);
|
||||
extern fn Time_t mktime(Tm *timeptr);
|
||||
extern fn Time_t timegm(Tm *timeptr);
|
||||
$endif
|
||||
|
||||
extern fn Clock clock();
|
||||
extern fn ZString ctime(Time *timer);
|
||||
extern fn double difftime(Time time1, Time time2);
|
||||
extern fn Tm* gmtime(Time *timer);
|
||||
extern fn Tm* localtime(Time *timer);
|
||||
extern fn Time mktime(Tm *timeptr);
|
||||
extern fn usz strftime(char* str, usz maxsize, char* format, Tm *timeptr);
|
||||
extern fn Time_t time(Time_t *timer);
|
||||
extern fn Time time(Time *timer);
|
||||
|
||||
// signal
|
||||
def SignalFunction = fn void(int);
|
||||
typedef SignalFunction = fn void(int);
|
||||
extern fn SignalFunction signal(int sig, SignalFunction function);
|
||||
// Incomplete
|
||||
|
||||
@@ -451,7 +386,7 @@ const Errno ENOEXEC = 8; // Exec format error
|
||||
const Errno EBADF = 9; // Bad file number
|
||||
const Errno ECHILD = 10; // No child processes
|
||||
|
||||
$if env::os_is_darwin():
|
||||
$if (env::OS_TYPE == MACOSX)
|
||||
const Errno EAGAIN = 35; // Try again Macos
|
||||
$else
|
||||
const Errno EAGAIN = 11; // Try again
|
||||
@@ -483,7 +418,7 @@ const Errno ERANGE = 34; // Math result not representable
|
||||
|
||||
$switch (env::OS_TYPE)
|
||||
|
||||
$case MACOS:
|
||||
$case MACOSX:
|
||||
const Errno EDEADLK = 11; // Resource deadlock would occur MacOS
|
||||
const Errno ENAMETOOLONG = 63; // File name too long MacOS
|
||||
const Errno ELOOP = 62; // Too many symbolic links encountered
|
||||
@@ -493,7 +428,6 @@ const Errno ENETDOWN = 50; // Network is down MacOS
|
||||
const Errno ENETUNREACH = 51; // Network is unreachable MacOS
|
||||
const Errno ENETRESET = 52; // Network dropped connection because of reset MacOS
|
||||
const Errno EOPNOTSUPP = 45; // Operation not supported on transport endpoint
|
||||
const Errno ENOTEMPTY = 66; // Directory not empty
|
||||
|
||||
$case WIN32:
|
||||
const Errno EDEADLK = 36; // Resource deadlock would occur Win32
|
||||
@@ -505,7 +439,6 @@ const Errno ECONNRESET = 108; // Connection reset by peer
|
||||
const Errno ENETUNREACH = 118; // Network is unreachable
|
||||
const Errno ENETRESET = 117; // Network dropped connection because of reset
|
||||
const Errno EOPNOTSUPP = 130; // Operation not supported on transport endpoint
|
||||
const Errno ENOTEMPTY = 41; // Directory not empty
|
||||
|
||||
$default:
|
||||
const Errno EDEADLK = 35; // Resource deadlock would occur Linux (others?)
|
||||
@@ -517,7 +450,6 @@ const Errno ECONNRESET = 104; // Connection reset by peer
|
||||
const Errno ENETUNREACH = 101; // Network is unreachable
|
||||
const Errno ENETRESET = 102; // Network dropped connection because of reset
|
||||
const Errno EOPNOTSUPP = 95; // Operation not supported on transport endpoint
|
||||
const Errno ENOTEMPTY = 39; // Directory not empty
|
||||
|
||||
$endswitch
|
||||
|
||||
@@ -526,6 +458,7 @@ $endswitch
|
||||
/*
|
||||
const Errno ENOLCK = 37; /* No record locks available */
|
||||
const Errno ENOSYS = 38; /* Function not implemented */
|
||||
const Errno ENOTEMPTY = 39; /* Directory not empty */
|
||||
|
||||
const Errno ENOMSG = 42; /* No message of desired type */
|
||||
const Errno EIDRM = 43; /* Identifier removed */
|
||||
@@ -596,7 +529,7 @@ const Errno EHOSTUNREACH = 113; /* No route to host */
|
||||
|
||||
$switch (env::OS_TYPE)
|
||||
|
||||
$case MACOS:
|
||||
$case MACOSX:
|
||||
const Errno ETIMEDOUT = 60; // Connection timed out
|
||||
const Errno EINPROGRESS = 36; // Operation now in progress MacOS
|
||||
const Errno EALREADY = 37; // Operation already in progress MacOS
|
||||
|
||||
@@ -9,7 +9,7 @@ extern fn int* __errno_location();
|
||||
macro int errno() => *__errno_location();
|
||||
macro void errno_set(int err) => *(__errno_location()) = err;
|
||||
|
||||
$case env::COMPILER_LIBC_AVAILABLE && env::OS_TYPE == MACOS:
|
||||
$case env::COMPILER_LIBC_AVAILABLE && env::OS_TYPE == MACOSX:
|
||||
|
||||
extern fn int* __error();
|
||||
macro int errno() => *__error();
|
||||
|
||||
@@ -85,33 +85,29 @@ fault MatrixError
|
||||
MATRIX_INVERSE_DOESNT_EXIST,
|
||||
}
|
||||
|
||||
def Complexf = Complex<float>;
|
||||
def Complex = Complex<double>;
|
||||
def complexf_identity = complex::identity<float>;
|
||||
def complex_identity = complex::identity<double>;
|
||||
typedef Complexf = Complex<float>;
|
||||
typedef Complex = Complex<double>;
|
||||
define complexf_identity = complex::identity<float>;
|
||||
define complex_identity = complex::identity<double>;
|
||||
|
||||
def Quaternionf = Quaternion<float>;
|
||||
def Quaternion = Quaternion<double>;
|
||||
def quaternionf_identity = quaternion::identity<float>;
|
||||
def quaternion_identity = quaternion::identity<double>;
|
||||
typedef Quaternionf = Quaternion<float>;
|
||||
typedef Quaternion = Quaternion<double>;
|
||||
define quaternionf_identity = quaternion::identity<float>;
|
||||
define quaternion_identity = quaternion::identity<double>;
|
||||
|
||||
def Matrix2f = Matrix2x2<float>;
|
||||
def Matrix2 = Matrix2x2<double>;
|
||||
def Matrix3f = Matrix3x3<float>;
|
||||
def Matrix3 = Matrix3x3<double>;
|
||||
def Matrix4f = Matrix4x4<float>;
|
||||
def Matrix4 = Matrix4x4<double>;
|
||||
def matrix4_ortho = matrix::ortho<double>;
|
||||
def matrix4_perspective = matrix::perspective<double>;
|
||||
def matrix4f_ortho = matrix::ortho<float>;
|
||||
def matrix4f_perspective = matrix::perspective<float>;
|
||||
|
||||
def MATRIX2_IDENTITY = matrix::IDENTITY2<double>;
|
||||
def MATRIX2F_IDENTITY = matrix::IDENTITY2<float>;
|
||||
def MATRIX3_IDENTITY = matrix::IDENTITY3<double>;
|
||||
def MATRIX3F_IDENTITY = matrix::IDENTITY3<float>;
|
||||
def MATRIX4_IDENTITY = matrix::IDENTITY4<double>;
|
||||
def MATRIX4F_IDENTITY = matrix::IDENTITY4<float>;
|
||||
typedef Matrix2f = Matrix2x2<float>;
|
||||
typedef Matrix2 = Matrix2x2<double>;
|
||||
typedef Matrix3f = Matrix3x3<float>;
|
||||
typedef Matrix3 = Matrix3x3<double>;
|
||||
typedef Matrix4f = Matrix4x4<float>;
|
||||
typedef Matrix4 = Matrix4x4<double>;
|
||||
define matrix4_ortho = matrix::ortho<double>;
|
||||
define matrix4_perspective = matrix::perspective<double>;
|
||||
define matrix4f_ortho = matrix::ortho<float>;
|
||||
define matrix4f_perspective = matrix::perspective<float>;
|
||||
macro Matrix4 matrix4_indentity() => { .m = { [0] = 1, [5] = 1, [10] = 1, [15] = 1 } };
|
||||
macro Matrix3 matrix3_indentity() => { .m = { [0] = 1, [4] = 1, [8] = 1 } };
|
||||
macro Matrix2 matrix2_indentity() => { .m = { [0] = 1, [3] = 1 } };
|
||||
|
||||
/**
|
||||
* @require types::is_numerical($typeof(x)) `The input must be a numerical value or numerical vector`
|
||||
@@ -124,7 +120,7 @@ macro abs(x) => $$abs(x);
|
||||
macro sign(x)
|
||||
{
|
||||
var $Type = $typeof(x);
|
||||
$if $Type.kindof == TypeKind.UNSIGNED_INT:
|
||||
$if ($Type.kindof == TypeKind.UNSIGNED_INT)
|
||||
return ($Type)(x > 0);
|
||||
$else
|
||||
return ($Type)(x > 0) - ($Type)(x < 0);
|
||||
@@ -138,7 +134,7 @@ macro sign(x)
|
||||
**/
|
||||
macro atan2(x, y)
|
||||
{
|
||||
$if @typeis(x, float) && @typeis(y, float):
|
||||
$if (@typeis(x, float) && @typeis(y, float))
|
||||
return _atan2f(x, y);
|
||||
$else
|
||||
return _atan2(x, y);
|
||||
@@ -150,9 +146,9 @@ macro atan2(x, y)
|
||||
* @checked (*y)[0] = x, y.len
|
||||
* @require y.len == 2
|
||||
**/
|
||||
macro sincos(x, y)
|
||||
macro @sincos(x, y)
|
||||
{
|
||||
$if $typeof(y[0]).typeid == float.typeid:
|
||||
$if ($typeof(y[0]).typeid == float.typeid)
|
||||
return _sincosf(x, y);
|
||||
$else
|
||||
return _sincos(x, y);
|
||||
@@ -165,73 +161,13 @@ macro sincos(x, y)
|
||||
**/
|
||||
macro atan(x)
|
||||
{
|
||||
$if $typeof(x).typeid == float.typeid:
|
||||
$if ($typeof(x).typeid == float.typeid)
|
||||
return _atanf(x);
|
||||
$else
|
||||
return _atan(x);
|
||||
$endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @require values::@is_int(x) || values::@is_float(x) "Expected an integer or floating point value"
|
||||
**/
|
||||
macro atanh(x)
|
||||
{
|
||||
$if $typeof(x).typeid == float.typeid:
|
||||
return _atanhf(x);
|
||||
$else
|
||||
return _atanh(x);
|
||||
$endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @require values::@is_int(x) || values::@is_float(x) "Expected an integer or floating point value"
|
||||
**/
|
||||
macro acos(x)
|
||||
{
|
||||
$if $typeof(x).typeid == float.typeid:
|
||||
return _acosf(x);
|
||||
$else
|
||||
return _acos(x);
|
||||
$endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @require values::@is_int(x) || values::@is_float(x) "Expected an integer or floating point value"
|
||||
**/
|
||||
macro acosh(x)
|
||||
{
|
||||
$if $typeof(x).typeid == float.typeid:
|
||||
return _acoshf(x);
|
||||
$else
|
||||
return _acosh(x);
|
||||
$endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @require values::@is_int(x) || values::@is_float(x) "Expected an integer or floating point value"
|
||||
**/
|
||||
macro asin(x)
|
||||
{
|
||||
$if $typeof(x).typeid == float.typeid:
|
||||
return _asinf(x);
|
||||
$else
|
||||
return _asin(x);
|
||||
$endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @require values::@is_int(x) || values::@is_float(x) "Expected an integer or floating point value"
|
||||
**/
|
||||
macro asinh(x)
|
||||
{
|
||||
$if $typeof(x).typeid == float.typeid:
|
||||
return _asinhf(x);
|
||||
$else
|
||||
return _asinh(x);
|
||||
$endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @require values::@is_floatlike(x) `The input must be a floating point value or float vector`
|
||||
**/
|
||||
@@ -340,7 +276,7 @@ macro log10(x) => $$log10(values::promote_int(x));
|
||||
**/
|
||||
macro max(x, y, ...)
|
||||
{
|
||||
$if $vacount == 0:
|
||||
$if ($vacount == 0)
|
||||
return $$max(x, y);
|
||||
$else
|
||||
var m = $$max(x, y);
|
||||
@@ -357,7 +293,7 @@ macro max(x, y, ...)
|
||||
**/
|
||||
macro min(x, y, ...)
|
||||
{
|
||||
$if $vacount == 0:
|
||||
$if ($vacount == 0)
|
||||
return $$min(x, y);
|
||||
$else
|
||||
var m = $$min(x, y);
|
||||
@@ -385,7 +321,7 @@ macro nearbyint(x) => $$nearbyint(x);
|
||||
**/
|
||||
macro pow(x, exp)
|
||||
{
|
||||
$if types::is_floatlike($typeof(exp)):
|
||||
$if (types::is_floatlike($typeof(exp)))
|
||||
return $$pow(x, ($typeof(x))exp);
|
||||
$else
|
||||
return $$pow_int(x, exp);
|
||||
@@ -397,7 +333,7 @@ macro pow(x, exp)
|
||||
**/
|
||||
macro frexp(x, int* e)
|
||||
{
|
||||
$switch ($typeof(x))
|
||||
$switch($typeof(x))
|
||||
$case float:
|
||||
$case float16:
|
||||
return _frexpf((float)x, e);
|
||||
@@ -411,7 +347,7 @@ macro frexp(x, int* e)
|
||||
**/
|
||||
macro int signbit(x)
|
||||
{
|
||||
$switch ($typeof(x))
|
||||
$switch($typeof(x))
|
||||
$case float:
|
||||
$case float16:
|
||||
return bitcast((float)x, uint) >> 31;
|
||||
@@ -486,7 +422,7 @@ $endswitch
|
||||
**/
|
||||
macro bool is_finite(x)
|
||||
{
|
||||
$switch ($typeof(x))
|
||||
$switch($typeof(x))
|
||||
$case float:
|
||||
$case float16:
|
||||
return bitcast((float)x, uint) & 0x7fffffff < 0x7f800000;
|
||||
@@ -505,7 +441,7 @@ macro is_nan(x)
|
||||
$case float16:
|
||||
return bitcast((float)x, uint) & 0x7fffffff > 0x7f800000;
|
||||
$default:
|
||||
return bitcast((double)x, ulong) & (~0u64 >> 1) > 0x7ffu64 << 52;
|
||||
return bitcast((double)x, ulong) & (~0u64 >> 1) > 0x7ff << 52;
|
||||
$endswitch
|
||||
}
|
||||
|
||||
@@ -519,7 +455,7 @@ macro is_inf(x)
|
||||
$case float16:
|
||||
return bitcast((float)x, uint) & 0x7fffffff == 0x7f800000;
|
||||
$default:
|
||||
return bitcast((double)x, ulong) & (~0u64 >> 1) == 0x7ffu64 << 52;
|
||||
return bitcast((double)x, ulong) & (~0u64 >> 1) == 0x7ff << 52;
|
||||
$endswitch
|
||||
}
|
||||
|
||||
@@ -632,13 +568,6 @@ macro bool[<*>] double[<*>].comp_gt(double[<*>] x, double[<*>] y) => $$veccompgt
|
||||
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 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);
|
||||
@@ -647,13 +576,6 @@ 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 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);
|
||||
@@ -677,12 +599,6 @@ 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 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);
|
||||
@@ -691,12 +607,6 @@ 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 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);
|
||||
@@ -720,13 +630,6 @@ 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 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);
|
||||
@@ -735,12 +638,6 @@ 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 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);
|
||||
@@ -750,13 +647,6 @@ 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 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);
|
||||
@@ -765,13 +655,6 @@ 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 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);
|
||||
@@ -780,13 +663,6 @@ 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 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);
|
||||
@@ -877,6 +753,7 @@ macro uint float.word(float d) => bitcast(d, uint);
|
||||
|
||||
macro double scalbn(double x, int n) => _scalbn(x, n);
|
||||
|
||||
|
||||
extern fn double _atan(double x) @extern("atan");
|
||||
extern fn float _atanf(float x) @extern("atanf");
|
||||
extern fn double _atan2(double, double) @extern("atan2");
|
||||
@@ -886,17 +763,6 @@ extern fn void _sincosf(float, float*) @extern("sincosf");
|
||||
extern fn double _tan(double x) @extern("tan");
|
||||
extern fn float _tanf(float x) @extern("tanf");
|
||||
extern fn double _scalbn(double x, int n) @extern("scalbn");
|
||||
extern fn double _acos(double x) @extern("acos");
|
||||
extern fn double _asin(double x) @extern("asin");
|
||||
extern fn double _acosh(double x) @extern("acosh");
|
||||
extern fn double _asinh(double x) @extern("asinh");
|
||||
extern fn double _atanh(double x) @extern("atanh");
|
||||
extern fn float _acosf(float x) @extern("acosf");
|
||||
extern fn float _asinf(float x) @extern("asinf");
|
||||
extern fn float _acoshf(float x) @extern("acoshf");
|
||||
extern fn float _asinhf(float x) @extern("asinhf");
|
||||
extern fn float _atanhf(float x) @extern("atanhf");
|
||||
|
||||
|
||||
fn double _frexp(double x, int* e)
|
||||
{
|
||||
|
||||
@@ -276,7 +276,7 @@ fn Matrix4x4 Matrix4x4.adjoint(Matrix4x4* mat)
|
||||
fn Matrix2x2! Matrix2x2.inverse(Matrix2x2* m)
|
||||
{
|
||||
Real det = m.determinant();
|
||||
if (det == 0) return MatrixError.MATRIX_INVERSE_DOESNT_EXIST?;
|
||||
if (det == 0) return MatrixError.MATRIX_INVERSE_DOESNT_EXIST!;
|
||||
Matrix2x2 adj = m.adjoint();
|
||||
return adj.component_mul(1 / det).transpose();
|
||||
}
|
||||
@@ -284,7 +284,7 @@ fn Matrix2x2! Matrix2x2.inverse(Matrix2x2* m)
|
||||
fn Matrix3x3! Matrix3x3.inverse(Matrix3x3* m)
|
||||
{
|
||||
Real det = m.determinant();
|
||||
if (det == 0) return MatrixError.MATRIX_INVERSE_DOESNT_EXIST?;
|
||||
if (det == 0) return MatrixError.MATRIX_INVERSE_DOESNT_EXIST!;
|
||||
Matrix3x3 adj = m.adjoint();
|
||||
return adj.component_mul(1 / det).transpose();
|
||||
}
|
||||
@@ -292,7 +292,7 @@ fn Matrix3x3! Matrix3x3.inverse(Matrix3x3* m)
|
||||
fn Matrix4x4! Matrix4x4.inverse(Matrix4x4* m)
|
||||
{
|
||||
Real det = m.determinant();
|
||||
if (det == 0) return MatrixError.MATRIX_INVERSE_DOESNT_EXIST?;
|
||||
if (det == 0) return MatrixError.MATRIX_INVERSE_DOESNT_EXIST!;
|
||||
Matrix4x4 adj = m.adjoint();
|
||||
return adj.component_mul(1 / det).transpose();
|
||||
}
|
||||
@@ -411,9 +411,6 @@ fn Matrix4x4 perspective(Real fov, Real aspect_ratio, Real near, Real far)
|
||||
};
|
||||
}
|
||||
|
||||
const Matrix2x2 IDENTITY2 = { .m = { [0] = 1, [3] = 1 } };
|
||||
const Matrix3x3 IDENTITY3 = { .m = { [0] = 1, [4] = 1, [8] = 1 } };
|
||||
const Matrix4x4 IDENTITY4 = { .m = { [0] = 1, [5] = 1, [10] = 1, [15] = 1 } };
|
||||
|
||||
macro matrix_component_mul(mat, val) @private
|
||||
{
|
||||
|
||||
@@ -6,9 +6,9 @@ struct Random
|
||||
void* state;
|
||||
}
|
||||
|
||||
def RandomSeedFn = fn void(Random*, char[] seed);
|
||||
def RandomNextBytesFn = fn void(Random*, char[] buffer);
|
||||
def RandomNextFn = fn uint(Random*, int bits);
|
||||
typedef RandomSeedFn = fn void(Random*, char[] seed);
|
||||
typedef RandomNextBytesFn = fn void(Random*, char[] buffer);
|
||||
typedef RandomNextFn = fn uint(Random*, int bits);
|
||||
|
||||
struct RandomInterface
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module std::math::nolibc;
|
||||
|
||||
$if !env::COMPILER_LIBC_AVAILABLE:
|
||||
$if (!env::COMPILER_LIBC_AVAILABLE)
|
||||
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/k_cos.c */
|
||||
/*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module std::math::nolibc;
|
||||
|
||||
$if !env::COMPILER_LIBC_AVAILABLE:
|
||||
$if (!env::COMPILER_LIBC_AVAILABLE)
|
||||
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/k_cosf.c */
|
||||
/*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module std::math::nolibc;
|
||||
|
||||
$if !env::COMPILER_LIBC_AVAILABLE:
|
||||
$if (!env::COMPILER_LIBC_AVAILABLE)
|
||||
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/k_sin.c */
|
||||
/*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module std::math::nolibc;
|
||||
|
||||
$if !env::COMPILER_LIBC_AVAILABLE:
|
||||
$if (!env::COMPILER_LIBC_AVAILABLE)
|
||||
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/k_sinf.c */
|
||||
/*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module std::math::nolibc;
|
||||
|
||||
$if !env::COMPILER_LIBC_AVAILABLE:
|
||||
$if (!env::COMPILER_LIBC_AVAILABLE)
|
||||
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/k_tan.c */
|
||||
/*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module std::math::nolibc;
|
||||
|
||||
$if !env::COMPILER_LIBC_AVAILABLE:
|
||||
$if (!env::COMPILER_LIBC_AVAILABLE)
|
||||
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/k_tanf.c */
|
||||
/*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module std::math::nolibc::atan;
|
||||
|
||||
$if !env::COMPILER_LIBC_AVAILABLE:
|
||||
$if (!env::COMPILER_LIBC_AVAILABLE)
|
||||
|
||||
const double[*] ATANHI @private = {
|
||||
4.63647609000806093515e-01, /* atan(0.5)hi 0x3FDDAC67, 0x0561BB4F */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module std::math::nolibc;
|
||||
|
||||
$if !env::COMPILER_LIBC_AVAILABLE:
|
||||
$if (!env::COMPILER_LIBC_AVAILABLE)
|
||||
|
||||
fn double _ceil(double x) @weak @extern("ceil") @nostrip
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module std::math::nolibc;
|
||||
|
||||
$if !env::COMPILER_LIBC_AVAILABLE:
|
||||
$if (!env::COMPILER_LIBC_AVAILABLE)
|
||||
|
||||
fn float _cosf(float x) @extern("cosf") @weak @nostrip
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module std::math::nolibc;
|
||||
|
||||
$if !env::COMPILER_LIBC_AVAILABLE:
|
||||
$if (!env::COMPILER_LIBC_AVAILABLE)
|
||||
|
||||
macro uint _top12f(float x) @private => bitcast(x, uint) >> 20;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module std::math::nolibc;
|
||||
|
||||
$if !env::COMPILER_LIBC_AVAILABLE:
|
||||
$if (!env::COMPILER_LIBC_AVAILABLE)
|
||||
|
||||
fn double _floor(double x) @weak @extern("floor") @nostrip
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module std::math::nolibc;
|
||||
|
||||
$if !env::COMPILER_LIBC_AVAILABLE:
|
||||
$if (!env::COMPILER_LIBC_AVAILABLE)
|
||||
|
||||
fn float powf_broken(float x, float f) @extern("powf") @weak @nostrip
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
module std::math::nolibc;
|
||||
import std::math;
|
||||
|
||||
$if !env::COMPILER_LIBC_AVAILABLE:
|
||||
$if (!env::COMPILER_LIBC_AVAILABLE)
|
||||
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/e_rem_pio2f.c */
|
||||
/*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module std::math::nolibc;
|
||||
|
||||
$if !env::COMPILER_LIBC_AVAILABLE:
|
||||
$if (!env::COMPILER_LIBC_AVAILABLE)
|
||||
|
||||
fn double _round(double x) @extern("round") @weak @nostrip
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module std::math::nolibc;
|
||||
|
||||
$if !env::COMPILER_LIBC_AVAILABLE:
|
||||
$if (!env::COMPILER_LIBC_AVAILABLE)
|
||||
|
||||
fn double _scalbn(double x, int n) @weak @extern("scalbn") @nostrip
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module std::math::nolibc;
|
||||
|
||||
$if !env::COMPILER_LIBC_AVAILABLE:
|
||||
$if (!env::COMPILER_LIBC_AVAILABLE)
|
||||
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.c */
|
||||
/*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module std::math::nolibc;
|
||||
|
||||
$if !env::COMPILER_LIBC_AVAILABLE:
|
||||
$if (!env::COMPILER_LIBC_AVAILABLE)
|
||||
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/s_sinf.c */
|
||||
/*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module std::math::nolibc;
|
||||
|
||||
$if !env::COMPILER_LIBC_AVAILABLE:
|
||||
$if (!env::COMPILER_LIBC_AVAILABLE)
|
||||
|
||||
/* origin: FreeBSD /usr/src/lib/msun/src/s_tan.c */
|
||||
/*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module std::math::nolibc::trig;
|
||||
|
||||
$if !env::COMPILER_LIBC_AVAILABLE:
|
||||
$if (!env::COMPILER_LIBC_AVAILABLE)
|
||||
|
||||
fn double sincos_broken(double x) @extern("sincos") @weak @nostrip
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module std::math::nolibc;
|
||||
|
||||
$if !env::COMPILER_LIBC_AVAILABLE:
|
||||
$if (!env::COMPILER_LIBC_AVAILABLE)
|
||||
|
||||
fn double _trunc(double x) @weak @extern("trunc") @nostrip
|
||||
{
|
||||
|
||||
@@ -18,8 +18,6 @@ macro Quaternion Quaternion.scale(Quaternion a, Real s) => Quaternion { .v = a.v
|
||||
macro Quaternion Quaternion.normalize(Quaternion q) => { .v = q.v.normalize() };
|
||||
macro Real Quaternion.length(Quaternion q) => q.v.length();
|
||||
macro Quaternion Quaternion.lerp(Quaternion q1, Quaternion q2, Real amount) => { .v = q1.v.lerp(q2.v, amount) };
|
||||
macro Matrix4f Quaternion.to_matrixf(Quaternion* q) => into_matrix(q, Matrix4f);
|
||||
macro Matrix4 Quaternion.to_matrix(Quaternion* q) => into_matrix(q, Matrix4);
|
||||
fn Quaternion Quaternion.nlerp(Quaternion q1, Quaternion q2, Real amount) => { .v = q1.v.lerp(q2.v, amount).normalize() };
|
||||
|
||||
fn Quaternion Quaternion.invert(Quaternion q)
|
||||
@@ -67,32 +65,4 @@ fn Quaternion Quaternion.mul(Quaternion a, Quaternion b)
|
||||
a.l * b.l - a.i * b.i - a.j * a.j - a.k * a.k };
|
||||
}
|
||||
|
||||
macro into_matrix(Quaternion* q, $Type) @private
|
||||
{
|
||||
$Type result = { .m = { [0] = 1, [5] = 1, [10] = 1, [15] = 1 } };
|
||||
Quaternion norm = q.normalize();
|
||||
|
||||
var ii = norm.i*norm.i;
|
||||
var jj = norm.j*norm.j;
|
||||
var kk = norm.k*norm.k;
|
||||
var ik = norm.i*norm.k;
|
||||
var ij = norm.i*q.j;
|
||||
var jk = norm.j*norm.k;
|
||||
var li = norm.l*norm.i;
|
||||
var lj = norm.l*norm.j;
|
||||
var lk = norm.l*norm.k;
|
||||
|
||||
result.m00 = 1 - 2*(jj + kk);
|
||||
result.m01 = 2*(ik + lk);
|
||||
result.m02 = 2*(ij - lj);
|
||||
|
||||
result.m10 = 2*(ij - lk);
|
||||
result.m11 = 1 - 2*(ii + kk);
|
||||
result.m12 = 2*(jk + li);
|
||||
|
||||
result.m20 = 2*(ik + lj);
|
||||
result.m21 = 2*(jk - li);
|
||||
result.m22 = 1 - 2*(ii + jj);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
module std::math::vector;
|
||||
import std::math;
|
||||
|
||||
def Vec2f = float[<2>];
|
||||
def Vec3f = float[<3>];
|
||||
def Vec4f = float[<4>];
|
||||
typedef Vec2f = float[<2>];
|
||||
typedef Vec3f = float[<3>];
|
||||
typedef Vec4f = float[<4>];
|
||||
|
||||
def Vec2 = double[<2>];
|
||||
def Vec3 = double[<3>];
|
||||
def Vec4 = double[<4>];
|
||||
typedef Vec2 = double[<2>];
|
||||
typedef Vec3 = double[<3>];
|
||||
typedef Vec4 = double[<4>];
|
||||
|
||||
macro Vec2f.length_sq(Vec2f v) => v.dot(v);
|
||||
macro Vec3f.length_sq(Vec3f v) => v.dot(v);
|
||||
@@ -138,9 +138,8 @@ macro cross3(v1, v2) @private
|
||||
|
||||
macro transform2(v, mat) @private
|
||||
{
|
||||
return $typeof(v) {
|
||||
mat.m00 * v[0] + mat.m10 * v[1] + mat.m30 ,
|
||||
mat.m01 * v[0] + mat.m11 * v[1] + mat.m31 };
|
||||
return $typeof(v) { mat.m00 * v[0] + mat.m10 * v[1] + mat.30,
|
||||
mat.m01 * v[0] + mar.m11 * v[1] + mat.31 };
|
||||
}
|
||||
|
||||
macro transform3(v, mat) @private
|
||||
@@ -217,7 +216,7 @@ return v;
|
||||
var view_proj = m1.mul(m2);
|
||||
var invert = view_proj.invert();
|
||||
// Create quaternion from source point
|
||||
$if $typeof(v[0]).typeid == float.typeid:
|
||||
$if ($typeof(v[0]).typeid == float.typeid)
|
||||
Quaternionf quat = { v.x, v.y, v.z, 1 };
|
||||
$else
|
||||
Quaternion quat = { v.x, v.y, v.z, 1 };
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module std::math;
|
||||
|
||||
def SimpleRandom = distinct ulong;
|
||||
typedef SimpleRandom = distinct ulong;
|
||||
|
||||
const long SIMPLE_RANDOM_MULTIPLIER @local = 0x5DEECE66D;
|
||||
const long SIMPLE_RANDOM_ADDEND @local = 0xB;
|
||||
|
||||
@@ -37,42 +37,46 @@ struct InetAddress
|
||||
}
|
||||
}
|
||||
|
||||
static initialize
|
||||
{
|
||||
io::formatter_register_type(InetAddress);
|
||||
}
|
||||
|
||||
fn void! InetAddress.to_format(InetAddress* addr, Formatter* formatter) @dynamic
|
||||
fn void! InetAddress.to_format(InetAddress* addr, Formatter* formatter)
|
||||
{
|
||||
if (addr.is_ipv6)
|
||||
{
|
||||
formatter.printf("%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
|
||||
addr.ipv6.a, addr.ipv6.b, addr.ipv6.c, addr.ipv6.d,
|
||||
addr.ipv6.e, addr.ipv6.f, addr.ipv6.g, addr.ipv6.h)!;
|
||||
addr.ipv6.e, addr.ipv6.f, addr.ipv6.g, addr.ipv6.h)?;
|
||||
return;
|
||||
}
|
||||
formatter.printf("%d.%d.%d.%d", addr.ipv4.a, addr.ipv4.b, addr.ipv4.c, addr.ipv4.d)!;
|
||||
formatter.printf("%d.%d.%d.%d", addr.ipv4.a, addr.ipv4.b, addr.ipv4.c, addr.ipv4.d)?;
|
||||
}
|
||||
|
||||
fn String! InetAddress.to_string(InetAddress* addr, Allocator* using = mem::heap()) @dynamic
|
||||
fn String! InetAddress.to_string(InetAddress* addr, Allocator* using = mem::heap())
|
||||
{
|
||||
if (addr.is_ipv6)
|
||||
{
|
||||
char[8 * 5 + 1] buffer;
|
||||
String res = (String)io::bprintf(&buffer, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x",
|
||||
addr.ipv6.a, addr.ipv6.b, addr.ipv6.c, addr.ipv6.d,
|
||||
addr.ipv6.e, addr.ipv6.f, addr.ipv6.g, addr.ipv6.h)!;
|
||||
addr.ipv6.e, addr.ipv6.f, addr.ipv6.g, addr.ipv6.h)?;
|
||||
return res.copy(using);
|
||||
}
|
||||
char[3 * 4 + 3 + 1] buffer;
|
||||
String res = (String)io::bprintf(&buffer, "%d.%d.%d.%d", addr.ipv4.a, addr.ipv4.b, addr.ipv4.c, addr.ipv4.d)!;
|
||||
String res = (String)io::bprintf(&buffer, "%d.%d.%d.%d", addr.ipv4.a, addr.ipv4.b, addr.ipv4.c, addr.ipv4.d)?;
|
||||
return res.copy(using);
|
||||
}
|
||||
|
||||
fn InetAddress! ipv6_from_str(String s)
|
||||
{
|
||||
uint sections = 0;
|
||||
if (s.len < 2) return NetError.INVALID_IP_STRING?;
|
||||
if (s.len < 2) return NetError.INVALID_IP_STRING!;
|
||||
foreach (c : s) if (c == ':') sections++;
|
||||
int zero_segment_len = s[0] == ':' || s[^1] == ':' ? 9 - sections : 8 - sections;
|
||||
if (zero_segment_len == 7 && s.len == 2) return { .is_ipv6 = true };
|
||||
if (zero_segment_len > 7) return NetError.INVALID_IP_STRING?;
|
||||
if (zero_segment_len > 7) return NetError.INVALID_IP_STRING!;
|
||||
usz index = 0;
|
||||
bool last_was_colon, found_zero;
|
||||
int current = -1;
|
||||
@@ -88,7 +92,7 @@ fn InetAddress! ipv6_from_str(String s)
|
||||
last_was_colon = true;
|
||||
continue;
|
||||
}
|
||||
if (current < 0 || current > 65535) return NetError.INVALID_IP_STRING?;
|
||||
if (current < 0 || current > 65535) return NetError.INVALID_IP_STRING!;
|
||||
addr.ipv6arr[index++].val = (ushort)current;
|
||||
current = -1;
|
||||
last_was_colon = true;
|
||||
@@ -96,9 +100,9 @@ fn InetAddress! ipv6_from_str(String s)
|
||||
}
|
||||
assert(current == -1);
|
||||
// Check that this is the first ::
|
||||
if (found_zero) return NetError.INVALID_IP_STRING?;
|
||||
if (found_zero) return NetError.INVALID_IP_STRING!;
|
||||
// Also check that the zeroed section is at least 2
|
||||
if (zero_segment_len < 2) return NetError.INVALID_IP_STRING?;
|
||||
if (zero_segment_len < 2) return NetError.INVALID_IP_STRING!;
|
||||
// Skip (will be zero by default
|
||||
index += zero_segment_len;
|
||||
found_zero = true;
|
||||
@@ -106,7 +110,7 @@ fn InetAddress! ipv6_from_str(String s)
|
||||
continue;
|
||||
}
|
||||
last_was_colon = false;
|
||||
if (index > 7 || !c.is_xdigit()) return NetError.INVALID_IP_STRING?;
|
||||
if (index > 7 || !c.is_xdigit()) return NetError.INVALID_IP_STRING!;
|
||||
if (current < 0) current = 0;
|
||||
current = current * 16 + (c <= '9' ? c - '0' : (c | 32) - 'a' + 10);
|
||||
}
|
||||
@@ -114,7 +118,7 @@ fn InetAddress! ipv6_from_str(String s)
|
||||
if (index == 8 && current == -1) return addr;
|
||||
|
||||
// Ends with number
|
||||
if (index != 7 || current < 0 || current > 65535) return NetError.INVALID_IP_STRING?;
|
||||
if (index != 7 || current < 0 || current > 65535) return NetError.INVALID_IP_STRING!;
|
||||
addr.ipv6arr[7].val = (ushort)current;
|
||||
return addr;
|
||||
}
|
||||
@@ -128,20 +132,20 @@ fn InetAddress! ipv4_from_str(String s)
|
||||
{
|
||||
if (c == '.')
|
||||
{
|
||||
if (current < 0) return NetError.INVALID_IP_STRING?;
|
||||
if (current > 255) return NetError.INVALID_IP_STRING?;
|
||||
if (current < 0) return NetError.INVALID_IP_STRING!;
|
||||
if (current > 255) return NetError.INVALID_IP_STRING!;
|
||||
switch (element)
|
||||
{
|
||||
case 0: addr.ipv4.a = (char)current;
|
||||
case 1: addr.ipv4.b = (char)current;
|
||||
case 2: addr.ipv4.c = (char)current;
|
||||
default: return NetError.INVALID_IP_STRING?;
|
||||
default: return NetError.INVALID_IP_STRING!;
|
||||
}
|
||||
current = -1;
|
||||
element++;
|
||||
continue;
|
||||
}
|
||||
if (element > 3 || c < '0' || c > '9') return NetError.INVALID_IP_STRING?;
|
||||
if (element > 3 || c < '0' || c > '9') return NetError.INVALID_IP_STRING!;
|
||||
if (current < 0)
|
||||
{
|
||||
current = c - '0';
|
||||
@@ -149,7 +153,7 @@ fn InetAddress! ipv4_from_str(String s)
|
||||
}
|
||||
current = current * 10 + c - '0';
|
||||
}
|
||||
if (element != 3 || current < 0 || current > 255) return NetError.INVALID_IP_STRING?;
|
||||
if (element != 3 || current < 0 || current > 255) return NetError.INVALID_IP_STRING!;
|
||||
addr.ipv4.d = (char)current;
|
||||
return addr;
|
||||
}
|
||||
|
||||
@@ -19,13 +19,13 @@ fn uint! ipv4toint(String s)
|
||||
{
|
||||
if (c == '.')
|
||||
{
|
||||
if (current < 0) return NetError.INVALID_IP_STRING?;
|
||||
if (current < 0) return NetError.INVALID_IP_STRING!;
|
||||
out = out << 8 + current;
|
||||
current = -1;
|
||||
element++;
|
||||
continue;
|
||||
}
|
||||
if (element > 3 || c < '0' || c > '9') return NetError.INVALID_IP_STRING?;
|
||||
if (element > 3 || c < '0' || c > '9') return NetError.INVALID_IP_STRING!;
|
||||
if (current < 0)
|
||||
{
|
||||
current = c - '0';
|
||||
@@ -33,7 +33,7 @@ fn uint! ipv4toint(String s)
|
||||
}
|
||||
current = current * 10 + c - '0';
|
||||
}
|
||||
if (element != 3 || current < 0) return NetError.INVALID_IP_STRING?;
|
||||
if (element != 3 || current < 0) return NetError.INVALID_IP_STRING!;
|
||||
out = out << 8 + current;
|
||||
return out;
|
||||
}
|
||||
@@ -41,6 +41,6 @@ fn uint! ipv4toint(String s)
|
||||
fn String! inttoipv4(uint val, Allocator* using = mem::heap())
|
||||
{
|
||||
char[3 * 4 + 3 + 1] buffer;
|
||||
String res = (String)io::bprintf(&buffer, "%d.%d.%d.%d", val >> 24, (val >> 16) & 0xFF, (val >> 8) & 0xFF, val & 0xFF)!;
|
||||
String res = (String)io::bprintf(&buffer, "%d.%d.%d.%d", val >> 24, (val >> 16) & 0xFF, (val >> 8) & 0xFF, val & 0xFF)?;
|
||||
return res.copy(using);
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
module std::net::os;
|
||||
|
||||
$if $defined(PLATFORM_AF_INET):
|
||||
$if ($defined(PLATFORM_AF_INET))
|
||||
|
||||
$if !$defined(PLATFORM_O_NONBLOCK):
|
||||
$if (!$defined(PLATFORM_O_NONBLOCK))
|
||||
const PLATFORM_O_NONBLOCK = 0;
|
||||
$endif
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
module std::net::os;
|
||||
import libc;
|
||||
|
||||
$if env::os_is_darwin():
|
||||
$if (env::OS_TYPE == OsType.MACOSX)
|
||||
|
||||
const AI_NUMERICSERV = 0x1000;
|
||||
const AI_ALL = 0x100;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
module std::net::os;
|
||||
import libc;
|
||||
|
||||
$if env::OS_TYPE == LINUX:
|
||||
$if (env::OS_TYPE == OsType.LINUX)
|
||||
|
||||
struct AddrInfo
|
||||
{
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
module std::net::os;
|
||||
import libc;
|
||||
|
||||
$if !env::os_is_win32() && $defined(AddrInfo):
|
||||
$if (env::OS_TYPE != OsType.WIN32 && $defined(AddrInfo))
|
||||
|
||||
const int F_GETFL = 3;
|
||||
const int F_SETFL = 4;
|
||||
|
||||
def NativeSocket = distinct int;
|
||||
typedef NativeSocket = distinct int;
|
||||
|
||||
extern fn NativeSocket socket(int af, int type, int protocol) @extern("socket");
|
||||
extern fn int getaddrinfo(ZString nodename, ZString servname, AddrInfo* hints, AddrInfo** res);
|
||||
@@ -19,8 +19,8 @@ macro void! NativeSocket.close(NativeSocket this)
|
||||
{
|
||||
if (close(this))
|
||||
{
|
||||
if (libc::errno() == errno::EBADF) return NetError.INVALID_SOCKET?;
|
||||
return NetError.GENERAL_ERROR?;
|
||||
if (libc::errno() == errno::EBADF) return NetError.INVALID_SOCKET!;
|
||||
return NetError.GENERAL_ERROR!;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,8 +29,8 @@ macro void! NativeSocket.set_non_blocking(NativeSocket this)
|
||||
int flags = fcntl(this, F_GETFL, 0);
|
||||
if (fcntl(this, F_SETFL, flags | O_NONBLOCK) == -1)
|
||||
{
|
||||
if (libc::errno() == errno::EBADF) return NetError.INVALID_SOCKET?;
|
||||
return NetError.GENERAL_ERROR?;
|
||||
if (libc::errno() == errno::EBADF) return NetError.INVALID_SOCKET!;
|
||||
return NetError.GENERAL_ERROR!;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module std::net::os;
|
||||
|
||||
$if env::os_is_win32():
|
||||
$if (env::OS_TYPE == OsType.WIN32)
|
||||
|
||||
const int PLATFORM_AF_INET = 1;
|
||||
const int PLATFORM_AF_IPX = 6;
|
||||
@@ -22,7 +22,7 @@ struct AddrInfo
|
||||
AddrInfo* ai_next;
|
||||
}
|
||||
|
||||
def NativeSocket = distinct uptr;
|
||||
typedef NativeSocket = distinct uptr;
|
||||
|
||||
extern fn int wsa_startup(int, void*) @extern("WSAStartup");
|
||||
extern fn int ioctlsocket(NativeSocket, long cmd, ulong *argp);
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
module std::os::macos::cf;
|
||||
|
||||
$if env::os_is_darwin():
|
||||
$if (env::OS_TYPE == OsType.MACOSX)
|
||||
|
||||
def CFAllocatorRef = distinct void*;
|
||||
def CFAllocatorContextRef = distinct void*;
|
||||
def CFOptionFlags = usz;
|
||||
typedef CFAllocatorRef = distinct void*;
|
||||
typedef CFAllocatorContextRef = distinct void*;
|
||||
typedef CFOptionFlags = usz;
|
||||
|
||||
macro CFAllocatorRef default_allocator() => _macos_CFAllocatorGetDefault();
|
||||
macro void CFAllocatorRef.dealloc(CFAllocatorRef allocator, void* ptr) => _macos_CFAllocatorDeallocate(allocator, ptr);
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
module std::os::macos::cf;
|
||||
|
||||
$if env::os_is_darwin():
|
||||
$if (env::OS_TYPE == OsType.MACOSX)
|
||||
|
||||
def CFArrayRef = distinct void*;
|
||||
def CFArrayCallBacksRef = distinct void*;
|
||||
def CFMutableArrayRef = distinct void*;
|
||||
typedef CFArrayRef = distinct void*;
|
||||
typedef CFArrayCallBacksRef = distinct void*;
|
||||
typedef CFMutableArrayRef = distinct void*;
|
||||
extern fn CFArrayRef _macos_CFArrayCreate(CFAllocatorRef allocator, void** values, CFIndex num_values, CFArrayCallBacksRef callBacks) @extern("CFArrayCreate");
|
||||
extern fn CFArrayRef _macos_CFArrayCopy(CFAllocatorRef allocator, CFArrayRef array) @extern("CFArrayCopy");
|
||||
extern fn CFIndex _macos_CFArrayGetCount(CFArrayRef array) @extern("CFArrayGetCount");
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
module std::os::macos::cf;
|
||||
|
||||
$if env::os_is_darwin():
|
||||
$if (env::OS_TYPE == OsType.MACOSX)
|
||||
|
||||
def CFTypeRef = distinct void*;
|
||||
def CFIndex = isz;
|
||||
typedef CFTypeRef = distinct void*;
|
||||
typedef CFIndex = isz;
|
||||
struct CFRange
|
||||
{
|
||||
CFIndex location;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
module std::os::macos::objc;
|
||||
|
||||
$if env::os_is_darwin():
|
||||
$if (env::OS_TYPE == OsType.MACOSX)
|
||||
|
||||
def Class = distinct void*;
|
||||
def Method = distinct void*;
|
||||
def Ivar = distinct void*;
|
||||
def Selector = distinct void*;
|
||||
typedef Class = distinct void*;
|
||||
typedef Method = distinct void*;
|
||||
typedef Ivar = distinct void*;
|
||||
typedef Selector = distinct void*;
|
||||
|
||||
fault ObjcFailure
|
||||
{
|
||||
@@ -24,7 +24,7 @@ macro Selector selector_register(char* c) => _macos_sel_registerName(c);
|
||||
macro Class! class_by_name(char* c)
|
||||
{
|
||||
Class cls = _macos_objc_lookUpClass(c);
|
||||
if (!cls) return ObjcFailure.CLASS_NOT_FOUND?;
|
||||
if (!cls) return ObjcFailure.CLASS_NOT_FOUND!;
|
||||
return cls;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
module std::os::posix;
|
||||
|
||||
$if env::os_is_posix() && env::COMPILER_LIBC_AVAILABLE:
|
||||
|
||||
extern fn int rmdir(ZString);
|
||||
extern fn int mkdir(ZString, ushort mode_t);
|
||||
extern fn int chdir(ZString);
|
||||
extern fn ZString getcwd(char* pwd, usz len);
|
||||
|
||||
$endif
|
||||
29
lib/std/os/win32/error.c3
Normal file
29
lib/std/os/win32/error.c3
Normal file
@@ -0,0 +1,29 @@
|
||||
module std::os::win32::wsa;
|
||||
|
||||
$if (env::OS_TYPE == OsType.WIN32)
|
||||
extern fn int get_last_error() @extern("WSAGetLastError");
|
||||
extern fn void set_last_error(int error) @extern("WSASetLastError");
|
||||
|
||||
const int INVALID_HANDLE = 6;
|
||||
const int NOT_ENOUGHT_MEMORY = 8;
|
||||
const int INVALID_PARAMETER = 87;
|
||||
const int OPERATION_ABORTED = 995;
|
||||
const int IO_INCOMPLETE = 996;
|
||||
const int IO_PENDING = 997;
|
||||
const int EINTR = 10004;
|
||||
const int EBADF = 10009;
|
||||
const int ACCESS = 10013;
|
||||
const int EFAULT = 10014;
|
||||
const int EINVAL = 10022;
|
||||
const int EMFILE = 10024;
|
||||
const int EWOULDBLOCK = 10035;
|
||||
const int EINPROGRESS = 10036;
|
||||
const int EALREADY = 10037;
|
||||
const int ENOTSOCK = 10038;
|
||||
const int EDESTADDRREQ = 10039;
|
||||
const int EMSGSIZE = 10040;
|
||||
const int EPROTOTYPE = 10041;
|
||||
const int ENOPROTOOPT = 10042;
|
||||
const int EPROTONOSUPPORT = 10043;
|
||||
const int ESOCKTNOSUPPORT = 10044;
|
||||
$endif
|
||||
@@ -1,6 +1,6 @@
|
||||
module std::os::win32;
|
||||
module std::os::win32::files;
|
||||
|
||||
$if env::os_is_win32():
|
||||
$if (env::os_is_win32())
|
||||
|
||||
enum Win32_GET_FILEEX_INFO_LEVELS
|
||||
{
|
||||
@@ -8,6 +8,11 @@ enum Win32_GET_FILEEX_INFO_LEVELS
|
||||
MAX,
|
||||
}
|
||||
|
||||
struct Win32_FILETIME
|
||||
{
|
||||
Win32_DWORD dwLowDateTime;
|
||||
Win32_DWORD dwHighDateTime;
|
||||
}
|
||||
|
||||
struct Win32_FILE_ATTRIBUTE_DATA
|
||||
{
|
||||
@@ -19,47 +24,18 @@ struct Win32_FILE_ATTRIBUTE_DATA
|
||||
Win32_DWORD nFileSizeLow;
|
||||
}
|
||||
|
||||
|
||||
const MAX_PATH = 260;
|
||||
|
||||
struct Win32_WIN32_FIND_DATAW
|
||||
{
|
||||
Win32_DWORD dwFileAttributes;
|
||||
Win32_FILETIME ftCreationTime;
|
||||
Win32_FILETIME ftLastAccessTime;
|
||||
Win32_FILETIME ftLastWriteTime;
|
||||
Win32_DWORD nFileSizeHigh;
|
||||
Win32_DWORD nFileSizeLow;
|
||||
Win32_DWORD dwReserved0;
|
||||
Win32_DWORD dwReserved1;
|
||||
Win32_WCHAR[260] cFileName;
|
||||
Win32_WCHAR[14] cAlternateFileName;
|
||||
Win32_DWORD dwFileType; // Obsolete. Do not use.
|
||||
Win32_DWORD dwCreatorType; // Obsolete. Do not use
|
||||
Win32_WORD wFinderFlags; // Obsolete. Do not use
|
||||
}
|
||||
|
||||
def Win32_LPWIN32_FIND_DATAW = Win32_WIN32_FIND_DATAW*;
|
||||
|
||||
extern fn Win32_BOOL win32_CloseHandle(Win32_HANDLE) @extern("CloseHandle");
|
||||
extern fn Win32_BOOL win32_CreatePipe(Win32_PHANDLE hReadPipe, Win32_PHANDLE hWritePipe, Win32_LPSECURITY_ATTRIBUTES lpPipeAttributes, Win32_DWORD nSize) @extern("CreatePipe");
|
||||
extern fn Win32_BOOL win32_GetFileAttributesExW(Win32_LPCWSTR, Win32_GET_FILEEX_INFO_LEVELS, Win32_LPVOID) @extern("GetFileAttributesExW");
|
||||
extern fn Win32_BOOL win32_PathFileExistsW(Win32_LPCWSTR) @extern("PathFileExistsW");
|
||||
extern fn Win32_DWORD win32_GetTempPathW(Win32_DWORD nBufferLength, Win32_LPWSTR lpBuffer) @extern("GetTempPathW");
|
||||
extern fn Win32_BOOL win32_SetCurrentDirectoryW(Win32_LPCTSTR buffer) @extern("SetCurrentDirectoryW");
|
||||
extern fn Win32_BOOL win32_RemoveDirectoryW(Win32_LPCWSTR lpPathName) @extern("RemoveDirectoryW");
|
||||
extern fn Win32_BOOL win32_CreateDirectoryW(Win32_LPCWSTR lpPathName, Win32_LPSECURITY_ATTRIBUTES lpPipeAttributes) @extern("CreateDirectoryW");
|
||||
extern fn Win32_BOOL win32_DeleteFileW(Win32_LPCWSTR lpFileName) @extern("DeleteFileW");
|
||||
extern fn Win32_HANDLE win32_FindFirstFileW(Win32_LPCWSTR lpFileName, Win32_LPWIN32_FIND_DATAW lpFindFileData) @extern("FindFirstFileW");
|
||||
extern fn Win32_BOOL win32_FindNextFileW(Win32_HANDLE hFindFile, Win32_LPWIN32_FIND_DATAW lpFindFileData) @extern("FindNextFileW");
|
||||
extern fn Win32_BOOL win32_FindClose(Win32_HANDLE hFindFile) @extern("FindClose");
|
||||
|
||||
extern fn Char16* _wgetcwd(Char16* buffer, int maxlen);
|
||||
extern fn usz wcslen(Char16* str);
|
||||
|
||||
/*
|
||||
extern ulong _win32_GetCurrentDirectoryW(ulong, Char16* buffer) @extern("GetCurrentDirectoryW");
|
||||
extern bool _win32_CreateSymbolicLinkW(Char16* symlink_file, Char16* target_file, ulong flags) @extern("CreateSymbolicLinkW");
|
||||
extern bool _win32_CreateDirectoryW(Char16* path_name, void* security_attributes) @extern("CreateDirectoryW");
|
||||
extern bool _win32_DeleteFileW(Char16* file) @extern("DeleteFileW");
|
||||
extern bool _win32_CopyFileW(Char16* from_file, Char16* to_file, bool no_overwrite) @extern("CopyFileW");
|
||||
extern ulong _win32_GetFullPathNameW(Char16* file_name, ulong buffer_len, Char16* buffer, Char16** file_part) @extern("GetFullPathNameW");
|
||||
*/
|
||||
|
||||
@@ -1,227 +0,0 @@
|
||||
module std::os::win32;
|
||||
|
||||
$if env::os_is_win32():
|
||||
|
||||
extern fn Win32_DWORD win32_GetLastError() @extern("GetLastError");
|
||||
|
||||
const Win32_DWORD ERROR_INVALID_FUNCTION = 0x1;
|
||||
const Win32_DWORD ERROR_FILE_NOT_FOUND = 0x2;
|
||||
const Win32_DWORD ERROR_PATH_NOT_FOUND = 0x3;
|
||||
const Win32_DWORD ERROR_TOO_MANY_OPEN_FILES = 0x4;
|
||||
const Win32_DWORD ERROR_ACCESS_DENIED = 0x5;
|
||||
const Win32_DWORD ERROR_INVALID_HANDLE = 0x6;
|
||||
const Win32_DWORD ERROR_ARENA_TRASHED = 0x7;
|
||||
const Win32_DWORD ERROR_NOT_ENOUGH_MEMORY = 0x8;
|
||||
const Win32_DWORD ERROR_INVALID_BLOCK = 0x9;
|
||||
const Win32_DWORD ERROR_BAD_ENVIRONMENT = 0xA;
|
||||
const Win32_DWORD ERROR_BAD_FORMAT = 0xB;
|
||||
const Win32_DWORD ERROR_INVALID_ACCESS = 0xC;
|
||||
const Win32_DWORD ERROR_INVALID_DATA = 0xD;
|
||||
const Win32_DWORD ERROR_OUTOFMEMORY = 0xE;
|
||||
const Win32_DWORD ERROR_INVALID_DRIVE = 0xF;
|
||||
const Win32_DWORD ERROR_CURRENT_DIRECTORY = 0x10;
|
||||
const Win32_DWORD ERROR_NOT_SAME_DEVICE = 0x11;
|
||||
const Win32_DWORD ERROR_NO_MORE_FILES = 0x12;
|
||||
const Win32_DWORD ERROR_WRITE_PROTECT = 0x13;
|
||||
const Win32_DWORD ERROR_BAD_UNIT = 0x14;
|
||||
const Win32_DWORD ERROR_NOT_READY = 0x15;
|
||||
const Win32_DWORD ERROR_BAD_COMMAND = 0x16;
|
||||
const Win32_DWORD ERROR_CRC = 0x17;
|
||||
const Win32_DWORD ERROR_BAD_LENGTH = 0x18;
|
||||
const Win32_DWORD ERROR_SEEK = 0x19;
|
||||
const Win32_DWORD ERROR_NOT_DOS_DISK = 0x1A;
|
||||
const Win32_DWORD ERROR_SECTOR_NOT_FOUND = 0x1B;
|
||||
const Win32_DWORD ERROR_OUT_OF_PAPER = 0x1C;
|
||||
const Win32_DWORD ERROR_WRITE_FAULT = 0x1D;
|
||||
const Win32_DWORD ERROR_READ_FAULT = 0x1E;
|
||||
const Win32_DWORD ERROR_GEN_FAILURE = 0x1F;
|
||||
const Win32_DWORD ERROR_SHARING_VIOLATION = 0x20;
|
||||
const Win32_DWORD ERROR_LOCK_VIOLATION = 0x21;
|
||||
const Win32_DWORD ERROR_WRONG_DISK = 0x22;
|
||||
const Win32_DWORD ERROR_SHARING_BUFFER_EXCEEDED = 0x24;
|
||||
const Win32_DWORD ERROR_HANDLE_EOF = 0x26;
|
||||
const Win32_DWORD ERROR_HANDLE_DISK_FULL = 0x27;
|
||||
const Win32_DWORD ERROR_NOT_SUPPORTED = 0x32;
|
||||
const Win32_DWORD ERROR_REM_NOT_LIST = 0x33;
|
||||
const Win32_DWORD ERROR_DUP_NAME = 0x34;
|
||||
const Win32_DWORD ERROR_BAD_NETPATH = 0x35;
|
||||
const Win32_DWORD ERROR_NETWORK_BUSY = 0x36;
|
||||
const Win32_DWORD ERROR_DEV_NOT_EXIST = 0x37;
|
||||
const Win32_DWORD ERROR_TOO_MANY_CMDS = 0x38;
|
||||
const Win32_DWORD ERROR_ADAP_HDW_ERR = 0x39;
|
||||
const Win32_DWORD ERROR_BAD_NET_RESP = 0x3A;
|
||||
const Win32_DWORD ERROR_UNEXP_NET_ERR = 0x3B;
|
||||
const Win32_DWORD ERROR_BAD_REM_ADAP = 0x3C;
|
||||
const Win32_DWORD ERROR_PRINTQ_FULL = 0x3D;
|
||||
const Win32_DWORD ERROR_NO_SPOOL_SPACE = 0x3E;
|
||||
const Win32_DWORD ERROR_PRINT_CANCELLED = 0x3F;
|
||||
const Win32_DWORD ERROR_NETNAME_DELETED = 0x40;
|
||||
const Win32_DWORD ERROR_NETWORK_ACCESS_DENIED = 0x41;
|
||||
const Win32_DWORD ERROR_BAD_DEV_TYPE = 0x42;
|
||||
const Win32_DWORD ERROR_BAD_NET_NAME = 0x43;
|
||||
const Win32_DWORD ERROR_TOO_MANY_NAMES = 0x44;
|
||||
const Win32_DWORD ERROR_TOO_MANY_SESS = 0x45;
|
||||
const Win32_DWORD ERROR_SHARING_PAUSED = 0x46;
|
||||
const Win32_DWORD ERROR_REQ_NOT_ACCEP = 0x47;
|
||||
const Win32_DWORD ERROR_REDIR_PAUSED = 0x48;
|
||||
const Win32_DWORD ERROR_FILE_EXISTS = 0x50;
|
||||
const Win32_DWORD ERROR_CANNOT_MAKE = 0x52;
|
||||
const Win32_DWORD ERROR_FAIL_I24 = 0x53;
|
||||
const Win32_DWORD ERROR_OUT_OF_STRUCTURES = 0x54;
|
||||
const Win32_DWORD ERROR_ALREADY_ASSIGNED = 0x55;
|
||||
const Win32_DWORD ERROR_INVALID_PASSWORD = 0x56;
|
||||
const Win32_DWORD ERROR_INVALID_PARAMETER = 0x57;
|
||||
const Win32_DWORD ERROR_NET_WRITE_FAULT = 0x58;
|
||||
const Win32_DWORD ERROR_NO_PROC_SLOTS = 0x59;
|
||||
const Win32_DWORD ERROR_TOO_MANY_SEMAPHORES = 0x64;
|
||||
const Win32_DWORD ERROR_EXCL_SEM_ALREADY_OWNED = 0x65;
|
||||
const Win32_DWORD ERROR_SEM_IS_SET = 0x66;
|
||||
const Win32_DWORD ERROR_TOO_MANY_SEM_REQUESTS = 0x67;
|
||||
const Win32_DWORD ERROR_INVALID_AT_INTERRUPT_TIME = 0x68;
|
||||
const Win32_DWORD ERROR_SEM_OWNER_DIED = 0x69;
|
||||
const Win32_DWORD ERROR_SEM_USER_LIMIT = 0x6A;
|
||||
const Win32_DWORD ERROR_DISK_CHANGE = 0x6B;
|
||||
const Win32_DWORD ERROR_DRIVE_LOCKED = 0x6C;
|
||||
const Win32_DWORD ERROR_BROKEN_PIPE = 0x6D;
|
||||
const Win32_DWORD ERROR_OPEN_FAILED = 0x6E;
|
||||
const Win32_DWORD ERROR_BUFFER_OVERFLOW = 0x6F;
|
||||
const Win32_DWORD ERROR_DISK_FULL = 0x70;
|
||||
const Win32_DWORD ERROR_NO_MORE_SEARCH_HANDLES = 0x71;
|
||||
const Win32_DWORD ERROR_INVALID_TARGET_HANDLE = 0x72;
|
||||
const Win32_DWORD ERROR_INVALID_CATEGORY = 0x75;
|
||||
const Win32_DWORD ERROR_INVALID_VERIFY_SWITCH = 0x76;
|
||||
const Win32_DWORD ERROR_BAD_DRIVER_LEVEL = 0x77;
|
||||
const Win32_DWORD ERROR_CALL_NOT_IMPLEMENTED = 0x78;
|
||||
const Win32_DWORD ERROR_SEM_TIMEOUT = 0x79;
|
||||
const Win32_DWORD ERROR_INSUFFICIENT_BUFFER = 0x7A;
|
||||
const Win32_DWORD ERROR_INVALID_NAME = 0x7B;
|
||||
const Win32_DWORD ERROR_INVALID_LEVEL = 0x7C;
|
||||
const Win32_DWORD ERROR_NO_VOLUME_LABEL = 0x7D;
|
||||
const Win32_DWORD ERROR_MOD_NOT_FOUND = 0x7E;
|
||||
const Win32_DWORD ERROR_PROC_NOT_FOUND = 0x7F;
|
||||
const Win32_DWORD ERROR_WAIT_NO_CHILDREN = 0x80;
|
||||
const Win32_DWORD ERROR_CHILD_NOT_COMPLETE = 0x81;
|
||||
const Win32_DWORD ERROR_DIRECT_ACCESS_HANDLE = 0x82;
|
||||
const Win32_DWORD ERROR_NEGATIVE_SEEK = 0x83;
|
||||
const Win32_DWORD ERROR_SEEK_ON_DEVICE = 0x84;
|
||||
const Win32_DWORD ERROR_IS_JOIN_TARGET = 0x85;
|
||||
const Win32_DWORD ERROR_IS_JOINED = 0x86;
|
||||
const Win32_DWORD ERROR_IS_SUBSTED = 0x87;
|
||||
const Win32_DWORD ERROR_NOT_JOINED = 0x88;
|
||||
const Win32_DWORD ERROR_NOT_SUBSTED = 0x89;
|
||||
const Win32_DWORD ERROR_JOIN_TO_JOIN = 0x8A;
|
||||
const Win32_DWORD ERROR_SUBST_TO_SUBST = 0x8B;
|
||||
const Win32_DWORD ERROR_JOIN_TO_SUBST = 0x8C;
|
||||
const Win32_DWORD ERROR_SUBST_TO_JOIN = 0x8D;
|
||||
const Win32_DWORD ERROR_BUSY_DRIVE = 0x8E;
|
||||
const Win32_DWORD ERROR_SAME_DRIVE = 0x8F;
|
||||
const Win32_DWORD ERROR_DIR_NOT_ROOT = 0x90;
|
||||
const Win32_DWORD ERROR_DIR_NOT_EMPTY = 0x91;
|
||||
const Win32_DWORD ERROR_IS_SUBST_PATH = 0x92;
|
||||
const Win32_DWORD ERROR_IS_JOIN_PATH = 0x93;
|
||||
const Win32_DWORD ERROR_PATH_BUSY = 0x94;
|
||||
const Win32_DWORD ERROR_IS_SUBST_TARGET = 0x95;
|
||||
const Win32_DWORD ERROR_SYSTEM_TRACE = 0x96;
|
||||
const Win32_DWORD ERROR_INVALID_EVENT_COUNT = 0x97;
|
||||
const Win32_DWORD ERROR_TOO_MANY_MUXWAITERS = 0x98;
|
||||
const Win32_DWORD ERROR_INVALID_LIST_FORMAT = 0x99;
|
||||
const Win32_DWORD ERROR_LABEL_TOO_LONG = 0x9A;
|
||||
const Win32_DWORD ERROR_TOO_MANY_TCBS = 0x9B;
|
||||
const Win32_DWORD ERROR_SIGNAL_REFUSED = 0x9C;
|
||||
const Win32_DWORD ERROR_DISCARDED = 0x9D;
|
||||
const Win32_DWORD ERROR_NOT_LOCKED = 0x9E;
|
||||
const Win32_DWORD ERROR_BAD_THREADID_ADDR = 0x9F;
|
||||
const Win32_DWORD ERROR_BAD_ARGUMENTS = 0xA0;
|
||||
const Win32_DWORD ERROR_BAD_PATHNAME = 0xA1;
|
||||
const Win32_DWORD ERROR_SIGNAL_PENDING = 0xA2;
|
||||
const Win32_DWORD ERROR_MAX_THRDS_REACHED = 0xA4;
|
||||
const Win32_DWORD ERROR_LOCK_FAILED = 0xA7;
|
||||
const Win32_DWORD ERROR_BUSY = 0xAA;
|
||||
const Win32_DWORD ERROR_DEVICE_SUPPORT_IN_PROGRESS = 0xAB;
|
||||
const Win32_DWORD ERROR_CANCEL_VIOLATION = 0xAD;
|
||||
const Win32_DWORD ERROR_ATOMIC_LOCKS_NOT_SUPPORTED = 0xAE;
|
||||
const Win32_DWORD ERROR_INVALID_SEGMENT_NUMBER = 0xB4;
|
||||
const Win32_DWORD ERROR_INVALID_ORDINAL = 0xB6;
|
||||
const Win32_DWORD ERROR_ALREADY_EXISTS = 0xB7;
|
||||
const Win32_DWORD ERROR_INVALID_FLAG_NUMBER = 0xBA;
|
||||
const Win32_DWORD ERROR_SEM_NOT_FOUND = 0xBB;
|
||||
const Win32_DWORD ERROR_INVALID_STARTING_CODESEG = 0xBC;
|
||||
const Win32_DWORD ERROR_INVALID_STACKSEG = 0xBD;
|
||||
const Win32_DWORD ERROR_INVALID_MODULETYPE = 0xBE;
|
||||
const Win32_DWORD ERROR_INVALID_EXE_SIGNATURE = 0xBF;
|
||||
|
||||
const Win32_DWORD ERROR_EXE_MARKED_INVALID = 0xC0;
|
||||
const Win32_DWORD ERROR_BAD_EXE_FORMAT = 0xC1;
|
||||
const Win32_DWORD ERROR_ITERATED_DATA_EXCEEDS_64K = 0xC2;
|
||||
const Win32_DWORD ERROR_INVALID_MINALLOCSIZE = 0xC3;
|
||||
const Win32_DWORD ERROR_DYNLINK_FROM_INVALID_RING = 0xC4;
|
||||
const Win32_DWORD ERROR_IOPL_NOT_ENABLED = 0xC5;
|
||||
const Win32_DWORD ERROR_INVALID_SEGDPL = 0xC6;
|
||||
const Win32_DWORD ERROR_AUTODATASEG_EXCEEDS_64K = 0xC7;
|
||||
const Win32_DWORD ERROR_RING2SEG_MUST_BE_MOVABLE = 0xC8;
|
||||
const Win32_DWORD ERROR_RELOC_CHAIN_XEEDS_SEGLIM = 0xC9;
|
||||
const Win32_DWORD ERROR_INFLOOP_IN_RELOC_CHAIN = 0xCA;
|
||||
const Win32_DWORD ERROR_ENVVAR_NOT_FOUND = 0xCB;
|
||||
const Win32_DWORD ERROR_NO_SIGNAL_SENT = 0xCD;
|
||||
const Win32_DWORD ERROR_FILENAME_EXCED_RANGE = 0xCE;
|
||||
const Win32_DWORD ERROR_RING2_STACK_IN_USE = 0xCF;
|
||||
const Win32_DWORD ERROR_META_EXPANSION_TOO_LONG = 0xD0;
|
||||
const Win32_DWORD ERROR_INVALID_SIGNAL_NUMBER = 0xD1;
|
||||
const Win32_DWORD ERROR_THREAD_1_INACTIVE = 0xD2;
|
||||
const Win32_DWORD ERROR_LOCKED = 0xD4;
|
||||
const Win32_DWORD ERROR_TOO_MANY_MODULES = 0xD6;
|
||||
const Win32_DWORD ERROR_NESTING_NOT_ALLOWED = 0xD7;
|
||||
const Win32_DWORD ERROR_EXE_MACHINE_TYPE_MISMATCH = 0xD8;
|
||||
const Win32_DWORD ERROR_EXE_CANNOT_MODIFY_SIGNED_BINARY = 0xD9;
|
||||
const Win32_DWORD ERROR_EXE_CANNOT_MODIFY_STRONG_SIGNED_BINARY = 0xDA;
|
||||
const Win32_DWORD ERROR_FILE_CHECKED_OUT = 0xDC;
|
||||
const Win32_DWORD ERROR_CHECKOUT_REQUIRED = 0xDD;
|
||||
const Win32_DWORD ERROR_BAD_FILE_TYPE = 0xDE;
|
||||
const Win32_DWORD ERROR_FILE_TOO_LARGE = 0xDF;
|
||||
const Win32_DWORD ERROR_FORMS_AUTH_REQUIRED = 0xE0;
|
||||
const Win32_DWORD ERROR_VIRUS_INFECTED = 0xE1;
|
||||
const Win32_DWORD ERROR_VIRUS_DELETED = 0xE2;
|
||||
const Win32_DWORD ERROR_PIPE_LOCAL = 0xE5;
|
||||
const Win32_DWORD ERROR_BAD_PIPE = 0xE6;
|
||||
const Win32_DWORD ERROR_PIPE_BUSY = 0xE7;
|
||||
const Win32_DWORD ERROR_NO_DATA = 0xE8;
|
||||
const Win32_DWORD ERROR_PIPE_NOT_CONNECTED = 0xE9;
|
||||
const Win32_DWORD ERROR_MORE_DATA = 0xEA;
|
||||
const Win32_DWORD ERROR_VC_DISCONNECTED = 0xF0;
|
||||
const Win32_DWORD ERROR_INVALID_EA_NAME = 0xFE;
|
||||
const Win32_DWORD ERROR_EA_LIST_INCONSISTENT = 0xFF;
|
||||
const Win32_DWORD WAIT_TIMEOUT = 0x102;
|
||||
const Win32_DWORD ERROR_NO_MORE_ITEMS = 0x103;
|
||||
const Win32_DWORD ERROR_CANNOT_COPY = 0x10A;
|
||||
const Win32_DWORD ERROR_DIRECTORY = 0x10B;
|
||||
|
||||
const Win32_DWORD ERROR_EAS_DIDNT_FIT = 0x113;
|
||||
const Win32_DWORD ERROR_EA_FILE_CORRUPT = 0x114;
|
||||
const Win32_DWORD ERROR_EA_TABLE_FULL = 0x115;
|
||||
const Win32_DWORD ERROR_INVALID_EA_HANDLE = 0x116;
|
||||
const Win32_DWORD ERROR_EAS_NOT_SUPPORTED = 0x11A;
|
||||
const Win32_DWORD ERROR_NOT_OWNER = 0x120;
|
||||
const Win32_DWORD ERROR_TOO_MANY_POSTS = 0x12A;
|
||||
const Win32_DWORD ERROR_PARTIAL_COPY = 0x12A;
|
||||
const Win32_DWORD ERROR_OPLOCK_NOT_GRANTED = 0x12C;
|
||||
const Win32_DWORD ERROR_INVALID_OPLOCK_PROTOCOL = 0x12D;
|
||||
const Win32_DWORD ERROR_DISK_TOO_FRAGMENTED = 0x12E;
|
||||
const Win32_DWORD ERROR_DELETE_PENDING = 0x12F;
|
||||
const Win32_DWORD ERROR_INCOMPATIBLE_WITH_GLOBAL_SHORT_NAME_REGISTRY_SETTING = 0x130;
|
||||
const Win32_DWORD ERROR_SHORT_NAMES_NOT_ENABLED_ON_VOLUME = 0x131;
|
||||
const Win32_DWORD ERROR_SECURITY_STREAM_IS_INCONSISTENT = 0x132;
|
||||
const Win32_DWORD ERROR_INVALID_LOCK_RANGE = 0x133;
|
||||
const Win32_DWORD ERROR_IMAGE_SUBSYSTEM_NOT_PRESENT = 0x134;
|
||||
const Win32_DWORD ERROR_NOTIFICATION_GUID_ALREADY_DEFINED = 0x135;
|
||||
const Win32_DWORD ERROR_INVALID_EXCEPTION_HANDLER = 0x136;
|
||||
const Win32_DWORD ERROR_DUPLICATE_PRIVILEGES = 0x137;
|
||||
const Win32_DWORD ERROR_NO_RANGES_PROCESSED = 0x138;
|
||||
const Win32_DWORD ERROR_NOT_ALLOWED_ON_SYSTEM_FILE = 0x139;
|
||||
const Win32_DWORD ERROR_DISK_RESOURCES_EXHAUSTED = 0x13A;
|
||||
const Win32_DWORD ERROR_INVALID_TOKEN = 0x13B;
|
||||
const Win32_DWORD ERROR_DEVICE_FEATURE_NOT_SUPPORTED = 0x13C;
|
||||
const Win32_DWORD ERROR_MR_MID_NOT_FOUND = 0x13D;
|
||||
const Win32_DWORD ERROR_SCOPE_NOT_FOUND = 0x13E;
|
||||
const Win32_DWORD ERROR_UNDEFINED_SCOPE = 0x13F;
|
||||
|
||||
$endif
|
||||
@@ -1,6 +1,6 @@
|
||||
module std::os::win32;
|
||||
module std::os::win32::process;
|
||||
|
||||
$if env::os_is_win32():
|
||||
$if (env::os_is_win32())
|
||||
|
||||
extern fn bool win32_CreateProcessW(
|
||||
Win32_LPCWSTR lpApplicationName,
|
||||
@@ -13,6 +13,6 @@ extern fn bool win32_CreateProcessW(
|
||||
Win32_LPCWSTR lpCurrentDirectory,
|
||||
Win32_LPSTARTUPINFOW lpStartupInfo,
|
||||
Win32_LPPROCESS_INFORMATION lpProcessInformation
|
||||
) @extern("CreateProcessW");
|
||||
);
|
||||
|
||||
$endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user