mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
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:
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 (b.read_idx == 0 && bytes.len >= b.bytes.len)
|
||||
if (self.read_idx == self.write_idx)
|
||||
{
|
||||
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?;
|
||||
}
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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));
|
||||
|
||||
Reference in New Issue
Block a user