mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d7cc37b951 | ||
|
|
4ce62cf221 | ||
|
|
1f052da0b9 | ||
|
|
812dc0c292 | ||
|
|
798fe0dce9 | ||
|
|
3f6fe55f9a | ||
|
|
aee4aecfe7 | ||
|
|
748c737e8f | ||
|
|
c673101bbb | ||
|
|
d66674655c | ||
|
|
da292e41bd | ||
|
|
deb4cc7c4b | ||
|
|
e91f6e268e | ||
|
|
2595ed5cc9 |
36
.github/workflows/main.yml
vendored
36
.github/workflows/main.yml
vendored
@@ -61,6 +61,14 @@ jobs:
|
||||
run: |
|
||||
build\${{ matrix.build_type }}\c3c.exe vendor-fetch raylib
|
||||
|
||||
- name: Try raylib
|
||||
run: |
|
||||
cd resources
|
||||
..\build\${{ matrix.build_type }}\c3c.exe vendor-fetch raylib
|
||||
..\build\${{ matrix.build_type }}\c3c.exe compile --lib raylib --wincrt=none examples\raylib\raylib_arkanoid.c3
|
||||
..\build\${{ matrix.build_type }}\c3c.exe compile --lib raylib --wincrt=none examples\raylib\raylib_snake.c3
|
||||
..\build\${{ matrix.build_type }}\c3c.exe compile --lib raylib --wincrt=none examples\raylib\raylib_tetris.c3
|
||||
|
||||
- name: run compiler tests
|
||||
run: |
|
||||
cd test
|
||||
@@ -71,6 +79,11 @@ jobs:
|
||||
cd test
|
||||
..\build\${{ matrix.build_type }}\c3c.exe compile-test unit -O1
|
||||
|
||||
- name: Test python script
|
||||
run: |
|
||||
py msvc_build_libraries.py --accept-license
|
||||
dir msvc_sdk
|
||||
|
||||
- name: upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
@@ -193,7 +206,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
build_type: [Release, Debug]
|
||||
llvm_version: [15, 16, 17, 18]
|
||||
llvm_version: [15, 16, 17, 18, 19]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
@@ -207,7 +220,7 @@ jobs:
|
||||
if [[ "${{matrix.llvm_version}}" < 16 ]]; then
|
||||
sudo apt remove libllvm15
|
||||
fi
|
||||
if [[ "${{matrix.llvm_version}}" < 18 ]]; then
|
||||
if [[ "${{matrix.llvm_version}}" < 19 ]]; then
|
||||
sudo add-apt-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-${{matrix.llvm_version}} main"
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y -t llvm-toolchain-focal-${{matrix.llvm_version}} libpolly-${{matrix.llvm_version}}-dev \
|
||||
@@ -222,6 +235,7 @@ jobs:
|
||||
libmlir-${{matrix.llvm_version}}-dev mlir-${{matrix.llvm_version}}-tools
|
||||
fi
|
||||
- name: CMake
|
||||
if: matrix.llvm_version != 18
|
||||
run: |
|
||||
cmake -B build \
|
||||
-G Ninja \
|
||||
@@ -234,6 +248,20 @@ jobs:
|
||||
-DCMAKE_DLLTOOL=llvm-dlltool-${{matrix.llvm_version}} \
|
||||
-DC3_LLVM_VERSION=${{matrix.llvm_version}}
|
||||
cmake --build build
|
||||
- name: CMake18
|
||||
if: matrix.llvm_version == 18
|
||||
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=18.1
|
||||
cmake --build build
|
||||
|
||||
- name: Compile and run some examples
|
||||
run: |
|
||||
@@ -418,7 +446,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
build_type: [Release, Debug]
|
||||
llvm_version: [15, 16]
|
||||
llvm_version: [15, 16, 17]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Download LLVM
|
||||
@@ -523,8 +551,6 @@ jobs:
|
||||
- run: cp -r lib c3-windows-Debug
|
||||
- run: cp msvc_build_libraries.py c3-windows-Release
|
||||
- run: cp msvc_build_libraries.py c3-windows-Debug
|
||||
- run: cp install_win_reqs.bat c3-windows-Release
|
||||
- run: cp install_win_reqs.bat c3-windows-Debug
|
||||
- run: zip -r c3-windows-Release.zip c3-windows-Release
|
||||
- run: zip -r c3-windows-Debug.zip c3-windows-Debug
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ if (NOT WIN32)
|
||||
find_package(CURL)
|
||||
endif()
|
||||
if (NOT C3_LLVM_VERSION STREQUAL "auto")
|
||||
if (${C3_LLVM_VERSION} VERSION_LESS 15 OR ${C3_LLVM_VERSION} VERSION_GREATER 18)
|
||||
if (${C3_LLVM_VERSION} VERSION_LESS 15 OR ${C3_LLVM_VERSION} VERSION_GREATER 19)
|
||||
message(FATAL_ERROR "LLVM ${C3_LLVM_VERSION} is not supported!")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
17
README.md
17
README.md
@@ -35,7 +35,7 @@ whole new language.
|
||||
The following code shows [generic modules](http://www.c3-lang.org/generics/) (more examples can be found at http://www.c3-lang.org/examples/).
|
||||
|
||||
```c++
|
||||
module stack <Type>;
|
||||
module stack (<Type>);
|
||||
// Above: the parameterized type is applied to the entire module.
|
||||
|
||||
struct Stack
|
||||
@@ -319,6 +319,21 @@ You should now have a `c3c` executable.
|
||||
You can try it out by running some sample code: `./c3c compile ../resources/examples/hash.c3`
|
||||
|
||||
|
||||
#### Compiling on Void Linux
|
||||
|
||||
1. As root, ensure that all project dependencies are installed: `xbps-install git cmake llvm15 lld-devel libcurl-devel ncurses-devel zlib-devel libzstd-devel libxml2-devel`
|
||||
2. Clone the C3C repository: `git clone https://github.com/c3lang/c3c.git`
|
||||
- If you only need the latest commit, you may want to make a shallow clone instead: `git clone https://github.com/c3lang/c3c.git --depth=1`
|
||||
3. Enter the directory: `cd c3c`
|
||||
4. Create a build directory: `mkdir build`
|
||||
5. Enter the build directory: `cd build`
|
||||
6. Create the CMake build cache: `cmake ..`
|
||||
7. Build: `cmake --build .`
|
||||
|
||||
Your c3c executable should have compiled properly. You may want to test it: `./c3c compile ../resources/examples/hash.c3`
|
||||
For a sytem-wide installation, run the following as root: `cmake --install .`
|
||||
|
||||
|
||||
#### Compiling on other Linux / Unix variants
|
||||
|
||||
1. Install CMake.
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
@echo off
|
||||
|
||||
set DOWNLOAD_URL=https://aka.ms/vs/17/release
|
||||
|
||||
mkdir tmp 2> NUL
|
||||
|
||||
if not exist "tmp\vs_buildtools.exe" (
|
||||
bitsadmin /transfer /download /priority foreground %DOWNLOAD_URL%/vs_buildtools.exe %CD%\tmp\vs_buildtools.exe
|
||||
)
|
||||
|
||||
echo Preparing Build Tools, please wait...
|
||||
tmp\vs_BuildTools.exe --quiet --wait --layout tmp\ --add Microsoft.VisualStudio.Component.Windows10SDK.19041
|
||||
|
||||
echo Installing Build Tools, please wait...
|
||||
tmp\vs_BuildTools.exe --quiet --wait --noweb --add Microsoft.VisualStudio.Component.Windows10SDK.19041
|
||||
|
||||
REM rmdir tmp /s /q
|
||||
@@ -86,15 +86,29 @@ struct GrowableBitSet
|
||||
* @param initial_capacity
|
||||
* @param [&inout] allocator "The allocator to use, defaults to the heap allocator"
|
||||
**/
|
||||
fn GrowableBitSet* GrowableBitSet.init_new(&self, usz initial_capacity = 1, Allocator* allocator = mem::heap())
|
||||
fn GrowableBitSet* GrowableBitSet.new_init(&self, usz initial_capacity = 1, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
self.data.init_new(initial_capacity, allocator);
|
||||
self.data.new_init(initial_capacity, allocator);
|
||||
return self;
|
||||
}
|
||||
|
||||
fn GrowableBitSet* GrowableBitSet.init_temp(&self, usz initial_capacity = 1)
|
||||
/**
|
||||
* @param initial_capacity
|
||||
* @param [&inout] allocator "The allocator to use, defaults to the heap allocator"
|
||||
**/
|
||||
fn GrowableBitSet* GrowableBitSet.init_new(&self, usz initial_capacity = 1, Allocator* allocator = allocator::heap()) @deprecated("Replaced by new_init")
|
||||
{
|
||||
return self.init_new(initial_capacity, mem::temp()) @inline;
|
||||
return self.new_init(initial_capacity, allocator) @inline;
|
||||
}
|
||||
|
||||
fn GrowableBitSet* GrowableBitSet.temp_init(&self, usz initial_capacity = 1)
|
||||
{
|
||||
return self.new_init(initial_capacity, allocator::temp()) @inline;
|
||||
}
|
||||
|
||||
fn GrowableBitSet* GrowableBitSet.init_temp(&self, usz initial_capacity = 1) @deprecated("Replaced by temp_init")
|
||||
{
|
||||
return self.temp_init(initial_capacity);
|
||||
}
|
||||
|
||||
fn void GrowableBitSet.free(&self)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
module std::collections::enummap(<Enum, ValueType>);
|
||||
|
||||
import std::io;
|
||||
struct EnumMap (Printable)
|
||||
{
|
||||
ValueType[Enum.len] values;
|
||||
@@ -25,7 +25,7 @@ fn usz! EnumMap.to_format(&self, Formatter* formatter) @dynamic
|
||||
return n;
|
||||
}
|
||||
|
||||
fn String EnumMap.to_new_string(&self, Allocator* allocator = mem::heap()) @dynamic
|
||||
fn String EnumMap.to_new_string(&self, Allocator* allocator = allocator::heap()) @dynamic
|
||||
{
|
||||
return string::new_format("%s", *self, .allocator = allocator);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2021 Christoffer Lerno. All rights reserved.
|
||||
// Copyright (c) 2021-2024 Christoffer Lerno. All rights reserved.
|
||||
// Use of self source code is governed by the MIT license
|
||||
// a copy of which can be found in the LICENSE_STDLIB file.
|
||||
|
||||
@@ -6,8 +6,9 @@
|
||||
* @require Enum.kindof == TypeKind.ENUM : "Only enums maybe be used with an enumset"
|
||||
**/
|
||||
module std::collections::enumset(<Enum>);
|
||||
import std::io;
|
||||
|
||||
def EnumSetType = $typefrom(private::type_for_enum_elements(Enum.elements)) @private ;
|
||||
def EnumSetType = $typefrom(private::type_for_enum_elements(Enum.elements)) @private;
|
||||
|
||||
const IS_CHAR_ARRAY = Enum.elements > 128;
|
||||
distinct EnumSet (Printable) = EnumSetType;
|
||||
@@ -140,7 +141,7 @@ fn usz! EnumSet.to_format(&set, Formatter* formatter) @dynamic
|
||||
return n;
|
||||
}
|
||||
|
||||
fn String EnumSet.to_new_string(&set, Allocator* allocator = mem::heap()) @dynamic
|
||||
fn String EnumSet.to_new_string(&set, Allocator* allocator = allocator::heap()) @dynamic
|
||||
{
|
||||
return string::new_format("%s", *set, .allocator = allocator);
|
||||
}
|
||||
|
||||
467
lib/std/collections/generic_list.c3
Normal file
467
lib/std/collections/generic_list.c3
Normal file
@@ -0,0 +1,467 @@
|
||||
// Copyright (c) 2024 Christoffer Lerno. All rights reserved.
|
||||
// Use of self source code is governed by the MIT license
|
||||
// a copy of which can be found in the LICENSE_STDLIB file.
|
||||
module std::collections::generic_list;
|
||||
import std::io,std::math;
|
||||
|
||||
def GenericPredicate = fn bool(any* value);
|
||||
def GenericTest = fn bool(any* type, any* context);
|
||||
|
||||
struct GenericList (Printable)
|
||||
{
|
||||
usz size;
|
||||
usz capacity;
|
||||
Allocator* allocator;
|
||||
any** entries;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param initial_capacity "The initial capacity to reserve"
|
||||
* @param [&inout] allocator "The allocator to use, defaults to the heap allocator"
|
||||
**/
|
||||
fn GenericList* GenericList.new_init(&self, usz initial_capacity = 16, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
self.allocator = allocator;
|
||||
self.size = 0;
|
||||
if (initial_capacity > 0)
|
||||
{
|
||||
initial_capacity = math::next_power_of_2(initial_capacity);
|
||||
self.entries = allocator::alloc_array(allocator, any*, initial_capacity);
|
||||
}
|
||||
else
|
||||
{
|
||||
self.entries = null;
|
||||
}
|
||||
self.capacity = initial_capacity;
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param initial_capacity "The initial capacity to reserve"
|
||||
* @param [&inout] allocator "The allocator to use, defaults to the heap allocator"
|
||||
**/
|
||||
fn GenericList* GenericList.init_new(&self, usz initial_capacity = 16, Allocator* allocator = allocator::heap()) @deprecated("Replaced by new_init")
|
||||
{
|
||||
return self.new_init(initial_capacity, allocator) @inline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the list using the temp allocator.
|
||||
*
|
||||
* @param initial_capacity "The initial capacity to reserve"
|
||||
**/
|
||||
fn GenericList* GenericList.temp_init(&self, usz initial_capacity = 16)
|
||||
{
|
||||
return self.new_init(initial_capacity, allocator::temp()) @inline;
|
||||
}
|
||||
|
||||
fn usz! GenericList.to_format(&self, Formatter* formatter) @dynamic
|
||||
{
|
||||
switch (self.size)
|
||||
{
|
||||
case 0:
|
||||
return formatter.print("[]")!;
|
||||
case 1:
|
||||
return formatter.printf("[%s]", self.entries[0])!;
|
||||
default:
|
||||
usz n = formatter.print("[")!;
|
||||
foreach (i, element : self.entries[:self.size])
|
||||
{
|
||||
if (i != 0) formatter.print(", ")!;
|
||||
n += formatter.printf("%s", element)!;
|
||||
}
|
||||
n += formatter.print("]")!;
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
fn String GenericList.to_new_string(&self, Allocator* allocator = allocator::heap()) @dynamic
|
||||
{
|
||||
return string::new_format("%s", *self, .allocator = allocator);
|
||||
}
|
||||
|
||||
fn String GenericList.to_tstring(&self)
|
||||
{
|
||||
return string::tformat("%s", *self);
|
||||
}
|
||||
|
||||
/**
|
||||
* Push an element on the list by cloning it.
|
||||
**/
|
||||
macro void GenericList.push(&self, element)
|
||||
{
|
||||
if (!self.allocator) self.allocator = allocator::heap();
|
||||
self.append_internal(allocator::clone(self.allocator, element));
|
||||
}
|
||||
|
||||
fn void GenericList.append_internal(&self, any* element) @local
|
||||
{
|
||||
self.ensure_capacity();
|
||||
self.entries[self.size++] = element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free a retained element removed using *_retained.
|
||||
**/
|
||||
fn void GenericList.free_element(&self, any* element) @inline
|
||||
{
|
||||
allocator::free(self.allocator, element.ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pop a value who's type is known. If the type is incorrect, this
|
||||
* will still pop the element.
|
||||
*
|
||||
* @return! CastResult.TYPE_MISMATCH, IteratorResult.NO_MORE_ELEMENT
|
||||
**/
|
||||
macro GenericList.pop(&self, $Type)
|
||||
{
|
||||
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
|
||||
defer self.free_element(self.entries[self.size]);
|
||||
return *anycast(self.entries[--self.size], $Type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pop the last value and allocate the copy using the given allocator.
|
||||
* @return! IteratorResult.NO_MORE_ELEMENT
|
||||
**/
|
||||
fn any*! GenericList.new_pop(&self, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
|
||||
defer self.free_element(self.entries[self.size]);
|
||||
return allocator::clone_any(allocator, self.entries[--self.size]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pop the last value and allocate the copy using the temp allocator
|
||||
* @return! IteratorResult.NO_MORE_ELEMENT
|
||||
**/
|
||||
fn any*! GenericList.temp_pop(&self) => self.new_pop(allocator::temp());
|
||||
|
||||
/**
|
||||
* Pop the last value. It must later be released using list.free_element()
|
||||
* @return! IteratorResult.NO_MORE_ELEMENT
|
||||
**/
|
||||
fn any*! GenericList.pop_retained(&self)
|
||||
{
|
||||
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
|
||||
return self.entries[--self.size];
|
||||
}
|
||||
|
||||
fn void GenericList.clear(&self)
|
||||
{
|
||||
for (usz i = 0; i < self.size; i++)
|
||||
{
|
||||
self.free_element(self.entries[i]);
|
||||
}
|
||||
self.size = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as pop() but pops the first value instead.
|
||||
**/
|
||||
macro GenericList.pop_first(&self, $Type)
|
||||
{
|
||||
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
|
||||
defer self.remove_at(0);
|
||||
return *anycast(self.entries[0], $Type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as pop_retained() but pops the first value instead.
|
||||
**/
|
||||
fn any*! GenericList.pop_first_retained(&self)
|
||||
{
|
||||
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
|
||||
defer self.remove_at(0);
|
||||
return self.entries[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as new_pop() but pops the first value instead.
|
||||
**/
|
||||
fn any*! GenericList.new_pop_first(&self, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
|
||||
defer self.free_element(self.entries[self.size]);
|
||||
defer self.remove_at(0);
|
||||
return allocator::clone_any(allocator, self.entries[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as temp_pop() but pops the first value instead.
|
||||
**/
|
||||
fn any*! GenericList.temp_pop_first(&self) => self.new_pop_first(allocator::temp());
|
||||
|
||||
/**
|
||||
* @require index < self.size
|
||||
**/
|
||||
fn void GenericList.remove_at(&self, usz index)
|
||||
{
|
||||
if (!--self.size || index == self.size) return;
|
||||
self.free_element(self.entries[index]);
|
||||
self.entries[index .. self.size - 1] = self.entries[index + 1 .. self.size];
|
||||
}
|
||||
|
||||
fn void GenericList.add_all(&self, GenericList* other_list)
|
||||
{
|
||||
if (!other_list.size) return;
|
||||
self.reserve(other_list.size);
|
||||
foreach (value : other_list)
|
||||
{
|
||||
self.entries[self.size++] = allocator::clone_any(self.allocator, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the elements in a list.
|
||||
**/
|
||||
fn void GenericList.reverse(&self)
|
||||
{
|
||||
if (self.size < 2) return;
|
||||
usz half = self.size / 2U;
|
||||
usz end = self.size - 1;
|
||||
for (usz i = 0; i < half; i++)
|
||||
{
|
||||
self.swap(i, end - i);
|
||||
}
|
||||
}
|
||||
|
||||
fn any*[] GenericList.array_view(&self)
|
||||
{
|
||||
return self.entries[:self.size];
|
||||
}
|
||||
|
||||
/**
|
||||
* Push an element to the front of the list.
|
||||
**/
|
||||
macro void GenericList.push_front(&self, type)
|
||||
{
|
||||
self.insert_at(0, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @require index < self.size
|
||||
**/
|
||||
macro void GenericList.insert_at(&self, usz index, type) @local
|
||||
{
|
||||
any* value = allocator::copy(self.allocator, type);
|
||||
self.insert_at_internal(self, index, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @require index < self.size
|
||||
**/
|
||||
fn void GenericList.insert_at_internal(&self, usz index, any* value) @local
|
||||
{
|
||||
self.ensure_capacity();
|
||||
for (usz i = self.size; i > index; i--)
|
||||
{
|
||||
self.entries[i] = self.entries[i - 1];
|
||||
}
|
||||
self.size++;
|
||||
self.entries[index] = value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @require self.size > 0
|
||||
**/
|
||||
fn void GenericList.remove_last(&self)
|
||||
{
|
||||
self.free_element(self.entries[--self.size]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @require self.size > 0
|
||||
**/
|
||||
fn void GenericList.remove_first(&self)
|
||||
{
|
||||
self.remove_at(0);
|
||||
}
|
||||
|
||||
macro GenericList.first(&self, $Type)
|
||||
{
|
||||
return *anycast(self.first_any(), $Type);
|
||||
}
|
||||
|
||||
fn any*! GenericList.first_any(&self) @inline
|
||||
{
|
||||
return self.size ? self.entries[0] : IteratorResult.NO_MORE_ELEMENT?;
|
||||
}
|
||||
|
||||
macro GenericList.last(&self, $Type)
|
||||
{
|
||||
return *anycast(self.last_any(), $Type);
|
||||
}
|
||||
|
||||
fn any*! GenericList.last_any(&self) @inline
|
||||
{
|
||||
return self.size ? self.entries[self.size - 1] : IteratorResult.NO_MORE_ELEMENT?;
|
||||
}
|
||||
|
||||
fn bool GenericList.is_empty(&self) @inline
|
||||
{
|
||||
return !self.size;
|
||||
}
|
||||
|
||||
fn usz GenericList.len(&self) @operator(len) @inline
|
||||
{
|
||||
return self.size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require index < self.size "Index out of range"
|
||||
**/
|
||||
macro GenericList.get(&self, usz index, $Type)
|
||||
{
|
||||
return *anycast(self.entries[index], $Type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @require index < self.size "Index out of range"
|
||||
**/
|
||||
fn any* GenericList.get_any(&self, usz index) @inline
|
||||
{
|
||||
return self.entries[index];
|
||||
}
|
||||
|
||||
fn void GenericList.free(&self)
|
||||
{
|
||||
if (!self.allocator) return;
|
||||
self.clear();
|
||||
allocator::free(self.allocator, self.entries);
|
||||
self.capacity = 0;
|
||||
self.entries = null;
|
||||
}
|
||||
|
||||
fn void GenericList.swap(&self, usz i, usz j)
|
||||
{
|
||||
any* temp = self.entries[i];
|
||||
self.entries[i] = self.entries[j];
|
||||
self.entries[j] = temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param filter "The function to determine if it should be removed or not"
|
||||
* @return "the number of deleted elements"
|
||||
**/
|
||||
fn usz GenericList.remove_if(&self, GenericPredicate filter)
|
||||
{
|
||||
return self._remove_if(filter, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param selection "The function to determine if it should be kept or not"
|
||||
* @return "the number of deleted elements"
|
||||
**/
|
||||
fn usz GenericList.retain_if(&self, GenericPredicate selection)
|
||||
{
|
||||
return self._remove_if(selection, true);
|
||||
}
|
||||
|
||||
macro usz GenericList._remove_if(&self, GenericPredicate filter, bool $invert) @local
|
||||
{
|
||||
usz size = self.size;
|
||||
for (usz i = size, usz k = size; k > 0; k = i)
|
||||
{
|
||||
// Find last index of item to be deleted.
|
||||
$if $invert:
|
||||
while (i > 0 && !filter(&self.entries[i - 1])) i--;
|
||||
$else
|
||||
while (i > 0 && filter(&self.entries[i - 1])) i--;
|
||||
$endif
|
||||
// Remove the items from this index up to the one not to be deleted.
|
||||
usz n = self.size - k;
|
||||
for (usz j = i; j < k; j++) self.free_element(self.entries[j]);
|
||||
self.entries[i:n] = self.entries[k:n];
|
||||
self.size -= k - i;
|
||||
// Find last index of item not to be deleted.
|
||||
$if $invert:
|
||||
while (i > 0 && filter(&self.entries[i - 1])) i--;
|
||||
$else
|
||||
while (i > 0 && !filter(&self.entries[i - 1])) i--;
|
||||
$endif
|
||||
}
|
||||
return size - self.size;
|
||||
}
|
||||
|
||||
fn usz GenericList.remove_using_test(&self, GenericTest filter, any* context)
|
||||
{
|
||||
return self._remove_using_test(filter, false, context);
|
||||
}
|
||||
|
||||
fn usz GenericList.retain_using_test(&self, GenericTest filter, any* context)
|
||||
{
|
||||
return self._remove_using_test(filter, true, context);
|
||||
}
|
||||
|
||||
macro usz GenericList._remove_using_test(&self, GenericTest filter, bool $invert, ctx) @local
|
||||
{
|
||||
usz size = self.size;
|
||||
for (usz i = size, usz k = size; k > 0; k = i)
|
||||
{
|
||||
// Find last index of item to be deleted.
|
||||
$if $invert:
|
||||
while (i > 0 && !filter(&self.entries[i - 1], ctx)) i--;
|
||||
$else
|
||||
while (i > 0 && filter(&self.entries[i - 1], ctx)) i--;
|
||||
$endif
|
||||
// Remove the items from this index up to the one not to be deleted.
|
||||
usz n = self.size - k;
|
||||
for (usz j = i; j < k; j++) self.free_element(self.entries[j]);
|
||||
self.entries[i:n] = self.entries[k:n];
|
||||
self.size -= k - i;
|
||||
// Find last index of item not to be deleted.
|
||||
$if $invert:
|
||||
while (i > 0 && filter(&self.entries[i - 1], ctx)) i--;
|
||||
$else
|
||||
while (i > 0 && !filter(&self.entries[i - 1], ctx)) i--;
|
||||
$endif
|
||||
}
|
||||
return size - self.size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reserve at least min_capacity
|
||||
**/
|
||||
fn void GenericList.reserve(&self, usz min_capacity)
|
||||
{
|
||||
if (!min_capacity) return;
|
||||
if (self.capacity >= min_capacity) return;
|
||||
if (!self.allocator) self.allocator = allocator::heap();
|
||||
min_capacity = math::next_power_of_2(min_capacity);
|
||||
self.entries = allocator::realloc(self.allocator, self.entries, any*.sizeof * min_capacity);
|
||||
self.capacity = min_capacity;
|
||||
}
|
||||
|
||||
macro any* GenericList.@item_at(&self, usz index) @operator([])
|
||||
{
|
||||
return self.entries[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* @require index <= self.size "Index out of range"
|
||||
**/
|
||||
macro void GenericList.set(&self, usz index, value)
|
||||
{
|
||||
if (index == self.size)
|
||||
{
|
||||
self.push(value);
|
||||
return;
|
||||
}
|
||||
self.free_element(self.entries[index]);
|
||||
self.entries[index] = allocator::copy(self.allocator, value);
|
||||
}
|
||||
|
||||
fn void GenericList.ensure_capacity(&self, usz added = 1) @inline @private
|
||||
{
|
||||
usz new_size = self.size + added;
|
||||
if (self.capacity >= new_size) return;
|
||||
|
||||
assert(new_size < usz.max / 2U);
|
||||
usz new_capacity = self.capacity ? 2U * self.capacity : 16U;
|
||||
while (new_capacity < new_size) new_capacity *= 2U;
|
||||
self.reserve(new_capacity);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2021 Christoffer Lerno. All rights reserved.
|
||||
// Copyright (c) 2021-2024 Christoffer Lerno. All rights reserved.
|
||||
// Use of self source code is governed by the MIT license
|
||||
// a copy of which can be found in the LICENSE_STDLIB file.
|
||||
module std::collections::linkedlist(<Type>);
|
||||
@@ -32,15 +32,29 @@ fn void LinkedList.push_last(&self, Type value)
|
||||
* @param [&inout] allocator "The allocator to use, defaults to the heap allocator"
|
||||
* @return "the initialized list"
|
||||
**/
|
||||
fn LinkedList* LinkedList.init_new(&self, Allocator* allocator = mem::heap())
|
||||
fn LinkedList* LinkedList.new_init(&self, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
*self = { .allocator = allocator };
|
||||
return self;
|
||||
}
|
||||
|
||||
fn LinkedList* LinkedList.init_temp(&self)
|
||||
/**
|
||||
* @param [&inout] allocator "The allocator to use, defaults to the heap allocator"
|
||||
* @return "the initialized list"
|
||||
**/
|
||||
fn LinkedList* LinkedList.init_new(&self, Allocator* allocator = allocator::heap()) @deprecated("Replaced by new_init")
|
||||
{
|
||||
return self.init_new(mem::temp()) @inline;
|
||||
return self.new_init(allocator);
|
||||
}
|
||||
|
||||
fn LinkedList* LinkedList.temp_init(&self)
|
||||
{
|
||||
return self.new_init(allocator::temp()) @inline;
|
||||
}
|
||||
|
||||
fn LinkedList* LinkedList.init_temp(&self) @deprecated("Replaced by temp_init")
|
||||
{
|
||||
return self.temp_init() @inline;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -48,12 +62,13 @@ fn LinkedList* LinkedList.init_temp(&self)
|
||||
**/
|
||||
macro void LinkedList.free_node(&self, Node* node) @private
|
||||
{
|
||||
self.allocator.free(node);
|
||||
allocator::free(self.allocator, node);
|
||||
}
|
||||
|
||||
macro Node* LinkedList.alloc_node(&self) @private
|
||||
{
|
||||
if (!self.allocator) self.allocator = mem::heap();
|
||||
return self.allocator.new(Node);
|
||||
if (!self.allocator) self.allocator = allocator::heap();
|
||||
return allocator::alloc(self.allocator, Node);
|
||||
}
|
||||
|
||||
fn void LinkedList.link_first(&self, Type value) @private
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// Copyright (c) 2021 Christoffer Lerno. All rights reserved.
|
||||
// Copyright (c) 2021-2024 Christoffer Lerno. All rights reserved.
|
||||
// Use of self source code is governed by the MIT license
|
||||
// a copy of which can be found in the LICENSE_STDLIB file.
|
||||
module std::collections::list(<Type>);
|
||||
import std::io;
|
||||
import std::math;
|
||||
import std::io,std::math;
|
||||
|
||||
def ElementPredicate = fn bool(Type *type);
|
||||
def ElementTest = fn bool(Type *type, any* context);
|
||||
@@ -18,18 +17,19 @@ struct List (Printable)
|
||||
Type *entries;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param initial_capacity "The initial capacity to reserve"
|
||||
* @param [&inout] allocator "The allocator to use, defaults to the heap allocator"
|
||||
**/
|
||||
fn List* List.init_new(&self, usz initial_capacity = 16, Allocator* allocator = mem::heap())
|
||||
fn List* List.new_init(&self, usz initial_capacity = 16, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
self.allocator = allocator;
|
||||
self.size = 0;
|
||||
if (initial_capacity > 0)
|
||||
{
|
||||
initial_capacity = math::next_power_of_2(initial_capacity);
|
||||
self.entries = allocator.alloc_aligned(Type.sizeof * initial_capacity, .alignment = Type[1].alignof)!!;
|
||||
self.entries = allocator::malloc_aligned(allocator, Type.sizeof * initial_capacity, .alignment = Type[1].alignof)!!;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -39,20 +39,39 @@ fn List* List.init_new(&self, usz initial_capacity = 16, Allocator* allocator =
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param initial_capacity "The initial capacity to reserve"
|
||||
* @param [&inout] allocator "The allocator to use, defaults to the heap allocator"
|
||||
**/
|
||||
fn List* List.init_new(&self, usz initial_capacity = 16, Allocator* allocator = allocator::heap()) @deprecated("Replaced by new_init")
|
||||
{
|
||||
return self.new_init(initial_capacity, allocator) @inline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the list using the temp allocator.
|
||||
*
|
||||
* @param initial_capacity "The initial capacity to reserve"
|
||||
**/
|
||||
fn List* List.init_temp(&self, usz initial_capacity = 16)
|
||||
fn List* List.temp_init(&self, usz initial_capacity = 16)
|
||||
{
|
||||
return self.init_new(initial_capacity, mem::temp()) @inline;
|
||||
return self.new_init(initial_capacity, allocator::temp()) @inline;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the list using the temp allocator.
|
||||
*
|
||||
* @param initial_capacity "The initial capacity to reserve"
|
||||
**/
|
||||
fn List* List.init_temp(&self, usz initial_capacity = 16) @deprecated("Replaced by temp_init")
|
||||
{
|
||||
return self.temp_init(initial_capacity) @inline;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require self.size == 0 "The List must be empty"
|
||||
**/
|
||||
fn void List.init_wrapping_array(&self, Type[] types, Allocator* allocator = mem::heap())
|
||||
fn void List.init_wrapping_array(&self, Type[] types, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
self.allocator = allocator;
|
||||
self.size = types.len;
|
||||
@@ -80,7 +99,7 @@ fn usz! List.to_format(&self, Formatter* formatter) @dynamic
|
||||
}
|
||||
}
|
||||
|
||||
fn String List.to_new_string(&self, Allocator* allocator = mem::heap()) @dynamic
|
||||
fn String List.to_new_string(&self, Allocator* allocator = allocator::heap()) @dynamic
|
||||
{
|
||||
return string::new_format("%s", *self, .allocator = allocator);
|
||||
}
|
||||
@@ -129,11 +148,8 @@ fn Type List.pop_first(&self)
|
||||
**/
|
||||
fn void List.remove_at(&self, usz index)
|
||||
{
|
||||
for (usz i = index + 1; i < self.size; i++)
|
||||
{
|
||||
self.entries[i - 1] = self.entries[i];
|
||||
}
|
||||
self.size--;
|
||||
if (!--self.size || index == self.size) return;
|
||||
self.entries[index .. self.size - 1] = self.entries[index + 1 .. self.size];
|
||||
}
|
||||
|
||||
fn void List.add_all(&self, List* other_list)
|
||||
@@ -147,17 +163,17 @@ fn void List.add_all(&self, List* other_list)
|
||||
}
|
||||
|
||||
|
||||
fn Type[] List.to_new_array(&self, Allocator* allocator = mem::heap())
|
||||
fn Type[] List.to_new_array(&self, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
if (!self.size) return Type[] {};
|
||||
Type[] result = allocator.new_array(Type, self.size);
|
||||
Type[] result = allocator::alloc_array(allocator, Type, self.size);
|
||||
result[..] = self.entries[:self.size];
|
||||
return result;
|
||||
}
|
||||
|
||||
fn Type[] List.to_tarray(&self)
|
||||
{
|
||||
return self.to_new_array(mem::temp());
|
||||
return self.to_new_array(allocator::temp());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -247,6 +263,11 @@ fn bool List.is_empty(&self) @inline
|
||||
return !self.size;
|
||||
}
|
||||
|
||||
fn usz List.byte_size(&self) @inline
|
||||
{
|
||||
return Type.sizeof * self.size;
|
||||
}
|
||||
|
||||
fn usz List.len(&self) @operator(len) @inline
|
||||
{
|
||||
return self.size;
|
||||
@@ -260,7 +281,7 @@ fn Type List.get(&self, usz index) @inline
|
||||
fn void List.free(&self)
|
||||
{
|
||||
if (!self.allocator) return;
|
||||
self.allocator.free_aligned(self.entries);
|
||||
allocator::free_aligned(self.allocator, self.entries);
|
||||
self.capacity = 0;
|
||||
self.size = 0;
|
||||
self.entries = null;
|
||||
@@ -356,9 +377,9 @@ fn void List.reserve(&self, usz min_capacity)
|
||||
{
|
||||
if (!min_capacity) return;
|
||||
if (self.capacity >= min_capacity) return;
|
||||
if (!self.allocator) self.allocator = mem::heap();
|
||||
if (!self.allocator) self.allocator = allocator::heap();
|
||||
min_capacity = math::next_power_of_2(min_capacity);
|
||||
self.entries = self.allocator.realloc_aligned(self.entries, Type.sizeof * min_capacity, .alignment = Type[1].alignof) ?? null;
|
||||
self.entries = allocator::realloc_aligned(self.allocator, self.entries, Type.sizeof * min_capacity, .alignment = Type[1].alignof) ?? null;
|
||||
self.capacity = min_capacity;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,23 @@ struct HashMap
|
||||
float load_factor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [&inout] allocator "The allocator to use"
|
||||
* @require capacity > 0 "The capacity must be 1 or higher"
|
||||
* @require load_factor > 0.0 "The load factor must be higher than 0"
|
||||
* @require !self.allocator "Map was already initialized"
|
||||
* @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
|
||||
**/
|
||||
fn HashMap* HashMap.new_init(&self, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
capacity = math::next_power_of_2(capacity);
|
||||
self.allocator = allocator;
|
||||
self.load_factor = load_factor;
|
||||
self.threshold = (uint)(capacity * load_factor);
|
||||
self.table = allocator::new_array(allocator, Entry*, capacity);
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [&inout] allocator "The allocator to use"
|
||||
* @require capacity > 0 "The capacity must be 1 or higher"
|
||||
@@ -26,14 +43,20 @@ struct HashMap
|
||||
* @require !map.allocator "Map was already initialized"
|
||||
* @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
|
||||
**/
|
||||
fn HashMap* HashMap.init_new(&map, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator* allocator = mem::heap())
|
||||
fn HashMap* HashMap.init_new(&map, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR, Allocator* allocator = allocator::heap()) @deprecated("Replaced by new_init")
|
||||
{
|
||||
capacity = math::next_power_of_2(capacity);
|
||||
map.allocator = allocator;
|
||||
map.load_factor = load_factor;
|
||||
map.threshold = (uint)(capacity * load_factor);
|
||||
map.table = allocator.new_zero_array(Entry*, capacity);
|
||||
return map;
|
||||
return map.new_init(capacity, load_factor, allocator);
|
||||
}
|
||||
|
||||
/**
|
||||
* @require capacity > 0 "The capacity must be 1 or higher"
|
||||
* @require load_factor > 0.0 "The load factor must be higher than 0"
|
||||
* @require !self.allocator "Map was already initialized"
|
||||
* @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
|
||||
**/
|
||||
fn HashMap* HashMap.temp_init(&self, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR)
|
||||
{
|
||||
return self.new_init(capacity, load_factor, allocator::temp()) @inline;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -42,9 +65,9 @@ fn HashMap* HashMap.init_new(&map, uint capacity = DEFAULT_INITIAL_CAPACITY, flo
|
||||
* @require !map.allocator "Map was already initialized"
|
||||
* @require capacity < MAXIMUM_CAPACITY "Capacity cannot exceed maximum"
|
||||
**/
|
||||
fn HashMap* HashMap.init_temp(&map, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR)
|
||||
fn HashMap* HashMap.init_temp(&map, uint capacity = DEFAULT_INITIAL_CAPACITY, float load_factor = DEFAULT_LOAD_FACTOR) @deprecated("Replaced by temp_init")
|
||||
{
|
||||
return map.init_new(capacity, load_factor, mem::temp());
|
||||
return map.temp_init(capacity, load_factor) @inline;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,21 +85,40 @@ fn bool HashMap.is_initialized(&map)
|
||||
* @param [&inout] allocator "The allocator to use"
|
||||
* @param [&in] other_map "The map to copy from."
|
||||
**/
|
||||
fn HashMap* HashMap.init_new_from_map(&self, HashMap* other_map, Allocator* allocator = mem::heap())
|
||||
fn HashMap* HashMap.new_init_from_map(&self, HashMap* other_map, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
self.init_new(other_map.table.len, other_map.load_factor, allocator);
|
||||
self.new_init(other_map.table.len, other_map.load_factor, allocator);
|
||||
self.put_all_for_create(other_map);
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [&inout] allocator "The allocator to use"
|
||||
* @param [&in] other_map "The map to copy from."
|
||||
**/
|
||||
fn HashMap* HashMap.init_temp_from_map(&map, HashMap* other_map)
|
||||
fn HashMap* HashMap.init_new_from_map(&self, HashMap* other_map, Allocator* allocator = allocator::heap()) @deprecated("Replaced by new_init_from_map")
|
||||
|
||||
{
|
||||
return map.init_new_from_map(other_map, mem::temp()) @inline;
|
||||
return self.new_init_from_map(other_map, allocator) @inline;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [&in] other_map "The map to copy from."
|
||||
**/
|
||||
fn HashMap* HashMap.temp_init_from_map(&map, HashMap* other_map)
|
||||
{
|
||||
return map.new_init_from_map(other_map, allocator::temp()) @inline;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [&in] other_map "The map to copy from."
|
||||
**/
|
||||
fn HashMap* HashMap.init_temp_from_map(&map, HashMap* other_map) @deprecated("Replaced by temp_init_from_map")
|
||||
{
|
||||
return map.temp_init_from_map(other_map) @inline;
|
||||
}
|
||||
|
||||
|
||||
fn bool HashMap.is_empty(&map) @inline
|
||||
{
|
||||
return !map.count;
|
||||
@@ -111,6 +153,7 @@ fn Entry*! HashMap.get_entry(&map, Key key)
|
||||
|
||||
/**
|
||||
* Get the value or update and
|
||||
* @require $assignable(#expr, Value)
|
||||
**/
|
||||
macro Value HashMap.@get_or_set(&map, Key key, Value #expr)
|
||||
{
|
||||
@@ -146,7 +189,7 @@ fn bool HashMap.set(&map, Key key, Value value) @operator([]=)
|
||||
// If the map isn't initialized, use the defaults to initialize it.
|
||||
if (!map.allocator)
|
||||
{
|
||||
map.init_new();
|
||||
map.new_init();
|
||||
}
|
||||
uint hash = rehash(key.hash());
|
||||
uint index = index_for(hash, map.table.len);
|
||||
@@ -197,14 +240,14 @@ fn void HashMap.free(&map)
|
||||
|
||||
fn Key[] HashMap.key_tlist(&map)
|
||||
{
|
||||
return map.key_new_list(mem::temp()) @inline;
|
||||
return map.key_new_list(allocator::temp()) @inline;
|
||||
}
|
||||
|
||||
fn Key[] HashMap.key_new_list(&map, Allocator* allocator = mem::heap())
|
||||
fn Key[] HashMap.key_new_list(&map, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
if (!map.count) return {};
|
||||
|
||||
Key[] list = allocator.new_array(Key, map.count);
|
||||
Key[] list = allocator::alloc_array(allocator, Key, map.count);
|
||||
usz index = 0;
|
||||
foreach (Entry* entry : map.table)
|
||||
{
|
||||
@@ -241,13 +284,13 @@ macro HashMap.@each_entry(map; @body(entry))
|
||||
|
||||
fn Value[] HashMap.value_tlist(&map)
|
||||
{
|
||||
return map.value_new_list(mem::temp()) @inline;
|
||||
return map.value_new_list(allocator::temp()) @inline;
|
||||
}
|
||||
|
||||
fn Value[] HashMap.value_new_list(&map, Allocator* allocator = mem::heap())
|
||||
fn Value[] HashMap.value_new_list(&map, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
if (!map.count) return {};
|
||||
Value[] list = allocator.new_array(Value, map.count);
|
||||
Value[] list = allocator::alloc_array(allocator, Value, map.count);
|
||||
usz index = 0;
|
||||
foreach (Entry* entry : map.table)
|
||||
{
|
||||
@@ -278,11 +321,10 @@ fn bool HashMap.has_value(&map, Value v) @if(VALUE_IS_EQUATABLE)
|
||||
|
||||
fn void HashMap.add_entry(&map, uint hash, Key key, Value value, uint bucket_index) @private
|
||||
{
|
||||
Entry* entry = map.allocator.new(Entry);
|
||||
$if COPY_KEYS:
|
||||
key = key.copy(map.allocator);
|
||||
$endif
|
||||
*entry = { .hash = hash, .key = key, .value = value, .next = map.table[bucket_index] };
|
||||
Entry* entry = allocator::new(map.allocator, Entry, { .hash = hash, .key = key, .value = value, .next = map.table[bucket_index] });
|
||||
map.table[bucket_index] = entry;
|
||||
if (map.count++ >= map.threshold)
|
||||
{
|
||||
@@ -299,7 +341,7 @@ fn void HashMap.resize(&map, uint new_capacity) @private
|
||||
map.threshold = uint.max;
|
||||
return;
|
||||
}
|
||||
Entry*[] new_table = map.allocator.new_zero_array(Entry*, new_capacity);
|
||||
Entry*[] new_table = allocator::new_array(map.allocator, Entry*, new_capacity);
|
||||
map.transfer(new_table);
|
||||
map.table = new_table;
|
||||
map.free_internal(old_table.ptr);
|
||||
@@ -363,7 +405,7 @@ fn void HashMap.put_for_create(&map, Key key, Value value) @private
|
||||
|
||||
fn void HashMap.free_internal(&map, void* ptr) @inline @private
|
||||
{
|
||||
map.allocator.free(ptr);
|
||||
allocator::free(map.allocator, ptr);
|
||||
}
|
||||
|
||||
fn bool HashMap.remove_entry_for_key(&map, Key key) @private
|
||||
@@ -398,11 +440,10 @@ fn bool HashMap.remove_entry_for_key(&map, Key key) @private
|
||||
fn void HashMap.create_entry(&map, uint hash, Key key, Value value, int bucket_index) @private
|
||||
{
|
||||
Entry *e = map.table[bucket_index];
|
||||
Entry* entry = map.allocator.new(Entry);
|
||||
$if COPY_KEYS:
|
||||
key = key.copy(map.allocator);
|
||||
$endif
|
||||
*entry = { .hash = hash, .key = key, .value = value, .next = map.table[bucket_index] };
|
||||
Entry* entry = allocator::new(map.allocator, Entry, { .hash = hash, .key = key, .value = value, .next = map.table[bucket_index] });
|
||||
map.table[bucket_index] = entry;
|
||||
map.count++;
|
||||
}
|
||||
@@ -410,7 +451,7 @@ fn void HashMap.create_entry(&map, uint hash, Key key, Value value, int bucket_i
|
||||
fn void HashMap.free_entry(&self, Entry *entry) @local
|
||||
{
|
||||
$if COPY_KEYS:
|
||||
self.allocator.free(entry.key);
|
||||
allocator::free(self.allocator, entry.key);
|
||||
$endif
|
||||
self.free_internal(entry);
|
||||
}
|
||||
|
||||
@@ -2,9 +2,7 @@
|
||||
// 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::collections::object;
|
||||
import std::collections::map;
|
||||
import std::collections::list;
|
||||
import std::io;
|
||||
import std::collections::map, std::collections::list, std::io;
|
||||
|
||||
const Object TRUE_OBJECT = { .b = true, .type = bool.typeid };
|
||||
const Object FALSE_OBJECT = { .b = false, .type = bool.typeid };
|
||||
@@ -80,9 +78,7 @@ fn usz! Object.to_format(&self, Formatter* formatter) @dynamic
|
||||
|
||||
fn Object* new_obj(Allocator* allocator)
|
||||
{
|
||||
Object* o = allocator.new(Object);
|
||||
*o = { .allocator = allocator, .type = void.typeid };
|
||||
return o;
|
||||
return allocator::new(allocator, Object, { .allocator = allocator, .type = void.typeid });
|
||||
}
|
||||
|
||||
fn Object* new_null()
|
||||
@@ -92,30 +88,22 @@ fn Object* new_null()
|
||||
|
||||
fn Object* new_int(int128 i, Allocator* allocator)
|
||||
{
|
||||
Object* o = allocator.new(Object);
|
||||
*o = { .i = i, .allocator = allocator, .type = int128.typeid };
|
||||
return o;
|
||||
return allocator::new(allocator, Object, { .i = i, .allocator = allocator, .type = int128.typeid });
|
||||
}
|
||||
|
||||
macro Object* new_enum(e, Allocator* allocator)
|
||||
{
|
||||
Object* o = allocator.new(Object);
|
||||
*o = { .i = (int128)e, .allocator = allocator, .type = @typeid(e) };
|
||||
return o;
|
||||
return allocator::new(allocator, Object, { .i = (int128)e, .allocator = allocator, .type = @typeid(e) });
|
||||
}
|
||||
|
||||
fn Object* new_float(double f, Allocator* allocator)
|
||||
{
|
||||
Object* o = allocator.new(Object);
|
||||
*o = { .f = f, .allocator = allocator, .type = double.typeid };
|
||||
return o;
|
||||
return allocator::new(allocator, Object, { .f = f, .allocator = allocator, .type = double.typeid });
|
||||
}
|
||||
|
||||
fn Object* new_string(String s, Allocator* allocator)
|
||||
{
|
||||
Object* o = allocator.new(Object);
|
||||
*o = { .s = s.copy(allocator), .allocator = allocator, .type = String.typeid };
|
||||
return o;
|
||||
return allocator::new(allocator, Object, { .s = s.copy(allocator), .allocator = allocator, .type = String.typeid });
|
||||
}
|
||||
|
||||
|
||||
@@ -131,7 +119,7 @@ fn void Object.free(&self)
|
||||
case void:
|
||||
break;
|
||||
case String:
|
||||
self.allocator.free(self.s);
|
||||
allocator::free(self.allocator, self.s);
|
||||
case ObjectInternalList:
|
||||
foreach (ol : self.array)
|
||||
{
|
||||
@@ -140,13 +128,13 @@ fn void Object.free(&self)
|
||||
self.array.free();
|
||||
case ObjectInternalMap:
|
||||
self.map.@each_entry(; ObjectInternalMapEntry* entry) {
|
||||
self.allocator.free(entry.key);
|
||||
allocator::free(self.allocator, entry.key);
|
||||
entry.value.free();
|
||||
};
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (self.allocator) self.allocator.free(self);
|
||||
if (self.allocator) allocator::free(self.allocator, self);
|
||||
}
|
||||
|
||||
fn bool Object.is_null(&self) @inline => self == &NULL_OBJECT;
|
||||
@@ -168,7 +156,7 @@ fn void Object.init_map_if_needed(&self) @private
|
||||
if (self.is_empty())
|
||||
{
|
||||
self.type = ObjectInternalMap.typeid;
|
||||
self.map.init_new(.allocator = self.allocator);
|
||||
self.map.new_init(.allocator = self.allocator);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,7 +168,7 @@ fn void Object.init_array_if_needed(&self) @private
|
||||
if (self.is_empty())
|
||||
{
|
||||
self.type = ObjectInternalList.typeid;
|
||||
self.array.init_new(.allocator = self.allocator);
|
||||
self.array.new_init(.allocator = self.allocator);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,7 +181,7 @@ fn void Object.set_object(&self, String key, Object* new_object) @private
|
||||
ObjectInternalMapEntry*! entry = self.map.get_entry(key);
|
||||
defer
|
||||
{
|
||||
(void)self.allocator.free(entry.key);
|
||||
(void)allocator::free(self.allocator, entry.key);
|
||||
(void)entry.value.free();
|
||||
}
|
||||
self.map.set(key.copy(self.map.allocator), new_object);
|
||||
|
||||
@@ -27,7 +27,7 @@ distinct PriorityQueue = inline PrivatePriorityQueue(<Type, false>);
|
||||
distinct PriorityQueueMax = inline PrivatePriorityQueue(<Type, true>);
|
||||
|
||||
module std::collections::priorityqueue::private(<Type, MAX>);
|
||||
import std::collections::list;
|
||||
import std::collections::list, std::io;
|
||||
|
||||
def Heap = List(<Type>);
|
||||
|
||||
@@ -36,14 +36,24 @@ struct PrivatePriorityQueue (Printable)
|
||||
Heap heap;
|
||||
}
|
||||
|
||||
fn void PrivatePriorityQueue.init_new(&self, usz initial_capacity = 16, Allocator* allocator = mem::heap()) @inline
|
||||
fn void PrivatePriorityQueue.init_new(&self, usz initial_capacity = 16, Allocator* allocator = allocator::heap()) @inline @deprecated("Replaced by new_init")
|
||||
{
|
||||
self.heap.init_new(initial_capacity, allocator);
|
||||
return self.new_init(initial_capacity, allocator);
|
||||
}
|
||||
|
||||
fn void PrivatePriorityQueue.init_temp(&self, usz initial_capacity = 16) @inline
|
||||
fn void PrivatePriorityQueue.new_init(&self, usz initial_capacity = 16, Allocator* allocator = allocator::heap()) @inline
|
||||
{
|
||||
self.heap.init_new(initial_capacity, mem::temp()) @inline;
|
||||
self.heap.new_init(initial_capacity, allocator);
|
||||
}
|
||||
|
||||
fn void PrivatePriorityQueue.temp_init(&self, usz initial_capacity = 16) @inline
|
||||
{
|
||||
self.heap.new_init(initial_capacity, allocator::temp()) @inline;
|
||||
}
|
||||
|
||||
fn void PrivatePriorityQueue.init_temp(&self, usz initial_capacity = 16) @inline @deprecated("Replaced by temp_init")
|
||||
{
|
||||
return self.temp_init(initial_capacity) @inline;
|
||||
}
|
||||
|
||||
fn void PrivatePriorityQueue.push(&self, Type element)
|
||||
@@ -74,29 +84,32 @@ fn Type! PrivatePriorityQueue.pop(&self)
|
||||
usz i = 0;
|
||||
usz len = self.heap.len();
|
||||
if (!len) return IteratorResult.NO_MORE_ELEMENT?;
|
||||
usz newCount = len - 1;
|
||||
self.heap.swap(0, newCount);
|
||||
while ((2 * i + 1) < newCount)
|
||||
usz new_count = len - 1;
|
||||
self.heap.swap(0, new_count);
|
||||
while OUTER: ((2 * i + 1) < new_count)
|
||||
{
|
||||
usz j = 2 * i + 1;
|
||||
Type itemj = self.heap[j];
|
||||
if ((j + 1) < newCount)
|
||||
{
|
||||
Type nextj = self.heap[j + 1];
|
||||
$if MAX:
|
||||
bool ok = greater(nextj, itemj);
|
||||
$else
|
||||
bool ok = less(nextj, itemj);
|
||||
$endif
|
||||
if (ok) j++;
|
||||
}
|
||||
Type left = self.heap[j];
|
||||
Type item = self.heap[i];
|
||||
$if MAX:
|
||||
bool ok = less(item, itemj);
|
||||
$else
|
||||
bool ok = greater(item, itemj);
|
||||
$endif
|
||||
if (!ok) break;
|
||||
switch
|
||||
{
|
||||
case j + 1 < new_count:
|
||||
Type right = self.heap[j + 1];
|
||||
$if MAX:
|
||||
if (!greater(right, left)) nextcase;
|
||||
if (!greater(right, item)) break OUTER;
|
||||
$else
|
||||
if (!greater(left, right)) nextcase;
|
||||
if (!greater(item, right)) break OUTER;
|
||||
$endif
|
||||
j++;
|
||||
default:
|
||||
$if MAX:
|
||||
if (!greater(left, item)) break OUTER;
|
||||
$else
|
||||
if (!greater(item, left)) break OUTER;
|
||||
$endif
|
||||
}
|
||||
self.heap.swap(i, j);
|
||||
i = j;
|
||||
}
|
||||
@@ -138,7 +151,7 @@ fn usz! PrivatePriorityQueue.to_format(&self, Formatter* formatter) @dynamic
|
||||
return self.heap.to_format(formatter);
|
||||
}
|
||||
|
||||
fn String PrivatePriorityQueue.to_new_string(&self, Allocator* allocator = mem::heap()) @dynamic
|
||||
fn String PrivatePriorityQueue.to_new_string(&self, Allocator* allocator = allocator::heap()) @dynamic
|
||||
{
|
||||
return self.heap.to_new_string(allocator);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
* @require Type.is_ordered : "The type must be ordered"
|
||||
**/
|
||||
module std::collections::range(<Type>);
|
||||
import std::io;
|
||||
|
||||
struct Range (Printable)
|
||||
{
|
||||
@@ -28,14 +29,14 @@ fn Type Range.get(&self, usz index) @operator([])
|
||||
return (Type)(self.start + (usz)index);
|
||||
}
|
||||
|
||||
fn String Range.to_new_string(&self, Allocator* allocator = mem::heap()) @dynamic
|
||||
fn String Range.to_new_string(&self, Allocator* allocator = allocator::heap()) @dynamic
|
||||
{
|
||||
return string::new_format("[%s..%s]", self.start, self.end, .allocator = allocator);
|
||||
}
|
||||
|
||||
fn String Range.to_tstring(&self)
|
||||
{
|
||||
return self.to_new_string(mem::temp());
|
||||
return self.to_new_string(allocator::temp());
|
||||
}
|
||||
|
||||
fn usz! Range.to_format(&self, Formatter* formatter) @dynamic
|
||||
@@ -65,14 +66,14 @@ fn usz! ExclusiveRange.to_format(&self, Formatter* formatter) @dynamic
|
||||
return formatter.printf("[%s..<%s]", self.start, self.end)!;
|
||||
}
|
||||
|
||||
fn String ExclusiveRange.to_new_string(&self, Allocator* allocator = mem::heap()) @dynamic
|
||||
fn String ExclusiveRange.to_new_string(&self, Allocator* allocator = allocator::heap()) @dynamic
|
||||
{
|
||||
return string::new_format("[%s..<%s]", self.start, self.end, .allocator = allocator);
|
||||
}
|
||||
|
||||
fn String ExclusiveRange.to_tstring(&self)
|
||||
{
|
||||
return self.to_new_string(mem::temp());
|
||||
return self.to_new_string(allocator::temp());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// 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::allocator;
|
||||
import std::math;
|
||||
|
||||
struct ArenaAllocator (Allocator)
|
||||
{
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
// Copyright (c) 2021 Christoffer Lerno. All rights reserved.
|
||||
// Copyright (c) 2021-2024 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::allocator;
|
||||
import std::math;
|
||||
|
||||
struct DynamicArenaAllocator (Allocator)
|
||||
{
|
||||
@@ -29,14 +30,14 @@ fn void DynamicArenaAllocator.free(&self)
|
||||
while (page)
|
||||
{
|
||||
DynamicArenaPage* next_page = page.prev_arena;
|
||||
self.backing_allocator.free(page);
|
||||
allocator::free(self.backing_allocator, page);
|
||||
page = next_page;
|
||||
}
|
||||
page = self.unused_page;
|
||||
while (page)
|
||||
{
|
||||
DynamicArenaPage* next_page = page.prev_arena;
|
||||
self.backing_allocator.free(page);
|
||||
allocator::free(self.backing_allocator, page);
|
||||
page = next_page;
|
||||
}
|
||||
self.page = null;
|
||||
@@ -140,11 +141,11 @@ fn void*! DynamicArenaAllocator._alloc_new(&self, usz size, usz alignment, usz o
|
||||
usz page_size = max(self.page_size, mem::aligned_offset(size + DynamicArenaChunk.sizeof + offset, alignment) - offset);
|
||||
|
||||
// Grab the page without alignment (we do it ourselves)
|
||||
void* mem = self.backing_allocator.alloc_checked(page_size)!;
|
||||
DynamicArenaPage*! page = self.backing_allocator.new(DynamicArenaPage);
|
||||
void* mem = allocator::malloc_try(self.backing_allocator, page_size)!;
|
||||
DynamicArenaPage*! page = allocator::new_try(self.backing_allocator, DynamicArenaPage);
|
||||
if (catch err = page)
|
||||
{
|
||||
self.backing_allocator.free(mem);
|
||||
allocator::free(self.backing_allocator, mem);
|
||||
return err?;
|
||||
}
|
||||
page.memory = mem;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// Copyright (c) 2021-2023 Christoffer Lerno. All rights reserved.
|
||||
// Copyright (c) 2021-2024 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::allocator;
|
||||
|
||||
import std::math;
|
||||
|
||||
struct SimpleHeapAllocator (Allocator)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2021 Christoffer Lerno. All rights reserved.
|
||||
// Copyright (c) 2021-2024 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.
|
||||
|
||||
|
||||
@@ -34,15 +34,15 @@ fn void OnStackAllocator.free(&self)
|
||||
{
|
||||
if (chunk.is_aligned)
|
||||
{
|
||||
self.backing_allocator.free_aligned(chunk.data);
|
||||
allocator::free_aligned(self.backing_allocator, chunk.data);
|
||||
}
|
||||
else
|
||||
{
|
||||
self.backing_allocator.free(chunk.data);
|
||||
allocator::free(self.backing_allocator, chunk.data);
|
||||
}
|
||||
void* old = chunk;
|
||||
chunk = chunk.prev;
|
||||
self.backing_allocator.free(old);
|
||||
allocator::free(self.backing_allocator, old);
|
||||
}
|
||||
self.chunk = null;
|
||||
self.used = 0;
|
||||
@@ -76,7 +76,7 @@ fn void on_stack_allocator_remove_chunk(OnStackAllocator* a, void* ptr) @local
|
||||
if (chunk.data == ptr)
|
||||
{
|
||||
*addr = chunk.prev;
|
||||
a.backing_allocator.free(chunk);
|
||||
allocator::free(a.backing_allocator, chunk);
|
||||
return;
|
||||
}
|
||||
addr = &chunk.prev;
|
||||
@@ -140,8 +140,8 @@ fn void*! OnStackAllocator.acquire(&self, usz size, bool clear, usz alignment, u
|
||||
|
||||
if (end > total_len)
|
||||
{
|
||||
OnStackAllocatorExtraChunk* chunk = backing_allocator.alloc_checked(OnStackAllocatorExtraChunk.sizeof)!;
|
||||
defer catch backing_allocator.free(chunk);
|
||||
OnStackAllocatorExtraChunk* chunk = allocator::alloc_try(backing_allocator, OnStackAllocatorExtraChunk)!;
|
||||
defer catch allocator::free(backing_allocator, chunk);
|
||||
defer try self.chunk = chunk;
|
||||
*chunk = { .prev = self.chunk, .is_aligned = aligned };
|
||||
return chunk.data = backing_allocator.acquire(size, clear, aligned ? alignment : 0, offset)!;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
module std::core::mem::allocator;
|
||||
import std::io;
|
||||
import std::io, std::math;
|
||||
|
||||
struct TempAllocatorChunk @local
|
||||
{
|
||||
@@ -35,9 +35,9 @@ macro bool TempAllocatorPage.is_aligned(&self) => self.size & PAGE_IS_ALIGNED ==
|
||||
/**
|
||||
* @require size >= 16
|
||||
**/
|
||||
fn TempAllocator*! new_temp(usz size, Allocator* allocator)
|
||||
fn TempAllocator*! new_temp_allocator(usz size, Allocator* allocator)
|
||||
{
|
||||
TempAllocator* temp = allocator.alloc_checked(TempAllocator.sizeof + size)!;
|
||||
TempAllocator* temp = allocator::alloc_with_padding(allocator, TempAllocator, size)!;
|
||||
temp.last_page = null;
|
||||
temp.backing_allocator = allocator;
|
||||
temp.used = 0;
|
||||
@@ -45,6 +45,11 @@ fn TempAllocator*! new_temp(usz size, Allocator* allocator)
|
||||
return temp;
|
||||
}
|
||||
|
||||
fn TempAllocator*! new_temp(usz size, Allocator* allocator) @deprecated("Use new_temp_allocator")
|
||||
{
|
||||
return new_temp_allocator(size, allocator);
|
||||
}
|
||||
|
||||
fn usz TempAllocator.mark(&self) @dynamic => self.used;
|
||||
|
||||
fn void TempAllocator.release(&self, void* old_pointer, bool) @dynamic
|
||||
@@ -71,8 +76,7 @@ fn void TempAllocator.reset(&self, usz mark) @dynamic
|
||||
fn void! TempAllocator._free_page(&self, TempAllocatorPage* page) @inline @local
|
||||
{
|
||||
void* mem = page.start;
|
||||
if (page.is_aligned()) return self.backing_allocator.free_aligned(mem);
|
||||
return self.backing_allocator.free(mem);
|
||||
return self.backing_allocator.release(mem, page.is_aligned());
|
||||
}
|
||||
|
||||
fn void*! TempAllocator._realloc_page(&self, TempAllocatorPage* page, usz size, usz alignment, usz offset) @inline @local
|
||||
@@ -92,14 +96,7 @@ fn void*! TempAllocator._realloc_page(&self, TempAllocatorPage* page, usz size,
|
||||
// Clear on size > original size.
|
||||
void* data = self.acquire(size, size > page_size, alignment, offset)!;
|
||||
mem::copy(data, &page.data[0], page_size, mem::DEFAULT_MEM_ALIGNMENT, mem::DEFAULT_MEM_ALIGNMENT);
|
||||
if (page.is_aligned())
|
||||
{
|
||||
self.backing_allocator.free_aligned(real_pointer);
|
||||
}
|
||||
else
|
||||
{
|
||||
self.backing_allocator.free(real_pointer);
|
||||
}
|
||||
self.backing_allocator.release(real_pointer, page.is_aligned());
|
||||
return data;
|
||||
}
|
||||
|
||||
@@ -168,11 +165,11 @@ fn void*! TempAllocator.acquire(&self, usz size, bool clear, usz alignment, usz
|
||||
usz total_alloc_size = TempAllocatorPage.sizeof + size;
|
||||
if (clear)
|
||||
{
|
||||
page = self.backing_allocator.calloc_aligned(total_alloc_size, alignment, TempAllocatorPage.sizeof + offset)!;
|
||||
page = allocator::calloc_aligned(self.backing_allocator, total_alloc_size, alignment, TempAllocatorPage.sizeof + offset)!;
|
||||
}
|
||||
else
|
||||
{
|
||||
page = self.backing_allocator.alloc_aligned(total_alloc_size, alignment, TempAllocatorPage.sizeof + offset)!;
|
||||
page = allocator::malloc_aligned(self.backing_allocator, total_alloc_size, alignment, TempAllocatorPage.sizeof + offset)!;
|
||||
}
|
||||
page.start = page;
|
||||
page.size = size | PAGE_IS_ALIGNED;
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
// Copyright (c) 2021 Christoffer Lerno. All rights reserved.
|
||||
// Copyright (c) 2021-2024 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::allocator;
|
||||
import std::collections::map;
|
||||
import std::collections::list;
|
||||
import std::collections, std::io, std::os::backtrace;
|
||||
|
||||
const MAX_BACKTRACE = 16;
|
||||
struct Allocation
|
||||
@@ -35,7 +34,7 @@ struct TrackingAllocator (Allocator)
|
||||
fn void TrackingAllocator.init(&self, Allocator* allocator)
|
||||
{
|
||||
*self = { .inner_allocator = allocator };
|
||||
self.map.init_new(.allocator = allocator);
|
||||
self.map.new_init(.allocator = allocator);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -168,7 +167,7 @@ fn void! TrackingAllocator.fprint_report(&self, OutStream* out)
|
||||
Backtrace trace = backtrace::BACKTRACE_UNKNOWN;
|
||||
if (allocation.backtrace[3])
|
||||
{
|
||||
trace = backtrace::symbolize_backtrace(allocation.backtrace[3:1], mem::temp()).get(0) ?? backtrace::BACKTRACE_UNKNOWN;
|
||||
trace = backtrace::symbolize_backtrace(allocation.backtrace[3:1], allocator::temp()).get(0) ?? backtrace::BACKTRACE_UNKNOWN;
|
||||
}
|
||||
if (trace.function.len) leaks = true;
|
||||
io::fprintfn(out, "%13s %p %s:%d", allocation.size,
|
||||
@@ -207,7 +206,7 @@ fn void! TrackingAllocator.fprint_report(&self, OutStream* out)
|
||||
break;
|
||||
}
|
||||
}
|
||||
BacktraceList list = backtrace::symbolize_backtrace(allocation.backtrace[3..(end - 1)], mem::temp())!;
|
||||
BacktraceList list = backtrace::symbolize_backtrace(allocation.backtrace[3..(end - 1)], allocator::temp())!;
|
||||
io::fprintfn(out, "Allocation %d (%d bytes): ", i + 1, allocation.size)!;
|
||||
foreach (trace : list)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
module std::core::array;
|
||||
import std::core::array::slice;
|
||||
|
||||
/**
|
||||
* @param [in] array
|
||||
@@ -15,6 +16,19 @@ macro index_of(array, element)
|
||||
return SearchResult.MISSING?;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require @typekind(array) == VECTOR || @typekind(array) == ARRAY
|
||||
* @require @typekind(array[0]) == VECTOR || @typekind(array[0]) == ARRAY
|
||||
**/
|
||||
macro slice2d(array, x = 0, xlen = 0, y = 0, ylen = 0)
|
||||
{
|
||||
if (xlen < 1) xlen = $typeof(array[0]).len + xlen;
|
||||
if (ylen < 1) ylen = $typeof(array).len + ylen;
|
||||
var $ElementType = $typeof(array[0][0]);
|
||||
return Slice2d(<$ElementType>) { ($ElementType*)&array, $typeof(array[0]).len, y, ylen, x, xlen };
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param [in] array
|
||||
* @param [in] element
|
||||
@@ -41,10 +55,10 @@ macro rindex_of(array, element)
|
||||
* @require @typeis(arr1[0], $typeof(arr2[0])) "Arrays must have the same type"
|
||||
* @ensure result.len == arr1.len + arr2.len
|
||||
**/
|
||||
macro concat_new(arr1, arr2, Allocator* allocator = mem::heap())
|
||||
macro concat_new(arr1, arr2, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
var $Type = $typeof(arr1[0]);
|
||||
$Type[] result = allocator.new_array($Type, arr1.len + arr2.len);
|
||||
$Type[] result = allocator::alloc_array(allocator, $Type, arr1.len + arr2.len);
|
||||
if (arr1.len > 0)
|
||||
{
|
||||
mem::copy(result.ptr, &arr1[0], arr1.len * $Type.sizeof, $Type.alignof, $Type.alignof);
|
||||
@@ -67,4 +81,67 @@ macro concat_new(arr1, arr2, Allocator* allocator = mem::heap())
|
||||
* @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 tconcat(arr1, arr2) => concat(arr1, arr2, allocator::temp());
|
||||
|
||||
module std::core::array::slice(<Type>);
|
||||
|
||||
struct Slice2d
|
||||
{
|
||||
Type* ptr;
|
||||
usz inner_len;
|
||||
usz ystart;
|
||||
usz ylen;
|
||||
usz xstart;
|
||||
usz xlen;
|
||||
}
|
||||
|
||||
fn usz Slice2d.len(&self) @operator(len)
|
||||
{
|
||||
return self.ylen;
|
||||
}
|
||||
|
||||
fn usz Slice2d.count(&self)
|
||||
{
|
||||
return self.ylen * self.xlen;
|
||||
}
|
||||
|
||||
macro void Slice2d.@each(&self; @body(usz[<2>], Type))
|
||||
{
|
||||
foreach (y, line : *self)
|
||||
{
|
||||
foreach (x, val : line)
|
||||
{
|
||||
@body({ x, y }, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro void Slice2d.@each_ref(&self; @body(usz[<2>], Type*))
|
||||
{
|
||||
foreach (y, line : *self)
|
||||
{
|
||||
foreach (x, &val : line)
|
||||
{
|
||||
@body({ x, y }, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @require idy >= 0 && idy < self.ylen
|
||||
**/
|
||||
macro Type[] Slice2d.get(self, usz idy) @operator([])
|
||||
{
|
||||
return (self.ptr + self.inner_len * (idy + self.ystart))[self.xstart:self.xlen];
|
||||
}
|
||||
|
||||
/**
|
||||
* @require y >= 0 && y < self.ylen
|
||||
* @require x >= 0 && x < self.xlen
|
||||
**/
|
||||
fn Slice2d Slice2d.slice(&self, isz x = 0, isz xlen = 0, isz y = 0, isz ylen = 0)
|
||||
{
|
||||
if (xlen < 1) xlen = self.xlen + xlen;
|
||||
if (ylen < 1) ylen = self.ylen + ylen;
|
||||
return { self.ptr, self.inner_len, y + self.ystart, ylen, x + self.xstart, xlen };
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
// Copyright (c) 2021-2022 Christoffer Lerno and contributors. All rights reserved.
|
||||
// Copyright (c) 2021-2024 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::builtin;
|
||||
import libc;
|
||||
import std::hash;
|
||||
import libc, std::hash, std::io, std::os::backtrace;
|
||||
|
||||
/**
|
||||
* Use `IteratorResult` when reading the end of an iterator, or accessing a result out of bounds.
|
||||
@@ -75,7 +74,7 @@ fn bool print_backtrace(String message, int backtraces_to_ignore) @if(env::NATIV
|
||||
void*[256] buffer;
|
||||
void*[] backtraces = backtrace::capture_current(&buffer);
|
||||
backtraces_to_ignore++;
|
||||
BacktraceList! backtrace = backtrace::symbolize_backtrace(backtraces, mem::temp());
|
||||
BacktraceList! backtrace = backtrace::symbolize_backtrace(backtraces, allocator::temp());
|
||||
if (catch backtrace) return false;
|
||||
if (backtrace.len() <= backtraces_to_ignore) return false;
|
||||
io::eprint("\nERROR: '");
|
||||
@@ -130,7 +129,7 @@ fn void panicf(String fmt, String file, String function, uint line, args...)
|
||||
@stack_mem(512; Allocator* allocator)
|
||||
{
|
||||
DString s;
|
||||
s.init_new(.allocator = allocator);
|
||||
s.new_init(.allocator = allocator);
|
||||
s.appendf(fmt, ...args);
|
||||
panic(s.str_view(), file, function, line);
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2021-2022 Christoffer Lerno and contributors. All rights reserved.
|
||||
// Copyright (c) 2021-2024 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::builtin;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2021 Christoffer Lerno. All rights reserved.
|
||||
// Copyright (c) 2021-2024 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::cinterop;
|
||||
|
||||
@@ -8,10 +8,10 @@ const usz MIN_CAPACITY @private = 16;
|
||||
/**
|
||||
* @require !self.data() "String already initialized"
|
||||
**/
|
||||
fn DString DString.init_new(&self, usz capacity = MIN_CAPACITY, Allocator* allocator = mem::heap())
|
||||
fn DString DString.new_init(&self, usz capacity = MIN_CAPACITY, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
if (capacity < MIN_CAPACITY) capacity = MIN_CAPACITY;
|
||||
StringData* data = allocator.new(StringData, .end_padding = capacity);
|
||||
StringData* data = allocator::alloc_with_padding(allocator, StringData, capacity)!!;
|
||||
data.allocator = allocator;
|
||||
data.len = 0;
|
||||
data.capacity = capacity;
|
||||
@@ -21,20 +21,36 @@ fn DString DString.init_new(&self, usz capacity = MIN_CAPACITY, Allocator* alloc
|
||||
/**
|
||||
* @require !self.data() "String already initialized"
|
||||
**/
|
||||
fn DString DString.init_temp(&self, usz capacity = MIN_CAPACITY)
|
||||
fn DString DString.init_new(&self, usz capacity = MIN_CAPACITY, Allocator* allocator = allocator::heap()) @deprecated("Replaced by new_init")
|
||||
{
|
||||
self.init_new(capacity, mem::temp()) @inline;
|
||||
return self.new_init(capacity, allocator) @inline;
|
||||
}
|
||||
|
||||
/**
|
||||
* @require !self.data() "String already initialized"
|
||||
**/
|
||||
fn DString DString.temp_init(&self, usz capacity = MIN_CAPACITY)
|
||||
{
|
||||
self.new_init(capacity, allocator::temp()) @inline;
|
||||
return *self;
|
||||
}
|
||||
|
||||
fn DString new_with_capacity(usz capacity, Allocator* allocator = mem::heap())
|
||||
/**
|
||||
* @require !self.data() "String already initialized"
|
||||
**/
|
||||
fn DString DString.init_temp(&self, usz capacity = MIN_CAPACITY) @deprecated("Replaced by temp_init")
|
||||
{
|
||||
return DString{}.init_new(capacity, allocator);
|
||||
return self.temp_init(capacity) @inline;
|
||||
}
|
||||
|
||||
fn DString temp_with_capacity(usz capacity) => new_with_capacity(capacity, mem::temp()) @inline;
|
||||
fn DString new_with_capacity(usz capacity, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
return DString{}.new_init(capacity, allocator);
|
||||
}
|
||||
|
||||
fn DString new(String c = "", Allocator* allocator = mem::heap())
|
||||
fn DString temp_with_capacity(usz capacity) => new_with_capacity(capacity, allocator::temp()) @inline;
|
||||
|
||||
fn DString new(String c = "", Allocator* allocator = allocator::heap())
|
||||
{
|
||||
usz len = c.len;
|
||||
StringData* data = (StringData*)new_with_capacity(len, allocator);
|
||||
@@ -46,18 +62,20 @@ fn DString new(String c = "", Allocator* allocator = mem::heap())
|
||||
return (DString)data;
|
||||
}
|
||||
|
||||
fn DString temp_new(String s = "") => new(s, mem::temp()) @inline;
|
||||
fn DString temp_new(String s = "") => new(s, allocator::temp()) @inline;
|
||||
|
||||
fn DString DString.new_concat(self, DString b, Allocator* allocator = mem::heap())
|
||||
fn DString DString.new_concat(self, DString b, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
DString string;
|
||||
string.init_new(self.len() + b.len(), allocator);
|
||||
string.new_init(self.len() + b.len(), allocator);
|
||||
string.append(self);
|
||||
string.append(b);
|
||||
return string;
|
||||
}
|
||||
|
||||
fn DString DString.new_tconcat(self, DString b) => self.new_concat(b, mem::temp());
|
||||
fn DString DString.temp_concat(self, DString b) => self.new_concat(b, allocator::temp());
|
||||
|
||||
fn DString DString.new_tconcat(self, DString b) @deprecated("Replaced by temp_concat") => self.new_concat(b, allocator::temp());
|
||||
|
||||
fn ZString DString.zstr_view(&self)
|
||||
{
|
||||
@@ -146,7 +164,7 @@ fn void DString.append_char32(&self, Char32 c)
|
||||
data.len += n;
|
||||
}
|
||||
|
||||
fn DString DString.tcopy(&self) => self.copy(mem::temp());
|
||||
fn DString DString.tcopy(&self) => self.copy(allocator::temp());
|
||||
|
||||
fn DString DString.copy(self, Allocator* allocator = null)
|
||||
{
|
||||
@@ -156,32 +174,32 @@ fn DString DString.copy(self, Allocator* allocator = null)
|
||||
return (DString)null;
|
||||
}
|
||||
StringData* data = self.data();
|
||||
if (!allocator) allocator = mem::heap();
|
||||
if (!allocator) allocator = allocator::heap();
|
||||
DString 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 DString.copy_zstr(self, Allocator* allocator = mem::heap())
|
||||
fn ZString DString.copy_zstr(self, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
usz str_len = self.len();
|
||||
if (!str_len)
|
||||
{
|
||||
return (ZString)allocator.calloc(1);
|
||||
return (ZString)allocator::calloc(allocator, 1);
|
||||
}
|
||||
char* zstr = allocator.alloc(str_len + 1);
|
||||
char* zstr = allocator::malloc(allocator, str_len + 1);
|
||||
StringData* data = self.data();
|
||||
mem::copy(zstr, &data.chars, str_len);
|
||||
zstr[str_len] = 0;
|
||||
return (ZString)zstr;
|
||||
}
|
||||
|
||||
fn String DString.copy_str(self, Allocator* allocator = mem::heap())
|
||||
fn String DString.copy_str(self, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
return (String)self.copy_zstr(allocator)[:self.len()];
|
||||
}
|
||||
|
||||
fn String DString.tcopy_str(self) => self.copy_str(mem::temp()) @inline;
|
||||
fn String DString.tcopy_str(self) => self.copy_str(allocator::temp()) @inline;
|
||||
|
||||
fn bool DString.equals(self, DString other_string)
|
||||
{
|
||||
@@ -204,7 +222,7 @@ fn void DString.free(&self)
|
||||
if (!*self) return;
|
||||
StringData* data = self.data();
|
||||
if (!data) return;
|
||||
data.allocator.free(data);
|
||||
allocator::free(data.allocator, data);
|
||||
*self = (DString)null;
|
||||
}
|
||||
|
||||
@@ -240,7 +258,7 @@ fn void DString.append_chars(&self, String str)
|
||||
data.len += other_len;
|
||||
}
|
||||
|
||||
fn Char32[] DString.copy_utf32(&self, Allocator* allocator = mem::heap())
|
||||
fn Char32[] DString.copy_utf32(&self, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
return self.str_view().to_new_utf32(allocator) @inline!!;
|
||||
}
|
||||
@@ -385,7 +403,7 @@ fn usz! DString.appendfn(&self, String format, args...) @maydiscard
|
||||
return len + 1;
|
||||
}
|
||||
|
||||
fn DString new_join(String[] s, String joiner, Allocator* allocator = mem::heap())
|
||||
fn DString new_join(String[] s, String joiner, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
if (!s.len) return (DString)null;
|
||||
usz total_size = joiner.len * s.len;
|
||||
@@ -429,7 +447,7 @@ fn void DString.reserve(&self, usz addition)
|
||||
if (new_capacity < MIN_CAPACITY) new_capacity = MIN_CAPACITY;
|
||||
while (new_capacity < len) new_capacity *= 2;
|
||||
data.capacity = new_capacity;
|
||||
*self = (DString)data.allocator.realloc(data, StringData.sizeof + new_capacity);
|
||||
*self = (DString)allocator::realloc(data.allocator, data, StringData.sizeof + new_capacity);
|
||||
}
|
||||
|
||||
fn usz! DString.read_from_stream(&self, InStream* reader)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2021 Christoffer Lerno. All rights reserved.
|
||||
// Copyright (c) 2021-2024 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::env;
|
||||
@@ -131,6 +131,7 @@ const bool TESTING = $$TESTING;
|
||||
const MemoryEnvironment MEMORY_ENV = (MemoryEnvironment)$$MEMORY_ENVIRONMENT;
|
||||
const bool TRACK_MEMORY = DEBUG_SYMBOLS && (COMPILER_SAFE_MODE || TESTING);
|
||||
const bool X86_64 = ARCH_TYPE == X86_64;
|
||||
const bool X86 = ARCH_TYPE == X86;
|
||||
const bool AARCH64 = ARCH_TYPE == AARCH64;
|
||||
const bool NATIVE_STACKTRACE = LINUX || DARWIN || WIN32;
|
||||
const bool LINUX = LIBC && OS_TYPE == LINUX;
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
// 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;
|
||||
import std::core::mem::allocator @public;
|
||||
import std::math;
|
||||
|
||||
const MAX_MEMORY_ALIGNMENT = 0x1000_0000;
|
||||
const DEFAULT_MEM_ALIGNMENT = (void*.alignof) * 2;
|
||||
@@ -379,9 +381,9 @@ macro type_alloc_must_be_aligned($Type)
|
||||
**/
|
||||
macro void @scoped(Allocator* allocator; @body())
|
||||
{
|
||||
Allocator* old_allocator = thread_allocator;
|
||||
thread_allocator = allocator;
|
||||
defer thread_allocator = old_allocator;
|
||||
Allocator* old_allocator = allocator::thread_allocator;
|
||||
allocator::thread_allocator = allocator;
|
||||
defer allocator::thread_allocator = old_allocator;
|
||||
@body();
|
||||
}
|
||||
|
||||
@@ -389,11 +391,11 @@ macro void @report_heap_allocs_in_scope(;@body())
|
||||
{
|
||||
TrackingAllocator tracker;
|
||||
tracker.init(thread_allocator);
|
||||
Allocator* old_allocator = thread_allocator;
|
||||
thread_allocator = &tracker;
|
||||
Allocator* old_allocator = allocator::thread_allocator;
|
||||
allocator::thread_allocator = &tracker;
|
||||
defer
|
||||
{
|
||||
thread_allocator = old_allocator;
|
||||
allocator::thread_allocator = old_allocator;
|
||||
tracker.print_report();
|
||||
tracker.free();
|
||||
}
|
||||
@@ -404,7 +406,7 @@ macro void @stack_mem(usz $size; @body(Allocator* mem)) @builtin
|
||||
{
|
||||
char[$size] buffer;
|
||||
OnStackAllocator allocator;
|
||||
allocator.init(&buffer, mem::heap());
|
||||
allocator.init(&buffer, allocator::heap());
|
||||
defer allocator.free();
|
||||
@body(&allocator);
|
||||
}
|
||||
@@ -413,7 +415,7 @@ macro void @stack_pool(usz $size; @body) @builtin
|
||||
{
|
||||
char[$size] buffer;
|
||||
OnStackAllocator allocator;
|
||||
allocator.init(&buffer, mem::heap());
|
||||
allocator.init(&buffer, allocator::heap());
|
||||
defer allocator.free();
|
||||
mem::@scoped(&allocator)
|
||||
{
|
||||
@@ -421,76 +423,67 @@ macro void @stack_pool(usz $size; @body) @builtin
|
||||
};
|
||||
}
|
||||
|
||||
struct TempState
|
||||
{
|
||||
TempAllocator* old;
|
||||
TempAllocator* current;
|
||||
usz mark;
|
||||
}
|
||||
|
||||
/**
|
||||
* Push the current temp allocator. A push must always be balanced with a pop using the current state.
|
||||
**/
|
||||
fn TempState temp_push(TempAllocator* other = null)
|
||||
{
|
||||
TempAllocator* current = allocator::temp();
|
||||
TempAllocator* old = current;
|
||||
if (other == current)
|
||||
{
|
||||
current = allocator::temp_allocator_next();
|
||||
}
|
||||
return { old, current, current.used };
|
||||
}
|
||||
|
||||
/**
|
||||
* Pop the current temp allocator. A pop must always be balanced with a push.
|
||||
**/
|
||||
fn void temp_pop(TempState old_state)
|
||||
{
|
||||
assert(allocator::thread_temp_allocator == old_state.current, "Tried to pop temp allocators out of order.");
|
||||
assert(old_state.current.used >= old_state.mark, "Tried to pop temp allocators out of order.");
|
||||
old_state.current.reset(old_state.mark);
|
||||
allocator::thread_temp_allocator = old_state.old;
|
||||
}
|
||||
|
||||
macro void @pool(TempAllocator* #other_temp = null; @body) @builtin
|
||||
{
|
||||
TempAllocator* current = temp();
|
||||
TempAllocator* current = allocator::temp();
|
||||
var $has_arg = !$is_const(#other_temp);
|
||||
$if $has_arg:
|
||||
TempAllocator* original = current;
|
||||
if (current == (void*)#other_temp) current = temp_allocator_next();
|
||||
if (current == (void*)#other_temp) current = allocator::temp_allocator_next();
|
||||
$endif
|
||||
usz mark = current.used;
|
||||
defer
|
||||
{
|
||||
current.reset(mark);
|
||||
$if $has_arg:
|
||||
thread_temp_allocator = original;
|
||||
allocator::thread_temp_allocator = original;
|
||||
$endif;
|
||||
}
|
||||
@body();
|
||||
}
|
||||
|
||||
tlocal Allocator* thread_allocator @private = &allocator::LIBC_ALLOCATOR;
|
||||
tlocal TempAllocator* thread_temp_allocator @private = null;
|
||||
tlocal TempAllocator*[2] temp_allocator_pair @private;
|
||||
Allocator* temp_base_allocator @private = &allocator::LIBC_ALLOCATOR;
|
||||
|
||||
macro TempAllocator* create_default_sized_temp_allocator(Allocator* allocator) @local
|
||||
{
|
||||
$switch (env::MEMORY_ENV)
|
||||
$case NORMAL:
|
||||
return allocator::new_temp(1024 * 256, allocator)!!;
|
||||
$case SMALL:
|
||||
return allocator::new_temp(1024 * 16, allocator)!!;
|
||||
$case TINY:
|
||||
return allocator::new_temp(1024 * 2, allocator)!!;
|
||||
$case NONE:
|
||||
unreachable("Temp allocator must explicitly created when memory-env is set to 'none'.");
|
||||
$endswitch
|
||||
}
|
||||
|
||||
fn TempAllocator *temp_allocator_next() @private
|
||||
{
|
||||
if (!thread_temp_allocator)
|
||||
{
|
||||
init_default_temp_allocators();
|
||||
return thread_temp_allocator;
|
||||
}
|
||||
usz index = thread_temp_allocator == temp_allocator_pair[0] ? 1 : 0;
|
||||
return thread_temp_allocator = temp_allocator_pair[index];
|
||||
}
|
||||
|
||||
import libc;
|
||||
|
||||
fn void init_default_temp_allocators() @private
|
||||
{
|
||||
temp_allocator_pair[0] = create_default_sized_temp_allocator(temp_base_allocator);
|
||||
temp_allocator_pair[1] = create_default_sized_temp_allocator(temp_base_allocator);
|
||||
thread_temp_allocator = temp_allocator_pair[0];
|
||||
}
|
||||
|
||||
macro TempAllocator* temp()
|
||||
{
|
||||
if (!thread_temp_allocator)
|
||||
{
|
||||
init_default_temp_allocators();
|
||||
}
|
||||
return thread_temp_allocator;
|
||||
}
|
||||
|
||||
macro Allocator* current_allocator() => thread_allocator;
|
||||
macro Allocator* heap() => thread_allocator;
|
||||
|
||||
macro TempAllocator* temp() @deprecated("Use allocator::temp()") => allocator::temp();
|
||||
macro Allocator* current_allocator() @deprecated("Use allocator::heap()") => allocator::heap();
|
||||
macro Allocator* heap() @deprecated("Use allocator::heap()") => allocator::heap();
|
||||
|
||||
module std::core::mem @if(WASM_NOLIBC);
|
||||
|
||||
@@ -520,88 +513,143 @@ macro TrackingEnv* get_tracking_env()
|
||||
$endif
|
||||
}
|
||||
|
||||
macro @clone(value) @builtin
|
||||
macro @clone(value) @builtin @nodiscard
|
||||
{
|
||||
return mem::heap().clone(value);
|
||||
return allocator::clone(allocator::heap(), value);
|
||||
}
|
||||
|
||||
macro @tclone(value) @builtin
|
||||
macro @tclone(value) @builtin @nodiscard
|
||||
{
|
||||
return mem::temp().clone(value);
|
||||
return temp_new($typeof(value), value);
|
||||
}
|
||||
|
||||
fn void* malloc(usz size) @builtin @inline
|
||||
fn void* malloc(usz size) @builtin @inline @nodiscard
|
||||
{
|
||||
return mem::heap().alloc(size);
|
||||
return allocator::malloc(allocator::heap(), size);
|
||||
}
|
||||
|
||||
fn void* tmalloc(usz size, usz alignment = 0, usz offset = 0) @builtin @inline
|
||||
fn void* tmalloc(usz size, usz alignment = 0, usz offset = 0) @builtin @inline @nodiscard
|
||||
{
|
||||
return temp().acquire(size, false, alignment, offset)!!;
|
||||
return allocator::temp().acquire(size, false, alignment, offset)!!;
|
||||
}
|
||||
|
||||
macro new($Type)
|
||||
/**
|
||||
* @require $vacount < 2 : "Too many arguments."
|
||||
* @require $or($vacount == 0, $assignable($vaexpr(0), $Type)) : "The second argument must be an initializer for the type"
|
||||
**/
|
||||
macro new($Type, ...) @nodiscard
|
||||
{
|
||||
return heap().new($Type);
|
||||
$if $vacount == 0:
|
||||
return ($Type*)calloc($Type.sizeof);
|
||||
$else
|
||||
$Type* val = malloc($Type.sizeof);
|
||||
*val = $vaexpr(0);
|
||||
return val;
|
||||
$endif
|
||||
}
|
||||
|
||||
macro new_clear($Type)
|
||||
macro alloc($Type) @nodiscard
|
||||
{
|
||||
return heap().new_clear($Type);
|
||||
return ($Type*)malloc($Type.sizeof);
|
||||
}
|
||||
|
||||
macro new_temp($Type)
|
||||
macro new_clear($Type) @deprecated("Use mem::new")
|
||||
{
|
||||
return new($Type);
|
||||
}
|
||||
|
||||
macro new_temp($Type) @deprecated("Use mem::temp_alloc or mem::temp_new")
|
||||
{
|
||||
return tmalloc($Type.sizeof);
|
||||
}
|
||||
|
||||
macro new_temp_clear($Type)
|
||||
/**
|
||||
* @require $vacount < 2 : "Too many arguments."
|
||||
* @require $or($vacount == 0, $assignable($vaexpr(0), $Type)) : "The second argument must be an initializer for the type"
|
||||
**/
|
||||
macro temp_new($Type, ...) @nodiscard
|
||||
{
|
||||
$if $vacount == 0:
|
||||
return ($Type*)tcalloc($Type.sizeof) @inline;
|
||||
$else
|
||||
$Type* val = tmalloc($Type.sizeof) @inline;
|
||||
*val = $vaexpr(0);
|
||||
return val;
|
||||
$endif
|
||||
}
|
||||
|
||||
macro temp_alloc($Type) @nodiscard
|
||||
{
|
||||
return tmalloc($Type.sizeof);
|
||||
}
|
||||
|
||||
macro new_temp_clear($Type) @deprecated("use mem::temp_new")
|
||||
{
|
||||
return tcalloc($Type.sizeof);
|
||||
}
|
||||
|
||||
macro new_array($Type, usz elements)
|
||||
macro new_array($Type, usz elements) @nodiscard
|
||||
{
|
||||
return heap().new_array($Type, elements);
|
||||
return allocator::new_array(allocator::heap(), $Type, elements);
|
||||
}
|
||||
|
||||
macro temp_array($Type, usz elements)
|
||||
macro alloc_array($Type, usz elements) @nodiscard
|
||||
{
|
||||
return allocator::alloc_array(allocator::heap(), $Type, elements);
|
||||
}
|
||||
|
||||
macro talloc_array($Type, usz elements) @nodiscard @deprecated("use mem::temp_alloc_array")
|
||||
{
|
||||
return temp_alloc_array($Type, elements);
|
||||
}
|
||||
|
||||
macro temp_alloc_array($Type, usz elements) @nodiscard
|
||||
{
|
||||
return (($Type*)tmalloc($Type.sizeof * elements, $Type.alignof))[:elements];
|
||||
}
|
||||
|
||||
macro new_zero_array($Type, usz elements)
|
||||
macro temp_array($Type, usz elements) @nodiscard @deprecated("use mem::temp_alloc_array")
|
||||
{
|
||||
return heap().new_zero_array($Type, elements);
|
||||
return temp_alloc_array($Type, elements);
|
||||
}
|
||||
|
||||
macro temp_zero_array($Type, usz elements)
|
||||
macro temp_new_array($Type, usz elements) @nodiscard
|
||||
{
|
||||
return (($Type*)tcalloc($Type.sizeof * elements, $Type.alignof))[:elements];
|
||||
}
|
||||
|
||||
fn void* calloc(usz size) @builtin @inline
|
||||
macro new_zero_array($Type, usz elements) @deprecated("Use new_array")
|
||||
{
|
||||
return heap().calloc(size);
|
||||
return new_array($Type, elements);
|
||||
}
|
||||
|
||||
fn void* tcalloc(usz size, usz alignment = 0, usz offset = 0) @builtin @inline
|
||||
macro temp_zero_array($Type, usz elements) @deprecated("Use temp_new_array")
|
||||
{
|
||||
return temp().acquire(size, false, alignment, offset)!!;
|
||||
return temp_new_array($Type, elements);
|
||||
}
|
||||
|
||||
fn void* realloc(void *ptr, usz new_size) @builtin @inline
|
||||
fn void* calloc(usz size) @builtin @inline @nodiscard
|
||||
{
|
||||
return heap().realloc(ptr, new_size);
|
||||
return allocator::calloc(allocator::heap(), size);
|
||||
}
|
||||
|
||||
fn void* tcalloc(usz size, usz alignment = 0, usz offset = 0) @builtin @inline @nodiscard
|
||||
{
|
||||
return allocator::temp().acquire(size, false, alignment, offset)!!;
|
||||
}
|
||||
|
||||
fn void* realloc(void *ptr, usz new_size) @builtin @inline @nodiscard
|
||||
{
|
||||
return allocator::realloc(allocator::heap(), ptr, new_size);
|
||||
}
|
||||
|
||||
fn void free(void* ptr) @builtin @inline
|
||||
{
|
||||
heap().free(ptr);
|
||||
return allocator::free(allocator::heap(), ptr);
|
||||
}
|
||||
|
||||
fn void* trealloc(void* ptr, usz size, usz alignment = mem::DEFAULT_MEM_ALIGNMENT) @builtin @inline
|
||||
fn void* trealloc(void* ptr, usz size, usz alignment = mem::DEFAULT_MEM_ALIGNMENT) @builtin @inline @nodiscard
|
||||
{
|
||||
return temp().resize(ptr, size, alignment, 0)!!;
|
||||
return allocator::temp().resize(ptr, size, alignment, 0)!!;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,12 +20,292 @@ interface Allocator
|
||||
fn void release(void* ptr, bool aligned);
|
||||
}
|
||||
|
||||
struct AlignedBlock
|
||||
def MemoryAllocFn = fn char[]!(usz);
|
||||
|
||||
fault AllocationFailure
|
||||
{
|
||||
usz len;
|
||||
void* start;
|
||||
OUT_OF_MEMORY,
|
||||
CHUNK_TOO_LARGE,
|
||||
}
|
||||
|
||||
fn usz alignment_for_allocation(usz alignment) @inline @private
|
||||
{
|
||||
return alignment < mem::DEFAULT_MEM_ALIGNMENT ? alignment = mem::DEFAULT_MEM_ALIGNMENT : alignment;
|
||||
}
|
||||
|
||||
macro void* malloc(Allocator* allocator, usz size) @nodiscard
|
||||
{
|
||||
return malloc_try(allocator, size)!!;
|
||||
}
|
||||
|
||||
macro void*! malloc_try(Allocator* allocator, usz size) @nodiscard
|
||||
{
|
||||
$if env::TESTING:
|
||||
char* data = allocator.acquire(size, false, 0, 0)!;
|
||||
mem::set(data, 0xAA, size, mem::DEFAULT_MEM_ALIGNMENT);
|
||||
return data;
|
||||
$else
|
||||
return allocator.acquire(size, false, 0, 0);
|
||||
$endif
|
||||
}
|
||||
|
||||
macro void* calloc(Allocator* allocator, usz size) @nodiscard
|
||||
{
|
||||
return calloc_try(allocator, size)!!;
|
||||
}
|
||||
|
||||
macro void*! calloc_try(Allocator* allocator, usz size) @nodiscard
|
||||
{
|
||||
return allocator.acquire(size, true, 0, 0);
|
||||
}
|
||||
|
||||
macro void* realloc(Allocator* allocator, void* ptr, usz new_size) @nodiscard
|
||||
{
|
||||
return realloc_try(allocator, ptr, new_size)!!;
|
||||
}
|
||||
|
||||
macro void*! realloc_try(Allocator* allocator, void* ptr, usz new_size) @nodiscard
|
||||
{
|
||||
return allocator.resize(ptr, new_size, 0, 0);
|
||||
}
|
||||
|
||||
macro void free(Allocator* allocator, void* ptr)
|
||||
{
|
||||
$if env::TESTING:
|
||||
if (ptr) ((char*)ptr)[0] = 0xBA;
|
||||
$endif
|
||||
allocator.release(ptr, false);
|
||||
}
|
||||
|
||||
macro void*! malloc_aligned(Allocator* allocator, usz size, usz alignment, usz offset = 0) @nodiscard
|
||||
{
|
||||
$if env::TESTING:
|
||||
char* data = allocator.acquire(size, false, alignment, offset)!;
|
||||
mem::set(data, 0xAA, size, mem::DEFAULT_MEM_ALIGNMENT);
|
||||
return data;
|
||||
$else
|
||||
return allocator.acquire(size, false, alignment, offset);
|
||||
$endif
|
||||
}
|
||||
|
||||
macro void*! calloc_aligned(Allocator* allocator, usz size, usz alignment, usz offset = 0) @nodiscard
|
||||
{
|
||||
return allocator.acquire(size, true, alignment, offset);
|
||||
}
|
||||
|
||||
macro void*! realloc_aligned(Allocator* allocator, void* ptr, usz new_size, usz alignment, usz offset = 0) @nodiscard
|
||||
{
|
||||
return allocator.resize(ptr, new_size, alignment, offset);
|
||||
}
|
||||
|
||||
macro void free_aligned(Allocator* allocator, void* ptr)
|
||||
{
|
||||
$if env::TESTING:
|
||||
if (ptr) ((char*)ptr)[0] = 0xBA;
|
||||
$endif
|
||||
allocator.release(ptr, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @require $vacount < 2 : "Too many arguments."
|
||||
* @require $or($vacount == 0, $assignable($vaexpr(0), $Type)) : "The second argument must be an initializer for the type"
|
||||
**/
|
||||
macro new(Allocator* allocator, $Type, ...) @nodiscard
|
||||
{
|
||||
$if $vacount == 0:
|
||||
return ($Type*)calloc(allocator, $Type.sizeof);
|
||||
$else
|
||||
$Type* val = malloc(allocator, $Type.sizeof);
|
||||
*val = $vaexpr(0);
|
||||
return val;
|
||||
$endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @require $vacount < 2 : "Too many arguments."
|
||||
* @require $or($vacount == 0, $assignable($vaexpr(0), $Type)) : "The second argument must be an initializer for the type"
|
||||
**/
|
||||
macro new_try(Allocator* allocator, $Type, ...) @nodiscard
|
||||
{
|
||||
$if $vacount == 0:
|
||||
return ($Type*)calloc_try(allocator, $Type.sizeof);
|
||||
$else
|
||||
$Type* val = malloc_try(allocator, $Type.sizeof)!;
|
||||
*val = $vaexpr(0);
|
||||
return val;
|
||||
$endif
|
||||
}
|
||||
|
||||
macro new_with_padding(Allocator* allocator, $Type, usz padding) @nodiscard
|
||||
{
|
||||
return ($Type*)calloc_try(allocator, $Type.sizeof + padding);
|
||||
}
|
||||
|
||||
macro alloc(Allocator* allocator, $Type) @nodiscard
|
||||
{
|
||||
return ($Type*)malloc(allocator, $Type.sizeof);
|
||||
}
|
||||
|
||||
macro alloc_try(Allocator* allocator, $Type) @nodiscard
|
||||
{
|
||||
return ($Type*)malloc_try(allocator, $Type.sizeof);
|
||||
}
|
||||
|
||||
macro alloc_with_padding(Allocator* allocator, $Type, usz padding) @nodiscard
|
||||
{
|
||||
return ($Type*)malloc_try(allocator, $Type.sizeof + padding);
|
||||
}
|
||||
|
||||
macro new_array(Allocator* allocator, $Type, usz elements) @nodiscard
|
||||
{
|
||||
return new_array_try(allocator, $Type, elements)!!;
|
||||
}
|
||||
|
||||
macro new_array_try(Allocator* allocator, $Type, usz elements) @nodiscard
|
||||
{
|
||||
return (($Type*)calloc_try(allocator, $Type.sizeof * elements))[:elements];
|
||||
}
|
||||
|
||||
macro alloc_array(Allocator* allocator, $Type, usz elements) @nodiscard
|
||||
{
|
||||
return alloc_array_try(allocator, $Type, elements)!!;
|
||||
}
|
||||
|
||||
macro alloc_array_try(Allocator* allocator, $Type, usz elements) @nodiscard
|
||||
{
|
||||
return (($Type*)malloc_try(allocator, $Type.sizeof * elements))[:elements];
|
||||
}
|
||||
|
||||
macro clone(Allocator* allocator, value) @nodiscard
|
||||
{
|
||||
return new(allocator, $typeof(value), value);
|
||||
}
|
||||
|
||||
fn any* clone_any(Allocator* allocator, any* value) @nodiscard
|
||||
{
|
||||
usz size = value.type.sizeof;
|
||||
void* data = malloc(allocator, size);
|
||||
mem::copy(data, value.ptr, size);
|
||||
return any_make(data, value.type);
|
||||
}
|
||||
|
||||
// Allocator "functions"
|
||||
|
||||
macro void*! Allocator.alloc_checked(&self, usz size) @deprecated("Use allocator::malloc_try")
|
||||
{
|
||||
$if env::TESTING:
|
||||
char* data = self.acquire(size, false, 0, 0)!;
|
||||
mem::set(data, 0xAA, size, mem::DEFAULT_MEM_ALIGNMENT);
|
||||
return data;
|
||||
$else
|
||||
return self.acquire(size, false, 0, 0);
|
||||
$endif
|
||||
}
|
||||
|
||||
macro void*! Allocator.calloc_checked(&self, usz size) @deprecated("Use allocator::calloc_try")
|
||||
{
|
||||
return self.acquire(size, true, 0, 0);
|
||||
}
|
||||
|
||||
macro void*! Allocator.realloc_checked(&self, void* ptr, usz new_size) @deprecated("Use allocator::realloc_try")
|
||||
{
|
||||
return self.resize(ptr, new_size, 0, 0);
|
||||
}
|
||||
|
||||
macro Allocator.new_array(&self, $Type, usz size, usz end_padding = 0) @deprecated("Use allocator::alloc_array")
|
||||
{
|
||||
return (($Type*)self.alloc_checked($Type.sizeof * size + end_padding))[:size]!!;
|
||||
}
|
||||
|
||||
macro Allocator.new_array_checked(&self, $Type, usz size, usz end_padding = 0) @deprecated("Use allocator::alloc_array_try")
|
||||
{
|
||||
return (($Type*)self.alloc_checked($Type.sizeof * size + end_padding))[:size];
|
||||
}
|
||||
|
||||
macro Allocator.new_zero_array(&self, $Type, usz size, usz end_padding = 0) @deprecated("Use allocator::new_array")
|
||||
{
|
||||
return (($Type*)self.calloc_checked($Type.sizeof * size + end_padding))[:size]!!;
|
||||
}
|
||||
|
||||
macro Allocator.new_zero_array_checked(&self, $Type, usz size, usz end_padding = 0) @deprecated("Use allocator::new_array_try")
|
||||
{
|
||||
return (($Type*)self.calloc_checked($Type.sizeof * size + end_padding))[:size];
|
||||
}
|
||||
|
||||
macro Allocator.new(&self, $Type, usz end_padding = 0) @nodiscard @deprecated("Use allocator::alloc")
|
||||
{
|
||||
return ($Type*)self.alloc_checked($Type.sizeof + end_padding)!!;
|
||||
}
|
||||
|
||||
macro Allocator.new_checked(&self, $Type, usz end_padding = 0) @nodiscard @deprecated("Use allocator::alloc_try")
|
||||
{
|
||||
return ($Type*)self.alloc_checked($Type.sizeof + end_padding);
|
||||
}
|
||||
|
||||
macro Allocator.new_clear(&self, $Type, usz end_padding = 0) @nodiscard @deprecated("Use allocator::new")
|
||||
{
|
||||
return ($Type*)self.calloc_checked($Type.sizeof + end_padding)!!;
|
||||
}
|
||||
|
||||
macro Allocator.new_clear_checked(&self, $Type, usz end_padding = 0) @nodiscard @deprecated("Use allocator::new_try")
|
||||
{
|
||||
return ($Type*)self.calloc_checked($Type.sizeof + end_padding);
|
||||
}
|
||||
macro Allocator.clone(&self, value) @deprecated("Use allocator::clone")
|
||||
{
|
||||
var x = self.alloc($typeof(value));
|
||||
*x = value;
|
||||
return x;
|
||||
}
|
||||
|
||||
macro void* Allocator.alloc(&self, usz size) @nodiscard @deprecated("Use allocator::malloc")
|
||||
{
|
||||
return self.alloc_checked(size)!!;
|
||||
}
|
||||
macro void* Allocator.calloc(&self, usz size) @nodiscard @deprecated("Use allocator::calloc")
|
||||
{
|
||||
return self.acquire(size, true, 0, 0)!!;
|
||||
}
|
||||
macro void* Allocator.realloc(&self, void* ptr, usz new_size) @nodiscard @deprecated("Use allocator::realloc")
|
||||
{
|
||||
return self.resize(ptr, new_size, 0, 0)!!;
|
||||
}
|
||||
|
||||
macro void*! Allocator.alloc_aligned(&self, usz size, usz alignment, usz offset = 0) @deprecated("Use allocator::alloc_aligned")
|
||||
{
|
||||
$if env::TESTING:
|
||||
char* data = self.acquire(size, false, alignment, offset)!;
|
||||
mem::set(data, 0xAA, size, mem::DEFAULT_MEM_ALIGNMENT);
|
||||
return data;
|
||||
$else
|
||||
return self.acquire(size, false, alignment, offset);
|
||||
$endif
|
||||
}
|
||||
macro void*! Allocator.calloc_aligned(&self, usz size, usz alignment, usz offset = 0) @deprecated("Use allocator::calloc_aligned")
|
||||
{
|
||||
return self.acquire(size, true, alignment, offset);
|
||||
}
|
||||
macro void*! Allocator.realloc_aligned(&self, void* ptr, usz new_size, usz alignment = 0, usz offset = 0) @deprecated("Use allocator::realloc_aligned")
|
||||
{
|
||||
return self.resize(ptr, new_size, alignment, offset);
|
||||
}
|
||||
|
||||
macro void Allocator.free(&self, void* ptr) @deprecated("Use allocator::free")
|
||||
{
|
||||
$if env::TESTING:
|
||||
if (ptr) ((char*)ptr)[0] = 0xBA;
|
||||
$endif
|
||||
self.release(ptr, false);
|
||||
}
|
||||
macro void Allocator.free_aligned(&self, void* ptr) @deprecated("Use allocator::free_aligned")
|
||||
{
|
||||
$if env::TESTING:
|
||||
if (ptr) ((char*)ptr)[0] = 0xBA;
|
||||
$endif
|
||||
self.release(ptr, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @require bytes > 0
|
||||
* @require alignment > 0
|
||||
@@ -64,6 +344,22 @@ macro void*! @aligned_calloc(#calloc_fn, usz bytes, usz alignment, usz offset)
|
||||
return mem;
|
||||
}
|
||||
|
||||
struct AlignedBlock
|
||||
{
|
||||
usz len;
|
||||
void* start;
|
||||
}
|
||||
|
||||
macro void! @aligned_free(#free_fn, void* old_pointer)
|
||||
{
|
||||
AlignedBlock* desc = (AlignedBlock*)old_pointer - 1;
|
||||
$if @typekind(#free_fn(desc.start)) == OPTIONAL:
|
||||
#free_fn(desc.start)!;
|
||||
$else
|
||||
#free_fn(desc.start);
|
||||
$endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @require bytes > 0
|
||||
* @require alignment > 0
|
||||
@@ -82,143 +378,52 @@ macro void*! @aligned_realloc(#calloc_fn, #free_fn, void* old_pointer, usz bytes
|
||||
return new_data;
|
||||
}
|
||||
|
||||
macro void! @aligned_free(#free_fn, void* old_pointer)
|
||||
|
||||
// All allocators
|
||||
tlocal Allocator* thread_allocator @private = &allocator::LIBC_ALLOCATOR;
|
||||
tlocal TempAllocator* thread_temp_allocator @private = null;
|
||||
tlocal TempAllocator*[2] temp_allocator_pair @private;
|
||||
Allocator* temp_base_allocator @private = &allocator::LIBC_ALLOCATOR;
|
||||
|
||||
macro TempAllocator* create_default_sized_temp_allocator(Allocator* allocator) @local
|
||||
{
|
||||
AlignedBlock* desc = (AlignedBlock*)old_pointer - 1;
|
||||
$if @typekind(#free_fn(desc.start)) == OPTIONAL:
|
||||
#free_fn(desc.start)!;
|
||||
$else
|
||||
#free_fn(desc.start);
|
||||
$endif
|
||||
$switch (env::MEMORY_ENV)
|
||||
$case NORMAL:
|
||||
return new_temp_allocator(1024 * 256, allocator)!!;
|
||||
$case SMALL:
|
||||
return new_temp_allocator(1024 * 16, allocator)!!;
|
||||
$case TINY:
|
||||
return new_temp_allocator(1024 * 2, allocator)!!;
|
||||
$case NONE:
|
||||
unreachable("Temp allocator must explicitly created when memory-env is set to 'none'.");
|
||||
$endswitch
|
||||
}
|
||||
|
||||
def MemoryAllocFn = fn char[]!(usz);
|
||||
macro Allocator* heap() => thread_allocator;
|
||||
|
||||
fault AllocationFailure
|
||||
macro TempAllocator* temp()
|
||||
{
|
||||
OUT_OF_MEMORY,
|
||||
CHUNK_TOO_LARGE,
|
||||
if (!thread_temp_allocator)
|
||||
{
|
||||
init_default_temp_allocators();
|
||||
}
|
||||
return thread_temp_allocator;
|
||||
}
|
||||
|
||||
fn usz alignment_for_allocation(usz alignment) @inline @private
|
||||
fn void init_default_temp_allocators() @private
|
||||
{
|
||||
return alignment < mem::DEFAULT_MEM_ALIGNMENT ? alignment = mem::DEFAULT_MEM_ALIGNMENT : alignment;
|
||||
temp_allocator_pair[0] = create_default_sized_temp_allocator(temp_base_allocator);
|
||||
temp_allocator_pair[1] = create_default_sized_temp_allocator(temp_base_allocator);
|
||||
thread_temp_allocator = temp_allocator_pair[0];
|
||||
}
|
||||
|
||||
// Allocator "functions"
|
||||
|
||||
macro void*! Allocator.alloc_checked(&self, usz size)
|
||||
fn TempAllocator *temp_allocator_next() @private
|
||||
{
|
||||
$if env::TESTING:
|
||||
char* data = self.acquire(size, false, 0, 0)!;
|
||||
mem::set(data, 0xAA, size, mem::DEFAULT_MEM_ALIGNMENT);
|
||||
return data;
|
||||
$else
|
||||
return self.acquire(size, false, 0, 0);
|
||||
$endif
|
||||
}
|
||||
|
||||
macro void*! Allocator.calloc_checked(&self, usz size)
|
||||
{
|
||||
return self.acquire(size, true, 0, 0);
|
||||
}
|
||||
macro void*! Allocator.realloc_checked(&self, void* ptr, usz new_size)
|
||||
{
|
||||
return self.resize(ptr, new_size, 0, 0);
|
||||
}
|
||||
|
||||
macro Allocator.new_array(&self, $Type, usz size, usz end_padding = 0)
|
||||
{
|
||||
return (($Type*)self.alloc_checked($Type.sizeof * size + end_padding))[:size]!!;
|
||||
}
|
||||
|
||||
macro Allocator.new_array_checked(&self, $Type, usz size, usz end_padding = 0)
|
||||
{
|
||||
return (($Type*)self.alloc_checked($Type.sizeof * size + end_padding))[:size];
|
||||
}
|
||||
|
||||
macro Allocator.new_zero_array(&self, $Type, usz size, usz end_padding = 0)
|
||||
{
|
||||
return (($Type*)self.calloc_checked($Type.sizeof * size + end_padding))[:size]!!;
|
||||
}
|
||||
|
||||
macro Allocator.new_zero_array_checked(&self, $Type, usz size, usz end_padding = 0)
|
||||
{
|
||||
return (($Type*)self.calloc_checked($Type.sizeof * size + end_padding))[:size];
|
||||
}
|
||||
|
||||
macro Allocator.new(&self, $Type, usz end_padding = 0) @nodiscard
|
||||
{
|
||||
return ($Type*)self.alloc_checked($Type.sizeof + end_padding)!!;
|
||||
}
|
||||
|
||||
macro Allocator.new_checked(&self, $Type, usz end_padding = 0) @nodiscard
|
||||
{
|
||||
return ($Type*)self.alloc_checked($Type.sizeof + end_padding);
|
||||
}
|
||||
|
||||
macro Allocator.new_clear(&self, $Type, usz end_padding = 0) @nodiscard
|
||||
{
|
||||
return ($Type*)self.calloc_checked($Type.sizeof + end_padding)!!;
|
||||
}
|
||||
|
||||
macro Allocator.new_clear_checked(&self, $Type, usz end_padding = 0) @nodiscard
|
||||
{
|
||||
return ($Type*)self.calloc_checked($Type.sizeof + end_padding);
|
||||
}
|
||||
|
||||
macro Allocator.clone(&self, value)
|
||||
{
|
||||
var x = self.alloc($typeof(value));
|
||||
*x = value;
|
||||
return x;
|
||||
}
|
||||
|
||||
macro void* Allocator.alloc(&self, usz size) @nodiscard
|
||||
{
|
||||
return self.alloc_checked(size)!!;
|
||||
}
|
||||
macro void* Allocator.calloc(&self, usz size) @nodiscard
|
||||
{
|
||||
return self.acquire(size, true, 0, 0)!!;
|
||||
}
|
||||
macro void* Allocator.realloc(&self, void* ptr, usz new_size) @nodiscard
|
||||
{
|
||||
return self.resize(ptr, new_size, 0, 0)!!;
|
||||
}
|
||||
|
||||
macro void*! Allocator.alloc_aligned(&self, usz size, usz alignment, usz offset = 0)
|
||||
{
|
||||
$if env::TESTING:
|
||||
char* data = self.acquire(size, false, alignment, offset)!;
|
||||
mem::set(data, 0xAA, size, mem::DEFAULT_MEM_ALIGNMENT);
|
||||
return data;
|
||||
$else
|
||||
return self.acquire(size, false, alignment, offset);
|
||||
$endif
|
||||
}
|
||||
macro void*! Allocator.calloc_aligned(&self, usz size, usz alignment, usz offset = 0)
|
||||
{
|
||||
return self.acquire(size, true, alignment, offset);
|
||||
}
|
||||
macro void*! Allocator.realloc_aligned(&self, void* ptr, usz new_size, usz alignment = 0, usz offset = 0)
|
||||
{
|
||||
return self.resize(ptr, new_size, alignment, offset);
|
||||
}
|
||||
|
||||
macro void Allocator.free(&self, void* ptr)
|
||||
{
|
||||
$if env::TESTING:
|
||||
if (ptr) ((char*)ptr)[0] = 0xBA;
|
||||
$endif
|
||||
self.release(ptr, false);
|
||||
}
|
||||
macro void Allocator.free_aligned(&self, void* ptr)
|
||||
{
|
||||
$if env::TESTING:
|
||||
if (ptr) ((char*)ptr)[0] = 0xBA;
|
||||
$endif
|
||||
self.release(ptr, true);
|
||||
}
|
||||
|
||||
|
||||
if (!thread_temp_allocator)
|
||||
{
|
||||
init_default_temp_allocators();
|
||||
return thread_temp_allocator;
|
||||
}
|
||||
usz index = thread_temp_allocator == temp_allocator_pair[0] ? 1 : 0;
|
||||
return thread_temp_allocator = temp_allocator_pair[index];
|
||||
}
|
||||
258
lib/std/core/private/cpu_detect.c3
Normal file
258
lib/std/core/private/cpu_detect.c3
Normal file
@@ -0,0 +1,258 @@
|
||||
module std::core::cpudetect @if(env::X86 || env::X86_64);
|
||||
|
||||
struct CpuId
|
||||
{
|
||||
uint eax, ebx, ecx, edx;
|
||||
}
|
||||
fn CpuId x86_cpuid(uint eax, uint ecx = 0)
|
||||
{
|
||||
int edx;
|
||||
int ebx;
|
||||
asm
|
||||
{
|
||||
movl $eax, eax;
|
||||
movl $ecx, ecx;
|
||||
cpuid;
|
||||
movl eax, $eax;
|
||||
movl ebx, $ebx;
|
||||
movl ecx, $ecx;
|
||||
movl edx, $edx;
|
||||
}
|
||||
return { eax, ebx, ecx, edx };
|
||||
}
|
||||
|
||||
enum X86Feature
|
||||
{
|
||||
ADX,
|
||||
AES,
|
||||
AMX_BF16,
|
||||
AMX_COMPLEX,
|
||||
AMX_FP16,
|
||||
AMX_INT8,
|
||||
AMX_TILE,
|
||||
AVX,
|
||||
AVX10_1_256,
|
||||
AVX10_1_512,
|
||||
AVX2,
|
||||
AVX5124FMAPS,
|
||||
AVX5124VNNIW,
|
||||
AVX512BF16,
|
||||
AVX512BITALG,
|
||||
AVX512BW,
|
||||
AVX512CD,
|
||||
AVX512DQ,
|
||||
AVX512ER,
|
||||
AVX512F,
|
||||
AVX512FP16,
|
||||
AVX512IFMA,
|
||||
AVX512PF,
|
||||
AVX512VBMI,
|
||||
AVX512VBMI2,
|
||||
AVX512VL,
|
||||
AVX512VNNI,
|
||||
AVX512VP2INTERSECT,
|
||||
AVX512VPOPCNTDQ,
|
||||
AVXIFMA,
|
||||
AVXNECONVERT,
|
||||
AVXVNNI,
|
||||
AVXVNNIINT16,
|
||||
AVXVNNIINT8,
|
||||
BMI,
|
||||
BMI2,
|
||||
CLDEMOTE,
|
||||
CLFLUSHOPT,
|
||||
CLWB,
|
||||
CLZERO,
|
||||
CMOV,
|
||||
CMPCCXADD,
|
||||
CMPXCHG16B,
|
||||
CX8,
|
||||
ENQCMD,
|
||||
F16C,
|
||||
FMA,
|
||||
FMA4,
|
||||
FSGSBASE,
|
||||
FXSR,
|
||||
GFNI,
|
||||
HRESET,
|
||||
INVPCID,
|
||||
KL,
|
||||
LWP,
|
||||
LZCNT,
|
||||
MMX,
|
||||
MOVBE,
|
||||
MOVDIR64B,
|
||||
MOVDIRI,
|
||||
MWAITX,
|
||||
PCLMUL,
|
||||
PCONFIG,
|
||||
PKU,
|
||||
POPCNT,
|
||||
PREFETCHI,
|
||||
PREFETCHWT1,
|
||||
PRFCHW,
|
||||
PTWRITE,
|
||||
RAOINT,
|
||||
RDPID,
|
||||
RDPRU,
|
||||
RDRND,
|
||||
RDSEED,
|
||||
RTM,
|
||||
SAHF,
|
||||
SERIALIZE,
|
||||
SGX,
|
||||
SHA,
|
||||
SHA512,
|
||||
SHSTK,
|
||||
SM3,
|
||||
SM4,
|
||||
SSE,
|
||||
SSE2,
|
||||
SSE3,
|
||||
SSE4_1,
|
||||
SSE4_2,
|
||||
SSE4_A,
|
||||
SSSE3,
|
||||
TBM,
|
||||
TSXLDTRK,
|
||||
UINTR,
|
||||
USERMSR,
|
||||
VAES,
|
||||
VPCLMULQDQ,
|
||||
WAITPKG,
|
||||
WBNOINVD,
|
||||
WIDEKL,
|
||||
X87,
|
||||
XOP,
|
||||
XSAVE,
|
||||
XSAVEC,
|
||||
XSAVEOPT,
|
||||
XSAVES,
|
||||
}
|
||||
|
||||
uint128 x86_features;
|
||||
|
||||
fn void add_feature_if_bit(X86Feature feature, uint register, int bit)
|
||||
{
|
||||
if (register & 1U << bit) x86_features |= 1u128 << feature.ordinal;
|
||||
}
|
||||
|
||||
fn void x86_initialize_cpu_features()
|
||||
{
|
||||
uint max_level = x86_cpuid(0).eax;
|
||||
CpuId feat = x86_cpuid(1);
|
||||
CpuId leaf7 = max_level >= 8 ? x86_cpuid(7) : CpuId {};
|
||||
CpuId leaf7s1 = leaf7.eax >= 1 ? x86_cpuid(7, 1) : CpuId {};
|
||||
CpuId ext1 = x86_cpuid(0x80000000).eax >= 0x80000001 ? x86_cpuid(0x80000001) : CpuId {};
|
||||
CpuId ext8 = x86_cpuid(0x80000000).eax >= 0x80000008 ? x86_cpuid(0x80000008) : CpuId {};
|
||||
CpuId leaf_d = max_level >= 0xd ? x86_cpuid(0xd, 0x1) : CpuId {};
|
||||
CpuId leaf_14 = max_level >= 0x14 ? x86_cpuid(0x14) : CpuId {};
|
||||
CpuId leaf_19 = max_level >= 0x19 ? x86_cpuid(0x19) : CpuId {};
|
||||
CpuId leaf_24 = max_level >= 0x24 ? x86_cpuid(0x24) : CpuId {};
|
||||
add_feature_if_bit(ADX, leaf7.ebx, 19);
|
||||
add_feature_if_bit(AES, feat.ecx, 25);
|
||||
add_feature_if_bit(AMX_BF16, leaf7.edx, 22);
|
||||
add_feature_if_bit(AMX_COMPLEX, leaf7s1.edx, 8);
|
||||
add_feature_if_bit(AMX_FP16, leaf7s1.eax, 21);
|
||||
add_feature_if_bit(AMX_INT8, leaf7.edx, 25);
|
||||
add_feature_if_bit(AMX_TILE, leaf7.edx, 24);
|
||||
add_feature_if_bit(AVX, feat.ecx, 28);
|
||||
add_feature_if_bit(AVX10_1_256, leaf7s1.edx, 19);
|
||||
add_feature_if_bit(AVX10_1_512, leaf_24.ebx, 18);
|
||||
add_feature_if_bit(AVX2, leaf7.ebx, 5);
|
||||
add_feature_if_bit(AVX5124FMAPS, leaf7.edx, 3);
|
||||
add_feature_if_bit(AVX5124VNNIW, leaf7.edx, 2);
|
||||
add_feature_if_bit(AVX512BF16, leaf7s1.eax, 5);
|
||||
add_feature_if_bit(AVX512BITALG, leaf7.ecx, 12);
|
||||
add_feature_if_bit(AVX512BW, leaf7.ebx, 30);
|
||||
add_feature_if_bit(AVX512CD, leaf7.ebx, 28);
|
||||
add_feature_if_bit(AVX512DQ, leaf7.ebx, 17);
|
||||
add_feature_if_bit(AVX512ER, leaf7.ebx, 27);
|
||||
add_feature_if_bit(AVX512F, leaf7.ebx, 16);
|
||||
add_feature_if_bit(AVX512FP16, leaf7.edx, 23);
|
||||
add_feature_if_bit(AVX512IFMA, leaf7.ebx, 21);
|
||||
add_feature_if_bit(AVX512PF, leaf7.ebx, 26);
|
||||
add_feature_if_bit(AVX512VBMI, leaf7.ecx, 1);
|
||||
add_feature_if_bit(AVX512VBMI2, leaf7.ecx, 6);
|
||||
add_feature_if_bit(AVX512VL, leaf7.ebx, 31);
|
||||
add_feature_if_bit(AVX512VNNI, leaf7.ecx, 11);
|
||||
add_feature_if_bit(AVX512VP2INTERSECT, leaf7.edx, 8);
|
||||
add_feature_if_bit(AVX512VPOPCNTDQ, leaf7.ecx, 14);
|
||||
add_feature_if_bit(AVXIFMA, leaf7s1.eax, 23);
|
||||
add_feature_if_bit(AVXNECONVERT, leaf7s1.edx, 5);
|
||||
add_feature_if_bit(AVXVNNI, leaf7s1.eax, 4);
|
||||
add_feature_if_bit(AVXVNNIINT16, leaf7s1.edx, 10);
|
||||
add_feature_if_bit(AVXVNNIINT8, leaf7s1.edx, 4);
|
||||
add_feature_if_bit(BMI, leaf7.ebx, 3);
|
||||
add_feature_if_bit(BMI2, leaf7.ebx, 8);
|
||||
add_feature_if_bit(CLDEMOTE, leaf7.ecx, 25);
|
||||
add_feature_if_bit(CLFLUSHOPT, leaf7.ebx, 23);
|
||||
add_feature_if_bit(CLWB, leaf7.ebx, 24);
|
||||
add_feature_if_bit(CLZERO, ext8.ecx, 0);
|
||||
add_feature_if_bit(CMOV, feat.edx, 15);
|
||||
add_feature_if_bit(CMPCCXADD, leaf7s1.eax, 7);
|
||||
add_feature_if_bit(CMPXCHG16B, feat.ecx, 12);
|
||||
add_feature_if_bit(CX8, feat.edx, 8);
|
||||
add_feature_if_bit(ENQCMD, leaf7.ecx, 29);
|
||||
add_feature_if_bit(F16C, feat.ecx, 29);
|
||||
add_feature_if_bit(FMA, feat.ecx, 12);
|
||||
add_feature_if_bit(FMA4, ext1.ecx, 16);
|
||||
add_feature_if_bit(FSGSBASE, leaf7.ebx, 0);
|
||||
add_feature_if_bit(FXSR, feat.edx, 24);
|
||||
add_feature_if_bit(GFNI, leaf7.ecx, 8);
|
||||
add_feature_if_bit(HRESET, leaf7s1.eax, 22);
|
||||
add_feature_if_bit(INVPCID, leaf7.ebx, 10);
|
||||
add_feature_if_bit(KL, leaf7.ecx, 23);
|
||||
add_feature_if_bit(LWP, ext1.ecx, 15);
|
||||
add_feature_if_bit(LZCNT, ext1.ecx, 5);
|
||||
add_feature_if_bit(MMX, feat.edx, 23);
|
||||
add_feature_if_bit(MOVBE, feat.ecx, 22);
|
||||
add_feature_if_bit(MOVDIR64B, leaf7.ecx, 28);
|
||||
add_feature_if_bit(MOVDIRI, leaf7.ecx, 27);
|
||||
add_feature_if_bit(MWAITX, ext1.ecx, 29);
|
||||
add_feature_if_bit(PCLMUL, feat.ecx, 1);
|
||||
add_feature_if_bit(PCONFIG, leaf7.edx, 18);
|
||||
add_feature_if_bit(PKU, leaf7.ecx, 4);
|
||||
add_feature_if_bit(POPCNT, feat.ecx, 23);
|
||||
add_feature_if_bit(PREFETCHI, leaf7s1.edx, 14);
|
||||
add_feature_if_bit(PREFETCHWT1, leaf7.ecx, 0);
|
||||
add_feature_if_bit(PRFCHW, ext1.ecx, 8);
|
||||
add_feature_if_bit(PTWRITE, leaf_14.ebx, 4);
|
||||
add_feature_if_bit(RAOINT, leaf7s1.eax, 3);
|
||||
add_feature_if_bit(RDPID, leaf7.ecx, 22);
|
||||
add_feature_if_bit(RDPRU, ext8.ecx, 4);
|
||||
add_feature_if_bit(RDRND, feat.ecx, 30);
|
||||
add_feature_if_bit(RDSEED, leaf7.ebx, 18);
|
||||
add_feature_if_bit(RTM, leaf7.ebx, 11);
|
||||
add_feature_if_bit(SAHF, ext1.ecx, 0);
|
||||
add_feature_if_bit(SERIALIZE, leaf7.edx, 14);
|
||||
add_feature_if_bit(SGX, leaf7.ebx, 2);
|
||||
add_feature_if_bit(SHA, leaf7.ebx, 29);
|
||||
add_feature_if_bit(SHA512, leaf7s1.eax, 0);
|
||||
add_feature_if_bit(SHSTK, leaf7.ecx, 7);
|
||||
add_feature_if_bit(SM3, leaf7s1.eax, 1);
|
||||
add_feature_if_bit(SM4, leaf7s1.eax, 2);
|
||||
add_feature_if_bit(SSE, feat.edx, 25);
|
||||
add_feature_if_bit(SSE2, feat.edx, 26);
|
||||
add_feature_if_bit(SSE3, feat.ecx, 0);
|
||||
add_feature_if_bit(SSE4_1, feat.ecx, 19);
|
||||
add_feature_if_bit(SSE4_2, feat.ecx, 20);
|
||||
add_feature_if_bit(SSE4_A, ext1.ecx, 6);
|
||||
add_feature_if_bit(SSSE3, feat.ecx, 9);
|
||||
add_feature_if_bit(TBM, ext1.ecx, 21);
|
||||
add_feature_if_bit(TSXLDTRK, leaf7.edx, 16);
|
||||
add_feature_if_bit(UINTR, leaf7.edx, 5);
|
||||
add_feature_if_bit(USERMSR, leaf7s1.edx, 15);
|
||||
add_feature_if_bit(VAES, leaf7.ecx, 9);
|
||||
add_feature_if_bit(VPCLMULQDQ, leaf7.ecx, 10);
|
||||
add_feature_if_bit(WAITPKG, leaf7.ecx, 5);
|
||||
add_feature_if_bit(WBNOINVD, ext8.ecx, 9);
|
||||
add_feature_if_bit(WIDEKL, leaf_19.ebx, 2);
|
||||
add_feature_if_bit(X87, feat.edx, 0);
|
||||
add_feature_if_bit(XOP, ext1.ecx, 11);
|
||||
add_feature_if_bit(XSAVE, feat.ecx, 26);
|
||||
add_feature_if_bit(XSAVEC, leaf_d.eax, 1);
|
||||
add_feature_if_bit(XSAVEOPT, leaf_d.eax, 0);
|
||||
add_feature_if_bit(XSAVES, leaf_d.eax, 3);
|
||||
|
||||
}
|
||||
254
lib/std/core/private/macho_runtime.c3
Normal file
254
lib/std/core/private/macho_runtime.c3
Normal file
@@ -0,0 +1,254 @@
|
||||
module std::core::machoruntime @if(env::DARWIN) @private;
|
||||
|
||||
struct SegmentCommand64
|
||||
{
|
||||
uint cmd;
|
||||
uint cmdsize;
|
||||
char[16] segname;
|
||||
ulong vmaddr;
|
||||
ulong vmsize;
|
||||
ulong fileoff;
|
||||
ulong filesize;
|
||||
uint maxprot;
|
||||
uint initprot;
|
||||
uint nsects;
|
||||
uint flags;
|
||||
}
|
||||
|
||||
struct LoadCommand
|
||||
{
|
||||
uint cmd;
|
||||
uint cmdsize;
|
||||
}
|
||||
|
||||
struct Section64
|
||||
{
|
||||
char[16] sectname;
|
||||
char[16] segname;
|
||||
ulong addr;
|
||||
ulong size;
|
||||
uint offset;
|
||||
uint align;
|
||||
uint reloff;
|
||||
uint nreloc;
|
||||
uint flags;
|
||||
uint reserved1;
|
||||
uint reserved2;
|
||||
uint reserved3;
|
||||
}
|
||||
|
||||
struct MachHeader
|
||||
{
|
||||
uint magic;
|
||||
uint cputype;
|
||||
uint cpusubtype;
|
||||
uint filetype;
|
||||
uint ncmds;
|
||||
uint sizeofcmds;
|
||||
uint flags;
|
||||
}
|
||||
|
||||
struct MachHeader64
|
||||
{
|
||||
inline MachHeader header;
|
||||
uint reserved;
|
||||
}
|
||||
|
||||
const LC_SEGMENT_64 = 0x19;
|
||||
|
||||
fault MachoSearch
|
||||
{
|
||||
NOT_FOUND
|
||||
}
|
||||
fn bool name_cmp(char* a, char[16]* b)
|
||||
{
|
||||
for (usz i = 0; i < 16; i++)
|
||||
{
|
||||
if (a[i] != (*b)[i]) return false;
|
||||
if (a[i] == '\0') return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
fn SegmentCommand64*! find_segment(MachHeader* header, char* segname)
|
||||
{
|
||||
LoadCommand* command = (void*)header + MachHeader64.sizeof;
|
||||
for (uint i = 0; i < header.ncmds; i++)
|
||||
{
|
||||
if (command.cmd == LC_SEGMENT_64)
|
||||
{
|
||||
SegmentCommand64* segment = (SegmentCommand64*)command;
|
||||
if (name_cmp(segname, &segment.segname)) return segment;
|
||||
}
|
||||
command = (void*)command + command.cmdsize;
|
||||
}
|
||||
return MachoSearch.NOT_FOUND?;
|
||||
}
|
||||
fn Section64*! find_section(SegmentCommand64* command, char* sectname)
|
||||
{
|
||||
Section64* section = (void*)command + SegmentCommand64.sizeof;
|
||||
for (uint i = 0; i < command.nsects; i++)
|
||||
{
|
||||
if (name_cmp(sectname, §ion.sectname)) return section;
|
||||
section++;
|
||||
}
|
||||
return MachoSearch.NOT_FOUND?;
|
||||
}
|
||||
|
||||
macro find_segment_section_body(MachHeader* header, char* segname, char* sectname, $Type)
|
||||
{
|
||||
|
||||
Section64*! section = find_section(find_segment(header, segname), sectname);
|
||||
if (catch section)
|
||||
{
|
||||
return $Type[] {};
|
||||
}
|
||||
$Type* ptr = (void*)header + section.offset;
|
||||
return ptr[:section.size / $Type.sizeof];
|
||||
}
|
||||
|
||||
def DyldCallback = fn void (MachHeader* mh, isz vmaddr_slide);
|
||||
|
||||
extern fn void _dyld_register_func_for_add_image(DyldCallback);
|
||||
|
||||
|
||||
struct DlInfo
|
||||
{
|
||||
char* dli_fname;
|
||||
void* dli_fbase;
|
||||
char* dli_sname;
|
||||
void* dli_saddr;
|
||||
}
|
||||
|
||||
extern fn void printf(char*, ...);
|
||||
extern fn int dladdr(MachHeader* mh, DlInfo* dlinfo);
|
||||
extern fn void* realloc(void* ptr, usz size);
|
||||
extern fn void* malloc(usz size);
|
||||
extern fn void free(void* ptr);
|
||||
|
||||
def CallbackFn = fn void();
|
||||
struct Callback
|
||||
{
|
||||
uint priority;
|
||||
CallbackFn xtor;
|
||||
Callback* next;
|
||||
}
|
||||
struct DynamicMethod
|
||||
{
|
||||
void* fn_ptr;
|
||||
char* sel;
|
||||
union
|
||||
{
|
||||
DynamicMethod* next;
|
||||
TypeId* type;
|
||||
}
|
||||
}
|
||||
|
||||
enum StartupState
|
||||
{
|
||||
NOT_STARTED,
|
||||
INIT,
|
||||
RUN_CTORS,
|
||||
READ_DYLIB,
|
||||
RUN_DYLIB_CTORS,
|
||||
RUN_DTORS,
|
||||
SHUTDOWN
|
||||
}
|
||||
|
||||
StartupState runtime_state = NOT_STARTED;
|
||||
|
||||
Callback* ctor_first;
|
||||
Callback* dtor_first;
|
||||
|
||||
fn void runtime_startup() @public @export("__c3_runtime_startup")
|
||||
{
|
||||
if (runtime_state != NOT_STARTED) return;
|
||||
runtime_state = INIT;
|
||||
_dyld_register_func_for_add_image(&dl_reg_callback);
|
||||
assert(runtime_state == INIT);
|
||||
runtime_state = RUN_CTORS;
|
||||
Callback* ctor = ctor_first;
|
||||
while (ctor)
|
||||
{
|
||||
ctor.xtor();
|
||||
ctor = ctor.next;
|
||||
}
|
||||
assert(runtime_state == RUN_CTORS);
|
||||
runtime_state = READ_DYLIB;
|
||||
ctor = null;
|
||||
}
|
||||
|
||||
fn void runtime_finalize() @public @export("__c3_runtime_finalize")
|
||||
{
|
||||
if (runtime_state != READ_DYLIB) return;
|
||||
runtime_state = RUN_DTORS;
|
||||
Callback* dtor = dtor_first;
|
||||
while (dtor)
|
||||
{
|
||||
dtor.xtor();
|
||||
dtor = dtor.next;
|
||||
}
|
||||
assert(runtime_state == RUN_DTORS);
|
||||
runtime_state = SHUTDOWN;
|
||||
}
|
||||
|
||||
fn void append_xxlizer(Callback** ref, Callback* cb)
|
||||
{
|
||||
while (Callback* current = *ref, current)
|
||||
{
|
||||
if (current.priority > cb.priority)
|
||||
{
|
||||
cb.next = current;
|
||||
break;
|
||||
}
|
||||
ref = ¤t.next;
|
||||
}
|
||||
*ref = cb;
|
||||
}
|
||||
|
||||
struct TypeId
|
||||
{
|
||||
char type;
|
||||
TypeId* parentof;
|
||||
DynamicMethod* dtable;
|
||||
usz sizeof;
|
||||
TypeId* inner;
|
||||
usz len;
|
||||
typeid[*] additional;
|
||||
}
|
||||
|
||||
fn void dl_reg_callback(MachHeader* mh, isz vmaddr_slide)
|
||||
{
|
||||
usz size = 0;
|
||||
assert(runtime_state == INIT || runtime_state == READ_DYLIB, "State was %s", runtime_state);
|
||||
foreach (&dm : find_segment_section_body(mh, "__DATA", "__c3_dynamic", DynamicMethod))
|
||||
{
|
||||
TypeId* type = dm.type;
|
||||
dm.next = type.dtable;
|
||||
type.dtable = dm;
|
||||
DynamicMethod* m = dm;
|
||||
while (m)
|
||||
{
|
||||
m = m.next;
|
||||
}
|
||||
}
|
||||
foreach (&cb : find_segment_section_body(mh, "__DATA", "__c3dtor", Callback))
|
||||
{
|
||||
append_xxlizer(&dtor_first, cb);
|
||||
}
|
||||
foreach (&cb : find_segment_section_body(mh, "__DATA", "__c3ctor", Callback))
|
||||
{
|
||||
append_xxlizer(&ctor_first, cb);
|
||||
}
|
||||
if (runtime_state != READ_DYLIB) return;
|
||||
runtime_state = RUN_DYLIB_CTORS;
|
||||
Callback* ctor = ctor_first;
|
||||
ctor_first = null;
|
||||
while (ctor)
|
||||
{
|
||||
ctor.xtor();
|
||||
ctor = ctor.next;
|
||||
}
|
||||
assert(runtime_state == RUN_DYLIB_CTORS);
|
||||
runtime_state = READ_DYLIB;
|
||||
}
|
||||
@@ -21,7 +21,7 @@ macro int @main_to_void_main(#m, int, char**)
|
||||
|
||||
macro String[] args_to_strings(int argc, char** argv) @private
|
||||
{
|
||||
String[] list = mem::new_array(String, argc);
|
||||
String[] list = mem::alloc_array(String, argc);
|
||||
for (int i = 0; i < argc; i++)
|
||||
{
|
||||
char* arg = argv[i];
|
||||
@@ -68,7 +68,7 @@ macro String[] win_command_line_to_strings(ushort* cmd_line) @private
|
||||
|
||||
macro String[] wargs_strings(int argc, Char16** argv) @private
|
||||
{
|
||||
String[] list = mem::new_array(String, argc);
|
||||
String[] list = mem::alloc_array(String, argc);
|
||||
for (int i = 0; i < argc; i++)
|
||||
{
|
||||
Char16* arg = argv[i];
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by the MIT license
|
||||
// a copy of which can be found in the LICENSE_STDLIB file.
|
||||
module std::core::runtime;
|
||||
import libc;
|
||||
import libc, std::time, std::io, std::sort;
|
||||
|
||||
struct AnyStruct
|
||||
{
|
||||
@@ -24,11 +24,11 @@ struct BenchmarkUnit
|
||||
BenchmarkFn func;
|
||||
}
|
||||
|
||||
fn BenchmarkUnit[] benchmark_collection_create(Allocator* allocator = mem::heap())
|
||||
fn BenchmarkUnit[] benchmark_collection_create(Allocator* allocator = allocator::heap())
|
||||
{
|
||||
BenchmarkFn[] fns = $$BENCHMARK_FNS;
|
||||
String[] names = $$BENCHMARK_NAMES;
|
||||
BenchmarkUnit[] benchmarks = allocator.new_array(BenchmarkUnit, names.len);
|
||||
BenchmarkUnit[] benchmarks = allocator::alloc_array(allocator, BenchmarkUnit, names.len);
|
||||
foreach (i, benchmark : fns)
|
||||
{
|
||||
benchmarks[i] = { names[i], fns[i] };
|
||||
@@ -130,7 +130,7 @@ fn bool default_benchmark_runner()
|
||||
{
|
||||
@pool()
|
||||
{
|
||||
return run_benchmarks(benchmark_collection_create(mem::temp()));
|
||||
return run_benchmarks(benchmark_collection_create(allocator::temp()));
|
||||
};
|
||||
}
|
||||
|
||||
@@ -142,11 +142,11 @@ struct TestUnit
|
||||
TestFn func;
|
||||
}
|
||||
|
||||
fn TestUnit[] test_collection_create(Allocator* allocator = mem::heap())
|
||||
fn TestUnit[] test_collection_create(Allocator* allocator = allocator::heap())
|
||||
{
|
||||
TestFn[] fns = $$TEST_FNS;
|
||||
String[] names = $$TEST_NAMES;
|
||||
TestUnit[] tests = allocator.new_array(TestUnit, names.len);
|
||||
TestUnit[] tests = allocator::alloc_array(allocator, TestUnit, names.len);
|
||||
foreach (i, test : fns)
|
||||
{
|
||||
tests[i] = { names[i], fns[i] };
|
||||
@@ -236,7 +236,7 @@ fn bool default_test_runner()
|
||||
{
|
||||
@pool()
|
||||
{
|
||||
return run_tests(test_collection_create(mem::temp()));
|
||||
return run_tests(test_collection_create(allocator::temp()));
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ macro String tformat(String fmt, ...)
|
||||
return str.str_view();
|
||||
}
|
||||
|
||||
macro String new_format(String fmt, ..., Allocator* allocator = mem::heap())
|
||||
macro String new_format(String fmt, ..., Allocator* allocator = allocator::heap())
|
||||
{
|
||||
@pool(allocator)
|
||||
{
|
||||
@@ -55,11 +55,11 @@ macro bool char_in_set(char c, String set)
|
||||
return false;
|
||||
}
|
||||
|
||||
fn String join_new(String[] s, String joiner, Allocator* allocator = mem::heap())
|
||||
fn String join_new(String[] s, String joiner, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
if (!s)
|
||||
{
|
||||
return (String)allocator.new_zero_array(char, 2)[:0];
|
||||
return (String)allocator::new_array(allocator, char, 2)[:0];
|
||||
}
|
||||
|
||||
usz total_size = joiner.len * s.len;
|
||||
@@ -153,11 +153,11 @@ fn String String.strip_end(string, String needle)
|
||||
* @require needle.len > 0 "The needle must be at least 1 character long"
|
||||
* @ensure return.len > 0
|
||||
**/
|
||||
fn String[] String.split(s, String needle, usz max = 0, Allocator* allocator = mem::heap())
|
||||
fn String[] String.split(s, String needle, usz max = 0, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
usz capacity = 16;
|
||||
usz i = 0;
|
||||
String* holder = allocator.new_array(String, capacity);
|
||||
String* holder = allocator::alloc_array(allocator, String, capacity);
|
||||
bool no_more = false;
|
||||
while (!no_more)
|
||||
{
|
||||
@@ -176,7 +176,7 @@ fn String[] String.split(s, String needle, usz max = 0, Allocator* allocator = m
|
||||
if (i == capacity)
|
||||
{
|
||||
capacity *= 2;
|
||||
holder = allocator.realloc(holder, String.sizeof * capacity);
|
||||
holder = allocator::realloc(allocator, holder, String.sizeof * capacity);
|
||||
}
|
||||
holder[i++] = res;
|
||||
}
|
||||
@@ -193,7 +193,7 @@ fn String[] String.split(s, String needle, usz max = 0, Allocator* allocator = m
|
||||
**/
|
||||
fn String[] String.tsplit(s, String needle, usz max = 0)
|
||||
{
|
||||
return s.split(needle, max, mem::temp()) @inline;
|
||||
return s.split(needle, max, allocator::temp()) @inline;
|
||||
}
|
||||
|
||||
fn bool String.contains(s, String needle)
|
||||
@@ -312,19 +312,19 @@ fn usz ZString.len(str)
|
||||
}
|
||||
|
||||
|
||||
fn ZString String.zstr_copy(s, Allocator* allocator = mem::heap())
|
||||
fn ZString String.zstr_copy(s, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
usz len = s.len;
|
||||
char* str = allocator.alloc(len + 1);
|
||||
char* str = allocator::malloc(allocator, len + 1);
|
||||
mem::copy(str, s.ptr, len);
|
||||
str[len] = 0;
|
||||
return (ZString)str;
|
||||
}
|
||||
|
||||
fn String String.concat(s1, String s2, Allocator* allocator = mem::heap())
|
||||
fn String String.concat(s1, String s2, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
usz full_len = s1.len + s2.len;
|
||||
char* str = allocator.alloc(full_len + 1);
|
||||
char* str = allocator::malloc(allocator, full_len + 1);
|
||||
usz s1_len = s1.len;
|
||||
mem::copy(str, s1.ptr, s1_len);
|
||||
mem::copy(str + s1_len, s2.ptr, s2.len);
|
||||
@@ -332,37 +332,37 @@ fn String String.concat(s1, String s2, Allocator* allocator = mem::heap())
|
||||
return (String)str[:full_len];
|
||||
}
|
||||
|
||||
fn String String.tconcat(s1, String s2) => s1.concat(s2, mem::temp());
|
||||
fn String String.tconcat(s1, String s2) => s1.concat(s2, allocator::temp());
|
||||
|
||||
|
||||
fn ZString String.zstr_tcopy(s) => s.zstr_copy(mem::temp()) @inline;
|
||||
fn ZString String.zstr_tcopy(s) => s.zstr_copy(allocator::temp()) @inline;
|
||||
|
||||
fn String String.copy(s, Allocator* allocator = mem::heap())
|
||||
fn String String.copy(s, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
usz len = s.len;
|
||||
char* str = allocator.alloc(len + 1);
|
||||
char* str = allocator::malloc(allocator, len + 1);
|
||||
mem::copy(str, s.ptr, len);
|
||||
str[len] = 0;
|
||||
return (String)str[:len];
|
||||
}
|
||||
|
||||
fn void String.free(&s, Allocator* allocator = mem::heap())
|
||||
fn void String.free(&s, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
if (!s.len) return;
|
||||
allocator.free(s.ptr);
|
||||
allocator::free(allocator, s.ptr);
|
||||
*s = "";
|
||||
}
|
||||
|
||||
fn String String.tcopy(s) => s.copy(mem::temp()) @inline;
|
||||
fn String String.tcopy(s) => s.copy(allocator::temp()) @inline;
|
||||
|
||||
fn String ZString.copy(z, Allocator* allocator = mem::temp())
|
||||
fn String ZString.copy(z, Allocator* allocator = allocator::temp())
|
||||
{
|
||||
return z.str_view().copy(allocator) @inline;
|
||||
}
|
||||
|
||||
fn String ZString.tcopy(z)
|
||||
{
|
||||
return z.str_view().copy(mem::temp()) @inline;
|
||||
return z.str_view().copy(allocator::temp()) @inline;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -371,10 +371,10 @@ fn String ZString.tcopy(z)
|
||||
* @return! UnicodeResult.INVALID_UTF8 "If the string contained an invalid UTF-8 sequence"
|
||||
* @return! AllocationFailure "If allocation of the string fails"
|
||||
**/
|
||||
fn Char16[]! String.to_new_utf16(s, Allocator* allocator = mem::heap())
|
||||
fn Char16[]! String.to_new_utf16(s, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
usz len16 = conv::utf16len_for_utf8(s);
|
||||
Char16* data = allocator.new_array_checked(Char16, len16 + 1)!;
|
||||
Char16* data = allocator::alloc_array_try(allocator, Char16, len16 + 1)!;
|
||||
conv::utf8to16_unsafe(s, data)!;
|
||||
data[len16] = 0;
|
||||
return data[:len16];
|
||||
@@ -388,10 +388,10 @@ fn Char16[]! String.to_new_utf16(s, Allocator* allocator = mem::heap())
|
||||
**/
|
||||
fn Char16[]! String.to_temp_utf16(s)
|
||||
{
|
||||
return s.to_new_utf16(mem::temp());
|
||||
return s.to_new_utf16(allocator::temp());
|
||||
}
|
||||
|
||||
fn WString! String.to_new_wstring(s, Allocator* allocator = mem::heap())
|
||||
fn WString! String.to_new_wstring(s, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
return (WString)s.to_new_utf16(allocator).ptr;
|
||||
}
|
||||
@@ -401,10 +401,10 @@ fn WString! String.to_temp_wstring(s)
|
||||
return (WString)s.to_temp_utf16().ptr;
|
||||
}
|
||||
|
||||
fn Char32[]! String.to_new_utf32(s, Allocator* allocator = mem::heap())
|
||||
fn Char32[]! String.to_new_utf32(s, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
usz codepoints = conv::utf8_codepoints(s);
|
||||
Char32* data = allocator.new_array(Char32, codepoints + 1);
|
||||
Char32* data = allocator::alloc_array_try(allocator, Char32, codepoints + 1)!;
|
||||
conv::utf8to32_unsafe(s, data)!;
|
||||
data[codepoints] = 0;
|
||||
return data[:codepoints];
|
||||
@@ -412,7 +412,7 @@ fn Char32[]! String.to_new_utf32(s, Allocator* allocator = mem::heap())
|
||||
|
||||
fn Char32[]! String.to_temp_utf32(s)
|
||||
{
|
||||
return s.to_new_utf32(mem::temp());
|
||||
return s.to_new_utf32(allocator::temp());
|
||||
}
|
||||
|
||||
fn void String.convert_ascii_to_lower(s)
|
||||
@@ -420,16 +420,16 @@ fn void String.convert_ascii_to_lower(s)
|
||||
foreach (&c : s) if (c.is_upper()) *c += 'a' - 'A';
|
||||
}
|
||||
|
||||
fn String String.new_ascii_to_lower(s, Allocator* allocator = mem::heap())
|
||||
fn String String.new_ascii_to_lower(s, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
String copy = s.copy(allocator);
|
||||
copy.convert_ascii_to_lower();
|
||||
return copy;
|
||||
}
|
||||
|
||||
fn String String.temp_ascii_to_lower(s, Allocator* allocator = mem::heap())
|
||||
fn String String.temp_ascii_to_lower(s, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
return s.new_ascii_to_lower(mem::temp());
|
||||
return s.new_ascii_to_lower(allocator::temp());
|
||||
}
|
||||
|
||||
fn void String.convert_ascii_to_upper(s)
|
||||
@@ -437,7 +437,7 @@ fn void String.convert_ascii_to_upper(s)
|
||||
foreach (&c : s) if (c.is_lower()) *c -= 'a' - 'A';
|
||||
}
|
||||
|
||||
fn String String.new_ascii_to_upper(s, Allocator* allocator = mem::heap())
|
||||
fn String String.new_ascii_to_upper(s, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
String copy = s.copy(allocator);
|
||||
copy.convert_ascii_to_upper();
|
||||
@@ -451,30 +451,30 @@ fn StringIterator String.iterator(s)
|
||||
|
||||
fn String String.temp_ascii_to_upper(s)
|
||||
{
|
||||
return s.new_ascii_to_upper(mem::temp());
|
||||
return s.new_ascii_to_upper(allocator::temp());
|
||||
}
|
||||
|
||||
fn String! new_from_utf32(Char32[] utf32, Allocator* allocator = mem::heap())
|
||||
fn String! new_from_utf32(Char32[] utf32, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
usz len = conv::utf8len_for_utf32(utf32);
|
||||
char* data = allocator.alloc_checked(len + 1)!;
|
||||
defer catch allocator.free(data);
|
||||
char* data = allocator::malloc_try(allocator, len + 1)!;
|
||||
defer catch allocator::free(allocator, data);
|
||||
conv::utf32to8_unsafe(utf32, data);
|
||||
data[len] = 0;
|
||||
return (String)data[:len];
|
||||
}
|
||||
|
||||
fn String! new_from_utf16(Char16[] utf16, Allocator* allocator = mem::heap())
|
||||
fn String! new_from_utf16(Char16[] utf16, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
usz len = conv::utf8len_for_utf16(utf16);
|
||||
char* data = allocator.alloc_checked(len + 1)!;
|
||||
defer catch allocator.free(data);
|
||||
char* data = allocator::malloc_try(allocator, len + 1)!;
|
||||
defer catch allocator::free(allocator, data);
|
||||
conv::utf16to8_unsafe(utf16, data)!;
|
||||
data[len] = 0;
|
||||
return (String)data[:len];
|
||||
}
|
||||
|
||||
fn String! new_from_wstring(WString wstring, Allocator* allocator = mem::heap())
|
||||
fn String! new_from_wstring(WString wstring, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
usz utf16_len;
|
||||
while (wstring[utf16_len] != 0) utf16_len++;
|
||||
@@ -482,8 +482,8 @@ fn String! new_from_wstring(WString wstring, Allocator* allocator = mem::heap())
|
||||
return new_from_utf16(utf16, allocator);
|
||||
}
|
||||
|
||||
fn String! temp_from_wstring(WString wstring) => new_from_wstring(wstring, mem::temp()) @inline;
|
||||
fn String! temp_from_utf16(Char16[] utf16) => new_from_utf16(utf16, mem::temp()) @inline;
|
||||
fn String! temp_from_wstring(WString wstring) => new_from_wstring(wstring, allocator::temp()) @inline;
|
||||
fn String! temp_from_utf16(Char16[] utf16) => new_from_utf16(utf16, allocator::temp()) @inline;
|
||||
|
||||
fn usz String.utf8_codepoints(s)
|
||||
{
|
||||
@@ -495,7 +495,11 @@ fn usz String.utf8_codepoints(s)
|
||||
return len;
|
||||
}
|
||||
|
||||
macro String.to_integer(string, $Type)
|
||||
|
||||
/**
|
||||
* @require (base <= 10 && base > 1) || base == 16 : "Unsupported base"
|
||||
**/
|
||||
macro String.to_integer(string, $Type, int base = 10)
|
||||
{
|
||||
usz len = string.len;
|
||||
usz index = 0;
|
||||
@@ -515,8 +519,8 @@ macro String.to_integer(string, $Type)
|
||||
break;
|
||||
}
|
||||
if (len == index) return NumberConversion.MALFORMED_INTEGER?;
|
||||
$Type base = 10;
|
||||
if (string[index] == '0')
|
||||
$Type base_used = ($Type)base;
|
||||
if (string[index] == '0' && base == 10)
|
||||
{
|
||||
index++;
|
||||
if (index == len) return ($Type)0;
|
||||
@@ -524,15 +528,15 @@ macro String.to_integer(string, $Type)
|
||||
{
|
||||
case 'x':
|
||||
case 'X':
|
||||
base = 16;
|
||||
base_used = 16;
|
||||
index++;
|
||||
case 'b':
|
||||
case 'B':
|
||||
base = 2;
|
||||
base_used = 2;
|
||||
index++;
|
||||
case 'o':
|
||||
case 'O':
|
||||
base = 8;
|
||||
base_used = 8;
|
||||
index++;
|
||||
default:
|
||||
break;
|
||||
@@ -544,21 +548,21 @@ macro String.to_integer(string, $Type)
|
||||
{
|
||||
char c = {|
|
||||
char ch = string[index++];
|
||||
if (base != 16 || ch < 'A') return (char)(ch - '0');
|
||||
if (ch <= 'F') return (char)(ch - 'A');
|
||||
if (base_used != 16 || ch < 'A') return (char)(ch - '0');
|
||||
if (ch <= 'F') return (char)(ch - 'A' + 10);
|
||||
if (ch < 'a') return NumberConversion.MALFORMED_INTEGER?;
|
||||
if (ch > 'f') return NumberConversion.MALFORMED_INTEGER?;
|
||||
return (char)(ch - 'a');
|
||||
return (char)(ch - 'a' + 10);
|
||||
|}!;
|
||||
if (c >= base) return NumberConversion.MALFORMED_INTEGER?;
|
||||
if (c >= base_used) return NumberConversion.MALFORMED_INTEGER?;
|
||||
value = {|
|
||||
if (is_negative)
|
||||
{
|
||||
$Type new_value = value * base - c;
|
||||
$Type new_value = value * base_used - c;
|
||||
if (new_value > value) return NumberConversion.INTEGER_OVERFLOW?;
|
||||
return new_value;
|
||||
}
|
||||
$Type new_value = value * base + c;
|
||||
$Type new_value = value * base_used + c;
|
||||
if (new_value < value) return NumberConversion.INTEGER_OVERFLOW?;
|
||||
return new_value;
|
||||
|}!;
|
||||
@@ -566,17 +570,17 @@ macro String.to_integer(string, $Type)
|
||||
return value;
|
||||
}
|
||||
|
||||
fn int128! String.to_int128(s) => s.to_integer(int128);
|
||||
fn long! String.to_long(s) => s.to_integer(long);
|
||||
fn int! String.to_int(s) => s.to_integer(int);
|
||||
fn short! String.to_short(s) => s.to_integer(short);
|
||||
fn ichar! String.to_ichar(s) => s.to_integer(ichar);
|
||||
fn int128! String.to_int128(s, int base = 10) => s.to_integer(int128, base);
|
||||
fn long! String.to_long(s, int base = 10) => s.to_integer(long, base);
|
||||
fn int! String.to_int(s, int base = 10) => s.to_integer(int, base);
|
||||
fn short! String.to_short(s, int base = 10) => s.to_integer(short, base);
|
||||
fn ichar! String.to_ichar(s, int base = 10) => s.to_integer(ichar, base);
|
||||
|
||||
fn uint128! String.to_uint128(s) => s.to_integer(uint128);
|
||||
fn ulong! String.to_ulong(s) => s.to_integer(ulong);
|
||||
fn uint! String.to_uint(s) => s.to_integer(uint);
|
||||
fn ushort! String.to_ushort(s) => s.to_integer(ushort);
|
||||
fn char! String.to_uchar(s) => s.to_integer(char);
|
||||
fn uint128! String.to_uint128(s, int base = 10) => s.to_integer(uint128, base);
|
||||
fn ulong! String.to_ulong(s, int base = 10) => s.to_integer(ulong, base);
|
||||
fn uint! String.to_uint(s, int base = 10) => s.to_integer(uint, base);
|
||||
fn ushort! String.to_ushort(s, int base = 10) => s.to_integer(ushort, base);
|
||||
fn char! String.to_uchar(s, int base = 10) => s.to_integer(char, base);
|
||||
|
||||
fn double! String.to_double(s) => s.to_real(double);
|
||||
fn float! String.to_float(s) => s.to_real(float);
|
||||
|
||||
@@ -13,12 +13,12 @@ fn void CsvReader.init(&self, InStream* stream, String separator = ",")
|
||||
self.separator = separator;
|
||||
}
|
||||
|
||||
fn String[]! CsvReader.read_new_row(self, Allocator* allocator = mem::heap())
|
||||
fn String[]! CsvReader.read_new_row(self, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
return self.read_new_row_with_allocator(mem::temp()) @inline;
|
||||
return self.read_new_row_with_allocator(allocator::temp()) @inline;
|
||||
}
|
||||
|
||||
fn String[]! CsvReader.read_new_row_with_allocator(self, Allocator* allocator = mem::heap())
|
||||
fn String[]! CsvReader.read_new_row_with_allocator(self, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
@pool(allocator)
|
||||
{
|
||||
@@ -28,7 +28,7 @@ fn String[]! CsvReader.read_new_row_with_allocator(self, Allocator* allocator =
|
||||
|
||||
fn String[]! CsvReader.read_temp_row(self)
|
||||
{
|
||||
return self.read_new_row_with_allocator(mem::temp()) @inline;
|
||||
return self.read_new_row_with_allocator(allocator::temp()) @inline;
|
||||
}
|
||||
|
||||
fn void! CsvReader.skip_row(self) @maydiscard
|
||||
|
||||
@@ -15,7 +15,7 @@ fault JsonParsingError
|
||||
INVALID_NUMBER,
|
||||
}
|
||||
|
||||
fn Object*! parse(InStream* s, Allocator* allocator = mem::heap())
|
||||
fn Object*! parse(InStream* s, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
JsonContext context = { .last_string = dstring::new_with_capacity(64, allocator), .stream = s, .allocator = allocator };
|
||||
defer context.last_string.free();
|
||||
|
||||
@@ -7,7 +7,7 @@ struct File (InStream, OutStream)
|
||||
}
|
||||
|
||||
module std::io::file;
|
||||
import libc;
|
||||
import libc, std::io::path, std::io::os;
|
||||
|
||||
fn File! open(String filename, String mode)
|
||||
{
|
||||
@@ -161,14 +161,14 @@ fn char[]! load_buffer(String filename, char[] buffer)
|
||||
|
||||
}
|
||||
|
||||
fn char[]! load_new(String filename, Allocator* allocator = mem::heap())
|
||||
fn char[]! load_new(String filename, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
File file = open(filename, "rb")!;
|
||||
defer (void)file.close();
|
||||
usz len = file.seek(0, END)!;
|
||||
file.seek(0, SET)!;
|
||||
char* data = allocator.alloc_checked(len)!;
|
||||
defer catch allocator.free(data);
|
||||
char* data = allocator::malloc_try(allocator, len)!;
|
||||
defer catch allocator::free(allocator, data);
|
||||
usz read = 0;
|
||||
while (read < len)
|
||||
{
|
||||
@@ -179,7 +179,7 @@ fn char[]! load_new(String filename, Allocator* allocator = mem::heap())
|
||||
|
||||
fn char[]! load_temp(String filename)
|
||||
{
|
||||
return load_new(filename, mem::temp());
|
||||
return load_new(filename, allocator::temp());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -98,9 +98,9 @@ fn usz! Formatter.print_with_function(&self, Printable* arg)
|
||||
self.width = old_width;
|
||||
self.prec = old_prec;
|
||||
}
|
||||
@pool()
|
||||
@stack_mem(1024; Allocator* mem)
|
||||
{
|
||||
return self.out_substr(arg.to_new_string(mem::temp()));
|
||||
return self.out_substr(arg.to_new_string(mem));
|
||||
};
|
||||
}
|
||||
return SearchResult.MISSING?;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
module std::io;
|
||||
import std::math;
|
||||
|
||||
const char[16] XDIGITS_H = "0123456789ABCDEF";
|
||||
const char[16] XDIGITS_L = "0123456789abcdef";
|
||||
|
||||
@@ -49,7 +49,7 @@ fault IoError
|
||||
* @param stream
|
||||
* @require @is_instream(stream)
|
||||
**/
|
||||
macro String! readline(stream = io::stdin(), Allocator* allocator = mem::heap())
|
||||
macro String! readline(stream = io::stdin(), Allocator* allocator = allocator::heap())
|
||||
{
|
||||
bool $is_stream = @typeid(stream) == InStream*.typeid;
|
||||
$if $is_stream:
|
||||
@@ -84,7 +84,7 @@ macro String! readline(stream = io::stdin(), Allocator* allocator = mem::heap())
|
||||
};
|
||||
}
|
||||
|
||||
macro String! treadline(stream = io::stdin()) => readline(stream, mem::temp()) @inline;
|
||||
macro String! treadline(stream = io::stdin()) => readline(stream, allocator::temp()) @inline;
|
||||
|
||||
/**
|
||||
* @require @is_outstream(out) "The output must implement OutStream"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
module std::io::os;
|
||||
import libc;
|
||||
import std::io::path, libc, std::os;
|
||||
|
||||
macro void! native_chdir(Path path)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
module std::io::os;
|
||||
import libc;
|
||||
import libc, std::os, std::io;
|
||||
|
||||
fn void! native_stat(Stat* stat, String path) @if(env::DARWIN || env::LINUX)
|
||||
{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
module std::io::os;
|
||||
import libc;
|
||||
import libc, std::os;
|
||||
|
||||
macro String! getcwd(Allocator* allocator = mem::heap())
|
||||
macro String! getcwd(Allocator* allocator = allocator::heap())
|
||||
{
|
||||
$switch
|
||||
$case env::WIN32:
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
module std::io::file::os @if(env::POSIX);
|
||||
module std::io::os @if(env::POSIX);
|
||||
import std::io, std::os;
|
||||
|
||||
fn PathList! native_ls(Path dir, bool no_dirs, bool no_symlinks, String mask, Allocator* allocator)
|
||||
{
|
||||
PathList list;
|
||||
list.init_new(.allocator = allocator);
|
||||
list.new_init(.allocator = allocator);
|
||||
DIRPtr directory = posix::opendir(dir.str_view() ? dir.as_zstr() : (ZString)".");
|
||||
defer if (directory) posix::closedir(directory);
|
||||
if (!directory) return (path::is_dir(dir) ? IoError.CANNOT_READ_DIR : IoError.FILE_NOT_DIR)?;
|
||||
@@ -21,11 +22,12 @@ fn PathList! native_ls(Path dir, bool no_dirs, bool no_symlinks, String mask, Al
|
||||
}
|
||||
|
||||
module std::io::os @if(env::WIN32);
|
||||
import std::time, std::os, std::io;
|
||||
|
||||
fn PathList! native_ls(Path dir, bool no_dirs, bool no_symlinks, String mask, Allocator* allocator)
|
||||
{
|
||||
PathList list;
|
||||
list.init_new(.allocator = allocator);
|
||||
list.new_init(.allocator = allocator);
|
||||
|
||||
@pool(allocator)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
module std::io::file::os @if(env::POSIX);
|
||||
import libc;
|
||||
module std::io::os @if(env::POSIX);
|
||||
import std::io, std::os, libc;
|
||||
|
||||
/**
|
||||
* @require dir.str_view()
|
||||
@@ -33,6 +33,7 @@ fn void! native_rmtree(Path dir)
|
||||
}
|
||||
|
||||
module std::io::os @if(env::WIN32);
|
||||
import std::io, std::time, std::os;
|
||||
|
||||
fn void! native_rmtree(Path path)
|
||||
{
|
||||
@@ -46,7 +47,7 @@ fn void! native_rmtree(Path path)
|
||||
{
|
||||
@pool()
|
||||
{
|
||||
String filename = string::new_from_wstring((WString)&find_data.cFileName, mem::temp())!;
|
||||
String filename = string::new_from_wstring((WString)&find_data.cFileName, allocator::temp())!;
|
||||
if (filename == "." || filename == "..") continue;
|
||||
Path file_path = path.tappend(filename)!;
|
||||
if (find_data.dwFileAttributes & win32::FILE_ATTRIBUTE_DIRECTORY)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
module std::io::os @if(env::LIBC);
|
||||
import std::io::path, std::os;
|
||||
|
||||
fn Path! native_temp_directory(Allocator* allocator = mem::heap()) @if(!env::WIN32)
|
||||
fn Path! native_temp_directory(Allocator* allocator = allocator::heap()) @if(!env::WIN32)
|
||||
{
|
||||
foreach (String env : { "TMPDIR", "TMP", "TEMP", "TEMPDIR" })
|
||||
{
|
||||
@@ -10,13 +11,13 @@ fn Path! native_temp_directory(Allocator* allocator = mem::heap()) @if(!env::WIN
|
||||
return path::new("/tmp", allocator);
|
||||
}
|
||||
|
||||
fn Path! native_temp_directory(Allocator* allocator = mem::heap()) @if(env::WIN32)
|
||||
fn Path! native_temp_directory(Allocator* allocator = allocator::heap()) @if(env::WIN32)
|
||||
{
|
||||
@pool(allocator)
|
||||
{
|
||||
Win32_DWORD len = win32::getTempPathW(0, null);
|
||||
if (!len) return IoError.GENERAL_ERROR?;
|
||||
Char16[] buff = mem::temp_array(Char16, len + (usz)1);
|
||||
Char16[] buff = mem::temp_alloc_array(Char16, len + (usz)1);
|
||||
if (!win32::getTempPathW(len, buff)) return IoError.GENERAL_ERROR?;
|
||||
return path::new(string::temp_from_utf16(buff[:len]), allocator);
|
||||
};
|
||||
@@ -24,7 +25,7 @@ fn Path! native_temp_directory(Allocator* allocator = mem::heap()) @if(env::WIN3
|
||||
|
||||
module std::io::os @if(env::NO_LIBC);
|
||||
|
||||
macro Path! native_temp_directory(Allocator* allocator = mem::heap())
|
||||
macro Path! native_temp_directory(Allocator* allocator = allocator::heap())
|
||||
{
|
||||
return IoError.UNSUPPORTED_OPERATION?;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
module std::io::path;
|
||||
import std::collections::list;
|
||||
import std::collections::list, std::io::os;
|
||||
|
||||
const PathEnv DEFAULT_PATH_ENV = env::WIN32 ? PathEnv.WIN32 : PathEnv.POSIX;
|
||||
const char PREFERRED_SEPARATOR_WIN32 = '\\';
|
||||
@@ -26,11 +26,11 @@ enum PathEnv
|
||||
POSIX
|
||||
}
|
||||
|
||||
fn Path! getcwd(Allocator* allocator = mem::heap())
|
||||
fn Path! getcwd(Allocator* allocator = allocator::heap())
|
||||
{
|
||||
@pool(allocator)
|
||||
{
|
||||
return new(os::getcwd(mem::temp()), allocator);
|
||||
return new(os::getcwd(allocator::temp()), allocator);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -38,9 +38,9 @@ fn bool is_dir(Path path) => os::native_is_dir(path.str_view());
|
||||
fn bool is_file(Path path) => os::native_is_file(path.str_view());
|
||||
fn usz! file_size(Path path) => os::native_file_size(path.str_view());
|
||||
fn bool exists(Path path) => os::native_file_or_dir_exists(path.str_view());
|
||||
fn Path! tgetcwd() => getcwd(mem::temp()) @inline;
|
||||
fn Path! tgetcwd() => getcwd(allocator::temp()) @inline;
|
||||
fn void! chdir(Path path) => os::native_chdir(path) @inline;
|
||||
fn Path! temp_directory(Allocator* allocator = mem::heap()) => os::native_temp_directory(allocator);
|
||||
fn Path! temp_directory(Allocator* allocator = allocator::heap()) => os::native_temp_directory(allocator);
|
||||
fn void! delete(Path path) => os::native_remove(path.str_view()) @inline;
|
||||
|
||||
macro bool is_separator(char c, PathEnv path_env = DEFAULT_PATH_ENV)
|
||||
@@ -58,7 +58,7 @@ macro bool is_win32_separator(char c)
|
||||
return c == '/' || c == '\\';
|
||||
}
|
||||
|
||||
fn PathList! ls(Path dir, bool no_dirs = false, bool no_symlinks = false, String mask = "", Allocator* allocator = mem::heap())
|
||||
fn PathList! ls(Path dir, bool no_dirs = false, bool no_symlinks = false, String mask = "", Allocator* allocator = allocator::heap())
|
||||
{
|
||||
$if $defined(os::native_ls):
|
||||
return os::native_ls(dir, no_dirs, no_symlinks, mask, allocator);
|
||||
@@ -105,17 +105,17 @@ fn void! rmtree(Path path)
|
||||
$endif
|
||||
}
|
||||
|
||||
fn Path! new(String path, Allocator* allocator = mem::heap(), PathEnv path_env = DEFAULT_PATH_ENV)
|
||||
fn Path! new(String path, Allocator* allocator = allocator::heap(), PathEnv path_env = DEFAULT_PATH_ENV)
|
||||
{
|
||||
return { normalize(path.copy(allocator), path_env), path_env };
|
||||
}
|
||||
|
||||
fn Path! temp_new(String path, PathEnv path_env = DEFAULT_PATH_ENV)
|
||||
{
|
||||
return new(path, mem::temp(), path_env);
|
||||
return new(path, allocator::temp(), path_env);
|
||||
}
|
||||
|
||||
fn Path! new_win32_wstring(WString path, Allocator* allocator = mem::heap())
|
||||
fn Path! new_win32_wstring(WString path, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
@pool(allocator)
|
||||
{
|
||||
@@ -123,12 +123,12 @@ fn Path! new_win32_wstring(WString path, Allocator* allocator = mem::heap())
|
||||
};
|
||||
}
|
||||
|
||||
fn Path! new_windows(String path, Allocator* allocator = mem::heap())
|
||||
fn Path! new_windows(String path, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
return new(path, allocator, WIN32);
|
||||
}
|
||||
|
||||
fn Path! new_posix(String path, Allocator* allocator = mem::heap())
|
||||
fn Path! new_posix(String path, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
return new(path, allocator, POSIX);
|
||||
}
|
||||
@@ -143,7 +143,7 @@ fn bool Path.equals(self, Path p2)
|
||||
*
|
||||
* @param [in] filename
|
||||
**/
|
||||
fn Path! Path.append(self, String filename, Allocator* allocator = mem::heap())
|
||||
fn Path! Path.append(self, String filename, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
if (!self.path_string.len) return new(filename, allocator, self.env)!;
|
||||
assert(!is_separator(self.path_string[^1], self.env));
|
||||
@@ -158,7 +158,7 @@ fn Path! Path.append(self, String filename, Allocator* allocator = mem::heap())
|
||||
};
|
||||
}
|
||||
|
||||
fn Path! Path.tappend(self, String filename) => self.append(filename, mem::temp());
|
||||
fn Path! Path.tappend(self, String filename) => self.append(filename, allocator::temp());
|
||||
|
||||
fn usz Path.start_of_base_name(self) @local
|
||||
{
|
||||
@@ -179,13 +179,13 @@ fn bool! Path.is_absolute(self)
|
||||
return path_start < path_str.len && is_separator(path_str[path_start], self.env);
|
||||
}
|
||||
|
||||
fn Path! Path.absolute(self, Allocator* allocator = mem::heap())
|
||||
fn Path! Path.absolute(self, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
String path_str = self.str_view();
|
||||
if (!path_str.len) path_str = ".";
|
||||
if (path_str == ".")
|
||||
{
|
||||
String cwd = os::getcwd(mem::temp())!;
|
||||
String cwd = os::getcwd(allocator::temp())!;
|
||||
return new(cwd, allocator, self.env);
|
||||
}
|
||||
switch (self.env)
|
||||
@@ -196,7 +196,7 @@ fn Path! Path.absolute(self, Allocator* allocator = mem::heap())
|
||||
case POSIX:
|
||||
if (path_str[0] == PREFERRED_SEPARATOR_POSIX) return self;
|
||||
}
|
||||
String cwd = os::getcwd(mem::temp())!;
|
||||
String cwd = os::getcwd(allocator::temp())!;
|
||||
return Path{ cwd, self.env }.append(path_str, allocator)!;
|
||||
}
|
||||
|
||||
@@ -459,7 +459,7 @@ fn usz! Path.to_format(&self, Formatter* formatter) @dynamic
|
||||
return formatter.print(self.str_view());
|
||||
}
|
||||
|
||||
fn String Path.to_new_string(&self, Allocator* allocator = mem::heap()) @dynamic
|
||||
fn String Path.to_new_string(&self, Allocator* allocator = allocator::heap()) @dynamic
|
||||
{
|
||||
return self.str_view().copy(allocator);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
module std::io;
|
||||
import std::math;
|
||||
|
||||
interface InStream
|
||||
{
|
||||
@@ -142,12 +143,12 @@ fn usz! copy_to(InStream* in, OutStream* dst, char[] buffer = {})
|
||||
$case NORMAL:
|
||||
@pool()
|
||||
{
|
||||
return copy_through_buffer(in, dst, mem::temp_array(char, 4096));
|
||||
return copy_through_buffer(in, dst, mem::temp_alloc_array(char, 4096));
|
||||
};
|
||||
$case SMALL:
|
||||
@pool()
|
||||
{
|
||||
return copy_through_buffer(in, dst, mem::temp_array(char, 1024));
|
||||
return copy_through_buffer(in, dst, mem::temp_alloc_array(char, 1024));
|
||||
};
|
||||
$case TINY:
|
||||
$case NONE:
|
||||
|
||||
@@ -16,7 +16,17 @@ struct ByteBuffer (InStream, OutStream)
|
||||
* max_read defines how many bytes might be kept before its internal buffer is shrinked.
|
||||
* @require self.bytes.len == 0 "Buffer already initialized."
|
||||
**/
|
||||
fn ByteBuffer*! ByteBuffer.init_new(&self, usz max_read, usz initial_capacity = 16, Allocator* allocator = mem::heap())
|
||||
fn ByteBuffer*! ByteBuffer.init_new(&self, usz max_read, usz initial_capacity = 16, Allocator* allocator = allocator::heap()) @deprecated("Replaced by new_init")
|
||||
{
|
||||
return self.new_init(max_read, initial_capacity, allocator) @inline;
|
||||
}
|
||||
|
||||
/**
|
||||
* ByteBuffer provides a streamable read/write buffer.
|
||||
* max_read defines how many bytes might be kept before its internal buffer is shrinked.
|
||||
* @require self.bytes.len == 0 "Buffer already initialized."
|
||||
**/
|
||||
fn ByteBuffer*! ByteBuffer.new_init(&self, usz max_read, usz initial_capacity = 16, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
*self = { .allocator = allocator, .max_read = max_read };
|
||||
initial_capacity = max(initial_capacity, 16);
|
||||
@@ -24,9 +34,14 @@ fn ByteBuffer*! ByteBuffer.init_new(&self, usz max_read, usz initial_capacity =
|
||||
return self;
|
||||
}
|
||||
|
||||
fn ByteBuffer*! ByteBuffer.init_temp(&self, usz max_read, usz initial_capacity = 16)
|
||||
fn ByteBuffer*! ByteBuffer.init_temp(&self, usz max_read, usz initial_capacity = 16) @deprecated("Replaced by temp_init")
|
||||
{
|
||||
return self.init_new(max_read, initial_capacity, mem::temp());
|
||||
return self.temp_init(max_read, initial_capacity) @inline;
|
||||
}
|
||||
|
||||
fn ByteBuffer*! ByteBuffer.temp_init(&self, usz max_read, usz initial_capacity = 16)
|
||||
{
|
||||
return self.new_init(max_read, initial_capacity, allocator::temp());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -41,7 +56,7 @@ fn ByteBuffer*! ByteBuffer.init_with_buffer(&self, char[] buf)
|
||||
|
||||
fn void ByteBuffer.free(&self)
|
||||
{
|
||||
if (self.allocator) self.allocator.free(self.bytes);
|
||||
if (self.allocator) allocator::free(self.allocator, self.bytes);
|
||||
*self = {};
|
||||
}
|
||||
|
||||
@@ -131,7 +146,7 @@ fn usz! ByteBuffer.available(&self) @inline @dynamic
|
||||
fn void! ByteBuffer.grow(&self, usz n)
|
||||
{
|
||||
n = math::next_power_of_2(n);
|
||||
char* p = self.allocator.realloc_aligned(self.bytes, n, .alignment = char.alignof)!;
|
||||
char* p = allocator::realloc_aligned(self.allocator, self.bytes, n, .alignment = char.alignof)!;
|
||||
self.bytes = p[:n];
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
module std::io;
|
||||
import std::math;
|
||||
|
||||
struct ByteWriter (OutStream)
|
||||
{
|
||||
@@ -13,20 +14,41 @@ struct ByteWriter (OutStream)
|
||||
* @require self.bytes.len == 0 "Init may not run on on already initialized data"
|
||||
* @ensure (bool)allocator, self.index == 0
|
||||
**/
|
||||
fn ByteWriter* ByteWriter.init_new(&self, Allocator* allocator = mem::heap())
|
||||
fn ByteWriter* ByteWriter.new_init(&self, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
*self = { .bytes = {}, .allocator = allocator };
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [&inout] self
|
||||
* @param [&inout] allocator
|
||||
* @require self.bytes.len == 0 "Init may not run on on already initialized data"
|
||||
* @ensure (bool)allocator, self.index == 0
|
||||
**/
|
||||
fn ByteWriter* ByteWriter.init_new(&self, Allocator* allocator = allocator::heap()) @deprecated("Replaced by new_init")
|
||||
{
|
||||
return self.new_init(allocator) @inline;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [&inout] self
|
||||
* @require self.bytes.len == 0 "Init may not run on on already initialized data"
|
||||
* @ensure self.index == 0
|
||||
**/
|
||||
fn ByteWriter* ByteWriter.init_temp(&self)
|
||||
fn ByteWriter* ByteWriter.temp_init(&self)
|
||||
{
|
||||
return self.init_new(mem::temp());
|
||||
return self.new_init(allocator::temp()) @inline;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param [&inout] self
|
||||
* @require self.bytes.len == 0 "Init may not run on on already initialized data"
|
||||
* @ensure self.index == 0
|
||||
**/
|
||||
fn ByteWriter* ByteWriter.init_temp(&self) @deprecated("Replaced by temp_init")
|
||||
{
|
||||
return self.temp_init() @inline;
|
||||
}
|
||||
|
||||
fn ByteWriter* ByteWriter.init_with_buffer(&self, char[] data)
|
||||
@@ -38,7 +60,7 @@ fn ByteWriter* ByteWriter.init_with_buffer(&self, char[] data)
|
||||
fn void! ByteWriter.destroy(&self) @dynamic
|
||||
{
|
||||
if (!self.allocator) return;
|
||||
if (void* ptr = self.bytes.ptr) self.allocator.free(ptr);
|
||||
if (void* ptr = self.bytes.ptr) allocator::free(self.allocator, ptr);
|
||||
*self = { };
|
||||
}
|
||||
|
||||
@@ -53,7 +75,7 @@ fn void! ByteWriter.ensure_capacity(&self, usz len) @inline
|
||||
if (!self.allocator) return IoError.OUT_OF_SPACE?;
|
||||
if (len < 16) len = 16;
|
||||
usz new_capacity = math::next_power_of_2(len);
|
||||
char* new_ptr = self.allocator.realloc_checked(self.bytes.ptr, new_capacity)!;
|
||||
char* new_ptr = allocator::realloc_try(self.allocator, self.bytes.ptr, new_capacity)!;
|
||||
self.bytes = new_ptr[:new_capacity];
|
||||
}
|
||||
|
||||
|
||||
@@ -99,6 +99,8 @@ def Quaternionf = Quaternion(<float>);
|
||||
def Quaternion = Quaternion(<double>);
|
||||
def quaternionf_identity = quaternion::identity(<float>);
|
||||
def quaternion_identity = quaternion::identity(<double>);
|
||||
def QUATERNION_IDENTITY = quaternion::IDENTITY(<double>);
|
||||
def QUATERNIONF_IDENTITY = quaternion::IDENTITY(<float>);
|
||||
|
||||
def Matrix2f = Matrix2x2(<float>);
|
||||
def Matrix2 = Matrix2x2(<double>);
|
||||
|
||||
@@ -401,13 +401,13 @@ fn Matrix4x4 ortho(Real left, Real right, Real top, Real bottom, Real near, Real
|
||||
fn Matrix4x4 perspective(Real fov, Real aspect_ratio, Real near, Real far)
|
||||
{
|
||||
Real f = (Real)math::tan(math::PI * 0.5 - 0.5 * fov);
|
||||
Real rangeInv = (Real)1.0 / (near - far);
|
||||
|
||||
Real range_inv = (Real)1.0 / (near - far);
|
||||
|
||||
return {
|
||||
f / aspect_ratio, 0, 0, 0,
|
||||
0, f, 0, 0,
|
||||
0, 0, (near + far) * rangeInv, -1,
|
||||
0, 0, near * far * rangeInv * 2, 0,
|
||||
0, 0, (near + far) * range_inv, near * far * range_inv * 2,
|
||||
0, 0, -1, 0,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ union Quaternion
|
||||
}
|
||||
|
||||
macro Quaternion identity() => { 0, 0, 0, 1 };
|
||||
const Quaternion IDENTITY = { 0, 0, 0, 1 };
|
||||
macro Quaternion Quaternion.add(Quaternion a, Quaternion b) => Quaternion { .v = a.v + b.v };
|
||||
macro Quaternion Quaternion.add_each(Quaternion a, Real b) => Quaternion { .v = a.v + b };
|
||||
macro Quaternion Quaternion.sub(Quaternion a, Quaternion b) => Quaternion { .v = a.v - b.v };
|
||||
@@ -69,30 +70,33 @@ fn Quaternion Quaternion.mul(a, Quaternion b)
|
||||
|
||||
macro into_matrix(Quaternion* q, $Type) @private
|
||||
{
|
||||
$Type result = { .m = { [0] = 1, [5] = 1, [10] = 1, [15] = 1 } };
|
||||
Quaternion norm = q.normalize();
|
||||
Quaternion q_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;
|
||||
var x = q_norm.i;
|
||||
var y = q_norm.j;
|
||||
var z = q_norm.k;
|
||||
var w = q_norm.l;
|
||||
|
||||
result.m00 = 1 - 2*(jj + kk);
|
||||
result.m01 = 2*(ik + lk);
|
||||
result.m02 = 2*(ij - lj);
|
||||
var xx = x + x;
|
||||
var yy = y + y;
|
||||
var zz = z + z;
|
||||
|
||||
result.m10 = 2*(ij - lk);
|
||||
result.m11 = 1 - 2*(ii + kk);
|
||||
result.m12 = 2*(jk + li);
|
||||
var xxx = xx * x;
|
||||
var xxy = xx * y;
|
||||
var xxz = xx * z;
|
||||
|
||||
result.m20 = 2*(ik + lj);
|
||||
result.m21 = 2*(jk - li);
|
||||
result.m22 = 1 - 2*(ii + jj);
|
||||
var yyy = yy * y;
|
||||
var yyz = yy * z;
|
||||
var zzz = zz * z;
|
||||
|
||||
return result;
|
||||
var yyw = yy * w;
|
||||
var zzw = zz * w;
|
||||
var xxw = xx * w;
|
||||
|
||||
return $Type {
|
||||
1 - yyy - zzz, xxy - zzw, xxz + yyw, 0,
|
||||
xxy + zzw, 1 - xxx - zzz, yyz - xxw, 0,
|
||||
xxz - yyw, yyz + zzw, 1.0 - xxx - yyy, 0,
|
||||
0, 0, 0, 1,
|
||||
};
|
||||
}
|
||||
@@ -203,10 +203,10 @@ macro matrix_look_at($Type, eye, target, up) @private
|
||||
var vy = vz.cross(vx);
|
||||
|
||||
return $Type {
|
||||
vx[0], vy[0], vz[0], 0,
|
||||
vx[1], vy[1], vz[1], 0,
|
||||
vx[2], vy[2], vz[2], 0,
|
||||
- vx.dot(eye), - vy.dot(eye), - vz.dot(eye), 1
|
||||
vx[0], vx[1], vx[2], - vx.dot(eye),
|
||||
vy[0], vy[1], vy[2], - vy.dot(eye),
|
||||
vz[0], vz[1], vz[2], - vz.dot(eye),
|
||||
0, 0, 0, 1
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
module std::math::random;
|
||||
import std::hash::fnv32a;
|
||||
import std::hash::fnv32a, std::time;
|
||||
|
||||
const ODD_PHI64 @local = 0x9e3779b97f4a7c15;
|
||||
const MUL_MCG64 @local = 0xf1357aea2e62a9c5;
|
||||
@@ -26,7 +26,7 @@ fn void seeder(char[] input, char[] out_buffer)
|
||||
usz out_chars = out_buffer.len;
|
||||
@pool()
|
||||
{
|
||||
ulong[] words = mem::temp_array(ulong, (out_chars + 7) / 8);
|
||||
ulong[] words = mem::temp_alloc_array(ulong, (out_chars + 7) / 8);
|
||||
words[..] = ODD_PHI64;
|
||||
usz words_len_2 = words.len * 2;
|
||||
|
||||
@@ -85,8 +85,8 @@ fn char[8 * 4] entropy()
|
||||
hash(&entropy),
|
||||
random_int,
|
||||
hash(clock::now()),
|
||||
hash(&DString.init_new),
|
||||
hash(mem::heap())
|
||||
hash(&DString.new_init),
|
||||
hash(allocator::heap())
|
||||
};
|
||||
return bitcast(entropy_data, char[8 * 4]);
|
||||
}
|
||||
@@ -56,7 +56,7 @@ fn usz! InetAddress.to_format(InetAddress* addr, Formatter* formatter) @dynamic
|
||||
return formatter.printf("%d.%d.%d.%d", addr.ipv4.a, addr.ipv4.b, addr.ipv4.c, addr.ipv4.d)!;
|
||||
}
|
||||
|
||||
fn String InetAddress.to_new_string(InetAddress* addr, Allocator* allocator = mem::heap()) @dynamic
|
||||
fn String InetAddress.to_new_string(InetAddress* addr, Allocator* allocator = allocator::heap()) @dynamic
|
||||
{
|
||||
if (addr.is_ipv6)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
module std::net;
|
||||
import std::io;
|
||||
|
||||
fault NetError
|
||||
{
|
||||
@@ -56,7 +57,7 @@ fn uint! ipv4toint(String s)
|
||||
return out;
|
||||
}
|
||||
|
||||
fn String! int_to_new_ipv4(uint val, Allocator* allocator = mem::heap())
|
||||
fn String! int_to_new_ipv4(uint val, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
char[3 * 4 + 3 + 1] buffer;
|
||||
String res = (String)io::bprintf(&buffer, "%d.%d.%d.%d", val >> 24, (val >> 16) & 0xFF, (val >> 8) & 0xFF, val & 0xFF)!;
|
||||
@@ -65,5 +66,5 @@ fn String! int_to_new_ipv4(uint val, Allocator* allocator = mem::heap())
|
||||
|
||||
fn String! int_to_temp_ipv4(uint val)
|
||||
{
|
||||
return int_to_new_ipv4(val, mem::temp());
|
||||
return int_to_new_ipv4(val, allocator::temp());
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
module std::net::os @if(env::POSIX && SUPPORTS_INET);
|
||||
import libc;
|
||||
import std::io, libc;
|
||||
|
||||
const int F_GETFL = 3;
|
||||
const int F_SETFL = 4;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
module std::net::os @if(env::WIN32);
|
||||
import std::os::win32;
|
||||
import libc;
|
||||
import std::os, std::io, libc;
|
||||
|
||||
const AIFamily PLATFORM_AF_IPX = 6;
|
||||
const AIFamily PLATFORM_AF_APPLETALK = 16;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
module std::net @if(os::SUPPORTS_INET);
|
||||
import std::io;
|
||||
import libc;
|
||||
import std::io, std::os, std::time, libc;
|
||||
|
||||
struct Socket (InStream, OutStream)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
module std::net @if(os::SUPPORTS_INET);
|
||||
import libc;
|
||||
import std::time, libc, std::os;
|
||||
|
||||
macro apply_sockoptions(sockfd, options) @private
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module std::net::tcp @if(os::SUPPORTS_INET);
|
||||
import std::net @public;
|
||||
import libc;
|
||||
import std::time, libc;
|
||||
|
||||
distinct TcpSocket = inline Socket;
|
||||
distinct TcpServerSocket = inline Socket;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
module std::os::backtrace;
|
||||
import std::collections::list;
|
||||
import std::collections::list, std::os, std::io;
|
||||
|
||||
fault BacktraceFault
|
||||
{
|
||||
@@ -48,9 +48,9 @@ fn usz! Backtrace.to_format(&self, Formatter* formatter) @dynamic
|
||||
fn void Backtrace.free(&self)
|
||||
{
|
||||
if (!self.allocator) return;
|
||||
self.allocator.free(self.function);
|
||||
self.allocator.free(self.object_file);
|
||||
self.allocator.free(self.file);
|
||||
allocator::free(self.allocator, self.function);
|
||||
allocator::free(self.allocator, self.object_file);
|
||||
allocator::free(self.allocator, self.file);
|
||||
}
|
||||
|
||||
fn Backtrace* Backtrace.init(&self, uptr offset, String function, String object_file, String file = "", uint line = 0, Allocator* allocator)
|
||||
|
||||
@@ -2,14 +2,14 @@
|
||||
// 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::os::env;
|
||||
import libc;
|
||||
import std::io::path, libc, std::os;
|
||||
|
||||
/**
|
||||
* @param [in] name
|
||||
* @require name.len > 0
|
||||
* @return! SearchResult.MISSING
|
||||
**/
|
||||
fn String! get_var(String name, Allocator* allocator = mem::heap())
|
||||
fn String! get_var(String name, Allocator* allocator = allocator::heap())
|
||||
{
|
||||
@pool(allocator)
|
||||
{
|
||||
@@ -38,7 +38,7 @@ fn String! get_var(String name, Allocator* allocator = mem::heap())
|
||||
|
||||
fn String! get_var_temp(String name)
|
||||
{
|
||||
return get_var(name, mem::temp());
|
||||
return get_var(name, allocator::temp());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -72,7 +72,7 @@ fn bool set_var(String name, String value, bool overwrite = true)
|
||||
/**
|
||||
* Returns the current user's home directory.
|
||||
**/
|
||||
fn String! get_home_dir(Allocator* using = mem::heap())
|
||||
fn String! get_home_dir(Allocator* using = allocator::heap())
|
||||
{
|
||||
String home;
|
||||
$if !env::WIN32:
|
||||
@@ -86,7 +86,7 @@ fn String! get_home_dir(Allocator* using = mem::heap())
|
||||
/**
|
||||
* Returns the current user's config directory.
|
||||
**/
|
||||
fn Path! get_config_dir(Allocator* allocator = mem::heap())
|
||||
fn Path! get_config_dir(Allocator* allocator = allocator::heap())
|
||||
{
|
||||
@pool(allocator)
|
||||
{
|
||||
@@ -126,7 +126,7 @@ fn bool clear_var(String name)
|
||||
};
|
||||
}
|
||||
|
||||
fn String! executable_path(Allocator *allocator = mem::heap())
|
||||
fn String! executable_path(Allocator *allocator = allocator::heap())
|
||||
{
|
||||
$if env::DARWIN:
|
||||
return darwin::executable_path(allocator);
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
module std::os::linux @if(env::LINUX);
|
||||
import libc;
|
||||
import std::os::posix;
|
||||
import std::io;
|
||||
import std::collections::list;
|
||||
import libc, std::os, std::io, std::collections::list;
|
||||
|
||||
extern fn isz readlink(ZString path, char* buf, usz bufsize);
|
||||
|
||||
@@ -133,7 +130,7 @@ fn ulong! elf_module_image_base(String path) @local
|
||||
|
||||
fn Backtrace! backtrace_load_from_exec(void* addr, Allocator* allocator) @local
|
||||
{
|
||||
char[] buf = mem::temp_array(char, 1024);
|
||||
char[] buf = mem::temp_alloc_array(char, 1024);
|
||||
|
||||
String exec_path = process::execute_stdout_to_buffer(buf, {"realpath", "-e", string::tformat("/proc/%d/exe", posix::getpid())})!;
|
||||
String obj_name = exec_path.copy(allocator);
|
||||
@@ -143,7 +140,7 @@ fn Backtrace! backtrace_load_from_exec(void* addr, Allocator* allocator) @local
|
||||
|
||||
fn Backtrace! backtrace_load_from_dlinfo(void* addr, Linux_Dl_info* info, Allocator* allocator) @local
|
||||
{
|
||||
char[] buf = mem::temp_array(char, 1024);
|
||||
char[] buf = mem::temp_alloc_array(char, 1024);
|
||||
|
||||
void* obj_addr = addr - (uptr)info.dli_fbase + (uptr)elf_module_image_base(info.dli_fname.str_view())!;
|
||||
ZString obj_path = info.dli_fname;
|
||||
@@ -185,7 +182,7 @@ fn Backtrace! backtrace_from_addr2line(void* addr, String addr2line, String obj_
|
||||
};
|
||||
}
|
||||
|
||||
fn Backtrace! backtrace_load_element(void* addr, Allocator* allocator = mem::heap()) @local
|
||||
fn Backtrace! backtrace_load_element(void* addr, Allocator* allocator = allocator::heap()) @local
|
||||
{
|
||||
if (!addr) return backtrace::BACKTRACE_UNKNOWN;
|
||||
|
||||
@@ -203,7 +200,7 @@ fn Backtrace! backtrace_load_element(void* addr, Allocator* allocator = mem::hea
|
||||
fn BacktraceList! symbolize_backtrace(void*[] backtrace, Allocator* allocator)
|
||||
{
|
||||
BacktraceList list;
|
||||
list.init_new(backtrace.len, allocator);
|
||||
list.new_init(backtrace.len, allocator);
|
||||
defer catch
|
||||
{
|
||||
foreach (trace : list)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
module std::os::darwin @if(env::DARWIN);
|
||||
import std::collections::list;
|
||||
import std::collections::list, std::os;
|
||||
|
||||
const CTL_UNSPEC = 0; /* unused */
|
||||
const CTL_KERN = 1; /* "high kernel": proc, limits */
|
||||
@@ -80,7 +80,7 @@ fn uptr! load_address() @local
|
||||
{
|
||||
Darwin_segment_command_64* cmd = darwin::getsegbyname("__TEXT");
|
||||
if (!cmd) return BacktraceFault.SEGMENT_NOT_FOUND?;
|
||||
String path = env::executable_path(mem::temp()) ?? BacktraceFault.EXECUTABLE_PATH_NOT_FOUND?!;
|
||||
String path = env::executable_path(allocator::temp()) ?? BacktraceFault.EXECUTABLE_PATH_NOT_FOUND?!;
|
||||
uint dyld_count = darwin::_dyld_image_count();
|
||||
for (uint i = 0; i < dyld_count; i++)
|
||||
{
|
||||
@@ -93,7 +93,7 @@ fn uptr! load_address() @local
|
||||
}
|
||||
|
||||
|
||||
fn Backtrace! backtrace_load_element(String execpath, void* buffer, void* load_address, Allocator* allocator = mem::heap()) @local
|
||||
fn Backtrace! backtrace_load_element(String execpath, void* buffer, void* load_address, Allocator* allocator = allocator::heap()) @local
|
||||
{
|
||||
@pool(allocator)
|
||||
{
|
||||
@@ -136,7 +136,7 @@ fn BacktraceList! symbolize_backtrace(void*[] backtrace, Allocator* allocator)
|
||||
{
|
||||
void *load_addr = (void *)load_address()!;
|
||||
BacktraceList list;
|
||||
list.init_new(backtrace.len, allocator);
|
||||
list.new_init(backtrace.len, allocator);
|
||||
defer catch
|
||||
{
|
||||
foreach (trace : list)
|
||||
@@ -147,7 +147,7 @@ fn BacktraceList! symbolize_backtrace(void*[] backtrace, Allocator* allocator)
|
||||
}
|
||||
@pool(allocator)
|
||||
{
|
||||
String execpath = executable_path(mem::temp())!;
|
||||
String execpath = executable_path(allocator::temp())!;
|
||||
foreach (addr : backtrace)
|
||||
{
|
||||
list.append(backtrace_load_element(execpath, addr, load_addr, allocator) ?? backtrace::BACKTRACE_UNKNOWN);
|
||||
|
||||
@@ -26,7 +26,7 @@ macro Class! class_by_name(char* c)
|
||||
return cls;
|
||||
}
|
||||
|
||||
macro Class[] class_get_list(Allocator *allocator = mem::heap())
|
||||
macro Class[] class_get_list(Allocator *allocator = allocator::heap())
|
||||
{
|
||||
int num_classes = _macos_objc_getClassList(null, 0);
|
||||
if (!num_classes) return {};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
module std::os::posix @if(env::POSIX);
|
||||
import std::thread;
|
||||
import libc;
|
||||
|
||||
const PTHREAD_MUTEX_NORMAL = 0;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
module std::os::process @if(env::WIN32 || env::POSIX);
|
||||
import std::io::file;
|
||||
import libc;
|
||||
import std::io, libc, std::os;
|
||||
|
||||
// This code is based on https://github.com/sheredom/subprocess.h
|
||||
|
||||
@@ -247,7 +246,7 @@ fn SubProcess! create(String[] command_line, SubProcessOptions options = {}, Str
|
||||
**/
|
||||
fn ZString* tcopy_command_line(String[] command_line) @local @inline @if(env::POSIX)
|
||||
{
|
||||
ZString* copy = mem::temp_array(ZString, command_line.len + 1);
|
||||
ZString* copy = mem::temp_alloc_array(ZString, command_line.len + 1);
|
||||
foreach (i, str : command_line)
|
||||
{
|
||||
copy[i] = str.zstr_tcopy();
|
||||
@@ -260,7 +259,7 @@ const ZString[1] EMPTY_ENVIRONMENT @if(env::POSIX) = { null };
|
||||
fn ZString* tcopy_env(String[] environment) @local @inline @if(env::POSIX)
|
||||
{
|
||||
if (!environment.len) return &EMPTY_ENVIRONMENT;
|
||||
ZString* copy = mem::temp_array(ZString, environment.len + 1);
|
||||
ZString* copy = mem::temp_alloc_array(ZString, environment.len + 1);
|
||||
copy[environment.len] = null;
|
||||
foreach (i, str : environment)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
module std::os::win32 @if(env::WIN32);
|
||||
import std::thread, std::os::backtrace;
|
||||
|
||||
const Win32_DWORD STARTF_USESTDHANDLES = 0x00000100;
|
||||
const Win32_DWORD CREATE_NO_WINDOW = 0x08000000;
|
||||
@@ -152,7 +153,7 @@ Win32_DWORD64 displacement;
|
||||
fn BacktraceList! symbolize_backtrace(void*[] backtrace, Allocator* allocator)
|
||||
{
|
||||
BacktraceList list;
|
||||
list.init_new(backtrace.len, allocator);
|
||||
list.new_init(backtrace.len, allocator);
|
||||
Win32_HANDLE process = getCurrentProcess();
|
||||
symInitialize(process, null, 1);
|
||||
defer symCleanup(process);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
module std::threads::os @if(env::POSIX);
|
||||
import std::os::posix;
|
||||
import libc;
|
||||
module std::thread::os @if(env::POSIX);
|
||||
import std::os::posix, std::time, libc;
|
||||
|
||||
struct NativeMutex
|
||||
{
|
||||
@@ -151,8 +150,8 @@ fn void* callback(void* arg) @private
|
||||
|
||||
fn void! NativeThread.create(&thread, ThreadFn thread_fn, void* arg)
|
||||
{
|
||||
PosixThreadData *thread_data = mem::new(PosixThreadData);
|
||||
*thread_data = { .thread_fn = thread_fn, .arg = arg };
|
||||
|
||||
PosixThreadData *thread_data = mem::new(PosixThreadData, { .thread_fn = thread_fn, .arg = arg });
|
||||
if (posix::pthread_create(thread, null, &callback, thread_data) != 0)
|
||||
{
|
||||
*thread = null;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
module std::thread::os @if(env::WIN32);
|
||||
import std::os::win32;
|
||||
import std::os::win32, std::time;
|
||||
|
||||
distinct NativeThread = inline Win32_HANDLE;
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
module std::thread;
|
||||
import std::thread::os;
|
||||
import std::time;
|
||||
|
||||
distinct MutexType = int;
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
module std::time::clock;
|
||||
import std::time::os;
|
||||
|
||||
fn Clock now()
|
||||
{
|
||||
$if $defined(native_clock):
|
||||
$if $defined(os::native_clock):
|
||||
return os::native_clock();
|
||||
$else
|
||||
return 0;
|
||||
unreachable("Clock unsupported");
|
||||
$endif
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
module std::time;
|
||||
import std::io, std::time::os;
|
||||
|
||||
distinct Time = long;
|
||||
distinct Duration = long;
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
|
||||
import platform
|
||||
import io
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import shutil
|
||||
import hashlib
|
||||
@@ -16,7 +14,6 @@ import tempfile
|
||||
import argparse
|
||||
import subprocess
|
||||
import urllib.request
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
OUTPUT = Path("msvc_temp") # output folder
|
||||
@@ -176,10 +173,10 @@ for pkg in msvc_packages:
|
||||
|
||||
sdk_packages = [
|
||||
# Windows SDK libs
|
||||
f"Windows SDK for Windows Store Apps Libs-x86_en-us.msi",
|
||||
f"Windows SDK Desktop Libs x64-x86_en-us.msi",
|
||||
"Windows SDK for Windows Store Apps Libs-x86_en-us.msi",
|
||||
"Windows SDK Desktop Libs x64-x86_en-us.msi",
|
||||
# CRT headers & libs
|
||||
f"Universal CRT Headers Libraries and Sources-x86_en-us.msi",
|
||||
"Universal CRT Headers Libraries and Sources-x86_en-us.msi",
|
||||
]
|
||||
|
||||
with tempfile.TemporaryDirectory() as d:
|
||||
|
||||
@@ -1,5 +1,87 @@
|
||||
# C3C Release Notes
|
||||
|
||||
## 0.5.4 Change list
|
||||
|
||||
### Changes / improvements
|
||||
- Hash variables may now take a designated initializer.
|
||||
- Added @safemacro to override the `@` requirement for non-function-like macros.
|
||||
- More information available with debug log in non debug builds.
|
||||
- Removed install_win_reqs.bat which didn't work well.
|
||||
- Support `**` to mean `./**`
|
||||
- MacOS init/finalizer now respects priority.
|
||||
- Bitstructs supports `!=` and `==`.
|
||||
- Support Windows `.def` files using `--windef`.
|
||||
- Bitstructs now fold compile time constant bit ops.
|
||||
- Fix issue where in some cases a constant global with a string wasn't folded (e.g. in asm stmts)
|
||||
- Lateral implicit imports removed.
|
||||
- Default to '.' if no libdir is specified.
|
||||
- Improved error messages for `--lib`.
|
||||
- Added `--linker` to set the linker #1067.
|
||||
|
||||
### Fixes
|
||||
- Fixes to macro context evaluation with macro varargs.
|
||||
- Dynamic methods registered before init functions on MacOS.
|
||||
- Fixed clobber on x86 `cpuid` instruction.
|
||||
- Removed invalid syntax from grammar.y.
|
||||
- `output` project setting now respected.
|
||||
- Aliased declarations caused errors when used in initializers.
|
||||
- Aliased consts used as constant initializers caused errors.
|
||||
- Exported module names replace `::` by `_`.
|
||||
- Const ternary would evaluate incorrectly for ?:
|
||||
- `$$MODULE` would report the incorrect module name in macros.
|
||||
- Fixed debug info for globals and for/switch scopes.
|
||||
- `out` now correctly detects subscript[] use.
|
||||
- Ambiguous recursive imports are now correctly detected.
|
||||
- Overzealous local escape check corrected #1127.
|
||||
- Fixes to the matrix functions #1130.
|
||||
|
||||
### Stdlib changes
|
||||
- Deprecated `Allocator` helper functions.
|
||||
- Added `mem::allocator` functions corresponding to removed allocator functions.
|
||||
- Changed `mem::new` / `mem::temp_new` to accept an optional initializer, and will clear by default.
|
||||
- Mem `_clear` and `_zero` variants deprecated. "new_*" functions will clear by default.
|
||||
- Mem "alloc_*" functions replace old "new_*" behaviour.
|
||||
- Fixed temp memory issue with formatter.
|
||||
- Added temp_push and temp_pop for pushing / popping the temp allocator manually (or from C).
|
||||
- Added byte_size to `List`
|
||||
- Added `GenericList`.
|
||||
|
||||
## 0.5.3 Change list
|
||||
|
||||
### Changes / improvements
|
||||
- Migrate from using actual type with GEP, use i8 or i8 array instead.
|
||||
- Optimize foreach for single element arrays.
|
||||
- Move all calls to panic due to checks to the end of the function.
|
||||
|
||||
### Fixes
|
||||
- Single module command line option was not respected.
|
||||
- Fixed issue with compile time defined types (String in this case), which would crash the compiler in certain cases.
|
||||
- Projects now correctly respect optimization directives.
|
||||
- Generic modules now correctly follow the implicit import rules of regular modules.
|
||||
- Passing an untyped list to a macro and then using it as a vaarg would crash the compiler.
|
||||
- Extern const globals now work correctly.
|
||||
|
||||
### Stdlib changes
|
||||
- init_new/init_temp deprecated, replaced by new_init and temp_init.
|
||||
|
||||
## 0.5.2 Change list
|
||||
|
||||
### Changes / improvements
|
||||
- Allow trailing comma in calls and parameters #1092.
|
||||
|
||||
### Fixes
|
||||
- Fixes issue where single character filenames like 'a.c3' would be rejected.
|
||||
- Better errors when index type doesn't match len() when doing user defined foreach.
|
||||
- Fixes to `to_int` for hexadecimal strings.
|
||||
- Fixed issue when using a generic type from a generic type.
|
||||
- Bug with vector parameters when the size > 2 and modified.
|
||||
- Missing error on assigning to in-parameters through subscripting.
|
||||
- Inference of a vector on the lhs of a binary expression would cause a crash.
|
||||
- Fixes to PriorityQueue
|
||||
|
||||
### Stdlib changes
|
||||
- Allow `to_int` family functions take a base, parsing base 2-10 and 16.
|
||||
|
||||
## 0.5.1 Change list
|
||||
|
||||
### Changes / improvements
|
||||
@@ -7,7 +89,7 @@
|
||||
- Do not link with debug libraries unless using static libraries.
|
||||
- Add 'print-linking' build option.
|
||||
- System linker may be used even if the target arch is different from current.
|
||||
- Slice -> array/vector works for constant slice lenghts.
|
||||
- Slice -> array/vector works for constant slice lengths.
|
||||
|
||||
### Fixes
|
||||
- On Aarch64 use the correct frame pointer type.
|
||||
@@ -193,7 +275,7 @@
|
||||
- Added `saturated` math.
|
||||
- Added `@expect`, `@unlikely` and `@likely` macros.
|
||||
- Temp allocator uses memory-env to determine starting size.
|
||||
- Temp allocator is now accessed using `mem::temp()`, heap allocator using `mem::heap()`.
|
||||
- Temp allocator is now accessed using `mem::temp()`, heap allocator using `allocator::heap()`.
|
||||
- Float parsing added.
|
||||
- Additions to std::net, ipv4/ipv6 parsing.
|
||||
- Stream api.
|
||||
|
||||
@@ -75,7 +75,7 @@ fn void main()
|
||||
{
|
||||
const String[] URLS = { "good", "title-empty", "title-missing", "head-missing", "fail" };
|
||||
DynamicArenaAllocator dynamic_arena;
|
||||
dynamic_arena.init(1024, mem::heap());
|
||||
dynamic_arena.init(1024, allocator::heap());
|
||||
OutStream* out = io::stdout();
|
||||
foreach (String url : URLS)
|
||||
{
|
||||
|
||||
@@ -5,9 +5,9 @@ import libc;
|
||||
|
||||
fn int fannkuchredux(int n)
|
||||
{
|
||||
int* perm = mem::new_array(int, n);
|
||||
int* perm1 = mem::new_array(int, n);
|
||||
int* count = mem::new_array(int, n);
|
||||
int* perm = mem::alloc_array(int, n);
|
||||
int* perm1 = mem::alloc_array(int, n);
|
||||
int* count = mem::alloc_array(int, n);
|
||||
int max_flips_count;
|
||||
int perm_count;
|
||||
int checksum;
|
||||
|
||||
@@ -4,9 +4,9 @@ import std::math;
|
||||
|
||||
fn int fannkuchredux(int n)
|
||||
{
|
||||
int[] perm = mem::new_array(int, n);
|
||||
int[] perm1 = mem::new_array(int, n);
|
||||
int* count = mem::new_array(int, n);
|
||||
int[] perm = mem::alloc_array(int, n);
|
||||
int[] perm1 = mem::alloc_array(int, n);
|
||||
int* count = mem::alloc_array(int, n);
|
||||
int max_flips_count;
|
||||
int perm_count;
|
||||
int checksum;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
module arkanoid;
|
||||
import raylib;
|
||||
import std::math;
|
||||
/**
|
||||
*
|
||||
* raylib - classic game: arkanoid
|
||||
@@ -102,7 +103,7 @@ fn void main()
|
||||
// Initialize game variables
|
||||
fn void init_game()
|
||||
{
|
||||
brick_size = { raylib::get_screen_width() / BRICKS_PER_LINE, 40 };
|
||||
brick_size = { (float)raylib::get_screen_width() / BRICKS_PER_LINE, 40 };
|
||||
|
||||
// Initialize player
|
||||
player.position = { SCREEN_WIDTH/2, SCREEN_HEIGHT * 7 / 8 };
|
||||
@@ -201,7 +202,7 @@ fn void update_game()
|
||||
// Hit below
|
||||
if (((ball.position.y - ball.radius) <= (brick[i][j].position.y + brick_size.y / 2)) &&
|
||||
((ball.position.y - ball.radius) > (brick[i][j].position.y + brick_size.y / 2 + ball.speed.y)) &&
|
||||
((math::fabs((double)ball.position.x - brick[i][j].position.x)) < (double)(brick_size.x / 2 + ball.radius * 2 / 3)) && (ball.speed.y < 0))
|
||||
((math::abs(ball.position.x - brick[i][j].position.x)) < (brick_size.x / 2 + ball.radius * 2.0f / 3)) && (ball.speed.y < 0))
|
||||
{
|
||||
brick[i][j].active = false;
|
||||
ball.speed.y *= -1;
|
||||
@@ -209,7 +210,7 @@ fn void update_game()
|
||||
// Hit above
|
||||
else if (((ball.position.y + ball.radius) >= (brick[i][j].position.y - brick_size.y/2)) &&
|
||||
((ball.position.y + ball.radius) < (brick[i][j].position.y - brick_size.y/2 + ball.speed.y)) &&
|
||||
((math::fabs((double)ball.position.x - brick[i][j].position.x)) < (double)(brick_size.x/2 + ball.radius*2/3)) && (ball.speed.y > 0))
|
||||
((math::abs(ball.position.x - brick[i][j].position.x)) < (brick_size.x / 2 + ball.radius * 2.0f / 3)) && (ball.speed.y > 0))
|
||||
{
|
||||
brick[i][j].active = false;
|
||||
ball.speed.y *= -1;
|
||||
@@ -217,7 +218,7 @@ fn void update_game()
|
||||
// Hit left
|
||||
else if (((ball.position.x + ball.radius) >= (brick[i][j].position.x - brick_size.x/2)) &&
|
||||
((ball.position.x + ball.radius) < (brick[i][j].position.x - brick_size.x/2 + ball.speed.x)) &&
|
||||
((math::fabs((double)ball.position.y - brick[i][j].position.y)) < (double)(brick_size.y/2 + ball.radius*2/3)) && (ball.speed.x > 0))
|
||||
((math::abs(ball.position.y - brick[i][j].position.y)) < (brick_size.y / 2 + ball.radius * 2.0f / 3)) && (ball.speed.x > 0))
|
||||
{
|
||||
brick[i][j].active = false;
|
||||
ball.speed.x *= -1;
|
||||
@@ -225,7 +226,7 @@ fn void update_game()
|
||||
// Hit right
|
||||
else if (((ball.position.x - ball.radius) <= (brick[i][j].position.x + brick_size.x/2)) &&
|
||||
((ball.position.x - ball.radius) > (brick[i][j].position.x + brick_size.x/2 + ball.speed.x)) &&
|
||||
((math::fabs((double)ball.position.y - brick[i][j].position.y)) < (double)(brick_size.y/2 + ball.radius*2/3)) && (ball.speed.x < 0))
|
||||
((math::abs(ball.position.y - brick[i][j].position.y)) < (brick_size.y / 2 + ball.radius * 2.0f / 3)) && (ball.speed.x < 0))
|
||||
{
|
||||
brick[i][j].active = false;
|
||||
ball.speed.x *= -1;
|
||||
|
||||
@@ -124,12 +124,12 @@ fn void update_game()
|
||||
|
||||
if (raylib::is_key_pressed(keyboard::RIGHT) && allow_move)
|
||||
{
|
||||
snake_direction = (SnakeDirection)((snake_direction + 1) % 4);
|
||||
snake_direction = (SnakeDirection)((snake_direction.ordinal + 1) % 4);
|
||||
allow_move = false;
|
||||
}
|
||||
if (raylib::is_key_pressed(keyboard::LEFT) && allow_move)
|
||||
{
|
||||
snake_direction = (SnakeDirection)((snake_direction + 3) % 4);
|
||||
snake_direction = (SnakeDirection)((snake_direction.ordinal + 3) % 4);
|
||||
allow_move = false;
|
||||
}
|
||||
|
||||
@@ -179,13 +179,13 @@ fn void update_game()
|
||||
if (!fruit.active)
|
||||
{
|
||||
fruit.active = true;
|
||||
fruit.position = { raylib::get_random_value(0, (SCREEN_WIDTH / SQUARE_SIZE) - 1) * SQUARE_SIZE + offset.x/2, raylib::get_random_value(0, (SCREEN_HEIGHT / SQUARE_SIZE) - 1) * SQUARE_SIZE + offset.y / 2 };
|
||||
fruit.position = { (float)raylib::get_random_value(0, (SCREEN_WIDTH / SQUARE_SIZE) - 1) * SQUARE_SIZE + offset.x / 2, (float)raylib::get_random_value(0, (SCREEN_HEIGHT / SQUARE_SIZE) - 1) * SQUARE_SIZE + offset.y / 2 };
|
||||
|
||||
for (int i = 0; i < counter_tail; i++)
|
||||
{
|
||||
while ((fruit.position.x == snake[i].position.x) && (fruit.position.y == snake[i].position.y))
|
||||
{
|
||||
fruit.position = { raylib::get_random_value(0, (SCREEN_WIDTH / SQUARE_SIZE) - 1) * SQUARE_SIZE + offset.x/2, raylib::get_random_value(0, (SCREEN_HEIGHT / SQUARE_SIZE) - 1) * SQUARE_SIZE + offset.y / 2 };
|
||||
fruit.position = { (float)raylib::get_random_value(0, (SCREEN_WIDTH / SQUARE_SIZE) - 1) * SQUARE_SIZE + offset.x/2, (float)raylib::get_random_value(0, (SCREEN_HEIGHT / SQUARE_SIZE) - 1) * SQUARE_SIZE + offset.y / 2 };
|
||||
i = 0;
|
||||
}
|
||||
}
|
||||
@@ -213,12 +213,12 @@ fn void draw_game()
|
||||
// Draw grid lines
|
||||
for (int i = 0; i < SCREEN_WIDTH / SQUARE_SIZE + 1; i++)
|
||||
{
|
||||
raylib::draw_line_v({SQUARE_SIZE * i + offset.x/2, offset.y/2}, {SQUARE_SIZE * i + offset.x/2, SCREEN_HEIGHT - offset.y/2}, raylib::LIGHTGRAY);
|
||||
raylib::draw_line_v({(float)SQUARE_SIZE * i + offset.x/2, offset.y/2}, {(float)SQUARE_SIZE * i + offset.x/2, SCREEN_HEIGHT - offset.y/2}, raylib::LIGHTGRAY);
|
||||
}
|
||||
|
||||
for (int i = 0; i < SCREEN_HEIGHT/SQUARE_SIZE + 1; i++)
|
||||
{
|
||||
raylib::draw_line_v({offset.x/2, SQUARE_SIZE * i + offset.y / 2 }, { SCREEN_WIDTH - offset.x/2, SQUARE_SIZE * i + offset.y / 2 }, raylib::LIGHTGRAY);
|
||||
raylib::draw_line_v({offset.x/2, (float)SQUARE_SIZE * i + offset.y / 2 }, { SCREEN_WIDTH - offset.x/2, (float)SQUARE_SIZE * i + offset.y / 2 }, raylib::LIGHTGRAY);
|
||||
}
|
||||
|
||||
// Draw snake
|
||||
@@ -248,5 +248,4 @@ fn void update_draw_frame()
|
||||
{
|
||||
update_game();
|
||||
draw_game();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -44,10 +44,10 @@ fn void eval_AtA_times_u(double[] u, double[] atau, double[] x)
|
||||
fn void main(String[] args)
|
||||
{
|
||||
int n = args.len == 2 ? args[1].to_int()!! : 2000;
|
||||
temparr = mem::new_array(double, n);
|
||||
double[] u = mem::new_array(double, n);
|
||||
double[] v = mem::new_array(double, n);
|
||||
double[] x = mem::new_array(double, (usz)(n * n));
|
||||
temparr = mem::alloc_array(double, n);
|
||||
double[] u = mem::alloc_array(double, n);
|
||||
double[] v = mem::alloc_array(double, n);
|
||||
double[] x = mem::alloc_array(double, (usz)(n * n));
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
for (int j = 0; j < n; j++)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
%option yylineno
|
||||
|
||||
D [0-9]
|
||||
DU [0-9_]
|
||||
@@ -18,8 +19,8 @@ E [Ee][+-]?{D}+
|
||||
P [Pp][+-]?{D}+
|
||||
B64 [ \t\v\n\f]?[A-Za-z0-9+/][ \t\v\n\fA-Za-z0-9+/=]+
|
||||
HEX [ \t\v\n\f]?[A-Fa-f0-9][ \t\v\n\fA-Fa-f0-9]+
|
||||
INTTYPE (([ui](8|16|32|64|128))|([Uu][Ll]?|[Ll]))?
|
||||
REALTYPE [f](8|16|32|64|128)?
|
||||
INTTYPE ([ui](8|16|32|64|128)|[Uu][Ll]?|[Ll])
|
||||
REALTYPE ([f](8|16|32|64|128)?)
|
||||
INT {D}(_*{D})*
|
||||
HINT {H}(_*{H})*
|
||||
OINT {O}(_*{O})*
|
||||
@@ -167,29 +168,31 @@ ${IDENTIFIER} { count(); return(CT_IDENT); }
|
||||
0[oO]{OINT}{INTTYPE}? { count(); return(INTEGER); }
|
||||
0[bB]{BINT}{INTTYPE}? { count(); return(INTEGER); }
|
||||
{INT}{INTTYPE}? { count(); return(INTEGER); }
|
||||
x\'{HEX}+\' { count(); return(BYTES); }
|
||||
x\"{HEX}+\" { count(); return(BYTES); }
|
||||
x\`{HEX}+\` { count(); return(BYTES); }
|
||||
b64\'{B64}+\' { count(); return(BYTES); }
|
||||
b64\"{B64}+\" { count(); return(BYTES); }
|
||||
b64\`{B64}+\` { count(); return(BYTES); }
|
||||
x\'{HEX}\' { count(); return(BYTES); }
|
||||
x\"{HEX}\" { count(); return(BYTES); }
|
||||
x\`{HEX}\` { count(); return(BYTES); }
|
||||
b64\'{B64}\' { count(); return(BYTES); }
|
||||
b64\"{B64}\" { count(); return(BYTES); }
|
||||
b64\`{B64}\` { count(); return(BYTES); }
|
||||
|
||||
{INT}{E}?{REALTYPE}? { count(); return(REAL); }
|
||||
{INT}{REALTYPE} { count(); return(REAL); }
|
||||
{INT}{E}{REALTYPE}? { count(); return(REAL); }
|
||||
0[xX]{HINT}{P}{REALTYPE}? { count(); return(REAL); }
|
||||
{INT}"."{INT}{E}?{REALTYPE}? { count(); return(REAL); }
|
||||
0[xX]{HINT}"."{HINT}{P}{REALTYPE}? { count(); return(REAL); }
|
||||
|
||||
\"(\\.|[^\\"])*\" { count(); return(STRING_LITERAL); }
|
||||
\'(\\.|[^\\'])*\' { count(); return(CHAR_LITERAL); }
|
||||
\'(\\[ux]{HEX}|\\.|[^\\'])\' { count(); return(CHAR_LITERAL); }
|
||||
|
||||
"`" { count(); BEGIN(RAW_STRING); }
|
||||
<RAW_STRING>{
|
||||
"``" { count(); }
|
||||
"`" { count(); BEGIN(INITIAL); return(STRING_LITERAL); }
|
||||
"*"+ { count(); }
|
||||
"[^`]"+ { count(); }
|
||||
<<EOF>> { BEGIN(INITIAL); return(RAW_STRING); }
|
||||
}
|
||||
|
||||
"!!" { count(); return(BANGBANG); }
|
||||
"..." { count(); return(ELLIPSIS); }
|
||||
".." { count(); return(DOTDOT); }
|
||||
">>=" { count(); return(SHR_ASSIGN); }
|
||||
|
||||
@@ -4,10 +4,11 @@
|
||||
#define YYERROR_VERBOSE
|
||||
int yydebug = 1;
|
||||
extern char yytext[];
|
||||
extern int column;
|
||||
extern int column, yylineno;
|
||||
int yylex(void);
|
||||
void yyerror(char *s);
|
||||
void yyerror(const char *s);
|
||||
%}
|
||||
%locations
|
||||
|
||||
%token IDENT HASH_IDENT CT_IDENT CONST_IDENT
|
||||
%token TYPE_IDENT CT_TYPE_IDENT
|
||||
@@ -39,9 +40,9 @@ void yyerror(char *s);
|
||||
%%
|
||||
|
||||
path
|
||||
: IDENT SCOPE
|
||||
| path IDENT SCOPE
|
||||
;
|
||||
: IDENT SCOPE
|
||||
| path IDENT SCOPE
|
||||
;
|
||||
|
||||
path_const
|
||||
: path CONST_IDENT
|
||||
@@ -66,7 +67,7 @@ ident_expr
|
||||
|
||||
local_ident_expr
|
||||
: CT_IDENT
|
||||
| HASH_IDENT
|
||||
| HASH_IDENT
|
||||
;
|
||||
|
||||
ct_call
|
||||
@@ -91,9 +92,9 @@ ct_analyse
|
||||
|
||||
ct_arg
|
||||
: CT_VACONST
|
||||
| CT_VAARG
|
||||
| CT_VAREF
|
||||
| CT_VAEXPR
|
||||
| CT_VAARG
|
||||
| CT_VAREF
|
||||
| CT_VAEXPR
|
||||
;
|
||||
|
||||
flat_path
|
||||
@@ -126,12 +127,16 @@ base_expr
|
||||
| INTEGER
|
||||
| bytes_expr
|
||||
| NUL
|
||||
| BUILTIN CONST_IDENT
|
||||
| BUILTIN IDENT
|
||||
| CHAR_LITERAL
|
||||
| REAL
|
||||
| TRUE
|
||||
| FALSE
|
||||
| base_expr_assignable
|
||||
;
|
||||
|
||||
base_expr_assignable
|
||||
: BUILTIN CONST_IDENT
|
||||
| BUILTIN IDENT
|
||||
| path ident_expr
|
||||
| ident_expr
|
||||
| local_ident_expr
|
||||
@@ -170,7 +175,6 @@ range_expr
|
||||
| DOTDOT
|
||||
;
|
||||
|
||||
|
||||
call_inline_attributes
|
||||
: AT_IDENT
|
||||
| call_inline_attributes AT_IDENT
|
||||
@@ -203,7 +207,7 @@ call_trailing
|
||||
;
|
||||
|
||||
call_stmt_expr
|
||||
: base_expr
|
||||
: base_expr_assignable
|
||||
| call_stmt_expr call_trailing
|
||||
;
|
||||
|
||||
@@ -239,7 +243,7 @@ mult_op
|
||||
: '*'
|
||||
| '/'
|
||||
| '%'
|
||||
;
|
||||
;
|
||||
|
||||
mult_expr
|
||||
: unary_expr
|
||||
@@ -266,12 +270,11 @@ shift_stmt_expr
|
||||
| shift_stmt_expr shift_op mult_expr
|
||||
;
|
||||
|
||||
|
||||
bit_op
|
||||
: '&'
|
||||
| '^'
|
||||
| '|'
|
||||
;
|
||||
: '&'
|
||||
| '^'
|
||||
| '|'
|
||||
;
|
||||
|
||||
bit_expr
|
||||
: shift_expr
|
||||
@@ -286,7 +289,7 @@ bit_stmt_expr
|
||||
additive_op
|
||||
: '+'
|
||||
| '-'
|
||||
;
|
||||
;
|
||||
|
||||
additive_expr
|
||||
: bit_expr
|
||||
@@ -385,19 +388,20 @@ assignment_op
|
||||
;
|
||||
|
||||
empty
|
||||
:
|
||||
: /*empty*/
|
||||
;
|
||||
|
||||
assignment_expr
|
||||
: ternary_expr
|
||||
| CT_TYPE_IDENT '=' type
|
||||
| unary_expr assignment_op assignment_expr
|
||||
;
|
||||
: ternary_expr
|
||||
| CT_TYPE_IDENT '=' type
|
||||
| unary_expr assignment_op assignment_expr
|
||||
;
|
||||
|
||||
assignment_stmt_expr
|
||||
: ternary_stmt_expr
|
||||
| CT_TYPE_IDENT '=' type
|
||||
| unary_stmt_expr assignment_op assignment_expr
|
||||
;
|
||||
: ternary_stmt_expr
|
||||
| CT_TYPE_IDENT '=' type
|
||||
| unary_stmt_expr assignment_op assignment_expr
|
||||
;
|
||||
|
||||
implies_body
|
||||
: IMPLIES expr
|
||||
@@ -415,7 +419,6 @@ expr
|
||||
: assignment_expr
|
||||
;
|
||||
|
||||
|
||||
constant_expr
|
||||
: ternary_expr
|
||||
;
|
||||
@@ -431,7 +434,8 @@ param_path
|
||||
| param_path param_path_element
|
||||
;
|
||||
|
||||
arg : param_path '=' expr
|
||||
arg
|
||||
: param_path '=' expr
|
||||
| type
|
||||
| param_path '=' type
|
||||
| expr
|
||||
@@ -443,21 +447,18 @@ arg : param_path '=' expr
|
||||
arg_list
|
||||
: arg
|
||||
| arg_list ',' arg
|
||||
| arg_list ','
|
||||
;
|
||||
|
||||
opt_arg_list
|
||||
: arg_list
|
||||
| empty
|
||||
;
|
||||
|
||||
call_arg_list
|
||||
: arg_list
|
||||
| arg_list ';'
|
||||
| arg_list ';' parameters
|
||||
| ';'
|
||||
| ';' parameters
|
||||
| empty
|
||||
;
|
||||
|
||||
opt_arg_list_trailing
|
||||
: arg_list
|
||||
| arg_list ','
|
||||
| empty
|
||||
: opt_arg_list
|
||||
| opt_arg_list ';'
|
||||
| opt_arg_list ';' parameters
|
||||
;
|
||||
|
||||
interfaces
|
||||
@@ -470,10 +471,11 @@ opt_interface_impl
|
||||
| '(' ')'
|
||||
| empty
|
||||
;
|
||||
|
||||
enum_constants
|
||||
: enum_constant
|
||||
| enum_constants ',' enum_constant
|
||||
;
|
||||
: enum_constant
|
||||
| enum_constants ',' enum_constant
|
||||
;
|
||||
|
||||
enum_list
|
||||
: enum_constants
|
||||
@@ -483,7 +485,6 @@ enum_list
|
||||
enum_constant
|
||||
: CONST_IDENT opt_attributes
|
||||
| CONST_IDENT '(' arg_list ')' opt_attributes
|
||||
| CONST_IDENT '(' arg_list ',' ')' opt_attributes
|
||||
;
|
||||
|
||||
identifier_list
|
||||
@@ -498,53 +499,53 @@ enum_param_decl
|
||||
;
|
||||
|
||||
base_type
|
||||
: VOID
|
||||
| BOOL
|
||||
| CHAR
|
||||
| ICHAR
|
||||
| SHORT
|
||||
| USHORT
|
||||
| INT
|
||||
| UINT
|
||||
| LONG
|
||||
| ULONG
|
||||
| INT128
|
||||
| UINT128
|
||||
| FLOAT
|
||||
| DOUBLE
|
||||
| FLOAT16
|
||||
| BFLOAT16
|
||||
| FLOAT128
|
||||
| IPTR
|
||||
| UPTR
|
||||
| ISZ
|
||||
| USZ
|
||||
| ANYFAULT
|
||||
| ANY
|
||||
| TYPEID
|
||||
| TYPE_IDENT opt_generic_parameters
|
||||
| path TYPE_IDENT opt_generic_parameters
|
||||
| CT_TYPE_IDENT
|
||||
| CT_TYPEOF '(' expr ')'
|
||||
| CT_TYPEFROM '(' constant_expr ')'
|
||||
| CT_VATYPE '(' constant_expr ')'
|
||||
| CT_EVALTYPE '(' constant_expr ')'
|
||||
;
|
||||
: VOID
|
||||
| BOOL
|
||||
| CHAR
|
||||
| ICHAR
|
||||
| SHORT
|
||||
| USHORT
|
||||
| INT
|
||||
| UINT
|
||||
| LONG
|
||||
| ULONG
|
||||
| INT128
|
||||
| UINT128
|
||||
| FLOAT
|
||||
| DOUBLE
|
||||
| FLOAT16
|
||||
| BFLOAT16
|
||||
| FLOAT128
|
||||
| IPTR
|
||||
| UPTR
|
||||
| ISZ
|
||||
| USZ
|
||||
| ANYFAULT
|
||||
| ANY
|
||||
| TYPEID
|
||||
| TYPE_IDENT opt_generic_parameters
|
||||
| path TYPE_IDENT opt_generic_parameters
|
||||
| CT_TYPE_IDENT
|
||||
| CT_TYPEOF '(' expr ')'
|
||||
| CT_TYPEFROM '(' constant_expr ')'
|
||||
| CT_VATYPE '(' constant_expr ')'
|
||||
| CT_EVALTYPE '(' constant_expr ')'
|
||||
;
|
||||
|
||||
type
|
||||
: base_type
|
||||
| type '*'
|
||||
| type '[' constant_expr ']'
|
||||
| type '[' ']'
|
||||
| type '[' '*' ']'
|
||||
| type LVEC constant_expr RVEC
|
||||
| type LVEC '*' RVEC
|
||||
;
|
||||
: base_type
|
||||
| type '*'
|
||||
| type '[' constant_expr ']'
|
||||
| type '[' ']'
|
||||
| type '[' '*' ']'
|
||||
| type LVEC constant_expr RVEC
|
||||
| type LVEC '*' RVEC
|
||||
;
|
||||
|
||||
optional_type
|
||||
: type
|
||||
| type '!'
|
||||
;
|
||||
: type
|
||||
| type '!'
|
||||
;
|
||||
|
||||
local_decl_after_type
|
||||
: CT_IDENT
|
||||
@@ -573,22 +574,22 @@ var_decl
|
||||
;
|
||||
|
||||
initializer_list
|
||||
: '{' opt_arg_list_trailing '}'
|
||||
: '{' opt_arg_list '}'
|
||||
;
|
||||
|
||||
ct_case_stmt
|
||||
: CT_CASE constant_expr ':' opt_stmt_list
|
||||
| CT_CASE type ':' opt_stmt_list
|
||||
| CT_DEFAULT ':' opt_stmt_list
|
||||
;
|
||||
: CT_CASE constant_expr ':' opt_stmt_list
|
||||
| CT_CASE type ':' opt_stmt_list
|
||||
| CT_DEFAULT ':' opt_stmt_list
|
||||
;
|
||||
|
||||
ct_switch_body
|
||||
: ct_case_stmt
|
||||
| ct_switch_body ct_case_stmt
|
||||
;
|
||||
| ct_switch_body ct_case_stmt
|
||||
;
|
||||
|
||||
ct_for_stmt
|
||||
: CT_FOR '(' for_cond ')' opt_stmt_list CT_ENDFOR
|
||||
: CT_FOR '(' for_cond ')' opt_stmt_list CT_ENDFOR
|
||||
;
|
||||
|
||||
ct_foreach_stmt
|
||||
@@ -596,10 +597,10 @@ ct_foreach_stmt
|
||||
| CT_FOREACH '(' CT_IDENT ',' CT_IDENT ':' expr ')' opt_stmt_list CT_ENDFOREACH
|
||||
;
|
||||
ct_switch
|
||||
: CT_SWITCH '(' constant_expr ')'
|
||||
| CT_SWITCH '(' type ')'
|
||||
| CT_SWITCH
|
||||
;
|
||||
: CT_SWITCH '(' constant_expr ')'
|
||||
| CT_SWITCH '(' type ')'
|
||||
| CT_SWITCH
|
||||
;
|
||||
|
||||
ct_switch_stmt
|
||||
: ct_switch ct_switch_body CT_ENDSWITCH
|
||||
@@ -607,6 +608,7 @@ ct_switch_stmt
|
||||
|
||||
var_stmt
|
||||
: var_decl ';'
|
||||
;
|
||||
|
||||
decl_stmt_after_type
|
||||
: local_decl_after_type
|
||||
@@ -758,7 +760,7 @@ foreach_vars
|
||||
|
||||
foreach_stmt
|
||||
: FOREACH optional_label '(' foreach_vars ':' expr ')' statement
|
||||
: FOREACH_R optional_label '(' foreach_vars ':' expr ')' statement
|
||||
| FOREACH_R optional_label '(' foreach_vars ':' expr ')' statement
|
||||
;
|
||||
|
||||
defer_stmt
|
||||
@@ -813,6 +815,7 @@ asm_expr
|
||||
| INTEGER
|
||||
| '(' expr ')'
|
||||
| '[' asm_addr ']'
|
||||
;
|
||||
|
||||
asm_exprs
|
||||
: asm_expr
|
||||
@@ -833,7 +836,6 @@ asm_block_stmt
|
||||
| ASM AT_IDENT '{' '}'
|
||||
;
|
||||
|
||||
|
||||
/* Order here matches compiler */
|
||||
statement
|
||||
: compound_statement
|
||||
@@ -851,15 +853,15 @@ statement
|
||||
| break_stmt
|
||||
| nextcase_stmt
|
||||
| asm_block_stmt
|
||||
| ct_echo_stmt
|
||||
| ct_echo_stmt
|
||||
| ct_assert_stmt
|
||||
| ct_if_stmt
|
||||
| ct_switch_stmt
|
||||
| ct_foreach_stmt
|
||||
| ct_for_stmt
|
||||
| expr_no_list ';'
|
||||
| assert_stmt
|
||||
| ';'
|
||||
| ct_if_stmt
|
||||
| ct_switch_stmt
|
||||
| ct_foreach_stmt
|
||||
| ct_for_stmt
|
||||
| expr_no_list ';'
|
||||
| assert_stmt
|
||||
| ';'
|
||||
;
|
||||
|
||||
compound_statement
|
||||
@@ -884,9 +886,9 @@ switch_stmt
|
||||
;
|
||||
|
||||
expression_list
|
||||
: decl_or_expr
|
||||
| expression_list ',' decl_or_expr
|
||||
;
|
||||
: decl_or_expr
|
||||
| expression_list ',' decl_or_expr
|
||||
;
|
||||
|
||||
optional_label
|
||||
: CONST_IDENT ':'
|
||||
@@ -905,9 +907,11 @@ ct_include_stmt
|
||||
|
||||
ct_echo_stmt
|
||||
: CT_ECHO constant_expr ';'
|
||||
;
|
||||
|
||||
bitstruct_declaration
|
||||
: BITSTRUCT TYPE_IDENT opt_interface_impl ':' type opt_attributes bitstruct_body
|
||||
;
|
||||
|
||||
bitstruct_body
|
||||
: '{' '}'
|
||||
@@ -930,7 +934,6 @@ bitstruct_def
|
||||
| base_type IDENT ':' constant_expr ';'
|
||||
;
|
||||
|
||||
|
||||
attribute_name
|
||||
: AT_IDENT
|
||||
| AT_TYPE_IDENT
|
||||
@@ -954,9 +957,9 @@ attribute_param_list
|
||||
;
|
||||
|
||||
attribute
|
||||
: attribute_name
|
||||
| attribute_name '(' attribute_param_list ')'
|
||||
;
|
||||
: attribute_name
|
||||
| attribute_name '(' attribute_param_list ')'
|
||||
;
|
||||
|
||||
attribute_list
|
||||
: attribute
|
||||
@@ -964,9 +967,9 @@ attribute_list
|
||||
;
|
||||
|
||||
opt_attributes
|
||||
: attribute_list
|
||||
| empty
|
||||
;
|
||||
: attribute_list
|
||||
| empty
|
||||
;
|
||||
|
||||
trailing_block_param
|
||||
: AT_IDENT
|
||||
@@ -987,7 +990,7 @@ macro_func_body
|
||||
;
|
||||
|
||||
macro_declaration
|
||||
: MACRO macro_header '(' macro_params ')' opt_attributes macro_func_body
|
||||
: MACRO macro_header '(' macro_params ')' opt_attributes macro_func_body
|
||||
;
|
||||
|
||||
struct_or_union
|
||||
@@ -997,16 +1000,16 @@ struct_or_union
|
||||
|
||||
struct_declaration
|
||||
: struct_or_union TYPE_IDENT opt_interface_impl opt_attributes struct_body
|
||||
;
|
||||
;
|
||||
|
||||
struct_body
|
||||
: '{' struct_declaration_list '}'
|
||||
: '{' struct_declaration_list '}'
|
||||
;
|
||||
|
||||
struct_declaration_list
|
||||
: struct_member_decl
|
||||
| struct_declaration_list struct_member_decl
|
||||
;
|
||||
| struct_declaration_list struct_member_decl
|
||||
;
|
||||
|
||||
enum_params
|
||||
: enum_param_decl
|
||||
@@ -1020,16 +1023,15 @@ enum_param_list
|
||||
;
|
||||
|
||||
struct_member_decl
|
||||
: type identifier_list opt_attributes ';'
|
||||
| struct_or_union IDENT opt_attributes struct_body
|
||||
| struct_or_union opt_attributes struct_body
|
||||
| BITSTRUCT ':' type opt_attributes bitstruct_body
|
||||
| BITSTRUCT IDENT ':' type opt_attributes bitstruct_body
|
||||
| INLINE type IDENT opt_attributes ';'
|
||||
| INLINE type opt_attributes ';'
|
||||
: type identifier_list opt_attributes ';'
|
||||
| struct_or_union IDENT opt_attributes struct_body
|
||||
| struct_or_union opt_attributes struct_body
|
||||
| BITSTRUCT ':' type opt_attributes bitstruct_body
|
||||
| BITSTRUCT IDENT ':' type opt_attributes bitstruct_body
|
||||
| INLINE type IDENT opt_attributes ';'
|
||||
| INLINE type opt_attributes ';'
|
||||
;
|
||||
|
||||
|
||||
enum_spec
|
||||
: ':' type enum_param_list
|
||||
| empty
|
||||
@@ -1040,14 +1042,14 @@ enum_declaration
|
||||
;
|
||||
|
||||
faults
|
||||
: CONST_IDENT
|
||||
| faults ',' CONST_IDENT
|
||||
;
|
||||
: CONST_IDENT
|
||||
| faults ',' CONST_IDENT
|
||||
;
|
||||
|
||||
fault_declaration
|
||||
: FAULT TYPE_IDENT opt_interface_impl opt_attributes '{' faults '}'
|
||||
| FAULT TYPE_IDENT opt_interface_impl opt_attributes '{' faults ',' '}'
|
||||
;
|
||||
: FAULT TYPE_IDENT opt_interface_impl opt_attributes '{' faults '}'
|
||||
| FAULT TYPE_IDENT opt_interface_impl opt_attributes '{' faults ',' '}'
|
||||
;
|
||||
|
||||
func_macro_name
|
||||
: IDENT
|
||||
@@ -1070,11 +1072,15 @@ fn_parameter_list
|
||||
| '(' ')'
|
||||
;
|
||||
|
||||
parameter_default
|
||||
: parameter
|
||||
| parameter '=' expr
|
||||
;
|
||||
|
||||
parameters
|
||||
: parameter '=' expr
|
||||
| parameter
|
||||
| parameters ',' parameter
|
||||
| parameters ',' parameter '=' expr
|
||||
: parameter_default
|
||||
| parameters ',' parameter_default
|
||||
| parameters ','
|
||||
;
|
||||
|
||||
parameter
|
||||
@@ -1082,7 +1088,7 @@ parameter
|
||||
| type ELLIPSIS IDENT opt_attributes
|
||||
| type ELLIPSIS CT_IDENT
|
||||
| type CT_IDENT
|
||||
| type ELLIPSIS opt_attributes
|
||||
| type ELLIPSIS opt_attributes
|
||||
| type HASH_IDENT opt_attributes
|
||||
| type '&' IDENT opt_attributes
|
||||
| type opt_attributes
|
||||
@@ -1107,11 +1113,12 @@ func_definition
|
||||
const_declaration
|
||||
: CONST CONST_IDENT opt_attributes '=' expr ';'
|
||||
| CONST type CONST_IDENT opt_attributes '=' expr ';'
|
||||
| CONST type CONST_IDENT opt_attributes ';'
|
||||
;
|
||||
|
||||
func_typedef
|
||||
: FN optional_type fn_parameter_list
|
||||
;
|
||||
: FN optional_type fn_parameter_list
|
||||
;
|
||||
|
||||
opt_inline
|
||||
: INLINE
|
||||
@@ -1130,8 +1137,6 @@ typedef_type
|
||||
| type
|
||||
;
|
||||
|
||||
|
||||
|
||||
multi_declaration
|
||||
: ',' IDENT
|
||||
| multi_declaration ',' IDENT
|
||||
@@ -1143,27 +1148,11 @@ global_storage
|
||||
;
|
||||
|
||||
global_declaration
|
||||
: global_storage optional_type IDENT opt_attributes ';'
|
||||
| global_storage optional_type IDENT multi_declaration opt_attributes ';'
|
||||
| global_storage optional_type IDENT opt_attributes '=' expr ';'
|
||||
;
|
||||
|
||||
opt_tl_stmts
|
||||
: top_level_statements
|
||||
| empty
|
||||
: global_storage optional_type IDENT opt_attributes ';'
|
||||
| global_storage optional_type IDENT multi_declaration opt_attributes ';'
|
||||
| global_storage optional_type IDENT opt_attributes '=' expr ';'
|
||||
;
|
||||
|
||||
tl_ct_case
|
||||
: CT_CASE constant_expr ':' opt_tl_stmts
|
||||
| CT_CASE type ':' opt_tl_stmts
|
||||
| CT_DEFAULT ':' opt_tl_stmts
|
||||
;
|
||||
|
||||
tl_ct_switch_body
|
||||
: tl_ct_case
|
||||
| tl_ct_switch_body tl_ct_case
|
||||
;
|
||||
|
||||
define_attribute
|
||||
: AT_TYPE_IDENT '(' parameters ')' opt_attributes '=' '{' opt_attributes '}'
|
||||
| AT_TYPE_IDENT opt_attributes '=' '{' opt_attributes '}'
|
||||
@@ -1178,17 +1167,15 @@ opt_generic_parameters
|
||||
| empty
|
||||
;
|
||||
|
||||
|
||||
|
||||
define_ident
|
||||
: IDENT '=' path_ident opt_generic_parameters
|
||||
| CONST_IDENT '=' path_const opt_generic_parameters
|
||||
| AT_IDENT '=' path_at_ident opt_generic_parameters
|
||||
;
|
||||
;
|
||||
|
||||
define_declaration
|
||||
: DEF define_ident opt_attributes ';'
|
||||
| DEF define_attribute opt_attributes';'
|
||||
| DEF define_attribute opt_attributes ';'
|
||||
| DEF TYPE_IDENT opt_attributes '=' typedef_type opt_attributes ';'
|
||||
;
|
||||
|
||||
@@ -1206,28 +1193,15 @@ distinct_declaration
|
||||
: DISTINCT TYPE_IDENT opt_interface_impl opt_attributes '=' opt_inline type ';'
|
||||
;
|
||||
|
||||
tl_ct_if
|
||||
: CT_IF constant_expr ':' opt_tl_stmts tl_ct_if_tail
|
||||
;
|
||||
|
||||
tl_ct_if_tail
|
||||
: CT_ENDIF
|
||||
| CT_ELSE opt_tl_stmts CT_ENDIF
|
||||
;
|
||||
|
||||
tl_ct_switch
|
||||
: ct_switch tl_ct_switch_body CT_ENDSWITCH
|
||||
;
|
||||
|
||||
module_param
|
||||
: CONST_IDENT
|
||||
| TYPE_IDENT
|
||||
;
|
||||
: CONST_IDENT
|
||||
| TYPE_IDENT
|
||||
;
|
||||
|
||||
module_params
|
||||
: module_param
|
||||
| module_params ',' module_param
|
||||
;
|
||||
| module_params ',' module_param
|
||||
;
|
||||
|
||||
module
|
||||
: MODULE path_ident opt_attributes ';'
|
||||
@@ -1240,18 +1214,18 @@ import_paths
|
||||
;
|
||||
|
||||
import_decl
|
||||
: IMPORT import_paths opt_attributes ';'
|
||||
;
|
||||
: IMPORT import_paths opt_attributes ';'
|
||||
;
|
||||
|
||||
translation_unit
|
||||
: top_level_statements
|
||||
| empty
|
||||
;
|
||||
: top_level_statements
|
||||
| empty
|
||||
;
|
||||
|
||||
top_level_statements
|
||||
: top_level
|
||||
| top_level_statements top_level
|
||||
;
|
||||
: top_level
|
||||
| top_level_statements top_level
|
||||
;
|
||||
|
||||
opt_extern
|
||||
: EXTERN
|
||||
@@ -1267,8 +1241,6 @@ top_level
|
||||
| ct_assert_stmt
|
||||
| ct_echo_stmt
|
||||
| ct_include_stmt
|
||||
| tl_ct_if
|
||||
| tl_ct_switch
|
||||
| struct_declaration
|
||||
| fault_declaration
|
||||
| enum_declaration
|
||||
@@ -1279,17 +1251,17 @@ top_level
|
||||
| interface_declaration
|
||||
;
|
||||
|
||||
|
||||
%%
|
||||
|
||||
void yyerror(char *s)
|
||||
void yyerror(const char *s)
|
||||
{
|
||||
fflush(stdout);
|
||||
printf("\n%*s\n%*s\n", column, "^", column, s);
|
||||
printf(":%d:%d:\n%*s\n%*s\n", yylineno, column, column, "^", column, s);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
yyparse();
|
||||
return 0;
|
||||
}
|
||||
int rc = yyparse();
|
||||
printf(" -> yyparse return %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ enum Foo
|
||||
|
||||
fn void print_pages()
|
||||
{
|
||||
mem::temp().print_pages(io::stdout())!!;
|
||||
allocator::temp().print_pages(io::stdout())!!;
|
||||
}
|
||||
|
||||
fn void setstring(char* dst, String str)
|
||||
@@ -24,16 +24,16 @@ fn void setstring(char* dst, String str)
|
||||
fn void testAllocator(Allocator* a, int val)
|
||||
{
|
||||
io::printn("Test");
|
||||
void* data = a.alloc_aligned(val, 128, 16)!!;
|
||||
void* data = allocator::malloc_aligned(a, val, 128, 16)!!;
|
||||
io::printf("Aligned with offset %p, align 16: %s offset align 128: %s\n", data, mem::ptr_is_aligned(data, 16), mem::ptr_is_aligned(data + 16, 128));
|
||||
data = a.calloc_aligned(val, 128, 16)!!;
|
||||
data = allocator::calloc_aligned(a, val, 128, 16)!!;
|
||||
io::printf("Aligned with offset %p, align 16: %s offset align 128: %s\n", data, mem::ptr_is_aligned(data, 16), mem::ptr_is_aligned(data + 16, 128));
|
||||
data = a.realloc_aligned(data, (usz)val + 1, 128, 16)!!;
|
||||
data = allocator::realloc_aligned(a, data, (usz)val + 1, 128, 16)!!;
|
||||
io::printf("Aligned with offset %p, align 16: %s offset align 128: %s\n", data, mem::ptr_is_aligned(data, 16), mem::ptr_is_aligned(data + 16, 128));
|
||||
data = a.realloc_aligned(data, (usz)val + 1, 128, 0)!!;
|
||||
data = allocator::realloc_aligned(a, data, (usz)val + 1, 128, 0)!!;
|
||||
io::printf("No offset %p, align 16: %s offset align 128: %s\n", data, mem::ptr_is_aligned(data, 16), mem::ptr_is_aligned(data + 16, 128));
|
||||
io::printfn("Freeing %p", data);
|
||||
a.free_aligned(data);
|
||||
allocator::free_aligned(a, data);
|
||||
}
|
||||
fn void main()
|
||||
{
|
||||
@@ -63,7 +63,7 @@ fn void main()
|
||||
io::printf("First big: %p\n", first_big);
|
||||
print_pages();
|
||||
};
|
||||
mem::@scoped(mem::temp())
|
||||
mem::@scoped(allocator::temp())
|
||||
{
|
||||
io::printf("Malloc: %p\n", (void*)malloc(23));
|
||||
io::printf("Malloc: %p\n", (void*)malloc(23));
|
||||
@@ -73,14 +73,14 @@ fn void main()
|
||||
{
|
||||
io::printf("Talloc: %p\n", (void*)tmalloc(22));
|
||||
};
|
||||
testAllocator(mem::temp(), 126);
|
||||
testAllocator(mem::temp(), 12600);
|
||||
testAllocator(allocator::temp(), 126);
|
||||
testAllocator(allocator::temp(), 12600);
|
||||
ArenaAllocator aa;
|
||||
aa.init(&&char[1024] {});
|
||||
testAllocator(&aa, 126);
|
||||
io::printn("Test dynamic arena");
|
||||
DynamicArenaAllocator dynamic_arena;
|
||||
dynamic_arena.init(1024, mem::heap());
|
||||
dynamic_arena.init(1024, allocator::heap());
|
||||
testAllocator(&dynamic_arena, 112);
|
||||
testAllocator(&dynamic_arena, 712);
|
||||
first_big[3] = 123;
|
||||
|
||||
@@ -23,16 +23,15 @@ struct TopoList
|
||||
|
||||
fn void sort(InputPair[] pairs, uint elements)
|
||||
{
|
||||
InputPair[] result = mem::new_array(InputPair, pairs.len);
|
||||
TopoList* top = mem::new_array(TopoList, elements);
|
||||
InputPair[] result = mem::alloc_array(InputPair, pairs.len);
|
||||
TopoList* top = mem::alloc_array(TopoList, elements);
|
||||
for (int i = 0; i < pairs.len; i++)
|
||||
{
|
||||
InputPair pair = pairs[i];
|
||||
assert(pair.value >= 0 && pair.value < elements);
|
||||
assert(pair.successor >= 0 && pair.successor < elements);
|
||||
top[pair.successor].count++;
|
||||
Entry* successor_entry = mem::new(Entry);
|
||||
*successor_entry = { pair.successor, null };
|
||||
Entry* successor_entry = mem::new(Entry, { pair.successor, null });
|
||||
Entry** next_ref = &top[pair.value].next;
|
||||
while (*next_ref)
|
||||
{
|
||||
@@ -40,7 +39,7 @@ fn void sort(InputPair[] pairs, uint elements)
|
||||
}
|
||||
*next_ref = successor_entry;
|
||||
}
|
||||
int[] intout = mem::new_array(int, elements);
|
||||
int[] intout = mem::alloc_array(int, elements);
|
||||
int count = 0;
|
||||
while LOOP: (1)
|
||||
{
|
||||
|
||||
@@ -308,6 +308,7 @@ typedef struct BuildOptions_
|
||||
const char* std_lib_dir;
|
||||
struct {
|
||||
const char *sdk;
|
||||
const char *def;
|
||||
WinCrtLinking crt_linking;
|
||||
} win;
|
||||
struct {
|
||||
@@ -329,6 +330,7 @@ typedef struct BuildOptions_
|
||||
const char *target_select;
|
||||
const char *path;
|
||||
const char *template;
|
||||
const char *linker;
|
||||
uint32_t symtab_size;
|
||||
unsigned version;
|
||||
CompilerBackend backend;
|
||||
@@ -431,6 +433,7 @@ typedef struct
|
||||
const char **link_args;
|
||||
const char *build_dir;
|
||||
const char *object_file_dir;
|
||||
const char *output_dir;
|
||||
const char *ir_file_dir;
|
||||
const char *asm_file_dir;
|
||||
const char *script_dir;
|
||||
@@ -480,6 +483,7 @@ typedef struct
|
||||
const char **csource_dirs;
|
||||
const char **csources;
|
||||
const char **feature_list;
|
||||
const char *linker;
|
||||
struct
|
||||
{
|
||||
SoftFloat soft_float : 3;
|
||||
@@ -501,6 +505,7 @@ typedef struct
|
||||
struct
|
||||
{
|
||||
const char *sdk;
|
||||
const char *def;
|
||||
WinCrtLinking crt_linking;
|
||||
bool use_win_subsystem;
|
||||
} win;
|
||||
@@ -551,6 +556,7 @@ static BuildTarget default_build_target = {
|
||||
.feature.x86_cpu_set = X86CPU_DEFAULT,
|
||||
.feature.safe_mode = SAFETY_NOT_SET,
|
||||
.win.crt_linking = WIN_CRT_DEFAULT,
|
||||
.win.def = NULL,
|
||||
.switchrange_max_size = DEFAULT_SWITCHRANGE_MAX_SIZE,
|
||||
};
|
||||
|
||||
|
||||
@@ -124,6 +124,7 @@ static void usage(void)
|
||||
OUTPUT(" -z <argument> - Send the <argument> as a parameter to the linker.");
|
||||
OUTPUT(" --system-linker=<yes|no> - Use the system linker (default: no for cross compilation, yes otherwise).");
|
||||
OUTPUT(" --cc <path> - Set C compiler (for C files in projects and use as system linker).");
|
||||
OUTPUT(" --linker <path> - Use the linker in the given path.");
|
||||
OUTPUT("");
|
||||
OUTPUT(" --use-stdlib=<yes|no> - Include the standard library (default: yes).");
|
||||
OUTPUT(" --link-libc=<yes|no> - Link libc other default libraries (default: yes).");
|
||||
@@ -162,6 +163,7 @@ static void usage(void)
|
||||
OUTPUT("");
|
||||
OUTPUT(" --winsdk <dir> - Set the directory for Windows system library files for cross compilation.");
|
||||
OUTPUT(" --wincrt=<option> - Windows CRT linking: none, static, dynamic (default).");
|
||||
OUTPUT(" --windef <file> - Use Windows 'def' file for function exports instead of 'dllexport'.");
|
||||
OUTPUT("");
|
||||
OUTPUT(" --macossdk <dir> - Set the directory for the MacOS SDK for cross compilation.");
|
||||
OUTPUT(" --macos-min-version <ver> - Set the minimum MacOS version to compile for.");
|
||||
@@ -675,6 +677,14 @@ static void parse_option(BuildOptions *options)
|
||||
if ((argopt = match_argopt("system-linker")))
|
||||
{
|
||||
options->system_linker = (SystemLinker)parse_multi_option(argopt, 2, on_off);
|
||||
options->linker = NULL;
|
||||
return;
|
||||
}
|
||||
if (match_longopt("linker"))
|
||||
{
|
||||
if (at_end() || next_is_opt()) error_exit("error: --linker expects a valid linker name.");
|
||||
options->system_linker = SYSTEM_LINKER_NOT_SET;
|
||||
options->linker = next_arg();
|
||||
return;
|
||||
}
|
||||
if ((argopt = match_argopt("link-libc")))
|
||||
@@ -898,6 +908,12 @@ static void parse_option(BuildOptions *options)
|
||||
options->trust_level = (TrustLevel) parse_multi_option(argopt, 3, trust_level);
|
||||
return;
|
||||
}
|
||||
if (match_longopt("windef"))
|
||||
{
|
||||
if (at_end() || next_is_opt()) error_exit("error: --windef needs a file.");
|
||||
options->win.def = next_arg();
|
||||
return;
|
||||
}
|
||||
if ((argopt = match_argopt("wincrt")))
|
||||
{
|
||||
options->win.crt_linking = (WinCrtLinking)parse_multi_option(argopt, 3, wincrt_linking);
|
||||
@@ -951,8 +967,27 @@ static void parse_option(BuildOptions *options)
|
||||
const char *name = next_arg();
|
||||
if (!str_is_valid_lowercase_name(name))
|
||||
{
|
||||
if (str_has_suffix(name, ".c3l"))
|
||||
{
|
||||
error_exit("When specifying libraries, the .c3l suffix should"
|
||||
" not be included, so rather than '--lib %s', try using '--lib %s' instead.",
|
||||
name, str_remove_suffix(name, ".c3l"));
|
||||
}
|
||||
if (str_has_suffix(name, ".lib") || str_has_suffix(name, ".a")
|
||||
|| str_has_suffix(name, ".dll") || str_has_suffix(name, ".so"))
|
||||
{
|
||||
error_exit("You tried to add '%s' as a C3 library, but from the name it appears to be a"
|
||||
" static/dynamic library. To link with such a library, use '-l <name>' instead.",
|
||||
name);
|
||||
}
|
||||
char *name_copy = strdup(name);
|
||||
str_ellide_in_place(name_copy, 32);
|
||||
if (strchr(name, '/') != NULL || (PLATFORM_WINDOWS && strchr(name, '\\') != NULL))
|
||||
{
|
||||
error_exit("There is a problem including the library '%s': a library name should never contain the path. Use '--libdir' to add the "
|
||||
"directory to the library search paths, then use the plain name for '--lib', "
|
||||
"e.g '--libdir my_project/libs --lib some_lib'.", name_copy);
|
||||
}
|
||||
error_exit("Invalid library name '%s', it should be something like 'foo_lib'.", name_copy);
|
||||
}
|
||||
options->libs[options->lib_count++] = name;
|
||||
|
||||
@@ -234,6 +234,10 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions *
|
||||
{
|
||||
target->optsize = options->optsize;
|
||||
}
|
||||
if (options->single_module != SINGLE_MODULE_NOT_SET)
|
||||
{
|
||||
target->single_module = options->single_module;
|
||||
}
|
||||
if (options->safety_level != SAFETY_NOT_SET)
|
||||
{
|
||||
target->feature.safe_mode = options->safety_level;
|
||||
@@ -270,9 +274,19 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions *
|
||||
vec_add(target->linker_libs, options->linker_libs[i]);
|
||||
}
|
||||
target->trust_level = options->trust_level;
|
||||
if (options->win.def) target->win.def = options->win.def;
|
||||
if (options->use_stdlib != USE_STDLIB_NOT_SET) target->use_stdlib = options->use_stdlib;
|
||||
if (options->link_libc != LINK_LIBC_NOT_SET) target->link_libc = options->link_libc;
|
||||
if (options->system_linker != SYSTEM_LINKER_NOT_SET) target->system_linker = options->system_linker;
|
||||
if (options->system_linker != SYSTEM_LINKER_NOT_SET)
|
||||
{
|
||||
target->system_linker = options->system_linker;
|
||||
target->linker = NULL;
|
||||
}
|
||||
if (options->linker)
|
||||
{
|
||||
target->linker = options->linker;
|
||||
target->system_linker = SYSTEM_LINKER_NOT_SET;
|
||||
}
|
||||
if (options->emit_stdlib != EMIT_STDLIB_NOT_SET) target->emit_stdlib = options->emit_stdlib;
|
||||
if (options->no_entry) target->no_entry = true;
|
||||
target->print_output = options->print_output;
|
||||
@@ -378,6 +392,10 @@ static void update_build_target_from_options(BuildTarget *target, BuildOptions *
|
||||
{
|
||||
target->optsetting = options->optsetting;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (target->optsetting == OPT_SETTING_NOT_SET) target->optsetting = OPT_SETTING_O0;
|
||||
}
|
||||
update_build_target_with_opt_level(target, target->optsetting);
|
||||
}
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ const char *project_default_keys[][2] = {
|
||||
{"version", "Version using semantic versioning."},
|
||||
{"warnings", "Warnings used for all targets."},
|
||||
{"wincrt", "Windows CRT linking: none, static, dynamic (default)."},
|
||||
{"windef", "Windows def file, used as an alternative to dllexport when exporting a DLL."},
|
||||
{"winsdk", "Set the path to Windows system library files for cross compilation."},
|
||||
{"x86cpu", "Set general level of x64 cpu: baseline, ssse3, sse4, avx1, avx2-v1, avx2-v2 (Skylake/Zen1+), avx512 (Icelake/Zen4+), native."},
|
||||
{"x86vec", "Set max type of vector use: none, mmx, sse, avx, avx512, native."},
|
||||
@@ -108,6 +109,7 @@ const char* project_target_keys[][2] = {
|
||||
{"version", "Version using semantic versioning."},
|
||||
{"warnings", "Warnings used for all targets."},
|
||||
{"wincrt", "Windows CRT linking: none, static, dynamic (default)."},
|
||||
{"windef", "Windows def file, used as an alternative to dllexport when exporting a DLL."},
|
||||
{"winsdk", "Set the path to Windows system library files for cross compilation."},
|
||||
{"x86cpu", "Set general level of x64 cpu: baseline, ssse3, sse4, avx1, avx2-v1, avx2-v2 (Skylake/Zen1+), avx512 (Icelake/Zen4+), native."},
|
||||
{"x86vec", "Set max type of vector use: none, mmx, sse, avx, avx512, native."},
|
||||
@@ -116,20 +118,24 @@ const char* project_target_keys[][2] = {
|
||||
|
||||
const int project_target_keys_count = ELEMENTLEN(project_target_keys);
|
||||
|
||||
const char *get_valid_string(JSONObject *table, const char *key, const char *category, bool mandatory)
|
||||
static const char *get_string(JSONObject *table, const char *key, const char *category, const char *default_value)
|
||||
{
|
||||
JSONObject *value = json_obj_get(table, key);
|
||||
if (!value)
|
||||
{
|
||||
if (mandatory)
|
||||
{
|
||||
error_exit("%s was missing a mandatory '%s' field, please add it.", category, key);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
if (!value) return default_value;
|
||||
if (value->type != J_STRING)
|
||||
{
|
||||
error_exit("%s had an invalid mandatory '%s' field that was not a string, please correct it.", category, key);
|
||||
error_exit("%s had an invalid '%s' field that was not a string, please correct it.", category, key);
|
||||
}
|
||||
return value->str;
|
||||
}
|
||||
|
||||
static const char *get_valid_string(JSONObject *table, const char *key, const char *category)
|
||||
{
|
||||
JSONObject *value = json_obj_get(table, key);
|
||||
if (!value) return NULL;
|
||||
if (value->type != J_STRING)
|
||||
{
|
||||
error_exit("%s had an invalid '%s' field that was not a string, please correct it.", category, key);
|
||||
}
|
||||
return value->str;
|
||||
}
|
||||
@@ -262,11 +268,9 @@ static void load_into_build_target(JSONObject *json, const char *type, BuildTarg
|
||||
{
|
||||
check_json_keys(project_target_keys, project_target_keys_count, json, type);
|
||||
}
|
||||
const char *cc = get_valid_string(json, "cc", type, false);
|
||||
if (cc) target->cc = cc;
|
||||
target->cc = get_string(json, "cc", type, target->cc);
|
||||
|
||||
const char *script_dir = get_valid_string(json, "script-dir", type, false);
|
||||
if (script_dir) target->script_dir = script_dir;
|
||||
target->script_dir = get_string(json, "script-dir", type, target->script_dir);
|
||||
|
||||
// Exec
|
||||
const char **exec = get_valid_array(json, is_default ? "exec" : "exec-override" , type, false);
|
||||
@@ -289,9 +293,11 @@ static void load_into_build_target(JSONObject *json, const char *type, BuildTarg
|
||||
FOREACH_END();
|
||||
}
|
||||
|
||||
target->output_dir = get_string(json, "output", type, target->output_dir);
|
||||
|
||||
// CFlags
|
||||
const char *cflags = get_valid_string(json, is_default ? "cflags" : "cflags-override" , type, false);
|
||||
const char *cflags_add = is_default ? NULL : get_valid_string(json, "cflags-add" , type, false);
|
||||
const char *cflags = get_valid_string(json, is_default ? "cflags" : "cflags-override" , type);
|
||||
const char *cflags_add = is_default ? NULL : get_valid_string(json, "cflags-add" , type);
|
||||
if (cflags && cflags_add)
|
||||
{
|
||||
error_exit("'%s' is combining both 'cflags-add' and 'cflags-override', only one may be used.", type);
|
||||
@@ -365,7 +371,7 @@ static void load_into_build_target(JSONObject *json, const char *type, BuildTarg
|
||||
[OPT_SETTING_OTINY] = "Oz"
|
||||
};
|
||||
OptimizationSetting opt = (OptimizationSetting)get_valid_string_setting(json, "opt", type, opt_settings, 0, ELEMENTLEN(opt_settings), "'O0', 'O1' etc.");
|
||||
update_build_target_with_opt_level(target, opt);
|
||||
if (opt != OPT_SETTING_NOT_SET) target->optsetting = opt;
|
||||
|
||||
// Safety level
|
||||
target->feature.safe_mode = (SafetyLevel)get_valid_bool(json, "safe", type, target->feature.safe_mode);
|
||||
@@ -393,7 +399,7 @@ static void load_into_build_target(JSONObject *json, const char *type, BuildTarg
|
||||
}
|
||||
|
||||
// Target
|
||||
const char *arch_os_string = get_valid_string(json, "target", type, false);
|
||||
const char *arch_os_string = get_valid_string(json, "target", type);
|
||||
if (arch_os_string)
|
||||
{
|
||||
ArchOsTarget arch_os = arch_os_target_from_string(arch_os_string);
|
||||
@@ -406,8 +412,7 @@ static void load_into_build_target(JSONObject *json, const char *type, BuildTarg
|
||||
if (reloc > -1) target->reloc_model = (RelocModel)reloc;
|
||||
|
||||
// Cpu
|
||||
const char *cpu = get_valid_string(json, "cpu", type, false);
|
||||
if (cpu) target->cpu = cpu;
|
||||
target->cpu = get_string(json, "cpu", type, target->cpu);
|
||||
|
||||
// WinCRT
|
||||
int wincrt = get_valid_string_setting(json, "wincrt", type, wincrt_linking, 0, ELEMENTLEN(wincrt_linking), "'none', 'static' or 'dynamic'.");
|
||||
@@ -442,42 +447,40 @@ static void load_into_build_target(JSONObject *json, const char *type, BuildTarg
|
||||
if (riscv_float > -1) target->feature.riscv_float_capability = riscv_float;
|
||||
|
||||
// winsdk
|
||||
target->win.sdk = get_valid_string(json, "winsdk", type, false);
|
||||
target->win.sdk = get_string(json, "winsdk", type, target->win.sdk);
|
||||
|
||||
// windef
|
||||
target->win.def = get_string(json, "windef", type, target->win.def);
|
||||
|
||||
// macossdk
|
||||
target->macos.sysroot = get_valid_string(json, "macossdk", type, false);
|
||||
target->macos.sysroot = get_string(json, "macossdk", type, target->macos.sysroot);
|
||||
|
||||
// macos-min-version
|
||||
target->macos.min_version = get_valid_string(json, "macos-min-version", type, false);
|
||||
target->macos.min_version = get_string(json, "macos-min-version", type, target->macos.min_version);
|
||||
|
||||
// macos-sdk-version
|
||||
target->macos.sdk_version = get_valid_string(json, "macos-sdk-version", type, false);
|
||||
target->macos.sdk_version = get_string(json, "macos-sdk-version", type, target->macos.sdk_version);
|
||||
|
||||
// Linux crt
|
||||
target->linuxpaths.crt = get_valid_string(json, "linux-crt", type, false);
|
||||
target->linuxpaths.crt = get_string(json, "linux-crt", type, target->linuxpaths.crt);
|
||||
|
||||
// Linux crtbegin
|
||||
target->linuxpaths.crtbegin = get_valid_string(json, "linux-crtbegin", type, false);
|
||||
target->linuxpaths.crtbegin = get_string(json, "linux-crtbegin", type, target->linuxpaths.crtbegin);
|
||||
|
||||
// version
|
||||
const char *version = get_valid_string(json, "version", type, false);
|
||||
if (version) target->version = version;
|
||||
target->version = get_string(json, "version", type, target->version);
|
||||
|
||||
// langrev
|
||||
const char *langrev = get_valid_string(json, "langrev", type, false);
|
||||
if (langrev) target->langrev = langrev;
|
||||
target->langrev = get_string(json, "langrev", type, target->langrev);
|
||||
|
||||
// panicfn
|
||||
const char *panicfn = get_valid_string(json, "panicfn", type, false);
|
||||
target->panicfn = panicfn;
|
||||
target->panicfn = get_string(json, "panicfn", type, target->panicfn);
|
||||
|
||||
// testfn
|
||||
const char *testfn = get_valid_string(json, "testfn", type, false);
|
||||
target->testfn = testfn;
|
||||
target->testfn = get_string(json, "testfn", type, target->testfn);
|
||||
|
||||
// testfn
|
||||
const char *benchfn = get_valid_string(json, "benchfn", type, false);
|
||||
target->benchfn = benchfn;
|
||||
target->benchfn = get_string(json, "benchfn", type, target->benchfn);
|
||||
|
||||
// link-libc
|
||||
target->link_libc = (LinkLibc)get_valid_bool(json, "link-libc", type, target->link_libc);
|
||||
@@ -488,6 +491,13 @@ static void load_into_build_target(JSONObject *json, const char *type, BuildTarg
|
||||
// system-linker
|
||||
target->system_linker = (SystemLinker)get_valid_bool(json, "system-linker", type, target->system_linker);
|
||||
|
||||
// linker
|
||||
target->linker = get_string(json, "linker", type, target->linker);
|
||||
|
||||
if (target->system_linker != SYSTEM_LINKER_NOT_SET && target->linker)
|
||||
{
|
||||
error_exit("%s has both 'linker' and 'system-linker' set. They cannot be combined, so please remove one of them.", type);
|
||||
}
|
||||
// no-entry
|
||||
target->no_entry = get_valid_bool(json, "no-entry", type, target->no_entry);
|
||||
|
||||
@@ -527,6 +537,7 @@ static void project_add_target(Project *project, BuildTarget *default_target, J
|
||||
}
|
||||
type = str_printf("%s %s", type, target->name);
|
||||
load_into_build_target(json, type, target, false);
|
||||
update_build_target_with_opt_level(target, target->optsetting);
|
||||
}
|
||||
|
||||
static void project_add_targets(Project *project, JSONObject *project_data)
|
||||
|
||||
@@ -384,7 +384,7 @@ static void init_asm_x86(void)
|
||||
reg_instr_clob("subw", rax_cc_mask, "rw:r16/mem, r16/mem/imm16");
|
||||
reg_instr_clob("subl", rax_cc_mask, "rw:r32/mem, r32/mem/imm32");
|
||||
reg_instr_clob("subq", rax_cc_mask, "rw:r64/mem, r64/mem/immi32/imm64");
|
||||
reg_instr("cpuid", NULL);
|
||||
reg_instr_clob("cpuid", clobbers_make_from(cc_flag_mask, X86_RAX, X86_RBX, X86_RCX, X86_RDX, -1), NULL);
|
||||
reg_instr("hlt", NULL);
|
||||
reg_instr("in", "w:r8/r16/r32, r16/imm8"); // Actually ensure reg_al_ax and dx
|
||||
reg_instr_clob("incb", cc_flag_mask, "rw:r8/mem");
|
||||
|
||||
@@ -35,6 +35,7 @@ Decl *decl_new(DeclKind decl_kind, const char *name, SourceSpan span)
|
||||
return decl;
|
||||
}
|
||||
|
||||
|
||||
// Check if local or parameter $foo/$Foo
|
||||
bool decl_is_ct_var(Decl *decl)
|
||||
{
|
||||
@@ -89,6 +90,12 @@ Decl *decl_new_with_type(const char *name, SourceSpan loc, DeclKind decl_type)
|
||||
return decl;
|
||||
}
|
||||
|
||||
const char *decl_safe_name(Decl *decl)
|
||||
{
|
||||
if (!decl) return "<no decl>";
|
||||
if (decl->name) return decl->name;
|
||||
return decl_to_name(decl);
|
||||
}
|
||||
const char *decl_to_name(Decl *decl)
|
||||
{
|
||||
const char *name = decl_to_a_name(decl);
|
||||
@@ -163,16 +170,16 @@ void decl_set_external_name(Decl *decl)
|
||||
if (!name) name = "$anon";
|
||||
|
||||
// "extern" or the module has no prefix?
|
||||
if (decl->is_extern || decl->unit->module->no_extprefix)
|
||||
if (decl->is_extern || decl_module(decl)->no_extprefix)
|
||||
{
|
||||
assert(decl->name || decl->unit->module->no_extprefix);
|
||||
assert(decl->name || decl_module(decl)->no_extprefix);
|
||||
decl->extname = name;
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, first put the module name into the scratch buffer
|
||||
scratch_buffer_clear();
|
||||
Module *module = decl->unit->module;
|
||||
Module *module = decl_module(decl);
|
||||
const char *module_name = module->extname ? module->extname : module->name->module;
|
||||
char c;
|
||||
while ((c = *(module_name++)) != 0)
|
||||
@@ -180,7 +187,7 @@ void decl_set_external_name(Decl *decl)
|
||||
switch (c)
|
||||
{
|
||||
case ':':
|
||||
scratch_buffer_append_char('.');
|
||||
scratch_buffer_append_char(decl->is_export ? '_' : '.');
|
||||
module_name++;
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -486,6 +486,7 @@ void compiler_compile(void)
|
||||
|
||||
if (output_exe)
|
||||
{
|
||||
if (active_target.output_dir) output_exe = file_append_path(active_target.output_dir, output_exe);
|
||||
if (file_is_dir(output_exe))
|
||||
{
|
||||
error_exit("Cannot create exe with the name '%s' - there is already a directory with that name.", output_exe);
|
||||
@@ -508,7 +509,7 @@ void compiler_compile(void)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (use_system_linker)
|
||||
if (use_system_linker || active_target.linker)
|
||||
{
|
||||
platform_linker(output_exe, obj_files, output_file_count);
|
||||
compiler_link_time = bench_mark();
|
||||
@@ -541,6 +542,7 @@ void compiler_compile(void)
|
||||
}
|
||||
else if (output_static)
|
||||
{
|
||||
if (active_target.output_dir) output_static = file_append_path(active_target.output_dir, output_static);
|
||||
if (file_is_dir(output_static))
|
||||
{
|
||||
error_exit("Cannot create a static library with the name '%s' - there is already a directory with that name.", output_exe);
|
||||
@@ -556,6 +558,7 @@ void compiler_compile(void)
|
||||
}
|
||||
else if (output_dynamic)
|
||||
{
|
||||
if (active_target.output_dir) output_dynamic = file_append_path(active_target.output_dir, output_dynamic);
|
||||
if (file_is_dir(output_dynamic))
|
||||
{
|
||||
error_exit("Cannot create a dynamic library with the name '%s' - there is already a directory with that name.", output_exe);
|
||||
@@ -582,7 +585,7 @@ static const char **target_expand_source_names(const char** dirs, const char **s
|
||||
VECEACH(dirs, i)
|
||||
{
|
||||
const char *name = dirs[i];
|
||||
DEBUG_LOG("Searching for sources in %s", name);
|
||||
INFO_LOG("Searching for sources in %s", name);
|
||||
size_t name_len = strlen(name);
|
||||
if (name_len < 1) goto INVALID_NAME;
|
||||
if (name[name_len - 1] == '*')
|
||||
@@ -594,7 +597,7 @@ static const char **target_expand_source_names(const char** dirs, const char **s
|
||||
continue;
|
||||
}
|
||||
if (name[name_len - 2] != '*') goto INVALID_NAME;
|
||||
DEBUG_LOG("Searching for wildcard sources in %s", name);
|
||||
INFO_LOG("Searching for wildcard sources in %s", name);
|
||||
if (name_len == 2 || name[name_len - 3] == '/')
|
||||
{
|
||||
char *path = str_copy(name, name_len - 2);
|
||||
@@ -604,8 +607,7 @@ static const char **target_expand_source_names(const char** dirs, const char **s
|
||||
}
|
||||
goto INVALID_NAME;
|
||||
}
|
||||
if (name_len < 4) goto INVALID_NAME;
|
||||
if (name_len < 5 || !file_has_suffix_in_list(name, name_len, suffix_list, suffix_count)) goto INVALID_NAME;
|
||||
if (!file_has_suffix_in_list(name, name_len, suffix_list, suffix_count)) goto INVALID_NAME;
|
||||
vec_add(files, name);
|
||||
continue;
|
||||
INVALID_NAME:
|
||||
@@ -615,7 +617,7 @@ static const char **target_expand_source_names(const char** dirs, const char **s
|
||||
continue;
|
||||
}
|
||||
if (!error_on_mismatch) continue;
|
||||
error_exit("File names must end with %s or they cannot be compiled: '%s' is invalid.", suffix_list[0], name);
|
||||
error_exit("File names must be a non-empty name followed by %s or they cannot be compiled: '%s' is invalid.", suffix_list[0], name);
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
@@ -64,6 +64,7 @@ typedef unsigned AstId;
|
||||
typedef unsigned ExprId;
|
||||
typedef unsigned DeclId;
|
||||
typedef unsigned TypeInfoId;
|
||||
typedef struct SemaContext_ SemaContext;
|
||||
|
||||
|
||||
typedef struct Int128_
|
||||
@@ -469,7 +470,7 @@ typedef struct VarDecl_
|
||||
int32_t index;
|
||||
struct
|
||||
{
|
||||
struct SemaContext_ *context;
|
||||
SemaContext *context;
|
||||
SourceSpan span;
|
||||
} hash_var;
|
||||
struct
|
||||
@@ -533,6 +534,7 @@ struct Signature_
|
||||
CalleeAttributes attrs;
|
||||
bool is_macro : 1;
|
||||
bool is_at_macro : 1;
|
||||
bool is_safemacro : 1;
|
||||
Variadic variadic : 3;
|
||||
CallABI abi : 8;
|
||||
unsigned vararg_index;
|
||||
@@ -1138,6 +1140,11 @@ typedef struct
|
||||
TypeInfoId type;
|
||||
} ExprCastable;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Expr *inner;
|
||||
SemaContext *context;
|
||||
} ExprOtherContext;
|
||||
|
||||
struct Expr_
|
||||
{
|
||||
@@ -1159,6 +1166,7 @@ struct Expr_
|
||||
ExprConst const_expr; // 32
|
||||
ExprCtArg ct_arg_expr;
|
||||
ExprCtAndOr ct_and_or_expr;
|
||||
ExprOtherContext expr_other_context;
|
||||
ExprCastable castable_expr;
|
||||
ExprCtCall ct_call_expr; // 24
|
||||
ExprIdentifierRaw ct_ident_expr; // 24
|
||||
@@ -1515,6 +1523,7 @@ typedef struct Module_
|
||||
Decl** private_method_extensions;
|
||||
HTable symbols;
|
||||
struct CompilationUnit_ **units;
|
||||
Module *generic_module;
|
||||
Module *parent_module;
|
||||
Module *top_module;
|
||||
Module **sub_modules;
|
||||
@@ -1663,7 +1672,7 @@ typedef struct
|
||||
};
|
||||
} CallEnv;
|
||||
|
||||
typedef struct SemaContext_
|
||||
struct SemaContext_
|
||||
{
|
||||
Module *core_module;
|
||||
// Evaluated in this.
|
||||
@@ -1686,6 +1695,7 @@ typedef struct SemaContext_
|
||||
struct
|
||||
{
|
||||
uint32_t original_inline_line;
|
||||
Module *original_module;
|
||||
Decl **yield_params;
|
||||
Ast *yield_body;
|
||||
BlockExit** block_exit_ref;
|
||||
@@ -1699,11 +1709,11 @@ typedef struct SemaContext_
|
||||
Decl** ct_locals;
|
||||
};
|
||||
Type *rtype;
|
||||
struct SemaContext_ *yield_context;
|
||||
SemaContext *yield_context;
|
||||
Decl** locals;
|
||||
DynamicScope active_scope;
|
||||
Expr *return_expr;
|
||||
} SemaContext;
|
||||
};
|
||||
|
||||
|
||||
typedef struct
|
||||
@@ -2010,7 +2020,6 @@ int64_t int_to_i64(Int op);
|
||||
bool int_is_zero(Int op);
|
||||
unsigned int_bits_needed(Int op);
|
||||
bool int_fits(Int op1, TypeKind kind);
|
||||
Int int_rightmost_bits(Int op, unsigned to_bits, TypeKind result_type);
|
||||
Int int_conv(Int op, TypeKind to_type);
|
||||
Int int_div(Int op1, Int op2);
|
||||
Int int_mul(Int op1, Int op2);
|
||||
@@ -2163,6 +2172,7 @@ Decl *decl_new_with_type(const char *name, SourceSpan span, DeclKind decl_type);
|
||||
Decl *decl_new_var(const char *name, SourceSpan span, TypeInfo *type, VarDeclKind kind);
|
||||
Decl *decl_new_generated_var(Type *type, VarDeclKind kind, SourceSpan span);
|
||||
void decl_set_external_name(Decl *decl);
|
||||
const char *decl_safe_name(Decl *decl);
|
||||
const char *decl_to_name(Decl *decl);
|
||||
const char *decl_to_a_name(Decl *decl);
|
||||
int decl_count_elements(Decl *structlike);
|
||||
@@ -2177,6 +2187,7 @@ static inline Decl *decl_raw(Decl *decl);
|
||||
static inline DeclKind decl_from_token(TokenType type);
|
||||
static inline bool decl_is_var_local(Decl *decl);
|
||||
bool decl_is_ct_var(Decl *decl);
|
||||
INLINE Module* decl_module(Decl *decl);
|
||||
Decl *decl_find_enum_constant(Decl *decl, const char *name);
|
||||
bool decl_needs_prefix(Decl *decl);
|
||||
AlignSize decl_find_member_offset(Decl *decl, Decl *member);
|
||||
@@ -2715,7 +2726,6 @@ INLINE CanonicalType *type_pointer_type(Type *type)
|
||||
|
||||
INLINE bool type_is_pointer_like(Type *type)
|
||||
{
|
||||
CanonicalType *res = type->canonical;
|
||||
TypeKind kind = type->type_kind;
|
||||
return kind == TYPE_POINTER || (kind == TYPE_VECTOR && type->array.base->canonical->type_kind == TYPE_POINTER);
|
||||
}
|
||||
@@ -3505,6 +3515,11 @@ INLINE bool decl_var_kind_is_ct(VarDeclKind kind)
|
||||
return kind >= VARDECL_FIRST_CT && kind <= VARDECL_LAST_CT;
|
||||
}
|
||||
|
||||
INLINE Module *decl_module(Decl *decl)
|
||||
{
|
||||
return decl->unit ? decl->unit->module : global_context.core_module;
|
||||
}
|
||||
|
||||
static inline bool decl_is_var_local(Decl *decl)
|
||||
{
|
||||
if (decl->decl_kind != DECL_VAR) return false;
|
||||
|
||||
@@ -110,7 +110,7 @@ bool context_set_module(ParseContext *context, Path *path, const char **generic_
|
||||
|
||||
void unit_register_external_symbol(CompilationUnit *unit, Decl *decl)
|
||||
{
|
||||
if (!decl->unit || decl->unit->module == unit->module || !decl->extname) return;
|
||||
if (decl_module(decl) == unit->module || !decl->extname) return;
|
||||
decl->is_external_visible = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -296,6 +296,9 @@ Expr *copy_expr(CopyStruct *c, Expr *source_expr)
|
||||
{
|
||||
case EXPR_ANYSWITCH:
|
||||
UNREACHABLE
|
||||
case EXPR_OTHER_CONTEXT:
|
||||
MACRO_COPY_EXPR(expr->expr_other_context.inner);
|
||||
return expr;
|
||||
case EXPR_EMBED:
|
||||
MACRO_COPY_EXPR(expr->embed_expr.len);
|
||||
MACRO_COPY_EXPR(expr->embed_expr.filename);
|
||||
|
||||
@@ -247,6 +247,7 @@ typedef enum
|
||||
EXPR_MACRO_BODY_EXPANSION,
|
||||
EXPR_NOP,
|
||||
EXPR_OPERATOR_CHARS,
|
||||
EXPR_OTHER_CONTEXT,
|
||||
EXPR_POINTER_OFFSET,
|
||||
EXPR_POST_UNARY,
|
||||
EXPR_RETHROW,
|
||||
@@ -808,6 +809,7 @@ typedef enum
|
||||
ATTRIBUTE_PUBLIC,
|
||||
ATTRIBUTE_PURE,
|
||||
ATTRIBUTE_REFLECT,
|
||||
ATTRIBUTE_SAFEMACRO,
|
||||
ATTRIBUTE_SECTION,
|
||||
ATTRIBUTE_TEST,
|
||||
ATTRIBUTE_UNUSED,
|
||||
@@ -848,7 +850,6 @@ typedef enum
|
||||
|
||||
typedef enum
|
||||
{
|
||||
|
||||
BUILTIN_ABS,
|
||||
BUILTIN_ANY_MAKE,
|
||||
BUILTIN_ATOMIC_LOAD,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user