Compare commits

...

14 Commits

Author SHA1 Message Date
Christoffer Lerno
d7cc37b951 Important fixes to project settings. 2024-02-17 11:39:08 +01:00
Christoffer Lerno
4ce62cf221 Fix of allocator::new. 2024-02-16 21:55:30 +01:00
Christoffer Lerno
1f052da0b9 Clock.c3 fix. 2024-02-16 21:31:49 +01:00
Christoffer Lerno
812dc0c292 Update memory test code. 2024-02-16 14:19:42 +01:00
Christoffer Lerno
798fe0dce9 Updated lex file. 2024-02-16 12:01:13 +01:00
Christoffer Lerno
3f6fe55f9a Grammar fix. 2024-02-15 23:18:11 +01:00
Christoffer Lerno
aee4aecfe7 Remove install_win_reqs.bat from releases. 2024-02-15 22:41:44 +01:00
Christoffer Lerno
748c737e8f 0.5.4: Hash variables accept designated initializers. @safemacro overrides the need for @ in macro names. Fixes to macro context evaluation. Updated allocator api. Removed install_win_reqs.bat. Deterministic @init for MacOS. Fixed temp memory issue with formatter. Support LLVM 19. Add support to compare bitstructs using == and !=. Support Windows .def files. Removed invalid grammar from grammar.y. Support compile time folding of &|^~ for bitstructs. output project setting now respected. Fix issue where constants were not properly constant folded. Add temp_push/pop. Aliased declarations caused errors when used in initializers. Fix export output. Fix of const ternary #1118. Fix of $$MODULE in nested macros #1117. Fix debug info on globals. out now correctly detects subscript[] use #1116. Lateral implicit imports removed. Default to '.' if no libdir is specified. Improved error messages for --lib. Fix raylib snake example. Overzealous local escape check corrected #1127. Improved yacc grammar #1128. --linker argument #1067. Fixes to the matrix operations #1130. Added GenericList. 2024-02-15 21:39:33 +01:00
Christoffer Lerno
c673101bbb Fix incorrect code in sample. 2024-02-14 09:16:36 +01:00
Poly2it
d66674655c Update compilation instructions for Void Linux 2024-02-13 16:45:51 +01:00
Christian Clauss
da292e41bd msvc_build_libraries.py: Remove unused import an f-strings with no placeholder
% `ruff ` # https://docs.astral.sh/ruff
```
 Error: msvc_build_libraries.py:9:8: F401 `os` imported but unused
Error: msvc_build_libraries.py:10:8: F401 `sys` imported but unused
Error: msvc_build_libraries.py:19:8: F401 `re` imported but unused
Error: msvc_build_libraries.py:179:3: F541 f-string without any placeholders
Error: msvc_build_libraries.py:180:3: F541 f-string without any placeholders
Error: msvc_build_libraries.py:182:3: F541 f-string without any placeholders
Error: Process completed with exit code 1.
```
2024-01-18 11:24:03 +01:00
Christoffer Lerno
deb4cc7c4b 0.5.3: Single-module not respected. Fix issue with compiler defined types. Fix optimization levels for projects. Use GEP i8 on offsets. Optimize foreach on len 1 arrays. Move panic blocks last. Fix generic module wildcard imports. Deprecate init_temp / init_new. Fix issue with macro vaarg and untyped lists. Fix extern const globals. 2024-01-14 15:34:54 +01:00
Christoffer Lerno
e91f6e268e 0.5.2: Allow trailing comma in calls and parameter declarations #1092. Fixes issue where single character filenames like 'a.c3' would be rejected. Improve error messages for incorrect user defined foreach. Fix bug with generics in generics. Fix to error with modified vector parameters. Crash with lhs vector inference. Fixes to priority queue. 2023-12-23 23:15:51 +01:00
Poly2it
2595ed5cc9 Add compilation instructions for Void Linux 2023-12-09 15:15:17 +01:00
326 changed files with 13605 additions and 10918 deletions

View File

@@ -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

View File

@@ -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()

View File

@@ -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.

View File

@@ -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

View File

@@ -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)

View File

@@ -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);
}

View File

@@ -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);
}

View 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);
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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());
}
/**

View File

@@ -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)
{

View File

@@ -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;

View File

@@ -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)
{

View File

@@ -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.

View 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)!;

View File

@@ -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;

View File

@@ -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)
{

View File

@@ -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 };
}

View File

@@ -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);
};

View File

@@ -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;

View File

@@ -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;

View File

@@ -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)

View File

@@ -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;

View File

@@ -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)!!;
}

View File

@@ -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];
}

View 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);
}

View 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, &section.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 = &current.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;
}

View File

@@ -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];

View File

@@ -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()));
};
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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();

View File

@@ -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());
}
/**

View File

@@ -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?;

View File

@@ -1,4 +1,5 @@
module std::io;
import std::math;
const char[16] XDIGITS_H = "0123456789ABCDEF";
const char[16] XDIGITS_L = "0123456789abcdef";

View File

@@ -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"

View File

@@ -1,5 +1,5 @@
module std::io::os;
import libc;
import std::io::path, libc, std::os;
macro void! native_chdir(Path path)
{

View File

@@ -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)
{

View File

@@ -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:

View File

@@ -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)
{

View File

@@ -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)

View File

@@ -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?;
}

View File

@@ -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);
}

View File

@@ -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:

View File

@@ -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];
}

View File

@@ -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];
}

View File

@@ -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>);

View File

@@ -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,
};
}

View File

@@ -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,
};
}

View File

@@ -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
};
}

View File

@@ -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]);
}

View File

@@ -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)
{

View File

@@ -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());
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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)
{

View File

@@ -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
{

View File

@@ -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;

View File

@@ -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)

View File

@@ -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);

View File

@@ -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)

View File

@@ -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);

View File

@@ -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 {};

View File

@@ -1,4 +1,5 @@
module std::os::posix @if(env::POSIX);
import std::thread;
import libc;
const PTHREAD_MUTEX_NORMAL = 0;

View File

@@ -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)
{

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;

View File

@@ -1,5 +1,6 @@
module std::thread;
import std::thread::os;
import std::time;
distinct MutexType = int;

View File

@@ -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
}

View File

@@ -1,4 +1,5 @@
module std::time;
import std::io, std::time::os;
distinct Time = long;
distinct Duration = long;

View File

@@ -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:

View File

@@ -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.

View File

@@ -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)
{

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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();
}
}

View File

@@ -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++)

View File

@@ -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); }

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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)
{

View File

@@ -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,
};

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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)

View File

@@ -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");

View File

@@ -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:

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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