New faults and syntax (#2034)

- Remove `[?]` syntax.
- Change `int!` to `int?` syntax.
- New `fault` declarations.
- Enum associated values can reference the calling enum.
This commit is contained in:
Christoffer Lerno
2025-03-10 00:11:35 +01:00
committed by GitHub
parent fefce25081
commit 25bccf4883
392 changed files with 3129 additions and 3658 deletions

View File

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

View File

@@ -49,7 +49,7 @@ fn AnyList* AnyList.tinit(&self, usz initial_capacity = 16)
fn bool AnyList.is_initialized(&self) @inline => self.allocator != null;
fn usz! AnyList.to_format(&self, Formatter* formatter) @dynamic
fn usz? AnyList.to_format(&self, Formatter* formatter) @dynamic
{
switch (self.size)
{
@@ -96,22 +96,22 @@ fn void AnyList.free_element(&self, any element) @inline
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
@return! TYPE_MISMATCH, NO_MORE_ELEMENT
*>
macro AnyList.pop(&self, $Type)
{
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
if (!self.size) return 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
@return! NO_MORE_ELEMENT
*>
fn any! AnyList.copy_pop(&self, Allocator allocator)
fn any? AnyList.copy_pop(&self, Allocator allocator)
{
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
if (!self.size) return NO_MORE_ELEMENT?;
defer self.free_element(self.entries[self.size]);
return allocator::clone_any(allocator, self.entries[--self.size]);
}
@@ -119,17 +119,17 @@ fn any! AnyList.copy_pop(&self, Allocator allocator)
<*
Pop the last value and allocate the copy using the temp allocator
@return! IteratorResult.NO_MORE_ELEMENT
@return! NO_MORE_ELEMENT
*>
fn any! AnyList.tcopy_pop(&self) => self.copy_pop(tmem());
fn any? AnyList.tcopy_pop(&self) => self.copy_pop(tmem());
<*
Pop the last value. It must later be released using list.free_element()
@return! IteratorResult.NO_MORE_ELEMENT
@return! NO_MORE_ELEMENT
*>
fn any! AnyList.pop_retained(&self)
fn any? AnyList.pop_retained(&self)
{
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
if (!self.size) return NO_MORE_ELEMENT?;
return self.entries[--self.size];
}
@@ -147,7 +147,7 @@ fn void AnyList.clear(&self)
*>
macro AnyList.pop_first(&self, $Type)
{
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
if (!self.size) return NO_MORE_ELEMENT?;
defer self.remove_at(0);
return *anycast(self.entries[0], $Type);
}
@@ -155,9 +155,9 @@ macro AnyList.pop_first(&self, $Type)
<*
Same as pop_retained() but pops the first value instead.
*>
fn any! AnyList.pop_first_retained(&self)
fn any? AnyList.pop_first_retained(&self)
{
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
if (!self.size) return NO_MORE_ELEMENT?;
defer self.remove_at(0);
return self.entries[0];
}
@@ -166,9 +166,9 @@ fn any! AnyList.pop_first_retained(&self)
<*
Same as copy_pop() but pops the first value instead.
*>
fn any! AnyList.copy_pop_first(&self, Allocator allocator = allocator::heap())
fn any? AnyList.copy_pop_first(&self, Allocator allocator = allocator::heap())
{
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
if (!self.size) return NO_MORE_ELEMENT?;
defer self.free_element(self.entries[self.size]);
defer self.remove_at(0);
return allocator::clone_any(allocator, self.entries[0]);
@@ -177,7 +177,7 @@ fn any! AnyList.copy_pop_first(&self, Allocator allocator = allocator::heap())
<*
Same as temp_pop() but pops the first value instead.
*>
fn any! AnyList.tcopy_pop_first(&self) => self.copy_pop_first(tmem());
fn any? AnyList.tcopy_pop_first(&self) => self.copy_pop_first(tmem());
<*
@require index < self.size
@@ -271,9 +271,9 @@ macro AnyList.first(&self, $Type)
return *anycast(self.first_any(), $Type);
}
fn any! AnyList.first_any(&self) @inline
fn any? AnyList.first_any(&self) @inline
{
return self.size ? self.entries[0] : IteratorResult.NO_MORE_ELEMENT?;
return self.size ? self.entries[0] : NO_MORE_ELEMENT?;
}
macro AnyList.last(&self, $Type)
@@ -281,9 +281,9 @@ macro AnyList.last(&self, $Type)
return *anycast(self.last_any(), $Type);
}
fn any! AnyList.last_any(&self) @inline
fn any? AnyList.last_any(&self) @inline
{
return self.size ? self.entries[self.size - 1] : IteratorResult.NO_MORE_ELEMENT?;
return self.size ? self.entries[self.size - 1] : NO_MORE_ELEMENT?;
}
fn bool AnyList.is_empty(&self) @inline

View File

@@ -4,7 +4,7 @@
<*
@require MAX_SIZE >= 1 : `The size must be at least 1 element big.`
*>
module std::collections::elastic_array{Type, MAX_SIZE};
module std::collections::elastic_array {Type, MAX_SIZE};
import std::io, std::math, std::collections::list_common;
def ElementPredicate = fn bool(Type *type);
@@ -19,7 +19,7 @@ struct ElasticArray (Printable)
Type[MAX_SIZE] entries;
}
fn usz! ElasticArray.to_format(&self, Formatter* formatter) @dynamic
fn usz? ElasticArray.to_format(&self, Formatter* formatter) @dynamic
{
switch (self.size)
{
@@ -44,9 +44,9 @@ fn String ElasticArray.to_tstring(&self)
return string::tformat("%s", *self);
}
fn void! ElasticArray.push_try(&self, Type element) @inline
fn void? ElasticArray.push_try(&self, Type element) @inline
{
if (self.size == MAX_SIZE) return AllocationFailure.OUT_OF_MEMORY?;
if (self.size == MAX_SIZE) return mem::OUT_OF_MEMORY?;
self.entries[self.size++] = element;
}
@@ -58,9 +58,9 @@ fn void ElasticArray.push(&self, Type element) @inline
self.entries[self.size++] = element;
}
fn Type! ElasticArray.pop(&self)
fn Type? ElasticArray.pop(&self)
{
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
if (!self.size) return NO_MORE_ELEMENT?;
return self.entries[--self.size];
}
@@ -72,9 +72,9 @@ fn void ElasticArray.clear(&self)
<*
@require self.size > 0
*>
fn Type! ElasticArray.pop_first(&self)
fn Type? ElasticArray.pop_first(&self)
{
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
if (!self.size) return NO_MORE_ELEMENT?;
defer self.remove_at(0);
return self.entries[0];
}
@@ -199,7 +199,7 @@ fn void ElasticArray.push_front(&self, Type type) @inline
<*
@require self.size < MAX_SIZE : `List would exceed max size`
*>
fn void! ElasticArray.push_front_try(&self, Type type) @inline
fn void? ElasticArray.push_front_try(&self, Type type) @inline
{
return self.insert_at_try(0, type);
}
@@ -207,9 +207,9 @@ fn void! ElasticArray.push_front_try(&self, Type type) @inline
<*
@require index <= self.size
*>
fn void! ElasticArray.insert_at_try(&self, usz index, Type value)
fn void? ElasticArray.insert_at_try(&self, usz index, Type value)
{
if (self.size == MAX_SIZE) return AllocationFailure.OUT_OF_MEMORY?;
if (self.size == MAX_SIZE) return mem::OUT_OF_MEMORY?;
self.insert_at(index, value);
}
@@ -235,27 +235,27 @@ fn void ElasticArray.set_at(&self, usz index, Type type)
self.entries[index] = type;
}
fn void! ElasticArray.remove_last(&self) @maydiscard
fn void? ElasticArray.remove_last(&self) @maydiscard
{
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
if (!self.size) return NO_MORE_ELEMENT?;
self.size--;
}
fn void! ElasticArray.remove_first(&self) @maydiscard
fn void? ElasticArray.remove_first(&self) @maydiscard
{
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
if (!self.size) return NO_MORE_ELEMENT?;
self.remove_at(0);
}
fn Type! ElasticArray.first(&self)
fn Type? ElasticArray.first(&self)
{
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
if (!self.size) return NO_MORE_ELEMENT?;
return self.entries[0];
}
fn Type! ElasticArray.last(&self)
fn Type? ElasticArray.last(&self)
{
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
if (!self.size) return NO_MORE_ELEMENT?;
return self.entries[self.size - 1];
}
@@ -330,22 +330,22 @@ fn void ElasticArray.set(&self, usz index, Type value) @operator([]=)
// Functions for equatable types
fn usz! ElasticArray.index_of(&self, Type type) @if(ELEMENT_IS_EQUATABLE)
fn usz? ElasticArray.index_of(&self, Type type) @if(ELEMENT_IS_EQUATABLE)
{
foreach (i, v : self)
{
if (equals(v, type)) return i;
}
return SearchResult.MISSING?;
return NOT_FOUND?;
}
fn usz! ElasticArray.rindex_of(&self, Type type) @if(ELEMENT_IS_EQUATABLE)
fn usz? ElasticArray.rindex_of(&self, Type type) @if(ELEMENT_IS_EQUATABLE)
{
foreach_r (i, v : self)
{
if (equals(v, type)) return i;
}
return SearchResult.MISSING?;
return NOT_FOUND?;
}
fn bool ElasticArray.equals(&self, ElasticArray other_list) @if(ELEMENT_IS_EQUATABLE)

View File

@@ -16,7 +16,7 @@ fn void EnumMap.init(&self, ValueType init_value)
}
}
fn usz! EnumMap.to_format(&self, Formatter* formatter) @dynamic
fn usz? EnumMap.to_format(&self, Formatter* formatter) @dynamic
{
usz n = formatter.print("{ ")!;
foreach (i, &value : self.values)

View File

@@ -126,7 +126,7 @@ fn EnumSet EnumSet.xor_of(&self, EnumSet s)
$endif
}
fn usz! EnumSet.to_format(&set, Formatter* formatter) @dynamic
fn usz? EnumSet.to_format(&set, Formatter* formatter) @dynamic
{
usz n = formatter.print("[")!;
bool found;

View File

@@ -171,26 +171,26 @@ fn usz HashMap.len(&map) @inline
return map.count;
}
fn Value*! HashMap.get_ref(&map, Key key)
fn Value*? HashMap.get_ref(&map, Key key)
{
if (!map.count) return SearchResult.MISSING?;
if (!map.count) return NOT_FOUND?;
uint hash = rehash(key.hash());
for (Entry *e = map.table[index_for(hash, map.table.len)]; e != null; e = e.next)
{
if (e.hash == hash && equals(key, e.key)) return &e.value;
}
return SearchResult.MISSING?;
return NOT_FOUND?;
}
fn Entry*! HashMap.get_entry(&map, Key key)
fn Entry*? HashMap.get_entry(&map, Key key)
{
if (!map.count) return SearchResult.MISSING?;
if (!map.count) return NOT_FOUND?;
uint hash = rehash(key.hash());
for (Entry *e = map.table[index_for(hash, map.table.len)]; e != null; e = e.next)
{
if (e.hash == hash && equals(key, e.key)) return e;
}
return SearchResult.MISSING?;
return NOT_FOUND?;
}
<*
@@ -216,7 +216,7 @@ macro Value HashMap.@get_or_set(&map, Key key, Value #expr)
return val;
}
fn Value! HashMap.get(&map, Key key) @operator([])
fn Value? HashMap.get(&map, Key key) @operator([])
{
return *map.get_ref(key) @inline;
}
@@ -252,9 +252,9 @@ fn bool HashMap.set(&map, Key key, Value value) @operator([]=)
return false;
}
fn void! HashMap.remove(&map, Key key) @maydiscard
fn void? HashMap.remove(&map, Key key) @maydiscard
{
if (!map.remove_entry_for_key(key)) return SearchResult.MISSING?;
if (!map.remove_entry_for_key(key)) return NOT_FOUND?;
}
fn void HashMap.clear(&map)
@@ -413,7 +413,7 @@ fn void HashMap.resize(&map, uint new_capacity) @private
map.threshold = (uint)(new_capacity * map.load_factor);
}
fn usz! HashMap.to_format(&self, Formatter* f) @dynamic
fn usz? HashMap.to_format(&self, Formatter* f) @dynamic
{
usz len;
len += f.print("{ ")!;

View File

@@ -85,18 +85,18 @@ fn void LinkedList.push(&self, Type value)
self.size++;
}
fn Type! LinkedList.peek(&self) => self.first() @inline;
fn Type! LinkedList.peek_last(&self) => self.last() @inline;
fn Type? LinkedList.peek(&self) => self.first() @inline;
fn Type? LinkedList.peek_last(&self) => self.last() @inline;
fn Type! LinkedList.first(&self)
fn Type? LinkedList.first(&self)
{
if (!self._first) return IteratorResult.NO_MORE_ELEMENT?;
if (!self._first) return NO_MORE_ELEMENT?;
return self._first.value;
}
fn Type! LinkedList.last(&self)
fn Type? LinkedList.last(&self)
{
if (!self._last) return IteratorResult.NO_MORE_ELEMENT?;
if (!self._last) return NO_MORE_ELEMENT?;
return self._last.value;
}
@@ -231,9 +231,9 @@ fn usz LinkedList.remove(&self, Type t) @if(ELEMENT_IS_EQUATABLE)
return start - self.size;
}
fn Type! LinkedList.pop(&self)
fn Type? LinkedList.pop(&self)
{
if (!self._last) return IteratorResult.NO_MORE_ELEMENT?;
if (!self._last) return NO_MORE_ELEMENT?;
defer self.unlink_last();
return self._last.value;
}
@@ -243,22 +243,22 @@ fn bool LinkedList.is_empty(&self)
return !self._first;
}
fn Type! LinkedList.pop_front(&self)
fn Type? LinkedList.pop_front(&self)
{
if (!self._first) return IteratorResult.NO_MORE_ELEMENT?;
if (!self._first) return NO_MORE_ELEMENT?;
defer self.unlink_first();
return self._first.value;
}
fn void! LinkedList.remove_last(&self) @maydiscard
fn void? LinkedList.remove_last(&self) @maydiscard
{
if (!self._first) return IteratorResult.NO_MORE_ELEMENT?;
if (!self._first) return NO_MORE_ELEMENT?;
self.unlink_last();
}
fn void! LinkedList.remove_first(&self) @maydiscard
fn void? LinkedList.remove_first(&self) @maydiscard
{
if (!self._first) return IteratorResult.NO_MORE_ELEMENT?;
if (!self._first) return NO_MORE_ELEMENT?;
self.unlink_first();
}

View File

@@ -87,7 +87,7 @@ fn void List.init_wrapping_array(&self, Allocator allocator, Type[] types)
fn bool List.is_initialized(&self) @inline => self.allocator != null && self.allocator != (Allocator)&dummy;
fn usz! List.to_format(&self, Formatter* formatter) @dynamic
fn usz? List.to_format(&self, Formatter* formatter) @dynamic
{
switch (self.size)
{
@@ -113,9 +113,9 @@ fn void List.push(&self, Type element) @inline
self.entries[self.set_size(self.size + 1)] = element;
}
fn Type! List.pop(&self)
fn Type? List.pop(&self)
{
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
if (!self.size) return NO_MORE_ELEMENT?;
defer self.set_size(self.size - 1);
return self.entries[self.size - 1];
}
@@ -125,9 +125,9 @@ fn void List.clear(&self)
self.set_size(0);
}
fn Type! List.pop_first(&self)
fn Type? List.pop_first(&self)
{
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
if (!self.size) return NO_MORE_ELEMENT?;
defer self.remove_at(0);
return self.entries[0];
}
@@ -233,27 +233,27 @@ fn void List.set_at(&self, usz index, Type type)
self.entries[index] = type;
}
fn void! List.remove_last(&self) @maydiscard
fn void? List.remove_last(&self) @maydiscard
{
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
if (!self.size) return NO_MORE_ELEMENT?;
self.set_size(self.size - 1);
}
fn void! List.remove_first(&self) @maydiscard
fn void? List.remove_first(&self) @maydiscard
{
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
if (!self.size) return NO_MORE_ELEMENT?;
self.remove_at(0);
}
fn Type! List.first(&self)
fn Type? List.first(&self)
{
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
if (!self.size) return NO_MORE_ELEMENT?;
return self.entries[0];
}
fn Type! List.last(&self)
fn Type? List.last(&self)
{
if (!self.size) return IteratorResult.NO_MORE_ELEMENT?;
if (!self.size) return NO_MORE_ELEMENT?;
return self.entries[self.size - 1];
}
@@ -446,22 +446,22 @@ macro void List.post_alloc(&self) @private
// Functions for equatable types
fn usz! List.index_of(&self, Type type) @if(ELEMENT_IS_EQUATABLE)
fn usz? List.index_of(&self, Type type) @if(ELEMENT_IS_EQUATABLE)
{
foreach (i, v : self)
{
if (equals(v, type)) return i;
}
return SearchResult.MISSING?;
return NOT_FOUND?;
}
fn usz! List.rindex_of(&self, Type type) @if(ELEMENT_IS_EQUATABLE)
fn usz? List.rindex_of(&self, Type type) @if(ELEMENT_IS_EQUATABLE)
{
foreach_r (i, v : self)
{
if (equals(v, type)) return i;
}
return SearchResult.MISSING?;
return NOT_FOUND?;
}
fn bool List.equals(&self, List other_list) @if(ELEMENT_IS_EQUATABLE)

View File

@@ -7,7 +7,7 @@ struct Maybe (Printable)
bool has_value;
}
fn usz! Maybe.to_format(&self, Formatter* f) @dynamic
fn usz? Maybe.to_format(&self, Formatter* f) @dynamic
{
if (self.has_value) return f.printf("[%s]", self.value);
return f.printf("[EMPTY]");
@@ -30,7 +30,7 @@ fn Maybe value(Type val)
const Maybe EMPTY = { };
macro Type! Maybe.get(self)
macro Type? Maybe.get(self)
{
return self.has_value ? self.value : SearchResult.MISSING?;
return self.has_value ? self.value : NOT_FOUND?;
}

View File

@@ -25,7 +25,7 @@ struct Object (Printable)
}
fn usz! Object.to_format(&self, Formatter* formatter) @dynamic
fn usz? Object.to_format(&self, Formatter* formatter) @dynamic
{
switch (self.type)
{
@@ -178,7 +178,7 @@ fn void Object.init_array_if_needed(&self) @private
fn void Object.set_object(&self, String key, Object* new_object) @private
{
self.init_map_if_needed();
ObjectInternalMapEntry*! entry = self.map.get_entry(key);
ObjectInternalMapEntry*? entry = self.map.get_entry(key);
defer
{
(void)entry.value.free();
@@ -201,7 +201,7 @@ macro Object* Object.object_from_value(&self, value) @private
$case $Type.typeid == Object*.typeid:
return value;
$case $Type.typeid == void*.typeid:
if (value != null) return CastResult.TYPE_MISMATCH?;
if (value != null) return TYPE_MISMATCH?;
return &NULL_OBJECT;
$case $assignable(value, String):
return new_string(value, self.allocator);
@@ -242,7 +242,7 @@ macro Object* Object.push(&self, value)
<*
@require self.is_keyable()
*>
fn Object*! Object.get(&self, String key) => self.is_empty() ? SearchResult.MISSING? : self.map.get(key);
fn Object*? Object.get(&self, String key) => self.is_empty() ? NOT_FOUND? : self.map.get(key);
fn bool Object.has_key(&self, String key) => self.is_map() && self.map.has_key(key);
@@ -308,7 +308,7 @@ macro get_integer_value(Object* value, $Type)
return ($Type)value.s.to_uint128();
$endif
}
if (!value.is_int()) return NumberConversion.MALFORMED_INTEGER?;
if (!value.is_int()) return string::MALFORMED_INTEGER?;
return ($Type)value.i;
}
@@ -331,77 +331,77 @@ macro Object.get_integer(&self, $Type, String key) @private
return get_integer_value(self.get(key), $Type);
}
fn ichar! Object.get_ichar(&self, String key) => self.get_integer(ichar, key);
fn short! Object.get_short(&self, String key) => self.get_integer(short, key);
fn int! Object.get_int(&self, String key) => self.get_integer(int, key);
fn long! Object.get_long(&self, String key) => self.get_integer(long, key);
fn int128! Object.get_int128(&self, String key) => self.get_integer(int128, key);
fn ichar? Object.get_ichar(&self, String key) => self.get_integer(ichar, key);
fn short? Object.get_short(&self, String key) => self.get_integer(short, key);
fn int? Object.get_int(&self, String key) => self.get_integer(int, key);
fn long? Object.get_long(&self, String key) => self.get_integer(long, key);
fn int128? Object.get_int128(&self, String key) => self.get_integer(int128, key);
fn ichar! Object.get_ichar_at(&self, usz index) => self.get_integer_at(ichar, index);
fn short! Object.get_short_at(&self, usz index) => self.get_integer_at(short, index);
fn int! Object.get_int_at(&self, usz index) => self.get_integer_at(int, index);
fn long! Object.get_long_at(&self, usz index) => self.get_integer_at(long, index);
fn int128! Object.get_int128_at(&self, usz index) => self.get_integer_at(int128, index);
fn ichar? Object.get_ichar_at(&self, usz index) => self.get_integer_at(ichar, index);
fn short? Object.get_short_at(&self, usz index) => self.get_integer_at(short, index);
fn int? Object.get_int_at(&self, usz index) => self.get_integer_at(int, index);
fn long? Object.get_long_at(&self, usz index) => self.get_integer_at(long, index);
fn int128? Object.get_int128_at(&self, usz index) => self.get_integer_at(int128, index);
fn char! Object.get_char(&self, String key) => self.get_integer(ichar, key);
fn short! Object.get_ushort(&self, String key) => self.get_integer(ushort, key);
fn uint! Object.get_uint(&self, String key) => self.get_integer(uint, key);
fn ulong! Object.get_ulong(&self, String key) => self.get_integer(ulong, key);
fn uint128! Object.get_uint128(&self, String key) => self.get_integer(uint128, key);
fn char? Object.get_char(&self, String key) => self.get_integer(ichar, key);
fn short? Object.get_ushort(&self, String key) => self.get_integer(ushort, key);
fn uint? Object.get_uint(&self, String key) => self.get_integer(uint, key);
fn ulong? Object.get_ulong(&self, String key) => self.get_integer(ulong, key);
fn uint128? Object.get_uint128(&self, String key) => self.get_integer(uint128, key);
fn char! Object.get_char_at(&self, usz index) => self.get_integer_at(char, index);
fn ushort! Object.get_ushort_at(&self, usz index) => self.get_integer_at(ushort, index);
fn uint! Object.get_uint_at(&self, usz index) => self.get_integer_at(uint, index);
fn ulong! Object.get_ulong_at(&self, usz index) => self.get_integer_at(ulong, index);
fn uint128! Object.get_uint128_at(&self, usz index) => self.get_integer_at(uint128, index);
fn char? Object.get_char_at(&self, usz index) => self.get_integer_at(char, index);
fn ushort? Object.get_ushort_at(&self, usz index) => self.get_integer_at(ushort, index);
fn uint? Object.get_uint_at(&self, usz index) => self.get_integer_at(uint, index);
fn ulong? Object.get_ulong_at(&self, usz index) => self.get_integer_at(ulong, index);
fn uint128? Object.get_uint128_at(&self, usz index) => self.get_integer_at(uint128, index);
<*
@require self.is_keyable()
*>
fn String! Object.get_string(&self, String key)
fn String? Object.get_string(&self, String key)
{
Object* value = self.get(key)!;
if (!value.is_string()) return CastResult.TYPE_MISMATCH?;
if (!value.is_string()) return TYPE_MISMATCH?;
return value.s;
}
<*
@require self.is_indexable()
*>
fn String! Object.get_string_at(&self, usz index)
fn String? Object.get_string_at(&self, usz index)
{
Object* value = self.get_at(index);
if (!value.is_string()) return CastResult.TYPE_MISMATCH?;
if (!value.is_string()) return TYPE_MISMATCH?;
return value.s;
}
<*
@require self.is_keyable()
*>
macro String! Object.get_enum(&self, $EnumType, String key)
macro String? Object.get_enum(&self, $EnumType, String key)
{
Object value = self.get(key)!;
if ($EnumType.typeid != value.type) return CastResult.TYPE_MISMATCH?;
if ($EnumType.typeid != value.type) return TYPE_MISMATCH?;
return ($EnumType)value.i;
}
<*
@require self.is_indexable()
*>
macro String! Object.get_enum_at(&self, $EnumType, usz index)
macro String? Object.get_enum_at(&self, $EnumType, usz index)
{
Object value = self.get_at(index);
if ($EnumType.typeid != value.type) return CastResult.TYPE_MISMATCH?;
if ($EnumType.typeid != value.type) return TYPE_MISMATCH?;
return ($EnumType)value.i;
}
<*
@require self.is_keyable()
*>
fn bool! Object.get_bool(&self, String key)
fn bool? Object.get_bool(&self, String key)
{
Object* value = self.get(key)!;
if (!value.is_bool()) return CastResult.TYPE_MISMATCH?;
if (!value.is_bool()) return TYPE_MISMATCH?;
return value.b;
}
@@ -409,17 +409,17 @@ fn bool! Object.get_bool(&self, String key)
<*
@require self.is_indexable()
*>
fn bool! Object.get_bool_at(&self, usz index)
fn bool? Object.get_bool_at(&self, usz index)
{
Object* value = self.get_at(index);
if (!value.is_bool()) return CastResult.TYPE_MISMATCH?;
if (!value.is_bool()) return TYPE_MISMATCH?;
return value.b;
}
<*
@require self.is_keyable()
*>
fn double! Object.get_float(&self, String key)
fn double? Object.get_float(&self, String key)
{
Object* value = self.get(key)!;
switch (value.type.kindof)
@@ -431,14 +431,14 @@ fn double! Object.get_float(&self, String key)
case FLOAT:
return value.f;
default:
return CastResult.TYPE_MISMATCH?;
return TYPE_MISMATCH?;
}
}
<*
@require self.is_indexable()
*>
fn double! Object.get_float_at(&self, usz index)
fn double? Object.get_float_at(&self, usz index)
{
Object* value = self.get_at(index);
switch (value.type.kindof)
@@ -450,7 +450,7 @@ fn double! Object.get_float_at(&self, usz index)
case FLOAT:
return value.f;
default:
return CastResult.TYPE_MISMATCH?;
return TYPE_MISMATCH?;
}
}

View File

@@ -82,11 +82,11 @@ fn void PrivatePriorityQueue.remove_at(&self, usz index)
<*
@require self != null
*>
fn Type! PrivatePriorityQueue.pop(&self)
fn Type? PrivatePriorityQueue.pop(&self)
{
usz i = 0;
usz len = self.heap.len();
if (!len) return IteratorResult.NO_MORE_ELEMENT?;
if (!len) return NO_MORE_ELEMENT?;
usz new_count = len - 1;
self.heap.swap(0, new_count);
while OUTER: ((2 * i + 1) < new_count)
@@ -120,7 +120,7 @@ fn Type! PrivatePriorityQueue.pop(&self)
return self.heap.pop();
}
fn Type! PrivatePriorityQueue.first(&self)
fn Type? PrivatePriorityQueue.first(&self)
{
return self.heap.first();
}
@@ -148,7 +148,7 @@ fn Type PrivatePriorityQueue.get(&self, usz index) @operator([])
return self.heap[index];
}
fn usz! PrivatePriorityQueue.to_format(&self, Formatter* formatter) @dynamic
fn usz? PrivatePriorityQueue.to_format(&self, Formatter* formatter) @dynamic
{
return self.heap.to_format(formatter);
}

View File

@@ -29,7 +29,7 @@ fn Type Range.get(&self, usz index) @operator([])
return (Type)(self.start + (usz)index);
}
fn usz! Range.to_format(&self, Formatter* formatter) @dynamic
fn usz? Range.to_format(&self, Formatter* formatter) @dynamic
{
return formatter.printf("[%s..%s]", self.start, self.end)!;
}
@@ -51,7 +51,7 @@ fn bool ExclusiveRange.contains(&self, Type value) @inline
return value >= self.start && value < self.end;
}
fn usz! ExclusiveRange.to_format(&self, Formatter* formatter) @dynamic
fn usz? ExclusiveRange.to_format(&self, Formatter* formatter) @dynamic
{
return formatter.printf("[%s..<%s]", self.start, self.end)!;
}

View File

@@ -43,12 +43,12 @@ fn Element RingBuffer.get(&self, usz index) @operator([])
return self.buf[index - avail];
}
fn Element! RingBuffer.pop(&self)
fn Element? RingBuffer.pop(&self)
{
switch
{
case self.written == 0:
return SearchResult.MISSING?;
return NO_MORE_ELEMENT?;
case self.written < self.buf.len:
self.written--;
return self.buf[self.written];
@@ -58,7 +58,7 @@ fn Element! RingBuffer.pop(&self)
}
}
fn usz! RingBuffer.to_format(&self, Formatter* format) @dynamic
fn usz? RingBuffer.to_format(&self, Formatter* format) @dynamic
{
// Improve this?
return format.printf("%s", self.buf);

View File

@@ -42,14 +42,7 @@ struct QOIDesc
QOI Errors.
These are all the possible bad outcomes.
*>
fault QOIError
{
INVALID_PARAMETERS,
FILE_OPEN_FAILED,
FILE_WRITE_FAILED,
INVALID_DATA,
TOO_MANY_PIXELS
}
fault INVALID_PARAMETERS, FILE_OPEN_FAILED, FILE_WRITE_FAILED, INVALID_DATA, TOO_MANY_PIXELS;
// Let the user decide if they want to use std::io
@@ -71,7 +64,7 @@ import std::io;
@param [in] input : `The raw RGB or RGBA pixels to encode`
@param [&in] desc : `The descriptor of the image`
*>
fn usz! write(String filename, char[] input, QOIDesc* desc) => @pool()
fn usz? write(String filename, char[] input, QOIDesc* desc) => @pool()
{
// encode data
char[] output = encode(tmem(), input, desc)!;
@@ -101,11 +94,12 @@ fn usz! write(String filename, char[] input, QOIDesc* desc) => @pool()
@param [in] filename : `The file's name to read the image from`
@param [&out] desc : `The descriptor to fill with the image's info`
@param channels : `The channels to be used`
@return! FILE_OPEN_FAILED, INVALID_DATA, TOO_MANY_PIXELS
*>
fn char[]! read(Allocator allocator, String filename, QOIDesc* desc, QOIChannels channels = AUTO) => @pool(allocator)
fn char[]? read(Allocator allocator, String filename, QOIDesc* desc, QOIChannels channels = AUTO) => @pool(allocator)
{
// read file
char[] data = file::load_temp(filename) ?? QOIError.FILE_OPEN_FAILED?!;
char[] data = file::load_temp(filename) ?? FILE_OPEN_FAILED?!;
// pass data to decode function
return decode(allocator, data, desc, channels);
}
@@ -128,18 +122,19 @@ import std::bits;
@param [in] input : `The raw RGB or RGBA pixels to encode`
@param [&in] desc : `The descriptor of the image`
@return! INVALID_PARAMETERS, TOO_MANY_PIXELS, INVALID_DATA
*>
fn char[]! encode(Allocator allocator, char[] input, QOIDesc* desc) @nodiscard
fn char[]? encode(Allocator allocator, char[] input, QOIDesc* desc) @nodiscard
{
// check info in desc
if (desc.width == 0 || desc.height == 0) return QOIError.INVALID_PARAMETERS?;
if (desc.channels == AUTO) return QOIError.INVALID_PARAMETERS?;
if (desc.width == 0 || desc.height == 0) return INVALID_PARAMETERS?;
if (desc.channels == AUTO) return INVALID_PARAMETERS?;
uint pixels = desc.width * desc.height;
if (pixels > PIXELS_MAX) return QOIError.TOO_MANY_PIXELS?;
if (pixels > PIXELS_MAX) return TOO_MANY_PIXELS?;
// check input data size
uint image_size = pixels * desc.channels.id;
if (image_size != input.len) return QOIError.INVALID_DATA?;
if (image_size != input.len) return INVALID_DATA?;
// allocate memory for encoded data (output)
// header + chunk tag and RGB(A) data for each pixel + end of stream
@@ -282,31 +277,32 @@ fn char[]! encode(Allocator allocator, char[] input, QOIDesc* desc) @nodiscard
@param [in] data : `The QOI image data to decode`
@param [&out] desc : `The descriptor to fill with the image's info`
@param channels : `The channels to be used`
@return! INVALID_DATA, TOO_MANY_PIXELS
*>
fn char[]! decode(Allocator allocator, char[] data, QOIDesc* desc, QOIChannels channels = AUTO) @nodiscard
fn char[]? decode(Allocator allocator, char[] data, QOIDesc* desc, QOIChannels channels = AUTO) @nodiscard
{
// check input data
if (data.len < Header.sizeof + END_OF_STREAM.len) return QOIError.INVALID_DATA?;
if (data.len < Header.sizeof + END_OF_STREAM.len) return INVALID_DATA?;
// get header
Header* header = (Header*)data.ptr;
// check magic bytes (FourCC)
if (bswap(header.be_magic) != 'qoif') return QOIError.INVALID_DATA?;
if (bswap(header.be_magic) != 'qoif') return INVALID_DATA?;
// copy header data to desc
desc.width = bswap(header.be_width);
desc.height = bswap(header.be_height);
desc.channels = @enumcast(QOIChannels, header.channels)!; // Rethrow if invalid
desc.colorspace = @enumcast(QOIColorspace, header.colorspace)!; // Rethrow if invalid
if (desc.channels == AUTO) return QOIError.INVALID_DATA?; // Channels must be specified in the header
if (desc.channels == AUTO) return INVALID_DATA?; // Channels must be specified in the header
// check width and height
if (desc.width == 0 || desc.height == 0) return QOIError.INVALID_DATA?;
if (desc.width == 0 || desc.height == 0) return INVALID_DATA?;
// check pixel count
ulong pixels = (ulong)desc.width * (ulong)desc.height;
if (pixels > PIXELS_MAX) return QOIError.TOO_MANY_PIXELS?;
if (pixels > PIXELS_MAX) return TOO_MANY_PIXELS?;
uint pos = Header.sizeof; // Current position in data
uint loc; // Current position in image (top-left corner)
@@ -405,16 +401,20 @@ struct Header @packed
char colorspace; // 0 = sRGB with linear alpha, 1 = all channels linear
}
const char[?] END_OF_STREAM = {0, 0, 0, 0, 0, 0, 0, 1};
const char[*] END_OF_STREAM = {0, 0, 0, 0, 0, 0, 0, 1};
// inefficient, but it's only run once at a time
<*
@return! INVALID_DATA
*>
macro @enumcast($Type, raw)
{
foreach (value : $Type.values)
{
if (value.id == raw) return value;
}
return QOIError.INVALID_DATA?;
return INVALID_DATA?;
}
distinct Pixel = inline char[<4>];

View File

@@ -28,7 +28,7 @@ fn void ArenaAllocator.clear(&self)
struct ArenaAllocatorHeader @local
{
usz size;
char[?] data;
char[*] data;
}
macro ArenaAllocator* wrap(char[] bytes)
@@ -57,17 +57,18 @@ fn void ArenaAllocator.reset(&self, usz mark) @dynamic => self.used = mark;
@require !alignment || math::is_power_of_2(alignment)
@require alignment <= mem::MAX_MEMORY_ALIGNMENT : `alignment too big`
@require size > 0
@return! mem::INVALID_ALLOC_SIZE, mem::OUT_OF_MEMORY
*>
fn void*! ArenaAllocator.acquire(&self, usz size, AllocInitType init_type, usz alignment) @dynamic
fn void*? ArenaAllocator.acquire(&self, usz size, AllocInitType init_type, usz alignment) @dynamic
{
alignment = alignment_for_allocation(alignment);
usz total_len = self.data.len;
if (size > total_len) return AllocationFailure.CHUNK_TOO_LARGE?;
if (size > total_len) return mem::INVALID_ALLOC_SIZE?;
void* start_mem = self.data.ptr;
void* unaligned_pointer_to_offset = start_mem + self.used + ArenaAllocatorHeader.sizeof;
void* mem = mem::aligned_pointer(unaligned_pointer_to_offset, alignment);
usz end = (usz)(mem - self.data.ptr) + size;
if (end > total_len) return AllocationFailure.OUT_OF_MEMORY?;
if (end > total_len) return mem::OUT_OF_MEMORY?;
self.used = end;
ArenaAllocatorHeader* header = mem - ArenaAllocatorHeader.sizeof;
header.size = size;
@@ -80,13 +81,14 @@ fn void*! ArenaAllocator.acquire(&self, usz size, AllocInitType init_type, usz a
@require alignment <= mem::MAX_MEMORY_ALIGNMENT : `alignment too big`
@require old_pointer != null
@require size > 0
@return! mem::INVALID_ALLOC_SIZE, mem::OUT_OF_MEMORY
*>
fn void*! ArenaAllocator.resize(&self, void *old_pointer, usz size, usz alignment) @dynamic
fn void*? ArenaAllocator.resize(&self, void *old_pointer, usz size, usz alignment) @dynamic
{
alignment = alignment_for_allocation(alignment);
assert(old_pointer >= self.data.ptr, "Pointer originates from a different allocator.");
usz total_len = self.data.len;
if (size > total_len) return AllocationFailure.CHUNK_TOO_LARGE?;
if (size > total_len) return mem::INVALID_ALLOC_SIZE?;
ArenaAllocatorHeader* header = old_pointer - ArenaAllocatorHeader.sizeof;
usz old_size = header.size;
// Do last allocation and alignment match?
@@ -99,7 +101,7 @@ fn void*! ArenaAllocator.resize(&self, void *old_pointer, usz size, usz alignmen
else
{
usz new_used = self.used + size - old_size;
if (new_used > total_len) return AllocationFailure.OUT_OF_MEMORY?;
if (new_used > total_len) return mem::OUT_OF_MEMORY?;
self.used = new_used;
}
header.size = size;

View File

@@ -78,8 +78,9 @@ fn void DynamicArenaAllocator.release(&self, void* ptr, bool) @dynamic
@require size > 0 : `Resize doesn't support zeroing`
@require old_pointer != null : `Resize doesn't handle null pointers`
@require self.page != null : `tried to realloc pointer on invalid allocator`
@return! mem::INVALID_ALLOC_SIZE, mem::OUT_OF_MEMORY
*>
fn void*! DynamicArenaAllocator.resize(&self, void* old_pointer, usz size, usz alignment) @dynamic
fn void*? DynamicArenaAllocator.resize(&self, void* old_pointer, usz size, usz alignment) @dynamic
{
DynamicArenaPage* current_page = self.page;
alignment = alignment_for_allocation(alignment);
@@ -129,15 +130,16 @@ fn void DynamicArenaAllocator.reset(&self, usz mark = 0) @dynamic
<*
@require math::is_power_of_2(alignment)
@require size > 0
@return! mem::INVALID_ALLOC_SIZE, mem::OUT_OF_MEMORY
*>
fn void*! DynamicArenaAllocator._alloc_new(&self, usz size, usz alignment) @local
fn void*? DynamicArenaAllocator._alloc_new(&self, usz size, usz alignment) @local
{
// First, make sure that we can align it, extending the page size if needed.
usz page_size = max(self.page_size, mem::aligned_offset(size + DynamicArenaChunk.sizeof + alignment, alignment));
assert(page_size > size + DynamicArenaChunk.sizeof);
// Grab the page without alignment (we do it ourselves)
void* mem = allocator::malloc_try(self.backing_allocator, page_size)!;
DynamicArenaPage*! page = allocator::new_try(self.backing_allocator, DynamicArenaPage);
DynamicArenaPage*? page = allocator::new_try(self.backing_allocator, DynamicArenaPage);
if (catch err = page)
{
allocator::free(self.backing_allocator, mem);
@@ -159,8 +161,9 @@ fn void*! DynamicArenaAllocator._alloc_new(&self, usz size, usz alignment) @loca
<*
@require size > 0 : `acquire expects size > 0`
@require !alignment || math::is_power_of_2(alignment)
@return! mem::INVALID_ALLOC_SIZE, mem::OUT_OF_MEMORY
*>
fn void*! DynamicArenaAllocator.acquire(&self, usz size, AllocInitType init_type, usz alignment) @dynamic
fn void*? DynamicArenaAllocator.acquire(&self, usz size, AllocInitType init_type, usz alignment) @dynamic
{
alignment = alignment_for_allocation(alignment);
DynamicArenaPage* page = self.page;

View File

@@ -21,7 +21,7 @@ fn void SimpleHeapAllocator.init(&self, MemoryAllocFn allocator)
self.free_list = null;
}
fn void*! SimpleHeapAllocator.acquire(&self, usz size, AllocInitType init_type, usz alignment) @dynamic
fn void*? SimpleHeapAllocator.acquire(&self, usz size, AllocInitType init_type, usz alignment) @dynamic
{
if (init_type == ZERO)
{
@@ -30,7 +30,7 @@ fn void*! SimpleHeapAllocator.acquire(&self, usz size, AllocInitType init_type,
return alignment > 0 ? @aligned_alloc(self._alloc, size, alignment) : self._alloc(size);
}
fn void*! SimpleHeapAllocator.resize(&self, void* old_pointer, usz size, usz alignment) @dynamic
fn void*? SimpleHeapAllocator.resize(&self, void* old_pointer, usz size, usz alignment) @dynamic
{
return alignment > 0
? @aligned_realloc(self._calloc, self._free, old_pointer, size, alignment)
@@ -52,7 +52,7 @@ fn void SimpleHeapAllocator.release(&self, void* old_pointer, bool aligned) @dyn
<*
@require old_pointer && bytes > 0
*>
fn void*! SimpleHeapAllocator._realloc(&self, void* old_pointer, usz bytes) @local
fn void*? SimpleHeapAllocator._realloc(&self, void* old_pointer, usz bytes) @local
{
// Find the block header.
Header* block = (Header*)old_pointer - 1;
@@ -64,14 +64,14 @@ fn void*! SimpleHeapAllocator._realloc(&self, void* old_pointer, usz bytes) @loc
return new;
}
fn void*! SimpleHeapAllocator._calloc(&self, usz bytes) @local
fn void*? SimpleHeapAllocator._calloc(&self, usz bytes) @local
{
void* data = self._alloc(bytes)!;
mem::clear(data, bytes, mem::DEFAULT_MEM_ALIGNMENT);
return data;
}
fn void*! SimpleHeapAllocator._alloc(&self, usz bytes) @local
fn void*? SimpleHeapAllocator._alloc(&self, usz bytes) @local
{
usz aligned_bytes = mem::aligned_offset(bytes, mem::DEFAULT_MEM_ALIGNMENT);
if (!self.free_list)
@@ -120,7 +120,7 @@ fn void*! SimpleHeapAllocator._alloc(&self, usz bytes) @local
return self._alloc(aligned_bytes);
}
fn void! SimpleHeapAllocator.add_block(&self, usz aligned_bytes) @local
fn void? SimpleHeapAllocator.add_block(&self, usz aligned_bytes) @local
{
assert(mem::aligned_offset(aligned_bytes, mem::DEFAULT_MEM_ALIGNMENT) == aligned_bytes);
char[] result = self.alloc_fn(aligned_bytes + Header.sizeof)!;

View File

@@ -10,36 +10,36 @@ const LibcAllocator LIBC_ALLOCATOR = {};
distinct LibcAllocator (Allocator, Printable) = uptr;
fn String LibcAllocator.to_string(&self, Allocator allocator) @dynamic => "Libc allocator".copy(allocator);
fn usz! LibcAllocator.to_format(&self, Formatter *format) @dynamic => format.print("Libc allocator");
fn usz? LibcAllocator.to_format(&self, Formatter *format) @dynamic => format.print("Libc allocator");
module std::core::mem::allocator @if(env::POSIX);
import std::os;
import libc;
fn void*! LibcAllocator.acquire(&self, usz bytes, AllocInitType init_type, usz alignment) @dynamic
fn void*? LibcAllocator.acquire(&self, usz bytes, AllocInitType init_type, usz alignment) @dynamic
{
if (init_type == ZERO)
{
void* data @noinit;
if (alignment > mem::DEFAULT_MEM_ALIGNMENT)
{
if (posix::posix_memalign(&data, alignment, bytes)) return AllocationFailure.OUT_OF_MEMORY?;
if (posix::posix_memalign(&data, alignment, bytes)) return mem::OUT_OF_MEMORY?;
mem::clear(data, bytes, mem::DEFAULT_MEM_ALIGNMENT);
return data;
}
return libc::calloc(1, bytes) ?: AllocationFailure.OUT_OF_MEMORY?;
return libc::calloc(1, bytes) ?: mem::OUT_OF_MEMORY?;
}
else
{
void* data @noinit;
if (alignment > mem::DEFAULT_MEM_ALIGNMENT)
{
if (posix::posix_memalign(&data, alignment, bytes)) return AllocationFailure.OUT_OF_MEMORY?;
if (posix::posix_memalign(&data, alignment, bytes)) return mem::OUT_OF_MEMORY?;
}
else
{
if (!(data = libc::malloc(bytes))) return AllocationFailure.OUT_OF_MEMORY?;
if (!(data = libc::malloc(bytes))) return mem::OUT_OF_MEMORY?;
}
$if env::TESTING:
for (usz i = 0; i < bytes; i++) ((char*)data)[i] = 0xAA;
@@ -48,11 +48,11 @@ fn void*! LibcAllocator.acquire(&self, usz bytes, AllocInitType init_type, usz a
}
}
fn void*! LibcAllocator.resize(&self, void* old_ptr, usz new_bytes, usz alignment) @dynamic
fn void*? LibcAllocator.resize(&self, void* old_ptr, usz new_bytes, usz alignment) @dynamic
{
if (alignment <= mem::DEFAULT_MEM_ALIGNMENT) return libc::realloc(old_ptr, new_bytes) ?: AllocationFailure.OUT_OF_MEMORY?;
if (alignment <= mem::DEFAULT_MEM_ALIGNMENT) return libc::realloc(old_ptr, new_bytes) ?: mem::OUT_OF_MEMORY?;
void* new_ptr;
if (posix::posix_memalign(&new_ptr, alignment, new_bytes)) return AllocationFailure.OUT_OF_MEMORY?;
if (posix::posix_memalign(&new_ptr, alignment, new_bytes)) return mem::OUT_OF_MEMORY?;
$switch:
$case env::DARWIN:
@@ -78,31 +78,31 @@ module std::core::mem::allocator @if(env::WIN32);
import std::os::win32;
import libc;
fn void*! LibcAllocator.acquire(&self, usz bytes, AllocInitType init_type, usz alignment) @dynamic
fn void*? LibcAllocator.acquire(&self, usz bytes, AllocInitType init_type, usz alignment) @dynamic
{
if (init_type == ZERO)
{
if (alignment > 0)
{
return win32::_aligned_recalloc(null, 1, bytes, alignment) ?: AllocationFailure.OUT_OF_MEMORY?;
return win32::_aligned_recalloc(null, 1, bytes, alignment) ?: mem::OUT_OF_MEMORY?;
}
return libc::calloc(1, bytes) ?: AllocationFailure.OUT_OF_MEMORY?;
return libc::calloc(1, bytes) ?: mem::OUT_OF_MEMORY?;
}
void* data = alignment > 0 ? win32::_aligned_malloc(bytes, alignment) : libc::malloc(bytes);
if (!data) return AllocationFailure.OUT_OF_MEMORY?;
if (!data) return mem::OUT_OF_MEMORY?;
$if env::TESTING:
for (usz i = 0; i < bytes; i++) ((char*)data)[i] = 0xAA;
$endif
return data;
}
fn void*! LibcAllocator.resize(&self, void* old_ptr, usz new_bytes, usz alignment) @dynamic
fn void*? LibcAllocator.resize(&self, void* old_ptr, usz new_bytes, usz alignment) @dynamic
{
if (alignment)
{
return win32::_aligned_realloc(old_ptr, new_bytes, alignment) ?: AllocationFailure.OUT_OF_MEMORY?;
return win32::_aligned_realloc(old_ptr, new_bytes, alignment) ?: mem::OUT_OF_MEMORY?;
}
return libc::realloc(old_ptr, new_bytes) ?: AllocationFailure.OUT_OF_MEMORY?;
return libc::realloc(old_ptr, new_bytes) ?: mem::OUT_OF_MEMORY?;
}
fn void LibcAllocator.release(&self, void* old_ptr, bool aligned) @dynamic
@@ -118,17 +118,17 @@ fn void LibcAllocator.release(&self, void* old_ptr, bool aligned) @dynamic
module std::core::mem::allocator @if(!env::WIN32 && !env::POSIX && env::LIBC);
import libc;
fn void*! LibcAllocator.acquire(&self, usz bytes, AllocInitType init_type, usz alignment) @dynamic
fn void*? LibcAllocator.acquire(&self, usz bytes, AllocInitType init_type, usz alignment) @dynamic
{
if (init_type == ZERO)
{
void* data = alignment ? @aligned_alloc(fn void*(usz bytes) => libc::calloc(bytes, 1), bytes, alignment)!! : libc::calloc(bytes, 1);
return data ?: AllocationFailure.OUT_OF_MEMORY?;
return data ?: mem::OUT_OF_MEMORYY?;
}
else
{
void* data = alignment ? @aligned_alloc(libc::malloc, bytes, alignment)!! : libc::malloc(bytes);
if (!data) return AllocationFailure.OUT_OF_MEMORY?;
if (!data) return mem::OUT_OF_MEMORY?;
$if env::TESTING:
for (usz i = 0; i < bytes; i++) ((char*)data)[i] = 0xAA;
$endif
@@ -137,14 +137,14 @@ fn void*! LibcAllocator.acquire(&self, usz bytes, AllocInitType init_type, usz a
}
fn void*! LibcAllocator.resize(&self, void* old_ptr, usz new_bytes, usz alignment) @dynamic
fn void*? LibcAllocator.resize(&self, void* old_ptr, usz new_bytes, usz alignment) @dynamic
{
if (alignment)
{
void* data = @aligned_realloc(fn void*(usz bytes) => libc::malloc(bytes), libc::free, old_ptr, new_bytes, alignment)!!;
return data ?: AllocationFailure.OUT_OF_MEMORY?;
return data ?: mem::OUT_OF_MEMORY?;
}
return libc::realloc(old_ptr, new_bytes) ?: AllocationFailure.OUT_OF_MEMORY?;
return libc::realloc(old_ptr, new_bytes) ?: mem::OUT_OF_MEMORY?;
}

View File

@@ -52,7 +52,7 @@ fn void OnStackAllocator.free(&self)
struct OnStackAllocatorHeader
{
usz size;
char[?] data;
char[*] data;
}
<*
@@ -104,7 +104,7 @@ fn OnStackAllocatorExtraChunk* on_stack_allocator_find_chunk(OnStackAllocator* a
@require old_pointer != null
@require alignment <= mem::MAX_MEMORY_ALIGNMENT : `alignment too big`
*>
fn void*! OnStackAllocator.resize(&self, void* old_pointer, usz size, usz alignment) @dynamic
fn void*? OnStackAllocator.resize(&self, void* old_pointer, usz size, usz alignment) @dynamic
{
if (!allocation_in_stack_mem(self, old_pointer))
{
@@ -124,7 +124,7 @@ fn void*! OnStackAllocator.resize(&self, void* old_pointer, usz size, usz alignm
@require alignment <= mem::MAX_MEMORY_ALIGNMENT : `alignment too big`
@require size > 0
*>
fn void*! OnStackAllocator.acquire(&self, usz size, AllocInitType init_type, usz alignment) @dynamic
fn void*? OnStackAllocator.acquire(&self, usz size, AllocInitType init_type, usz alignment) @dynamic
{
bool aligned = alignment > 0;
alignment = alignment_for_allocation(alignment);

View File

@@ -4,7 +4,7 @@ import std::io, std::math;
struct TempAllocatorChunk @local
{
usz size;
char[?] data;
char[*] data;
}
struct TempAllocator (Allocator)
@@ -13,7 +13,7 @@ struct TempAllocator (Allocator)
TempAllocatorPage* last_page;
usz used;
usz capacity;
char[?] data;
char[*] data;
}
const usz PAGE_IS_ALIGNED @private = (usz)isz.max + 1u;
@@ -26,7 +26,7 @@ struct TempAllocatorPage
usz mark;
usz size;
usz ident;
char[?] data;
char[*] data;
}
macro usz TempAllocatorPage.pagesize(&self) => self.size & ~PAGE_IS_ALIGNED;
@@ -35,7 +35,7 @@ macro bool TempAllocatorPage.is_aligned(&self) => self.size & PAGE_IS_ALIGNED ==
<*
@require size >= 16
*>
fn TempAllocator*! new_temp_allocator(usz size, Allocator allocator)
fn TempAllocator*? new_temp_allocator(usz size, Allocator allocator)
{
TempAllocator* temp = allocator::alloc_with_padding(allocator, TempAllocator, size)!;
temp.last_page = null;
@@ -90,13 +90,13 @@ fn void TempAllocator.reset(&self, usz mark) @dynamic
self.used = mark;
}
fn void! TempAllocator._free_page(&self, TempAllocatorPage* page) @inline @local
fn void? TempAllocator._free_page(&self, TempAllocatorPage* page) @inline @local
{
void* mem = page.start;
return self.backing_allocator.release(mem, page.is_aligned());
}
fn void*! TempAllocator._realloc_page(&self, TempAllocatorPage* page, usz size, usz alignment) @inline @local
fn void*? TempAllocator._realloc_page(&self, TempAllocatorPage* page, usz size, usz alignment) @inline @local
{
// Then the actual start pointer:
void* real_pointer = page.start;
@@ -117,7 +117,7 @@ fn void*! TempAllocator._realloc_page(&self, TempAllocatorPage* page, usz size,
return data;
}
fn void*! TempAllocator.resize(&self, void* pointer, usz size, usz alignment) @dynamic
fn void*? TempAllocator.resize(&self, void* pointer, usz size, usz alignment) @dynamic
{
TempAllocatorChunk *chunk = pointer - TempAllocatorChunk.sizeof;
if (chunk.size == (usz)-1)
@@ -139,7 +139,7 @@ fn void*! TempAllocator.resize(&self, void* pointer, usz size, usz alignment) @d
@require !alignment || math::is_power_of_2(alignment)
@require alignment <= mem::MAX_MEMORY_ALIGNMENT : `alignment too big`
*>
fn void*! TempAllocator.acquire(&self, usz size, AllocInitType init_type, usz alignment) @dynamic
fn void*? TempAllocator.acquire(&self, usz size, AllocInitType init_type, usz alignment) @dynamic
{
alignment = alignment_for_allocation(alignment);
void* start_mem = &self.data;
@@ -210,7 +210,7 @@ fn void*! TempAllocator.acquire(&self, usz size, AllocInitType init_type, usz al
return &page.data[0];
}
fn void! TempAllocator.print_pages(&self, File* f)
fn void? TempAllocator.print_pages(&self, File* f)
{
TempAllocatorPage *last_page = self.last_page;
if (!last_page)

View File

@@ -76,7 +76,7 @@ fn Allocation[] TrackingAllocator.allocations_tlist(&self, Allocator allocator)
*>
fn usz TrackingAllocator.allocation_count(&self) => self.map.count;
fn void*! TrackingAllocator.acquire(&self, usz size, AllocInitType init_type, usz alignment) @dynamic
fn void*? TrackingAllocator.acquire(&self, usz size, AllocInitType init_type, usz alignment) @dynamic
{
void* data = self.inner_allocator.acquire(size, init_type, alignment)!;
self.allocs_total++;
@@ -87,7 +87,7 @@ fn void*! TrackingAllocator.acquire(&self, usz size, AllocInitType init_type, us
return data;
}
fn void*! TrackingAllocator.resize(&self, void* old_pointer, usz size, usz alignment) @dynamic
fn void*? TrackingAllocator.resize(&self, void* old_pointer, usz size, usz alignment) @dynamic
{
void* data = self.inner_allocator.resize(old_pointer, size, alignment)!;
self.map.remove((uptr)old_pointer);
@@ -121,7 +121,7 @@ fn bool TrackingAllocator.has_leaks(&self)
fn void TrackingAllocator.print_report(&self) => self.fprint_report(io::stdout())!!;
fn void! TrackingAllocator.fprint_report(&self, OutStream out) => @pool()
fn void? TrackingAllocator.fprint_report(&self, OutStream out) => @pool()
{
usz total = 0;
usz entries = 0;

View File

@@ -5,7 +5,7 @@ import std::core::array::slice;
@param [in] array
@param [in] element
@return "the first index of the element"
@return! SearchResult.MISSING
@return! NOT_FOUND
*>
macro index_of(array, element)
{
@@ -13,7 +13,7 @@ macro index_of(array, element)
{
if (*e == element) return i;
}
return SearchResult.MISSING?;
return NOT_FOUND?;
}
<*
@@ -34,7 +34,7 @@ macro slice2d(array_ptr, x = 0, xlen = 0, y = 0, ylen = 0)
@param [in] array
@param [in] element
@return "the last index of the element"
@return! SearchResult.MISSING
@return! NOT_FOUND
*>
macro rindex_of(array, element)
{
@@ -42,7 +42,7 @@ macro rindex_of(array, element)
{
if (*e == element) return i;
}
return SearchResult.MISSING?;
return NOT_FOUND?;
}
<*

View File

@@ -32,17 +32,17 @@ macro @is_valid_macro_slot(#arg) @const @builtin => !@typeis(#arg, EmptySlot);
/*
Use `IteratorResult` when reading the end of an iterator, or accessing a result out of bounds.
*/
fault IteratorResult { NO_MORE_ELEMENT }
fault NO_MORE_ELEMENT @builtin;
/*
Use `SearchResult` when trying to return a value from some collection but the element is missing.
*/
fault SearchResult { MISSING }
fault NOT_FOUND @builtin;
/*
Use `CastResult` when an attempt at conversion fails.
*/
fault CastResult { TYPE_MISMATCH }
fault TYPE_MISMATCH @builtin;
def VoidFn = fn void();
@@ -79,11 +79,11 @@ macro void @swap(#a, #b) @builtin
@param $Type : `the type to convert to`
@return `The any.ptr converted to its type.`
@ensure @typeis(return, $Type*)
@return! CastResult.TYPE_MISMATCH
@return! TYPE_MISMATCH
*>
macro anycast(any v, $Type) @builtin
{
if (v.type != $Type.typeid) return CastResult.TYPE_MISMATCH?;
if (v.type != $Type.typeid) return TYPE_MISMATCH?;
return ($Type*)v.ptr;
}
@@ -92,7 +92,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(tmem(), backtraces);
BacktraceList? backtrace = backtrace::symbolize_backtrace(tmem(), backtraces);
if (catch backtrace) return false;
if (backtrace.len() <= backtraces_to_ignore) return false;
io::eprint("\nERROR: '");
@@ -247,7 +247,7 @@ macro bitcast(expr, $Type) @builtin
@param [in] enum_name : `The name of the enum to search for`
@require $Type.kindof == ENUM : `Only enums may be used`
@ensure @typeis(return, $Type)
@return! SearchResult.MISSING
@return! NOT_FOUND
*>
macro enum_by_name($Type, String enum_name) @builtin
{
@@ -256,7 +256,7 @@ macro enum_by_name($Type, String enum_name) @builtin
{
if (name == enum_name) return $Type.from_ordinal(i);
}
return SearchResult.MISSING?;
return NOT_FOUND?;
}
<*
@@ -265,7 +265,7 @@ macro enum_by_name($Type, String enum_name) @builtin
@require $defined($Type.#value) : `Expected '#value' to match an enum associated value`
@require $assignable(value, $typeof(($Type){}.#value)) : `Expected the value to match the type of the associated value`
@ensure @typeis(return, $Type)
@return! SearchResult.MISSING
@return! NOT_FOUND
*>
macro @enum_from_value($Type, #value, value) @builtin
{
@@ -274,7 +274,7 @@ macro @enum_from_value($Type, #value, value) @builtin
{
if (e.#value == value) return e;
}
return SearchResult.MISSING?;
return NOT_FOUND?;
}
<*

View File

@@ -12,28 +12,29 @@ const uint UTF16_SURROGATE_HIGH_VALUE @private = 0xD800;
<*
@param c : `The utf32 codepoint to convert`
@param [out] output : `the resulting buffer`
@return! string::CONVERSION_FAILED
*>
fn usz! char32_to_utf8(Char32 c, char[] output)
fn usz? char32_to_utf8(Char32 c, char[] output)
{
if (!output.len) return UnicodeResult.CONVERSION_FAILED?;
if (!output.len) return string::CONVERSION_FAILED?;
switch (true)
{
case c <= 0x7f:
output[0] = (char)c;
return 1;
case c <= 0x7ff:
if (output.len < 2) return UnicodeResult.CONVERSION_FAILED?;
if (output.len < 2) return string::CONVERSION_FAILED?;
output[0] = (char)(0xC0 | c >> 6);
output[1] = (char)(0x80 | (c & 0x3F));
return 2;
case c <= 0xffff:
if (output.len < 3) return UnicodeResult.CONVERSION_FAILED?;
if (output.len < 3) return string::CONVERSION_FAILED?;
output[0] = (char)(0xE0 | c >> 12);
output[1] = (char)(0x80 | (c >> 6 & 0x3F));
output[2] = (char)(0x80 | (c & 0x3F));
return 3;
case c <= 0x10ffff:
if (output.len < 4) return UnicodeResult.CONVERSION_FAILED?;
if (output.len < 4) return string::CONVERSION_FAILED?;
output[0] = (char)(0xF0 | c >> 18);
output[1] = (char)(0x80 | (c >> 12 & 0x3F));
output[2] = (char)(0x80 | (c >> 6 & 0x3F));
@@ -41,7 +42,7 @@ fn usz! char32_to_utf8(Char32 c, char[] output)
return 4;
default:
// 0x10FFFF and above is not defined.
return UnicodeResult.CONVERSION_FAILED?;
return string::CONVERSION_FAILED?;
}
}
@@ -73,7 +74,7 @@ fn void char32_to_utf16_unsafe(Char32 c, Char16** output)
@param [inout] available : `amount of UTF16 data available.`
@param [inout] output : `the resulting utf8 buffer to write to.`
*>
fn void! char16_to_utf8_unsafe(Char16 *ptr, usz *available, char** output)
fn void? char16_to_utf8_unsafe(Char16 *ptr, usz *available, char** output)
{
Char16 high = *ptr;
if (high & UTF16_SURROGATE_GENERIC_MASK != UTF16_SURROGATE_GENERIC_VALUE)
@@ -83,15 +84,15 @@ fn void! char16_to_utf8_unsafe(Char16 *ptr, usz *available, char** output)
return;
}
// Low surrogate first is an error
if (high & UTF16_SURROGATE_MASK != UTF16_SURROGATE_HIGH_VALUE) return UnicodeResult.INVALID_UTF16?;
if (high & UTF16_SURROGATE_MASK != UTF16_SURROGATE_HIGH_VALUE) return string::INVALID_UTF16?;
// Unmatched high surrogate is an error
if (*available == 1) return UnicodeResult.INVALID_UTF16?;
if (*available == 1) return string::INVALID_UTF16?;
Char16 low = ptr[1];
// Unmatched high surrogate, invalid
if (low & UTF16_SURROGATE_MASK != UTF16_SURROGATE_LOW_VALUE) return UnicodeResult.INVALID_UTF16?;
if (low & UTF16_SURROGATE_MASK != UTF16_SURROGATE_LOW_VALUE) return string::INVALID_UTF16?;
// The high bits of the codepoint are the value bits of the high surrogate
// The low bits of the codepoint are the value bits of the low surrogate
@@ -134,10 +135,10 @@ fn usz char32_to_utf8_unsafe(Char32 c, char** output)
@param [inout] size : `Set to max characters to read, set to characters read`
@return `the parsed 32 bit codepoint`
*>
fn Char32! utf8_to_char32(char* ptr, usz* size)
fn Char32? utf8_to_char32(char* ptr, usz* size)
{
usz max_size = *size;
if (max_size < 1) return UnicodeResult.INVALID_UTF8?;
if (max_size < 1) return string::INVALID_UTF8?;
char c = (ptr++)[0];
if ((c & 0x80) == 0)
@@ -147,40 +148,40 @@ fn Char32! utf8_to_char32(char* ptr, usz* size)
}
if ((c & 0xE0) == 0xC0)
{
if (max_size < 2) return UnicodeResult.INVALID_UTF8?;
if (max_size < 2) return string::INVALID_UTF8?;
*size = 2;
Char32 uc = (c & 0x1F) << 6;
c = *ptr;
// Overlong sequence or invalid second.
if (!uc || c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8?;
if (!uc || c & 0xC0 != 0x80) return string::INVALID_UTF8?;
return uc + c & 0x3F;
}
if ((c & 0xF0) == 0xE0)
{
if (max_size < 3) return UnicodeResult.INVALID_UTF8?;
if (max_size < 3) return string::INVALID_UTF8?;
*size = 3;
Char32 uc = (c & 0x0F) << 12;
c = ptr++[0];
if (c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8?;
if (c & 0xC0 != 0x80) return string::INVALID_UTF8?;
uc += (c & 0x3F) << 6;
c = ptr++[0];
// Overlong sequence or invalid last
if (!uc || c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8?;
if (!uc || c & 0xC0 != 0x80) return string::INVALID_UTF8?;
return uc + c & 0x3F;
}
if (max_size < 4) return UnicodeResult.INVALID_UTF8?;
if ((c & 0xF8) != 0xF0) return UnicodeResult.INVALID_UTF8?;
if (max_size < 4) return string::INVALID_UTF8?;
if ((c & 0xF8) != 0xF0) return string::INVALID_UTF8?;
*size = 4;
Char32 uc = (c & 0x07) << 18;
c = ptr++[0];
if (c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8?;
if (c & 0xC0 != 0x80) return string::INVALID_UTF8?;
uc += (c & 0x3F) << 12;
c = ptr++[0];
if (c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8?;
if (c & 0xC0 != 0x80) return string::INVALID_UTF8?;
uc += (c & 0x3F) << 6;
c = ptr++[0];
// Overlong sequence or invalid last
if (!uc || c & 0xC0 != 0x80) return UnicodeResult.INVALID_UTF8?;
if (!uc || c & 0xC0 != 0x80) return string::INVALID_UTF8?;
return uc + c & 0x3F;
}
@@ -300,7 +301,7 @@ fn usz utf16len_for_utf32(Char32[] utf32)
@param [out] utf8_buffer
@return `the number of bytes written.`
*>
fn usz! utf32to8(Char32[] utf32, char[] utf8_buffer)
fn usz? utf32to8(Char32[] utf32, char[] utf8_buffer)
{
char[] buffer = utf8_buffer;
foreach (uc : utf32)
@@ -320,7 +321,7 @@ fn usz! utf32to8(Char32[] utf32, char[] utf8_buffer)
@param [out] utf32_buffer
@return `the number of Char32s written.`
*>
fn usz! utf8to32(String utf8, Char32[] utf32_buffer)
fn usz? utf8to32(String utf8, Char32[] utf32_buffer)
{
usz len = utf8.len;
Char32* ptr = utf32_buffer.ptr;
@@ -328,7 +329,7 @@ fn usz! utf8to32(String utf8, Char32[] utf32_buffer)
usz buf_len = utf32_buffer.len;
for (usz i = 0; i < len;)
{
if (len32 == buf_len) return UnicodeResult.CONVERSION_FAILED?;
if (len32 == buf_len) return string::CONVERSION_FAILED?;
usz width = len - i;
Char32 uc = utf8_to_char32(&utf8[i], &width) @inline!;
i += width;
@@ -347,7 +348,7 @@ fn usz! utf8to32(String utf8, Char32[] utf32_buffer)
@param [in] utf16 : `The UTF16 array containing the data to convert.`
@param [out] utf8_buffer : `the (sufficiently large) buffer to hold the UTF16 data.`
*>
fn void! utf16to8_unsafe(Char16[] utf16, char* utf8_buffer)
fn void? utf16to8_unsafe(Char16[] utf16, char* utf8_buffer)
{
usz len16 = utf16.len;
for (usz i = 0; i < len16;)
@@ -366,7 +367,7 @@ fn void! utf16to8_unsafe(Char16[] utf16, char* utf8_buffer)
@param [in] utf8 : `The UTF8 buffer containing the data to convert.`
@param [out] utf32_buffer : `the (sufficiently large) buffer to hold the UTF8 data.`
*>
fn void! utf8to32_unsafe(String utf8, Char32* utf32_buffer)
fn void? utf8to32_unsafe(String utf8, Char32* utf32_buffer)
{
usz len = utf8.len;
for (usz i = 0; i < len;)
@@ -386,7 +387,7 @@ fn void! utf8to32_unsafe(String utf8, Char32* utf32_buffer)
@param [in] utf8 : `The UTF8 buffer containing the data to convert.`
@param [out] utf16_buffer : `the (sufficiently large) buffer to hold the UTF8 data.`
*>
fn void! utf8to16_unsafe(String utf8, Char16* utf16_buffer)
fn void? utf8to16_unsafe(String utf8, Char16* utf16_buffer)
{
usz len = utf8.len;
for (usz i = 0; i < len;)

View File

@@ -324,13 +324,13 @@ fn void DString.clear(self)
self.data().len = 0;
}
fn usz! DString.write(&self, char[] buffer) @dynamic
fn usz? DString.write(&self, char[] buffer) @dynamic
{
self.append_chars((String)buffer);
return buffer.len;
}
fn void! DString.write_byte(&self, char c) @dynamic
fn void? DString.write_byte(&self, char c) @dynamic
{
self.append_char(c);
}
@@ -535,7 +535,7 @@ macro void DString.insert_at(&self, usz index, value)
$endswitch
}
fn usz! DString.appendf(&self, String format, args...) @maydiscard
fn usz? DString.appendf(&self, String format, args...) @maydiscard
{
if (!self.data()) self.tinit(format.len + 20);
@pool(self.data().allocator)
@@ -546,7 +546,7 @@ fn usz! DString.appendf(&self, String format, args...) @maydiscard
};
}
fn usz! DString.appendfn(&self, String format, args...) @maydiscard
fn usz? DString.appendfn(&self, String format, args...) @maydiscard
{
if (!self.data()) self.tinit(format.len + 20);
@pool(self.data().allocator)
@@ -577,7 +577,7 @@ fn DString join(Allocator allocator, String[] s, String joiner)
return res;
}
fn void! out_string_append_fn(void* data, char c) @private
fn void? out_string_append_fn(void* data, char c) @private
{
DString* s = data;
s.append_char(c);
@@ -619,7 +619,7 @@ fn void DString.reserve(&self, usz addition)
*self = (DString)allocator::realloc(data.allocator, data, StringData.sizeof + new_capacity);
}
fn usz! DString.read_from_stream(&self, InStream reader)
fn usz? DString.read_from_stream(&self, InStream reader)
{
if (&reader.available)
{
@@ -654,5 +654,5 @@ struct StringData @private
Allocator allocator;
usz len;
usz capacity;
char[?] chars;
char[*] chars;
}

View File

@@ -8,6 +8,8 @@ import std::math;
const MAX_MEMORY_ALIGNMENT = 0x1000_0000;
const DEFAULT_MEM_ALIGNMENT = (void*.alignof) * 2;
fault OUT_OF_MEMORY, INVALID_ALLOC_SIZE;
macro bool @constant_is_power_of_2($x) @const @private
{
return $x != 0 && ($x & ($x - 1)) == 0;
@@ -25,7 +27,7 @@ macro bool @constant_is_power_of_2($x) @const @private
@return "A vector with the loaded values where the mask is true, passthru where the mask is false"
*>
macro masked_load(ptr, bool[<?>] mask, passthru)
macro masked_load(ptr, bool[<*>] mask, passthru)
{
return $$masked_load(ptr, mask, passthru, 0);
}
@@ -45,7 +47,7 @@ macro masked_load(ptr, bool[<?>] mask, passthru)
@return "A vector with the loaded values where the mask is true, passthru where the mask is false"
*>
macro @masked_load_aligned(ptr, bool[<?>] mask, passthru, usz $alignment)
macro @masked_load_aligned(ptr, bool[<*>] mask, passthru, usz $alignment)
{
return $$masked_load(ptr, mask, passthru, $alignment);
}
@@ -65,7 +67,7 @@ macro @masked_load_aligned(ptr, bool[<?>] mask, passthru, usz $alignment)
@return "A vector with the loaded values where the mask is true, passthru where the mask is false"
*>
macro gather(ptrvec, bool[<?>] mask, passthru)
macro gather(ptrvec, bool[<*>] mask, passthru)
{
return $$gather(ptrvec, mask, passthru, 0);
}
@@ -88,7 +90,7 @@ macro gather(ptrvec, bool[<?>] mask, passthru)
@return "A vector with the loaded values where the mask is true, passthru where the mask is false"
*>
macro @gather_aligned(ptrvec, bool[<?>] mask, passthru, usz $alignment)
macro @gather_aligned(ptrvec, bool[<*>] mask, passthru, usz $alignment)
{
return $$gather(ptrvec, mask, passthru, $alignment);
}
@@ -105,7 +107,7 @@ macro @gather_aligned(ptrvec, bool[<?>] mask, passthru, usz $alignment)
@require @typekind(value) == VECTOR : "Expected value to be a vector"
@require value.len == mask.len : "Mask and value must have the same length"
*>
macro masked_store(ptr, value, bool[<?>] mask)
macro masked_store(ptr, value, bool[<*>] mask)
{
return $$masked_store(ptr, value, mask, 0);
}
@@ -122,7 +124,7 @@ macro masked_store(ptr, value, bool[<?>] mask)
@require @constant_is_power_of_2($alignment) : "The alignment must be a power of two"
*>
macro @masked_store_aligned(ptr, value, bool[<?>] mask, usz $alignment)
macro @masked_store_aligned(ptr, value, bool[<*>] mask, usz $alignment)
{
return $$masked_store(ptr, value, mask, $alignment);
}
@@ -138,7 +140,7 @@ macro @masked_store_aligned(ptr, value, bool[<?>] mask, usz $alignment)
@require mask.len == ptrvec.len : "Mask and ptrvec must have the same length"
*>
macro scatter(ptrvec, value, bool[<?>] mask)
macro scatter(ptrvec, value, bool[<*>] mask)
{
return $$scatter(ptrvec, value, mask, 0);
}
@@ -156,7 +158,7 @@ macro scatter(ptrvec, value, bool[<?>] mask)
@require mask.len == ptrvec.len : "Mask and ptrvec must have the same length"
@require @constant_is_power_of_2($alignment) : "The alignment must be a power of two"
*>
macro @scatter_aligned(ptrvec, value, bool[<?>] mask, usz $alignment)
macro @scatter_aligned(ptrvec, value, bool[<*>] mask, usz $alignment)
{
return $$scatter(ptrvec, value, mask, $alignment);
}

View File

@@ -24,28 +24,26 @@ interface Allocator
@require !alignment || math::is_power_of_2(alignment)
@require alignment <= mem::MAX_MEMORY_ALIGNMENT : `alignment too big`
@require size > 0
@return! mem::INVALID_ALLOC_SIZE, mem::OUT_OF_MEMORY
*>
fn void*! acquire(usz size, AllocInitType init_type, usz alignment = 0);
fn void*? acquire(usz size, AllocInitType init_type, usz alignment = 0);
<*
@require !alignment || math::is_power_of_2(alignment)
@require alignment <= mem::MAX_MEMORY_ALIGNMENT : `alignment too big`
@require ptr != null
@require new_size > 0
@return! mem::INVALID_ALLOC_SIZE, mem::OUT_OF_MEMORY
*>
fn void*! resize(void* ptr, usz new_size, usz alignment = 0);
fn void*? resize(void* ptr, usz new_size, usz alignment = 0);
<*
@require ptr != null
*>
fn void release(void* ptr, bool aligned);
}
def MemoryAllocFn = fn char[]!(usz);
def MemoryAllocFn = fn char[]?(usz);
fault AllocationFailure
{
OUT_OF_MEMORY,
CHUNK_TOO_LARGE,
}
fn usz alignment_for_allocation(usz alignment) @inline @private
{
@@ -57,7 +55,7 @@ macro void* malloc(Allocator allocator, usz size) @nodiscard
return malloc_try(allocator, size)!!;
}
macro void*! malloc_try(Allocator allocator, usz size) @nodiscard
macro void*? malloc_try(Allocator allocator, usz size) @nodiscard
{
if (!size) return null;
$if env::TESTING:
@@ -74,7 +72,7 @@ macro void* calloc(Allocator allocator, usz size) @nodiscard
return calloc_try(allocator, size)!!;
}
macro void*! calloc_try(Allocator allocator, usz size) @nodiscard
macro void*? calloc_try(Allocator allocator, usz size) @nodiscard
{
if (!size) return null;
return allocator.acquire(size, ZERO);
@@ -85,7 +83,7 @@ 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
macro void*? realloc_try(Allocator allocator, void* ptr, usz new_size) @nodiscard
{
if (!new_size)
{
@@ -105,7 +103,7 @@ macro void free(Allocator allocator, void* ptr)
allocator.release(ptr, false);
}
macro void*! malloc_aligned(Allocator allocator, usz size, usz alignment) @nodiscard
macro void*? malloc_aligned(Allocator allocator, usz size, usz alignment) @nodiscard
{
if (!size) return null;
$if env::TESTING:
@@ -117,13 +115,13 @@ macro void*! malloc_aligned(Allocator allocator, usz size, usz alignment) @nodis
$endif
}
macro void*! calloc_aligned(Allocator allocator, usz size, usz alignment) @nodiscard
macro void*? calloc_aligned(Allocator allocator, usz size, usz alignment) @nodiscard
{
if (!size) return null;
return allocator.acquire(size, ZERO, alignment);
}
macro void*! realloc_aligned(Allocator allocator, void* ptr, usz new_size, usz alignment) @nodiscard
macro void*? realloc_aligned(Allocator allocator, void* ptr, usz new_size, usz alignment) @nodiscard
{
if (!new_size)
{
@@ -305,7 +303,7 @@ fn any clone_any(Allocator allocator, any value) @nodiscard
@require alignment > 0
@require bytes <= isz.max
*>
macro void*! @aligned_alloc(#alloc_fn, usz bytes, usz alignment)
macro void*? @aligned_alloc(#alloc_fn, usz bytes, usz alignment)
{
if (alignment < void*.alignof) alignment = void*.alignof;
usz header = AlignedBlock.sizeof + alignment;
@@ -328,7 +326,7 @@ struct AlignedBlock
void* start;
}
macro void! @aligned_free(#free_fn, void* old_pointer)
macro void? @aligned_free(#free_fn, void* old_pointer)
{
AlignedBlock* desc = (AlignedBlock*)old_pointer - 1;
$if @typekind(#free_fn(desc.start)) == OPTIONAL:
@@ -342,7 +340,7 @@ macro void! @aligned_free(#free_fn, void* old_pointer)
@require bytes > 0
@require alignment > 0
*>
macro void*! @aligned_realloc(#calloc_fn, #free_fn, void* old_pointer, usz bytes, usz alignment)
macro void*? @aligned_realloc(#calloc_fn, #free_fn, void* old_pointer, usz bytes, usz alignment)
{
AlignedBlock* desc = (AlignedBlock*)old_pointer - 1;
void* data_start = desc.start;
@@ -448,14 +446,14 @@ fn TempAllocator* temp_allocator_next() @private
const NullAllocator NULL_ALLOCATOR = {};
distinct NullAllocator (Allocator) = uptr;
fn void*! NullAllocator.acquire(&self, usz bytes, AllocInitType init_type, usz alignment) @dynamic
fn void*? NullAllocator.acquire(&self, usz bytes, AllocInitType init_type, usz alignment) @dynamic
{
return AllocationFailure.OUT_OF_MEMORY?;
return mem::OUT_OF_MEMORY?;
}
fn void*! NullAllocator.resize(&self, void* old_ptr, usz new_bytes, usz alignment) @dynamic
fn void*? NullAllocator.resize(&self, void* old_ptr, usz new_bytes, usz alignment) @dynamic
{
return AllocationFailure.OUT_OF_MEMORY?;
return mem::OUT_OF_MEMORY?;
}
fn void NullAllocator.release(&self, void* old_ptr, bool aligned) @dynamic

View File

@@ -11,7 +11,7 @@ struct WasmMemory
uptr use;
}
fn char[]! WasmMemory.allocate_block(&self, usz bytes)
fn char[]? WasmMemory.allocate_block(&self, usz bytes)
{
if (!self.allocation)
{
@@ -25,7 +25,7 @@ fn char[]! WasmMemory.allocate_block(&self, usz bytes)
}
usz blocks_required = (bytes_required + WASM_BLOCK_SIZE + 1) / WASM_BLOCK_SIZE;
if ($$wasm_memory_grow(0, blocks_required) == -1) return AllocationFailure.OUT_OF_MEMORY?;
if ($$wasm_memory_grow(0, blocks_required) == -1) return mem::OUT_OF_MEMORY?;
self.allocation = $$wasm_memory_size(0) * WASM_BLOCK_SIZE;
defer self.use += bytes;
return ((char*)self.use)[:bytes];

View File

@@ -56,10 +56,7 @@ struct MachHeader64
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++)
@@ -70,7 +67,7 @@ fn bool name_cmp(char* a, char[16]* b)
return false;
}
fn SegmentCommand64*! find_segment(MachHeader* header, char* segname)
fn SegmentCommand64*? find_segment(MachHeader* header, char* segname)
{
LoadCommand* command = (void*)header + MachHeader64.sizeof;
for (uint i = 0; i < header.ncmds; i++)
@@ -82,9 +79,9 @@ fn SegmentCommand64*! find_segment(MachHeader* header, char* segname)
}
command = (void*)command + command.cmdsize;
}
return MachoSearch.NOT_FOUND?;
return NOT_FOUND?;
}
fn Section64*! find_section(SegmentCommand64* command, char* sectname)
fn Section64*? find_section(SegmentCommand64* command, char* sectname)
{
Section64* section = (void*)command + SegmentCommand64.sizeof;
for (uint i = 0; i < command.nsects; i++)
@@ -92,13 +89,13 @@ fn Section64*! find_section(SegmentCommand64* command, char* sectname)
if (name_cmp(sectname, &section.sectname)) return section;
section++;
}
return MachoSearch.NOT_FOUND?;
return NOT_FOUND?;
}
macro find_segment_section_body(MachHeader* header, char* segname, char* sectname, $Type)
{
Section64*! section = find_section(find_segment(header, segname), sectname);
Section64*? section = find_section(find_segment(header, segname), sectname);
if (catch section)
{
return ($Type[]){};
@@ -214,7 +211,7 @@ struct TypeId
usz sizeof;
TypeId* inner;
usz len;
typeid[?] additional;
typeid[*] additional;
}
fn void dl_reg_callback(MachHeader* mh, isz vmaddr_slide)

View File

@@ -8,12 +8,8 @@ distinct WString = inline Char16*;
def Char32 = uint;
def Char16 = ushort;
fault UnicodeResult
{
INVALID_UTF8,
INVALID_UTF16,
CONVERSION_FAILED,
}
fault INVALID_UTF8, INVALID_UTF16, CONVERSION_FAILED, EMPTY_STRING, NEGATIVE_VALUE, MALFORMED_INTEGER,
INTEGER_OVERFLOW, MALFORMED_FLOAT, FLOAT_OUT_OF_RANGE;
const uint SURROGATE_OFFSET @private = 0x10000;
const uint SURROGATE_GENERIC_MASK @private = 0xF800;
@@ -23,16 +19,6 @@ const uint SURROGATE_BITS @private = 10;
const uint SURROGATE_LOW_VALUE @private = 0xDC00;
const uint SURROGATE_HIGH_VALUE @private = 0xD800;
fault NumberConversion
{
EMPTY_STRING,
NEGATIVE_VALUE,
MALFORMED_INTEGER,
INTEGER_OVERFLOW,
MALFORMED_FLOAT,
FLOAT_OUT_OF_RANGE,
}
macro Char32* @wstring32(String $string) @builtin
{
@@ -254,7 +240,7 @@ fn String[] String.split(s, Allocator allocator, String needle, usz max = 0, boo
bool no_more = false;
while (!no_more)
{
usz! index = i == max - 1 ? SearchResult.MISSING? : s.index_of(needle);
usz? index = i == max - 1 ? NOT_FOUND? : s.index_of(needle);
String res @noinit;
if (try index)
{
@@ -293,7 +279,7 @@ fn String[] String.split(s, Allocator allocator, String needle, usz max = 0, boo
*>
fn String[] String.tsplit(s, String needle, usz max = 0, bool skip_empty = false) => s.split(tmem(), needle, max, skip_empty) @inline;
fault SplitResult { BUFFER_EXCEEDED }
fault BUFFER_EXCEEDED;
<*
Split a string into parts, e.g "a|b|c" split with "|" yields { "a", "b", "c" }
@@ -304,16 +290,16 @@ fault SplitResult { BUFFER_EXCEEDED }
@param max : "Max number of elements, 0 means no limit, defaults to 0"
@require needle.len > 0 : "The needle must be at least 1 character long"
@ensure return.len > 0
@return! SplitResult.BUFFER_EXCEEDED : `If there are more elements than would fit the buffer`
@return! BUFFER_EXCEEDED : `If there are more elements than would fit the buffer`
*>
fn String[]! String.split_to_buffer(s, String needle, String[] buffer, usz max = 0, bool skip_empty = false)
fn String[]? String.split_to_buffer(s, String needle, String[] buffer, usz max = 0, bool skip_empty = false)
{
usz max_capacity = buffer.len;
usz i = 0;
bool no_more = false;
while (!no_more)
{
usz! index = i == max - 1 ? SearchResult.MISSING? : s.index_of(needle);
usz? index = i == max - 1 ? NOT_FOUND? : s.index_of(needle);
String res @noinit;
if (try index)
{
@@ -331,7 +317,7 @@ fn String[]! String.split_to_buffer(s, String needle, String[] buffer, usz max =
}
if (i == max_capacity)
{
return SplitResult.BUFFER_EXCEEDED?;
return BUFFER_EXCEEDED?;
}
buffer[i++] = res;
}
@@ -359,15 +345,15 @@ fn bool String.contains(s, String needle)
@pure
@ensure return < s.len
@return "the index of the needle"
@return! SearchResult.MISSING : "if the needle cannot be found"
@return! NOT_FOUND : "if the needle cannot be found"
*>
fn usz! String.index_of_char(s, char needle)
fn usz? String.index_of_char(s, char needle)
{
foreach (i, c : s)
{
if (c == needle) return i;
}
return SearchResult.MISSING?;
return NOT_FOUND?;
}
<*
@@ -378,9 +364,9 @@ fn usz! String.index_of_char(s, char needle)
@pure
@ensure return < s.len
@return "the index of the needle"
@return! SearchResult.MISSING : "if the needle cannot be found"
@return! NOT_FOUND : "if the needle cannot be found"
*>
fn usz! String.index_of_chars(String s, char[] needle)
fn usz? String.index_of_chars(String s, char[] needle)
{
foreach (i, c : s)
{
@@ -390,7 +376,7 @@ fn usz! String.index_of_chars(String s, char[] needle)
}
}
return SearchResult.MISSING?;
return NOT_FOUND?;
}
<*
@@ -402,17 +388,17 @@ fn usz! String.index_of_chars(String s, char[] needle)
@pure
@ensure return < s.len
@return "the index of the needle"
@return! SearchResult.MISSING : "if the needle cannot be found starting from the start_index"
@return! NOT_FOUND : "if the needle cannot be found starting from the start_index"
*>
fn usz! String.index_of_char_from(s, char needle, usz start_index)
fn usz? String.index_of_char_from(s, char needle, usz start_index)
{
usz len = s.len;
if (len <= start_index) return SearchResult.MISSING?;
if (len <= start_index) return NOT_FOUND?;
for (usz i = start_index; i < len; i++)
{
if (s[i] == needle) return i;
}
return SearchResult.MISSING?;
return NOT_FOUND?;
}
<*
@@ -423,15 +409,15 @@ fn usz! String.index_of_char_from(s, char needle, usz start_index)
@pure
@ensure return < s.len
@return "the index of the needle"
@return! SearchResult.MISSING : "if the needle cannot be found"
@return! NOT_FOUND : "if the needle cannot be found"
*>
fn usz! String.rindex_of_char(s, char needle)
fn usz? String.rindex_of_char(s, char needle)
{
foreach_r (i, c : s)
{
if (c == needle) return i;
}
return SearchResult.MISSING?;
return NOT_FOUND?;
}
<*
@@ -443,9 +429,9 @@ fn usz! String.rindex_of_char(s, char needle)
@ensure return < s.len
@require needle.len > 0 : "The needle must be len 1 or more"
@return "the index of the needle"
@return! SearchResult.MISSING : "if the needle cannot be found"
@return! NOT_FOUND : "if the needle cannot be found"
*>
fn usz! String.index_of(s, String needle)
fn usz? String.index_of(s, String needle)
{
usz needed = needle.len;
if (needed > 0 && s.len >= needed)
@@ -456,7 +442,7 @@ fn usz! String.index_of(s, String needle)
if (c == first && s[i:needed] == needle) return i;
}
}
return SearchResult.MISSING?;
return NOT_FOUND?;
}
<*
@@ -468,9 +454,9 @@ fn usz! String.index_of(s, String needle)
@ensure return < s.len
@require needle.len > 0 : "The needle must be len 1 or more"
@return "the index of the needle"
@return! SearchResult.MISSING : "if the needle cannot be found"
@return! NOT_FOUND : "if the needle cannot be found"
*>
fn usz! String.rindex_of(s, String needle)
fn usz? String.rindex_of(s, String needle)
{
usz needed = needle.len;
if (needed > 0 && s.len >= needed)
@@ -481,7 +467,7 @@ fn usz! String.rindex_of(s, String needle)
if (c == first && s[i:needed] == needle) return i;
}
}
return SearchResult.MISSING?;
return NOT_FOUND?;
}
fn String ZString.str_view(str)
@@ -570,10 +556,9 @@ fn String ZString.tcopy(z)
<*
Convert an UTF-8 string to UTF-16
@return "The UTF-16 string as a slice, allocated using the given allocator"
@return! UnicodeResult.INVALID_UTF8 : "If the string contained an invalid UTF-8 sequence"
@return! AllocationFailure : "If allocation of the string fails"
@return! INVALID_UTF8 : "If the string contained an invalid UTF-8 sequence"
*>
fn Char16[]! String.to_utf16(s, Allocator allocator)
fn Char16[]? String.to_utf16(s, Allocator allocator)
{
usz len16 = conv::utf16len_for_utf8(s);
Char16* data = allocator::alloc_array_try(allocator, Char16, len16 + 1)!;
@@ -582,16 +567,16 @@ fn Char16[]! String.to_utf16(s, Allocator allocator)
return data[:len16];
}
fn Char16[]! String.to_temp_utf16(s) => s.to_utf16(tmem());
fn Char16[]? String.to_temp_utf16(s) => s.to_utf16(tmem());
fn WString! String.to_wstring(s, Allocator allocator)
fn WString? String.to_wstring(s, Allocator allocator)
{
return (WString)s.to_utf16(allocator).ptr;
}
fn WString! String.to_temp_wstring(s) => s.to_wstring(tmem());
fn WString? String.to_temp_wstring(s) => s.to_wstring(tmem());
fn Char32[]! String.to_utf32(s, Allocator allocator)
fn Char32[]? String.to_utf32(s, Allocator allocator)
{
usz codepoints = conv::utf8_codepoints(s);
Char32* data = allocator::alloc_array_try(allocator, Char32, codepoints + 1)!;
@@ -600,7 +585,7 @@ fn Char32[]! String.to_utf32(s, Allocator allocator)
return data[:codepoints];
}
fn Char32[]! String.to_temp_utf32(s) => s.to_utf32(tmem());
fn Char32[]? String.to_temp_utf32(s) => s.to_utf32(tmem());
<*
Convert a string to ASCII lower case in place.
@@ -665,7 +650,7 @@ fn String String.to_upper_tcopy(s)
return s.to_upper_copy(tmem());
}
fn String! from_utf32(Allocator allocator, Char32[] utf32)
fn String? from_utf32(Allocator allocator, Char32[] utf32)
{
usz len = conv::utf8len_for_utf32(utf32);
char* data = allocator::malloc_try(allocator, len + 1)!;
@@ -675,7 +660,7 @@ fn String! from_utf32(Allocator allocator, Char32[] utf32)
return (String)data[:len];
}
fn String! from_utf16(Allocator allocator, Char16[] utf16)
fn String? from_utf16(Allocator allocator, Char16[] utf16)
{
usz len = conv::utf8len_for_utf16(utf16);
char* data = allocator::malloc_try(allocator, len + 1)!;
@@ -685,7 +670,7 @@ fn String! from_utf16(Allocator allocator, Char16[] utf16)
return (String)data[:len];
}
fn String! from_wstring(Allocator allocator, WString wstring)
fn String? from_wstring(Allocator allocator, WString wstring)
{
usz utf16_len;
while (wstring[utf16_len] != 0) utf16_len++;
@@ -693,8 +678,8 @@ fn String! from_wstring(Allocator allocator, WString wstring)
return from_utf16(allocator, utf16);
}
fn String! tfrom_wstring(WString wstring) => from_wstring(tmem(), wstring) @inline;
fn String! tfrom_utf16(Char16[] utf16) => from_utf16(tmem(), utf16) @inline;
fn String? tfrom_wstring(WString wstring) => from_wstring(tmem(), wstring) @inline;
fn String? tfrom_utf16(Char16[] utf16) => from_utf16(tmem(), utf16) @inline;
fn usz String.utf8_codepoints(s)
{
@@ -716,12 +701,12 @@ macro String.to_integer(string, $Type, int base = 10)
usz index = 0;
char* ptr = string.ptr;
while (index < len && ascii::is_blank_m(ptr[index])) index++;
if (len == index) return NumberConversion.EMPTY_STRING?;
if (len == index) return EMPTY_STRING?;
bool is_negative;
switch (string[index])
{
case '-':
if ($Type.min == 0) return NumberConversion.NEGATIVE_VALUE?;
if ($Type.min == 0) return NEGATIVE_VALUE?;
is_negative = true;
index++;
case '+':
@@ -729,7 +714,7 @@ macro String.to_integer(string, $Type, int base = 10)
default:
break;
}
if (len == index) return NumberConversion.MALFORMED_INTEGER?;
if (len == index) return MALFORMED_INTEGER?;
$Type base_used = ($Type)base;
if (string[index] == '0' && base == 10)
{
@@ -752,7 +737,7 @@ macro String.to_integer(string, $Type, int base = 10)
default:
break;
}
if (len == index) return NumberConversion.MALFORMED_INTEGER?;
if (len == index) return MALFORMED_INTEGER?;
}
$Type value = 0;
while (index != len)
@@ -762,41 +747,41 @@ macro String.to_integer(string, $Type, int base = 10)
{
case base_used != 16 || c < 'A': c -= '0';
case c <= 'F': c -= 'A' - 10;
case c < 'a' || c > 'f': return NumberConversion.MALFORMED_INTEGER?;
case c < 'a' || c > 'f': return MALFORMED_INTEGER?;
default: c -= 'a' - 10;
}
if (c >= base_used) return NumberConversion.MALFORMED_INTEGER?;
if (c >= base_used) return MALFORMED_INTEGER?;
do
{
if (is_negative)
{
$Type new_value = value * base_used - c;
if (new_value > value) return NumberConversion.INTEGER_OVERFLOW?;
if (new_value > value) return INTEGER_OVERFLOW?;
value = new_value;
break;
}
$Type new_value = value * base_used + c;
if (new_value < value) return NumberConversion.INTEGER_OVERFLOW?;
if (new_value < value) return INTEGER_OVERFLOW?;
value = new_value;
};
}
return value;
}
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 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, 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 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);
fn double? String.to_double(s) => s.to_real(double);
fn float? String.to_float(s) => s.to_real(float);
fn Splitter String.splitter(self, String split)
{
@@ -822,15 +807,15 @@ fn void Splitter.reset(&self)
self.current = 0;
}
fn String! Splitter.next(&self)
fn String? Splitter.next(&self)
{
while (true)
{
usz len = self.string.len;
usz current = self.current;
if (current >= len) return IteratorResult.NO_MORE_ELEMENT?;
if (current >= len) return NO_MORE_ELEMENT?;
String remaining = self.string[current..];
usz! next = remaining.index_of(self.split);
usz? next = remaining.index_of(self.split);
if (try next)
{
self.current = current + next + self.split.len;

View File

@@ -11,22 +11,22 @@ fn void StringIterator.reset(&self)
self.current = 0;
}
fn Char32! StringIterator.next(&self)
fn Char32? StringIterator.next(&self)
{
usz len = self.utf8.len;
usz current = self.current;
if (current >= len) return IteratorResult.NO_MORE_ELEMENT?;
if (current >= len) return NO_MORE_ELEMENT?;
usz read = (len - current < 4 ? len - current : 4);
Char32 res = conv::utf8_to_char32(&self.utf8[current], &read)!;
self.current += read;
return res;
}
fn Char32! StringIterator.peek(&self)
fn Char32? StringIterator.peek(&self)
{
usz len = self.utf8.len;
usz current = self.current;
if (current >= len) return IteratorResult.NO_MORE_ELEMENT?;
if (current >= len) return NO_MORE_ELEMENT?;
usz read = (len - current < 4 ? len - current : 4);
Char32 res = conv::utf8_to_char32(&self.utf8[current], &read)!;
return res;
@@ -37,13 +37,13 @@ fn bool StringIterator.has_next(&self)
return self.current < self.utf8.len;
}
fn Char32! StringIterator.get(&self)
fn Char32? StringIterator.get(&self)
{
usz len = self.utf8.len;
usz current = self.current;
usz read = (len - current < 4 ? len - current : 4);
usz index = current > read ? current - read : 0;
if (index >= len) return IteratorResult.NO_MORE_ELEMENT?;
if (index >= len) return NO_MORE_ELEMENT?;
Char32 res = conv::utf8_to_char32(&self.utf8[index], &read)!;
return res;
}

View File

@@ -34,13 +34,13 @@ const uint[2] B1B_MAX = { 9007199, 254740991 };
<*
@require chars.len > 0
*>
macro double! decfloat(char[] chars, int $bits, int $emin, int sign)
macro double? decfloat(char[] chars, int $bits, int $emin, int sign)
{
uint[KMAX] x;
const uint[2] TH = B1B_MAX;
int emax = - $emin - $bits + 3;
const int[?] P10S = { 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 };
const int[*] P10S = { 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 };
usz index;
bool got_digit = chars[0] == '0';
bool got_rad;
@@ -64,7 +64,7 @@ macro double! decfloat(char[] chars, int $bits, int $emin, int sign)
got_rad = true;
if (index == last_char)
{
if (!got_digit) return NumberConversion.MALFORMED_FLOAT?;
if (!got_digit) return MALFORMED_FLOAT?;
return sign * 0.0;
}
if (index != last_char && (c = chars[++index]) == '0')
@@ -83,7 +83,7 @@ macro double! decfloat(char[] chars, int $bits, int $emin, int sign)
switch
{
case c == '.':
if (got_rad) return NumberConversion.MALFORMED_FLOAT?;
if (got_rad) return MALFORMED_FLOAT?;
got_rad = true;
lrp = dc;
case k < KMAX - 3:
@@ -113,24 +113,24 @@ macro double! decfloat(char[] chars, int $bits, int $emin, int sign)
c = chars[++index];
}
if (!got_rad) lrp = dc;
if (!got_digit) return NumberConversion.MALFORMED_FLOAT?;
if (!got_digit) return MALFORMED_FLOAT?;
if ((c | 32) == 'e')
{
if (last_char == index) return NumberConversion.MALFORMED_FLOAT?;
long e10 = String.to_long((String)chars[index + 1..]) ?? NumberConversion.MALFORMED_FLOAT?!;
if (last_char == index) return MALFORMED_FLOAT?;
long e10 = String.to_long((String)chars[index + 1..]) ?? MALFORMED_FLOAT?!;
lrp += e10;
}
else if (index != last_char)
{
return NumberConversion.MALFORMED_FLOAT?;
return MALFORMED_FLOAT?;
}
// Handle zero specially to avoid nasty special cases later
if (!x[0]) return sign * 0.0;
// Optimize small integers (w/no exponent) and over/under-flow
if (lrp == dc && dc < 10 && ($bits > 30 || (ulong)x[0] >> $bits == 0)) return sign * (double)x[0];
if (lrp > - $emin / 2) return NumberConversion.FLOAT_OUT_OF_RANGE?;
if (lrp < $emin - 2 * math::DOUBLE_MANT_DIG) return NumberConversion.FLOAT_OUT_OF_RANGE?;
if (lrp > - $emin / 2) return FLOAT_OUT_OF_RANGE?;
if (lrp < $emin - 2 * math::DOUBLE_MANT_DIG) return FLOAT_OUT_OF_RANGE?;
// Align incomplete final B1B digit
if (j)
@@ -320,12 +320,12 @@ macro double! decfloat(char[] chars, int $bits, int $emin, int sign)
y *= 0.5;
e2++;
}
if (e2 + math::DOUBLE_MANT_DIG > emax || (denormal && frac)) return NumberConversion.MALFORMED_FLOAT?;
if (e2 + math::DOUBLE_MANT_DIG > emax || (denormal && frac)) return MALFORMED_FLOAT?;
}
return math::scalbn(y, e2);
}
macro double! hexfloat(char[] chars, int $bits, int $emin, int sign)
macro double? hexfloat(char[] chars, int $bits, int $emin, int sign)
{
double scale = 1;
uint x;
@@ -351,7 +351,7 @@ macro double! hexfloat(char[] chars, int $bits, int $emin, int sign)
got_rad = true;
if (index == last_char)
{
if (!got_digit) return NumberConversion.MALFORMED_FLOAT?;
if (!got_digit) return MALFORMED_FLOAT?;
return sign * 0.0;
}
if (index != last_char && (c = chars[++index]) == '0')
@@ -369,7 +369,7 @@ macro double! hexfloat(char[] chars, int $bits, int $emin, int sign)
{
if (c == '.')
{
if (got_rad) return NumberConversion.MALFORMED_FLOAT?;
if (got_rad) return MALFORMED_FLOAT?;
got_rad = true;
rp = dc;
}
@@ -393,20 +393,20 @@ macro double! hexfloat(char[] chars, int $bits, int $emin, int sign)
if (index == last_char) break;
c = chars[++index];
}
if (!got_digit) return NumberConversion.MALFORMED_FLOAT?;
if (!got_digit) return MALFORMED_FLOAT?;
if (!got_rad) rp = dc;
for (; dc < 8; dc++) x *= 16;
long e2;
if ((c | 32) == 'p')
{
long e2val = String.to_long((String)chars[index + 1..]) ?? (NumberConversion.MALFORMED_FLOAT?)!;
long e2val = String.to_long((String)chars[index + 1..]) ?? (MALFORMED_FLOAT?)!;
e2 = e2val;
}
e2 += 4 * rp - 32;
if (!x) return sign * 0.0;
if (e2 > -$emin) return NumberConversion.FLOAT_OUT_OF_RANGE?;
if (e2 < $emin - 2 * math::DOUBLE_MANT_DIG) return NumberConversion.FLOAT_OUT_OF_RANGE?;
if (e2 > -$emin) return FLOAT_OUT_OF_RANGE?;
if (e2 < $emin - 2 * math::DOUBLE_MANT_DIG) return FLOAT_OUT_OF_RANGE?;
while (x < 0x80000000)
{
@@ -441,7 +441,7 @@ macro double! hexfloat(char[] chars, int $bits, int $emin, int sign)
}
y = bias + sign * (double)x + sign * y;
y -= bias;
if (!y) return NumberConversion.FLOAT_OUT_OF_RANGE?;
if (!y) return FLOAT_OUT_OF_RANGE?;
return math::scalbn(y, (int)e2);
}
@@ -463,7 +463,7 @@ macro String.to_real(chars, $Type) @private
$endswitch
while (chars.len && chars[0] == ' ') chars = chars[1..];
if (!chars.len) return NumberConversion.MALFORMED_FLOAT?;
if (!chars.len) return MALFORMED_FLOAT?;
if (chars.len != 1)
{

View File

@@ -13,13 +13,13 @@ fault MathError
DIVISION_BY_ZERO
}
fn double! divide(int a, int b)
fn double? divide(int a, int b)
{
if (b == 0) return MathError.DIVISION_BY_ZERO?;
return (double)(a) / (double)(b);
}
fn void! test_div() @test
fn void? test_div() @test
{
test::eq(2, divide(6, 3)!);
test::ne(1, 2);

View File

@@ -3,11 +3,7 @@ module std::core::types;
import libc;
fault ConversionResult
{
VALUE_OUT_OF_RANGE,
VALUE_OUT_OF_UNSIGNED_RANGE,
}
fault VALUE_OUT_OF_RANGE, VALUE_OUT_OF_UNSIGNED_RANGE;
<*
@require $Type.kindof.is_int() : "Type was not an integer"
@@ -33,47 +29,47 @@ macro any_to_int(any v, $Type)
{
case ichar:
ichar c = *(char*)v.ptr;
if (is_mixed_signed && c < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE?;
if (is_mixed_signed && c < 0) return VALUE_OUT_OF_UNSIGNED_RANGE?;
return ($Type)c;
case short:
short s = *(short*)v.ptr;
if (is_mixed_signed && s < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE?;
if (s > max || s < min) return ConversionResult.VALUE_OUT_OF_RANGE?;
if (is_mixed_signed && s < 0) return VALUE_OUT_OF_UNSIGNED_RANGE?;
if (s > max || s < min) return VALUE_OUT_OF_RANGE?;
return ($Type)s;
case int:
int i = *(int*)v.ptr;
if (is_mixed_signed && i < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE?;
if (i > max || i < min) return ConversionResult.VALUE_OUT_OF_RANGE?;
if (is_mixed_signed && i < 0) return VALUE_OUT_OF_UNSIGNED_RANGE?;
if (i > max || i < min) return VALUE_OUT_OF_RANGE?;
return ($Type)i;
case long:
long l = *(long*)v.ptr;
if (is_mixed_signed && l < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE?;
if (l > max || l < min) return ConversionResult.VALUE_OUT_OF_RANGE?;
if (is_mixed_signed && l < 0) return VALUE_OUT_OF_UNSIGNED_RANGE?;
if (l > max || l < min) return VALUE_OUT_OF_RANGE?;
return ($Type)l;
case int128:
int128 i = *(int128*)v.ptr;
if (is_mixed_signed && i < 0) return ConversionResult.VALUE_OUT_OF_UNSIGNED_RANGE?;
if (i > max || i < min) return ConversionResult.VALUE_OUT_OF_RANGE?;
if (is_mixed_signed && i < 0) return VALUE_OUT_OF_UNSIGNED_RANGE?;
if (i > max || i < min) return VALUE_OUT_OF_RANGE?;
return ($Type)i;
case char:
char c = *(char*)v.ptr;
if (c > max) return ConversionResult.VALUE_OUT_OF_RANGE?;
if (c > max) return VALUE_OUT_OF_RANGE?;
return ($Type)c;
case ushort:
ushort s = *(ushort*)v.ptr;
if (s > max || s < min) return ConversionResult.VALUE_OUT_OF_RANGE?;
if (s > max || s < min) return VALUE_OUT_OF_RANGE?;
return ($Type)s;
case uint:
uint i = *(uint*)v.ptr;
if (i > max || i < min) return ConversionResult.VALUE_OUT_OF_RANGE?;
if (i > max || i < min) return VALUE_OUT_OF_RANGE?;
return ($Type)i;
case ulong:
ulong l = *(ulong*)v.ptr;
if (l > max || l < min) return ConversionResult.VALUE_OUT_OF_RANGE?;
if (l > max || l < min) return VALUE_OUT_OF_RANGE?;
return ($Type)l;
case uint128:
uint128 i = *(uint128*)v.ptr;
if (i > max || i < min) return ConversionResult.VALUE_OUT_OF_RANGE?;
if (i > max || i < min) return VALUE_OUT_OF_RANGE?;
return ($Type)i;
default:
unreachable();
@@ -363,7 +359,6 @@ enum TypeKind : char
ANYFAULT,
ANY,
ENUM,
FAULT,
STRUCT,
UNION,
BITSTRUCT,

View File

@@ -20,7 +20,7 @@ const char DEFAULT_PAD = '=';
@require padding < 0xFF : "Invalid padding character"
@return "The encoded string."
*>
fn String! encode(Allocator allocator, char[] src, char padding = DEFAULT_PAD, Base32Alphabet* alphabet = &STANDARD)
fn String? encode(Allocator allocator, char[] src, char padding = DEFAULT_PAD, Base32Alphabet* alphabet = &STANDARD)
{
char[] dst = allocator::alloc_array(allocator, char, encode_len(src.len, padding));
return encode_buffer(src, dst, padding, alphabet);
@@ -34,14 +34,14 @@ fn String! encode(Allocator allocator, char[] src, char padding = DEFAULT_PAD, B
@require padding < 0xFF : "Invalid padding character"
@return "The decoded data."
*>
fn char[]! decode(Allocator allocator, char[] src, char padding = DEFAULT_PAD, Base32Alphabet* alphabet = &STANDARD)
fn char[]? decode(Allocator allocator, char[] src, char padding = DEFAULT_PAD, Base32Alphabet* alphabet = &STANDARD)
{
char[] dst = allocator::alloc_array(allocator, char, decode_len(src.len, padding));
return decode_buffer(src, dst, padding, alphabet);
}
fn String! tencode(char[] code, char padding = DEFAULT_PAD, Base32Alphabet* alphabet = &STANDARD) @inline => encode(tmem(), code, padding, alphabet);
fn char[]! tdecode(char[] code, char padding = DEFAULT_PAD, Base32Alphabet* alphabet = &STANDARD) @inline => decode(tmem(), code, padding, alphabet);
fn String? tencode(char[] code, char padding = DEFAULT_PAD, Base32Alphabet* alphabet = &STANDARD) @inline => encode(tmem(), code, padding, alphabet);
fn char[]? tdecode(char[] code, char padding = DEFAULT_PAD, Base32Alphabet* alphabet = &STANDARD) @inline => decode(tmem(), code, padding, alphabet);
<*
Calculate the length in bytes of the decoded data.
@@ -84,9 +84,9 @@ fn usz encode_len(usz n, char padding)
@require padding < 0xFF : "Invalid padding character"
@require dst.len >= decode_len(src.len, padding) : "Destination buffer too small"
@return "The resulting dst buffer"
@return! DecodingFailure
@return! encoding::INVALID_PADDING, encoding::INVALID_CHARACTER
*>
fn char[]! decode_buffer(char[] src, char[] dst, char padding = DEFAULT_PAD, Base32Alphabet* alphabet = &STANDARD)
fn char[]? decode_buffer(char[] src, char[] dst, char padding = DEFAULT_PAD, Base32Alphabet* alphabet = &STANDARD)
{
if (src.len == 0) return dst[:0];
char* dst_ptr = dst;
@@ -101,12 +101,12 @@ fn char[]! decode_buffer(char[] src, char[] dst, char padding = DEFAULT_PAD, Bas
{
if (src.len == 0)
{
if (padding > 0) return DecodingFailure.INVALID_PADDING?;
if (padding > 0) return encoding::INVALID_PADDING?;
break;
}
if (src[0] == padding) break;
buf[i] = alphabet.reverse[src[0]];
if (buf[i] == INVALID) return DecodingFailure.INVALID_CHARACTER?;
if (buf[i] == INVALID) return encoding::INVALID_CHARACTER?;
src = src[1..];
}
@@ -150,7 +150,7 @@ fn char[]! decode_buffer(char[] src, char[] dst, char padding = DEFAULT_PAD, Bas
dst[0] = buf[1] >> 2 | buf[0] << 3;
n++;
default:
return DecodingFailure.INVALID_CHARACTER?;
return encoding::INVALID_CHARACTER?;
}
if (dst.len < 5) break;
dst = dst[5..];

View File

@@ -49,14 +49,14 @@ fn String encode(Allocator allocator, char[] src, char padding = DEFAULT_PAD, Ba
return encode_buffer(src, dst, padding, alphabet);
}
fn char[]! decode(Allocator allocator, char[] src, char padding = DEFAULT_PAD, Base64Alphabet* alphabet = &STANDARD)
fn char[]? decode(Allocator allocator, char[] src, char padding = DEFAULT_PAD, Base64Alphabet* alphabet = &STANDARD)
{
char[] dst = allocator::alloc_array(allocator, char, decode_len(src.len, padding))!;
return decode_buffer(src, dst, padding, alphabet);
}
fn String tencode(char[] code, char padding = DEFAULT_PAD, Base64Alphabet* alphabet = &STANDARD) @inline => encode(tmem(), code, padding, alphabet);
fn char[]! tdecode(char[] code, char padding = DEFAULT_PAD, Base64Alphabet* alphabet = &STANDARD) @inline => decode(tmem(), code, padding, alphabet);
fn char[]? tdecode(char[] code, char padding = DEFAULT_PAD, Base64Alphabet* alphabet = &STANDARD) @inline => decode(tmem(), code, padding, alphabet);
<*
@@ -79,19 +79,19 @@ fn usz encode_len(usz n, char padding)
@param padding : "The padding character or 0 if none"
@require padding < 0xFF : "Invalid padding character"
@return "The size of the input once decoded."
@return! DecodingFailure.INVALID_PADDING
@return! encoding::INVALID_PADDING
*>
fn usz! decode_len(usz n, char padding)
fn usz? decode_len(usz n, char padding)
{
usz dn = n / 4 * 3;
usz trailing = n % 4;
if (padding)
{
if (trailing != 0) return DecodingFailure.INVALID_PADDING?;
if (trailing != 0) return encoding::INVALID_PADDING?;
// source size is multiple of 4
return dn;
}
if (trailing == 1) return DecodingFailure.INVALID_PADDING?;
if (trailing == 1) return encoding::INVALID_PADDING?;
return dn + trailing * 3 / 4;
}
@@ -163,9 +163,9 @@ fn String encode_buffer(char[] src, char[] dst, char padding = DEFAULT_PAD, Base
@require (decode_len(src.len, padding) ?? 0) <= dst.len : "Destination buffer too small"
@require padding < 0xFF : "Invalid padding character"
@return "The decoded data."
@return! DecodingFailure
@return! encoding::INVALID_CHARACTER, encoding::INVALID_PADDING
*>
fn char[]! decode_buffer(char[] src, char[] dst, char padding = DEFAULT_PAD, Base64Alphabet* alphabet = &STANDARD)
fn char[]? decode_buffer(char[] src, char[] dst, char padding = DEFAULT_PAD, Base64Alphabet* alphabet = &STANDARD)
{
if (src.len == 0) return dst[:0];
usz dn = decode_len(src.len, padding)!;
@@ -196,7 +196,7 @@ fn char[]! decode_buffer(char[] src, char[] dst, char padding = DEFAULT_PAD, Bas
case c1:
case c2:
case c3:
return DecodingFailure.INVALID_CHARACTER?;
return encoding::INVALID_CHARACTER?;
}
uint group = (uint)c0 << 18 | (uint)c1 << 12 | (uint)c2 << 6 | (uint)c3;
dst[0] = (char)(group >> 16);
@@ -211,7 +211,7 @@ fn char[]! decode_buffer(char[] src, char[] dst, char padding = DEFAULT_PAD, Bas
src = src[^trailing..];
char c0 = alphabet.reverse[src[0]];
char c1 = alphabet.reverse[src[1]];
if (c0 == 0xFF || c1 == 0xFF) return DecodingFailure.INVALID_PADDING?;
if (c0 == 0xFF || c1 == 0xFF) return encoding::INVALID_PADDING?;
if (!padding)
{
switch (src.len)
@@ -221,7 +221,7 @@ fn char[]! decode_buffer(char[] src, char[] dst, char padding = DEFAULT_PAD, Bas
dst[0] = (char)(group >> 16);
case 3:
char c2 = alphabet.reverse[src[2]];
if (c2 == 0xFF) return DecodingFailure.INVALID_CHARACTER?;
if (c2 == 0xFF) return encoding::INVALID_CHARACTER?;
uint group = (uint)c0 << 18 | (uint)c1 << 12 | (uint)c2 << 6;
dst[0] = (char)(group >> 16);
dst[1] = (char)(group >> 8);
@@ -235,13 +235,13 @@ fn char[]! decode_buffer(char[] src, char[] dst, char padding = DEFAULT_PAD, Bas
switch (padding)
{
case src[2]:
if (src[3] != padding) return DecodingFailure.INVALID_PADDING?;
if (src[3] != padding) return encoding::INVALID_PADDING?;
uint group = (uint)c0 << 18 | (uint)c1 << 12;
dst[0] = (char)(group >> 16);
dn -= 2;
case src[3]:
char c2 = alphabet.reverse[src[2]];
if (c2 == 0xFF) return DecodingFailure.INVALID_CHARACTER?;
if (c2 == 0xFF) return encoding::INVALID_CHARACTER?;
uint group = (uint)c0 << 18 | (uint)c1 << 12 | (uint)c2 << 6;
dst[0] = (char)(group >> 16);
dst[1] = (char)(group >> 8);

View File

@@ -15,7 +15,7 @@ struct CsvRow (Printable)
Allocator allocator;
}
fn usz! CsvRow.to_format(&self, Formatter* f) @dynamic
fn usz? CsvRow.to_format(&self, Formatter* f) @dynamic
{
return f.printf("%s", self.list);
}
@@ -41,7 +41,7 @@ fn void CsvReader.init(&self, InStream stream, String separator = ",")
<*
@param [&inout] allocator
*>
fn CsvRow! CsvReader.read_row(self, Allocator allocator)
fn CsvRow? CsvReader.read_row(self, Allocator allocator)
{
String row = io::readline(allocator, self.stream)!;
defer catch allocator::free(allocator, row);
@@ -49,7 +49,7 @@ fn CsvRow! CsvReader.read_row(self, Allocator allocator)
return { list, row, allocator };
}
fn CsvRow! CsvReader.tread_row(self)
fn CsvRow? CsvReader.tread_row(self)
{
return self.read_row(tmem()) @inline;
}
@@ -64,12 +64,12 @@ fn void CsvRow.free(&self)
self.allocator = null;
}
fn void! CsvReader.skip_row(self) @maydiscard => @pool()
fn void? CsvReader.skip_row(self) @maydiscard => @pool()
{
(void)io::treadline(self.stream);
}
macro void! CsvReader.@each_row(self, int rows = int.max; @body(String[] row)) @maydiscard
macro void? CsvReader.@each_row(self, int rows = int.max; @body(String[] row)) @maydiscard
{
InStream stream = self.stream;
String sep = self.separator;
@@ -77,10 +77,10 @@ macro void! CsvReader.@each_row(self, int rows = int.max; @body(String[] row)) @
{
@stack_mem(512; Allocator mem)
{
String! s = io::readline(mem, stream);
String? s = io::readline(mem, stream);
if (catch err = s)
{
if (err == IoError.EOF) return;
if (err == io::EOF) return;
return err?;
}
@body(s.split(mem, sep));

View File

@@ -1,7 +1,3 @@
module std::encoding;
fault DecodingFailure
{
INVALID_CHARACTER,
INVALID_PADDING,
}
fault INVALID_CHARACTER, INVALID_PADDING;

View File

@@ -8,7 +8,7 @@ fn String encode_buffer(char[] code, char[] buffer)
return (String)buffer[:encode_bytes(code, buffer)];
}
fn char[]! decode_buffer(char[] code, char[] buffer)
fn char[]? decode_buffer(char[] code, char[] buffer)
{
return buffer[:decode_bytes(code, buffer)!];
}
@@ -19,14 +19,14 @@ fn String encode(Allocator allocator, char[] code)
return (String)data[:encode_bytes(code, data)];
}
fn char[]! decode(Allocator allocator, char[] code)
fn char[]? decode(Allocator allocator, char[] code)
{
char[] data = allocator::alloc_array(allocator, char, decode_len(code.len));
return data[:decode_bytes(code, data)!];
}
fn String tencode(char[] code) @inline => encode(tmem(), code);
fn char[]! tdecode(char[] code) @inline => decode(tmem(), code);
fn char[]? tdecode(char[] code) @inline => decode(tmem(), code);
<*
@@ -72,24 +72,24 @@ macro usz decode_len(usz n) => n / 2;
@param dst : "The decoded input."
@require src.len % 2 == 0 : "src is not of even length"
@require dst.len >= decode_len(src.len) : "Destination array is not large enough"
@return! DecodingFailure.INVALID_CHARACTER
@return! encoding::INVALID_CHARACTER
*>
fn usz! decode_bytes(char[] src, char[] dst)
fn usz? decode_bytes(char[] src, char[] dst)
{
usz i;
for (usz j = 1; j < src.len; j += 2)
{
char a = HEXREVERSE[src[j - 1]];
char b = HEXREVERSE[src[j]];
if (a > 0x0f || b > 0x0f) return DecodingFailure.INVALID_CHARACTER?;
if (a > 0x0f || b > 0x0f) return encoding::INVALID_CHARACTER?;
dst[i] = (a << 4) | b;
i++;
}
return i;
}
const char[?] HEXALPHABET @private = "0123456789abcdef";
const char[?] HEXREVERSE @private =
const char[*] HEXALPHABET @private = "0123456789abcdef";
const char[*] HEXREVERSE @private =
x`ffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffff
ffffffffffffffffffffffffffffffff

View File

@@ -6,26 +6,19 @@ import std::io;
import std::ascii;
import std::collections::object;
fault JsonParsingError
{
EOF,
UNEXPECTED_CHARACTER,
INVALID_ESCAPE_SEQUENCE,
DUPLICATE_MEMBERS,
INVALID_NUMBER,
}
fault UNEXPECTED_CHARACTER, INVALID_ESCAPE_SEQUENCE, DUPLICATE_MEMBERS, INVALID_NUMBER;
fn Object*! parse_string(Allocator allocator, String s)
fn Object*? parse_string(Allocator allocator, String s)
{
return parse(allocator, (ByteReader){}.init(s));
}
fn Object*! tparse_string(String s)
fn Object*? tparse_string(String s)
{
return parse(tmem(), (ByteReader){}.init(s));
}
fn Object*! parse(Allocator allocator, InStream s)
fn Object*? parse(Allocator allocator, InStream s)
{
@stack_mem(512; Allocator smem)
{
@@ -37,7 +30,7 @@ fn Object*! parse(Allocator allocator, InStream s)
};
}
fn Object*! tparse(InStream s)
fn Object*? tparse(InStream s)
{
return parse(tmem(), s);
}
@@ -78,7 +71,7 @@ struct JsonContext @local
}
fn Object*! parse_from_token(JsonContext* context, JsonTokenType token) @local
fn Object*? parse_from_token(JsonContext* context, JsonTokenType token) @local
{
switch (token)
{
@@ -88,21 +81,21 @@ fn Object*! parse_from_token(JsonContext* context, JsonTokenType token) @local
case COMMA:
case RBRACE:
case RBRACKET:
case COLON: return JsonParsingError.UNEXPECTED_CHARACTER?;
case COLON: return UNEXPECTED_CHARACTER?;
case STRING: return object::new_string(context.last_string.str_view(), context.allocator);
case NUMBER: return object::new_float(context.last_number, context.allocator);
case TRUE: return object::new_bool(true);
case FALSE: return object::new_bool(false);
case NULL: return object::new_null();
case EOF: return JsonParsingError.EOF?;
case EOF: return io::EOF?;
}
}
fn Object*! parse_any(JsonContext* context) @local
fn Object*? parse_any(JsonContext* context) @local
{
return parse_from_token(context, advance(context));
}
fn JsonTokenType! lex_number(JsonContext *context, char c) @local
fn JsonTokenType? lex_number(JsonContext *context, char c) @local
{
@stack_mem(256; Allocator mem)
{
@@ -137,7 +130,7 @@ fn JsonTokenType! lex_number(JsonContext *context, char c) @local
t.append(c);
c = read_next(context)!;
}
if (!c.is_digit()) return JsonParsingError.INVALID_NUMBER?;
if (!c.is_digit()) return INVALID_NUMBER?;
while (c.is_digit())
{
t.append(c);
@@ -145,13 +138,13 @@ fn JsonTokenType! lex_number(JsonContext *context, char c) @local
}
}
pushback(context, c);
double! d = t.str_view().to_double() ?? JsonParsingError.INVALID_NUMBER?;
double? d = t.str_view().to_double() ?? INVALID_NUMBER?;
context.last_number = d!;
return NUMBER;
};
}
fn Object*! parse_map(JsonContext* context) @local
fn Object*? parse_map(JsonContext* context) @local
{
Object* map = object::new_obj(context.allocator);
defer catch map.free();
@@ -162,9 +155,9 @@ fn Object*! parse_map(JsonContext* context) @local
DString temp_key = dstring::new_with_capacity(mem, 32);
while (token != JsonTokenType.RBRACE)
{
if (token != JsonTokenType.STRING) return JsonParsingError.UNEXPECTED_CHARACTER?;
if (token != JsonTokenType.STRING) return UNEXPECTED_CHARACTER?;
DString string = context.last_string;
if (map.has_key(string.str_view())) return JsonParsingError.DUPLICATE_MEMBERS?;
if (map.has_key(string.str_view())) return DUPLICATE_MEMBERS?;
// Copy the key to our temp holder, since our
// last_string may be used in parse_any
temp_key.clear();
@@ -178,13 +171,13 @@ fn Object*! parse_map(JsonContext* context) @local
token = advance(context)!;
continue;
}
if (token != JsonTokenType.RBRACE) return JsonParsingError.UNEXPECTED_CHARACTER?;
if (token != JsonTokenType.RBRACE) return UNEXPECTED_CHARACTER?;
}
return map;
};
}
fn Object*! parse_array(JsonContext* context) @local
fn Object*? parse_array(JsonContext* context) @local
{
Object* list = object::new_obj(context.allocator);
defer catch list.free();
@@ -199,7 +192,7 @@ fn Object*! parse_array(JsonContext* context) @local
token = advance(context)!;
continue;
}
if (token != JsonTokenType.RBRACKET) return JsonParsingError.UNEXPECTED_CHARACTER?;
if (token != JsonTokenType.RBRACKET) return UNEXPECTED_CHARACTER?;
}
return list;
}
@@ -214,7 +207,7 @@ fn void pushback(JsonContext* context, char c) @local
}
}
fn char! read_next(JsonContext* context) @local
fn char? read_next(JsonContext* context) @local
{
if (context.reached_end) return '\0';
if (context.pushed_back)
@@ -222,10 +215,10 @@ fn char! read_next(JsonContext* context) @local
context.pushed_back = false;
return context.current;
}
char! c = context.stream.read_byte();
char? c = context.stream.read_byte();
if (catch err = c)
{
if (err == IoError.EOF)
if (err == io::EOF)
{
context.reached_end = true;
return '\0';
@@ -239,7 +232,7 @@ fn char! read_next(JsonContext* context) @local
return c;
}
fn JsonTokenType! advance(JsonContext* context) @local
fn JsonTokenType? advance(JsonContext* context) @local
{
char c;
// Skip whitespace
@@ -287,7 +280,7 @@ fn JsonTokenType! advance(JsonContext* context) @local
switch (c)
{
case '\0':
return IoError.EOF?;
return io::EOF?;
case '{':
return LBRACE;
case '}':
@@ -315,25 +308,25 @@ fn JsonTokenType! advance(JsonContext* context) @local
match(context, "ull")!;
return NULL;
default:
return JsonParsingError.UNEXPECTED_CHARACTER?;
return UNEXPECTED_CHARACTER?;
}
}
fn void! match(JsonContext* context, String str) @local
fn void? match(JsonContext* context, String str) @local
{
foreach (c : str)
{
char l = read_next(context)!;
if (l != c) return JsonParsingError.UNEXPECTED_CHARACTER?;
if (l != c) return UNEXPECTED_CHARACTER?;
}
}
fn void! parse_expected(JsonContext* context, JsonTokenType token) @local
fn void? parse_expected(JsonContext* context, JsonTokenType token) @local
{
if (advance(context)! != token) return JsonParsingError.UNEXPECTED_CHARACTER?;
if (advance(context)! != token) return UNEXPECTED_CHARACTER?;
}
fn JsonTokenType! lex_string(JsonContext* context)
fn JsonTokenType? lex_string(JsonContext* context)
{
context.last_string.clear();
while LOOP: (true)
@@ -342,9 +335,9 @@ fn JsonTokenType! lex_string(JsonContext* context)
switch (c)
{
case '\0':
return JsonParsingError.EOF?;
return io::EOF?;
case 1..31:
return JsonParsingError.UNEXPECTED_CHARACTER?;
return UNEXPECTED_CHARACTER?;
case '"':
break LOOP;
case '\\':
@@ -357,9 +350,9 @@ fn JsonTokenType! lex_string(JsonContext* context)
switch (c)
{
case '\0':
return JsonParsingError.EOF?;
return io::EOF?;
case 1..31:
return JsonParsingError.UNEXPECTED_CHARACTER?;
return UNEXPECTED_CHARACTER?;
case '"':
case '\\':
case '/':
@@ -379,13 +372,13 @@ fn JsonTokenType! lex_string(JsonContext* context)
for (int i = 0; i < 4; i++)
{
c = read_next(context)!;
if (!c.is_xdigit()) return JsonParsingError.INVALID_ESCAPE_SEQUENCE?;
if (!c.is_xdigit()) return INVALID_ESCAPE_SEQUENCE?;
val = val << 4 + (c > '9' ? (c | 32) - 'a' + 10 : c - '0');
}
context.last_string.append_char32(val);
continue;
default:
return JsonParsingError.INVALID_ESCAPE_SEQUENCE?;
return INVALID_ESCAPE_SEQUENCE?;
}
context.last_string.append(c);
}

View File

@@ -71,12 +71,12 @@ fn void FrameScheduler.queue_event(&self, Event event)
@atomic_store(self.pending, true);
};
}
fn Event! FrameScheduler.pop_event(&self)
fn Event? FrameScheduler.pop_event(&self)
{
while (true)
{
if (try event = self.events.pop()) return event;
if (!@atomic_load(self.pending)) return IteratorResult.NO_MORE_ELEMENT?;
if (!@atomic_load(self.pending)) return NO_MORE_ELEMENT?;
self.mtx.@in_lock()
{
self.events.add_all(&self.pending_events);
@@ -88,7 +88,7 @@ fn Event! FrameScheduler.pop_event(&self)
self.events.push(self.delayed_events.pop()!!);
}
@atomic_store(self.pending, self.delayed_events.len() > 0);
if (!self.events.len()) return IteratorResult.NO_MORE_ELEMENT?;
if (!self.events.len()) return NO_MORE_ELEMENT?;
};
}
}

View File

@@ -21,7 +21,7 @@ fn void BitReader.clear(&self) @inline
@require nbits <= 8
@require self.len + nbits <= uint.sizeof * 8
*>
fn char! BitReader.read_bits(&self, uint nbits)
fn char? BitReader.read_bits(&self, uint nbits)
{
uint bits = self.bits;
if (self.len < nbits)
@@ -54,7 +54,7 @@ fn void BitWriter.init(&self, OutStream byte_writer)
*self = { .writer = byte_writer };
}
fn void! BitWriter.flush(&self)
fn void? BitWriter.flush(&self)
{
if (self.len == 0) return;
@@ -70,7 +70,7 @@ fn void! BitWriter.flush(&self)
<*
@require nbits <= 32
*>
fn void! BitWriter.write_bits(&self, uint bits, uint nbits)
fn void? BitWriter.write_bits(&self, uint bits, uint nbits)
{
if (nbits == 0) return;
while (self.len + nbits > WRITER_BITS)

View File

@@ -9,12 +9,12 @@ struct File (InStream, OutStream)
module std::io::file;
import libc, std::io::path, std::io::os;
fn File! open(String filename, String mode)
fn File? open(String filename, String mode)
{
return from_handle(os::native_fopen(filename, mode));
}
fn File! open_path(Path path, String mode)
fn File? open_path(Path path, String mode)
{
return from_handle(os::native_fopen(path.str_view(), mode));
}
@@ -39,12 +39,12 @@ fn bool is_dir(String path)
return os::native_is_dir(path);
}
fn usz! get_size(String path)
fn usz? get_size(String path)
{
return os::native_file_size(path);
}
fn void! delete(String filename)
fn void? delete(String filename)
{
return os::native_remove(filename) @inline;
}
@@ -53,7 +53,7 @@ fn void! delete(String filename)
<*
@require self.file != null
*>
fn void! File.reopen(&self, String filename, String mode)
fn void? File.reopen(&self, String filename, String mode)
{
self.file = os::native_freopen(self.file, filename, mode)!;
}
@@ -61,7 +61,7 @@ fn void! File.reopen(&self, String filename, String mode)
<*
@require self.file != null
*>
fn usz! File.seek(&self, isz offset, Seek seek_mode = Seek.SET) @dynamic
fn usz? File.seek(&self, isz offset, Seek seek_mode = Seek.SET) @dynamic
{
os::native_fseek(self.file, offset, seek_mode)!;
return os::native_ftell(self.file);
@@ -73,7 +73,7 @@ Implement later
<*
@require self.file == null
*>
fn void! File.memopen(File* file, char[] data, String mode)
fn void? File.memopen(File* file, char[] data, String mode)
{
@pool()
{
@@ -87,7 +87,7 @@ fn void! File.memopen(File* file, char[] data, String mode)
<*
@require self.file != null
*>
fn void! File.write_byte(&self, char c) @dynamic
fn void? File.write_byte(&self, char c) @dynamic
{
return os::native_fputc(c, self.file);
}
@@ -95,15 +95,15 @@ fn void! File.write_byte(&self, char c) @dynamic
<*
@param [&inout] self
*>
fn void! File.close(&self) @inline @dynamic
fn void? File.close(&self) @inline @dynamic
{
if (self.file && libc::fclose(self.file))
{
switch (libc::errno())
{
case errno::ECONNRESET:
case errno::EBADF: return IoError.FILE_NOT_VALID?;
case errno::EINTR: return IoError.INTERRUPTED?;
case errno::EBADF: return io::FILE_NOT_VALID?;
case errno::EINTR: return io::INTERRUPTED?;
case errno::EDQUOT:
case errno::EFAULT:
case errno::EAGAIN:
@@ -111,8 +111,8 @@ fn void! File.close(&self) @inline @dynamic
case errno::ENETDOWN:
case errno::ENETUNREACH:
case errno::ENOSPC:
case errno::EIO: return IoError.INCOMPLETE_WRITE?;
default: return IoError.UNKNOWN_ERROR?;
case errno::EIO: return io::INCOMPLETE_WRITE?;
default: return io::UNKNOWN_ERROR?;
}
}
self.file = null;
@@ -129,7 +129,7 @@ fn bool File.eof(&self) @inline
<*
@param [in] buffer
*>
fn usz! File.read(&self, char[] buffer) @dynamic
fn usz? File.read(&self, char[] buffer) @dynamic
{
return os::native_fread(self.file, buffer);
}
@@ -138,7 +138,7 @@ fn usz! File.read(&self, char[] buffer) @dynamic
@param [out] buffer
@require self.file != null : `File must be initialized`
*>
fn usz! File.write(&self, char[] buffer) @dynamic
fn usz? File.write(&self, char[] buffer) @dynamic
{
return os::native_fwrite(self.file, buffer);
}
@@ -153,26 +153,26 @@ fn bool File.isatty(self) @if(env::LIBC)
return libc::isatty(self.fd()) > 0;
}
fn char! File.read_byte(&self) @dynamic
fn char? File.read_byte(&self) @dynamic
{
int c = libc::fgetc(self.file);
if (c == -1) return IoError.EOF?;
if (c == -1) return io::EOF?;
return (char)c;
}
<*
Load up to buffer.len characters. Returns IoError.OVERFLOW if the file is longer
Load up to buffer.len characters. Returns io::OVERFLOW if the file is longer
than the buffer.
@param filename : "The path to the file to read"
@param [in] buffer : "The buffer to read to"
*>
fn char[]! load_buffer(String filename, char[] buffer)
fn char[]? load_buffer(String filename, char[] buffer)
{
File file = open(filename, "rb")!;
defer (void)file.close();
usz len = file.seek(0, END)!;
if (len > buffer.len) return IoError.OVERFLOW?;
if (len > buffer.len) return io::OVERFLOW?;
file.seek(0, SET)!;
usz read = 0;
while (read < len)
@@ -183,9 +183,9 @@ fn char[]! load_buffer(String filename, char[] buffer)
}
fn char[]! load(Allocator allocator, String filename) => load_new(filename, allocator);
fn char[]? load(Allocator allocator, String filename) => load_new(filename, allocator);
fn char[]! load_new(String filename, Allocator allocator = allocator::heap())
fn char[]? load_new(String filename, Allocator allocator = allocator::heap())
{
File file = open(filename, "rb")!;
defer (void)file.close();
@@ -201,16 +201,16 @@ fn char[]! load_new(String filename, Allocator allocator = allocator::heap())
return data[:len];
}
fn char[]! load_path_new(Path path, Allocator allocator = allocator::heap()) => load_new(path.str_view(), allocator);
fn char[]? load_path_new(Path path, Allocator allocator = allocator::heap()) => load_new(path.str_view(), allocator);
fn char[]! load_temp(String filename)
fn char[]? load_temp(String filename)
{
return load_new(filename, allocator::temp());
}
fn char[]! load_path_temp(Path path) => load_temp(path.str_view());
fn char[]? load_path_temp(Path path) => load_temp(path.str_view());
fn void! save(String filename, char[] data)
fn void? save(String filename, char[] data)
{
File file = open(filename, "wb")!;
defer (void)file.close();
@@ -224,7 +224,7 @@ fn void! save(String filename, char[] data)
<*
@require self.file != null : `File must be initialized`
*>
fn void! File.flush(&self) @dynamic
fn void? File.flush(&self) @dynamic
{
libc::fflush(self.file);
}

View File

@@ -7,19 +7,13 @@ const int PRINTF_NTOA_BUFFER_SIZE = 256;
interface Printable
{
fn String to_constant_string() @optional;
fn usz! to_format(Formatter* formatter) @optional;
fn usz? to_format(Formatter* formatter) @optional;
}
fault PrintFault
{
BUFFER_EXCEEDED,
INTERNAL_BUFFER_EXCEEDED,
INVALID_FORMAT,
NOT_ENOUGH_ARGUMENTS,
INVALID_ARGUMENT,
}
fault BUFFER_EXCEEDED, INTERNAL_BUFFER_EXCEEDED, INVALID_FORMAT, NOT_ENOUGH_ARGUMENTS,
INVALID_ARGUMENT;
def OutputFn = fn void!(void* buffer, char c);
def OutputFn = fn void?(void* buffer, char c);
def FloatType = double;
@@ -35,7 +29,7 @@ macro bool is_struct_with_default_print($Type)
@require @typekind(value) == STRUCT : `This macro is only valid on macros`
*>
macro usz! struct_to_format(value, Formatter* f, bool $force_dump)
macro usz? struct_to_format(value, Formatter* f, bool $force_dump)
{
var $Type = $typeof(value);
usz total = f.print("{ ")!;
@@ -56,12 +50,12 @@ macro usz! struct_to_format(value, Formatter* f, bool $force_dump)
return total + f.print(" }");
}
fn usz! ReflectedParam.to_format(&self, Formatter* f) @dynamic
fn usz? ReflectedParam.to_format(&self, Formatter* f) @dynamic
{
return f.printf("[Parameter '%s']", self.name);
}
fn usz! Formatter.printf(&self, String format, args...)
fn usz? Formatter.printf(&self, String format, args...)
{
return self.vprintf(format, args) @inline;
}
@@ -96,7 +90,7 @@ fn void Formatter.init(&self, OutputFn out_fn, void* data = null)
*self = { .data = data, .out_fn = out_fn};
}
fn usz! Formatter.out(&self, char c) @private
fn usz? Formatter.out(&self, char c) @private
{
if (catch err = self.out_fn(self.data, c))
{
@@ -107,7 +101,7 @@ fn usz! Formatter.out(&self, char c) @private
return 1;
}
fn usz! Formatter.print_with_function(&self, Printable arg)
fn usz? Formatter.print_with_function(&self, Printable arg)
{
if (&arg.to_format)
{
@@ -137,14 +131,14 @@ fn usz! Formatter.print_with_function(&self, Printable arg)
if (!arg) return self.out_substr("(null)");
return self.out_substr(arg.to_constant_string());
}
return SearchResult.MISSING?;
return NOT_FOUND?;
}
fn usz! Formatter.out_unknown(&self, String category, any arg) @private
fn usz? Formatter.out_unknown(&self, String category, any arg) @private
{
return self.out_substr("[") + self.out_substr(category) + self.out_substr(" type:") + self.ntoa((iptr)arg.type, false, 16) + self.out_substr(", addr:") + self.ntoa((iptr)arg.ptr, false, 16) + self.out_substr("]");
}
fn usz! Formatter.out_str(&self, any arg) @private
fn usz? Formatter.out_str(&self, any arg) @private
{
switch (arg.type.kindof)
{
@@ -153,7 +147,6 @@ fn usz! Formatter.out_str(&self, any arg) @private
case VOID:
return self.out_substr("void");
case ANYFAULT:
case FAULT:
return self.out_substr((*(anyfault*)arg.ptr).nameof);
case INTERFACE:
case ANY:
@@ -187,9 +180,9 @@ fn usz! Formatter.out_str(&self, any arg) @private
return self.out_substr(*(bool*)arg.ptr ? "true" : "false");
default:
}
usz! n = self.print_with_function((Printable)arg);
usz? n = self.print_with_function((Printable)arg);
if (try n) return n;
if (@catch(n) != SearchResult.MISSING) n!;
if (@catch(n) != NOT_FOUND) n!;
switch (arg.type.kindof)
{
case ENUM:
@@ -226,7 +219,7 @@ fn usz! Formatter.out_str(&self, any arg) @private
any deref = any_make(*pointer, inner);
n = self.print_with_function((Printable)deref);
if (try n) return n;
if (@catch(n) != SearchResult.MISSING) n!;
if (@catch(n) != NOT_FOUND) n!;
}
PrintFlags flags = self.flags;
uint width = self.width;
@@ -238,7 +231,7 @@ fn usz! Formatter.out_str(&self, any arg) @private
self.width = 0;
return self.out_substr("0x")! + self.ntoa_any(arg, 16);
case ARRAY:
// this is SomeType[?] so grab the "SomeType"
// this is SomeType[*] so grab the "SomeType"
PrintFlags flags = self.flags;
uint width = self.width;
defer
@@ -272,7 +265,7 @@ fn usz! Formatter.out_str(&self, any arg) @private
}
self.flags = {};
self.width = 0;
// this is SomeType[?] so grab the "SomeType"
// this is SomeType[*] so grab the "SomeType"
typeid inner = arg.type.inner;
usz size = inner.sizeof;
usz vlen = arg.type.len;
@@ -325,28 +318,28 @@ fn usz! Formatter.out_str(&self, any arg) @private
fn void! out_null_fn(void* data @unused, char c @unused) @private
fn void? out_null_fn(void* data @unused, char c @unused) @private
{
}
macro usz! @report_fault(Formatter* f, $fault)
macro usz? @report_fault(Formatter* f, $fault)
{
(void)f.out_substr($fault);
return PrintFault.INVALID_FORMAT?;
return INVALID_FORMAT?;
}
macro usz! @wrap_bad(Formatter* f, #action)
macro usz? @wrap_bad(Formatter* f, #action)
{
usz! len = #action;
usz? len = #action;
if (catch err = len)
{
switch (err)
{
case PrintFault.BUFFER_EXCEEDED:
case PrintFault.INTERNAL_BUFFER_EXCEEDED:
case BUFFER_EXCEEDED:
case INTERNAL_BUFFER_EXCEEDED:
return f.first_err(err)?;
default:
err = f.first_err(PrintFault.INVALID_ARGUMENT);
err = f.first_err(INVALID_ARGUMENT);
f.out_substr("<INVALID>")!;
return err?;
}
@@ -354,7 +347,7 @@ macro usz! @wrap_bad(Formatter* f, #action)
return len;
}
fn usz! Formatter.vprintf(&self, String format, any[] anys)
fn usz? Formatter.vprintf(&self, String format, any[] anys)
{
self.first_fault = {};
if (!self.out_fn)
@@ -400,7 +393,7 @@ fn usz! Formatter.vprintf(&self, String format, any[] anys)
c = format[i];
}
// evaluate width field
int! w = printf_parse_format_field(anys.ptr, anys.len, &variant_index, format.ptr, format.len, &i);
int? w = printf_parse_format_field(anys.ptr, anys.len, &variant_index, format.ptr, format.len, &i);
if (catch w) return @report_fault(self, "%ERR");
c = format[i];
if (w < 0)
@@ -415,7 +408,7 @@ fn usz! Formatter.vprintf(&self, String format, any[] anys)
{
self.flags.precision = true;
if (++i >= format_len) return @report_fault(self, "<BAD FORMAT>");
int! prec = printf_parse_format_field(anys.ptr, anys.len, &variant_index, format.ptr, format.len, &i);
int? prec = printf_parse_format_field(anys.ptr, anys.len, &variant_index, format.ptr, format.len, &i);
if (catch prec) return @report_fault(self, "<BAD FORMAT>");
self.prec = prec < 0 ? 0 : prec;
c = format[i];
@@ -425,7 +418,7 @@ fn usz! Formatter.vprintf(&self, String format, any[] anys)
uint base = 0;
if (variant_index >= anys.len)
{
self.first_err(PrintFault.NOT_ENOUGH_ARGUMENTS);
self.first_err(NOT_ENOUGH_ARGUMENTS);
total_len += self.out_substr("<MISSING>")!;
continue;
}
@@ -532,7 +525,7 @@ fn usz! Formatter.vprintf(&self, String format, any[] anys)
self.flags.hash = true;
base = 16;
default:
self.first_err(PrintFault.INVALID_FORMAT);
self.first_err(INVALID_FORMAT);
total_len += self.out_substr("<BAD FORMAT>")!;
continue;
}
@@ -556,7 +549,7 @@ fn usz! Formatter.vprintf(&self, String format, any[] anys)
}
fn usz! Formatter.print(&self, String str)
fn usz? Formatter.print(&self, String str)
{
if (!self.out_fn)
{

View File

@@ -4,12 +4,9 @@ import std::math;
const char[16] XDIGITS_H = "0123456789ABCDEF";
const char[16] XDIGITS_L = "0123456789abcdef";
fault FormattingFault
{
BAD_FORMAT
}
fault BAD_FORMAT;
fn usz! print_hex_chars(Formatter* f, char[] out, bool uppercase) @inline
fn usz? print_hex_chars(Formatter* f, char[] out, bool uppercase) @inline
{
char past_10 = (uppercase ? 'A' : 'a') - 10;
usz len = 0;
@@ -32,13 +29,13 @@ macro Formatter.first_err(&self, anyfault f)
return f;
}
fn usz! Formatter.adjust(&self, usz len) @local
fn usz? Formatter.adjust(&self, usz len) @local
{
if (!self.flags.left) return 0;
return self.pad(' ', self.width, len);
}
fn uint128! int_from_any(any arg, bool *is_neg) @private
fn uint128? int_from_any(any arg, bool *is_neg) @private
{
switch (arg.type.kindof)
{
@@ -88,11 +85,11 @@ fn uint128! int_from_any(any arg, bool *is_neg) @private
double d = *(double*)arg;
return (uint128)((*is_neg = d < 0) ? -d : d);
default:
return FormattingFault.BAD_FORMAT?;
return BAD_FORMAT?;
}
}
fn FloatType! float_from_any(any arg) @private
fn FloatType? float_from_any(any arg) @private
{
$if env::F128_SUPPORT:
if (arg.type == float128.typeid) return (FloatType)*((float128*)arg.ptr);
@@ -130,7 +127,7 @@ fn FloatType! float_from_any(any arg) @private
case double:
return (FloatType)*(double*)arg;
default:
return FormattingFault.BAD_FORMAT?;
return BAD_FORMAT?;
}
}
@@ -158,7 +155,7 @@ fn uint simple_atoi(char* buf, usz maxlen, usz* len_ptr) @inline @private
return i;
}
fn usz! Formatter.out_substr(&self, String str) @private
fn usz? Formatter.out_substr(&self, String str) @private
{
usz l = conv::utf8_codepoints(str);
uint prec = self.prec;
@@ -177,7 +174,7 @@ fn usz! Formatter.out_substr(&self, String str) @private
return index;
}
fn usz! Formatter.pad(&self, char c, isz width, isz len) @inline
fn usz? Formatter.pad(&self, char c, isz width, isz len) @inline
{
isz delta = width - len;
for (isz i = 0; i < delta; i++) self.out(c)!;
@@ -191,7 +188,7 @@ fn char* fmt_u(uint128 x, char* s)
return s;
}
fn usz! Formatter.out_chars(&self, char[] s)
fn usz? Formatter.out_chars(&self, char[] s)
{
foreach (c : s) self.out(c)!;
return s.len;
@@ -205,12 +202,12 @@ enum FloatFormatting
HEX
}
fn usz! Formatter.etoa(&self, double y) => self.floatformat(EXPONENTIAL, y);
fn usz! Formatter.ftoa(&self, double y) => self.floatformat(FLOAT, y);
fn usz! Formatter.gtoa(&self, double y) => self.floatformat(ADAPTIVE, y);
fn usz! Formatter.atoa(&self, double y) => self.floatformat(HEX, y);
fn usz? Formatter.etoa(&self, double y) => self.floatformat(EXPONENTIAL, y);
fn usz? Formatter.ftoa(&self, double y) => self.floatformat(FLOAT, y);
fn usz? Formatter.gtoa(&self, double y) => self.floatformat(ADAPTIVE, y);
fn usz? Formatter.atoa(&self, double y) => self.floatformat(HEX, y);
fn usz! Formatter.floatformat(&self, FloatFormatting formatting, double y) @private
fn usz? Formatter.floatformat(&self, FloatFormatting formatting, double y) @private
{
// This code is heavily based on musl's printf code
const BUF_SIZE = (math::DOUBLE_MANT_DIG + 28) / 29 + 1
@@ -285,7 +282,7 @@ fn usz! Formatter.floatformat(&self, FloatFormatting formatting, double y) @priv
} while (y);
isz outlen = s - buf;
isz explen = ebuf - estr;
if (p > int.max - 2 - explen - pl) return PrintFault.INTERNAL_BUFFER_EXCEEDED?;
if (p > int.max - 2 - explen - pl) return INTERNAL_BUFFER_EXCEEDED?;
usz len;
usz l = p && outlen - 2 < p
? p + 2 + explen
@@ -453,12 +450,12 @@ fn usz! Formatter.floatformat(&self, FloatFormatting formatting, double y) @priv
}
}
}
if (p > int.max - 1 - (isz)(p || self.flags.hash)) return PrintFault.INTERNAL_BUFFER_EXCEEDED?;
if (p > int.max - 1 - (isz)(p || self.flags.hash)) return INTERNAL_BUFFER_EXCEEDED?;
int l = (int)(1 + p + (isz)(p || self.flags.hash));
char* estr @noinit;
if (formatting == FLOAT)
{
if (e > int.max - l) return PrintFault.INTERNAL_BUFFER_EXCEEDED?;
if (e > int.max - l) return INTERNAL_BUFFER_EXCEEDED?;
if (e > 0) l += e;
}
else
@@ -467,10 +464,10 @@ fn usz! Formatter.floatformat(&self, FloatFormatting formatting, double y) @priv
while (ebuf - estr < 2) (--estr)[0] = '0';
*--estr = (e < 0 ? '-' : '+');
*--estr = self.flags.uppercase ? 'E' : 'e';
if (ebuf - estr > (isz)int.max - l) return PrintFault.INTERNAL_BUFFER_EXCEEDED?;
if (ebuf - estr > (isz)int.max - l) return INTERNAL_BUFFER_EXCEEDED?;
l += (int)(ebuf - estr);
}
if (l > int.max - pl) return PrintFault.INTERNAL_BUFFER_EXCEEDED?;
if (l > int.max - pl) return INTERNAL_BUFFER_EXCEEDED?;
usz len;
if (!self.flags.left && !self.flags.zeropad) len += self.pad(' ', self.width, pl + l)!;
if (is_neg || self.flags.plus) len += self.out(is_neg ? '-' : '+')!;
@@ -528,7 +525,7 @@ fn usz! Formatter.floatformat(&self, FloatFormatting formatting, double y) @priv
return len;
}
fn usz! Formatter.ntoa(&self, uint128 value, bool negative, uint base) @private
fn usz? Formatter.ntoa(&self, uint128 value, bool negative, uint base) @private
{
char[PRINTF_NTOA_BUFFER_SIZE] buf @noinit;
usz len;
@@ -542,7 +539,7 @@ fn usz! Formatter.ntoa(&self, uint128 value, bool negative, uint base) @private
char past_10 = (self.flags.uppercase ? 'A' : 'a') - 10;
do
{
if (len >= PRINTF_NTOA_BUFFER_SIZE) return PrintFault.INTERNAL_BUFFER_EXCEEDED?;
if (len >= PRINTF_NTOA_BUFFER_SIZE) return INTERNAL_BUFFER_EXCEEDED?;
char digit = (char)(value % base);
buf[len++] = digit + (digit < 10 ? '0' : past_10);
value /= base;
@@ -552,7 +549,7 @@ fn usz! Formatter.ntoa(&self, uint128 value, bool negative, uint base) @private
return self.ntoa_format((String)buf[:PRINTF_NTOA_BUFFER_SIZE], len, negative, base);
}
fn usz! Formatter.ntoa_format(&self, String buf, usz len, bool negative, uint base) @private
fn usz? Formatter.ntoa_format(&self, String buf, usz len, bool negative, uint base) @private
{
// pad leading zeros
if (!self.flags.left)
@@ -560,12 +557,12 @@ fn usz! Formatter.ntoa_format(&self, String buf, usz len, bool negative, uint ba
if (self.width && self.flags.zeropad && (negative || self.flags.plus || self.flags.space)) self.width--;
while (len < self.prec)
{
if (len >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED?;
if (len >= buf.len) return INTERNAL_BUFFER_EXCEEDED?;
buf[len++] = '0';
}
while (self.flags.zeropad && len < self.width)
{
if (len >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED?;
if (len >= buf.len) return INTERNAL_BUFFER_EXCEEDED?;
buf[len++] = '0';
}
}
@@ -580,7 +577,7 @@ fn usz! Formatter.ntoa_format(&self, String buf, usz len, bool negative, uint ba
}
if (base != 10)
{
if (len + 1 >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED?;
if (len + 1 >= buf.len) return INTERNAL_BUFFER_EXCEEDED?;
switch (base)
{
case 16:
@@ -599,13 +596,13 @@ fn usz! Formatter.ntoa_format(&self, String buf, usz len, bool negative, uint ba
switch (true)
{
case negative:
if (len >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED?;
if (len >= buf.len) return INTERNAL_BUFFER_EXCEEDED?;
buf[len++] = '-';
case self.flags.plus:
if (len >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED?;
if (len >= buf.len) return INTERNAL_BUFFER_EXCEEDED?;
buf[len++] = '+';
case self.flags.space:
if (len >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED?;
if (len >= buf.len) return INTERNAL_BUFFER_EXCEEDED?;
buf[len++] = ' ';
}
if (len) self.out_reverse(buf[:len])!;
@@ -613,13 +610,13 @@ fn usz! Formatter.ntoa_format(&self, String buf, usz len, bool negative, uint ba
}
fn usz! Formatter.ntoa_any(&self, any arg, uint base) @private
fn usz? Formatter.ntoa_any(&self, any arg, uint base) @private
{
bool is_neg;
return self.ntoa(int_from_any(arg, &is_neg)!!, is_neg, base) @inline;
}
fn usz! Formatter.out_char(&self, any arg) @private
fn usz? Formatter.out_char(&self, any arg) @private
{
if (!arg.type.kindof.is_int())
{
@@ -653,7 +650,7 @@ fn usz! Formatter.out_char(&self, any arg) @private
}
fn usz! Formatter.out_reverse(&self, char[] buf) @private
fn usz? Formatter.out_reverse(&self, char[] buf) @private
{
usz n;
usz buffer_start_idx = self.idx;
@@ -672,7 +669,7 @@ fn usz! Formatter.out_reverse(&self, char[] buf) @private
}
fn int! printf_parse_format_field(
fn int? printf_parse_format_field(
any* args_ptr, usz args_len, usz* args_index_ptr,
char* format_ptr, usz format_len, usz* index_ptr) @inline @private
{
@@ -680,10 +677,10 @@ fn int! printf_parse_format_field(
if (c.is_digit()) return simple_atoi(format_ptr, format_len, index_ptr);
if (c != '*') return 0;
usz len = ++(*index_ptr);
if (len >= format_len) return FormattingFault.BAD_FORMAT?;
if (*args_index_ptr >= args_len) return FormattingFault.BAD_FORMAT?;
if (len >= format_len) return BAD_FORMAT?;
if (*args_index_ptr >= args_len) return BAD_FORMAT?;
any val = args_ptr[(*args_index_ptr)++];
if (!val.type.kindof.is_int()) return FormattingFault.BAD_FORMAT?;
uint! intval = types::any_to_int(val, int);
return intval ?? FormattingFault.BAD_FORMAT?;
if (!val.type.kindof.is_int()) return BAD_FORMAT?;
uint? intval = types::any_to_int(val, int);
return intval ?? BAD_FORMAT?;
}

View File

@@ -11,8 +11,7 @@ enum Seek
END
}
fault IoError
{
fault
ALREADY_EXISTS,
BUSY,
CANNOT_READ_DIR,
@@ -41,8 +40,7 @@ fault IoError
UNEXPECTED_EOF,
UNKNOWN_ERROR,
UNSUPPORTED_OPERATION,
WOULD_BLOCK,
}
WOULD_BLOCK;
<*
@@ -55,7 +53,7 @@ fault IoError
@param [inout] allocator : `the allocator to use.`
@return `The string containing the data read.`
*>
macro String! readline(Allocator allocator, stream = io::stdin())
macro String? readline(Allocator allocator, stream = io::stdin())
{
bool $is_stream = @typeis(stream, InStream);
$if $is_stream:
@@ -73,13 +71,13 @@ macro String! readline(Allocator allocator, stream = io::stdin())
while (1)
{
$if $is_stream:
char! c = func((void*)stream);
char? c = func((void*)stream);
$else
char! c = stream.read_byte();
char? c = stream.read_byte();
$endif
if (catch err = c)
{
if (err == IoError.EOF) break;
if (err == io::EOF) break;
return err?;
}
if (c == '\r') continue;
@@ -98,7 +96,7 @@ macro String! readline(Allocator allocator, stream = io::stdin())
@require @is_instream(stream) : `The stream must implement InStream.`
@return `The temporary string containing the data read.`
*>
macro String! treadline(stream = io::stdin())
macro String? treadline(stream = io::stdin())
{
return readline(tmem(), stream) @inline;
}
@@ -111,7 +109,7 @@ macro String! treadline(stream = io::stdin())
@require @is_outstream(out) : `The output must implement OutStream.`
@return `the number of bytes printed.`
*>
macro usz! fprint(out, x)
macro usz? fprint(out, x)
{
var $Type = $typeof(x);
$switch $Type:
@@ -141,7 +139,7 @@ macro usz! fprint(out, x)
@param [in] format : `The printf-style format string`
@return `the number of characters printed`
*>
fn usz! fprintf(OutStream out, String format, args...)
fn usz? fprintf(OutStream out, String format, args...)
{
Formatter formatter;
formatter.init(&out_putstream_fn, &out);
@@ -156,7 +154,7 @@ fn usz! fprintf(OutStream out, String format, args...)
@param [in] format : `The printf-style format string`
@return `the number of characters printed`
*>
fn usz! fprintfn(OutStream out, String format, args...) @maydiscard
fn usz? fprintfn(OutStream out, String format, args...) @maydiscard
{
Formatter formatter;
formatter.init(&out_putstream_fn, &out);
@@ -169,7 +167,7 @@ fn usz! fprintfn(OutStream out, String format, args...) @maydiscard
<*
@require @is_outstream(out) : "The output must implement OutStream"
*>
macro usz! fprintn(out, x = "")
macro usz? fprintn(out, x = "")
{
usz len = fprint(out, x)!;
out.write_byte('\n')!;
@@ -219,13 +217,13 @@ macro void eprintn(x)
}
fn void! out_putstream_fn(void* data, char c) @private
fn void? out_putstream_fn(void* data, char c) @private
{
OutStream* stream = data;
return (*stream).write_byte(c);
}
fn void! out_putchar_fn(void* data @unused, char c) @private
fn void? out_putchar_fn(void* data @unused, char c) @private
{
$if env::TESTING:
// HACK: this is used for the purpose of unit test output hijacking
@@ -251,7 +249,7 @@ fn void! out_putchar_fn(void* data @unused, char c) @private
@param [in] format : `The printf-style format string`
@return `the number of characters printed`
*>
fn usz! printf(String format, args...) @maydiscard
fn usz? printf(String format, args...) @maydiscard
{
Formatter formatter;
formatter.init(&out_putchar_fn);
@@ -265,11 +263,11 @@ fn usz! printf(String format, args...) @maydiscard
@param [in] format : `The printf-style format string`
@return `the number of characters printed`
*>
fn usz! printfn(String format, args...) @maydiscard
fn usz? printfn(String format, args...) @maydiscard
{
Formatter formatter;
formatter.init(&out_putchar_fn);
usz! len = formatter.vprintf(format, args);
usz? len = formatter.vprintf(format, args);
out_putchar_fn(null, '\n')!;
io::stdout().flush()!;
return len + 1;
@@ -282,7 +280,7 @@ fn usz! printfn(String format, args...) @maydiscard
@param [in] format : `The printf-style format string`
@return `the number of characters printed`
*>
fn usz! eprintf(String format, args...) @maydiscard
fn usz? eprintf(String format, args...) @maydiscard
{
Formatter formatter;
OutStream stream = stderr();
@@ -298,12 +296,12 @@ fn usz! eprintf(String format, args...) @maydiscard
@param [in] format : `The printf-style format string`
@return `the number of characters printed`
*>
fn usz! eprintfn(String format, args...) @maydiscard
fn usz? eprintfn(String format, args...) @maydiscard
{
Formatter formatter;
OutStream stream = stderr();
formatter.init(&out_putstream_fn, &stream);
usz! len = formatter.vprintf(format, args);
usz? len = formatter.vprintf(format, args);
stderr().write_byte('\n')!;
stderr().flush()!;
return len + 1;
@@ -317,7 +315,7 @@ fn usz! eprintfn(String format, args...) @maydiscard
@param [in] format : `The printf-style format string`
@return `a slice formed from the "buffer" with the resulting length.`
*>
fn char[]! bprintf(char[] buffer, String format, args...) @maydiscard
fn char[]? bprintf(char[] buffer, String format, args...) @maydiscard
{
Formatter formatter;
BufferData data = { .buffer = buffer };
@@ -327,10 +325,10 @@ fn char[]! bprintf(char[] buffer, String format, args...) @maydiscard
}
// Used to print to a buffer.
fn void! out_buffer_fn(void *data, char c) @private
fn void? out_buffer_fn(void *data, char c) @private
{
BufferData *buffer_data = data;
if (buffer_data.written >= buffer_data.buffer.len) return PrintFault.BUFFER_EXCEEDED?;
if (buffer_data.written >= buffer_data.buffer.len) return BUFFER_EXCEEDED?;
buffer_data.buffer[buffer_data.written++] = c;
}

View File

@@ -1,7 +1,7 @@
module std::io::os;
import std::io::path, libc, std::os;
macro void! native_chdir(Path path)
macro void? native_chdir(Path path)
{
$switch:
$case env::POSIX:
@@ -9,12 +9,12 @@ macro void! native_chdir(Path path)
{
switch (libc::errno())
{
case errno::EACCES: return IoError.NO_PERMISSION?;
case errno::ENAMETOOLONG: return IoError.NAME_TOO_LONG?;
case errno::ENOTDIR: return IoError.FILE_NOT_DIR?;
case errno::ENOENT: return IoError.FILE_NOT_FOUND?;
case errno::ELOOP: return IoError.SYMLINK_FAILED?;
default: return IoError.GENERAL_ERROR?;
case errno::EACCES: return io::NO_PERMISSION?;
case errno::ENAMETOOLONG: return io::NAME_TOO_LONG?;
case errno::ENOTDIR: return io::FILE_NOT_DIR?;
case errno::ENOENT: return io::FILE_NOT_FOUND?;
case errno::ELOOP: return io::SYMLINK_FAILED?;
default: return io::GENERAL_ERROR?;
}
}
$case env::WIN32:
@@ -23,8 +23,8 @@ macro void! native_chdir(Path path)
// TODO improve with better error handling.
if (win32::setCurrentDirectoryW(path.str_view().to_temp_utf16()!!)) return;
};
return IoError.GENERAL_ERROR?;
return io::GENERAL_ERROR?;
$default:
return IoError.UNSUPPORTED_OPERATION?;
return io::UNSUPPORTED_OPERATION?;
$endswitch
}

View File

@@ -5,7 +5,7 @@ import libc;
@require mode.len > 0
@require filename.len > 0
*>
fn void*! native_fopen(String filename, String mode) @inline => @pool()
fn void*? native_fopen(String filename, String mode) @inline => @pool()
{
$if env::WIN32:
void* file = libc::_wfopen(filename.to_temp_wstring(), mode.to_temp_wstring())!;
@@ -15,7 +15,7 @@ fn void*! native_fopen(String filename, String mode) @inline => @pool()
return file ?: file_open_errno()?;
}
fn void! native_remove(String filename) => @pool()
fn void? native_remove(String filename) => @pool()
{
$if env::WIN32:
CInt result = libc::_wremove(filename.to_temp_wstring())!;
@@ -27,10 +27,10 @@ fn void! native_remove(String filename) => @pool()
switch (libc::errno())
{
case errno::ENOENT:
return IoError.FILE_NOT_FOUND?;
return io::FILE_NOT_FOUND?;
case errno::EACCES:
default:
return IoError.FILE_CANNOT_DELETE?;
return io::FILE_CANNOT_DELETE?;
}
}
}
@@ -39,7 +39,7 @@ fn void! native_remove(String filename) => @pool()
@require mode.len > 0
@require filename.len > 0
*>
fn void*! native_freopen(void* file, String filename, String mode) @inline => @pool()
fn void*? native_freopen(void* file, String filename, String mode) @inline => @pool()
{
$if env::WIN32:
file = libc::_wfreopen(filename.to_temp_wstring(), mode.to_temp_wstring(), file)!;
@@ -49,29 +49,29 @@ fn void*! native_freopen(void* file, String filename, String mode) @inline => @p
return file ?: file_open_errno()?;
}
fn void! native_fseek(void* file, isz offset, Seek seek_mode) @inline
fn void? native_fseek(void* file, isz offset, Seek seek_mode) @inline
{
if (libc::fseek(file, (SeekIndex)offset, seek_mode.ordinal)) return file_seek_errno()?;
}
fn usz! native_ftell(CFile file) @inline
fn usz? native_ftell(CFile file) @inline
{
long index = libc::ftell(file);
return index >= 0 ? (usz)index : file_seek_errno()?;
}
fn usz! native_fwrite(CFile file, char[] buffer) @inline
fn usz? native_fwrite(CFile file, char[] buffer) @inline
{
return libc::fwrite(buffer.ptr, 1, buffer.len, file);
}
fn void! native_fputc(CInt c, CFile stream) @inline
fn void? native_fputc(CInt c, CFile stream) @inline
{
if (libc::fputc(c, stream) == libc::EOF) return IoError.EOF?;
if (libc::fputc(c, stream) == libc::EOF) return io::EOF?;
}
fn usz! native_fread(CFile file, char[] buffer) @inline
fn usz? native_fread(CFile file, char[] buffer) @inline
{
return libc::fread(buffer.ptr, 1, buffer.len, file);
}
@@ -80,27 +80,27 @@ macro anyfault file_open_errno() @local
{
switch (libc::errno())
{
case errno::EACCES: return IoError.NO_PERMISSION;
case errno::EDQUOT: return IoError.OUT_OF_SPACE;
case errno::EBADF: return IoError.FILE_NOT_VALID;
case errno::EEXIST: return IoError.ALREADY_EXISTS;
case errno::EINTR: return IoError.INTERRUPTED;
case errno::EFAULT: return IoError.GENERAL_ERROR;
case errno::EISDIR: return IoError.FILE_IS_DIR;
case errno::ELOOP: return IoError.SYMLINK_FAILED;
case errno::EMFILE: return IoError.TOO_MANY_DESCRIPTORS;
case errno::ENAMETOOLONG: return IoError.NAME_TOO_LONG;
case errno::ENFILE: return IoError.OUT_OF_SPACE;
case errno::ENOTDIR: return IoError.FILE_NOT_DIR;
case errno::ENOENT: return IoError.FILE_NOT_FOUND;
case errno::ENOSPC: return IoError.OUT_OF_SPACE;
case errno::ENXIO: return IoError.FILE_NOT_FOUND;
case errno::EOVERFLOW: return IoError.OVERFLOW;
case errno::EROFS: return IoError.READ_ONLY;
case errno::EOPNOTSUPP: return IoError.UNSUPPORTED_OPERATION;
case errno::EIO: return IoError.INCOMPLETE_WRITE;
case errno::EWOULDBLOCK: return IoError.WOULD_BLOCK;
default: return IoError.UNKNOWN_ERROR;
case errno::EACCES: return io::NO_PERMISSION;
case errno::EDQUOT: return io::OUT_OF_SPACE;
case errno::EBADF: return io::FILE_NOT_VALID;
case errno::EEXIST: return io::ALREADY_EXISTS;
case errno::EINTR: return io::INTERRUPTED;
case errno::EFAULT: return io::GENERAL_ERROR;
case errno::EISDIR: return io::FILE_IS_DIR;
case errno::ELOOP: return io::SYMLINK_FAILED;
case errno::EMFILE: return io::TOO_MANY_DESCRIPTORS;
case errno::ENAMETOOLONG: return io::NAME_TOO_LONG;
case errno::ENFILE: return io::OUT_OF_SPACE;
case errno::ENOTDIR: return io::FILE_NOT_DIR;
case errno::ENOENT: return io::FILE_NOT_FOUND;
case errno::ENOSPC: return io::OUT_OF_SPACE;
case errno::ENXIO: return io::FILE_NOT_FOUND;
case errno::EOVERFLOW: return io::OVERFLOW;
case errno::EROFS: return io::READ_ONLY;
case errno::EOPNOTSUPP: return io::UNSUPPORTED_OPERATION;
case errno::EIO: return io::INCOMPLETE_WRITE;
case errno::EWOULDBLOCK: return io::WOULD_BLOCK;
default: return io::UNKNOWN_ERROR;
}
}
@@ -108,18 +108,18 @@ macro anyfault file_seek_errno() @local
{
switch (libc::errno())
{
case errno::ESPIPE: return IoError.FILE_IS_PIPE;
case errno::EPIPE: return IoError.FILE_IS_PIPE;
case errno::EOVERFLOW: return IoError.OVERFLOW;
case errno::ENXIO: return IoError.FILE_NOT_FOUND;
case errno::ENOSPC: return IoError.OUT_OF_SPACE;
case errno::EIO: return IoError.INCOMPLETE_WRITE;
case errno::EINVAL: return IoError.INVALID_POSITION;
case errno::EINTR: return IoError.INTERRUPTED;
case errno::EFBIG: return IoError.OUT_OF_SPACE;
case errno::EBADF: return IoError.FILE_NOT_VALID;
case errno::EAGAIN: return IoError.WOULD_BLOCK;
default: return IoError.UNKNOWN_ERROR;
case errno::ESPIPE: return io::FILE_IS_PIPE;
case errno::EPIPE: return io::FILE_IS_PIPE;
case errno::EOVERFLOW: return io::OVERFLOW;
case errno::ENXIO: return io::FILE_NOT_FOUND;
case errno::ENOSPC: return io::OUT_OF_SPACE;
case errno::EIO: return io::INCOMPLETE_WRITE;
case errno::EINVAL: return io::INVALID_POSITION;
case errno::EINTR: return io::INTERRUPTED;
case errno::EFBIG: return io::OUT_OF_SPACE;
case errno::EBADF: return io::FILE_NOT_VALID;
case errno::EAGAIN: return io::WOULD_BLOCK;
default: return io::UNKNOWN_ERROR;
}
}

View File

@@ -1,15 +1,15 @@
module std::io::os @if(env::NO_LIBC);
import libc;
def FopenFn = fn void*!(String, String);
def FreopenFn = fn void*!(void*, String, String);
def FcloseFn = fn void!(void*);
def FseekFn = fn void!(void*, isz, Seek);
def FtellFn = fn usz!(void*);
def FwriteFn = fn usz!(void*, char[] buffer);
def FreadFn = fn usz!(void*, char[] buffer);
def RemoveFn = fn void!(String);
def FputcFn = fn void!(int, void*);
def FopenFn = fn void*?(String, String);
def FreopenFn = fn void*?(void*, String, String);
def FcloseFn = fn void?(void*);
def FseekFn = fn void?(void*, isz, Seek);
def FtellFn = fn usz?(void*);
def FwriteFn = fn usz?(void*, char[] buffer);
def FreadFn = fn usz?(void*, char[] buffer);
def RemoveFn = fn void?(String);
def FputcFn = fn void?(int, void*);
FopenFn native_fopen_fn @weak @if(!$defined(native_fopen_fn));
FcloseFn native_fclose_fn @weak @if(!$defined(native_fclose_fn));
@@ -25,10 +25,10 @@ FputcFn native_fputc_fn @weak @if(!$defined(native_fputc_fn));
@require mode.len > 0
@require filename.len > 0
*>
fn void*! native_fopen(String filename, String mode) @inline
fn void*? native_fopen(String filename, String mode) @inline
{
if (native_fopen_fn) return native_fopen_fn(filename, mode);
return IoError.UNSUPPORTED_OPERATION?;
return io::UNSUPPORTED_OPERATION?;
}
<*
@@ -36,48 +36,48 @@ fn void*! native_fopen(String filename, String mode) @inline
@require filename.len > 0
*>
fn void! native_remove(String filename) @inline
fn void? native_remove(String filename) @inline
{
if (native_remove_fn) return native_remove_fn(filename);
return IoError.UNSUPPORTED_OPERATION?;
return io::UNSUPPORTED_OPERATION?;
}
<*
@require mode.len > 0
@require filename.len > 0
*>
fn void*! native_freopen(void* file, String filename, String mode) @inline
fn void*? native_freopen(void* file, String filename, String mode) @inline
{
if (native_freopen_fn) return native_freopen_fn(file, filename, mode);
return IoError.UNSUPPORTED_OPERATION?;
return io::UNSUPPORTED_OPERATION?;
}
fn void! native_fseek(void* file, isz offset, Seek seek_mode) @inline
fn void? native_fseek(void* file, isz offset, Seek seek_mode) @inline
{
if (native_fseek_fn) return native_fseek_fn(file, offset, seek_mode);
return IoError.UNSUPPORTED_OPERATION?;
return io::UNSUPPORTED_OPERATION?;
}
fn usz! native_ftell(CFile file) @inline
fn usz? native_ftell(CFile file) @inline
{
if (native_ftell_fn) return native_ftell_fn(file);
return IoError.UNSUPPORTED_OPERATION?;
return io::UNSUPPORTED_OPERATION?;
}
fn usz! native_fwrite(CFile file, char[] buffer) @inline
fn usz? native_fwrite(CFile file, char[] buffer) @inline
{
if (native_fwrite_fn) return native_fwrite_fn(file, buffer);
return IoError.UNSUPPORTED_OPERATION?;
return io::UNSUPPORTED_OPERATION?;
}
fn usz! native_fread(CFile file, char[] buffer) @inline
fn usz? native_fread(CFile file, char[] buffer) @inline
{
if (native_fread_fn) return native_fread_fn(file, buffer);
return IoError.UNSUPPORTED_OPERATION?;
return io::UNSUPPORTED_OPERATION?;
}
fn void! native_fputc(CInt c, CFile stream) @inline
fn void? native_fputc(CInt c, CFile stream) @inline
{
if (native_fputc_fn) return native_fputc_fn(c, stream);
return IoError.UNSUPPORTED_OPERATION?;
return io::UNSUPPORTED_OPERATION?;
}

View File

@@ -1,7 +1,7 @@
module std::io::os;
import libc, std::os, std::io;
fn void! native_stat(Stat* stat, String path) @if(env::DARWIN || env::LINUX || env::BSD_FAMILY) => @pool()
fn void? native_stat(Stat* stat, String path) @if(env::DARWIN || env::LINUX || env::BSD_FAMILY) => @pool()
{
$if env::DARWIN || env::LINUX || env::BSD_FAMILY:
int res = libc::stat(path.zstr_tcopy(), stat);
@@ -14,30 +14,30 @@ fn void! native_stat(Stat* stat, String path) @if(env::DARWIN || env::LINUX || e
switch (libc::errno())
{
case errno::EBADF:
return IoError.FILE_NOT_VALID?;
return io::FILE_NOT_VALID?;
case errno::EFAULT:
unreachable("Invalid stat");
case errno::EIO:
return IoError.GENERAL_ERROR?;
return io::GENERAL_ERROR?;
case errno::EACCES:
return IoError.NO_PERMISSION?;
return io::NO_PERMISSION?;
case errno::ELOOP:
return IoError.NO_PERMISSION?;
return io::NO_PERMISSION?;
case errno::ENAMETOOLONG:
return IoError.NAME_TOO_LONG?;
return io::NAME_TOO_LONG?;
case errno::ENOENT:
return IoError.FILE_NOT_FOUND?;
return io::FILE_NOT_FOUND?;
case errno::ENOTDIR:
return IoError.FILE_NOT_DIR?;
return io::FILE_NOT_DIR?;
case errno::EOVERFLOW:
return IoError.GENERAL_ERROR?;
return io::GENERAL_ERROR?;
default:
return IoError.UNKNOWN_ERROR?;
return io::UNKNOWN_ERROR?;
}
}
}
fn usz! native_file_size(String path) @if(env::WIN32) => @pool()
fn usz? native_file_size(String path) @if(env::WIN32) => @pool()
{
Win32_FILE_ATTRIBUTE_DATA data;
win32::getFileAttributesExW(path.to_temp_wstring()!, Win32_GET_FILEEX_INFO_LEVELS.STANDARD, &data);
@@ -47,14 +47,14 @@ fn usz! native_file_size(String path) @if(env::WIN32) => @pool()
return (usz)size.quadPart;
}
fn usz! native_file_size(String path) @if(!env::WIN32 && !env::DARWIN)
fn usz? native_file_size(String path) @if(!env::WIN32 && !env::DARWIN)
{
File f = file::open(path, "r")!;
defer (void)f.close();
return f.seek(0, Seek.END)!;
}
fn usz! native_file_size(String path) @if(env::DARWIN)
fn usz? native_file_size(String path) @if(env::DARWIN)
{
Stat stat;
native_stat(&stat, path)!;
@@ -97,7 +97,7 @@ fn bool native_is_file(String path)
Stat stat;
return @ok(native_stat(&stat, path)) && libc_S_ISTYPE(stat.st_mode, libc::S_IFREG);
$default:
File! f = file::open(path, "r");
File? f = file::open(path, "r");
defer (void)f.close();
return @ok(f);
$endswitch

View File

@@ -1,7 +1,7 @@
module std::io::os;
import libc, std::os;
macro String! getcwd(Allocator allocator = allocator::heap())
macro String? getcwd(Allocator allocator = allocator::heap())
{
$switch:
$case env::WIN32:
@@ -12,7 +12,7 @@ macro String! getcwd(Allocator allocator = allocator::heap())
defer if (free) libc::free(res);
if (!res)
{
if (libc::errno() != errno::ERANGE) return IoError.GENERAL_ERROR?;
if (libc::errno() != errno::ERANGE) return io::GENERAL_ERROR?;
res = win32::_wgetcwd(null, 0);
free = true;
}
@@ -27,7 +27,7 @@ macro String! getcwd(Allocator allocator = allocator::heap())
if (!res)
{
// Improve error
if (libc::errno() != errno::ERANGE) return IoError.GENERAL_ERROR?;
if (libc::errno() != errno::ERANGE) return io::GENERAL_ERROR?;
res = posix::getcwd(null, 0);
free = true;
}
@@ -35,7 +35,7 @@ macro String! getcwd(Allocator allocator = allocator::heap())
return res.copy(allocator);
$default:
return IoError.UNSUPPORTED_OPERATION?;
return io::UNSUPPORTED_OPERATION?;
$endswitch
}

View File

@@ -1,13 +1,13 @@
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)
fn PathList? native_ls(Path dir, bool no_dirs, bool no_symlinks, String mask, Allocator allocator)
{
PathList list;
list.init(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)?;
if (!directory) return (path::is_dir(dir) ? io::CANNOT_READ_DIR : io::FILE_NOT_DIR)?;
Posix_dirent* entry;
while ((entry = posix::readdir(directory)))
{
@@ -24,7 +24,7 @@ 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)
fn PathList? native_ls(Path dir, bool no_dirs, bool no_symlinks, String mask, Allocator allocator)
{
PathList list;
list.init(allocator);
@@ -34,7 +34,7 @@ fn PathList! native_ls(Path dir, bool no_dirs, bool no_symlinks, String mask, Al
WString result = dir.str_view().tconcat(`\*`).to_temp_wstring()!!;
Win32_WIN32_FIND_DATAW find_data;
Win32_HANDLE find = win32::findFirstFileW(result, &find_data);
if (find == win32::INVALID_HANDLE_VALUE) return IoError.CANNOT_READ_DIR?;
if (find == win32::INVALID_HANDLE_VALUE) return io::CANNOT_READ_DIR?;
defer win32::findClose(find);
do
{

View File

@@ -5,7 +5,7 @@ import std::os::win32;
import std::os::posix;
macro bool! native_mkdir(Path path, MkdirPermissions permissions)
macro bool? native_mkdir(Path path, MkdirPermissions permissions)
{
$switch:
$case env::POSIX:
@@ -15,15 +15,15 @@ macro bool! native_mkdir(Path path, MkdirPermissions permissions)
case errno::EACCES:
case errno::EPERM:
case errno::EROFS:
case errno::EFAULT: return IoError.NO_PERMISSION?;
case errno::ENAMETOOLONG: return IoError.NAME_TOO_LONG?;
case errno::EFAULT: return io::NO_PERMISSION?;
case errno::ENAMETOOLONG: return io::NAME_TOO_LONG?;
case errno::EDQUOT:
case errno::ENOSPC: return IoError.OUT_OF_SPACE?;
case errno::ENOSPC: return io::OUT_OF_SPACE?;
case errno::EISDIR:
case errno::EEXIST: return false;
case errno::ELOOP: return IoError.SYMLINK_FAILED?;
case errno::ENOTDIR: return IoError.FILE_NOT_FOUND?;
default: return IoError.GENERAL_ERROR?;
case errno::ELOOP: return io::SYMLINK_FAILED?;
case errno::ENOTDIR: return io::FILE_NOT_FOUND?;
default: return io::GENERAL_ERROR?;
}
$case env::WIN32:
@pool()
@@ -33,18 +33,18 @@ macro bool! native_mkdir(Path path, MkdirPermissions permissions)
switch (win32::getLastError())
{
case win32::ERROR_ACCESS_DENIED:
return IoError.NO_PERMISSION?;
return io::NO_PERMISSION?;
case win32::ERROR_DISK_FULL:
return IoError.OUT_OF_SPACE?;
return io::OUT_OF_SPACE?;
case win32::ERROR_ALREADY_EXISTS:
return false;
case win32::ERROR_PATH_NOT_FOUND:
return IoError.FILE_NOT_FOUND?;
return io::FILE_NOT_FOUND?;
default:
return IoError.GENERAL_ERROR?;
return io::GENERAL_ERROR?;
}
};
$default:
return IoError.UNSUPPORTED_OPERATION?;
return io::UNSUPPORTED_OPERATION?;
$endswitch
}

View File

@@ -4,24 +4,24 @@ import std::io::path;
import std::os::win32;
import std::os::posix;
macro bool! native_rmdir(Path path)
macro bool? native_rmdir(Path path)
{
$switch:
$case env::POSIX:
if (!posix::rmdir(path.as_zstr())) return true;
switch (libc::errno())
{
case errno::EBUSY: return IoError.BUSY?;
case errno::EBUSY: return io::BUSY?;
case errno::EACCES:
case errno::EPERM:
case errno::EROFS:
case errno::EFAULT: return IoError.NO_PERMISSION?;
case errno::ENAMETOOLONG: return IoError.NAME_TOO_LONG?;
case errno::EFAULT: return io::NO_PERMISSION?;
case errno::ENAMETOOLONG: return io::NAME_TOO_LONG?;
case errno::ENOTDIR:
case errno::ENOENT: return false;
case errno::ENOTEMPTY: return IoError.DIR_NOT_EMPTY?;
case errno::ELOOP: return IoError.SYMLINK_FAILED?;
default: return IoError.GENERAL_ERROR?;
case errno::ENOTEMPTY: return io::DIR_NOT_EMPTY?;
case errno::ELOOP: return io::SYMLINK_FAILED?;
default: return io::GENERAL_ERROR?;
}
$case env::WIN32:
@pool()
@@ -30,19 +30,19 @@ macro bool! native_rmdir(Path path)
switch (win32::getLastError())
{
case win32::ERROR_ACCESS_DENIED:
return IoError.NO_PERMISSION?;
return io::NO_PERMISSION?;
case win32::ERROR_CURRENT_DIRECTORY:
return IoError.BUSY?;
return io::BUSY?;
case win32::ERROR_DIR_NOT_EMPTY:
return IoError.DIR_NOT_EMPTY?;
return io::DIR_NOT_EMPTY?;
case win32::ERROR_DIRECTORY:
case win32::ERROR_PATH_NOT_FOUND:
return false;
default:
return IoError.GENERAL_ERROR?;
return io::GENERAL_ERROR?;
}
};
$default:
return IoError.UNSUPPORTED_OPERATION?;
return io::UNSUPPORTED_OPERATION?;
$endswitch
}

View File

@@ -4,11 +4,11 @@ import std::io, std::os, libc;
<*
@require dir.str_view().len > 0
*>
fn void! native_rmtree(Path dir)
fn void? native_rmtree(Path dir)
{
DIRPtr directory = posix::opendir(dir.as_zstr());
defer if (directory) posix::closedir(directory);
if (!directory) return path::is_dir(dir) ? IoError.CANNOT_READ_DIR? : IoError.FILE_NOT_DIR?;
if (!directory) return path::is_dir(dir) ? io::CANNOT_READ_DIR? : io::FILE_NOT_DIR?;
Posix_dirent* entry;
while ((entry = posix::readdir(directory)))
{
@@ -25,7 +25,7 @@ fn void! native_rmtree(Path dir)
if (libc::remove(new_path.as_zstr()))
{
// TODO improve
return IoError.GENERAL_ERROR?;
return io::GENERAL_ERROR?;
}
};
}
@@ -35,13 +35,13 @@ 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)
fn void? native_rmtree(Path path)
{
Win32_WIN32_FIND_DATAW find_data;
String s = path.str_view().tconcat("\\*");
Win32_HANDLE find = win32::findFirstFileW(s.to_temp_utf16(), &find_data)!;
if (find == win32::INVALID_HANDLE_VALUE) return IoError.CANNOT_READ_DIR?;
if (find == win32::INVALID_HANDLE_VALUE) return io::CANNOT_READ_DIR?;
defer win32::findClose(find);
do
{

View File

@@ -1,7 +1,7 @@
module std::io::os @if(env::LIBC);
import std::io::path, std::os;
fn Path! native_temp_directory(Allocator allocator) @if(!env::WIN32)
fn Path? native_temp_directory(Allocator allocator) @if(!env::WIN32)
{
foreach (String env : { "TMPDIR", "TMP", "TEMP", "TEMPDIR" })
{
@@ -11,19 +11,19 @@ fn Path! native_temp_directory(Allocator allocator) @if(!env::WIN32)
return path::new(allocator, "/tmp");
}
fn Path! native_temp_directory(Allocator allocator) @if(env::WIN32) => @pool(allocator)
fn Path? native_temp_directory(Allocator allocator) @if(env::WIN32) => @pool(allocator)
{
Win32_DWORD len = win32::getTempPathW(0, null);
if (!len) return IoError.GENERAL_ERROR?;
if (!len) return io::GENERAL_ERROR?;
Char16[] buff = mem::talloc_array(Char16, len + (usz)1);
if (!win32::getTempPathW(len, buff)) return IoError.GENERAL_ERROR?;
if (!win32::getTempPathW(len, buff)) return io::GENERAL_ERROR?;
return path::new(allocator, string::tfrom_utf16(buff[:len]));
}
module std::io::os @if(env::NO_LIBC);
import std::io::path;
macro Path! native_temp_directory(Allocator allocator = allocator::heap())
macro Path? native_temp_directory(Allocator allocator = allocator::heap())
{
return IoError.UNSUPPORTED_OPERATION?;
return io::UNSUPPORTED_OPERATION?;
}

View File

@@ -9,11 +9,7 @@ const char PREFERRED_SEPARATOR = env::WIN32 ? PREFERRED_SEPARATOR_WIN32 : PREFER
def PathList = List { Path };
fault PathResult
{
INVALID_PATH,
NO_PARENT,
}
fault INVALID_PATH, NO_PARENT;
def Path = PathImp;
@@ -30,7 +26,7 @@ enum PathEnv
POSIX
}
fn Path! cwd(Allocator allocator)
fn Path? cwd(Allocator allocator)
{
@pool(allocator)
{
@@ -40,14 +36,14 @@ fn Path! cwd(Allocator allocator)
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 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! tcwd() => cwd(tmem()) @inline;
fn Path? tcwd() => cwd(tmem()) @inline;
<*
@require @is_pathlike(path) : "Expected a Path or String to chdir"
*>
macro void! chdir(path)
macro void? chdir(path)
{
$if @typeis(path, String):
@pool()
@@ -59,9 +55,9 @@ macro void! chdir(path)
$endif
}
fn Path! temp_directory(Allocator allocator) => os::native_temp_directory(allocator);
fn Path? temp_directory(Allocator allocator) => os::native_temp_directory(allocator);
fn void! delete(Path path) => os::native_remove(path.str_view()) @inline;
fn void? delete(Path path) => os::native_remove(path.str_view()) @inline;
macro bool @is_pathlike(#path) => @typeis(#path, String) || @typeis(#path, Path);
@@ -73,12 +69,12 @@ macro bool is_separator(char c, PathEnv path_env = DEFAULT_ENV)
macro bool is_posix_separator(char c) => c == '/';
macro bool is_win32_separator(char c) => c == '/' || c == '\\';
fn PathList! ls(Allocator allocator, Path dir, bool no_dirs = false, bool no_symlinks = false, String mask = "")
fn PathList? ls(Allocator allocator, Path dir, bool no_dirs = false, bool no_symlinks = false, String mask = "")
{
$if $defined(os::native_ls):
return os::native_ls(dir, no_dirs, no_symlinks, mask, allocator);
$else
return IoError.UNSUPPORTED_OPERATION?;
return io::UNSUPPORTED_OPERATION?;
$endif
}
@@ -97,7 +93,7 @@ enum MkdirPermissions
@param recursive : `If directories in between should be created if they're missing, defaults to false`
@param permissions : `The permissions to set on the directory`
*>
macro bool! mkdir(Path path, bool recursive = false, MkdirPermissions permissions = NORMAL)
macro bool? mkdir(Path path, bool recursive = false, MkdirPermissions permissions = NORMAL)
{
$if @typeis(path, String):
@pool() { return _mkdir(temp(path), recursive, permissions); };
@@ -113,9 +109,9 @@ macro bool! mkdir(Path path, bool recursive = false, MkdirPermissions permission
@param path : `The path to delete`
@require @is_pathlike(path) : "Expected a Path or String to chdir"
@return `true if there was a directory to delete, false otherwise`
@return! PathResult.INVALID_PATH : `if the path was invalid`
@return! INVALID_PATH : `if the path was invalid`
*>
macro bool! rmdir(path)
macro bool? rmdir(path)
{
$if @typeis(path, String):
@pool() { return _rmdir(temp(path)); };
@@ -127,22 +123,22 @@ macro bool! rmdir(path)
<*
Like [rmdir] but deletes a directory even if it contains items.
*>
fn void! rmtree(Path path)
fn void? rmtree(Path path)
{
if (!path.path_string.len) return PathResult.INVALID_PATH?;
if (!path.path_string.len) return INVALID_PATH?;
$if $defined(os::native_rmtree):
return os::native_rmtree(path);
$else
return IoError.UNSUPPORTED_OPERATION?;
return io::UNSUPPORTED_OPERATION?;
$endif
}
<*
Creates a new path.
@return! PathResult.INVALID_PATH : `if the path was invalid`
@return! INVALID_PATH : `if the path was invalid`
*>
fn Path! new(Allocator allocator, String path, PathEnv path_env = DEFAULT_ENV)
fn Path? new(Allocator allocator, String path, PathEnv path_env = DEFAULT_ENV)
{
return { normalize(path.copy(allocator), path_env), path_env, allocator };
}
@@ -150,24 +146,24 @@ fn Path! new(Allocator allocator, String path, PathEnv path_env = DEFAULT_ENV)
<*
Creates a new path using the temp allocator.
@return! PathResult.INVALID_PATH : `if the path was invalid`
@return! INVALID_PATH : `if the path was invalid`
*>
fn Path! temp(String path, PathEnv path_env = DEFAULT_ENV)
fn Path? temp(String path, PathEnv path_env = DEFAULT_ENV)
{
return new(tmem(), path, path_env);
}
fn Path! from_win32_wstring(Allocator allocator, WString path) => @pool(allocator)
fn Path? from_win32_wstring(Allocator allocator, WString path) => @pool(allocator)
{
return path::new(allocator, string::tfrom_wstring(path)!);
}
fn Path! for_windows(Allocator allocator, String path)
fn Path? for_windows(Allocator allocator, String path)
{
return new(allocator, path, WIN32);
}
fn Path! for_posix(Allocator allocator, String path)
fn Path? for_posix(Allocator allocator, String path)
{
return new(allocator, path, POSIX);
}
@@ -182,7 +178,7 @@ fn bool Path.equals(self, Path p2)
@param [in] filename
*>
fn Path! Path.append(self, Allocator allocator, String filename)
fn Path? Path.append(self, Allocator allocator, String filename)
{
if (!self.path_string.len) return new(allocator, filename, self.env)!;
assert(!is_separator(self.path_string[^1], self.env));
@@ -197,12 +193,12 @@ fn Path! Path.append(self, Allocator allocator, String filename)
};
}
fn Path! Path.tappend(self, String filename) => self.append(tmem(), filename);
fn Path? Path.tappend(self, String filename) => self.append(tmem(), filename);
fn usz! start_of_base_name(String str, PathEnv path_env) @local
fn usz? start_of_base_name(String str, PathEnv path_env) @local
{
if (!str.len) return 0;
usz! start_slash = str.rindex_of_char('/');
usz? start_slash = str.rindex_of_char('/');
if (path_env != PathEnv.WIN32) return start_slash + 1 ?? 0;
if (try index = str.rindex_of_char('\\'))
{
@@ -213,7 +209,7 @@ fn usz! start_of_base_name(String str, PathEnv path_env) @local
// Find the \ before "foo"
usz last_index = 2 + str[2..].index_of_char('\\')!;
// If they don't match, we're done
if (last_index > index) return PathResult.INVALID_PATH?;
if (last_index > index) return INVALID_PATH?;
if (last_index != index) return index + 1;
// Otherwise just default to the volume length.
}
@@ -221,12 +217,12 @@ fn usz! start_of_base_name(String str, PathEnv path_env) @local
}
fn bool! String.is_absolute_path(self) => @pool()
fn bool? String.is_absolute_path(self) => @pool()
{
return temp(self).is_absolute();
}
fn bool! Path.is_absolute(self)
fn bool? Path.is_absolute(self)
{
String path_str = self.str_view();
if (!path_str.len) return false;
@@ -236,7 +232,7 @@ fn bool! Path.is_absolute(self)
}
fn Path! String.to_absolute_path(self, Allocator allocator) => @pool(allocator)
fn Path? String.to_absolute_path(self, Allocator allocator) => @pool(allocator)
{
return temp(self).absolute(allocator);
}
@@ -244,10 +240,10 @@ fn Path! String.to_absolute_path(self, Allocator allocator) => @pool(allocator)
<*
@require self.env == DEFAULT_ENV : "This method is only available on native paths"
*>
fn Path! Path.absolute(self, Allocator allocator)
fn Path? Path.absolute(self, Allocator allocator)
{
String path_str = self.str_view();
if (!path_str.len) return PathResult.INVALID_PATH?;
if (!path_str.len) return INVALID_PATH?;
if (self.is_absolute()!) return new(allocator, path_str, self.env);
if (path_str == ".")
{
@@ -263,7 +259,7 @@ fn Path! Path.absolute(self, Allocator allocator)
const usz BUFFER_LEN = 4096;
WString buffer = (WString)mem::talloc_array(Char16, BUFFER_LEN);
buffer = win32::_wfullpath(buffer, path_str.to_temp_wstring()!, BUFFER_LEN);
if (!buffer) return PathResult.INVALID_PATH?;
if (!buffer) return INVALID_PATH?;
return { string::from_wstring(allocator, buffer), WIN32, allocator };
};
$else
@@ -272,12 +268,12 @@ fn Path! Path.absolute(self, Allocator allocator)
$endif
}
fn String! String.file_basename(self, Allocator allocator) => @pool(allocator)
fn String? String.file_basename(self, Allocator allocator) => @pool(allocator)
{
return temp(self).basename().copy(allocator);
}
fn String! String.file_tbasename(self) => self.file_basename(tmem());
fn String? String.file_tbasename(self) => self.file_basename(tmem());
fn String Path.basename(self)
{
@@ -287,9 +283,9 @@ fn String Path.basename(self)
return path_str[basename_start..];
}
fn String! String.path_tdirname(self) => self.path_dirname(tmem());
fn String? String.path_tdirname(self) => self.path_dirname(tmem());
fn String! String.path_dirname(self, Allocator allocator) => @pool(allocator)
fn String? String.path_dirname(self, Allocator allocator) => @pool(allocator)
{
return temp(self).dirname().copy(allocator);
}
@@ -328,13 +324,12 @@ fn bool Path.has_extension(self, String extension)
return basename[^extension.len..] == extension;
}
fn String! Path.extension(self)
fn String? Path.extension(self)
{
String basename = self.basename();
usz index = basename.rindex_of(".")!;
// Plain ".foo" does not have an
if (index == 0) return SearchResult.MISSING?;
if (index == basename.len) return "";
// Plain ".foo" does not have an extension
if (index == 0 || index == basename.len) return "";
return basename[index + 1..];
}
@@ -345,17 +340,17 @@ fn String Path.volume_name(self)
return self.path_string[:len];
}
fn Path! String.to_path(self, Allocator allocator)
fn Path? String.to_path(self, Allocator allocator)
{
return new(allocator, self);
}
fn Path! String.to_tpath(self)
fn Path? String.to_tpath(self)
{
return new(tmem(), self);
}
fn usz! volume_name_len(String path, PathEnv path_env) @local
fn usz? volume_name_len(String path, PathEnv path_env) @local
{
usz len = path.len;
if (len < 2 || path_env != PathEnv.WIN32) return 0;
@@ -379,10 +374,10 @@ fn usz! volume_name_len(String path, PathEnv path_env) @local
base_found = i;
continue;
}
if (is_reserved_win32_path_char(c)) return PathResult.INVALID_PATH?;
if (is_reserved_win32_path_char(c)) return INVALID_PATH?;
}
if (base_found > 0 && base_found + 1 < len) return len;
return PathResult.INVALID_PATH?;
return INVALID_PATH?;
case 'A'..'Z':
case 'a'..'z':
return path[1] == ':' ? 2 : 0;
@@ -396,11 +391,11 @@ fn usz! volume_name_len(String path, PathEnv path_env) @local
of the path itself.
@return `The parent of the path as a non-allocated path`
@return! PathResult.NO_PARENT : `if this path does not have a parent`
@return! NO_PARENT : `if this path does not have a parent`
*>
fn Path! Path.parent(self)
fn Path? Path.parent(self)
{
if (self.path_string.len == 1 && is_separator(self.path_string[0], self.env)) return PathResult.NO_PARENT?;
if (self.path_string.len == 1 && is_separator(self.path_string[0], self.env)) return NO_PARENT?;
foreach_r(i, c : self.path_string)
{
if (is_separator(c, self.env))
@@ -408,10 +403,10 @@ fn Path! Path.parent(self)
return { self.path_string[:i], self.env, null };
}
}
return PathResult.NO_PARENT?;
return NO_PARENT?;
}
fn String! normalize(String path_str, PathEnv path_env = DEFAULT_ENV)
fn String? normalize(String path_str, PathEnv path_env = DEFAULT_ENV)
{
if (!path_str.len) return path_str;
usz path_start = volume_name_len(path_str, path_env)!;
@@ -450,7 +445,7 @@ fn String! normalize(String path_str, PathEnv path_env = DEFAULT_ENV)
// The rest are names of the path elements, so check that the
// characters are valid.
if (is_reserved_path_char(c, path_env)) return PathResult.INVALID_PATH?;
if (is_reserved_path_char(c, path_env)) return INVALID_PATH?;
// If we have '.' after a separator
if (c == '.' && previous_was_separator)
@@ -483,7 +478,7 @@ fn String! normalize(String path_str, PathEnv path_env = DEFAULT_ENV)
continue;
case 2:
// This is an error: /a/../..
if (len == path_start && has_root) return PathResult.INVALID_PATH?;
if (len == path_start && has_root) return INVALID_PATH?;
// If this .. at the start, or after ../? If so, we just copy ..
if (len == path_start ||
@@ -557,14 +552,14 @@ fn String Path.root_directory(self)
return path_str;
}
def PathWalker = fn bool! (Path, bool is_dir, void*);
def PathWalker = fn bool? (Path, bool is_dir, void*);
<*
Walk the path recursively. PathWalker is run on every file and
directory found. Return true to abort the walk.
@require self.env == DEFAULT_ENV : "This method is only available on native paths"
*>
fn bool! Path.walk(self, PathWalker w, void* data)
fn bool? Path.walk(self, PathWalker w, void* data)
{
const PATH_MAX = 512;
@stack_mem(PATH_MAX; Allocator allocator)
@@ -583,14 +578,14 @@ fn bool! Path.walk(self, PathWalker w, void* data)
return false;
}
def TraverseCallback = fn bool! (Path, bool is_dir, any data);
def TraverseCallback = fn bool? (Path, bool is_dir, any data);
<*
Walk the path recursively. TraverseCallback is run for every file and
directory found. Return true to abort the walk.
@require path.env == DEFAULT_ENV : "This method is only available on native paths"
*>
fn bool! traverse(Path path, TraverseCallback callback, any data)
fn bool? traverse(Path path, TraverseCallback callback, any data)
{
const PATH_MAX = 512;
@stack_mem(PATH_MAX; Allocator allocator)
@@ -631,7 +626,7 @@ fn void Path.free(self)
allocator::free(self.allocator, self.path_string.ptr);
}
fn usz! Path.to_format(&self, Formatter* formatter) @dynamic
fn usz? Path.to_format(&self, Formatter* formatter) @dynamic
{
return formatter.print(self.str_view());
}
@@ -665,23 +660,23 @@ macro bool is_reserved_path_char(char c, PathEnv path_env = DEFAULT_ENV)
? RESERVED_PATH_CHAR_WIN32[c]
: RESERVED_PATH_CHAR_POSIX[c];
}
fn bool! _mkdir(Path path, bool recursive = false, MkdirPermissions permissions = NORMAL) @private
fn bool? _mkdir(Path path, bool recursive = false, MkdirPermissions permissions = NORMAL) @private
{
if (!path.path_string.len) return PathResult.INVALID_PATH?;
if (!path.path_string.len) return INVALID_PATH?;
if (is_dir(path)) return false;
if (exists(path)) return IoError.FILE_NOT_DIR?;
if (exists(path)) return io::FILE_NOT_DIR?;
if (recursive)
{
if (try parent = path.parent()) mkdir(parent, true, permissions)!;
}
if (!is_dir(path.parent()) ?? false) return IoError.CANNOT_READ_DIR?;
if (!is_dir(path.parent()) ?? false) return io::CANNOT_READ_DIR?;
return os::native_mkdir(path, permissions);
}
fn bool! _rmdir(Path path) @private
fn bool? _rmdir(Path path) @private
{
if (!path.path_string.len) return PathResult.INVALID_PATH?;
if (!path.path_string.len) return INVALID_PATH?;
return os::native_rmdir(path);
}

View File

@@ -3,28 +3,28 @@ import std::math;
interface InStream
{
fn void! close() @optional;
fn usz! seek(isz offset, Seek seek) @optional;
fn void? close() @optional;
fn usz? seek(isz offset, Seek seek) @optional;
fn usz len() @optional;
fn usz! available() @optional;
fn usz! read(char[] buffer);
fn char! read_byte();
fn usz! write_to(OutStream out) @optional;
fn void! pushback_byte() @optional;
fn usz? available() @optional;
fn usz? read(char[] buffer);
fn char? read_byte();
fn usz? write_to(OutStream out) @optional;
fn void? pushback_byte() @optional;
}
interface OutStream
{
fn void! destroy() @optional;
fn void! close() @optional;
fn void! flush() @optional;
fn usz! write(char[] bytes);
fn void! write_byte(char c);
fn usz! read_to(InStream in) @optional;
fn void? destroy() @optional;
fn void? close() @optional;
fn void? flush() @optional;
fn usz? write(char[] bytes);
fn void? write_byte(char c);
fn usz? read_to(InStream in) @optional;
}
fn usz! available(InStream s)
fn usz? available(InStream s)
{
if (&s.available) return s.available();
if (&s.seek)
@@ -51,7 +51,7 @@ macro bool @is_outstream(#expr)
@param [&out] ref
@require @is_instream(stream)
*>
macro usz! read_any(stream, any ref)
macro usz? read_any(stream, any ref)
{
return read_all(stream, ((char*)ref)[:ref.type.sizeof]);
}
@@ -61,7 +61,7 @@ macro usz! read_any(stream, any ref)
@require @is_outstream(stream)
@ensure return == ref.type.sizeof
*>
macro usz! write_any(stream, any ref)
macro usz? write_any(stream, any ref)
{
return write_all(stream, ((char*)ref)[:ref.type.sizeof]);
}
@@ -69,18 +69,18 @@ macro usz! write_any(stream, any ref)
<*
@require @is_instream(stream)
*>
macro usz! read_all(stream, char[] buffer)
macro usz? read_all(stream, char[] buffer)
{
if (buffer.len == 0) return 0;
usz n = stream.read(buffer)!;
if (n != buffer.len) return IoError.UNEXPECTED_EOF?;
if (n != buffer.len) return UNEXPECTED_EOF?;
return n;
}
<*
@require @is_instream(stream)
*>
macro char[]! read_fully(Allocator allocator, stream)
macro char[]? read_fully(Allocator allocator, stream)
{
usz len = available(stream)!;
char* data = allocator::malloc_try(allocator, len)!;
@@ -96,23 +96,23 @@ macro char[]! read_fully(Allocator allocator, stream)
<*
@require @is_outstream(stream)
*>
macro usz! write_all(stream, char[] buffer)
macro usz? write_all(stream, char[] buffer)
{
if (buffer.len == 0) return 0;
usz n = stream.write(buffer)!;
if (n != buffer.len) return IoError.INCOMPLETE_WRITE?;
if (n != buffer.len) return INCOMPLETE_WRITE?;
return n;
}
macro usz! read_using_read_byte(s, char[] buffer)
macro usz? read_using_read_byte(s, char[] buffer)
{
usz len = 0;
foreach (&cptr : buffer)
{
char! c = s.read_byte();
char? c = s.read_byte();
if (catch err = c)
{
if (err == IoError.EOF) return len;
if (err == io::EOF) return len;
return err?;
}
*cptr = c;
@@ -121,35 +121,35 @@ macro usz! read_using_read_byte(s, char[] buffer)
return len;
}
macro void! write_byte_using_write(s, char c)
macro void? write_byte_using_write(s, char c)
{
char[1] buff = { c };
s.write(&buff)!;
}
macro char! read_byte_using_read(s)
macro char? read_byte_using_read(s)
{
char[1] buffer;
usz read = s.read(&buffer)!;
if (read != 1) return IoError.EOF?;
if (read != 1) return io::EOF?;
return buffer[0];
}
def ReadByteFn = fn char!();
def ReadByteFn = fn char?();
macro usz! write_using_write_byte(s, char[] bytes)
macro usz? write_using_write_byte(s, char[] bytes)
{
foreach (c : bytes) s.write_byte(self, c)!;
return bytes.len;
}
macro void! pushback_using_seek(s)
macro void? pushback_using_seek(s)
{
s.seek(-1, CURSOR)!;
}
fn usz! copy_to(InStream in, OutStream dst, char[] buffer = {})
fn usz? copy_to(InStream in, OutStream dst, char[] buffer = {})
{
if (buffer.len) return copy_through_buffer(in, dst, buffer);
if (&in.write_to) return in.write_to(dst);
@@ -165,31 +165,31 @@ fn usz! copy_to(InStream in, OutStream dst, char[] buffer = {})
$endswitch
}
macro usz! copy_through_buffer(InStream in, OutStream dst, char[] buffer) @local
macro usz? copy_through_buffer(InStream in, OutStream dst, char[] buffer) @local
{
usz total_copied;
while (true)
{
usz! len = in.read(buffer);
usz? len = in.read(buffer);
if (catch err = len)
{
if (err == IoError.EOF) return total_copied;
if (err == io::EOF) return total_copied;
return err?;
}
if (!len) return total_copied;
usz written = dst.write(buffer[:len])!;
total_copied += len;
if (written != len) return IoError.INCOMPLETE_WRITE?;
if (written != len) return INCOMPLETE_WRITE?;
}
}
const char[?] MAX_VARS @private = { [2] = 3, [4] = 5, [8] = 10 };
const char[*] MAX_VARS @private = { [2] = 3, [4] = 5, [8] = 10 };
<*
@require @is_instream(stream)
@require @typekind(x_ptr) == POINTER && $typeof(x_ptr).inner.kindof.is_int()
*>
macro usz! read_varint(stream, x_ptr)
macro usz? read_varint(stream, x_ptr)
{
var $Type = $typefrom($typeof(x_ptr).inner);
const MAX = MAX_VARS[$Type.sizeof];
@@ -198,10 +198,10 @@ macro usz! read_varint(stream, x_ptr)
usz n;
for (usz i = 0; i < MAX; i++)
{
char! c = stream.read_byte();
char? c = stream.read_byte();
if (catch err = c)
{
if (err == IoError.EOF) return IoError.UNEXPECTED_EOF?;
if (err == io::EOF) return io::UNEXPECTED_EOF?;
return err?;
}
n++;
@@ -218,13 +218,13 @@ macro usz! read_varint(stream, x_ptr)
x |= (c & 0x7F) << shift;
shift += 7;
}
return MathError.OVERFLOW?;
return math::OVERFLOW?;
}
<*
@require @is_outstream(stream)
@require @typekind(x).is_int()
*>
macro usz! write_varint(stream, x)
macro usz? write_varint(stream, x)
{
var $Type = $typeof(x);
const MAX = MAX_VARS[$Type.sizeof];
@@ -243,7 +243,7 @@ macro usz! write_varint(stream, x)
<*
@require @is_instream(stream)
*>
macro ushort! read_be_ushort(stream)
macro ushort? read_be_ushort(stream)
{
char hi_byte = stream.read_byte()!;
char lo_byte = stream.read_byte()!;
@@ -253,7 +253,7 @@ macro ushort! read_be_ushort(stream)
<*
@require @is_instream(stream)
*>
macro short! read_be_short(stream)
macro short? read_be_short(stream)
{
return read_be_ushort(stream);
}
@@ -261,7 +261,7 @@ macro short! read_be_short(stream)
<*
@require @is_outstream(stream)
*>
macro void! write_be_short(stream, ushort s)
macro void? write_be_short(stream, ushort s)
{
stream.write_byte((char)(s >> 8))!;
stream.write_byte((char)s)!;
@@ -270,7 +270,7 @@ macro void! write_be_short(stream, ushort s)
<*
@require @is_instream(stream)
*>
macro uint! read_be_uint(stream)
macro uint? read_be_uint(stream)
{
uint val = stream.read_byte()! << 24;
val += stream.read_byte()! << 16;
@@ -281,7 +281,7 @@ macro uint! read_be_uint(stream)
<*
@require @is_instream(stream)
*>
macro int! read_be_int(stream)
macro int? read_be_int(stream)
{
return read_be_uint(stream);
}
@@ -289,7 +289,7 @@ macro int! read_be_int(stream)
<*
@require @is_outstream(stream)
*>
macro void! write_be_int(stream, uint s)
macro void? write_be_int(stream, uint s)
{
stream.write_byte((char)(s >> 24))!;
stream.write_byte((char)(s >> 16))!;
@@ -300,7 +300,7 @@ macro void! write_be_int(stream, uint s)
<*
@require @is_instream(stream)
*>
macro ulong! read_be_ulong(stream)
macro ulong? read_be_ulong(stream)
{
ulong val = (ulong)stream.read_byte()! << 56;
val += (ulong)stream.read_byte()! << 48;
@@ -315,7 +315,7 @@ macro ulong! read_be_ulong(stream)
<*
@require @is_instream(stream)
*>
macro long! read_be_long(stream)
macro long? read_be_long(stream)
{
return read_be_ulong(stream);
}
@@ -323,7 +323,7 @@ macro long! read_be_long(stream)
<*
@require @is_outstream(stream)
*>
macro void! write_be_long(stream, ulong s)
macro void? write_be_long(stream, ulong s)
{
stream.write_byte((char)(s >> 56))!;
stream.write_byte((char)(s >> 48))!;
@@ -338,7 +338,7 @@ macro void! write_be_long(stream, ulong s)
<*
@require @is_instream(stream)
*>
macro uint128! read_be_uint128(stream)
macro uint128? read_be_uint128(stream)
{
uint128 val = (uint128)stream.read_byte()! << 120;
val += (uint128)stream.read_byte()! << 112;
@@ -361,7 +361,7 @@ macro uint128! read_be_uint128(stream)
<*
@require @is_instream(stream)
*>
macro int128! read_be_int128(stream)
macro int128? read_be_int128(stream)
{
return read_be_uint128(stream);
}
@@ -369,7 +369,7 @@ macro int128! read_be_int128(stream)
<*
@require @is_outstream(stream)
*>
macro void! write_be_int128(stream, uint128 s)
macro void? write_be_int128(stream, uint128 s)
{
stream.write_byte((char)(s >> 120))!;
stream.write_byte((char)(s >> 112))!;
@@ -393,7 +393,7 @@ macro void! write_be_int128(stream, uint128 s)
@require @is_outstream(stream)
@require data.len < 256 : "Data exceeded 255"
*>
macro usz! write_tiny_bytearray(stream, char[] data)
macro usz? write_tiny_bytearray(stream, char[] data)
{
stream.write_byte((char)data.len)!;
return stream.write(data) + 1;
@@ -402,7 +402,7 @@ macro usz! write_tiny_bytearray(stream, char[] data)
<*
@require @is_instream(stream)
*>
macro char[]! read_tiny_bytearray(stream, Allocator allocator)
macro char[]? read_tiny_bytearray(stream, Allocator allocator)
{
int len = stream.read_byte()!;
if (!len) return {};
@@ -415,7 +415,7 @@ macro char[]! read_tiny_bytearray(stream, Allocator allocator)
@require @is_outstream(stream)
@require data.len < 0x1000 : "Data exceeded 65535"
*>
macro usz! write_short_bytearray(stream, char[] data)
macro usz? write_short_bytearray(stream, char[] data)
{
io::write_be_short(stream, (ushort)data.len)!;
return stream.write(data) + 2;
@@ -424,7 +424,7 @@ macro usz! write_short_bytearray(stream, char[] data)
<*
@require @is_instream(stream)
*>
macro char[]! read_short_bytearray(stream, Allocator allocator)
macro char[]? read_short_bytearray(stream, Allocator allocator)
{
int len = io::read_be_ushort(stream)!;
if (!len) return {};

View File

@@ -24,12 +24,12 @@ fn String ReadBuffer.str_view(&self) @inline
return (String)self.bytes[self.read_idx:self.write_idx - self.read_idx];
}
fn void! ReadBuffer.close(&self) @dynamic
fn void? ReadBuffer.close(&self) @dynamic
{
if (&self.wrapped_stream.close) self.wrapped_stream.close()!;
}
fn usz! ReadBuffer.read(&self, char[] bytes) @dynamic
fn usz? ReadBuffer.read(&self, char[] bytes) @dynamic
{
if (self.read_idx == self.write_idx)
{
@@ -46,16 +46,16 @@ fn usz! ReadBuffer.read(&self, char[] bytes) @dynamic
return n;
}
fn char! ReadBuffer.read_byte(&self) @dynamic
fn char? ReadBuffer.read_byte(&self) @dynamic
{
if (self.read_idx == self.write_idx) self.refill()!;
if (self.read_idx == self.write_idx) return IoError.EOF?;
if (self.read_idx == self.write_idx) return io::EOF?;
char c = self.bytes[self.read_idx];
self.read_idx++;
return c;
}
fn void! ReadBuffer.refill(&self) @local @inline
fn void? ReadBuffer.refill(&self) @local @inline
{
self.read_idx = 0;
self.write_idx = self.wrapped_stream.read(self.bytes)!;
@@ -85,18 +85,18 @@ fn String WriteBuffer.str_view(&self) @inline
return (String)self.bytes[:self.index];
}
fn void! WriteBuffer.close(&self) @dynamic
fn void? WriteBuffer.close(&self) @dynamic
{
if (&self.wrapped_stream.close) return self.wrapped_stream.close();
}
fn void! WriteBuffer.flush(&self) @dynamic
fn void? WriteBuffer.flush(&self) @dynamic
{
self.write_pending()!;
if (&self.wrapped_stream.flush) self.wrapped_stream.flush()!;
}
fn usz! WriteBuffer.write(&self, char[] bytes) @dynamic
fn usz? WriteBuffer.write(&self, char[] bytes) @dynamic
{
usz n = self.bytes.len - self.index;
if (bytes.len < n)
@@ -118,7 +118,7 @@ fn usz! WriteBuffer.write(&self, char[] bytes) @dynamic
return bytes.len;
}
fn void! WriteBuffer.write_byte(&self, char c) @dynamic
fn void? WriteBuffer.write_byte(&self, char c) @dynamic
{
usz n = self.bytes.len - self.index;
if (n == 0)
@@ -129,8 +129,8 @@ fn void! WriteBuffer.write_byte(&self, char c) @dynamic
self.index += 1;
}
fn void! WriteBuffer.write_pending(&self) @local
fn void? WriteBuffer.write_pending(&self) @local
{
self.index -= self.wrapped_stream.write(self.bytes[:self.index])!;
if (self.index != 0) return IoError.INCOMPLETE_WRITE?;
if (self.index != 0) return INCOMPLETE_WRITE?;
}

View File

@@ -45,7 +45,7 @@ fn void ByteBuffer.free(&self)
*self = {};
}
fn usz! ByteBuffer.write(&self, char[] bytes) @dynamic
fn usz? ByteBuffer.write(&self, char[] bytes) @dynamic
{
usz cap = self.bytes.len - self.write_idx;
if (cap < bytes.len) self.grow(bytes.len);
@@ -54,7 +54,7 @@ fn usz! ByteBuffer.write(&self, char[] bytes) @dynamic
return bytes.len;
}
fn void! ByteBuffer.write_byte(&self, char c) @dynamic
fn void? ByteBuffer.write_byte(&self, char c) @dynamic
{
usz cap = self.bytes.len - self.write_idx;
if (cap == 0) self.grow(1);
@@ -62,13 +62,13 @@ fn void! ByteBuffer.write_byte(&self, char c) @dynamic
self.write_idx++;
}
fn usz! ByteBuffer.read(&self, char[] bytes) @dynamic
fn usz? ByteBuffer.read(&self, char[] bytes) @dynamic
{
usz readable = self.write_idx - self.read_idx;
if (readable == 0)
{
self.has_last = false;
return IoError.EOF?;
return io::EOF?;
}
usz n = min(readable, bytes.len);
bytes[:n] = self.bytes[self.read_idx:n];
@@ -78,13 +78,13 @@ fn usz! ByteBuffer.read(&self, char[] bytes) @dynamic
return n;
}
fn char! ByteBuffer.read_byte(&self) @dynamic
fn char? ByteBuffer.read_byte(&self) @dynamic
{
usz readable = self.write_idx - self.read_idx;
if (readable == 0)
{
self.has_last = false;
return IoError.EOF?;
return io::EOF?;
}
char c = self.bytes[self.read_idx];
self.read_idx++;
@@ -96,34 +96,34 @@ fn char! ByteBuffer.read_byte(&self) @dynamic
<*
Only the last byte of a successful read can be pushed back.
*>
fn void! ByteBuffer.pushback_byte(&self) @dynamic
fn void? ByteBuffer.pushback_byte(&self) @dynamic
{
if (!self.has_last) return IoError.EOF?;
if (!self.has_last) return io::EOF?;
assert(self.read_idx > 0);
self.read_idx--;
self.has_last = false;
}
fn usz! ByteBuffer.seek(&self, isz offset, Seek seek) @dynamic
fn usz? ByteBuffer.seek(&self, isz offset, Seek seek) @dynamic
{
switch (seek)
{
case SET:
if (offset < 0 || offset > self.write_idx) return IoError.INVALID_POSITION?;
if (offset < 0 || offset > self.write_idx) return INVALID_POSITION?;
self.read_idx = offset;
return offset;
case CURSOR:
if ((offset < 0 && self.read_idx < -offset) ||
(offset > 0 && self.read_idx + offset > self.write_idx)) return IoError.INVALID_POSITION?;
(offset > 0 && self.read_idx + offset > self.write_idx)) return INVALID_POSITION?;
self.read_idx += offset;
case END:
if (offset < 0 || offset > self.write_idx) return IoError.INVALID_POSITION?;
if (offset < 0 || offset > self.write_idx) return INVALID_POSITION?;
self.read_idx = self.write_idx - offset;
}
return self.read_idx;
}
fn usz! ByteBuffer.available(&self) @inline @dynamic
fn usz? ByteBuffer.available(&self) @inline @dynamic
{
return self.write_idx - self.read_idx;
}

View File

@@ -17,9 +17,9 @@ fn ByteReader* ByteReader.init(&self, char[] bytes)
return self;
}
fn usz! ByteReader.read(&self, char[] bytes) @dynamic
fn usz? ByteReader.read(&self, char[] bytes) @dynamic
{
if (self.index >= self.bytes.len) return IoError.EOF?;
if (self.index >= self.bytes.len) return io::EOF?;
usz len = min(self.bytes.len - self.index, bytes.len);
if (len == 0) return 0;
mem::copy(bytes.ptr, &self.bytes[self.index], len);
@@ -27,19 +27,19 @@ fn usz! ByteReader.read(&self, char[] bytes) @dynamic
return len;
}
fn char! ByteReader.read_byte(&self) @dynamic
fn char? ByteReader.read_byte(&self) @dynamic
{
if (self.index >= self.bytes.len) return IoError.EOF?;
if (self.index >= self.bytes.len) return io::EOF?;
return self.bytes[self.index++];
}
fn void! ByteReader.pushback_byte(&self) @dynamic
fn void? ByteReader.pushback_byte(&self) @dynamic
{
if (!self.index) return IoError.INVALID_PUSHBACK?;
if (!self.index) return INVALID_PUSHBACK?;
self.index--;
}
fn usz! ByteReader.seek(&self, isz offset, Seek seek) @dynamic
fn usz? ByteReader.seek(&self, isz offset, Seek seek) @dynamic
{
isz new_index;
switch (seek)
@@ -48,12 +48,12 @@ fn usz! ByteReader.seek(&self, isz offset, Seek seek) @dynamic
case CURSOR: new_index = self.index + offset;
case END: new_index = self.bytes.len + offset;
}
if (new_index < 0) return IoError.INVALID_POSITION?;
if (new_index < 0) return INVALID_POSITION?;
self.index = new_index;
return new_index;
}
fn usz! ByteReader.write_to(&self, OutStream writer) @dynamic
fn usz? ByteReader.write_to(&self, OutStream writer) @dynamic
{
if (self.index >= self.bytes.len) return 0;
usz written = writer.write(self.bytes[self.index..])!;
@@ -62,7 +62,7 @@ fn usz! ByteReader.write_to(&self, OutStream writer) @dynamic
return written;
}
fn usz! ByteReader.available(&self) @inline @dynamic
fn usz? ByteReader.available(&self) @inline @dynamic
{
return max(0, self.bytes.len - self.index);
}

View File

@@ -36,7 +36,7 @@ fn ByteWriter* ByteWriter.init_with_buffer(&self, char[] data)
return self;
}
fn void! ByteWriter.destroy(&self) @dynamic
fn void? ByteWriter.destroy(&self) @dynamic
{
if (!self.allocator) return;
if (void* ptr = self.bytes.ptr) allocator::free(self.allocator, ptr);
@@ -48,17 +48,17 @@ fn String ByteWriter.str_view(&self) @inline
return (String)self.bytes[:self.index];
}
fn void! ByteWriter.ensure_capacity(&self, usz len) @inline
fn void? ByteWriter.ensure_capacity(&self, usz len) @inline
{
if (self.bytes.len > len) return;
if (!self.allocator) return IoError.OUT_OF_SPACE?;
if (!self.allocator) return OUT_OF_SPACE?;
if (len < 16) len = 16;
usz new_capacity = math::next_power_of_2(len);
char* new_ptr = allocator::realloc_try(self.allocator, self.bytes.ptr, new_capacity)!;
self.bytes = new_ptr[:new_capacity];
}
fn usz! ByteWriter.write(&self, char[] bytes) @dynamic
fn usz? ByteWriter.write(&self, char[] bytes) @dynamic
{
self.ensure_capacity(self.index + bytes.len)!;
mem::copy(&self.bytes[self.index], bytes.ptr, bytes.len);
@@ -66,7 +66,7 @@ fn usz! ByteWriter.write(&self, char[] bytes) @dynamic
return bytes.len;
}
fn void! ByteWriter.write_byte(&self, char c) @dynamic
fn void? ByteWriter.write_byte(&self, char c) @dynamic
{
self.ensure_capacity(self.index + 1)!;
self.bytes[self.index++] = c;
@@ -76,7 +76,7 @@ fn void! ByteWriter.write_byte(&self, char c) @dynamic
@param [&inout] self
@param reader
*>
fn usz! ByteWriter.read_from(&self, InStream reader) @dynamic
fn usz? ByteWriter.read_from(&self, InStream reader) @dynamic
{
usz start_index = self.index;
if (&reader.available)

View File

@@ -16,29 +16,29 @@ fn LimitReader* LimitReader.init(&self, InStream wrapped_stream, usz limit)
return self;
}
fn void! LimitReader.close(&self) @dynamic
fn void? LimitReader.close(&self) @dynamic
{
if (&self.wrapped_stream.close) return self.wrapped_stream.close();
}
fn usz! LimitReader.read(&self, char[] bytes) @dynamic
fn usz? LimitReader.read(&self, char[] bytes) @dynamic
{
if (self.limit == 0) return IoError.EOF?;
if (self.limit == 0) return io::EOF?;
usz m = min(bytes.len, self.limit);
usz n = self.wrapped_stream.read(bytes[:m])!;
self.limit -= n;
return n;
}
fn char! LimitReader.read_byte(&self) @dynamic
fn char? LimitReader.read_byte(&self) @dynamic
{
if (self.limit == 0) return IoError.EOF?;
if (self.limit == 0) return io::EOF?;
defer try self.limit--;
return self.wrapped_stream.read_byte();
}
fn usz! LimitReader.available(&self) @inline @dynamic
fn usz? LimitReader.available(&self) @inline @dynamic
{
return self.limit;
}

View File

@@ -2,7 +2,7 @@ module std::io;
/* MultiReader implements the InStream interface and provides a logical
* concatenation of the provided readers. They are read sequentially. If all the
* data has been read, IoError.EOF is returned.
* data has been read, io::EOF is returned.
*/
struct MultiReader (InStream)
{
@@ -43,24 +43,24 @@ fn void MultiReader.free(&self)
*self = {};
}
fn usz! MultiReader.read(&self, char[] bytes) @dynamic
fn usz? MultiReader.read(&self, char[] bytes) @dynamic
{
InStream r = self.readers[self.index];
usz! n = r.read(bytes);
usz? n = r.read(bytes);
if (catch err = n)
{
if (err != IoError.EOF) return err?;
if (err != io::EOF) return err?;
self.index++;
if (self.index >= self.readers.len)
{
return IoError.EOF?;
return io::EOF?;
}
return self.read(bytes);
}
return n;
}
fn char! MultiReader.read_byte(&self) @dynamic
fn char? MultiReader.read_byte(&self) @dynamic
{
char[1] data;
self.read(data[..])!;

View File

@@ -40,18 +40,18 @@ fn void MultiWriter.free(&self)
*self = {};
}
fn usz! MultiWriter.write(&self, char[] bytes) @dynamic
fn usz? MultiWriter.write(&self, char[] bytes) @dynamic
{
usz n;
foreach (w : self.writers)
{
n = w.write(bytes)!;
if (n != bytes.len) return IoError.INCOMPLETE_WRITE?;
if (n != bytes.len) return INCOMPLETE_WRITE?;
}
return bytes.len;
}
fn void! MultiWriter.write_byte(&self, char c) @dynamic
fn void? MultiWriter.write_byte(&self, char c) @dynamic
{
char[1] data;
data[0] = c;

View File

@@ -35,7 +35,7 @@ fn char[] Scanner.flush(&self) @dynamic
return buf;
}
fn void! Scanner.close(&self) @dynamic
fn void? Scanner.close(&self) @dynamic
{
if (&self.wrapped_stream.close) return self.wrapped_stream.close();
}
@@ -45,7 +45,7 @@ fn void! Scanner.close(&self) @dynamic
@require pattern.len > 0 : "Non-empty pattern required."
@require self.buf.len > pattern.len : "Pattern too large."
*>
fn char[]! Scanner.scan(&self, String pattern = "\n")
fn char[]? Scanner.scan(&self, String pattern = "\n")
{
if (self.read_idx == 0)
{
@@ -65,7 +65,7 @@ fn char[]! Scanner.scan(&self, String pattern = "\n")
{
// Split pattern not found with maximized search, abort.
// Split pattern not found and already read as much as possible.
return SearchResult.MISSING?;
return NOT_FOUND?;
}
// Split pattern not found: maximize the search and try one more time.
self.buf[:n] = buf[..];
@@ -82,23 +82,23 @@ fn char[]! Scanner.scan(&self, String pattern = "\n")
return self.buf[:n + i];
}
macro usz! Scanner.find(&self, buf, pattern) @private
macro usz? Scanner.find(&self, buf, pattern) @private
{
return ((String)buf).index_of(pattern);
}
macro usz! Scanner.refill(&self, buf) @private
macro usz? Scanner.refill(&self, buf) @private
{
usz! n = self.wrapped_stream.read(buf);
usz? n = self.wrapped_stream.read(buf);
if (catch err = n)
{
if (err == IoError.EOF) return SearchResult.MISSING?;
if (err == io::EOF) return NOT_FOUND?;
return err?;
}
return n;
}
fn usz! Scanner.read(&self, char[] bytes) @dynamic
fn usz? Scanner.read(&self, char[] bytes) @dynamic
{
usz n;
if (self.pattern_idx < self.read_idx)
@@ -112,7 +112,7 @@ fn usz! Scanner.read(&self, char[] bytes) @dynamic
return n;
}
fn char! Scanner.read_byte(&self) @dynamic
fn char? Scanner.read_byte(&self) @dynamic
{
if (self.pattern_idx < self.read_idx)
{

View File

@@ -25,16 +25,16 @@ fn TeeReader* TeeReader.init(&self, InStream r, OutStream w)
return self;
}
fn usz! TeeReader.read(&self, char[] bytes) @dynamic
fn usz? TeeReader.read(&self, char[] bytes) @dynamic
{
usz nr, nw;
nr = self.r.read(bytes)!;
nw = self.w.write(bytes[:nr])!;
if (nr != nw) return IoError.GENERAL_ERROR?;
if (nr != nw) return GENERAL_ERROR?;
return nr;
}
fn char! TeeReader.read_byte(&self) @dynamic
fn char? TeeReader.read_byte(&self) @dynamic
{
char[1] data;
self.read(data[..])!;

View File

@@ -83,7 +83,7 @@ fn BigInt* BigInt.init_with_array(&self, uint[] values)
return self;
}
fn BigInt*! BigInt.init_string_radix(&self, String value, int radix)
fn BigInt*? BigInt.init_string_radix(&self, String value, int radix)
{
isz len = value.len;
isz limit = value[0] == '-' ? 1 : 0;
@@ -102,9 +102,9 @@ fn BigInt*! BigInt.init_string_radix(&self, String value, int radix)
case 'a'..'z':
pos_val -= 'a' - 10;
default:
return NumberConversion.MALFORMED_INTEGER?;
return string::MALFORMED_INTEGER?;
}
if (pos_val >= radix) return NumberConversion.MALFORMED_INTEGER?;
if (pos_val >= radix) return string::MALFORMED_INTEGER?;
if (limit == 1) pos_val = -pos_val;
self.add_this(multiplier.mult(from_int(pos_val)));
if (i - 1 >= limit)
@@ -115,9 +115,9 @@ fn BigInt*! BigInt.init_string_radix(&self, String value, int radix)
switch
{
case limit && !self.is_negative():
return NumberConversion.INTEGER_OVERFLOW?;
return string::INTEGER_OVERFLOW?;
case !limit && self.is_negative():
return NumberConversion.INTEGER_OVERFLOW?;
return string::INTEGER_OVERFLOW?;
}
return self;
}
@@ -506,7 +506,7 @@ fn BigInt BigInt.abs(&self)
return self.is_negative() ? self.unary_minus() : *self;
}
fn usz! BigInt.to_format(&self, Formatter* format) @dynamic
fn usz? BigInt.to_format(&self, Formatter* format) @dynamic
{
@stack_mem(4100; Allocator mem)
{
@@ -526,7 +526,7 @@ fn String BigInt.to_string_with_radix(&self, int radix, Allocator allocator)
{
if (self.is_zero()) return "0".copy(allocator);
const char[?] CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const char[*] CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
@stack_mem(4100; Allocator mem)
{
BigInt a = *self;

View File

@@ -80,15 +80,7 @@ enum RoundingMode : int
TOWARD_NEG_INFINITY
}
fault MathError
{
OVERFLOW,
}
fault MatrixError
{
MATRIX_INVERSE_DOESNT_EXIST,
}
fault OVERFLOW, MATRIX_INVERSE_DOESNT_EXIST;
def Complexf = Complex{float};
def Complex = Complex{double};
@@ -629,7 +621,7 @@ macro normalize(x) @private
@return "a vector of the same type as then/else"
*>
macro select(bool[<?>] mask, then_value, else_value)
macro select(bool[<*>] mask, then_value, else_value)
{
return $$select(mask, then_value, else_value);
}
@@ -647,35 +639,35 @@ macro float float.round(float x) => $$round(x);
macro float float.roundeven(float x) => $$roundeven(x);
macro float float.trunc(float x) => $$trunc(x);
macro float float[<?>].sum(float[<?>] x, float start = 0.0) => $$reduce_fadd(x, start);
macro float float[<?>].product(float[<?>] x, float start = 1.0) => $$reduce_fmul(x, start);
macro float float[<?>].max(float[<?>] x) => $$reduce_max(x);
macro float float[<?>].min(float[<?>] x) => $$reduce_min(x);
macro float[<?>] float[<?>].ceil(float[<?>] x) => $$ceil(x);
macro float[<?>] float[<?>].clamp(float[<?>] x, float[<?>] lower, float[<?>] upper) => $$max(lower, $$min(x, upper));
macro float[<?>] float[<?>].copysign(float[<?>] mag, float[<?>] sgn) => $$copysign(mag, sgn);
macro float[<?>] float[<?>].fma(float[<?>] a, float[<?>] b, float[<?>] c) => $$fma(a, b, c);
macro float[<?>] float[<?>].floor(float[<?>] x) => $$floor(x);
macro float[<?>] float[<?>].nearbyint(float[<?>] x) => $$nearbyint(x);
macro float[<?>] float[<?>].pow(float[<?>] x, exp) => pow(x, exp);
macro float[<?>] float[<?>].rint(float[<?>] x) => $$rint(x);
macro float[<?>] float[<?>].round(float[<?>] x) => $$round(x);
macro float[<?>] float[<?>].roundeven(float[<?>] x) => $$roundeven(x);
macro float[<?>] float[<?>].trunc(float[<?>] x) => $$trunc(x);
macro float float[<?>].dot(float[<?>] x, float[<?>] y) => (x * y).sum();
macro float float[<?>].length(float[<?>] x) => $$sqrt(x.dot(x));
macro float float[<?>].distance(float[<?>] x, float[<?>] y) => (x - y).length();
macro float[<?>] float[<?>].normalize(float[<?>] x) => normalize(x);
macro float[<?>] float[<?>].lerp(float[<?>] x, float[<?>] y, float amount) => lerp(x, y, amount);
macro float[<?>] float[<?>].reflect(float[<?>] x, float[<?>] y) => reflect(x, y);
macro bool float[<?>].equals(float[<?>] x, float[<?>] y) => equals_vec(x, y);
macro float float[<*>].sum(float[<*>] x, float start = 0.0) => $$reduce_fadd(x, start);
macro float float[<*>].product(float[<*>] x, float start = 1.0) => $$reduce_fmul(x, start);
macro float float[<*>].max(float[<*>] x) => $$reduce_max(x);
macro float float[<*>].min(float[<*>] x) => $$reduce_min(x);
macro float[<*>] float[<*>].ceil(float[<*>] x) => $$ceil(x);
macro float[<*>] float[<*>].clamp(float[<*>] x, float[<*>] lower, float[<*>] upper) => $$max(lower, $$min(x, upper));
macro float[<*>] float[<*>].copysign(float[<*>] mag, float[<*>] sgn) => $$copysign(mag, sgn);
macro float[<*>] float[<*>].fma(float[<*>] a, float[<*>] b, float[<*>] c) => $$fma(a, b, c);
macro float[<*>] float[<*>].floor(float[<*>] x) => $$floor(x);
macro float[<*>] float[<*>].nearbyint(float[<*>] x) => $$nearbyint(x);
macro float[<*>] float[<*>].pow(float[<*>] x, exp) => pow(x, exp);
macro float[<*>] float[<*>].rint(float[<*>] x) => $$rint(x);
macro float[<*>] float[<*>].round(float[<*>] x) => $$round(x);
macro float[<*>] float[<*>].roundeven(float[<*>] x) => $$roundeven(x);
macro float[<*>] float[<*>].trunc(float[<*>] x) => $$trunc(x);
macro float float[<*>].dot(float[<*>] x, float[<*>] y) => (x * y).sum();
macro float float[<*>].length(float[<*>] x) => $$sqrt(x.dot(x));
macro float float[<*>].distance(float[<*>] x, float[<*>] y) => (x - y).length();
macro float[<*>] float[<*>].normalize(float[<*>] x) => normalize(x);
macro float[<*>] float[<*>].lerp(float[<*>] x, float[<*>] y, float amount) => lerp(x, y, amount);
macro float[<*>] float[<*>].reflect(float[<*>] x, float[<*>] y) => reflect(x, y);
macro bool float[<*>].equals(float[<*>] x, float[<*>] y) => equals_vec(x, y);
macro bool[<?>] float[<?>].comp_lt(float[<?>] x, float[<?>] y) => $$veccomplt(x, y);
macro bool[<?>] float[<?>].comp_le(float[<?>] x, float[<?>] y) => $$veccomple(x, y);
macro bool[<?>] float[<?>].comp_eq(float[<?>] x, float[<?>] y) => $$veccompeq(x, y);
macro bool[<?>] float[<?>].comp_gt(float[<?>] x, float[<?>] y) => $$veccompgt(x, y);
macro bool[<?>] float[<?>].comp_ge(float[<?>] x, float[<?>] y) => $$veccompge(x, y);
macro bool[<?>] float[<?>].comp_ne(float[<?>] x, float[<?>] y) => $$veccompne(x, y);
macro bool[<*>] float[<*>].comp_lt(float[<*>] x, float[<*>] y) => $$veccomplt(x, y);
macro bool[<*>] float[<*>].comp_le(float[<*>] x, float[<*>] y) => $$veccomple(x, y);
macro bool[<*>] float[<*>].comp_eq(float[<*>] x, float[<*>] y) => $$veccompeq(x, y);
macro bool[<*>] float[<*>].comp_gt(float[<*>] x, float[<*>] y) => $$veccompgt(x, y);
macro bool[<*>] float[<*>].comp_ge(float[<*>] x, float[<*>] y) => $$veccompge(x, y);
macro bool[<*>] float[<*>].comp_ne(float[<*>] x, float[<*>] y) => $$veccompne(x, y);
macro double double.ceil(double x) => $$ceil(x);
macro double double.clamp(double x, double lower, double upper) => $$max(lower, $$min(x, upper));
@@ -690,289 +682,289 @@ macro double double.round(double x) => $$round(x);
macro double double.roundeven(double x) => $$roundeven(x);
macro double double.trunc(double x) => $$trunc(x);
macro double double[<?>].sum(double[<?>] x, double start = 0.0) => $$reduce_fadd(x, start);
macro double double[<?>].product(double[<?>] x, double start = 1.0) => $$reduce_fmul(x, start);
macro double double[<?>].max(double[<?>] x) => $$reduce_fmax(x);
macro double double[<?>].min(double[<?>] x) => $$reduce_fmin(x);
macro double[<?>] double[<?>].ceil(double[<?>] x) => $$ceil(x);
macro double[<?>] double[<?>].clamp(double[<?>] x, double[<?>] lower, double[<?>] upper) => $$max(lower, $$min(x, upper));
macro double[<?>] double[<?>].copysign(double[<?>] mag, double[<?>] sgn) => $$copysign(mag, sgn);
macro double[<?>] double[<?>].floor(double[<?>] x) => $$floor(x);
macro double[<?>] double[<?>].fma(double[<?>] a, double[<?>] b, double[<?>] c) => $$fma(a, b, c);
macro double[<?>] double[<?>].nearbyint(double[<?>] x) => $$nearbyint(x);
macro double[<?>] double[<?>].pow(double[<?>] x, exp) => pow(x, exp);
macro double[<?>] double[<?>].rint(double[<?>] x) => $$rint(x);
macro double[<?>] double[<?>].round(double[<?>] x) => $$round(x);
macro double[<?>] double[<?>].roundeven(double[<?>] x) => $$roundeven(x);
macro double[<?>] double[<?>].trunc(double[<?>] x) => $$trunc(x);
macro double double[<?>].dot(double[<?>] x, double[<?>] y) => (x * y).sum();
macro double double[<?>].length(double[<?>] x) => $$sqrt(x.dot(x));
macro double double[<?>].distance(double[<?>] x, double[<?>] y) => (x - y).length();
macro double[<?>] double[<?>].normalize(double[<?>] x) => normalize(x);
macro double[<?>] double[<?>].reflect(double[<?>] x, double[<?>] y) => reflect(x, y);
macro double[<?>] double[<?>].lerp(double[<?>] x, double[<?>] y, double amount) => lerp(x, y, amount);
macro bool double[<?>].equals(double[<?>] x, double[<?>] y) => equals_vec(x, y);
macro double double[<*>].sum(double[<*>] x, double start = 0.0) => $$reduce_fadd(x, start);
macro double double[<*>].product(double[<*>] x, double start = 1.0) => $$reduce_fmul(x, start);
macro double double[<*>].max(double[<*>] x) => $$reduce_fmax(x);
macro double double[<*>].min(double[<*>] x) => $$reduce_fmin(x);
macro double[<*>] double[<*>].ceil(double[<*>] x) => $$ceil(x);
macro double[<*>] double[<*>].clamp(double[<*>] x, double[<*>] lower, double[<*>] upper) => $$max(lower, $$min(x, upper));
macro double[<*>] double[<*>].copysign(double[<*>] mag, double[<*>] sgn) => $$copysign(mag, sgn);
macro double[<*>] double[<*>].floor(double[<*>] x) => $$floor(x);
macro double[<*>] double[<*>].fma(double[<*>] a, double[<*>] b, double[<*>] c) => $$fma(a, b, c);
macro double[<*>] double[<*>].nearbyint(double[<*>] x) => $$nearbyint(x);
macro double[<*>] double[<*>].pow(double[<*>] x, exp) => pow(x, exp);
macro double[<*>] double[<*>].rint(double[<*>] x) => $$rint(x);
macro double[<*>] double[<*>].round(double[<*>] x) => $$round(x);
macro double[<*>] double[<*>].roundeven(double[<*>] x) => $$roundeven(x);
macro double[<*>] double[<*>].trunc(double[<*>] x) => $$trunc(x);
macro double double[<*>].dot(double[<*>] x, double[<*>] y) => (x * y).sum();
macro double double[<*>].length(double[<*>] x) => $$sqrt(x.dot(x));
macro double double[<*>].distance(double[<*>] x, double[<*>] y) => (x - y).length();
macro double[<*>] double[<*>].normalize(double[<*>] x) => normalize(x);
macro double[<*>] double[<*>].reflect(double[<*>] x, double[<*>] y) => reflect(x, y);
macro double[<*>] double[<*>].lerp(double[<*>] x, double[<*>] y, double amount) => lerp(x, y, amount);
macro bool double[<*>].equals(double[<*>] x, double[<*>] y) => equals_vec(x, y);
macro bool[<?>] double[<?>].comp_lt(double[<?>] x, double[<?>] y) => $$veccomplt(x, y);
macro bool[<?>] double[<?>].comp_le(double[<?>] x, double[<?>] y) => $$veccomple(x, y);
macro bool[<?>] double[<?>].comp_eq(double[<?>] x, double[<?>] y) => $$veccompeq(x, y);
macro bool[<?>] double[<?>].comp_gt(double[<?>] x, double[<?>] y) => $$veccompgt(x, y);
macro bool[<?>] double[<?>].comp_ge(double[<?>] x, double[<?>] y) => $$veccompge(x, y);
macro bool[<?>] double[<?>].comp_ne(double[<?>] x, double[<?>] y) => $$veccompne(x, y);
macro bool[<*>] double[<*>].comp_lt(double[<*>] x, double[<*>] y) => $$veccomplt(x, y);
macro bool[<*>] double[<*>].comp_le(double[<*>] x, double[<*>] y) => $$veccomple(x, y);
macro bool[<*>] double[<*>].comp_eq(double[<*>] x, double[<*>] y) => $$veccompeq(x, y);
macro bool[<*>] double[<*>].comp_gt(double[<*>] x, double[<*>] y) => $$veccompgt(x, y);
macro bool[<*>] double[<*>].comp_ge(double[<*>] x, double[<*>] y) => $$veccompge(x, y);
macro bool[<*>] double[<*>].comp_ne(double[<*>] x, double[<*>] y) => $$veccompne(x, y);
macro bool[<?>] ichar[<?>].comp_lt(ichar[<?>] x, ichar[<?>] y) => $$veccomplt(x, y);
macro bool[<?>] ichar[<?>].comp_le(ichar[<?>] x, ichar[<?>] y) => $$veccomple(x, y);
macro bool[<?>] ichar[<?>].comp_eq(ichar[<?>] x, ichar[<?>] y) => $$veccompeq(x, y);
macro bool[<?>] ichar[<?>].comp_gt(ichar[<?>] x, ichar[<?>] y) => $$veccompgt(x, y);
macro bool[<?>] ichar[<?>].comp_ge(ichar[<?>] x, ichar[<?>] y) => $$veccompge(x, y);
macro bool[<?>] ichar[<?>].comp_ne(ichar[<?>] x, ichar[<?>] y) => $$veccompne(x, y);
macro bool[<*>] ichar[<*>].comp_lt(ichar[<*>] x, ichar[<*>] y) => $$veccomplt(x, y);
macro bool[<*>] ichar[<*>].comp_le(ichar[<*>] x, ichar[<*>] y) => $$veccomple(x, y);
macro bool[<*>] ichar[<*>].comp_eq(ichar[<*>] x, ichar[<*>] y) => $$veccompeq(x, y);
macro bool[<*>] ichar[<*>].comp_gt(ichar[<*>] x, ichar[<*>] y) => $$veccompgt(x, y);
macro bool[<*>] ichar[<*>].comp_ge(ichar[<*>] x, ichar[<*>] y) => $$veccompge(x, y);
macro bool[<*>] ichar[<*>].comp_ne(ichar[<*>] x, ichar[<*>] y) => $$veccompne(x, y);
macro ichar ichar[<?>].sum(ichar[<?>] x) => $$reduce_add(x);
macro ichar ichar[<?>].product(ichar[<?>] x) => $$reduce_mul(x);
macro ichar ichar[<?>].and(ichar[<?>] x) => $$reduce_and(x);
macro ichar ichar[<?>].or(ichar[<?>] x) => $$reduce_or(x);
macro ichar ichar[<?>].xor(ichar[<?>] x) => $$reduce_xor(x);
macro ichar ichar[<?>].max(ichar[<?>] x) => $$reduce_max(x);
macro ichar ichar[<?>].min(ichar[<?>] x) => $$reduce_min(x);
macro ichar ichar[<?>].dot(ichar[<?>] x, ichar[<?>] y) => (x * y).sum();
macro ichar ichar[<*>].sum(ichar[<*>] x) => $$reduce_add(x);
macro ichar ichar[<*>].product(ichar[<*>] x) => $$reduce_mul(x);
macro ichar ichar[<*>].and(ichar[<*>] x) => $$reduce_and(x);
macro ichar ichar[<*>].or(ichar[<*>] x) => $$reduce_or(x);
macro ichar ichar[<*>].xor(ichar[<*>] x) => $$reduce_xor(x);
macro ichar ichar[<*>].max(ichar[<*>] x) => $$reduce_max(x);
macro ichar ichar[<*>].min(ichar[<*>] x) => $$reduce_min(x);
macro ichar ichar[<*>].dot(ichar[<*>] x, ichar[<*>] y) => (x * y).sum();
macro bool[<?>] short[<?>].comp_lt(short[<?>] x, short[<?>] y) => $$veccomplt(x, y);
macro bool[<?>] short[<?>].comp_le(short[<?>] x, short[<?>] y) => $$veccomple(x, y);
macro bool[<?>] short[<?>].comp_eq(short[<?>] x, short[<?>] y) => $$veccompeq(x, y);
macro bool[<?>] short[<?>].comp_gt(short[<?>] x, short[<?>] y) => $$veccompgt(x, y);
macro bool[<?>] short[<?>].comp_ge(short[<?>] x, short[<?>] y) => $$veccompge(x, y);
macro bool[<?>] short[<?>].comp_ne(short[<?>] x, short[<?>] y) => $$veccompne(x, y);
macro bool[<*>] short[<*>].comp_lt(short[<*>] x, short[<*>] y) => $$veccomplt(x, y);
macro bool[<*>] short[<*>].comp_le(short[<*>] x, short[<*>] y) => $$veccomple(x, y);
macro bool[<*>] short[<*>].comp_eq(short[<*>] x, short[<*>] y) => $$veccompeq(x, y);
macro bool[<*>] short[<*>].comp_gt(short[<*>] x, short[<*>] y) => $$veccompgt(x, y);
macro bool[<*>] short[<*>].comp_ge(short[<*>] x, short[<*>] y) => $$veccompge(x, y);
macro bool[<*>] short[<*>].comp_ne(short[<*>] x, short[<*>] y) => $$veccompne(x, y);
macro short short[<?>].sum(short[<?>] x) => $$reduce_add(x);
macro short short[<?>].product(short[<?>] x) => $$reduce_mul(x);
macro short short[<?>].and(short[<?>] x) => $$reduce_and(x);
macro short short[<?>].or(short[<?>] x) => $$reduce_or(x);
macro short short[<?>].xor(short[<?>] x) => $$reduce_xor(x);
macro short short[<?>].max(short[<?>] x) => $$reduce_max(x);
macro short short[<?>].min(short[<?>] x) => $$reduce_min(x);
macro short short[<?>].dot(short[<?>] x, short[<?>] y) => (x * y).sum();
macro short short[<*>].sum(short[<*>] x) => $$reduce_add(x);
macro short short[<*>].product(short[<*>] x) => $$reduce_mul(x);
macro short short[<*>].and(short[<*>] x) => $$reduce_and(x);
macro short short[<*>].or(short[<*>] x) => $$reduce_or(x);
macro short short[<*>].xor(short[<*>] x) => $$reduce_xor(x);
macro short short[<*>].max(short[<*>] x) => $$reduce_max(x);
macro short short[<*>].min(short[<*>] x) => $$reduce_min(x);
macro short short[<*>].dot(short[<*>] x, short[<*>] y) => (x * y).sum();
macro bool[<?>] int[<?>].comp_lt(int[<?>] x, int[<?>] y) => $$veccomplt(x, y);
macro bool[<?>] int[<?>].comp_le(int[<?>] x, int[<?>] y) => $$veccomple(x, y);
macro bool[<?>] int[<?>].comp_eq(int[<?>] x, int[<?>] y) => $$veccompeq(x, y);
macro bool[<?>] int[<?>].comp_gt(int[<?>] x, int[<?>] y) => $$veccompgt(x, y);
macro bool[<?>] int[<?>].comp_ge(int[<?>] x, int[<?>] y) => $$veccompge(x, y);
macro bool[<?>] int[<?>].comp_ne(int[<?>] x, int[<?>] y) => $$veccompne(x, y);
macro bool[<*>] int[<*>].comp_lt(int[<*>] x, int[<*>] y) => $$veccomplt(x, y);
macro bool[<*>] int[<*>].comp_le(int[<*>] x, int[<*>] y) => $$veccomple(x, y);
macro bool[<*>] int[<*>].comp_eq(int[<*>] x, int[<*>] y) => $$veccompeq(x, y);
macro bool[<*>] int[<*>].comp_gt(int[<*>] x, int[<*>] y) => $$veccompgt(x, y);
macro bool[<*>] int[<*>].comp_ge(int[<*>] x, int[<*>] y) => $$veccompge(x, y);
macro bool[<*>] int[<*>].comp_ne(int[<*>] x, int[<*>] y) => $$veccompne(x, y);
macro int int[<?>].sum(int[<?>] x) => $$reduce_add(x);
macro int int[<?>].product(int[<?>] x) => $$reduce_mul(x);
macro int int[<?>].and(int[<?>] x) => $$reduce_and(x);
macro int int[<?>].or(int[<?>] x) => $$reduce_or(x);
macro int int[<?>].xor(int[<?>] x) => $$reduce_xor(x);
macro int int[<?>].max(int[<?>] x) => $$reduce_max(x);
macro int int[<?>].min(int[<?>] x) => $$reduce_min(x);
macro int int[<?>].dot(int[<?>] x, int[<?>] y) => (x * y).sum();
macro int int[<*>].sum(int[<*>] x) => $$reduce_add(x);
macro int int[<*>].product(int[<*>] x) => $$reduce_mul(x);
macro int int[<*>].and(int[<*>] x) => $$reduce_and(x);
macro int int[<*>].or(int[<*>] x) => $$reduce_or(x);
macro int int[<*>].xor(int[<*>] x) => $$reduce_xor(x);
macro int int[<*>].max(int[<*>] x) => $$reduce_max(x);
macro int int[<*>].min(int[<*>] x) => $$reduce_min(x);
macro int int[<*>].dot(int[<*>] x, int[<*>] y) => (x * y).sum();
macro bool[<?>] long[<?>].comp_lt(long[<?>] x, long[<?>] y) => $$veccomplt(x, y);
macro bool[<?>] long[<?>].comp_le(long[<?>] x, long[<?>] y) => $$veccomple(x, y);
macro bool[<?>] long[<?>].comp_eq(long[<?>] x, long[<?>] y) => $$veccompeq(x, y);
macro bool[<?>] long[<?>].comp_gt(long[<?>] x, long[<?>] y) => $$veccompgt(x, y);
macro bool[<?>] long[<?>].comp_ge(long[<?>] x, long[<?>] y) => $$veccompge(x, y);
macro bool[<?>] long[<?>].comp_ne(long[<?>] x, long[<?>] y) => $$veccompne(x, y);
macro long long[<?>].sum(long[<?>] x) => $$reduce_add(x);
macro long long[<?>].product(long[<?>] x) => $$reduce_mul(x);
macro long long[<?>].and(long[<?>] x) => $$reduce_and(x);
macro long long[<?>].or(long[<?>] x) => $$reduce_or(x);
macro long long[<?>].xor(long[<?>] x) => $$reduce_xor(x);
macro long long[<?>].max(long[<?>] x) => $$reduce_max(x);
macro long long[<?>].min(long[<?>] x) => $$reduce_min(x);
macro long long[<?>].dot(long[<?>] x, long[<?>] y) => (x * y).sum();
macro bool[<*>] long[<*>].comp_lt(long[<*>] x, long[<*>] y) => $$veccomplt(x, y);
macro bool[<*>] long[<*>].comp_le(long[<*>] x, long[<*>] y) => $$veccomple(x, y);
macro bool[<*>] long[<*>].comp_eq(long[<*>] x, long[<*>] y) => $$veccompeq(x, y);
macro bool[<*>] long[<*>].comp_gt(long[<*>] x, long[<*>] y) => $$veccompgt(x, y);
macro bool[<*>] long[<*>].comp_ge(long[<*>] x, long[<*>] y) => $$veccompge(x, y);
macro bool[<*>] long[<*>].comp_ne(long[<*>] x, long[<*>] y) => $$veccompne(x, y);
macro long long[<*>].sum(long[<*>] x) => $$reduce_add(x);
macro long long[<*>].product(long[<*>] x) => $$reduce_mul(x);
macro long long[<*>].and(long[<*>] x) => $$reduce_and(x);
macro long long[<*>].or(long[<*>] x) => $$reduce_or(x);
macro long long[<*>].xor(long[<*>] x) => $$reduce_xor(x);
macro long long[<*>].max(long[<*>] x) => $$reduce_max(x);
macro long long[<*>].min(long[<*>] x) => $$reduce_min(x);
macro long long[<*>].dot(long[<*>] x, long[<*>] y) => (x * y).sum();
macro bool[<?>] int128[<?>].comp_lt(int128[<?>] x, int128[<?>] y) => $$veccomplt(x, y);
macro bool[<?>] int128[<?>].comp_le(int128[<?>] x, int128[<?>] y) => $$veccomple(x, y);
macro bool[<?>] int128[<?>].comp_eq(int128[<?>] x, int128[<?>] y) => $$veccompeq(x, y);
macro bool[<?>] int128[<?>].comp_gt(int128[<?>] x, int128[<?>] y) => $$veccompgt(x, y);
macro bool[<?>] int128[<?>].comp_ge(int128[<?>] x, int128[<?>] y) => $$veccompge(x, y);
macro bool[<?>] int128[<?>].comp_ne(int128[<?>] x, int128[<?>] y) => $$veccompne(x, y);
macro int128 int128[<?>].sum(int128[<?>] x) => $$reduce_add(x);
macro int128 int128[<?>].product(int128[<?>] x) => $$reduce_mul(x);
macro int128 int128[<?>].and(int128[<?>] x) => $$reduce_and(x);
macro int128 int128[<?>].or(int128[<?>] x) => $$reduce_or(x);
macro int128 int128[<?>].xor(int128[<?>] x) => $$reduce_xor(x);
macro int128 int128[<?>].max(int128[<?>] x) => $$reduce_max(x);
macro int128 int128[<?>].min(int128[<?>] x) => $$reduce_min(x);
macro int128 int128[<?>].dot(int128[<?>] x, int128[<?>] y) => (x * y).sum();
macro bool[<*>] int128[<*>].comp_lt(int128[<*>] x, int128[<*>] y) => $$veccomplt(x, y);
macro bool[<*>] int128[<*>].comp_le(int128[<*>] x, int128[<*>] y) => $$veccomple(x, y);
macro bool[<*>] int128[<*>].comp_eq(int128[<*>] x, int128[<*>] y) => $$veccompeq(x, y);
macro bool[<*>] int128[<*>].comp_gt(int128[<*>] x, int128[<*>] y) => $$veccompgt(x, y);
macro bool[<*>] int128[<*>].comp_ge(int128[<*>] x, int128[<*>] y) => $$veccompge(x, y);
macro bool[<*>] int128[<*>].comp_ne(int128[<*>] x, int128[<*>] y) => $$veccompne(x, y);
macro int128 int128[<*>].sum(int128[<*>] x) => $$reduce_add(x);
macro int128 int128[<*>].product(int128[<*>] x) => $$reduce_mul(x);
macro int128 int128[<*>].and(int128[<*>] x) => $$reduce_and(x);
macro int128 int128[<*>].or(int128[<*>] x) => $$reduce_or(x);
macro int128 int128[<*>].xor(int128[<*>] x) => $$reduce_xor(x);
macro int128 int128[<*>].max(int128[<*>] x) => $$reduce_max(x);
macro int128 int128[<*>].min(int128[<*>] x) => $$reduce_min(x);
macro int128 int128[<*>].dot(int128[<*>] x, int128[<*>] y) => (x * y).sum();
macro bool[<?>] bool[<?>].comp_lt(bool[<?>] x, bool[<?>] y) => $$veccomplt(x, y);
macro bool[<?>] bool[<?>].comp_le(bool[<?>] x, bool[<?>] y) => $$veccomple(x, y);
macro bool[<?>] bool[<?>].comp_eq(bool[<?>] x, bool[<?>] y) => $$veccompeq(x, y);
macro bool[<?>] bool[<?>].comp_gt(bool[<?>] x, bool[<?>] y) => $$veccompgt(x, y);
macro bool[<?>] bool[<?>].comp_ge(bool[<?>] x, bool[<?>] y) => $$veccompge(x, y);
macro bool[<?>] bool[<?>].comp_ne(bool[<?>] x, bool[<?>] y) => $$veccompne(x, y);
macro bool[<*>] bool[<*>].comp_lt(bool[<*>] x, bool[<*>] y) => $$veccomplt(x, y);
macro bool[<*>] bool[<*>].comp_le(bool[<*>] x, bool[<*>] y) => $$veccomple(x, y);
macro bool[<*>] bool[<*>].comp_eq(bool[<*>] x, bool[<*>] y) => $$veccompeq(x, y);
macro bool[<*>] bool[<*>].comp_gt(bool[<*>] x, bool[<*>] y) => $$veccompgt(x, y);
macro bool[<*>] bool[<*>].comp_ge(bool[<*>] x, bool[<*>] y) => $$veccompge(x, y);
macro bool[<*>] bool[<*>].comp_ne(bool[<*>] x, bool[<*>] y) => $$veccompne(x, y);
macro bool bool[<?>].sum(bool[<?>] x) => $$reduce_add(x);
macro bool bool[<?>].product(bool[<?>] x) => $$reduce_mul(x);
macro bool bool[<?>].and(bool[<?>] x) => $$reduce_and(x);
macro bool bool[<?>].or(bool[<?>] x) => $$reduce_or(x);
macro bool bool[<?>].xor(bool[<?>] x) => $$reduce_xor(x);
macro bool bool[<?>].max(bool[<?>] x) => $$reduce_max(x);
macro bool bool[<?>].min(bool[<?>] x) => $$reduce_min(x);
macro bool bool[<*>].sum(bool[<*>] x) => $$reduce_add(x);
macro bool bool[<*>].product(bool[<*>] x) => $$reduce_mul(x);
macro bool bool[<*>].and(bool[<*>] x) => $$reduce_and(x);
macro bool bool[<*>].or(bool[<*>] x) => $$reduce_or(x);
macro bool bool[<*>].xor(bool[<*>] x) => $$reduce_xor(x);
macro bool bool[<*>].max(bool[<*>] x) => $$reduce_max(x);
macro bool bool[<*>].min(bool[<*>] x) => $$reduce_min(x);
macro bool[<?>] char[<?>].comp_lt(char[<?>] x, char[<?>] y) => $$veccomplt(x, y);
macro bool[<?>] char[<?>].comp_le(char[<?>] x, char[<?>] y) => $$veccomple(x, y);
macro bool[<?>] char[<?>].comp_eq(char[<?>] x, char[<?>] y) => $$veccompeq(x, y);
macro bool[<?>] char[<?>].comp_gt(char[<?>] x, char[<?>] y) => $$veccompgt(x, y);
macro bool[<?>] char[<?>].comp_ge(char[<?>] x, char[<?>] y) => $$veccompge(x, y);
macro bool[<?>] char[<?>].comp_ne(char[<?>] x, char[<?>] y) => $$veccompne(x, y);
macro bool[<*>] char[<*>].comp_lt(char[<*>] x, char[<*>] y) => $$veccomplt(x, y);
macro bool[<*>] char[<*>].comp_le(char[<*>] x, char[<*>] y) => $$veccomple(x, y);
macro bool[<*>] char[<*>].comp_eq(char[<*>] x, char[<*>] y) => $$veccompeq(x, y);
macro bool[<*>] char[<*>].comp_gt(char[<*>] x, char[<*>] y) => $$veccompgt(x, y);
macro bool[<*>] char[<*>].comp_ge(char[<*>] x, char[<*>] y) => $$veccompge(x, y);
macro bool[<*>] char[<*>].comp_ne(char[<*>] x, char[<*>] y) => $$veccompne(x, y);
macro char char[<?>].sum(char[<?>] x) => $$reduce_add(x);
macro char char[<?>].product(char[<?>] x) => $$reduce_mul(x);
macro char char[<?>].and(char[<?>] x) => $$reduce_and(x);
macro char char[<?>].or(char[<?>] x) => $$reduce_or(x);
macro char char[<?>].xor(char[<?>] x) => $$reduce_xor(x);
macro char char[<?>].max(char[<?>] x) => $$reduce_max(x);
macro char char[<?>].min(char[<?>] x) => $$reduce_min(x);
macro char char[<?>].dot(char[<?>] x, char[<?>] y) => (x * y).sum();
macro char char[<*>].sum(char[<*>] x) => $$reduce_add(x);
macro char char[<*>].product(char[<*>] x) => $$reduce_mul(x);
macro char char[<*>].and(char[<*>] x) => $$reduce_and(x);
macro char char[<*>].or(char[<*>] x) => $$reduce_or(x);
macro char char[<*>].xor(char[<*>] x) => $$reduce_xor(x);
macro char char[<*>].max(char[<*>] x) => $$reduce_max(x);
macro char char[<*>].min(char[<*>] x) => $$reduce_min(x);
macro char char[<*>].dot(char[<*>] x, char[<*>] y) => (x * y).sum();
macro bool[<?>] ushort[<?>].comp_lt(ushort[<?>] x, ushort[<?>] y) => $$veccomplt(x, y);
macro bool[<?>] ushort[<?>].comp_le(ushort[<?>] x, ushort[<?>] y) => $$veccomple(x, y);
macro bool[<?>] ushort[<?>].comp_eq(ushort[<?>] x, ushort[<?>] y) => $$veccompeq(x, y);
macro bool[<?>] ushort[<?>].comp_gt(ushort[<?>] x, ushort[<?>] y) => $$veccompgt(x, y);
macro bool[<?>] ushort[<?>].comp_ge(ushort[<?>] x, ushort[<?>] y) => $$veccompge(x, y);
macro bool[<?>] ushort[<?>].comp_ne(ushort[<?>] x, ushort[<?>] y) => $$veccompne(x, y);
macro bool[<*>] ushort[<*>].comp_lt(ushort[<*>] x, ushort[<*>] y) => $$veccomplt(x, y);
macro bool[<*>] ushort[<*>].comp_le(ushort[<*>] x, ushort[<*>] y) => $$veccomple(x, y);
macro bool[<*>] ushort[<*>].comp_eq(ushort[<*>] x, ushort[<*>] y) => $$veccompeq(x, y);
macro bool[<*>] ushort[<*>].comp_gt(ushort[<*>] x, ushort[<*>] y) => $$veccompgt(x, y);
macro bool[<*>] ushort[<*>].comp_ge(ushort[<*>] x, ushort[<*>] y) => $$veccompge(x, y);
macro bool[<*>] ushort[<*>].comp_ne(ushort[<*>] x, ushort[<*>] y) => $$veccompne(x, y);
macro ushort ushort[<?>].sum(ushort[<?>] x) => $$reduce_add(x);
macro ushort ushort[<?>].product(ushort[<?>] x) => $$reduce_mul(x);
macro ushort ushort[<?>].and(ushort[<?>] x) => $$reduce_and(x);
macro ushort ushort[<?>].or(ushort[<?>] x) => $$reduce_or(x);
macro ushort ushort[<?>].xor(ushort[<?>] x) => $$reduce_xor(x);
macro ushort ushort[<?>].max(ushort[<?>] x) => $$reduce_max(x);
macro ushort ushort[<?>].min(ushort[<?>] x) => $$reduce_min(x);
macro ushort ushort[<?>].dot(ushort[<?>] x, ushort[<?>] y) => (x * y).sum();
macro ushort ushort[<*>].sum(ushort[<*>] x) => $$reduce_add(x);
macro ushort ushort[<*>].product(ushort[<*>] x) => $$reduce_mul(x);
macro ushort ushort[<*>].and(ushort[<*>] x) => $$reduce_and(x);
macro ushort ushort[<*>].or(ushort[<*>] x) => $$reduce_or(x);
macro ushort ushort[<*>].xor(ushort[<*>] x) => $$reduce_xor(x);
macro ushort ushort[<*>].max(ushort[<*>] x) => $$reduce_max(x);
macro ushort ushort[<*>].min(ushort[<*>] x) => $$reduce_min(x);
macro ushort ushort[<*>].dot(ushort[<*>] x, ushort[<*>] y) => (x * y).sum();
macro bool[<?>] uint[<?>].comp_lt(uint[<?>] x, uint[<?>] y) => $$veccomplt(x, y);
macro bool[<?>] uint[<?>].comp_le(uint[<?>] x, uint[<?>] y) => $$veccomple(x, y);
macro bool[<?>] uint[<?>].comp_eq(uint[<?>] x, uint[<?>] y) => $$veccompeq(x, y);
macro bool[<?>] uint[<?>].comp_gt(uint[<?>] x, uint[<?>] y) => $$veccompgt(x, y);
macro bool[<?>] uint[<?>].comp_ge(uint[<?>] x, uint[<?>] y) => $$veccompge(x, y);
macro bool[<?>] uint[<?>].comp_ne(uint[<?>] x, uint[<?>] y) => $$veccompne(x, y);
macro bool[<*>] uint[<*>].comp_lt(uint[<*>] x, uint[<*>] y) => $$veccomplt(x, y);
macro bool[<*>] uint[<*>].comp_le(uint[<*>] x, uint[<*>] y) => $$veccomple(x, y);
macro bool[<*>] uint[<*>].comp_eq(uint[<*>] x, uint[<*>] y) => $$veccompeq(x, y);
macro bool[<*>] uint[<*>].comp_gt(uint[<*>] x, uint[<*>] y) => $$veccompgt(x, y);
macro bool[<*>] uint[<*>].comp_ge(uint[<*>] x, uint[<*>] y) => $$veccompge(x, y);
macro bool[<*>] uint[<*>].comp_ne(uint[<*>] x, uint[<*>] y) => $$veccompne(x, y);
macro uint uint[<?>].sum(uint[<?>] x) => $$reduce_add(x);
macro uint uint[<?>].product(uint[<?>] x) => $$reduce_mul(x);
macro uint uint[<?>].and(uint[<?>] x) => $$reduce_and(x);
macro uint uint[<?>].or(uint[<?>] x) => $$reduce_or(x);
macro uint uint[<?>].xor(uint[<?>] x) => $$reduce_xor(x);
macro uint uint[<?>].max(uint[<?>] x) => $$reduce_max(x);
macro uint uint[<?>].min(uint[<?>] x) => $$reduce_min(x);
macro uint uint[<?>].dot(uint[<?>] x, uint[<?>] y) => (x * y).sum();
macro uint uint[<*>].sum(uint[<*>] x) => $$reduce_add(x);
macro uint uint[<*>].product(uint[<*>] x) => $$reduce_mul(x);
macro uint uint[<*>].and(uint[<*>] x) => $$reduce_and(x);
macro uint uint[<*>].or(uint[<*>] x) => $$reduce_or(x);
macro uint uint[<*>].xor(uint[<*>] x) => $$reduce_xor(x);
macro uint uint[<*>].max(uint[<*>] x) => $$reduce_max(x);
macro uint uint[<*>].min(uint[<*>] x) => $$reduce_min(x);
macro uint uint[<*>].dot(uint[<*>] x, uint[<*>] y) => (x * y).sum();
macro bool[<?>] ulong[<?>].comp_lt(ulong[<?>] x, ulong[<?>] y) => $$veccomplt(x, y);
macro bool[<?>] ulong[<?>].comp_le(ulong[<?>] x, ulong[<?>] y) => $$veccomple(x, y);
macro bool[<?>] ulong[<?>].comp_eq(ulong[<?>] x, ulong[<?>] y) => $$veccompeq(x, y);
macro bool[<?>] ulong[<?>].comp_gt(ulong[<?>] x, ulong[<?>] y) => $$veccompgt(x, y);
macro bool[<?>] ulong[<?>].comp_ge(ulong[<?>] x, ulong[<?>] y) => $$veccompge(x, y);
macro bool[<?>] ulong[<?>].comp_ne(ulong[<?>] x, ulong[<?>] y) => $$veccompne(x, y);
macro bool[<*>] ulong[<*>].comp_lt(ulong[<*>] x, ulong[<*>] y) => $$veccomplt(x, y);
macro bool[<*>] ulong[<*>].comp_le(ulong[<*>] x, ulong[<*>] y) => $$veccomple(x, y);
macro bool[<*>] ulong[<*>].comp_eq(ulong[<*>] x, ulong[<*>] y) => $$veccompeq(x, y);
macro bool[<*>] ulong[<*>].comp_gt(ulong[<*>] x, ulong[<*>] y) => $$veccompgt(x, y);
macro bool[<*>] ulong[<*>].comp_ge(ulong[<*>] x, ulong[<*>] y) => $$veccompge(x, y);
macro bool[<*>] ulong[<*>].comp_ne(ulong[<*>] x, ulong[<*>] y) => $$veccompne(x, y);
macro ulong ulong[<?>].sum(ulong[<?>] x) => $$reduce_add(x);
macro ulong ulong[<?>].product(ulong[<?>] x) => $$reduce_mul(x);
macro ulong ulong[<?>].and(ulong[<?>] x) => $$reduce_and(x);
macro ulong ulong[<?>].or(ulong[<?>] x) => $$reduce_or(x);
macro ulong ulong[<?>].xor(ulong[<?>] x) => $$reduce_xor(x);
macro ulong ulong[<?>].max(ulong[<?>] x) => $$reduce_max(x);
macro ulong ulong[<?>].min(ulong[<?>] x) => $$reduce_min(x);
macro ulong ulong[<?>].dot(ulong[<?>] x, ulong[<?>] y) => (x * y).sum();
macro ulong ulong[<*>].sum(ulong[<*>] x) => $$reduce_add(x);
macro ulong ulong[<*>].product(ulong[<*>] x) => $$reduce_mul(x);
macro ulong ulong[<*>].and(ulong[<*>] x) => $$reduce_and(x);
macro ulong ulong[<*>].or(ulong[<*>] x) => $$reduce_or(x);
macro ulong ulong[<*>].xor(ulong[<*>] x) => $$reduce_xor(x);
macro ulong ulong[<*>].max(ulong[<*>] x) => $$reduce_max(x);
macro ulong ulong[<*>].min(ulong[<*>] x) => $$reduce_min(x);
macro ulong ulong[<*>].dot(ulong[<*>] x, ulong[<*>] y) => (x * y).sum();
macro bool[<?>] uint128[<?>].comp_lt(uint128[<?>] x, uint128[<?>] y) => $$veccomplt(x, y);
macro bool[<?>] uint128[<?>].comp_le(uint128[<?>] x, uint128[<?>] y) => $$veccomple(x, y);
macro bool[<?>] uint128[<?>].comp_eq(uint128[<?>] x, uint128[<?>] y) => $$veccompeq(x, y);
macro bool[<?>] uint128[<?>].comp_gt(uint128[<?>] x, uint128[<?>] y) => $$veccompgt(x, y);
macro bool[<?>] uint128[<?>].comp_ge(uint128[<?>] x, uint128[<?>] y) => $$veccompge(x, y);
macro bool[<?>] uint128[<?>].comp_ne(uint128[<?>] x, uint128[<?>] y) => $$veccompne(x, y);
macro bool[<*>] uint128[<*>].comp_lt(uint128[<*>] x, uint128[<*>] y) => $$veccomplt(x, y);
macro bool[<*>] uint128[<*>].comp_le(uint128[<*>] x, uint128[<*>] y) => $$veccomple(x, y);
macro bool[<*>] uint128[<*>].comp_eq(uint128[<*>] x, uint128[<*>] y) => $$veccompeq(x, y);
macro bool[<*>] uint128[<*>].comp_gt(uint128[<*>] x, uint128[<*>] y) => $$veccompgt(x, y);
macro bool[<*>] uint128[<*>].comp_ge(uint128[<*>] x, uint128[<*>] y) => $$veccompge(x, y);
macro bool[<*>] uint128[<*>].comp_ne(uint128[<*>] x, uint128[<*>] y) => $$veccompne(x, y);
macro uint128 uint128[<?>].sum(uint128[<?>] x) => $$reduce_add(x);
macro uint128 uint128[<?>].product(uint128[<?>] x) => $$reduce_mul(x);
macro uint128 uint128[<?>].and(uint128[<?>] x) => $$reduce_and(x);
macro uint128 uint128[<?>].or(uint128[<?>] x) => $$reduce_or(x);
macro uint128 uint128[<?>].xor(uint128[<?>] x) => $$reduce_xor(x);
macro uint128 uint128[<?>].max(uint128[<?>] x) => $$reduce_max(x);
macro uint128 uint128[<?>].min(uint128[<?>] x) => $$reduce_min(x);
macro uint128 uint128[<?>].dot(uint128[<?>] x, uint128[<?>] y) => (x * y).sum();
macro uint128 uint128[<*>].sum(uint128[<*>] x) => $$reduce_add(x);
macro uint128 uint128[<*>].product(uint128[<*>] x) => $$reduce_mul(x);
macro uint128 uint128[<*>].and(uint128[<*>] x) => $$reduce_and(x);
macro uint128 uint128[<*>].or(uint128[<*>] x) => $$reduce_or(x);
macro uint128 uint128[<*>].xor(uint128[<*>] x) => $$reduce_xor(x);
macro uint128 uint128[<*>].max(uint128[<*>] x) => $$reduce_max(x);
macro uint128 uint128[<*>].min(uint128[<*>] x) => $$reduce_min(x);
macro uint128 uint128[<*>].dot(uint128[<*>] x, uint128[<*>] y) => (x * y).sum();
macro char char.sat_add(char x, char y) => $$sat_add(x, y);
macro char char.sat_sub(char x, char y) => $$sat_sub(x, y);
macro char char.sat_mul(char x, char y) => $$sat_mul(x, y);
macro char char.sat_shl(char x, char y) => $$sat_shl(x, y);
macro char! char.overflow_add(char x, char y) => overflow_add_helper(x, y);
macro char! char.overflow_sub(char x, char y) => overflow_sub_helper(x, y);
macro char! char.overflow_mul(char x, char y) => overflow_mul_helper(x, y);
macro char? char.overflow_add(char x, char y) => overflow_add_helper(x, y);
macro char? char.overflow_sub(char x, char y) => overflow_sub_helper(x, y);
macro char? char.overflow_mul(char x, char y) => overflow_mul_helper(x, y);
macro ichar ichar.sat_add(ichar x, ichar y) => $$sat_add(x, y);
macro ichar ichar.sat_sub(ichar x, ichar y) => $$sat_sub(x, y);
macro ichar ichar.sat_mul(ichar x, ichar y) => $$sat_mul(x, y);
macro ichar ichar.sat_shl(ichar x, ichar y) => $$sat_shl(x, y);
macro ichar! ichar.overflow_add(ichar x, ichar y) => overflow_add_helper(x, y);
macro ichar! ichar.overflow_sub(ichar x, ichar y) => overflow_sub_helper(x, y);
macro ichar! ichar.overflow_mul(ichar x, ichar y) => overflow_mul_helper(x, y);
macro ichar? ichar.overflow_add(ichar x, ichar y) => overflow_add_helper(x, y);
macro ichar? ichar.overflow_sub(ichar x, ichar y) => overflow_sub_helper(x, y);
macro ichar? ichar.overflow_mul(ichar x, ichar y) => overflow_mul_helper(x, y);
macro ushort ushort.sat_add(ushort x, ushort y) => $$sat_add(x, y);
macro ushort ushort.sat_sub(ushort x, ushort y) => $$sat_sub(x, y);
macro ushort ushort.sat_mul(ushort x, ushort y) => $$sat_mul(x, y);
macro ushort ushort.sat_shl(ushort x, ushort y) => $$sat_shl(x, y);
macro ushort! ushort.overflow_add(ushort x, ushort y) => overflow_add_helper(x, y);
macro ushort! ushort.overflow_sub(ushort x, ushort y) => overflow_sub_helper(x, y);
macro ushort! ushort.overflow_mul(ushort x, ushort y) => overflow_mul_helper(x, y);
macro ushort? ushort.overflow_add(ushort x, ushort y) => overflow_add_helper(x, y);
macro ushort? ushort.overflow_sub(ushort x, ushort y) => overflow_sub_helper(x, y);
macro ushort? ushort.overflow_mul(ushort x, ushort y) => overflow_mul_helper(x, y);
macro short short.sat_add(short x, short y) => $$sat_add(x, y);
macro short short.sat_sub(short x, short y) => $$sat_sub(x, y);
macro short short.sat_mul(short x, short y) => $$sat_mul(x, y);
macro short short.sat_shl(short x, short y) => $$sat_shl(x, y);
macro short! short.overflow_add(short x, short y) => overflow_add_helper(x, y);
macro short! short.overflow_sub(short x, short y) => overflow_sub_helper(x, y);
macro short! short.overflow_mul(short x, short y) => overflow_mul_helper(x, y);
macro short? short.overflow_add(short x, short y) => overflow_add_helper(x, y);
macro short? short.overflow_sub(short x, short y) => overflow_sub_helper(x, y);
macro short? short.overflow_mul(short x, short y) => overflow_mul_helper(x, y);
macro uint uint.sat_add(uint x, uint y) => $$sat_add(x, y);
macro uint uint.sat_sub(uint x, uint y) => $$sat_sub(x, y);
macro uint uint.sat_mul(uint x, uint y) => $$sat_mul(x, y);
macro uint uint.sat_shl(uint x, uint y) => $$sat_shl(x, y);
macro uint! uint.overflow_add(uint x, uint y) => overflow_add_helper(x, y);
macro uint! uint.overflow_sub(uint x, uint y) => overflow_sub_helper(x, y);
macro uint! uint.overflow_mul(uint x, uint y) => overflow_mul_helper(x, y);
macro uint? uint.overflow_add(uint x, uint y) => overflow_add_helper(x, y);
macro uint? uint.overflow_sub(uint x, uint y) => overflow_sub_helper(x, y);
macro uint? uint.overflow_mul(uint x, uint y) => overflow_mul_helper(x, y);
macro int int.sat_add(int x, int y) => $$sat_add(x, y);
macro int int.sat_sub(int x, int y) => $$sat_sub(x, y);
macro int int.sat_mul(int x, int y) => $$sat_mul(x, y);
macro int int.sat_shl(int x, int y) => $$sat_shl(x, y);
macro int! int.overflow_add(int x, int y) => overflow_add_helper(x, y);
macro int! int.overflow_sub(int x, int y) => overflow_sub_helper(x, y);
macro int! int.overflow_mul(int x, int y) => overflow_mul_helper(x, y);
macro int? int.overflow_add(int x, int y) => overflow_add_helper(x, y);
macro int? int.overflow_sub(int x, int y) => overflow_sub_helper(x, y);
macro int? int.overflow_mul(int x, int y) => overflow_mul_helper(x, y);
macro ulong ulong.sat_add(ulong x, ulong y) => $$sat_add(x, y);
macro ulong ulong.sat_sub(ulong x, ulong y) => $$sat_sub(x, y);
macro ulong ulong.sat_mul(ulong x, ulong y) => $$sat_mul(x, y);
macro ulong ulong.sat_shl(ulong x, ulong y) => $$sat_shl(x, y);
macro ulong! ulong.overflow_add(ulong x, ulong y) => overflow_add_helper(x, y);
macro ulong! ulong.overflow_sub(ulong x, ulong y) => overflow_sub_helper(x, y);
macro ulong! ulong.overflow_mul(ulong x, ulong y) => overflow_mul_helper(x, y);
macro ulong? ulong.overflow_add(ulong x, ulong y) => overflow_add_helper(x, y);
macro ulong? ulong.overflow_sub(ulong x, ulong y) => overflow_sub_helper(x, y);
macro ulong? ulong.overflow_mul(ulong x, ulong y) => overflow_mul_helper(x, y);
macro long long.sat_add(long x, long y) => $$sat_add(x, y);
macro long long.sat_sub(long x, long y) => $$sat_sub(x, y);
macro long long.sat_mul(long x, long y) => $$sat_mul(x, y);
macro long long.sat_shl(long x, long y) => $$sat_shl(x, y);
macro long! long.overflow_add(long x, long y) => overflow_add_helper(x, y);
macro long! long.overflow_sub(long x, long y) => overflow_sub_helper(x, y);
macro long! long.overflow_mul(long x, long y) => overflow_mul_helper(x, y);
macro long? long.overflow_add(long x, long y) => overflow_add_helper(x, y);
macro long? long.overflow_sub(long x, long y) => overflow_sub_helper(x, y);
macro long? long.overflow_mul(long x, long y) => overflow_mul_helper(x, y);
macro uint128 uint128.sat_add(uint128 x, uint128 y) => $$sat_add(x, y);
macro uint128 uint128.sat_sub(uint128 x, uint128 y) => $$sat_sub(x, y);
macro uint128 uint128.sat_mul(uint128 x, uint128 y) => $$sat_mul(x, y);
macro uint128 uint128.sat_shl(uint128 x, uint128 y) => $$sat_shl(x, y);
macro uint128! uint128.overflow_add(uint128 x, uint128 y) => overflow_add_helper(x, y);
macro uint128! uint128.overflow_sub(uint128 x, uint128 y) => overflow_sub_helper(x, y);
macro uint128! uint128.overflow_mul(uint128 x, uint128 y) => overflow_mul_helper(x, y);
macro uint128? uint128.overflow_add(uint128 x, uint128 y) => overflow_add_helper(x, y);
macro uint128? uint128.overflow_sub(uint128 x, uint128 y) => overflow_sub_helper(x, y);
macro uint128? uint128.overflow_mul(uint128 x, uint128 y) => overflow_mul_helper(x, y);
macro int128 int128.sat_add(int128 x, int128 y) => $$sat_add(x, y);
macro int128 int128.sat_sub(int128 x, int128 y) => $$sat_sub(x, y);
macro int128 int128.sat_mul(int128 x, int128 y) => $$sat_mul(x, y);
macro int128 int128.sat_shl(int128 x, int128 y) => $$sat_shl(x, y);
macro int128! int128.overflow_add(int128 x, int128 y) => overflow_add_helper(x, y);
macro int128! int128.overflow_sub(int128 x, int128 y) => overflow_sub_helper(x, y);
macro int128! int128.overflow_mul(int128 x, int128 y) => overflow_mul_helper(x, y);
macro int128? int128.overflow_add(int128 x, int128 y) => overflow_add_helper(x, y);
macro int128? int128.overflow_sub(int128 x, int128 y) => overflow_sub_helper(x, y);
macro int128? int128.overflow_mul(int128 x, int128 y) => overflow_mul_helper(x, y);
<*
@require values::@is_int(x) : `The input must be an integer`
*>
@@ -1137,21 +1129,21 @@ fn float _frexpf(float x, int* e)
macro overflow_add_helper(x, y) @local
{
$typeof(x) res @noinit;
if ($$overflow_add(x, y, &res)) return MathError.OVERFLOW?;
if ($$overflow_add(x, y, &res)) return OVERFLOW?;
return res;
}
macro overflow_sub_helper(x, y) @local
{
$typeof(x) res @noinit;
if ($$overflow_sub(x, y, &res)) return MathError.OVERFLOW?;
if ($$overflow_sub(x, y, &res)) return OVERFLOW?;
return res;
}
macro overflow_mul_helper(x, y) @local
{
$typeof(x) res @noinit;
if ($$overflow_mul(x, y, &res)) return MathError.OVERFLOW?;
if ($$overflow_mul(x, y, &res)) return OVERFLOW?;
return res;
}
@@ -1178,49 +1170,49 @@ macro bool @is_same_vector_or_scalar(#vector_value, #vector_or_scalar) @private
@require @is_same_vector_or_scalar(self, mul) : `mul must be a vector of the same type as self, or be an integer scalar`
@require @is_same_vector_or_scalar(self, div) : `div must be a vector of the same type as self, or be an integer scalar`
*>
macro char[<?>] char[<?>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);
macro char[<*>] char[<*>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);
<*
@require @is_same_vector_or_scalar(self, mul) : `mul must be a vector of the same type as self, or be an integer scalar`
@require @is_same_vector_or_scalar(self, div) : `div must be a vector of the same type as self, or be an integer scalar`
*>
macro ichar[<?>] ichar[<?>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);
macro ichar[<*>] ichar[<*>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);
<*
@require @is_same_vector_or_scalar(self, mul) : `mul must be a vector of the same type as self, or be an integer scalar`
@require @is_same_vector_or_scalar(self, div) : `div must be a vector of the same type as self, or be an integer scalar`
*>
macro short[<?>] short[<?>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);
macro short[<*>] short[<*>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);
<*
@require @is_same_vector_or_scalar(self, mul) : `mul must be a vector of the same type as self, or be an integer scalar`
@require @is_same_vector_or_scalar(self, div) : `div must be a vector of the same type as self, or be an integer scalar`
*>
macro ushort[<?>] ushort[<?>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);
macro ushort[<*>] ushort[<*>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);
<*
@require @is_same_vector_or_scalar(self, mul) : `mul must be a vector of the same type as self, or be an integer scalar`
@require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar`
*>
macro int[<?>] int[<?>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);
macro int[<*>] int[<*>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);
<*
@require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar`
@require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar`
*>
macro uint[<?>] uint[<?>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);
macro uint[<*>] uint[<*>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);
<*
@require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar`
@require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar`
*>
macro long[<?>] long[<?>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);
macro long[<*>] long[<*>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);
<*
@require @is_same_vector_or_scalar(self, mul) `mul must be a vector of the same type as self, or be an integer scalar`
@require @is_same_vector_or_scalar(self, div) `div must be a vector of the same type as self, or be an integer scalar`
*>
macro ulong[<?>] ulong[<?>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);
macro ulong[<*>] ulong[<*>].muldiv(self, mul, div) => mul_div_helper(self, mul, div);
<*
@require types::is_int($typeof(a)) `The input must be an integer`

View File

@@ -275,26 +275,26 @@ fn Matrix4x4 Matrix4x4.adjoint(&self)
}
fn Matrix2x2! Matrix2x2.inverse(&self)
fn Matrix2x2? Matrix2x2.inverse(&self)
{
Real det = self.determinant();
if (det == 0) return MatrixError.MATRIX_INVERSE_DOESNT_EXIST?;
if (det == 0) return math::MATRIX_INVERSE_DOESNT_EXIST?;
Matrix2x2 adj = self.adjoint();
return adj.component_mul(1 / det).transpose();
}
fn Matrix3x3! Matrix3x3.inverse(&self)
fn Matrix3x3? Matrix3x3.inverse(&self)
{
Real det = self.determinant();
if (det == 0) return MatrixError.MATRIX_INVERSE_DOESNT_EXIST?;
if (det == 0) return math::MATRIX_INVERSE_DOESNT_EXIST?;
Matrix3x3 adj = self.adjoint();
return adj.component_mul(1 / det).transpose();
}
fn Matrix4x4! Matrix4x4.inverse(&self)
fn Matrix4x4? Matrix4x4.inverse(&self)
{
Real det = self.determinant();
if (det == 0) return MatrixError.MATRIX_INVERSE_DOESNT_EXIST?;
if (det == 0) return math::MATRIX_INVERSE_DOESNT_EXIST?;
Matrix4x4 adj = self.adjoint();
return adj.component_mul(1 / det).transpose();
}

View File

@@ -11,7 +11,7 @@ module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
* ====================================================
*/
const double[?] TAN_T = {
const double[*] TAN_T = {
3.33333333333334091986e-01, /* 3FD55555, 55555563 */
1.33333333333201242699e-01, /* 3FC11111, 1110FE7A */
5.39682539762260521377e-02, /* 3FABA1BA, 1BB341FE */

View File

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

View File

@@ -12,21 +12,21 @@ module std::math::nolibc @if(env::NO_LIBC || $feature(C3_MATH));
* ====================================================
*/
const double[?] ATANHI @private = {
const double[*] ATANHI @private = {
4.63647609000806093515e-01, /* atan(0.5)hi 0x3FDDAC67, 0x0561BB4F */
7.85398163397448278999e-01, /* atan(1.0)hi 0x3FE921FB, 0x54442D18 */
9.82793723247329054082e-01, /* atan(1.5)hi 0x3FEF730B, 0xD281F69B */
1.57079632679489655800e+00, /* atan(inf)hi 0x3FF921FB, 0x54442D18 */
};
const double[?] ATANLO @private = {
const double[*] ATANLO @private = {
2.26987774529616870924e-17, /* atan(0.5)lo 0x3C7A2B7F, 0x222F65E2 */
3.06161699786838301793e-17, /* atan(1.0)lo 0x3C81A626, 0x33145C07 */
1.39033110312309984516e-17, /* atan(1.5)lo 0x3C700788, 0x7AF0CBBD */
6.12323399573676603587e-17, /* atan(inf)lo 0x3C91A626, 0x33145C07 */
};
const double[?] AT @private = {
const double[*] AT @private = {
3.33333333333329318027e-01, /* 0x3FD55555, 0x5555550D */
-1.99999999998764832476e-01, /* 0xBFC99999, 0x9998EBC4 */
1.42857142725034663711e-01, /* 0x3FC24924, 0x920083FF */
@@ -116,21 +116,21 @@ fn double _atan(double x) @weak @extern("atan") @nostrip
* ====================================================
*/
const float[?] ATANHIF @private = {
const float[*] ATANHIF @private = {
4.6364760399e-01, /* atan(0.5)hi 0x3eed6338 */
7.8539812565e-01, /* atan(1.0)hi 0x3f490fda */
9.8279368877e-01, /* atan(1.5)hi 0x3f7b985e */
1.5707962513e+00, /* atan(inf)hi 0x3fc90fda */
};
const float[?] ATANLOF @private = {
const float[*] ATANLOF @private = {
5.0121582440e-09, /* atan(0.5)lo 0x31ac3769 */
3.7748947079e-08, /* atan(1.0)lo 0x33222168 */
3.4473217170e-08, /* atan(1.5)lo 0x33140fb4 */
7.5497894159e-08, /* atan(inf)lo 0x33a22168 */
};
const float[?] ATF @private = {
const float[*] ATF @private = {
3.3333328366e-01,
-1.9999158382e-01,
1.4253635705e-01,

View File

@@ -94,9 +94,9 @@ fn int __rem_pio2f(float x, double *y)
* ====================================================
*/
const int[?] INIT_JK = {3,4,4,6}; /* initial value for jk */
const int[*] INIT_JK = {3,4,4,6}; /* initial value for jk */
const int[?] IPIO2 = {
const int[*] IPIO2 = {
0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62,
0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A,
0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129,
@@ -109,7 +109,7 @@ const int[?] IPIO2 = {
0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880,
0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B, };
const double[?] PIO2 = {
const double[*] PIO2 = {
1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */
7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */
5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */

View File

@@ -25,7 +25,7 @@ fn Uuid generate_from_random(Random random)
return uuid;
}
fn usz! Uuid.to_format(&self, Formatter* formatter) @dynamic
fn usz? Uuid.to_format(&self, Formatter* formatter) @dynamic
{
return formatter.printf("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
(*self)[0], (*self)[1], (*self)[2], (*self)[3],

View File

@@ -55,7 +55,7 @@ struct HttpInternal @private
void* data;
}
fn String! parse_url(String url, String* port, String* resource) @private
fn String? parse_url(String url, String* port, String* resource) @private
{
if (url[:7] != "http://") return NetError.INVALID_URL?;
url = url[7..];
@@ -85,7 +85,7 @@ fn String! parse_url(String url, String* port, String* resource) @private
return address;
}
fn Socket! http_internal_connect(String address, uint port) @private
fn Socket? http_internal_connect(String address, uint port) @private
{
return tcp::connect_async(address, port)!;
}
@@ -108,7 +108,7 @@ fn HttpInternal* http_internal_create(usz request_data_size, Allocator allocator
return internal;
}
fn Http*! http_get(String url, Allocator allocator = allocator::temp())
fn Http*? http_get(String url, Allocator allocator = allocator::temp())
{
$if env::WIN32:
int[1024] wsa_data;
@@ -139,7 +139,7 @@ $endif
return internal;
}
fn Http*! http_post(String url, Allocator allocator = allocator::temp())
fn Http*? http_post(String url, Allocator allocator = allocator::temp())
{
$if env::OS_TYPE == OsType::WIN32:
int[1024] wsa_data;

View File

@@ -45,7 +45,7 @@ struct InetAddress (Printable)
}
fn usz! InetAddress.to_format(InetAddress* addr, Formatter* formatter) @dynamic
fn usz? InetAddress.to_format(InetAddress* addr, Formatter* formatter) @dynamic
{
if (addr.is_ipv6)
{
@@ -66,14 +66,14 @@ fn String InetAddress.to_tstring(&self)
return string::format(tmem(), "%s", *self);
}
fn InetAddress! ipv6_from_str(String s)
fn InetAddress? ipv6_from_str(String s)
{
uint sections = 0;
if (s.len < 2) return NetError.INVALID_IP_STRING?;
if (s.len < 2) return INVALID_IP_STRING?;
foreach (c : s) if (c == ':') sections++;
int zero_segment_len = s[0] == ':' || s[^1] == ':' ? 9 - sections : 8 - sections;
if (zero_segment_len == 7 && s.len == 2) return { .is_ipv6 = true };
if (zero_segment_len > 7) return NetError.INVALID_IP_STRING?;
if (zero_segment_len > 7) return INVALID_IP_STRING?;
usz index = 0;
bool last_was_colon, found_zero;
int current = -1;
@@ -89,7 +89,7 @@ fn InetAddress! ipv6_from_str(String s)
last_was_colon = true;
continue;
}
if (current < 0 || current > 65535) return NetError.INVALID_IP_STRING?;
if (current < 0 || current > 65535) return INVALID_IP_STRING?;
addr.ipv6arr[index++].val = (ushort)current;
current = -1;
last_was_colon = true;
@@ -97,9 +97,9 @@ fn InetAddress! ipv6_from_str(String s)
}
assert(current == -1);
// Check that this is the first ::
if (found_zero) return NetError.INVALID_IP_STRING?;
if (found_zero) return INVALID_IP_STRING?;
// Also check that the zeroed section is at least 2
if (zero_segment_len < 2) return NetError.INVALID_IP_STRING?;
if (zero_segment_len < 2) return INVALID_IP_STRING?;
// Skip (will be zero by default
index += zero_segment_len;
found_zero = true;
@@ -107,7 +107,7 @@ fn InetAddress! ipv6_from_str(String s)
continue;
}
last_was_colon = false;
if (index > 7 || !c.is_xdigit()) return NetError.INVALID_IP_STRING?;
if (index > 7 || !c.is_xdigit()) return INVALID_IP_STRING?;
if (current < 0) current = 0;
current = current * 16 + (c <= '9' ? c - '0' : (c | 32) - 'a' + 10);
}
@@ -115,12 +115,12 @@ fn InetAddress! ipv6_from_str(String s)
if (index == 8 && current == -1) return addr;
// Ends with number
if (index != 7 || current < 0 || current > 65535) return NetError.INVALID_IP_STRING?;
if (index != 7 || current < 0 || current > 65535) return INVALID_IP_STRING?;
addr.ipv6arr[7].val = (ushort)current;
return addr;
}
fn InetAddress! ipv4_from_str(String s)
fn InetAddress? ipv4_from_str(String s)
{
InetAddress addr;
int element;
@@ -129,20 +129,20 @@ fn InetAddress! ipv4_from_str(String s)
{
if (c == '.')
{
if (current < 0) return NetError.INVALID_IP_STRING?;
if (current > 255) return NetError.INVALID_IP_STRING?;
if (current < 0) return INVALID_IP_STRING?;
if (current > 255) return INVALID_IP_STRING?;
switch (element)
{
case 0: addr.ipv4.a = (char)current;
case 1: addr.ipv4.b = (char)current;
case 2: addr.ipv4.c = (char)current;
default: return NetError.INVALID_IP_STRING?;
default: return INVALID_IP_STRING?;
}
current = -1;
element++;
continue;
}
if (element > 3 || c < '0' || c > '9') return NetError.INVALID_IP_STRING?;
if (element > 3 || c < '0' || c > '9') return INVALID_IP_STRING?;
if (current < 0)
{
current = c - '0';
@@ -150,7 +150,7 @@ fn InetAddress! ipv4_from_str(String s)
}
current = current * 10 + c - '0';
}
if (element != 3 || current < 0 || current > 255) return NetError.INVALID_IP_STRING?;
if (element != 3 || current < 0 || current > 255) return INVALID_IP_STRING?;
addr.ipv4.d = (char)current;
return addr;
}
@@ -252,13 +252,13 @@ fn bool InetAddress.is_multicast_link_local(InetAddress* addr)
return addr.ipv4.a == 224 && addr.ipv4.b == 0 && addr.ipv4.c == 0;
}
fn AddrInfo*! addrinfo(String host, uint port, AIFamily ai_family, AISockType ai_socktype) @if(os::SUPPORTS_INET) => @pool()
fn AddrInfo*? addrinfo(String host, uint port, AIFamily ai_family, AISockType ai_socktype) @if(os::SUPPORTS_INET) => @pool()
{
ZString zhost = host.zstr_tcopy();
DString str = dstring::temp_with_capacity(32);
str.appendf("%d", port);
AddrInfo hints = { .ai_family = ai_family, .ai_socktype = ai_socktype };
AddrInfo* ai;
if (os::getaddrinfo(zhost, str.zstr_view(), &hints, &ai)) return NetError.ADDRINFO_FAILED?;
if (os::getaddrinfo(zhost, str.zstr_view(), &hints, &ai)) return ADDRINFO_FAILED?;
return ai;
}

View File

@@ -1,8 +1,7 @@
module std::net;
import std::io;
fault NetError
{
fault
INVALID_URL,
URL_TOO_LONG,
INVALID_SOCKET,
@@ -27,10 +26,9 @@ fault NetError
ALREADY_CONNECTED,
NETWORK_UNREACHABLE,
OPERATION_NOT_SUPPORTED_ON_SOCKET,
CONNECTION_RESET,
}
CONNECTION_RESET;
fn uint! ipv4toint(String s)
fn uint? ipv4toint(String s)
{
uint out;
int element;
@@ -39,13 +37,13 @@ fn uint! ipv4toint(String s)
{
if (c == '.')
{
if (current < 0) return NetError.INVALID_IP_STRING?;
if (current < 0) return INVALID_IP_STRING?;
out = out << 8 + current;
current = -1;
element++;
continue;
}
if (element > 3 || c < '0' || c > '9') return NetError.INVALID_IP_STRING?;
if (element > 3 || c < '0' || c > '9') return INVALID_IP_STRING?;
if (current < 0)
{
current = c - '0';
@@ -53,12 +51,12 @@ fn uint! ipv4toint(String s)
}
current = current * 10 + c - '0';
}
if (element != 3 || current < 0) return NetError.INVALID_IP_STRING?;
if (element != 3 || current < 0) return INVALID_IP_STRING?;
out = out << 8 + current;
return out;
}
fn String! int_to_ipv4(uint val, Allocator allocator)
fn String? int_to_ipv4(uint val, Allocator allocator)
{
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)!;

View File

@@ -34,20 +34,20 @@ fn anyfault convert_error(Errno error)
{
switch (error)
{
case errno::EACCES: return IoError.NO_PERMISSION;
case errno::EADDRINUSE: return NetError.ADDRESS_IN_USE;
case errno::EALREADY: return NetError.CONNECTION_ALREADY_IN_PROGRESS;
case errno::EBADF: return NetError.BAD_SOCKET_DESCRIPTOR;
case errno::ECONNREFUSED: return NetError.CONNECTION_REFUSED;
case errno::ECONNRESET: return NetError.CONNECTION_RESET;
case errno::EISCONN: return NetError.ALREADY_CONNECTED;
case errno::ENETUNREACH: return NetError.NETWORK_UNREACHABLE;
case errno::ENOTSOCK: return NetError.NOT_A_SOCKET;
case errno::EINTR: return IoError.INTERRUPTED;
case errno::EWOULDBLOCK: return IoError.WOULD_BLOCK;
case errno::EOPNOTSUPP: return NetError.OPERATION_NOT_SUPPORTED_ON_SOCKET;
case errno::ETIMEDOUT: return NetError.CONNECTION_TIMED_OUT;
default: return IoError.GENERAL_ERROR;
case errno::EACCES: return io::NO_PERMISSION;
case errno::EADDRINUSE: return net::ADDRESS_IN_USE;
case errno::EALREADY: return net::CONNECTION_ALREADY_IN_PROGRESS;
case errno::EBADF: return net::BAD_SOCKET_DESCRIPTOR;
case errno::ECONNREFUSED: return net::CONNECTION_REFUSED;
case errno::ECONNRESET: return net::CONNECTION_RESET;
case errno::EISCONN: return net::ALREADY_CONNECTED;
case errno::ENETUNREACH: return net::NETWORK_UNREACHABLE;
case errno::ENOTSOCK: return net::NOT_A_SOCKET;
case errno::EINTR: return io::INTERRUPTED;
case errno::EWOULDBLOCK: return io::WOULD_BLOCK;
case errno::EOPNOTSUPP: return net::OPERATION_NOT_SUPPORTED_ON_SOCKET;
case errno::ETIMEDOUT: return net::CONNECTION_TIMED_OUT;
default: return io::GENERAL_ERROR;
}
}
@@ -61,16 +61,16 @@ macro bool NativeSocket.is_valid(self)
return (iptr)self >= 0;
}
macro void! NativeSocket.close(self)
macro void? NativeSocket.close(self)
{
if (libc::close(self))
{
if (libc::errno() == errno::EBADF) return NetError.INVALID_SOCKET?;
return NetError.GENERAL_ERROR?;
if (libc::errno() == errno::EBADF) return net::INVALID_SOCKET?;
return net::GENERAL_ERROR?;
}
}
macro void! NativeSocket.set_non_blocking(self, bool non_blocking)
macro void? NativeSocket.set_non_blocking(self, bool non_blocking)
{
int flags = fcntl(self, F_GETFL, 0);
if (non_blocking)
@@ -85,8 +85,8 @@ macro void! NativeSocket.set_non_blocking(self, bool non_blocking)
}
if (fcntl(self, F_SETFL, flags) == -1)
{
if (libc::errno() == errno::EBADF) return NetError.INVALID_SOCKET?;
return NetError.GENERAL_ERROR?;
if (libc::errno() == errno::EBADF) return net::INVALID_SOCKET?;
return net::GENERAL_ERROR?;
}
}

View File

@@ -27,7 +27,7 @@ macro bool NativeSocket.is_valid(self)
return self != (NativeSocket)(uptr)-1;
}
fn void! NativeSocket.set_non_blocking(self, bool non_blocking)
fn void? NativeSocket.set_non_blocking(self, bool non_blocking)
{
if (ioctlsocket(self, win32::FIONBIO, &&(CULong)non_blocking))
{
@@ -35,7 +35,7 @@ fn void! NativeSocket.set_non_blocking(self, bool non_blocking)
}
}
macro void! NativeSocket.close(self)
macro void? NativeSocket.close(self)
{
WSAError error = closesocket(self);
if (error) return convert_error(error)?;
@@ -65,24 +65,24 @@ fn anyfault convert_error(WSAError error)
{
switch (error)
{
case wsa::NOTINITIALISED: return NetError.SOCKETS_NOT_INITIALIZED;
case wsa::ENETDOWN: return NetError.NETWORK_UNREACHABLE;
case wsa::INVALID_HANDLE: return NetError.BAD_SOCKET_DESCRIPTOR;
case wsa::EACCESS: return IoError.NO_PERMISSION;
case wsa::EINPROGRESS: return NetError.STILL_PROCESSING_CALLBACK;
case wsa::EADDRINUSE: return NetError.ADDRESS_IN_USE;
case wsa::EALREADY: return NetError.CONNECTION_ALREADY_IN_PROGRESS;
case wsa::EBADF: return NetError.BAD_SOCKET_DESCRIPTOR;
case wsa::EINTR: return IoError.INTERRUPTED;
case wsa::EWOULDBLOCK: return IoError.WOULD_BLOCK;
case wsa::ECONNREFUSED: return NetError.CONNECTION_REFUSED;
case wsa::EISCONN: return NetError.ALREADY_CONNECTED;
case wsa::ENETUNREACH: return NetError.NETWORK_UNREACHABLE;
case wsa::ENOTSOCK: return NetError.NOT_A_SOCKET;
case wsa::EOPNOTSUPP: return NetError.OPERATION_NOT_SUPPORTED_ON_SOCKET;
case wsa::ETIMEDOUT: return NetError.CONNECTION_TIMED_OUT;
case wsa::ECONNRESET: return NetError.CONNECTION_RESET;
default: return IoError.GENERAL_ERROR;
case wsa::NOTINITIALISED: return net::SOCKETS_NOT_INITIALIZED;
case wsa::ENETDOWN: return net::NETWORK_UNREACHABLE;
case wsa::INVALID_HANDLE: return net::BAD_SOCKET_DESCRIPTOR;
case wsa::EACCESS: return io::NO_PERMISSION;
case wsa::EINPROGRESS: return net::STILL_PROCESSING_CALLBACK;
case wsa::EADDRINUSE: return net::ADDRESS_IN_USE;
case wsa::EALREADY: return net::CONNECTION_ALREADY_IN_PROGRESS;
case wsa::EBADF: return net::BAD_SOCKET_DESCRIPTOR;
case wsa::EINTR: return io::INTERRUPTED;
case wsa::EWOULDBLOCK: return io::WOULD_BLOCK;
case wsa::ECONNREFUSED: return net::CONNECTION_REFUSED;
case wsa::EISCONN: return net::ALREADY_CONNECTED;
case wsa::ENETUNREACH: return net::NETWORK_UNREACHABLE;
case wsa::ENOTSOCK: return net::NOT_A_SOCKET;
case wsa::EOPNOTSUPP: return net::OPERATION_NOT_SUPPORTED_ON_SOCKET;
case wsa::ETIMEDOUT: return net::CONNECTION_TIMED_OUT;
case wsa::ECONNRESET: return net::CONNECTION_RESET;
default: return io::GENERAL_ERROR;
}
}

View File

@@ -56,7 +56,7 @@ struct Poll
@param [inout] polls
@param timeout : "duration to poll (clamped to CInt.max ms), or POLL_FOREVER."
*>
fn ulong! poll(Poll[] polls, Duration timeout)
fn ulong? poll(Poll[] polls, Duration timeout)
{
return poll_ms(polls, timeout == POLL_FOREVER ? -1 : timeout.to_ms()) @inline;
}
@@ -65,7 +65,7 @@ fn ulong! poll(Poll[] polls, Duration timeout)
@param [inout] polls
@param timeout_ms : "duration to poll in ms or -1. Clamped to CInt.max"
*>
fn ulong! poll_ms(Poll[] polls, long timeout_ms)
fn ulong? poll_ms(Poll[] polls, long timeout_ms)
{
if (timeout_ms > CInt.max) timeout_ms = CInt.max;
$if env::WIN32:
@@ -94,34 +94,34 @@ enum SocketOption : char (CInt value)
DONTROUTE = os::SO_DONTROUTE,
}
fn bool! Socket.get_broadcast(&self) => self.get_option(BROADCAST);
fn bool! Socket.get_keepalive(&self) => self.get_option(KEEPALIVE);
fn bool! Socket.get_reuseaddr(&self) => self.get_option(REUSEADDR);
fn bool! Socket.get_dontroute(&self) => self.get_option(DONTROUTE);
fn bool! Socket.get_oobinline(&self) => self.get_option(OOBINLINE);
fn bool? Socket.get_broadcast(&self) => self.get_option(BROADCAST);
fn bool? Socket.get_keepalive(&self) => self.get_option(KEEPALIVE);
fn bool? Socket.get_reuseaddr(&self) => self.get_option(REUSEADDR);
fn bool? Socket.get_dontroute(&self) => self.get_option(DONTROUTE);
fn bool? Socket.get_oobinline(&self) => self.get_option(OOBINLINE);
fn void! Socket.set_broadcast(&self, bool value) => self.set_option(BROADCAST, value);
fn void! Socket.set_keepalive(&self, bool value) => self.set_option(KEEPALIVE, value);
fn void! Socket.set_reuseaddr(&self, bool value) => self.set_option(REUSEADDR, value);
fn void! Socket.set_dontroute(&self, bool value) => self.set_option(DONTROUTE, value);
fn void! Socket.set_oobinline(&self, bool value) => self.set_option(OOBINLINE, value);
fn void? Socket.set_broadcast(&self, bool value) => self.set_option(BROADCAST, value);
fn void? Socket.set_keepalive(&self, bool value) => self.set_option(KEEPALIVE, value);
fn void? Socket.set_reuseaddr(&self, bool value) => self.set_option(REUSEADDR, value);
fn void? Socket.set_dontroute(&self, bool value) => self.set_option(DONTROUTE, value);
fn void? Socket.set_oobinline(&self, bool value) => self.set_option(OOBINLINE, value);
fn void! Socket.set_option(&self, SocketOption option, bool value)
fn void? Socket.set_option(&self, SocketOption option, bool value)
{
CInt flag = (CInt)value;
int errcode = os::setsockopt(self.sock, os::SOL_SOCKET, option.value, &flag, CInt.sizeof);
if (errcode != 0) return NetError.SOCKOPT_FAILED?;
if (errcode != 0) return SOCKOPT_FAILED?;
}
fn bool! Socket.get_option(&self, SocketOption option)
fn bool? Socket.get_option(&self, SocketOption option)
{
CInt flag;
int errcode = os::setsockopt(self.sock, os::SOL_SOCKET, option.value, &flag, CInt.sizeof);
if (errcode != 0) return NetError.SOCKOPT_FAILED?;
if (errcode != 0) return SOCKOPT_FAILED?;
return (bool)flag;
}
fn usz! Socket.read(&self, char[] bytes) @dynamic
fn usz? Socket.read(&self, char[] bytes) @dynamic
{
$if env::WIN32:
isz n = libc::recv(self.sock, bytes.ptr, (int)bytes.len, 0);
@@ -132,9 +132,9 @@ $endif
return (usz)n;
}
fn char! Socket.read_byte(&self) @dynamic => io::read_byte_using_read(self);
fn char? Socket.read_byte(&self) @dynamic => io::read_byte_using_read(self);
fn usz! Socket.write(&self, char[] bytes) @dynamic
fn usz? Socket.write(&self, char[] bytes) @dynamic
{
$if env::WIN32:
isz n = libc::send(self.sock, bytes.ptr, (int)bytes.len, 0);
@@ -145,18 +145,18 @@ $endif
return (usz)n;
}
fn void! Socket.write_byte(&self, char byte) @dynamic => io::write_byte_using_write(self, byte);
fn void? Socket.write_byte(&self, char byte) @dynamic => io::write_byte_using_write(self, byte);
fn void! Socket.destroy(&self) @dynamic
fn void? Socket.destroy(&self) @dynamic
{
self.close()!;
}
fn void! Socket.close(&self) @inline @dynamic
fn void? Socket.close(&self) @inline @dynamic
{
self.sock.close()!;
}
fn usz! Socket.peek(&self, char[] bytes) @dynamic
fn usz? Socket.peek(&self, char[] bytes) @dynamic
{
$if env::WIN32:
isz n = libc::recv(self.sock, bytes.ptr, (int)bytes.len, os::MSG_PEEK);
@@ -174,7 +174,7 @@ enum SocketShutdownHow : (inline CInt native_value)
BOTH = @select(env::WIN32, libc::SD_BOTH, libc::SHUT_RDWR),
}
fn void! Socket.shutdown(&self, SocketShutdownHow how)
fn void? Socket.shutdown(&self, SocketShutdownHow how)
{
if (libc::shutdown(self.sock, how) < 0)
{

View File

@@ -7,7 +7,7 @@ macro apply_sockoptions(sockfd, options) @private
foreach (o : options) sock.set_option(o, true)!;
}
fn Socket! connect_from_addrinfo(AddrInfo* addrinfo, SocketOption[] options) @private
fn Socket? connect_from_addrinfo(AddrInfo* addrinfo, SocketOption[] options) @private
{
@loop_over_ai(addrinfo; NativeSocket sockfd, AddrInfo* ai)
{
@@ -35,7 +35,7 @@ fn bool last_error_is_delayed_connect()
$endswitch
}
fn Socket! connect_with_timeout_from_addrinfo(AddrInfo* addrinfo, SocketOption[] options, Duration timeout) @private
fn Socket? connect_with_timeout_from_addrinfo(AddrInfo* addrinfo, SocketOption[] options, Duration timeout) @private
{
Clock c = 0;
@loop_over_ai(addrinfo; NativeSocket sockfd, AddrInfo* ai)
@@ -57,7 +57,7 @@ fn Socket! connect_with_timeout_from_addrinfo(AddrInfo* addrinfo, SocketOption[]
Duration to_remove = c.to_now().to_duration();
if (to_remove >= timeout_left)
{
return NetError.CONNECTION_TIMED_OUT?;
return CONNECTION_TIMED_OUT?;
}
timeout_left -= to_remove;
}
@@ -68,7 +68,7 @@ fn Socket! connect_with_timeout_from_addrinfo(AddrInfo* addrinfo, SocketOption[]
Poll poll_request = { sockfd, SUBSCRIBE_ANY_WRITE, 0 };
if (!poll((&poll_request)[:1], timeout_left)!)
{
return NetError.CONNECTION_TIMED_OUT?;
return CONNECTION_TIMED_OUT?;
}
if (poll_request.revents & POLL_EVENT_WRITE)
{
@@ -80,7 +80,7 @@ fn Socket! connect_with_timeout_from_addrinfo(AddrInfo* addrinfo, SocketOption[]
return os::socket_error()?;
}
fn Socket! connect_async_from_addrinfo(AddrInfo* addrinfo, SocketOption[] options) @private
fn Socket? connect_async_from_addrinfo(AddrInfo* addrinfo, SocketOption[] options) @private
{
@loop_over_ai(addrinfo; NativeSocket sockfd, AddrInfo* ai)
{

View File

@@ -5,7 +5,7 @@ import std::time, libc;
distinct TcpSocket = inline Socket;
distinct TcpServerSocket = inline Socket;
fn TcpSocket! connect(String host, uint port, Duration timeout = 0, SocketOption... options, IpProtocol ip_protocol = UNSPECIFIED)
fn TcpSocket? connect(String host, uint port, Duration timeout = 0, SocketOption... options, IpProtocol ip_protocol = UNSPECIFIED)
{
AddrInfo* ai = net::addrinfo(host, port, ip_protocol.ai_family, os::SOCK_STREAM)!;
defer os::freeaddrinfo(ai);
@@ -16,40 +16,40 @@ fn TcpSocket! connect(String host, uint port, Duration timeout = 0, SocketOption
return connect_to(ai, ...options);
}
fn TcpSocket! connect_async(String host, uint port, SocketOption... options, IpProtocol ip_protocol = UNSPECIFIED)
fn TcpSocket? connect_async(String host, uint port, SocketOption... options, IpProtocol ip_protocol = UNSPECIFIED)
{
AddrInfo* ai = net::addrinfo(host, port, ip_protocol.ai_family, os::SOCK_STREAM)!;
defer os::freeaddrinfo(ai);
return connect_async_to(ai, ...options);
}
fn TcpSocket! connect_to(AddrInfo* ai, SocketOption... options)
fn TcpSocket? connect_to(AddrInfo* ai, SocketOption... options)
{
return (TcpSocket)net::connect_from_addrinfo(ai, options);
}
fn TcpSocket! connect_async_to(AddrInfo* ai, SocketOption... options)
fn TcpSocket? connect_async_to(AddrInfo* ai, SocketOption... options)
{
return (TcpSocket)net::connect_async_from_addrinfo(ai, options);
}
fn TcpServerSocket! listen(String host, uint port, uint backlog, SocketOption... options, IpProtocol ip_protocol = UNSPECIFIED)
fn TcpServerSocket? listen(String host, uint port, uint backlog, SocketOption... options, IpProtocol ip_protocol = UNSPECIFIED)
{
AddrInfo* ai = net::addrinfo(host, port, ip_protocol.ai_family, os::SOCK_STREAM)!;
defer os::freeaddrinfo(ai);
return listen_to(ai, backlog, ...options);
}
fn TcpSocket! accept(TcpServerSocket* server_socket)
fn TcpSocket? accept(TcpServerSocket* server_socket)
{
TcpSocket socket;
socket.ai_addrlen = socket.ai_addr_storage.len;
socket.sock = os::accept(server_socket.sock, (SockAddrPtr)&socket.ai_addr_storage, &socket.ai_addrlen);
if (!socket.sock.is_valid()) return NetError.ACCEPT_FAILED?;
if (!socket.sock.is_valid()) return net::ACCEPT_FAILED?;
return socket;
}
fn TcpServerSocket! listen_to(AddrInfo* ai, uint backlog, SocketOption... options)
fn TcpServerSocket? listen_to(AddrInfo* ai, uint backlog, SocketOption... options)
{
net::@loop_over_ai(ai; NativeSocket sockfd, AddrInfo* ai_candidate)
{

View File

@@ -3,26 +3,26 @@ import std::net @public;
distinct UdpSocket = inline Socket;
fn UdpSocket! connect(String host, uint port, SocketOption... options, IpProtocol ip_protocol = UNSPECIFIED)
fn UdpSocket? connect(String host, uint port, SocketOption... options, IpProtocol ip_protocol = UNSPECIFIED)
{
AddrInfo* ai = net::addrinfo(host, port, ip_protocol.ai_family, os::SOCK_DGRAM)!;
defer os::freeaddrinfo(ai);
return connect_to(ai, ...options);
}
fn UdpSocket! connect_to(AddrInfo* ai, SocketOption... options)
fn UdpSocket? connect_to(AddrInfo* ai, SocketOption... options)
{
return (UdpSocket)net::connect_from_addrinfo(ai, options);
}
fn UdpSocket! connect_async(String host, uint port, SocketOption... options, IpProtocol ip_protocol = UNSPECIFIED)
fn UdpSocket? connect_async(String host, uint port, SocketOption... options, IpProtocol ip_protocol = UNSPECIFIED)
{
AddrInfo* ai = net::addrinfo(host, port, ip_protocol.ai_family, os::SOCK_DGRAM)!;
defer os::freeaddrinfo(ai);
return connect_async_to(ai, ...options);
}
fn UdpSocket! connect_async_to(AddrInfo* ai, SocketOption... options)
fn UdpSocket? connect_async_to(AddrInfo* ai, SocketOption... options)
{
return (UdpSocket)net::connect_async_from_addrinfo(ai, options);
}

View File

@@ -2,16 +2,14 @@ module std::net::url;
import std::io, std::collections::map, std::collections::list;
fault UrlParsingResult
{
fault
EMPTY,
INVALID_SCHEME,
INVALID_USER,
INVALID_PASSWORD,
INVALID_HOST,
INVALID_PATH,
INVALID_FRAGMENT,
}
INVALID_FRAGMENT;
<*
Represents the actual (decoded) Url.
@@ -49,7 +47,7 @@ struct Url(Printable)
@require url_string.len > 0 : "the url_string must be len 1 or more"
@return "the parsed Url"
*>
fn Url! tparse(String url_string) => parse(tmem(), url_string);
fn Url? tparse(String url_string) => parse(tmem(), url_string);
<*
Parse a URL string into a Url struct.
@@ -58,25 +56,25 @@ fn Url! tparse(String url_string) => parse(tmem(), url_string);
@require url_string.len > 0 : "the url_string must be len 1 or more"
@return "the parsed Url"
*>
fn Url! parse(Allocator allocator, String url_string)
fn Url? parse(Allocator allocator, String url_string)
{
url_string = url_string.trim();
if (!url_string) return UrlParsingResult.EMPTY?;
if (!url_string) return EMPTY?;
Url url = { .allocator = allocator };
// Parse scheme
if (try pos = url_string.index_of("://"))
{
if (!pos) return UrlParsingResult.INVALID_SCHEME?;
if (!pos) return INVALID_SCHEME?;
url.scheme = url_string[:pos].copy(allocator);
url_string = url_string[url.scheme.len + 3 ..];
}
else if (try pos = url_string.index_of(":"))
{
// Handle schemes without authority like 'mailto:'
if (!pos) return UrlParsingResult.INVALID_SCHEME?;
if (!pos) return INVALID_SCHEME?;
url.scheme = url_string[:pos].copy(allocator);
url.path = decode(allocator, url_string[pos + 1 ..], PATH) ?? UrlParsingResult.INVALID_PATH?!;
url.path = decode(allocator, url_string[pos + 1 ..], PATH) ?? INVALID_PATH?!;
return url;
}
@@ -95,11 +93,11 @@ fn Url! parse(Allocator allocator, String url_string)
{
String[] userpass = userinfo.tsplit(":", 2);
username = userpass[0];
if (!username.len) return UrlParsingResult.INVALID_USER?;
if (!username.len) return INVALID_USER?;
url.host =
url.username = decode(allocator, username, HOST) ?? UrlParsingResult.INVALID_USER?!;
if (userpass.len) url.password = decode(allocator, userpass[1], USERPASS) ?? UrlParsingResult.INVALID_PASSWORD?!;
url.username = decode(allocator, username, HOST) ?? INVALID_USER?!;
if (userpass.len) url.password = decode(allocator, userpass[1], USERPASS) ?? INVALID_PASSWORD?!;
};
authority = authority[userinfo.len + 1 ..];
}
@@ -131,23 +129,23 @@ fn Url! parse(Allocator allocator, String url_string)
}
};
}
url.host = decode(allocator, host, HOST) ?? UrlParsingResult.INVALID_HOST?!;
url.host = decode(allocator, host, HOST) ?? INVALID_HOST?!;
url_string = url_string[authority_end ..];
}
// Parse path
usz! query_index = url_string.index_of_char('?');
usz! fragment_index = url_string.index_of_char('#');
usz? query_index = url_string.index_of_char('?');
usz? fragment_index = url_string.index_of_char('#');
if (@ok(query_index) || @ok(fragment_index))
{
usz path_end = min(query_index ?? url_string.len, fragment_index ?? url_string.len);
url.path = decode(allocator, url_string[:path_end], PATH) ?? UrlParsingResult.INVALID_PATH?!;
url.path = decode(allocator, url_string[:path_end], PATH) ?? INVALID_PATH?!;
url_string = url_string[path_end ..];
}
else
{
url.path = decode(allocator, url_string, PATH) ?? UrlParsingResult.INVALID_PATH?!;
url.path = decode(allocator, url_string, PATH) ?? INVALID_PATH?!;
url_string = "";
}
@@ -165,12 +163,12 @@ fn Url! parse(Allocator allocator, String url_string)
// Parse fragment
if (url_string.starts_with("#"))
{
url.fragment = decode(allocator, url_string[1..], FRAGMENT) ?? UrlParsingResult.INVALID_FRAGMENT?!;
url.fragment = decode(allocator, url_string[1..], FRAGMENT) ?? INVALID_FRAGMENT?!;
}
return url;
}
fn usz! Url.to_format(&self, Formatter* f) @dynamic
fn usz? Url.to_format(&self, Formatter* f) @dynamic
{
usz len;
// Add scheme if it exists
@@ -310,7 +308,7 @@ fn UrlQueryValues* UrlQueryValues.add(&self, String key, String value)
fn usz! UrlQueryValues.to_format(&self, Formatter* f) @dynamic
fn usz? UrlQueryValues.to_format(&self, Formatter* f) @dynamic
{
usz len;
usz i;
@@ -319,7 +317,7 @@ fn usz! UrlQueryValues.to_format(&self, Formatter* f) @dynamic
@stack_mem(128; Allocator mem)
{
String encoded_key = encode(mem, key, QUERY);
UrlQueryValueList! values = self.map.get(key);
UrlQueryValueList? values = self.map.get(key);
if (catch values) continue;
foreach (value : values)
{

View File

@@ -15,10 +15,7 @@ enum UrlEncodingMode : char (String allowed)
FRAGMENT = "$&+,/:;=?@!()*", // section 4.1
}
fault UrlDecodingError
{
INVALID_HEX
}
fault INVALID_HEX;
<*
Returns true if char c should be encoded according to RFC 3986.
@@ -108,9 +105,9 @@ fn String tencode(String s, UrlEncodingMode mode) => encode(tmem(), s, mode);
<*
Calculate the length of the percent-decoded string.
@return! UrlDecodingError.INVALID_HEX
@return! INVALID_HEX
*>
fn usz! decode_len(String s, UrlEncodingMode mode) @inline
fn usz? decode_len(String s, UrlEncodingMode mode) @inline
{
usz n;
foreach (i, c: s)
@@ -118,7 +115,7 @@ fn usz! decode_len(String s, UrlEncodingMode mode) @inline
if (c != '%') continue;
if (i + 2 >= s.len || !s[i+1].is_xdigit() || !s[i+2].is_xdigit())
{
return UrlDecodingError.INVALID_HEX?;
return INVALID_HEX?;
}
n++;
}
@@ -134,7 +131,7 @@ fn usz! decode_len(String s, UrlEncodingMode mode) @inline
@param [inout] allocator
@return "Percent-decoded String"
*>
fn String! decode(Allocator allocator, String s, UrlEncodingMode mode) => @pool(allocator)
fn String? decode(Allocator allocator, String s, UrlEncodingMode mode) => @pool(allocator)
{
usz n = decode_len(s, mode)!;
DString builder = dstring::temp_with_capacity(n);
@@ -170,4 +167,4 @@ fn String! decode(Allocator allocator, String s, UrlEncodingMode mode) => @pool
@param mode : "Url encoding mode"
@return "Percent-decoded String"
*>
fn String! tdecode(String s, UrlEncodingMode mode) => decode(tmem(), s, mode);
fn String? tdecode(String s, UrlEncodingMode mode) => decode(tmem(), s, mode);

View File

@@ -1,14 +1,7 @@
module std::os::backtrace;
import std::collections::list, std::os, std::io;
fault BacktraceFault
{
SEGMENT_NOT_FOUND,
EXECUTABLE_PATH_NOT_FOUND,
IMAGE_NOT_FOUND,
NO_BACKTRACE_SYMBOLS,
RESOLUTION_FAILED,
}
fault SEGMENT_NOT_FOUND, EXECUTABLE_PATH_NOT_FOUND, IMAGE_NOT_FOUND, NO_BACKTRACE_SYMBOLS, RESOLUTION_FAILED;
const Backtrace BACKTRACE_UNKNOWN = { 0, "", "", "", 0, null, false };
@@ -34,7 +27,7 @@ fn bool Backtrace.is_unknown(&self)
return !self.object_file.len;
}
fn usz! Backtrace.to_format(&self, Formatter* formatter) @dynamic
fn usz? Backtrace.to_format(&self, Formatter* formatter) @dynamic
{
String inline_suffix = self.is_inline ? " [inline]" : "";
if (self.has_file())
@@ -97,7 +90,7 @@ def symbolize_backtrace = linux::symbolize_backtrace @if(env::LINUX);
def symbolize_backtrace = win32::symbolize_backtrace @if(env::WIN32);
def symbolize_backtrace = darwin::symbolize_backtrace @if(env::DARWIN);
fn BacktraceList! symbolize_backtrace(Allocator allocator, void*[] backtrace) @if(!env::NATIVE_STACKTRACE)
fn BacktraceList? symbolize_backtrace(Allocator allocator, void*[] backtrace) @if(!env::NATIVE_STACKTRACE)
{
return {};
}

View File

@@ -7,22 +7,22 @@ import std::io::path, libc, std::os;
<*
@param [in] name
@require name.len > 0
@return! SearchResult.MISSING
@return! NOT_FOUND
*>
fn String! get_var(Allocator allocator, String name) => @pool(allocator)
fn String? get_var(Allocator allocator, String name) => @pool(allocator)
{
$switch:
$case env::LIBC && !env::WIN32:
ZString val = libc::getenv(name.zstr_tcopy());
return val ? val.copy(allocator) : SearchResult.MISSING?;
return val ? val.copy(allocator) : NOT_FOUND?;
$case env::WIN32:
// https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getenvironmentvariable
const usz BUFSIZE = 1024;
WString buff = (WString)tcalloc(BUFSIZE * 2 + 2);
WString wstr = name.to_temp_wstring()!;
usz len = win32::getEnvironmentVariableW(wstr, buff, BUFSIZE);
if (len == 0) return SearchResult.MISSING?;
if (len == 0) return NOT_FOUND?;
if (len > BUFSIZE)
{
buff = (WString)tmalloc(len * 2 + 2);
@@ -34,7 +34,7 @@ fn String! get_var(Allocator allocator, String name) => @pool(allocator)
$endswitch
}
fn String! tget_var(String name)
fn String? tget_var(String name)
{
return get_var(tmem(), name);
}
@@ -66,7 +66,7 @@ fn bool set_var(String name, String value, bool overwrite = true) => @pool()
<*
Returns the current user's home directory.
*>
fn String! get_home_dir(Allocator using = allocator::heap())
fn String? get_home_dir(Allocator using = allocator::heap())
{
String home;
$if !env::WIN32:
@@ -81,7 +81,7 @@ fn String! get_home_dir(Allocator using = allocator::heap())
<*
Returns the current user's config directory.
*>
fn Path! get_config_dir(Allocator allocator) => @pool(allocator)
fn Path? get_config_dir(Allocator allocator) => @pool(allocator)
{
$if env::WIN32:
return path::new(allocator, tget_var("AppData"));
@@ -115,11 +115,11 @@ fn bool clear_var(String name) => @pool()
$endswitch
}
fn String! executable_path(Allocator allocator)
fn String? executable_path(Allocator allocator)
{
$if env::DARWIN:
return darwin::executable_path(allocator);
$else
return SearchResult.MISSING?;
return NOT_FOUND?;
$endif
}

View File

@@ -89,23 +89,23 @@ struct Linux_Dl_info
void* dli_saddr; /* Address of nearest symbol */
}
fn ulong! elf_module_image_base(String path) @local
fn ulong? elf_module_image_base(String path) @local
{
File file = file::open(path, "rb")!;
defer (void)file.close();
char[4] buffer;
io::read_all(&file, &buffer)!;
if (buffer != { 0x7f, 'E', 'L', 'F'}) return BacktraceFault.IMAGE_NOT_FOUND?;
if (buffer != { 0x7f, 'E', 'L', 'F'}) return backtrace::IMAGE_NOT_FOUND?;
bool is_64 = file.read_byte()! == 2;
bool is_little_endian = file.read_byte()! == 1;
// Actually, not supported.
if (!is_little_endian) return BacktraceFault.IMAGE_NOT_FOUND?;
if (!is_little_endian) return backtrace::IMAGE_NOT_FOUND?;
file.seek(0)!;
if (is_64)
{
Elf64_Ehdr file_header;
io::read_any(&file, &file_header)!;
if (file_header.e_ehsize != Elf64_Ehdr.sizeof) return BacktraceFault.IMAGE_NOT_FOUND?;
if (file_header.e_ehsize != Elf64_Ehdr.sizeof) return backtrace::IMAGE_NOT_FOUND?;
for (isz i = 0; i < file_header.e_phnum; i++)
{
Elf64_Phdr header;
@@ -117,7 +117,7 @@ fn ulong! elf_module_image_base(String path) @local
}
Elf32_Ehdr file_header;
io::read_any(&file, &file_header)!;
if (file_header.e_ehsize != Elf32_Ehdr.sizeof) return BacktraceFault.IMAGE_NOT_FOUND?;
if (file_header.e_ehsize != Elf32_Ehdr.sizeof) return backtrace::IMAGE_NOT_FOUND?;
for (isz i = 0; i < file_header.e_phnum; i++)
{
Elf32_Phdr header;
@@ -128,7 +128,7 @@ fn ulong! elf_module_image_base(String path) @local
return 0;
}
fn void! backtrace_add_from_exec(Allocator allocator, BacktraceList* list, void* addr) @local
fn void? backtrace_add_from_exec(Allocator allocator, BacktraceList* list, void* addr) @local
{
char[] buf = mem::talloc_array(char, 1024);
@@ -138,7 +138,7 @@ fn void! backtrace_add_from_exec(Allocator allocator, BacktraceList* list, void*
return backtrace_add_addr2line(allocator, list, addr, addr2line, obj_name, "???");
}
fn void! backtrace_add_from_dlinfo(Allocator allocator, BacktraceList* list, void* addr, Linux_Dl_info* info) @local
fn void? backtrace_add_from_dlinfo(Allocator allocator, BacktraceList* list, void* addr, Linux_Dl_info* info) @local
{
char[] buf = mem::talloc_array(char, 1024);
@@ -149,10 +149,10 @@ fn void! backtrace_add_from_dlinfo(Allocator allocator, BacktraceList* list, voi
return backtrace_add_addr2line(allocator, list, addr, addr2line, info.dli_fname.str_view(), sname);
}
fn Backtrace! backtrace_line_parse(Allocator allocator, String string, String obj_name, String func_name, bool is_inlined)
fn Backtrace? backtrace_line_parse(Allocator allocator, String string, String obj_name, String func_name, bool is_inlined)
{
String[] parts = string.trim().tsplit(" at ");
if (parts.len != 2) return SearchResult.MISSING?;
if (parts.len != 2) return NOT_FOUND?;
uint line = 0;
String source = "";
@@ -171,14 +171,14 @@ fn Backtrace! backtrace_line_parse(Allocator allocator, String string, String ob
.is_inline = is_inlined
};
}
fn void! backtrace_add_addr2line(Allocator allocator, BacktraceList* list, void* addr, String addr2line, String obj_name, String func_name) @local
fn void? backtrace_add_addr2line(Allocator allocator, BacktraceList* list, void* addr, String addr2line, String obj_name, String func_name) @local
{
String[] inline_parts = addr2line.tsplit("(inlined by)");
usz last = inline_parts.len - 1;
foreach (i, part : inline_parts)
{
bool is_inline = i != last;
Backtrace! trace = backtrace_line_parse(allocator, part, obj_name, func_name, is_inline);
Backtrace? trace = backtrace_line_parse(allocator, part, obj_name, func_name, is_inline);
if (catch trace)
{
list.push({
@@ -196,7 +196,7 @@ fn void! backtrace_add_addr2line(Allocator allocator, BacktraceList* list, void*
}
}
fn void! backtrace_add_element(Allocator allocator, BacktraceList *list, void* addr) @local
fn void? backtrace_add_element(Allocator allocator, BacktraceList *list, void* addr) @local
{
if (!addr)
{
@@ -215,7 +215,7 @@ fn void! backtrace_add_element(Allocator allocator, BacktraceList *list, void* a
};
}
fn BacktraceList! symbolize_backtrace(Allocator allocator, void*[] backtrace)
fn BacktraceList? symbolize_backtrace(Allocator allocator, void*[] backtrace)
{
BacktraceList list;
list.init(allocator, backtrace.len);

View File

@@ -68,19 +68,19 @@ struct Darwin_segment_command_64
}
fn String! executable_path(Allocator allocator)
fn String? executable_path(Allocator allocator)
{
char[4096] path;
uint len = path.len;
if (darwin_NSGetExecutablePath(&path, &len) < 0) return SearchResult.MISSING?;
if (darwin_NSGetExecutablePath(&path, &len) < 0) return NOT_FOUND?;
return ((ZString)&path).copy(allocator);
}
fn uptr! load_address() @local
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(tmem()) ?? BacktraceFault.EXECUTABLE_PATH_NOT_FOUND?!;
if (!cmd) return backtrace::SEGMENT_NOT_FOUND?;
String path = env::executable_path(tmem()) ?? backtrace::EXECUTABLE_PATH_NOT_FOUND?!;
uint dyld_count = darwin::_dyld_image_count();
for (uint i = 0; i < dyld_count; i++)
{
@@ -89,11 +89,11 @@ fn uptr! load_address() @local
if (image_name.str_view() != path) continue;
return cmd.vmaddr + darwin::_dyld_get_image_vmaddr_slide(i);
}
return BacktraceFault.IMAGE_NOT_FOUND?;
return backtrace::IMAGE_NOT_FOUND?;
}
fn Backtrace! backtrace_load_element(String execpath, void* buffer, void* load_address, Allocator allocator = allocator::heap()) @local
fn Backtrace? backtrace_load_element(String execpath, void* buffer, void* load_address, Allocator allocator = allocator::heap()) @local
{
@pool(allocator)
{
@@ -132,7 +132,7 @@ fn Backtrace! backtrace_load_element(String execpath, void* buffer, void* load_a
};
}
fn BacktraceList! symbolize_backtrace(Allocator allocator, void*[] backtrace)
fn BacktraceList? symbolize_backtrace(Allocator allocator, void*[] backtrace)
{
void *load_addr = (void *)load_address()!;
BacktraceList list;

View File

@@ -7,11 +7,7 @@ distinct ObjcSelector = void*;
def ObjcId = void*;
def SendVoid = fn void*(void*, ObjcSelector);
fault ObjcFailure
{
CLASS_NOT_FOUND,
UNKNOWN_EVENT
}
fault CLASS_NOT_FOUND, UNKNOWN_EVENT;
macro ZString ObjcClass.name(ObjcClass cls) => class_getName(cls);
macro ObjcClass ObjcClass.superclass(ObjcClass cls) => class_getSuperclass(cls);
@@ -24,10 +20,10 @@ macro bool ObjcClass.equals(ObjcClass a, ObjcClass b) => a == b;
fn ObjcId alloc(ObjcClass cls) => objc::msg_send(cls, SendVoid, "alloc");
fn void release(ObjcId id) => objc::msg_send(id, SendVoid, "release");
macro ObjcClass! class_by_name(ZString c)
macro ObjcClass? class_by_name(ZString c)
{
ObjcClass cls = objc::lookUpClass(c);
return cls ?: ObjcFailure.CLASS_NOT_FOUND?;
return cls ?: CLASS_NOT_FOUND?;
}
macro ObjcClass[] class_get_list(Allocator allocator = allocator::heap())
@@ -138,7 +134,7 @@ enum EventType : (long val)
CHANGE_MODE = 38,
}
fn EventType! event_type_from(int val)
fn EventType? event_type_from(int val)
{
switch(val)
{
@@ -176,7 +172,7 @@ fn EventType! event_type_from(int val)
case EventType.PRESSURE.val: return PRESSURE;
case EventType.DIRECT_TOUCH.val: return DIRECT_TOUCH;
case EventType.CHANGE_MODE.val: return CHANGE_MODE;
default: return ObjcFailure.UNKNOWN_EVENT?;
default: return UNKNOWN_EVENT?;
}
}

View File

@@ -22,7 +22,7 @@ struct Posix_dirent
char[255+1] name @if(env::FREEBSD || env::OPENBSD);
char[511+1] name @if(env::NETBSD);
char[1024] name @if(env::DARWIN);
char[?] name @if(!env::DARWIN && !env::BSD_FAMILY);
char[*] name @if(!env::DARWIN && !env::BSD_FAMILY);
}
extern fn int rmdir(ZString);

View File

@@ -3,8 +3,7 @@ import std::io, libc, std::os;
// This code is based on https://github.com/sheredom/subprocess.h
fault SubProcessResult
{
fault
FAILED_TO_CREATE_PIPE,
FAILED_TO_OPEN_STDIN,
FAILED_TO_OPEN_STDOUT,
@@ -13,8 +12,7 @@ fault SubProcessResult
FAILED_TO_INITIALIZE_ACTIONS,
PROCESS_JOIN_FAILED,
PROCESS_TERMINATION_FAILED,
READ_FAILED,
}
READ_FAILED;
struct SubProcess
{
@@ -49,7 +47,7 @@ bitstruct SubProcessOptions : int
bool search_user_path;
}
fn void! create_named_pipe_helper(void** rd, void **wr) @local @if(env::WIN32)
fn void? create_named_pipe_helper(void** rd, void **wr) @local @if(env::WIN32)
{
Win32_SECURITY_ATTRIBUTES sa_attr = { Win32_SECURITY_ATTRIBUTES.sizeof, null, 1 };
@@ -64,11 +62,11 @@ fn void! create_named_pipe_helper(void** rd, void **wr) @local @if(env::WIN32)
win32::PIPE_ACCESS_INBOUND | win32::FILE_FLAG_OVERLAPPED,
win32::PIPE_TYPE_BYTE | win32::PIPE_WAIT,
1, 4096, 4096, 0, &sa_attr);
if (win32::INVALID_HANDLE_VALUE == *rd) return SubProcessResult.FAILED_TO_CREATE_PIPE?;
if (win32::INVALID_HANDLE_VALUE == *rd) return FAILED_TO_CREATE_PIPE?;
*wr = win32::createFileA(
str, win32::GENERIC_WRITE, 0, &sa_attr,
win32::OPEN_EXISTING, win32::FILE_ATTRIBUTE_NORMAL, null);
if (win32::INVALID_HANDLE_VALUE == *wr) return SubProcessResult.FAILED_TO_CREATE_PIPE?;
if (win32::INVALID_HANDLE_VALUE == *wr) return FAILED_TO_CREATE_PIPE?;
};
}
@@ -115,7 +113,7 @@ fn WString convert_command_line_win32(String[] command_line) @inline @if(env::WI
<*
@require !environment || !options.inherit_environment
*>
fn SubProcess! create(String[] command_line, SubProcessOptions options = {}, String[] environment = {}) @if(env::WIN32)
fn SubProcess? create(String[] command_line, SubProcessOptions options = {}, String[] environment = {}) @if(env::WIN32)
{
void* rd, wr;
Win32_DWORD flags = win32::CREATE_UNICODE_ENVIRONMENT;
@@ -126,9 +124,9 @@ fn SubProcess! create(String[] command_line, SubProcessOptions options = {}, Str
.dwFlags = win32::STARTF_USESTDHANDLES
};
if (options.no_window) flags |= win32::CREATE_NO_WINDOW;
if (!win32::createPipe(&rd, &wr, &sa_attr, 0)) return SubProcessResult.FAILED_TO_CREATE_PIPE?;
if (!win32::createPipe(&rd, &wr, &sa_attr, 0)) return FAILED_TO_CREATE_PIPE?;
// TODO defer catch
if (!win32::setHandleInformation(wr, win32::HANDLE_FLAG_INHERIT, 0)) return SubProcessResult.FAILED_TO_CREATE_PIPE?;
if (!win32::setHandleInformation(wr, win32::HANDLE_FLAG_INHERIT, 0)) return FAILED_TO_CREATE_PIPE?;
CFile stdin;
CFile stdout;
@@ -155,7 +153,7 @@ fn SubProcess! create(String[] command_line, SubProcessOptions options = {}, Str
if (fd != -1)
{
stdin = win32::_fdopen(fd, "wb");
if (!stdin) return SubProcessResult.FAILED_TO_OPEN_STDIN?;
if (!stdin) return FAILED_TO_OPEN_STDIN?;
}
start_info.hStdInput = rd;
if (options.read_async)
@@ -164,14 +162,14 @@ fn SubProcess! create(String[] command_line, SubProcessOptions options = {}, Str
}
else
{
if (!win32::createPipe(&rd, &wr, &sa_attr, 0)) return SubProcessResult.FAILED_TO_CREATE_PIPE?;
if (!win32::createPipe(&rd, &wr, &sa_attr, 0)) return FAILED_TO_CREATE_PIPE?;
}
if (!win32::setHandleInformation(rd, win32::HANDLE_FLAG_INHERIT, 0)) return SubProcessResult.FAILED_TO_CREATE_PIPE?;
if (!win32::setHandleInformation(rd, win32::HANDLE_FLAG_INHERIT, 0)) return FAILED_TO_CREATE_PIPE?;
fd = win32::_open_osfhandle((iptr)rd, 0);
if (fd != -1)
{
stdout = win32::_fdopen(fd, "rb");
if (!stdout) return SubProcessResult.FAILED_TO_OPEN_STDOUT?;
if (!stdout) return FAILED_TO_OPEN_STDOUT?;
}
start_info.hStdOutput = wr;
@@ -190,15 +188,15 @@ fn SubProcess! create(String[] command_line, SubProcessOptions options = {}, Str
}
else
{
if (!win32::createPipe(&rd, &wr, &sa_attr, 0)) return SubProcessResult.FAILED_TO_CREATE_PIPE?;
if (!win32::createPipe(&rd, &wr, &sa_attr, 0)) return FAILED_TO_CREATE_PIPE?;
}
if (!win32::setHandleInformation(rd, win32::HANDLE_FLAG_INHERIT, 0)) return SubProcessResult.FAILED_TO_CREATE_PIPE?;
if (!win32::setHandleInformation(rd, win32::HANDLE_FLAG_INHERIT, 0)) return FAILED_TO_CREATE_PIPE?;
fd = win32::_open_osfhandle((iptr)rd, 0);
if (fd != -1)
{
stderr = win32::_fdopen(fd, "rb");
if (!stderr) return SubProcessResult.FAILED_TO_OPEN_STDERR?;
if (!stderr) return FAILED_TO_OPEN_STDERR?;
}
start_info.hStdError = wr;
};
@@ -219,7 +217,7 @@ fn SubProcess! create(String[] command_line, SubProcessOptions options = {}, Str
used_environment, // environment
null, // use parent dir
&start_info, // startup info ptr
&process_info)) return SubProcessResult.FAILED_TO_START_PROCESS?;
&process_info)) return FAILED_TO_START_PROCESS?;
};
// We don't need the handle of the primary thread in the called process.
win32::closeHandle(process_info.hThread);
@@ -266,7 +264,7 @@ fn ZString* tcopy_env(String[] environment) @local @inline @if(env::POSIX)
return copy;
}
fn String! execute_stdout_to_buffer(char[] buffer, String[] command_line, SubProcessOptions options = {}, String[] environment = {})
fn String? execute_stdout_to_buffer(char[] buffer, String[] command_line, SubProcessOptions options = {}, String[] environment = {})
{
SubProcess process = process::create(command_line, options, environment)!;
process.join()!;
@@ -277,31 +275,31 @@ fn String! execute_stdout_to_buffer(char[] buffer, String[] command_line, SubPro
<*
@require !environment || !options.inherit_environment
*>
fn SubProcess! create(String[] command_line, SubProcessOptions options = {}, String[] environment = {}) @if(env::POSIX)
fn SubProcess? create(String[] command_line, SubProcessOptions options = {}, String[] environment = {}) @if(env::POSIX)
{
CInt[2] stdinfd;
CInt[2] stdoutfd;
CInt[2] stderrfd;
if (posix::pipe(&stdinfd)) return SubProcessResult.FAILED_TO_OPEN_STDIN?;
if (posix::pipe(&stdoutfd)) return SubProcessResult.FAILED_TO_OPEN_STDOUT?;
if (!options.combined_stdout_stderr && posix::pipe(&stderrfd)) return SubProcessResult.FAILED_TO_OPEN_STDERR?;
if (posix::pipe(&stdinfd)) return FAILED_TO_OPEN_STDIN?;
if (posix::pipe(&stdoutfd)) return FAILED_TO_OPEN_STDOUT?;
if (!options.combined_stdout_stderr && posix::pipe(&stderrfd)) return FAILED_TO_OPEN_STDERR?;
Posix_spawn_file_actions_t actions;
if (posix::spawn_file_actions_init(&actions)) return SubProcessResult.FAILED_TO_INITIALIZE_ACTIONS?;
if (posix::spawn_file_actions_init(&actions)) return FAILED_TO_INITIALIZE_ACTIONS?;
defer posix::spawn_file_actions_destroy(&actions);
if (posix::spawn_file_actions_addclose(&actions, stdinfd[1])) return SubProcessResult.FAILED_TO_OPEN_STDIN?;
if (posix::spawn_file_actions_adddup2(&actions, stdinfd[0], libc::STDIN_FD)) return SubProcessResult.FAILED_TO_OPEN_STDIN?;
if (posix::spawn_file_actions_addclose(&actions, stdoutfd[0])) return SubProcessResult.FAILED_TO_OPEN_STDOUT?;
if (posix::spawn_file_actions_adddup2(&actions, stdoutfd[1], libc::STDOUT_FD)) return SubProcessResult.FAILED_TO_OPEN_STDOUT?;
if (posix::spawn_file_actions_addclose(&actions, stdinfd[1])) return FAILED_TO_OPEN_STDIN?;
if (posix::spawn_file_actions_adddup2(&actions, stdinfd[0], libc::STDIN_FD)) return FAILED_TO_OPEN_STDIN?;
if (posix::spawn_file_actions_addclose(&actions, stdoutfd[0])) return FAILED_TO_OPEN_STDOUT?;
if (posix::spawn_file_actions_adddup2(&actions, stdoutfd[1], libc::STDOUT_FD)) return FAILED_TO_OPEN_STDOUT?;
if (options.combined_stdout_stderr)
{
if (posix::spawn_file_actions_adddup2(&actions, libc::STDOUT_FD, libc::STDERR_FD)) return SubProcessResult.FAILED_TO_OPEN_STDERR?;
if (posix::spawn_file_actions_adddup2(&actions, libc::STDOUT_FD, libc::STDERR_FD)) return FAILED_TO_OPEN_STDERR?;
}
else
{
if (posix::spawn_file_actions_addclose(&actions, stderrfd[0])) return SubProcessResult.FAILED_TO_OPEN_STDERR?;
if (posix::spawn_file_actions_adddup2(&actions, stderrfd[1], libc::STDERR_FD)) return SubProcessResult.FAILED_TO_OPEN_STDERR?;
if (posix::spawn_file_actions_addclose(&actions, stderrfd[0])) return FAILED_TO_OPEN_STDERR?;
if (posix::spawn_file_actions_adddup2(&actions, stderrfd[1], libc::STDERR_FD)) return FAILED_TO_OPEN_STDERR?;
}
Pid_t child;
@pool()
@@ -310,11 +308,11 @@ fn SubProcess! create(String[] command_line, SubProcessOptions options = {}, Str
ZString* used_environment = options.inherit_environment ? posix::environ : tcopy_env(environment);
if (options.search_user_path)
{
if (posix::spawnp(&child, command_line_copy[0], &actions, null, command_line_copy, used_environment)) return SubProcessResult.FAILED_TO_START_PROCESS?;
if (posix::spawnp(&child, command_line_copy[0], &actions, null, command_line_copy, used_environment)) return FAILED_TO_START_PROCESS?;
}
else
{
if (posix::spawnp(&child, command_line_copy[0], &actions, null, command_line_copy, used_environment)) return SubProcessResult.FAILED_TO_START_PROCESS?;
if (posix::spawnp(&child, command_line_copy[0], &actions, null, command_line_copy, used_environment)) return FAILED_TO_START_PROCESS?;
}
};
libc::close(stdinfd[0]);
@@ -341,7 +339,7 @@ fn SubProcess! create(String[] command_line, SubProcessOptions options = {}, Str
};
}
fn CInt! SubProcess.join(&self) @if(env::POSIX)
fn CInt? SubProcess.join(&self) @if(env::POSIX)
{
if (self.stdin_file)
{
@@ -349,7 +347,7 @@ fn CInt! SubProcess.join(&self) @if(env::POSIX)
self.stdin_file = null;
}
CInt status;
if (self.child && self.child != posix::waitpid(self.child, &status, 0)) return SubProcessResult.PROCESS_JOIN_FAILED?;
if (self.child && self.child != posix::waitpid(self.child, &status, 0)) return PROCESS_JOIN_FAILED?;
self.child = 0;
self.is_alive = false;
@@ -367,7 +365,7 @@ fn File SubProcess.stderr(&self)
return file::from_handle(self.stderr_file);
}
fn CInt! SubProcess.join(&self) @if(env::WIN32)
fn CInt? SubProcess.join(&self) @if(env::WIN32)
{
if (self.stdin_file)
{
@@ -381,7 +379,7 @@ fn CInt! SubProcess.join(&self) @if(env::WIN32)
}
win32::waitForSingleObject(self.hProcess, win32::INFINITE);
Win32_DWORD return_code @noinit;
if (!win32::getExitCodeProcess(self.hProcess, &return_code)) return SubProcessResult.PROCESS_JOIN_FAILED?;
if (!win32::getExitCodeProcess(self.hProcess, &return_code)) return PROCESS_JOIN_FAILED?;
self.is_alive = false;
return return_code;
}
@@ -405,19 +403,19 @@ fn bool SubProcess.destroy(&self)
return true;
}
fn void! SubProcess.terminate(&self)
fn void? SubProcess.terminate(&self)
{
$if env::WIN32:
if (!win32::terminateProcess(self.hProcess, 99)) return SubProcessResult.PROCESS_TERMINATION_FAILED?;
if (!win32::terminateProcess(self.hProcess, 99)) return PROCESS_TERMINATION_FAILED?;
$else
if (posix::kill(self.child, 9)) return SubProcessResult.PROCESS_TERMINATION_FAILED?;
if (posix::kill(self.child, 9)) return PROCESS_TERMINATION_FAILED?;
$endif
}
<*
@require size <= Win32_DWORD.max
*>
fn usz! read_from_file_win32(CFile file, Win32_HANDLE event_handle, char* buffer, usz size) @if(env::WIN32) @local
fn usz? read_from_file_win32(CFile file, Win32_HANDLE event_handle, char* buffer, usz size) @if(env::WIN32) @local
{
CInt fd = libc::fileno(file);
Win32_DWORD bytes_read = 0;
@@ -436,21 +434,21 @@ fn usz! read_from_file_win32(CFile file, Win32_HANDLE event_handle, char* buffer
case win32::ERROR_HANDLE_EOF:
break;
default:
return SubProcessResult.READ_FAILED?;
return READ_FAILED?;
}
}
}
}
return bytes_read;
}
fn usz! read_from_file_posix(CFile file, char* buffer, usz size) @if(env::POSIX) @local
fn usz? read_from_file_posix(CFile file, char* buffer, usz size) @if(env::POSIX) @local
{
isz bytes_read = libc::read(libc::fileno(file), buffer, size);
if (bytes_read < 0) return SubProcessResult.READ_FAILED?;
if (bytes_read < 0) return READ_FAILED?;
return bytes_read;
}
fn usz! SubProcess.read_stdout(&self, char* buffer, usz size)
fn usz? SubProcess.read_stdout(&self, char* buffer, usz size)
{
$if env::WIN32:
return read_from_file_win32(self.stdout_file, self.hEventOutput, buffer, size);
@@ -459,7 +457,7 @@ fn usz! SubProcess.read_stdout(&self, char* buffer, usz size)
$endif
}
fn usz! SubProcess.read_stderr(&self, char* buffer, usz size)
fn usz? SubProcess.read_stderr(&self, char* buffer, usz size)
{
$if env::WIN32:
return read_from_file_win32(self.stderr_file, self.hEventError, buffer, size);
@@ -468,7 +466,7 @@ fn usz! SubProcess.read_stderr(&self, char* buffer, usz size)
$endif
}
fn bool! SubProcess.is_running(&self)
fn bool? SubProcess.is_running(&self)
{
if (!self.is_alive) return false;
$if env::WIN32:

View File

@@ -108,7 +108,7 @@ extern fn Win32_BOOL symGetModuleInfo64(Win32_HANDLE hProcess, Win32_DWORD64 qwA
extern fn Win32_HANDLE getModuleHandleA(Win32_LPCSTR lpModuleName) @extern("GetModuleHandleA");
extern fn Win32_HANDLE getModuleHandleW(Win32_LPCWSTR lpModuleName) @extern("GetModuleHandleW");
fn Win32_DWORD! load_modules()
fn Win32_DWORD? load_modules()
{
Win32_HANDLE process = getCurrentProcess();
Win32_DWORD needed;
@@ -119,9 +119,9 @@ fn Win32_DWORD! load_modules()
Win32_HMODULE[1024] mod_buffer;
if (!enumProcessModules(process, &mod_buffer, mod_buffer.len, &needed))
{
return BacktraceFault.RESOLUTION_FAILED?;
return backtrace::RESOLUTION_FAILED?;
}
if (needed > mod_buffer.len) return BacktraceFault.RESOLUTION_FAILED?;
if (needed > mod_buffer.len) return backtrace::RESOLUTION_FAILED?;
Win32_HMODULE[] modules = mod_buffer[:needed];
void* base = null;
foreach (mod : modules)
@@ -129,7 +129,7 @@ fn Win32_DWORD! load_modules()
Win32_MODULEINFO info;
if (!getModuleInformation(process, mod, &info, $sizeof(info)))
{
return BacktraceFault.RESOLUTION_FAILED?;
return backtrace::RESOLUTION_FAILED?;
}
if (!base) base = info.lpBaseOfDll;
Win32_DWORD load_size = info.sizeOfImage;
@@ -141,7 +141,7 @@ fn Win32_DWORD! load_modules()
if (len2 < 1) continue;
Win32_DWORD64 base_addr = symLoadModuleEx(process, null, (Win32_PCSTR)&char_buf, (Win32_PCSTR)&module_name, (Win32_DWORD64)info.lpBaseOfDll, load_size, null, 0);
}
if (!base) return BacktraceFault.IMAGE_NOT_FOUND?;
if (!base) return backtrace::IMAGE_NOT_FOUND?;
Win32_IMAGE_NT_HEADERS* h = imageNtHeader(base);
return h.fileHeader.machine;
}
@@ -154,7 +154,7 @@ struct Symbol
Win32_DWORD64 displacement;
fn BacktraceList! symbolize_backtrace(Allocator allocator, void*[] backtrace)
fn BacktraceList? symbolize_backtrace(Allocator allocator, void*[] backtrace)
{
BacktraceList list;
list.init(allocator, backtrace.len);
@@ -168,7 +168,7 @@ fn BacktraceList! symbolize_backtrace(Allocator allocator, void*[] backtrace)
return list;
}
fn Backtrace! resolve_backtrace(Allocator allocator, void* addr, Win32_HANDLE process)
fn Backtrace? resolve_backtrace(Allocator allocator, void* addr, Win32_HANDLE process)
{
Symbol symbol;
//Win32_DWORD image_type = load_modules()!;
@@ -176,13 +176,13 @@ fn Backtrace! resolve_backtrace(Allocator allocator, void* addr, Win32_HANDLE pr
symbol.maxNameLen = 255;
if (!symFromAddr(process, (Win32_DWORD64)addr - 1, &displacement, &symbol))
{
return BacktraceFault.NO_BACKTRACE_SYMBOLS?;
return backtrace::NO_BACKTRACE_SYMBOLS?;
}
Win32_IMAGEHLP_MODULE64 module_info;
module_info.sizeOfStruct = Win32_IMAGEHLP_MODULE64.sizeof;
if (!symGetModuleInfo64(process, (Win32_DWORD64)addr - 1, &module_info))
{
return BacktraceFault.NO_BACKTRACE_SYMBOLS?;
return backtrace::NO_BACKTRACE_SYMBOLS?;
}
ZString module_name = (ZString)&module_info.imageName;
char[256] name;

View File

@@ -85,7 +85,7 @@ fn void qsort(Type list, isz low, isz high, CmpFn cmp, Context context)
@require low <= k : "kth smalles element is smaller than lower bounds"
@require k <= high : "kth smalles element is larger than upper bounds"
*>
fn ElementType! qselect(Type list, isz low, isz high, isz k, CmpFn cmp, Context context)
fn ElementType? qselect(Type list, isz low, isz high, isz k, CmpFn cmp, Context context)
{
if (low >= 0 && high >= 0 && low < high)
{
@@ -108,7 +108,7 @@ fn ElementType! qselect(Type list, isz low, isz high, isz k, CmpFn cmp, Context
}
}
}
return SearchResult.MISSING?;
return NOT_FOUND?;
}
macro @partition(Type list, isz l, isz h, CmpFn cmp, Context context)

View File

@@ -8,7 +8,7 @@ const Language EN = "en";
def TranslationMap = HashMap{String, String};
fn uint Language.hash(self) => fnv32a::encode((char[])self);
HashMap{Language, TranslationMap*} language_map @private;
TranslationMap! current_map;
TranslationMap? current_map;
macro String @localized(String string) @builtin
{

View File

@@ -18,10 +18,10 @@ struct BufferedChannelImpl @private
usz read_waiting;
ConditionVariable read_cond;
Type[?] buf;
Type[*] buf;
}
fn void! BufferedChannel.init(&self, Allocator allocator, usz size = 1)
fn void? BufferedChannel.init(&self, Allocator allocator, usz size = 1)
{
BufferedChannelImpl* channel = allocator::new_with_padding(allocator, BufferedChannelImpl, Type.sizeof * size)!;
defer catch allocator::free(allocator, channel);
@@ -44,7 +44,7 @@ fn void! BufferedChannel.init(&self, Allocator allocator, usz size = 1)
*self = (BufferedChannel)channel;
}
fn void! BufferedChannel.destroy(&self)
fn void? BufferedChannel.destroy(&self)
{
BufferedChannelImpl* channel = (BufferedChannelImpl*)(*self);
@@ -58,7 +58,7 @@ fn void! BufferedChannel.destroy(&self)
if (err) return err?;
}
fn void! BufferedChannel.push(self, Type val)
fn void? BufferedChannel.push(self, Type val)
{
BufferedChannelImpl* channel = (BufferedChannelImpl*)self;
@@ -74,7 +74,7 @@ fn void! BufferedChannel.push(self, Type val)
}
// check if channel is closed
if (channel.closed) return ThreadFault.CHANNEL_CLOSED?;
if (channel.closed) return thread::CHANNEL_CLOSED?;
// save value to buf
channel.buf[channel.sendx] = val;
@@ -98,7 +98,7 @@ fn void! BufferedChannel.push(self, Type val)
channel.mu.unlock()!;
}
fn Type! BufferedChannel.pop(self)
fn Type? BufferedChannel.pop(self)
{
BufferedChannelImpl* channel = (BufferedChannelImpl*)self;
@@ -116,7 +116,7 @@ fn Type! BufferedChannel.pop(self)
// check if chan is closed and empty
if (channel.closed && channel.elems == 0)
{
return ThreadFault.CHANNEL_CLOSED?;
return thread::CHANNEL_CLOSED?;
}
// read from buf
@@ -143,7 +143,7 @@ fn Type! BufferedChannel.pop(self)
return ret;
}
fn void! BufferedChannel.close(self)
fn void? BufferedChannel.close(self)
{
BufferedChannelImpl* channel = (BufferedChannelImpl*)self;

View File

@@ -73,7 +73,7 @@ fn int run_thread(void* arg) @local
thread.state = KILLED;
continue;
}
EventThreadTask! task = thread.queue.wait_for_task();
EventThreadTask? task = thread.queue.wait_for_task();
if (catch task)
{
pool.notify_user_shutdown(thread);

View File

@@ -1,13 +1,11 @@
module std::thread;
fault THREAD_QUEUE_FULL;
module std::thread::threadpool @if (env::POSIX || env::WIN32);
import std::thread;
// Please do not use this one in production.
fault ThreadPoolResult
{
QUEUE_FULL
}
def ThreadPoolFn = fn void(any[] args);
struct FixedThreadPool
@@ -36,7 +34,7 @@ struct QueueItem @private
@require threads > 0 && threads < 0x1000 : `Threads should be greater than 0 and less than 0x1000`
@require queue_size < 0x10000 : `Queue size must be less than 65536`
*>
fn void! FixedThreadPool.init(&self, usz threads, usz queue_size = 0)
fn void? FixedThreadPool.init(&self, usz threads, usz queue_size = 0)
{
if (queue_size == 0) queue_size = threads * 32;
defer catch @ok(self.destroy());
@@ -61,7 +59,7 @@ fn void! FixedThreadPool.init(&self, usz threads, usz queue_size = 0)
Stop all the threads and cleanup the pool.
Any pending work will be dropped.
*>
fn void! FixedThreadPool.destroy(&self)
fn void? FixedThreadPool.destroy(&self)
{
return self.@shutdown(stop_now);
}
@@ -70,12 +68,12 @@ fn void! FixedThreadPool.destroy(&self)
Stop all the threads and cleanup the pool.
Any pending work will be processed.
*>
fn void! FixedThreadPool.stop_and_destroy(&self)
fn void? FixedThreadPool.stop_and_destroy(&self)
{
return self.@shutdown(stop);
}
macro void! FixedThreadPool.@shutdown(&self, #stop) @private
macro void? FixedThreadPool.@shutdown(&self, #stop) @private
{
if (self.initialized)
{
@@ -109,11 +107,11 @@ macro void! FixedThreadPool.@shutdown(&self, #stop) @private
Push a new job to the pool.
return Excuse if the queue is full, in which case the job is ignored.
*>
fn void! FixedThreadPool.push(&self, ThreadPoolFn func, args...)
fn void? FixedThreadPool.push(&self, ThreadPoolFn func, args...)
{
self.mu.lock()!;
defer self.mu.unlock()!!;
if (self.qindex == self.queue.len) return ThreadPoolResult.QUEUE_FULL?;
if (self.qindex == self.queue.len) return thread::THREAD_QUEUE_FULL?;
any[] data;
if (args.len)
{

View File

@@ -22,22 +22,23 @@ def NativeOnceFlag = Pthread_once_t;
@require !self.is_initialized() : "Mutex is already initialized"
@ensure self.is_initialized()
*>
fn void! NativeMutex.init(&self, MutexType type)
fn void? NativeMutex.init(&self, MutexType type)
{
Pthread_mutexattr_t attr;
if (posix::pthread_mutexattr_init(&attr)) return ThreadFault.INIT_FAILED?;
if (posix::pthread_mutexattr_init(&attr)) return thread::INIT_FAILED?;
defer posix::pthread_mutexattr_destroy(&attr);
// TODO: make a fine grained error instead
if (type & thread::MUTEX_RECURSIVE)
{
if (posix::pthread_mutexattr_settype(&attr, posix::PTHREAD_MUTEX_RECURSIVE)) return ThreadFault.INIT_FAILED?;
if (posix::pthread_mutexattr_settype(&attr, posix::PTHREAD_MUTEX_RECURSIVE)) return thread::INIT_FAILED?;
}
else
{
$if env::COMPILER_SAFE_MODE:
if (posix::pthread_mutexattr_settype(&attr, posix::PTHREAD_MUTEX_ERRORCHECK)) return ThreadFault.INIT_FAILED?;
if (posix::pthread_mutexattr_settype(&attr, posix::PTHREAD_MUTEX_ERRORCHECK)) return thread::INIT_FAILED?;
$endif
}
if (posix::pthread_mutex_init(&self.mutex, &attr)) return ThreadFault.INIT_FAILED?;
if (posix::pthread_mutex_init(&self.mutex, &attr)) return thread::INIT_FAILED?;
self.initialized = true;
}
@@ -50,24 +51,24 @@ fn bool NativeMutex.is_initialized(&self)
@require self.is_initialized() : "Mutex was not initialized"
@ensure !self.is_initialized()
*>
fn void! NativeMutex.destroy(&self)
fn void? NativeMutex.destroy(&self)
{
if (posix::pthread_mutex_destroy(&self.mutex)) return ThreadFault.DESTROY_FAILED?;
if (posix::pthread_mutex_destroy(&self.mutex)) return thread::DESTROY_FAILED?;
*self = {};
}
<*
@require self.is_initialized() : "Mutex was not initialized"
*>
fn void! NativeMutex.lock(&self)
fn void? NativeMutex.lock(&self)
{
if (posix::pthread_mutex_lock(&self.mutex)) return ThreadFault.LOCK_FAILED?;
if (posix::pthread_mutex_lock(&self.mutex)) return thread::LOCK_FAILED?;
}
<*
@require self.is_initialized() : "Mutex was not initialized"
*>
fn void! NativeMutex.lock_timeout(&self, ulong ms)
fn void? NativeMutex.lock_timeout(&self, ulong ms)
{
/* Try to acquire the lock and, if we fail, sleep for 5ms. */
Errno result;
@@ -75,7 +76,7 @@ fn void! NativeMutex.lock_timeout(&self, ulong ms)
{
if (!ms) break;
ulong sleep = min(5, ms);
if (!libc::nanosleep(&&time::ms(ms).to_timespec(), null)) return ThreadFault.LOCK_FAILED?;
if (!libc::nanosleep(&&time::ms(ms).to_timespec(), null)) return thread::LOCK_FAILED?;
ms -= sleep;
}
switch (result)
@@ -84,9 +85,9 @@ fn void! NativeMutex.lock_timeout(&self, ulong ms)
return;
case errno::EBUSY:
case errno::ETIMEDOUT:
return ThreadFault.LOCK_TIMEOUT?;
return thread::LOCK_TIMEOUT?;
default:
return ThreadFault.LOCK_FAILED?;
return thread::LOCK_FAILED?;
}
}
@@ -101,57 +102,57 @@ fn bool NativeMutex.try_lock(&self)
<*
@require self.is_initialized() : "Mutex was not initialized"
*>
fn void! NativeMutex.unlock(&self)
fn void? NativeMutex.unlock(&self)
{
if (posix::pthread_mutex_unlock(&self.mutex)) return ThreadFault.UNLOCK_FAILED?;
if (posix::pthread_mutex_unlock(&self.mutex)) return thread::UNLOCK_FAILED?;
}
fn void! NativeConditionVariable.init(&cond)
fn void? NativeConditionVariable.init(&cond)
{
if (posix::pthread_cond_init(cond, null)) return ThreadFault.INIT_FAILED?;
if (posix::pthread_cond_init(cond, null)) return thread::INIT_FAILED?;
}
fn void! NativeConditionVariable.destroy(&cond)
fn void? NativeConditionVariable.destroy(&cond)
{
if (posix::pthread_cond_destroy(cond)) return ThreadFault.DESTROY_FAILED?;
if (posix::pthread_cond_destroy(cond)) return thread::DESTROY_FAILED?;
}
fn void! NativeConditionVariable.signal(&cond)
fn void? NativeConditionVariable.signal(&cond)
{
if (posix::pthread_cond_signal(cond)) return ThreadFault.SIGNAL_FAILED?;
if (posix::pthread_cond_signal(cond)) return thread::SIGNAL_FAILED?;
}
fn void! NativeConditionVariable.broadcast(&cond)
fn void? NativeConditionVariable.broadcast(&cond)
{
if (posix::pthread_cond_broadcast(cond)) return ThreadFault.SIGNAL_FAILED?;
if (posix::pthread_cond_broadcast(cond)) return thread::SIGNAL_FAILED?;
}
<*
@require mtx.is_initialized()
*>
fn void! NativeConditionVariable.wait(&cond, NativeMutex* mtx)
fn void? NativeConditionVariable.wait(&cond, NativeMutex* mtx)
{
if (posix::pthread_cond_wait(cond, &mtx.mutex)) return ThreadFault.WAIT_FAILED?;
if (posix::pthread_cond_wait(cond, &mtx.mutex)) return thread::WAIT_FAILED?;
}
<*
@require mtx.is_initialized()
*>
fn void! NativeConditionVariable.wait_timeout(&cond, NativeMutex* mtx, ulong ms)
fn void? NativeConditionVariable.wait_timeout(&cond, NativeMutex* mtx, ulong ms)
{
TimeSpec now;
if (libc::timespec_get(&now, libc::TIME_UTC) != libc::TIME_UTC) return ThreadFault.WAIT_FAILED?;
if (libc::timespec_get(&now, libc::TIME_UTC) != libc::TIME_UTC) return thread::WAIT_FAILED?;
now.ns += (CLong)((ms % 1000) * 1000_000);
now.s += (Time_t)(ms / 1000 + now.ns / 1000_000_000);
now.ns = now.ns % 1000_000_000;
switch (posix::pthread_cond_timedwait(cond, &mtx.mutex, &now))
{
case errno::ETIMEDOUT:
return ThreadFault.WAIT_TIMEOUT?;
return thread::WAIT_TIMEOUT?;
case errno::OK:
return;
default:
return ThreadFault.WAIT_FAILED?;
return thread::WAIT_FAILED?;
}
}
@@ -164,19 +165,19 @@ fn void* callback(void* arg) @private
return (void*)(iptr)thread.thread_fn(thread.arg);
}
fn void! NativeThread.create(&thread, ThreadFn thread_fn, void* arg)
fn void? NativeThread.create(&thread, ThreadFn thread_fn, void* arg)
{
thread.thread_fn = thread_fn;
thread.arg = arg;
if (posix::pthread_create(&thread.pthread, null, &callback, thread) != 0)
{
return ThreadFault.INIT_FAILED?;
return thread::INIT_FAILED?;
}
}
fn void! NativeThread.detach(thread)
fn void? NativeThread.detach(thread)
{
if (posix::pthread_detach(thread.pthread)) return ThreadFault.DETACH_FAILED?;
if (posix::pthread_detach(thread.pthread)) return thread::DETACH_FAILED?;
}
fn void native_thread_exit(int result)
@@ -194,10 +195,10 @@ fn bool NativeThread.equals(thread, NativeThread other)
return (bool)posix::pthread_equal(thread.pthread, other.pthread);
}
fn int! NativeThread.join(thread)
fn int? NativeThread.join(thread)
{
void *pres;
if (posix::pthread_join(thread.pthread, &pres)) return ThreadFault.JOIN_FAILED?;
if (posix::pthread_join(thread.pthread, &pres)) return thread::JOIN_FAILED?;
return (int)(iptr)pres;
}
@@ -211,9 +212,9 @@ fn void native_thread_yield()
posix::sched_yield();
}
fn void! native_sleep_nano(NanoDuration nano)
fn void? native_sleep_nano(NanoDuration nano)
{
if (nano <= 0) return;
if (libc::nanosleep(&&nano.to_timespec(), null)) return ThreadFault.INTERRUPTED?;
if (libc::nanosleep(&&nano.to_timespec(), null)) return thread::INTERRUPTED?;
}

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