mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 03:51:18 +00:00
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:
committed by
GitHub
parent
fefce25081
commit
25bccf4883
140
lib/std/bits.c3
140
lib/std/bits.c3
@@ -10,85 +10,85 @@ macro reverse(i) => $$bitreverse(i);
|
||||
*>
|
||||
macro bswap(i) @builtin => $$bswap(i);
|
||||
|
||||
macro uint[<?>].popcount(self) => $$popcount(self);
|
||||
macro uint[<?>].ctz(self) => $$ctz(self);
|
||||
macro uint[<?>].clz(self) => $$clz(self);
|
||||
macro uint[<?>] uint[<?>].fshl(hi, uint[<?>] lo, uint[<?>] shift) => $$fshl(hi, lo, shift);
|
||||
macro uint[<?>] uint[<?>].fshr(hi, uint[<?>] lo, uint[<?>] shift) => $$fshr(hi, lo, shift);
|
||||
macro uint[<?>] uint[<?>].rotl(self, uint[<?>] shift) => $$fshl(self, self, shift);
|
||||
macro uint[<?>] uint[<?>].rotr(self, uint[<?>] shift) => $$fshr(self, self, shift);
|
||||
macro uint[<*>].popcount(self) => $$popcount(self);
|
||||
macro uint[<*>].ctz(self) => $$ctz(self);
|
||||
macro uint[<*>].clz(self) => $$clz(self);
|
||||
macro uint[<*>] uint[<*>].fshl(hi, uint[<*>] lo, uint[<*>] shift) => $$fshl(hi, lo, shift);
|
||||
macro uint[<*>] uint[<*>].fshr(hi, uint[<*>] lo, uint[<*>] shift) => $$fshr(hi, lo, shift);
|
||||
macro uint[<*>] uint[<*>].rotl(self, uint[<*>] shift) => $$fshl(self, self, shift);
|
||||
macro uint[<*>] uint[<*>].rotr(self, uint[<*>] shift) => $$fshr(self, self, shift);
|
||||
|
||||
macro int[<?>].popcount(self) => $$popcount(self);
|
||||
macro int[<?>].ctz(self) => $$ctz(self);
|
||||
macro int[<?>].clz(self) => $$clz(self);
|
||||
macro int[<?>] int[<?>].fshl(hi, int[<?>] lo, int[<?>] shift) => $$fshl(hi, lo, shift);
|
||||
macro int[<?>] int[<?>].fshr(hi, int[<?>] lo, int[<?>] shift) => $$fshr(hi, lo, shift);
|
||||
macro int[<?>] int[<?>].rotl(self, int[<?>] shift) => $$fshl(self, self, shift);
|
||||
macro int[<?>] int[<?>].rotr(self, int[<?>] shift) => $$fshr(self, self, shift);
|
||||
macro int[<*>].popcount(self) => $$popcount(self);
|
||||
macro int[<*>].ctz(self) => $$ctz(self);
|
||||
macro int[<*>].clz(self) => $$clz(self);
|
||||
macro int[<*>] int[<*>].fshl(hi, int[<*>] lo, int[<*>] shift) => $$fshl(hi, lo, shift);
|
||||
macro int[<*>] int[<*>].fshr(hi, int[<*>] lo, int[<*>] shift) => $$fshr(hi, lo, shift);
|
||||
macro int[<*>] int[<*>].rotl(self, int[<*>] shift) => $$fshl(self, self, shift);
|
||||
macro int[<*>] int[<*>].rotr(self, int[<*>] shift) => $$fshr(self, self, shift);
|
||||
|
||||
macro ushort[<?>].popcount(self) => $$popcount(self);
|
||||
macro ushort[<?>].ctz(self) => $$ctz(self);
|
||||
macro ushort[<?>].clz(self) => $$clz(self);
|
||||
macro ushort[<?>] ushort[<?>].fshl(hi, ushort[<?>] lo, ushort[<?>] shift) => $$fshl(hi, lo, shift);
|
||||
macro ushort[<?>] ushort[<?>].fshr(hi, ushort[<?>] lo, ushort[<?>] shift) => $$fshr(hi, lo, shift);
|
||||
macro ushort[<?>] ushort[<?>].rotl(self, ushort[<?>] shift) => $$fshl(self, self, shift);
|
||||
macro ushort[<?>] ushort[<?>].rotr(self, ushort[<?>] shift) => $$fshr(self, self, shift);
|
||||
macro ushort[<*>].popcount(self) => $$popcount(self);
|
||||
macro ushort[<*>].ctz(self) => $$ctz(self);
|
||||
macro ushort[<*>].clz(self) => $$clz(self);
|
||||
macro ushort[<*>] ushort[<*>].fshl(hi, ushort[<*>] lo, ushort[<*>] shift) => $$fshl(hi, lo, shift);
|
||||
macro ushort[<*>] ushort[<*>].fshr(hi, ushort[<*>] lo, ushort[<*>] shift) => $$fshr(hi, lo, shift);
|
||||
macro ushort[<*>] ushort[<*>].rotl(self, ushort[<*>] shift) => $$fshl(self, self, shift);
|
||||
macro ushort[<*>] ushort[<*>].rotr(self, ushort[<*>] shift) => $$fshr(self, self, shift);
|
||||
|
||||
macro short[<?>].popcount(self) => $$popcount(self);
|
||||
macro short[<?>].ctz(self) => $$ctz(self);
|
||||
macro short[<?>].clz(self) => $$clz(self);
|
||||
macro short[<?>] short[<?>].fshl(hi, short[<?>] lo, short[<?>] shift) => $$fshl(hi, lo, shift);
|
||||
macro short[<?>] short[<?>].fshr(hi, short[<?>] lo, short[<?>] shift) => $$fshr(hi, lo, shift);
|
||||
macro short[<?>] short[<?>].rotl(self, short[<?>] shift) => $$fshl(self, self, shift);
|
||||
macro short[<?>] short[<?>].rotr(self, short[<?>] shift) => $$fshr(self, self, shift);
|
||||
macro short[<*>].popcount(self) => $$popcount(self);
|
||||
macro short[<*>].ctz(self) => $$ctz(self);
|
||||
macro short[<*>].clz(self) => $$clz(self);
|
||||
macro short[<*>] short[<*>].fshl(hi, short[<*>] lo, short[<*>] shift) => $$fshl(hi, lo, shift);
|
||||
macro short[<*>] short[<*>].fshr(hi, short[<*>] lo, short[<*>] shift) => $$fshr(hi, lo, shift);
|
||||
macro short[<*>] short[<*>].rotl(self, short[<*>] shift) => $$fshl(self, self, shift);
|
||||
macro short[<*>] short[<*>].rotr(self, short[<*>] shift) => $$fshr(self, self, shift);
|
||||
|
||||
macro char[<?>].popcount(self) => $$popcount(self);
|
||||
macro char[<?>].ctz(self) => $$ctz(self);
|
||||
macro char[<?>].clz(self) => $$clz(self);
|
||||
macro char[<?>] char[<?>].fshl(hi, char[<?>] lo, char[<?>] shift) => $$fshl(hi, lo, shift);
|
||||
macro char[<?>] char[<?>].fshr(hi, char[<?>] lo, char[<?>] shift) => $$fshr(hi, lo, shift);
|
||||
macro char[<?>] char[<?>].rotl(self, char[<?>] shift) => $$fshl(self, self, shift);
|
||||
macro char[<?>] char[<?>].rotr(self, char[<?>] shift) => $$fshr(self, self, shift);
|
||||
macro char[<*>].popcount(self) => $$popcount(self);
|
||||
macro char[<*>].ctz(self) => $$ctz(self);
|
||||
macro char[<*>].clz(self) => $$clz(self);
|
||||
macro char[<*>] char[<*>].fshl(hi, char[<*>] lo, char[<*>] shift) => $$fshl(hi, lo, shift);
|
||||
macro char[<*>] char[<*>].fshr(hi, char[<*>] lo, char[<*>] shift) => $$fshr(hi, lo, shift);
|
||||
macro char[<*>] char[<*>].rotl(self, char[<*>] shift) => $$fshl(self, self, shift);
|
||||
macro char[<*>] char[<*>].rotr(self, char[<*>] shift) => $$fshr(self, self, shift);
|
||||
|
||||
macro ichar[<?>].popcount(self) => $$popcount(self);
|
||||
macro ichar[<?>].ctz(self) => $$ctz(self);
|
||||
macro ichar[<?>].clz(self) => $$clz(self);
|
||||
macro ichar[<?>] ichar[<?>].fshl(hi, ichar[<?>] lo, ichar[<?>] shift) => $$fshl(hi, lo, shift);
|
||||
macro ichar[<?>] ichar[<?>].fshr(hi, ichar[<?>] lo, ichar[<?>] shift) => $$fshr(hi, lo, shift);
|
||||
macro ichar[<?>] ichar[<?>].rotl(self, ichar[<?>] shift) => $$fshl(self, self, shift);
|
||||
macro ichar[<?>] ichar[<?>].rotr(self, ichar[<?>] shift) => $$fshr(self, self, shift);
|
||||
macro ichar[<*>].popcount(self) => $$popcount(self);
|
||||
macro ichar[<*>].ctz(self) => $$ctz(self);
|
||||
macro ichar[<*>].clz(self) => $$clz(self);
|
||||
macro ichar[<*>] ichar[<*>].fshl(hi, ichar[<*>] lo, ichar[<*>] shift) => $$fshl(hi, lo, shift);
|
||||
macro ichar[<*>] ichar[<*>].fshr(hi, ichar[<*>] lo, ichar[<*>] shift) => $$fshr(hi, lo, shift);
|
||||
macro ichar[<*>] ichar[<*>].rotl(self, ichar[<*>] shift) => $$fshl(self, self, shift);
|
||||
macro ichar[<*>] ichar[<*>].rotr(self, ichar[<*>] shift) => $$fshr(self, self, shift);
|
||||
|
||||
macro ulong[<?>].popcount(self) => $$popcount(self);
|
||||
macro ulong[<?>].ctz(self) => $$ctz(self);
|
||||
macro ulong[<?>].clz(self) => $$clz(self);
|
||||
macro ulong[<?>] ulong[<?>].fshl(hi, ulong[<?>] lo, ulong[<?>] shift) => $$fshl(hi, lo, shift);
|
||||
macro ulong[<?>] ulong[<?>].fshr(hi, ulong[<?>] lo, ulong[<?>] shift) => $$fshr(hi, lo, shift);
|
||||
macro ulong[<?>] ulong[<?>].rotl(self, ulong[<?>] shift) => $$fshl(self, self, shift);
|
||||
macro ulong[<?>] ulong[<?>].rotr(self, ulong[<?>] shift) => $$fshr(self, self, shift);
|
||||
macro ulong[<*>].popcount(self) => $$popcount(self);
|
||||
macro ulong[<*>].ctz(self) => $$ctz(self);
|
||||
macro ulong[<*>].clz(self) => $$clz(self);
|
||||
macro ulong[<*>] ulong[<*>].fshl(hi, ulong[<*>] lo, ulong[<*>] shift) => $$fshl(hi, lo, shift);
|
||||
macro ulong[<*>] ulong[<*>].fshr(hi, ulong[<*>] lo, ulong[<*>] shift) => $$fshr(hi, lo, shift);
|
||||
macro ulong[<*>] ulong[<*>].rotl(self, ulong[<*>] shift) => $$fshl(self, self, shift);
|
||||
macro ulong[<*>] ulong[<*>].rotr(self, ulong[<*>] shift) => $$fshr(self, self, shift);
|
||||
|
||||
macro long[<?>].popcount(self) => $$popcount(self);
|
||||
macro long[<?>].ctz(self) => $$ctz(self);
|
||||
macro long[<?>].clz(self) => $$clz(self);
|
||||
macro long[<?>] long[<?>].fshl(hi, long[<?>] lo, long[<?>] shift) => $$fshl(hi, lo, shift);
|
||||
macro long[<?>] long[<?>].fshr(hi, long[<?>] lo, long[<?>] shift) => $$fshr(hi, lo, shift);
|
||||
macro long[<?>] long[<?>].rotl(self, long[<?>] shift) => $$fshl(self, self, shift);
|
||||
macro long[<?>] long[<?>].rotr(self, long[<?>] shift) => $$fshr(self, self, shift);
|
||||
macro long[<*>].popcount(self) => $$popcount(self);
|
||||
macro long[<*>].ctz(self) => $$ctz(self);
|
||||
macro long[<*>].clz(self) => $$clz(self);
|
||||
macro long[<*>] long[<*>].fshl(hi, long[<*>] lo, long[<*>] shift) => $$fshl(hi, lo, shift);
|
||||
macro long[<*>] long[<*>].fshr(hi, long[<*>] lo, long[<*>] shift) => $$fshr(hi, lo, shift);
|
||||
macro long[<*>] long[<*>].rotl(self, long[<*>] shift) => $$fshl(self, self, shift);
|
||||
macro long[<*>] long[<*>].rotr(self, long[<*>] shift) => $$fshr(self, self, shift);
|
||||
|
||||
macro uint128[<?>].popcount(self) => $$popcount(self);
|
||||
macro uint128[<?>].ctz(self) => $$ctz(self);
|
||||
macro uint128[<?>].clz(self) => $$clz(self);
|
||||
macro uint128[<?>] uint128[<?>].fshl(hi, uint128[<?>] lo, uint128[<?>] shift) => $$fshl(hi, lo, shift);
|
||||
macro uint128[<?>] uint128[<?>].fshr(hi, uint128[<?>] lo, uint128[<?>] shift) => $$fshr(hi, lo, shift);
|
||||
macro uint128[<?>] uint128[<?>].rotl(self, uint128[<?>] shift) => $$fshl(self, self, shift);
|
||||
macro uint128[<?>] uint128[<?>].rotr(self, uint128[<?>] shift) => $$fshr(self, self, shift);
|
||||
macro uint128[<*>].popcount(self) => $$popcount(self);
|
||||
macro uint128[<*>].ctz(self) => $$ctz(self);
|
||||
macro uint128[<*>].clz(self) => $$clz(self);
|
||||
macro uint128[<*>] uint128[<*>].fshl(hi, uint128[<*>] lo, uint128[<*>] shift) => $$fshl(hi, lo, shift);
|
||||
macro uint128[<*>] uint128[<*>].fshr(hi, uint128[<*>] lo, uint128[<*>] shift) => $$fshr(hi, lo, shift);
|
||||
macro uint128[<*>] uint128[<*>].rotl(self, uint128[<*>] shift) => $$fshl(self, self, shift);
|
||||
macro uint128[<*>] uint128[<*>].rotr(self, uint128[<*>] shift) => $$fshr(self, self, shift);
|
||||
|
||||
macro int128[<?>].popcount(self) => $$popcount(self);
|
||||
macro int128[<?>].ctz(self) => $$ctz(self);
|
||||
macro int128[<?>].clz(self) => $$clz(self);
|
||||
macro int128[<?>] int128[<?>].fshl(hi, int128[<?>] lo, int128[<?>] shift) => $$fshl(hi, lo, shift);
|
||||
macro int128[<?>] int128[<?>].fshr(hi, int128[<?>] lo, int128[<?>] shift) => $$fshr(hi, lo, shift);
|
||||
macro int128[<?>] int128[<?>].rotl(self, int128[<?>] shift) => $$fshl(self, self, shift);
|
||||
macro int128[<?>] int128[<?>].rotr(self, int128[<?>] shift) => $$fshr(self, self, shift);
|
||||
macro int128[<*>].popcount(self) => $$popcount(self);
|
||||
macro int128[<*>].ctz(self) => $$ctz(self);
|
||||
macro int128[<*>].clz(self) => $$clz(self);
|
||||
macro int128[<*>] int128[<*>].fshl(hi, int128[<*>] lo, int128[<*>] shift) => $$fshl(hi, lo, shift);
|
||||
macro int128[<*>] int128[<*>].fshr(hi, int128[<*>] lo, int128[<*>] shift) => $$fshr(hi, lo, shift);
|
||||
macro int128[<*>] int128[<*>].rotl(self, int128[<*>] shift) => $$fshl(self, self, shift);
|
||||
macro int128[<*>] int128[<*>].rotr(self, int128[<*>] shift) => $$fshr(self, self, shift);
|
||||
|
||||
macro uint.popcount(self) => $$popcount(self);
|
||||
macro uint.ctz(self) => $$ctz(self);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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("{ ")!;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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?;
|
||||
}
|
||||
|
||||
@@ -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?;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)!;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>];
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)!;
|
||||
|
||||
@@ -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?;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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?;
|
||||
}
|
||||
|
||||
<*
|
||||
|
||||
@@ -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?;
|
||||
}
|
||||
|
||||
<*
|
||||
|
||||
@@ -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;)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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, §ion.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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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..];
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
module std::encoding;
|
||||
|
||||
fault DecodingFailure
|
||||
{
|
||||
INVALID_CHARACTER,
|
||||
INVALID_PADDING,
|
||||
}
|
||||
fault INVALID_CHARACTER, INVALID_PADDING;
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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?;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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?;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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?;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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?;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 {};
|
||||
|
||||
@@ -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?;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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[..])!;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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[..])!;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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`
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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],
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)!;
|
||||
|
||||
@@ -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?;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {};
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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?;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user