std/lib/collections: make List support the []= operator (#831)

* std/lib/collections: make List support the []= operator

Signed-off-by: Pierre Curto <pierre.curto@gmail.com>

* std/lib/io: rename receiver to self

Signed-off-by: Pierre Curto <pierre.curto@gmail.com>

---------

Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
This commit is contained in:
Pierre Curto
2023-07-07 13:51:44 +02:00
committed by GitHub
parent 79e2d683b6
commit 7dc1eab185
11 changed files with 418 additions and 406 deletions

View File

@@ -290,6 +290,11 @@ fn Type* List.get_ref(&self, usz index) @operator(&[]) @inline
return &self.entries[index];
}
fn void List.set(&self, usz index, Type value) @operator([]=)
{
self.entries[index] = value;
}
fn void List.ensure_capacity(&self, usz added = 1) @inline @private
{
usz new_size = self.size + added;

View File

@@ -19,27 +19,27 @@ fn File from_libc(CFile file)
}
/**
* @require file.file != null
* @require self.file != null
**/
fn void! File.reopen(File* file, String filename, String mode)
fn void! File.reopen(&self, String filename, String mode)
{
file.file = os::native_freopen(file.file, filename, mode)!;
self.file = os::native_freopen(self.file, filename, mode)!;
}
/**
* @require file.file != null
* @require self.file != null
**/
fn usz! File.seek(File file, isz offset, Seek seek_mode = Seek.SET)
fn usz! File.seek(self, isz offset, Seek seek_mode = Seek.SET)
{
os::native_fseek(file.file, offset, seek_mode)!;
return os::native_ftell(file.file);
os::native_fseek(self.file, offset, seek_mode)!;
return os::native_ftell(self.file);
}
/*
Implement later
/**
* @require file.file == null
* @require self.file == null
**/
fn void! File.memopen(File* file, char[] data, String mode)
{

View File

@@ -3,16 +3,16 @@ module std::io;
const char[16] XDIGITS_H = "0123456789ABCDEF";
const char[16] XDIGITS_L = "0123456789abcdef";
fn void! Formatter.left_adjust(Formatter* this, usz len) @local
fn void! Formatter.left_adjust(&self, usz len) @local
{
if (!this.flags.left) return;
for (usz l = len; l < this.width; l++) this.out(' ')!;
if (!self.flags.left) return;
for (usz l = len; l < self.width; l++) self.out(' ')!;
}
fn void! Formatter.right_adjust(Formatter* this, usz len) @local
fn void! Formatter.right_adjust(&self, usz len) @local
{
if (this.flags.left) return;
for (usz l = len; l < this.width; l++) this.out(' ')!;
if (self.flags.left) return;
for (usz l = len; l < self.width; l++) self.out(' ')!;
}
@@ -136,12 +136,12 @@ fn uint simple_atoi(char* buf, usz maxlen, usz* len_ptr) @inline @private
return i;
}
fn void! Formatter.out_substr(Formatter *this, String str) @private
fn void! Formatter.out_substr(&self, String str) @private
{
usz l = conv::utf8_codepoints(str);
uint prec = this.prec;
if (this.flags.precision && l < prec) l = prec;
this.right_adjust(' ')!;
uint prec = self.prec;
if (self.flags.precision && l < prec) l = prec;
self.right_adjust(' ')!;
usz index = 0;
usz chars = str.len;
char* ptr = str.ptr;
@@ -149,16 +149,16 @@ fn void! Formatter.out_substr(Formatter *this, String str) @private
{
char c = ptr[index];
// Break if we have precision set and we ran out...
if (c & 0xC0 != 0x80 && this.flags.precision && !prec--) break;
this.out(c)!;
if (c & 0xC0 != 0x80 && self.flags.precision && !prec--) break;
self.out(c)!;
index++;
}
return this.left_adjust(l);
return self.left_adjust(l);
}
fn void! Formatter.pad(Formatter* this, char c, isz width, isz len) @inline
fn void! Formatter.pad(&self, char c, isz width, isz len) @inline
{
for (isz i = len; i < width; i++) this.out(c)!;
for (isz i = len; i < width; i++) self.out(c)!;
}
fn char* fmt_u(uint128 x, char* s)
@@ -168,9 +168,9 @@ fn char* fmt_u(uint128 x, char* s)
return s;
}
fn void! Formatter.out_chars(Formatter* this, char[] s)
fn void! Formatter.out_chars(&self, char[] s)
{
foreach (c : s) this.out(c)!;
foreach (c : s) self.out(c)!;
}
enum FloatFormatting
@@ -181,12 +181,12 @@ enum FloatFormatting
HEX
}
fn void! Formatter.etoa(Formatter* this, double y) => this.floatformat(EXPONENTIAL, y);
fn void! Formatter.ftoa(Formatter* this, double y) => this.floatformat(FLOAT, y);
fn void! Formatter.gtoa(Formatter* this, double y) => this.floatformat(ADAPTIVE, y);
fn void! Formatter.atoa(Formatter* this, double y) => this.floatformat(HEX, y);
fn void! Formatter.etoa(&self, double y) => self.floatformat(EXPONENTIAL, y);
fn void! Formatter.ftoa(&self, double y) => self.floatformat(FLOAT, y);
fn void! Formatter.gtoa(&self, double y) => self.floatformat(ADAPTIVE, y);
fn void! Formatter.atoa(&self, double y) => self.floatformat(HEX, y);
fn void! Formatter.floatformat(Formatter* this, FloatFormatting formatting, double y) @private
fn void! 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
@@ -198,17 +198,17 @@ fn void! Formatter.floatformat(Formatter* this, FloatFormatting formatting, doub
is_neg = true;
y = -y;
}
int pl = is_neg || this.flags.plus ? 1 : 0;
int pl = is_neg || self.flags.plus ? 1 : 0;
// Print inf/nan
if (!math::is_finite(y))
{
// Add padding
if (!this.flags.left) this.pad(' ', this.width, 3 + pl)!;
String s = this.flags.uppercase ? "INF" : "inf";
if (y != y) this.flags.uppercase ? "NAN" : "nan";
if (pl) this.out(is_neg ? '-' : '+')!;
this.out_chars(s)!;
if (this.flags.left) this.pad(' ', this.width, 3 + pl)!;
if (!self.flags.left) self.pad(' ', self.width, 3 + pl)!;
String s = self.flags.uppercase ? "INF" : "inf";
if (y != y) self.flags.uppercase ? "NAN" : "nan";
if (pl) self.out(is_neg ? '-' : '+')!;
self.out_chars(s)!;
if (self.flags.left) self.pad(' ', self.width, 3 + pl)!;
return;
}
// Rescale
@@ -220,7 +220,7 @@ fn void! Formatter.floatformat(Formatter* this, FloatFormatting formatting, doub
char* ebuf = 12 + (char*)&ebuf0;
char[9 + math::DOUBLE_MANT_DIG / 4] buf_array;
char* buf = &buf_array;
isz p = this.flags.precision ? this.prec : -1;
isz p = self.flags.precision ? self.prec : -1;
if (formatting == HEX)
{
double round = 8.0;
@@ -248,15 +248,15 @@ fn void! Formatter.floatformat(Formatter* this, FloatFormatting formatting, doub
char* estr = fmt_u(e2 < 0 ? (int128)-e2 : (int128)e2, ebuf);
if (estr == ebuf) *--estr = '0';
*--estr = (e2 < 0 ? '-' : '+');
*--estr = this.flags.uppercase ? 'P' : 'p';
*--estr = self.flags.uppercase ? 'P' : 'p';
char* s = buf;
char* xdigits = this.flags.uppercase ? &XDIGITS_H : &XDIGITS_L;
char* xdigits = self.flags.uppercase ? &XDIGITS_H : &XDIGITS_L;
do
{
int x = (int)y;
*s++ = xdigits[x];
y = 16 * (y - x);
if (s - buf == 1 && (y || p > 0 || this.flags.hash)) *s++ = '.';
if (s - buf == 1 && (y || p > 0 || self.flags.hash)) *s++ = '.';
} while (y);
isz outlen = s - buf;
isz explen = ebuf - estr;
@@ -264,14 +264,14 @@ fn void! Formatter.floatformat(Formatter* this, FloatFormatting formatting, doub
usz l = p && outlen - 2 < p
? p + 2 + explen
: outlen + explen;
if (!this.flags.left && !this.flags.zeropad) this.pad(' ', this.width, pl + l)!;
if (is_neg || this.flags.plus) this.out(is_neg ? '-' : '+')!;
this.out_chars(this.flags.uppercase ? "0X" : "0x")!;
if (this.flags.zeropad) this.pad('0', this.width, pl + l)!;
this.out_chars(buf[:outlen])!;
this.pad('0', l - outlen - explen, 0)!;
this.out_chars(estr[:explen])!;
if (this.flags.left) this.pad(' ', this.width, pl + l)!;
if (!self.flags.left && !self.flags.zeropad) self.pad(' ', self.width, pl + l)!;
if (is_neg || self.flags.plus) self.out(is_neg ? '-' : '+')!;
self.out_chars(self.flags.uppercase ? "0X" : "0x")!;
if (self.flags.zeropad) self.pad('0', self.width, pl + l)!;
self.out_chars(buf[:outlen])!;
self.pad('0', l - outlen - explen, 0)!;
self.out_chars(estr[:explen])!;
if (self.flags.left) self.pad(' ', self.width, pl + l)!;
return;
}
if (p < 0) p = 6;
@@ -405,7 +405,7 @@ fn void! Formatter.floatformat(Formatter* this, FloatFormatting formatting, doub
formatting = EXPONENTIAL;
p--;
}
if (!this.flags.hash)
if (!self.flags.hash)
{
// Count trailing zeros in last place
if (z > a && z[-1])
@@ -427,8 +427,8 @@ fn void! Formatter.floatformat(Formatter* this, FloatFormatting formatting, doub
}
}
}
if (p > int.max - 1 - (isz)(p || this.flags.hash)) return PrintFault.INTERNAL_BUFFER_EXCEEDED?;
int l = (int)(1 + p + (isz)(p || this.flags.hash));
if (p > int.max - 1 - (isz)(p || self.flags.hash)) return PrintFault.INTERNAL_BUFFER_EXCEEDED?;
int l = (int)(1 + p + (isz)(p || self.flags.hash));
char* estr @noinit;
if (formatting == FLOAT)
{
@@ -440,14 +440,14 @@ fn void! Formatter.floatformat(Formatter* this, FloatFormatting formatting, doub
estr = fmt_u((uint128)(e < 0 ? -e : e), ebuf);
while (ebuf - estr < 2) (--estr)[0] = '0';
*--estr = (e < 0 ? '-' : '+');
*--estr = this.flags.uppercase ? 'E' : 'e';
*--estr = self.flags.uppercase ? 'E' : 'e';
if (ebuf - estr > (isz)int.max - l) return PrintFault.INTERNAL_BUFFER_EXCEEDED?;
l += (int)(ebuf - estr);
}
if (l > int.max - pl) return PrintFault.INTERNAL_BUFFER_EXCEEDED?;
if (!this.flags.left && !this.flags.zeropad) this.pad(' ', this.width, pl + l)!;
if (is_neg || this.flags.plus) this.out(is_neg ? '-' : '+')!;
if (this.flags.zeropad) this.pad('0', this.width, pl + l)!;
if (!self.flags.left && !self.flags.zeropad) self.pad(' ', self.width, pl + l)!;
if (is_neg || self.flags.plus) self.out(is_neg ? '-' : '+')!;
if (self.flags.zeropad) self.pad('0', self.width, pl + l)!;
if (formatting == FLOAT)
{
if (a > r) a = r;
@@ -462,16 +462,16 @@ fn void! Formatter.floatformat(Formatter* this, FloatFormatting formatting, doub
case s == buf + 9:
*--s = '0';
}
this.out_chars(s[:buf + 9 - s])!;
self.out_chars(s[:buf + 9 - s])!;
}
if (p || this.flags.hash) this.out('.')!;
if (p || self.flags.hash) self.out('.')!;
for (; d < z && p > 0; d++, p -= 9)
{
char* s = fmt_u(*d, buf + 9);
while (s > buf) *--s = '0';
this.out_chars(s[:math::min((isz)9, p)])!;
self.out_chars(s[:math::min((isz)9, p)])!;
}
this.pad('0', p + 9, 9)!;
self.pad('0', p + 9, 9)!;
}
else
{
@@ -486,33 +486,33 @@ fn void! Formatter.floatformat(Formatter* this, FloatFormatting formatting, doub
}
else
{
this.out(s++[0])!;
if (p > 0 || this.flags.hash) this.out('.')!;
self.out(s++[0])!;
if (p > 0 || self.flags.hash) self.out('.')!;
}
this.out_chars(s[:math::min(buf + 9 - s, p)])!;
self.out_chars(s[:math::min(buf + 9 - s, p)])!;
p -= buf + 9 - s;
}
this.pad('0', p + 18, 18)!;
this.out_chars(estr[:ebuf - estr])!;
self.pad('0', p + 18, 18)!;
self.out_chars(estr[:ebuf - estr])!;
}
if (this.flags.left) this.pad(' ', this.width, pl + l)!;
if (self.flags.left) self.pad(' ', self.width, pl + l)!;
return;
}
fn void! Formatter.ntoa(Formatter* this, uint128 value, bool negative, uint base) @private
fn void! Formatter.ntoa(&self, uint128 value, bool negative, uint base) @private
{
char[PRINTF_NTOA_BUFFER_SIZE] buf @noinit;
usz len = 0;
// no hash for 0 values
if (!value) this.flags.hash = false;
if (!value) self.flags.hash = false;
// write if precision != 0 or value is != 0
if (!this.flags.precision || value)
if (!self.flags.precision || value)
{
char past_10 = (this.flags.uppercase ? 'A' : 'a') - 10;
char past_10 = (self.flags.uppercase ? 'A' : 'a') - 10;
do
{
if (len >= PRINTF_NTOA_BUFFER_SIZE) return PrintFault.INTERNAL_BUFFER_EXCEEDED?;
@@ -522,21 +522,21 @@ fn void! Formatter.ntoa(Formatter* this, uint128 value, bool negative, uint base
}
while (value);
}
return this.ntoa_format((String)buf[:PRINTF_NTOA_BUFFER_SIZE], len, negative, base);
return self.ntoa_format((String)buf[:PRINTF_NTOA_BUFFER_SIZE], len, negative, base);
}
fn void! Formatter.ntoa_format(Formatter* this, String buf, usz len, bool negative, uint base) @private
fn void! Formatter.ntoa_format(&self, String buf, usz len, bool negative, uint base) @private
{
// pad leading zeros
if (!this.flags.left)
if (!self.flags.left)
{
if (this.width && this.flags.zeropad && (negative || this.flags.plus || this.flags.space)) this.width--;
while (len < this.prec)
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?;
buf[len++] = '0';
}
while (this.flags.zeropad && len < this.width)
while (self.flags.zeropad && len < self.width)
{
if (len >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED?;
buf[len++] = '0';
@@ -544,9 +544,9 @@ fn void! Formatter.ntoa_format(Formatter* this, String buf, usz len, bool negati
}
// handle hash
if (this.flags.hash && base != 10)
if (self.flags.hash && base != 10)
{
if (!this.flags.precision && len && len == this.prec && len == this.width)
if (!self.flags.precision && len && len == self.prec && len == self.width)
{
len--;
if (len) len--;
@@ -557,11 +557,11 @@ fn void! Formatter.ntoa_format(Formatter* this, String buf, usz len, bool negati
switch (base)
{
case 16:
buf[len++] = this.flags.uppercase ? 'X' : 'x';
buf[len++] = self.flags.uppercase ? 'X' : 'x';
case 8:
buf[len++] = this.flags.uppercase ? 'O' : 'o';
buf[len++] = self.flags.uppercase ? 'O' : 'o';
case 2:
buf[len++] = this.flags.uppercase ? 'B' : 'b';
buf[len++] = self.flags.uppercase ? 'B' : 'b';
default:
unreachable();
}
@@ -574,70 +574,70 @@ fn void! Formatter.ntoa_format(Formatter* this, String buf, usz len, bool negati
case negative:
if (len >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED?;
buf[len++] = '-';
case this.flags.plus:
case self.flags.plus:
if (len >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED?;
buf[len++] = '+';
case this.flags.space:
case self.flags.space:
if (len >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED?;
buf[len++] = ' ';
}
if (!len) return;
return this.out_reverse(buf[:len]);
return self.out_reverse(buf[:len]);
}
fn void! Formatter.ntoa_any(Formatter* this, any arg, uint base) @private
fn void! Formatter.ntoa_any(&self, any arg, uint base) @private
{
bool is_neg;
uint128 val = int_from_any(arg, &is_neg)!!;
return this.ntoa(val, is_neg, base) @inline;
return self.ntoa(val, is_neg, base) @inline;
}
fn void! Formatter.out_char(Formatter* this, any arg) @private
fn void! Formatter.out_char(&self, any arg) @private
{
uint l = 1;
// pre padding
this.right_adjust(l)!;
self.right_adjust(l)!;
// char output
Char32 c = types::any_to_int(arg, uint) ?? 0xFFFD;
switch (true)
{
case c < 0x7f:
this.out((char)c)!;
self.out((char)c)!;
case c < 0x7ff:
this.out((char)(0xC0 | c >> 6))!;
this.out((char)(0x80 | (c & 0x3F)))!;
self.out((char)(0xC0 | c >> 6))!;
self.out((char)(0x80 | (c & 0x3F)))!;
case c < 0xffff:
this.out((char)(0xE0 | c >> 12))!;
this.out((char)(0x80 | (c >> 6 & 0x3F)))!;
this.out((char)(0x80 | (c & 0x3F)))!;
self.out((char)(0xE0 | c >> 12))!;
self.out((char)(0x80 | (c >> 6 & 0x3F)))!;
self.out((char)(0x80 | (c & 0x3F)))!;
default:
this.out((char)(0xF0 | c >> 18))!;
this.out((char)(0x80 | (c >> 12 & 0x3F)))!;
this.out((char)(0x80 | (c >> 6 & 0x3F)))!;
this.out((char)(0x80 | (c & 0x3F)))!;
self.out((char)(0xF0 | c >> 18))!;
self.out((char)(0x80 | (c >> 12 & 0x3F)))!;
self.out((char)(0x80 | (c >> 6 & 0x3F)))!;
self.out((char)(0x80 | (c & 0x3F)))!;
}
return this.left_adjust(l);
return self.left_adjust(l);
}
fn void! Formatter.out_reverse(Formatter* this, char[] buf) @private
fn void! Formatter.out_reverse(&self, char[] buf) @private
{
usz buffer_start_idx = this.idx;
usz buffer_start_idx = self.idx;
usz len = buf.len;
// pad spaces up to given width
if (!this.flags.left && !this.flags.zeropad)
if (!self.flags.left && !self.flags.zeropad)
{
for (usz i = len; i < this.width; i++)
for (usz i = len; i < self.width; i++)
{
this.out(' ')!;
self.out(' ')!;
}
}
// reverse string
while (len) this.out(buf[--len])!;
while (len) self.out(buf[--len])!;
// append pad spaces up to given width
return this.left_adjust(this.idx - buffer_start_idx);
return self.left_adjust(self.idx - buffer_start_idx);
}
fn void! printf_advance_format(usz format_len, usz *index_ptr) @inline @private

View File

@@ -52,26 +52,26 @@ fn char[]! bprintf(char[] buffer, String format, args...) @maydiscard
return buffer[:data.written];
}
fn usz! File.printf(File file, String format, args...) @maydiscard
fn usz! File.printf(self, String format, args...) @maydiscard
{
Formatter formatter;
formatter.init(&out_fputchar_fn, &file);
formatter.init(&out_fputchar_fn, &self);
return formatter.vprintf(format, args)!;
}
fn usz! File.printfn(File file, String format, args...) @maydiscard
fn usz! File.printfn(self, String format, args...) @maydiscard
{
Formatter formatter;
formatter.init(&out_fputchar_fn, &file);
formatter.init(&out_fputchar_fn, &self);
usz len = formatter.vprintf(format, args)!;
file.putc('\n')!;
file.flush();
self.putc('\n')!;
self.flush();
return len + 1;
}
fn usz! Formatter.printf(Formatter* this, String format, args...)
fn usz! Formatter.printf(&self, String format, args...)
{
return this.vprintf(format, args) @inline;
return self.vprintf(format, args) @inline;
}
struct Formatter
@@ -98,46 +98,46 @@ bitstruct PrintFlags : uint
bool precision : 6;
}
fn void Formatter.init(Formatter* this, OutputFn out_fn, void* data = null)
fn void Formatter.init(&self, OutputFn out_fn, void* data = null)
{
*this = { .data = data, .out_fn = out_fn};
*self = { .data = data, .out_fn = out_fn};
}
fn void! Formatter.out(Formatter* this, char c) @private
fn void! Formatter.out(&self, char c) @private
{
this.out_fn(c, this.data)!;
self.out_fn(c, self.data)!;
}
macro bool! Formatter.print_with_function(Formatter* this, any arg)
macro bool! Formatter.print_with_function(&self, any arg)
{
if (&arg.to_format)
{
PrintFlags old = this.flags;
uint old_width = this.width;
uint old_prec = this.prec;
PrintFlags old = self.flags;
uint old_width = self.width;
uint old_prec = self.prec;
defer
{
this.flags = old;
this.width = old_width;
this.prec = old_prec;
self.flags = old;
self.width = old_width;
self.prec = old_prec;
}
arg.to_format(this)!;
arg.to_format(&self)!; // TODO should be self
return true;
}
if (&arg.to_string)
{
PrintFlags old = this.flags;
uint old_width = this.width;
uint old_prec = this.prec;
PrintFlags old = self.flags;
uint old_width = self.width;
uint old_prec = self.prec;
defer
{
this.flags = old;
this.width = old_width;
this.prec = old_prec;
self.flags = old;
self.width = old_width;
self.prec = old_prec;
}
@stack_mem(512; Allocator* mem)
{
this.out_substr(arg.to_string(mem))!;
self.out_substr(arg.to_string(mem))!;
return true;
};
}
@@ -145,109 +145,109 @@ macro bool! Formatter.print_with_function(Formatter* this, any arg)
}
fn void! Formatter.out_str(Formatter* this, any arg) @private
fn void! Formatter.out_str(&self, any arg) @private
{
switch (arg.type.kindof)
{
case TYPEID:
return this.out_substr("typeid");
return self.out_substr("typeid");
case VOID:
return this.out_substr("void");
return self.out_substr("void");
case ANYFAULT:
case FAULT:
return this.out_substr((*(anyfault*)arg.ptr).nameof);
return self.out_substr((*(anyfault*)arg.ptr).nameof);
case ANY:
return this.out_str(*(any*)arg);
return self.out_str(*(any*)arg);
case ENUM:
if (this.print_with_function(arg)!) return;
return this.out_substr(arg.type.names[types::any_to_int(arg, usz)!!]);
if (self.print_with_function(arg)!) return;
return self.out_substr(arg.type.names[types::any_to_int(arg, usz)!!]);
case STRUCT:
if (this.print_with_function(arg)!) return;
return this.out_substr("<struct>");
if (self.print_with_function(arg)!) return;
return self.out_substr("<struct>");
case UNION:
if (this.print_with_function(arg)!) return;
return this.out_substr("<union>");
if (self.print_with_function(arg)!) return;
return self.out_substr("<union>");
case BITSTRUCT:
if (this.print_with_function(arg)!) return;
return this.out_substr("<bitstruct>");
if (self.print_with_function(arg)!) return;
return self.out_substr("<bitstruct>");
case FUNC:
if (this.print_with_function(arg)!) return;
return this.out_substr("<function>");
if (self.print_with_function(arg)!) return;
return self.out_substr("<function>");
case OPTIONAL:
unreachable();
case DISTINCT:
if (this.print_with_function(arg)!) return;
if (self.print_with_function(arg)!) return;
if (arg.type == DString.typeid)
{
return this.out_substr(((DString*)arg).str());
return self.out_substr(((DString*)arg).str());
}
return this.out_str(any { arg.ptr, arg.type.inner });
return self.out_str(any { arg.ptr, arg.type.inner });
case POINTER:
if (this.print_with_function(arg)!) return;
return this.ntoa_any(arg, 16);
if (self.print_with_function(arg)!) return;
return self.ntoa_any(arg, 16);
case SIGNED_INT:
case UNSIGNED_INT:
return this.ntoa_any(arg, 10);
return self.ntoa_any(arg, 10);
case FLOAT:
return this.ftoa(float_from_any(arg)!!);
return self.ftoa(float_from_any(arg)!!);
case ARRAY:
if (this.print_with_function(arg)!) return;
if (self.print_with_function(arg)!) return;
// this is SomeType[*] so grab the "SomeType"
typeid inner = arg.type.inner;
usz size = inner.sizeof;
usz len = arg.type.len;
// Pretend this is a String
void* ptr = (void*)arg.ptr;
this.out('[')!;
self.out('[')!;
for (usz i = 0; i < len; i++)
{
if (i != 0) this.out_substr(", ")!;
this.out_str(any { ptr, inner })!;
if (i != 0) self.out_substr(", ")!;
self.out_str(any { ptr, inner })!;
ptr += size;
}
return this.out(']');
return self.out(']');
case VECTOR:
if (this.print_with_function(arg)!) return;
if (self.print_with_function(arg)!) return;
// this is SomeType[*] so grab the "SomeType"
typeid inner = arg.type.inner;
usz size = inner.sizeof;
usz len = arg.type.len;
// Pretend this is a String
void* ptr = (void*)arg.ptr;
this.out_substr("[<")!;
self.out_substr("[<")!;
for (usz i = 0; i < len; i++)
{
if (i != 0) this.out_substr(", ")!;
this.out_str(any { ptr, inner })!;
if (i != 0) self.out_substr(", ")!;
self.out_str(any { ptr, inner })!;
ptr += size;
}
return this.out_substr(">]");
return self.out_substr(">]");
case SUBARRAY:
if (this.print_with_function(arg)!) return;
if (self.print_with_function(arg)!) return;
// this is SomeType[] so grab the "SomeType"
typeid inner = arg.type.inner;
if (inner == char.typeid)
{
return this.out_substr(*(String*)arg);
return self.out_substr(*(String*)arg);
}
usz size = inner.sizeof;
// Pretend this is a String
String* temp = (void*)arg.ptr;
void* ptr = (void*)temp.ptr;
usz len = temp.len;
this.out('[')!;
self.out('[')!;
for (usz i = 0; i < len; i++)
{
if (i != 0) this.out_substr(", ")!;
this.out_str(any { ptr, inner })!;
if (i != 0) self.out_substr(", ")!;
self.out_str(any { ptr, inner })!;
ptr += size;
}
this.out(']')!;
self.out(']')!;
case BOOL:
return this.out_substr(*(bool*)arg.ptr ? "true" : "false");
return self.out_substr(*(bool*)arg.ptr ? "true" : "false");
default:
if (this.print_with_function(arg)!) return;
return this.out_substr("Invalid type");
if (self.print_with_function(arg)!) return;
return self.out_substr("Invalid type");
}
}
@@ -282,12 +282,12 @@ struct BufferData @private
}
fn usz! Formatter.vprintf(Formatter* this, String format, any[] anys)
fn usz! Formatter.vprintf(&self, String format, any[] anys)
{
if (!this.out_fn)
if (!self.out_fn)
{
// use null output function
this.out_fn = &out_null_fn;
self.out_fn = &out_null_fn;
}
usz format_len = format.len;
usz variant_index = 0;
@@ -298,7 +298,7 @@ fn usz! Formatter.vprintf(Formatter* this, String format, any[] anys)
if (c != '%')
{
// no
this.out(c)!;
self.out(c)!;
continue;
}
i++;
@@ -306,20 +306,20 @@ fn usz! Formatter.vprintf(Formatter* this, String format, any[] anys)
c = format[i];
if (c == '%')
{
this.out(c)!;
self.out(c)!;
continue;
}
// evaluate flags
this.flags = {};
self.flags = {};
while FLAG_EVAL: (true)
{
switch (c)
{
case '0': this.flags.zeropad = true;
case '-': this.flags.left = true;
case '+': this.flags.plus = true;
case ' ': this.flags.space = true;
case '#': this.flags.hash = true;
case '0': self.flags.zeropad = true;
case '-': self.flags.left = true;
case '+': self.flags.plus = true;
case ' ': self.flags.space = true;
case '#': self.flags.hash = true;
default: break FLAG_EVAL;
}
if (++i >= format_len) return PrintFault.INVALID_FORMAT_STRING?;
@@ -330,18 +330,18 @@ fn usz! Formatter.vprintf(Formatter* this, String format, any[] anys)
c = format[i];
if (w < 0)
{
this.flags.left = true;
self.flags.left = true;
w = -w;
}
this.width = w;
self.width = w;
// evaluate precision field
this.prec = 0;
self.prec = 0;
if (c == '.')
{
this.flags.precision = true;
self.flags.precision = true;
if (++i >= format_len) return PrintFault.INVALID_FORMAT_STRING?;
int prec = printf_parse_format_field(anys.ptr, anys.len, &variant_index, format.ptr, format.len, &i)!;
this.prec = prec < 0 ? 0 : prec;
self.prec = prec < 0 ? 0 : prec;
c = format[i];
}
@@ -353,91 +353,91 @@ fn usz! Formatter.vprintf(Formatter* this, String format, any[] anys)
{
case 'd':
base = 10;
this.flags.hash = false;
self.flags.hash = false;
case 'X' :
this.flags.uppercase = true;
self.flags.uppercase = true;
nextcase;
case 'x' :
base = 16;
case 'O':
this.flags.uppercase = true;
self.flags.uppercase = true;
nextcase;
case 'o' :
base = 8;
case 'B':
this.flags.uppercase = true;
self.flags.uppercase = true;
nextcase;
case 'b' :
base = 2;
case 'A':
this.flags.uppercase = true;
self.flags.uppercase = true;
nextcase;
case 'a':
this.atoa(float_from_any(current)!!)!;
self.atoa(float_from_any(current)!!)!;
continue;
case 'F' :
this.flags.uppercase = true;
self.flags.uppercase = true;
nextcase;
case 'f':
this.ftoa(float_from_any(current)!!)!;
self.ftoa(float_from_any(current)!!)!;
continue;
case 'E':
this.flags.uppercase = true;
self.flags.uppercase = true;
nextcase;
case 'e':
this.etoa(float_from_any(current)!!)!;
self.etoa(float_from_any(current)!!)!;
continue;
case 'G':
this.flags.uppercase = true;
self.flags.uppercase = true;
nextcase;
case 'g':
this.gtoa(float_from_any(current)!!)!;
self.gtoa(float_from_any(current)!!)!;
continue;
case 'c':
this.out_char(current)!;
self.out_char(current)!;
continue;
case 's':
this.out_str(current)!;
self.out_str(current)!;
continue;
case 'p':
this.flags.zeropad = true;
this.flags.hash = true;
self.flags.zeropad = true;
self.flags.hash = true;
base = 16;
default:
return PrintFault.INVALID_FORMAT_STRING?;
}
if (base != 10)
{
this.flags.plus = false;
this.flags.space = false;
self.flags.plus = false;
self.flags.space = false;
}
// ignore '0' flag when precision is given
if (this.flags.precision) this.flags.zeropad = false;
if (self.flags.precision) self.flags.zeropad = false;
bool is_neg;
uint128 v = int_from_any(current, &is_neg)!!;
this.ntoa(v, is_neg, base)!;
self.ntoa(v, is_neg, base)!;
}
// termination
// out((char)0, buffer, idx < maxlen ? idx : maxlen - 1U, maxlen);
// return written chars without terminating \0
return this.idx;
return self.idx;
}
fn usz! Formatter.print(Formatter* this, String str)
fn usz! Formatter.print(&self, String str)
{
if (!this.out_fn)
if (!self.out_fn)
{
// use null output function
this.out_fn = &out_null_fn;
self.out_fn = &out_null_fn;
}
usz len = str.len;
for (usz i = 0; i < len; i++)
{
this.out(str[i])!;
self.out(str[i])!;
}
return this.idx;
return self.idx;
}

View File

@@ -37,55 +37,55 @@ struct Stream
void* data;
}
fn bool Stream.supports_flush(Stream s) @inline => (bool)s.fns.flush_fn;
fn bool Stream.supports_seek(Stream s) @inline => (bool)s.fns.seek_fn;
fn bool Stream.supports_available(Stream s) @inline => s.fns.available_fn || s.fns.seek_fn;
fn bool Stream.supports_len(Stream s) @inline => s.fns.len_fn || s.fns.seek_fn;
fn bool Stream.supports_read(Stream s) @inline => s.fns.read_fn || s.fns.read_byte_fn;
fn bool Stream.supports_read_from(Stream s) @inline => (bool)s.fns.read_stream_fn;
fn bool Stream.supports_write_to(Stream s) @inline => (bool)s.fns.write_stream_fn;
fn bool Stream.supports_pushback_byte(Stream s) @inline => s.fns.pushback_byte_fn || s.fns.seek_fn;
fn bool Stream.supports_write(Stream s) @inline => s.fns.write_fn || s.fns.write_byte_fn;
fn bool Stream.supports_flush(s) @inline => (bool)s.fns.flush_fn;
fn bool Stream.supports_seek(s) @inline => (bool)s.fns.seek_fn;
fn bool Stream.supports_available(s) @inline => s.fns.available_fn || s.fns.seek_fn;
fn bool Stream.supports_len(s) @inline => s.fns.len_fn || s.fns.seek_fn;
fn bool Stream.supports_read(s) @inline => s.fns.read_fn || s.fns.read_byte_fn;
fn bool Stream.supports_read_from(s) @inline => (bool)s.fns.read_stream_fn;
fn bool Stream.supports_write_to(s) @inline => (bool)s.fns.write_stream_fn;
fn bool Stream.supports_pushback_byte(s) @inline => s.fns.pushback_byte_fn || s.fns.seek_fn;
fn bool Stream.supports_write(s) @inline => s.fns.write_fn || s.fns.write_byte_fn;
fn void! Stream.destroy(Stream s) @inline @maydiscard
fn void! Stream.destroy(self) @inline @maydiscard
{
if (s.fns.destroy_fn) return s.fns.destroy_fn(s);
return s.close();
if (self.fns.destroy_fn) return self.fns.destroy_fn(self);
return self.close();
}
fn void! Stream.close(Stream s) @inline @maydiscard
fn void! Stream.close(self) @inline @maydiscard
{
if (CloseStreamFn func = s.fns.close_fn) return func(s);
if (CloseStreamFn func = self.fns.close_fn) return func(self);
}
fn usz! Stream.seek(Stream s, isz offset, Seek seek) @inline
fn usz! Stream.seek(self, isz offset, Seek seek) @inline
{
if (SeekStreamFn func = s.fns.seek_fn) return func(s, offset, seek);
if (SeekStreamFn func = self.fns.seek_fn) return func(self, offset, seek);
return IoError.NOT_SEEKABLE?;
}
fn usz! Stream.available(Stream s) @inline
fn usz! Stream.available(self) @inline
{
if (AvailableStreamFn func = s.fns.available_fn) return func(s);
if (SeekStreamFn func = s.fns.seek_fn)
if (AvailableStreamFn func = self.fns.available_fn) return func(self);
if (SeekStreamFn func = self.fns.seek_fn)
{
usz curr = func(s, 0, Seek.CURSOR)!;
usz len = func(s, 0, Seek.END)!;
func(s, curr, Seek.SET)!;
usz curr = func(self, 0, Seek.CURSOR)!;
usz len = func(self, 0, Seek.END)!;
func(self, curr, Seek.SET)!;
return len - curr;
}
return IoError.NOT_SEEKABLE?;
}
fn usz! Stream.read(Stream s, char[] buffer)
fn usz! Stream.read(self, char[] buffer)
{
if (ReadStreamFn func = s.fns.read_fn) return func(s, buffer);
if (ReadByteStreamFn func = s.fns.read_byte_fn)
if (ReadStreamFn func = self.fns.read_fn) return func(self, buffer);
if (ReadByteStreamFn func = self.fns.read_byte_fn)
{
usz len = 0;
foreach (&cptr : buffer)
{
char! c = func(s);
char! c = func(self);
if (catch err = c)
{
case IoError.EOF: return len;
@@ -98,18 +98,18 @@ fn usz! Stream.read(Stream s, char[] buffer)
return IoError.UNSUPPORTED_OPERATION?;
}
fn char! Stream.read_byte(Stream s) @inline
fn char! Stream.read_byte(self) @inline
{
if (ReadByteStreamFn func = s.fns.read_byte_fn) return func(s);
if (ReadByteStreamFn func = self.fns.read_byte_fn) return func(self);
return IoError.UNSUPPORTED_OPERATION?;
}
fn String! Stream.readline(Stream s, Allocator* using = mem::heap())
fn String! Stream.readline(self, Allocator* using = mem::heap())
{
ReadByteStreamFn func;
if (func = s.fns.read_byte_fn, !func) return IoError.UNSUPPORTED_OPERATION?;
if (func = self.fns.read_byte_fn, !func) return IoError.UNSUPPORTED_OPERATION?;
bool read = false;
char val = func(s)!;
char val = func(self)!;
if (val == '\n') return "";
@stack_mem(256 + 64; Allocator* mem)
{
@@ -117,7 +117,7 @@ fn String! Stream.readline(Stream s, Allocator* using = mem::heap())
if (val != '\r') str.append(val);
while (1)
{
char! c = func(s);
char! c = func(self);
if (catch err = c)
{
if (err == IoError.EOF) break;
@@ -131,95 +131,95 @@ fn String! Stream.readline(Stream s, Allocator* using = mem::heap())
};
}
fn usz! Stream.write(Stream s, char[] bytes) @inline
fn usz! Stream.write(self, char[] bytes) @inline
{
if (WriteStreamFn func = s.fns.write_fn) return func(s, bytes);
if (WriteByteStreamFn func = s.fns.write_byte_fn)
if (WriteStreamFn func = self.fns.write_fn) return func(self, bytes);
if (WriteByteStreamFn func = self.fns.write_byte_fn)
{
foreach (c : bytes) func(s, c)!;
foreach (c : bytes) func(self, c)!;
return bytes.len;
}
return IoError.UNSUPPORTED_OPERATION?;
}
fn void! Stream.write_byte(Stream s, char b) @inline
fn void! Stream.write_byte(self, char b) @inline
{
if (WriteByteStreamFn func = s.fns.write_byte_fn) return func(s, b);
if (WriteByteStreamFn func = self.fns.write_byte_fn) return func(self, b);
return IoError.UNSUPPORTED_OPERATION?;
}
fn usz! Stream.write_to(Stream s, Stream to) @inline
fn usz! Stream.write_to(self, Stream to) @inline
{
if (WriteToStreamFn func = s.fns.write_stream_fn) return func(s, to);
if (WriteToStreamFn func = self.fns.write_stream_fn) return func(self, to);
return IoError.UNSUPPORTED_OPERATION?;
}
fn usz! Stream.read_from(Stream s, Stream from) @inline
fn usz! Stream.read_from(self, Stream from) @inline
{
if (ReadFromStreamFn func = s.fns.read_stream_fn) return func(s, from);
if (ReadFromStreamFn func = self.fns.read_stream_fn) return func(self, from);
return IoError.UNSUPPORTED_OPERATION?;
}
fn void! Stream.flush(Stream s) @inline @maydiscard
fn void! Stream.flush(self) @inline @maydiscard
{
if (FlushStreamFn func = s.fns.flush_fn) return func(s);
if (FlushStreamFn func = self.fns.flush_fn) return func(self);
return IoError.UNSUPPORTED_OPERATION?;
}
fn usz! Stream.len(Stream s) @inline
fn usz! Stream.len(self) @inline
{
if (LenStreamFn func = s.fns.len_fn) return func(s);
if (SeekStreamFn func = s.fns.seek_fn)
if (LenStreamFn func = self.fns.len_fn) return func(self);
if (SeekStreamFn func = self.fns.seek_fn)
{
usz curr = func(s, 0, Seek.CURSOR)!;
usz len = func(s, 0, Seek.END)!;
func(s, curr, Seek.SET)!;
usz curr = func(self, 0, Seek.CURSOR)!;
usz len = func(self, 0, Seek.END)!;
func(self, curr, Seek.SET)!;
return len;
}
return IoError.NOT_SEEKABLE?;
}
fn void! Stream.pushback_byte(Stream s) @inline
fn void! Stream.pushback_byte(self) @inline
{
if (PushbackByteStreamFn func = s.fns.pushback_byte_fn) return func(s);
if (SeekStreamFn func = s.fns.seek_fn)
if (PushbackByteStreamFn func = self.fns.pushback_byte_fn) return func(self);
if (SeekStreamFn func = self.fns.seek_fn)
{
func(s, -1, CURSOR)!;
func(self, -1, CURSOR)!;
return;
}
return IoError.UNSUPPORTED_OPERATION?;
}
fn void! Stream.write_string(Stream s, String str) @inline => (void)(s.write((char[])str)!);
fn void! Stream.write_string(self, String str) @inline => (void)(self.write((char[])str)!);
fn usz! Stream.copy_to(Stream s, Stream dst, char[] buffer = {})
fn usz! Stream.copy_to(self, Stream dst, char[] buffer = {})
{
if (buffer.len) return copy_through_buffer(s, dst, buffer);
if (WriteToStreamFn func = s.fns.write_stream_fn) return func(s, dst);
if (ReadFromStreamFn func = dst.fns.read_stream_fn) return func(dst, s);
if (buffer.len) return copy_through_buffer(self, dst, buffer);
if (WriteToStreamFn func = self.fns.write_stream_fn) return func(self, dst);
if (ReadFromStreamFn func = dst.fns.read_stream_fn) return func(dst, self);
$switch (env::MEMORY_ENV)
$case NORMAL:
@pool()
{
return copy_through_buffer(s, dst, tmalloc(char, 4096));
return copy_through_buffer(self, dst, tmalloc(char, 4096));
};
$case SMALL:
@pool()
{
return copy_through_buffer(s, dst, tmalloc(char, 1024));
return copy_through_buffer(self, dst, tmalloc(char, 1024));
};
$case TINY:
$case NONE:
return copy_through_buffer(s, dst, &&(char[256]{}));
return copy_through_buffer(self, dst, &&(char[256]{}));
$endswitch
}
macro usz! copy_through_buffer(Stream s, Stream dst, char[] buffer) @local
macro usz! copy_through_buffer(self, Stream dst, char[] buffer) @local
{
usz total_copied;
while (true)
{
usz! len = s.read(buffer);
usz! len = self.read(buffer);
if (catch err = len)
{
case IoError.EOF: return total_copied;

View File

@@ -10,18 +10,18 @@ struct ReadBuffer
/**
* Buffer reads from a stream.
* @param [inout] b
* @param [inout] self
* @require bytes.len > 0
* @require b.bytes.len == 0 "Init may not run on already initialized data"
* @require self.bytes.len == 0 "Init may not run on already initialized data"
**/
fn void ReadBuffer.init(ReadBuffer *b, Stream stream, char[] bytes)
fn void ReadBuffer.init(&self, Stream stream, char[] bytes)
{
*b = { .stream = stream, .bytes = bytes };
*self = { .stream = stream, .bytes = bytes };
}
fn Stream ReadBuffer.as_stream(ReadBuffer *b)
fn Stream ReadBuffer.as_stream(&self)
{
return { .fns = &readbuffer_interface, .data = b };
return { .fns = &readbuffer_interface, .data = self };
}
StreamInterface readbuffer_interface = {
@@ -29,36 +29,41 @@ StreamInterface readbuffer_interface = {
.read_byte_fn = fn(s) => ((ReadBuffer*)s.data).read_byte(),
};
fn usz! ReadBuffer.read(ReadBuffer *b, char[] bytes)
fn String ReadBuffer.as_str(&self)
{
if (b.read_idx == b.write_idx)
return (String)self.bytes[self.read_idx:self.write_idx - self.read_idx];
}
fn usz! ReadBuffer.read(&self, char[] bytes)
{
if (self.read_idx == self.write_idx)
{
if (b.read_idx == 0 && bytes.len >= b.bytes.len)
if (self.read_idx == 0 && bytes.len >= self.bytes.len)
{
// Read directly into the input buffer.
return b.stream.read(bytes)!;
return self.stream.read(bytes)!;
}
b.refill()!;
self.refill()!;
}
usz n = min(b.write_idx - b.read_idx, bytes.len);
bytes[:n] = b.bytes[b.read_idx:n];
b.read_idx += n;
usz n = min(self.write_idx - self.read_idx, bytes.len);
bytes[:n] = self.bytes[self.read_idx:n];
self.read_idx += n;
return n;
}
fn char! ReadBuffer.read_byte(ReadBuffer *b)
fn char! ReadBuffer.read_byte(&self)
{
if (b.read_idx == b.write_idx) b.refill()!;
if (b.read_idx == b.write_idx) return IoError.EOF?;
char c = b.bytes[b.read_idx];
b.read_idx++;
if (self.read_idx == self.write_idx) self.refill()!;
if (self.read_idx == self.write_idx) return IoError.EOF?;
char c = self.bytes[self.read_idx];
self.read_idx++;
return c;
}
fn void! ReadBuffer.refill(ReadBuffer* b) @local
fn void! ReadBuffer.refill(&self) @local
{
b.read_idx = 0;
b.write_idx = b.stream.read(b.bytes)!;
self.read_idx = 0;
self.write_idx = self.stream.read(self.bytes)!;
}
struct WriteBuffer
@@ -70,18 +75,18 @@ struct WriteBuffer
/**
* Buffer writes to a stream. Call `flush` when done writing to the buffer.
* @param [inout] b
* @param [inout] self
* @require bytes.len > 0 "Non-empty buffer required"
* @require b.bytes.len == 0 "Init may not run on already initialized data"
* @require self.bytes.len == 0 "Init may not run on already initialized data"
**/
fn void WriteBuffer.init(WriteBuffer *b, Stream stream, char[] bytes)
fn void WriteBuffer.init(&self, Stream stream, char[] bytes)
{
*b = { .stream = stream, .bytes = bytes };
*self = { .stream = stream, .bytes = bytes };
}
fn Stream WriteBuffer.as_stream(WriteBuffer *b)
fn Stream WriteBuffer.as_stream(&self)
{
return { .fns = &writebuffer_interface, .data = b };
return { .fns = &writebuffer_interface, .data = self };
}
StreamInterface writebuffer_interface = {
@@ -90,49 +95,49 @@ StreamInterface writebuffer_interface = {
.write_byte_fn = fn(s, char c) => ((WriteBuffer*)s.data).write_byte(c),
};
fn String WriteBuffer.as_str(WriteBuffer* b)
fn String WriteBuffer.as_str(&self)
{
return (String)b.bytes[:b.index];
return (String)self.bytes[:self.index];
}
fn void! WriteBuffer.flush(WriteBuffer* b)
fn void! WriteBuffer.flush(&self)
{
b.write_pending()!;
if (b.stream.supports_flush()) b.stream.flush()!;
self.write_pending()!;
if (self.stream.supports_flush()) self.stream.flush()!;
}
fn usz! WriteBuffer.write(WriteBuffer* b, char[] bytes)
fn usz! WriteBuffer.write(&self, char[] bytes)
{
usz n = b.bytes.len - b.index;
usz n = self.bytes.len - self.index;
if (bytes.len < n)
{
// Enough room in the buffer.
b.bytes[b.index:bytes.len] = bytes[..];
b.index += bytes.len;
self.bytes[self.index:bytes.len] = bytes[..];
self.index += bytes.len;
return bytes.len;
}
b.write_pending()!;
if (bytes.len >= b.bytes.len)
self.write_pending()!;
if (bytes.len >= self.bytes.len)
{
// Write directly to the stream.
return b.stream.write(bytes);
return self.stream.write(bytes);
}
// Buffer the data.
b.bytes[:bytes.len] = bytes[..];
b.index = bytes.len;
self.bytes[:bytes.len] = bytes[..];
self.index = bytes.len;
return bytes.len;
}
fn void! WriteBuffer.write_byte(WriteBuffer* b, char c)
fn void! WriteBuffer.write_byte(&self, char c)
{
usz n = b.bytes.len - b.index;
if (n == 0) b.write_pending()!;
b.bytes[0] = c;
b.index = 1;
usz n = self.bytes.len - self.index;
if (n == 0) self.write_pending()!;
self.bytes[0] = c;
self.index = 1;
}
fn void! WriteBuffer.write_pending(WriteBuffer* b) @local
fn void! WriteBuffer.write_pending(&self) @local
{
b.index -= b.stream.write(b.bytes[:b.index])!;
if (b.index != 0) return IoError.INCOMPLETE_WRITE?;
self.index -= self.stream.write(self.bytes[:self.index])!;
if (self.index != 0) return IoError.INCOMPLETE_WRITE?;
}

View File

@@ -7,64 +7,64 @@ struct ByteReader
usz index;
}
fn void ByteReader.init(ByteReader* reader, char[] bytes)
fn void ByteReader.init(&self, char[] bytes)
{
*reader = { .bytes = bytes };
*self = { .bytes = bytes };
}
fn Stream ByteReader.as_stream(ByteReader* reader)
fn Stream ByteReader.as_stream(&self)
{
return { .fns = &bytereader_interface, .data = reader };
return { .fns = &bytereader_interface, .data = self };
}
fn usz! ByteReader.read(ByteReader* reader, char[] bytes)
fn usz! ByteReader.read(&self, char[] bytes)
{
if (reader.index >= reader.bytes.len) return IoError.EOF?;
usz len = math::min(reader.bytes.len - reader.index, bytes.len);
if (self.index >= self.bytes.len) return IoError.EOF?;
usz len = math::min(self.bytes.len - self.index, bytes.len);
if (len == 0) return 0;
mem::copy(bytes.ptr, &reader.bytes[reader.index], len);
reader.index += len;
mem::copy(bytes.ptr, &self.bytes[self.index], len);
self.index += len;
return len;
}
fn char! ByteReader.read_byte(ByteReader* reader)
fn char! ByteReader.read_byte(&self)
{
if (reader.index >= reader.bytes.len) return IoError.EOF?;
return reader.bytes[reader.index++];
if (self.index >= self.bytes.len) return IoError.EOF?;
return self.bytes[self.index++];
}
fn void! ByteReader.pushback_byte(ByteReader* reader)
fn void! ByteReader.pushback_byte(&self)
{
if (!reader.index) return IoError.INVALID_PUSHBACK?;
reader.index--;
if (!self.index) return IoError.INVALID_PUSHBACK?;
self.index--;
}
fn usz! ByteReader.seek(ByteReader* reader, isz offset, Seek seek)
fn usz! ByteReader.seek(&self, isz offset, Seek seek)
{
isz new_index;
switch (seek)
{
case SET: new_index = offset;
case CURSOR: new_index = reader.index + offset;
case END: new_index = reader.bytes.len + offset;
case CURSOR: new_index = self.index + offset;
case END: new_index = self.bytes.len + offset;
}
if (new_index < 0) return IoError.INVALID_POSITION?;
reader.index = new_index;
self.index = new_index;
return new_index;
}
fn usz! ByteReader.write_stream(ByteReader* reader, Stream writer)
fn usz! ByteReader.write_stream(&self, Stream writer)
{
if (reader.index >= reader.bytes.len) return 0;
usz written = writer.write(reader.bytes[reader.index..])!;
reader.index += written;
assert(reader.index <= reader.bytes.len);
if (self.index >= self.bytes.len) return 0;
usz written = writer.write(self.bytes[self.index..])!;
self.index += written;
assert(self.index <= self.bytes.len);
return written;
}
fn usz ByteReader.available(ByteReader* reader)
fn usz ByteReader.available(&self)
{
return math::max((isz)0, (isz)reader.bytes.len - reader.index);
return math::max((isz)0, (isz)self.bytes.len - self.index);
}
StreamInterface bytereader_interface = {

View File

@@ -8,107 +8,107 @@ struct ByteWriter
}
/**
* @param [&inout] writer
* @param [&inout] self
* @param [&in] using
* @require writer.bytes.len == 0 "Init may not run on on already initialized data"
* @require self.bytes.len == 0 "Init may not run on on already initialized data"
* @ensure using != null, index == 0
**/
fn void ByteWriter.init(ByteWriter* writer, Allocator* using = mem::heap())
fn void ByteWriter.init(&self, Allocator* using = mem::heap())
{
*writer = { .bytes = {}, .allocator = using };
*self = { .bytes = {}, .allocator = using };
}
fn void ByteWriter.init_buffer(ByteWriter* writer, char[] data)
fn void ByteWriter.init_buffer(&self, char[] data)
{
*writer = { .bytes = data, .allocator = null };
*self = { .bytes = data, .allocator = null };
}
/**
* @param [&inout] writer
* @require writer.bytes.len == 0 "Init may not run on on already initialized data"
* @param [&inout] self
* @require self.bytes.len == 0 "Init may not run on on already initialized data"
**/
fn void ByteWriter.tinit(ByteWriter* writer)
fn void ByteWriter.tinit(&self)
{
*writer = { .bytes = {}, .allocator = mem::temp() };
*self = { .bytes = {}, .allocator = mem::temp() };
}
fn Stream ByteWriter.as_stream(ByteWriter* writer)
fn Stream ByteWriter.as_stream(&self)
{
return { .fns = &bytewriter_interface, .data = writer };
return { .fns = &bytewriter_interface, .data = self };
}
fn void ByteWriter.destroy(ByteWriter* writer)
fn void ByteWriter.destroy(&self)
{
if (!writer.allocator) return;
if (void* ptr = writer.bytes.ptr) free(ptr, .using = writer.allocator);
*writer = { };
if (!self.allocator) return;
if (void* ptr = self.bytes.ptr) free(ptr, .using = self.allocator);
*self = { };
}
fn String ByteWriter.as_str(ByteWriter* writer)
fn String ByteWriter.as_str(&self)
{
return (String)writer.bytes[:writer.index];
return (String)self.bytes[:self.index];
}
fn void! ByteWriter.ensure_capacity(ByteWriter* writer, usz len) @inline
fn void! ByteWriter.ensure_capacity(&self, usz len) @inline
{
if (writer.bytes.len > len) return;
if (!writer.allocator) return IoError.OUT_OF_SPACE?;
if (self.bytes.len > len) return;
if (!self.allocator) return IoError.OUT_OF_SPACE?;
if (len < 16) len = 16;
usz new_capacity = math::next_power_of_2(len);
char* new_ptr = realloc_checked(writer.bytes.ptr, new_capacity, .using = writer.allocator)!;
writer.bytes = new_ptr[:new_capacity];
char* new_ptr = realloc_checked(self.bytes.ptr, new_capacity, .using = self.allocator)!;
self.bytes = new_ptr[:new_capacity];
}
fn usz! ByteWriter.write(ByteWriter* writer, char[] bytes)
fn usz! ByteWriter.write(&self, char[] bytes)
{
writer.ensure_capacity(writer.index + bytes.len)!;
mem::copy(&writer.bytes[writer.index], bytes.ptr, bytes.len);
writer.index += bytes.len;
self.ensure_capacity(self.index + bytes.len)!;
mem::copy(&self.bytes[self.index], bytes.ptr, bytes.len);
self.index += bytes.len;
return bytes.len;
}
fn void! ByteWriter.write_byte(ByteWriter* writer, char c)
fn void! ByteWriter.write_byte(&self, char c)
{
writer.ensure_capacity(writer.index + 1)!;
writer.bytes[writer.index++] = c;
self.ensure_capacity(self.index + 1)!;
self.bytes[self.index++] = c;
}
/**
* @param [&inout] writer
* @param [&inout] self
* @param reader
**/
fn usz! ByteWriter.read_from(ByteWriter* writer, Stream reader)
fn usz! ByteWriter.read_from(&self, Stream reader)
{
usz start_index = writer.index;
usz start_index = self.index;
if (reader.supports_available())
{
while (usz available = reader.available()!)
{
writer.ensure_capacity(writer.index + available)!;
usz read = reader.read(writer.bytes[writer.index..])!;
writer.index += read;
self.ensure_capacity(self.index + available)!;
usz read = reader.read(self.bytes[self.index..])!;
self.index += read;
}
return writer.index - start_index;
return self.index - start_index;
}
if (writer.bytes.len == 0)
if (self.bytes.len == 0)
{
writer.ensure_capacity(16)!;
self.ensure_capacity(16)!;
}
while (true)
{
// See how much we can read.
usz len_to_read = writer.bytes.len - writer.index;
usz len_to_read = self.bytes.len - self.index;
// Less than 16 bytes? Double the capacity
if (len_to_read < 16)
{
writer.ensure_capacity(writer.bytes.len * 2)!;
len_to_read = writer.bytes.len - writer.index;
self.ensure_capacity(self.bytes.len * 2)!;
len_to_read = self.bytes.len - self.index;
}
// Read into the rest of the buffer
usz read = reader.read(writer.bytes[writer.index..])!;
writer.index += read;
usz read = reader.read(self.bytes[self.index..])!;
self.index += read;
// Ok, we reached the end.
if (read < len_to_read) return writer.index - start_index;
if (read < len_to_read) return self.index - start_index;
// Otherwise go another round
}
}

View File

@@ -1,8 +1,8 @@
module std::io;
fn Stream DString.as_stream(DString* dstring)
fn Stream DString.as_stream(&self)
{
return { .fns = &dstring_interface, .data = dstring };
return { .fns = &dstring_interface, .data = self };
}
StreamInterface dstring_interface = {

View File

@@ -1,8 +1,8 @@
module std::io;
fn Stream File.as_stream(File* file)
fn Stream File.as_stream(&self)
{
return { .fns = &filestream_interface, .data = file };
return { .fns = &filestream_interface, .data = self };
}
StreamInterface filestream_interface = {

View File

@@ -16,7 +16,9 @@ fn void! test_delete_contains_index()
test.push(3);
assert(test.array_view() == int[]{ 1, 2, 3 });
assert(test.contains(3));
test.remove(1);
test[0] = 10;
assert(test.contains(10));
test.remove(10);
assert(test.array_view() == int[]{ 2, 3 });
assert(!test.contains(1));
assert(test.contains(2));