Signed-off-by: Pierre Curto <pierre.curto@gmail.com>
This commit is contained in:
Pierre Curto
2023-08-24 16:39:49 +02:00
committed by Christoffer Lerno
parent b77f254ab1
commit c0b109fbc1
12 changed files with 312 additions and 169 deletions

91
lib/std/io/bits.c3 Normal file
View File

@@ -0,0 +1,91 @@
module std::io;
struct BitReader
{
Stream reader;
uint bits;
uint len;
}
/**
* @require byte_reader.supports_read_byte()
**/
fn void BitReader.init(&self, Stream byte_reader)
{
*self = { .reader = byte_reader };
}
fn void BitReader.clear(&self) @inline
{
self.len = 0;
}
/**
* @require nbits <= 8
* @require self.len + nbits <= uint.sizeof * 8
**/
fn char! BitReader.read_bits(&self, uint nbits)
{
uint bits = self.bits;
if (self.len < nbits)
{
// New bits are pushed right.
char c = self.reader.read_byte()!;
bits <<= 8;
bits |= c;
self.bits = bits;
self.len += 8;
}
self.len -= nbits;
uint mask = (1 << nbits) - 1;
return (char)((bits >> self.len) & mask);
}
struct BitWriter
{
Stream writer;
uint bits;
uint len;
}
/**
* @require byte_writer.supports_write_byte()
**/
fn void BitWriter.init(&self, Stream byte_writer)
{
*self = { .writer = byte_writer };
}
fn void! BitWriter.flush(&self)
{
if (self.len == 0) return;
uint bits = self.bits << (32 - self.len);
uint n = (self.len + 7) / 8;
char[4] buffer;
bitorder::write(bits, &buffer, UIntBE);
self.writer.write_all(buffer[:n])!;
self.len = 0;
}
/**
* @require nbits <= 8
**/
fn void! BitWriter.write_bits(&self, uint bits, uint nbits)
{
if (nbits == 0) return;
uint n = self.len + nbits;
uint to_write = n / 8;
uint left = n % 8;
if (to_write > 0)
{
ulong lbits;
if (self.len > 0) lbits = (ulong)self.bits << (64 - self.len);
lbits |= (ulong)(bits >> left) << (64 - (n - left));
char[8] buffer;
bitorder::write(lbits, &buffer, ULongBE);
self.writer.write_all(buffer[:to_write])!;
}
self.bits <<= left;
self.bits |= bits & ((1 << left) - 1);
self.len = left;
}

View File

@@ -3,19 +3,12 @@ module std::io;
const char[16] XDIGITS_H = "0123456789ABCDEF";
const char[16] XDIGITS_L = "0123456789abcdef";
fn void! Formatter.left_adjust(&self, usz len) @local
fn usz! Formatter.adjust(&self, usz len) @local
{
if (!self.flags.left) return;
for (usz l = len; l < self.width; l++) self.out(' ')!;
if (!self.flags.left) return 0;
return self.pad(' ', self.width, len);
}
fn void! Formatter.right_adjust(&self, usz len) @local
{
if (self.flags.left) return;
for (usz l = len; l < self.width; l++) self.out(' ')!;
}
fn uint128! int_from_any(any arg, bool *is_neg) @private
{
*is_neg = false;
@@ -136,12 +129,11 @@ fn uint simple_atoi(char* buf, usz maxlen, usz* len_ptr) @inline @private
return i;
}
fn void! Formatter.out_substr(&self, String str) @private
fn usz! Formatter.out_substr(&self, String str) @private
{
usz l = conv::utf8_codepoints(str);
uint prec = self.prec;
if (self.flags.precision && l < prec) l = prec;
self.right_adjust(l)!;
usz index = 0;
usz chars = str.len;
char* ptr = str.ptr;
@@ -153,12 +145,14 @@ fn void! Formatter.out_substr(&self, String str) @private
self.out(c)!;
index++;
}
return self.left_adjust(l);
return index;
}
fn void! Formatter.pad(&self, char c, isz width, isz len) @inline
fn usz! Formatter.pad(&self, char c, isz width, isz len) @inline
{
for (isz i = len; i < width; i++) self.out(c)!;
isz delta = width - len;
for (isz i = 0; i < delta; i++) self.out(c)!;
return max(0, delta);
}
fn char* fmt_u(uint128 x, char* s)
@@ -168,9 +162,10 @@ fn char* fmt_u(uint128 x, char* s)
return s;
}
fn void! Formatter.out_chars(&self, char[] s)
fn usz! Formatter.out_chars(&self, char[] s)
{
foreach (c : s) self.out(c)!;
return s.len;
}
enum FloatFormatting
@@ -181,12 +176,12 @@ enum FloatFormatting
HEX
}
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 usz! Formatter.etoa(&self, double y) => self.floatformat(EXPONENTIAL, y);
fn usz! Formatter.ftoa(&self, double y) => self.floatformat(FLOAT, y);
fn usz! Formatter.gtoa(&self, double y) => self.floatformat(ADAPTIVE, y);
fn usz! Formatter.atoa(&self, double y) => self.floatformat(HEX, y);
fn void! Formatter.floatformat(&self, FloatFormatting formatting, double y) @private
fn usz! Formatter.floatformat(&self, FloatFormatting formatting, double y) @private
{
// This code is heavily based on musl's printf code
const BUF_SIZE = (math::DOUBLE_MANT_DIG + 28) / 29 + 1
@@ -202,14 +197,16 @@ fn void! Formatter.floatformat(&self, FloatFormatting formatting, double y) @pri
// Print inf/nan
if (!math::is_finite(y))
{
usz len;
// Add padding
if (!self.flags.left) self.pad(' ', self.width, 3 + pl)!;
if (!self.flags.left) len += 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;
if (y != y) s = self.flags.uppercase ? "NAN" : "nan";
len += s.len;
if (pl) len += self.out(is_neg ? '-' : '+')!;
len += self.out_chars(s)!;
if (self.flags.left) len += self.pad(' ', self.width, 3 + pl)!;
return len;
}
// Rescale
int e2;
@@ -261,18 +258,19 @@ fn void! Formatter.floatformat(&self, FloatFormatting formatting, double y) @pri
isz outlen = s - buf;
isz explen = ebuf - estr;
if (p > int.max - 2 - explen - pl) return PrintFault.INTERNAL_BUFFER_EXCEEDED?;
usz len;
usz l = p && outlen - 2 < p
? p + 2 + explen
: outlen + explen;
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 (!self.flags.left && !self.flags.zeropad) len += self.pad(' ', self.width, pl + l)!;
if (is_neg || self.flags.plus) len += self.out(is_neg ? '-' : '+')!;
len += self.out_chars(self.flags.uppercase ? "0X" : "0x")!;
if (self.flags.zeropad) len += self.pad('0', self.width, pl + l)!;
len += self.out_chars(buf[:outlen])!;
len += self.pad('0', l - outlen - explen, 0)!;
len += self.out_chars(estr[:explen])!;
if (self.flags.left) len += self.pad(' ', self.width, pl + l)!;
return len;
}
if (p < 0) p = 6;
if (y)
@@ -445,9 +443,10 @@ fn void! Formatter.floatformat(&self, FloatFormatting formatting, double y) @pri
l += (int)(ebuf - estr);
}
if (l > int.max - pl) return PrintFault.INTERNAL_BUFFER_EXCEEDED?;
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)!;
usz len;
if (!self.flags.left && !self.flags.zeropad) len += self.pad(' ', self.width, pl + l)!;
if (is_neg || self.flags.plus) len += self.out(is_neg ? '-' : '+')!;
if (self.flags.zeropad) len += self.pad('0', self.width, pl + l)!;
if (formatting == FLOAT)
{
if (a > r) a = r;
@@ -462,16 +461,16 @@ fn void! Formatter.floatformat(&self, FloatFormatting formatting, double y) @pri
case s == buf + 9:
*--s = '0';
}
self.out_chars(s[:buf + 9 - s])!;
len += self.out_chars(s[:buf + 9 - s])!;
}
if (p || self.flags.hash) self.out('.')!;
if (p || self.flags.hash) len += self.out('.')!;
for (; d < z && p > 0; d++, p -= 9)
{
char* s = fmt_u(*d, buf + 9);
while (s > buf) *--s = '0';
self.out_chars(s[:math::min((isz)9, p)])!;
len += self.out_chars(s[:math::min((isz)9, p)])!;
}
self.pad('0', p + 9, 9)!;
len += self.pad('0', p + 9, 9)!;
}
else
{
@@ -486,25 +485,25 @@ fn void! Formatter.floatformat(&self, FloatFormatting formatting, double y) @pri
}
else
{
self.out(s++[0])!;
if (p > 0 || self.flags.hash) self.out('.')!;
len += self.out(s++[0])!;
if (p > 0 || self.flags.hash) len += self.out('.')!;
}
self.out_chars(s[:math::min(buf + 9 - s, p)])!;
len += self.out_chars(s[:math::min(buf + 9 - s, p)])!;
p -= buf + 9 - s;
}
self.pad('0', p + 18, 18)!;
self.out_chars(estr[:ebuf - estr])!;
len += self.pad('0', p + 18, 18)!;
len += self.out_chars(estr[:ebuf - estr])!;
}
if (self.flags.left) self.pad(' ', self.width, pl + l)!;
if (self.flags.left) len += self.pad(' ', self.width, pl + l)!;
return;
return len;
}
fn void! Formatter.ntoa(&self, uint128 value, bool negative, uint base) @private
fn usz! Formatter.ntoa(&self, uint128 value, bool negative, uint base) @private
{
char[PRINTF_NTOA_BUFFER_SIZE] buf @noinit;
usz len = 0;
usz len;
// no hash for 0 values
if (!value) self.flags.hash = false;
@@ -525,7 +524,7 @@ fn void! Formatter.ntoa(&self, uint128 value, bool negative, uint base) @private
return self.ntoa_format((String)buf[:PRINTF_NTOA_BUFFER_SIZE], len, negative, base);
}
fn void! Formatter.ntoa_format(&self, String buf, usz len, bool negative, uint base) @private
fn usz! Formatter.ntoa_format(&self, String buf, usz len, bool negative, uint base) @private
{
// pad leading zeros
if (!self.flags.left)
@@ -581,23 +580,24 @@ fn void! Formatter.ntoa_format(&self, String buf, usz len, bool negative, uint b
if (len >= buf.len) return PrintFault.INTERNAL_BUFFER_EXCEEDED?;
buf[len++] = ' ';
}
if (!len) return;
return self.out_reverse(buf[:len]);
if (len) self.out_reverse(buf[:len])!;
return len;
}
fn void! Formatter.ntoa_any(&self, any arg, uint base) @private
fn usz! Formatter.ntoa_any(&self, any arg, uint base) @private
{
bool is_neg;
uint128 val = int_from_any(arg, &is_neg)!!;
return self.ntoa(val, is_neg, base) @inline;
}
fn void! Formatter.out_char(&self, any arg) @private
fn usz! Formatter.out_char(&self, any arg) @private
{
usz len = 1;
uint l = 1;
// pre padding
self.right_adjust(l)!;
len += self.adjust(l)!;
// char output
Char32 c = types::any_to_int(arg, uint) ?? 0xFFFD;
switch (true)
@@ -617,27 +617,27 @@ fn void! Formatter.out_char(&self, any arg) @private
self.out((char)(0x80 | (c >> 6 & 0x3F)))!;
self.out((char)(0x80 | (c & 0x3F)))!;
}
return self.left_adjust(l);
len += self.adjust(l)!;
return len;
}
fn void! Formatter.out_reverse(&self, char[] buf) @private
fn usz! Formatter.out_reverse(&self, char[] buf) @private
{
usz n;
usz buffer_start_idx = self.idx;
usz len = buf.len;
// pad spaces up to given width
if (!self.flags.left && !self.flags.zeropad)
if (!self.flags.zeropad)
{
for (usz i = len; i < self.width; i++)
{
self.out(' ')!;
}
n += self.adjust(len)!;
}
// reverse string
while (len) self.out(buf[--len])!;
while (len) n += self.out(buf[--len])!;
// append pad spaces up to given width
return self.left_adjust(self.idx - buffer_start_idx);
n += self.adjust(self.idx - buffer_start_idx)!;
return n;
}
fn void! printf_advance_format(usz format_len, usz *index_ptr) @inline @private

View File

@@ -25,7 +25,7 @@ def OutputFn = fn void!(char c, void* buffer);
def FloatType = double;
fn String any.to_string(void* value, Allocator *using) @interface;
fn void! any.to_format(void* value, Formatter* formatter) @interface;
fn usz! any.to_format(void* value, Formatter* formatter) @interface;
fn usz! printf(String format, args...) @maydiscard
{
@@ -103,12 +103,13 @@ fn void Formatter.init(&self, OutputFn out_fn, void* data = null)
*self = { .data = data, .out_fn = out_fn};
}
fn void! Formatter.out(&self, char c) @private
fn usz! Formatter.out(&self, char c) @private
{
self.out_fn(c, self.data)!;
return 1;
}
macro bool! Formatter.print_with_function(&self, any arg)
macro usz! Formatter.print_with_function(&self, any arg)
{
if (&arg.to_format)
{
@@ -121,8 +122,7 @@ macro bool! Formatter.print_with_function(&self, any arg)
self.width = old_width;
self.prec = old_prec;
}
arg.to_format(self)!;
return true;
return arg.to_format(self);
}
if (&arg.to_string)
{
@@ -137,15 +137,14 @@ macro bool! Formatter.print_with_function(&self, any arg)
}
@pool()
{
self.out_substr(arg.to_string(mem::temp()))!;
return true;
return self.out_substr(arg.to_string(mem::temp()));
};
}
return false;
return SearchResult.MISSING?;
}
fn void! Formatter.out_str(&self, any arg) @private
fn usz! Formatter.out_str(&self, any arg) @private
{
switch (arg.type.kindof)
{
@@ -158,74 +157,82 @@ fn void! Formatter.out_str(&self, any arg) @private
return self.out_substr((*(anyfault*)arg.ptr).nameof);
case ANY:
return self.out_str(*(any*)arg);
case OPTIONAL:
unreachable();
case SIGNED_INT:
case UNSIGNED_INT:
return self.ntoa_any(arg, 10);
case FLOAT:
return self.ftoa(float_from_any(arg)!!);
case BOOL:
return self.out_substr(*(bool*)arg.ptr ? "true" : "false");
default:
}
usz! n = self.print_with_function(arg);
if (catch err = n)
{
case SearchResult.MISSING:
break;
default:
return err?;
} else {
return n;
}
switch (arg.type.kindof)
{
case ENUM:
if (self.print_with_function(arg)!) return;
usz i = types::any_to_int(arg, usz)!!;
assert(i < arg.type.names.len, "Illegal enum value found, numerical value was %d.", i);
return self.out_substr(arg.type.names[i]);
case STRUCT:
if (self.print_with_function(arg)!) return;
return self.out_substr("<struct>");
case UNION:
if (self.print_with_function(arg)!) return;
return self.out_substr("<union>");
case BITSTRUCT:
if (self.print_with_function(arg)!) return;
return self.out_substr("<bitstruct>");
case FUNC:
if (self.print_with_function(arg)!) return;
return self.out_substr("<function>");
case OPTIONAL:
unreachable();
case DISTINCT:
if (self.print_with_function(arg)!) return;
if (arg.type == DString.typeid)
{
return self.out_substr(((DString*)arg).as_str());
}
return self.out_str(any { arg.ptr, arg.type.inner });
case POINTER:
if (self.print_with_function(arg)!) return;
return self.ntoa_any(arg, 16);
case SIGNED_INT:
case UNSIGNED_INT:
return self.ntoa_any(arg, 10);
case FLOAT:
return self.ftoa(float_from_any(arg)!!);
case ARRAY:
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;
usz alen = arg.type.len;
// Pretend this is a String
void* ptr = (void*)arg.ptr;
self.out('[')!;
for (usz i = 0; i < len; i++)
usz len = self.out('[')!;
for (usz i = 0; i < alen; i++)
{
if (i != 0) self.out_substr(", ")!;
self.out_str(any { ptr, inner })!;
if (i != 0) len += self.out_substr(", ")!;
len += self.out_str(any { ptr, inner })!;
ptr += size;
}
return self.out(']');
len += self.out(']')!;
return len;
case VECTOR:
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;
usz vlen = arg.type.len;
// Pretend this is a String
void* ptr = (void*)arg.ptr;
self.out_substr("[<")!;
for (usz i = 0; i < len; i++)
usz len = self.out_substr("[<")!;
for (usz i = 0; i < vlen; i++)
{
if (i != 0) self.out_substr(", ")!;
self.out_str(any { ptr, inner })!;
if (i != 0) len += self.out_substr(", ")!;
len += self.out_str(any { ptr, inner })!;
ptr += size;
}
return self.out_substr(">]");
len += self.out_substr(">]")!;
return len;
case SUBARRAY:
if (self.print_with_function(arg)!) return;
// this is SomeType[] so grab the "SomeType"
typeid inner = arg.type.inner;
if (inner == char.typeid)
@@ -237,21 +244,19 @@ fn void! Formatter.out_str(&self, any arg) @private
// Pretend this is a String
String* temp = (void*)arg.ptr;
void* ptr = (void*)temp.ptr;
usz len = temp.len;
self.out('[')!;
for (usz i = 0; i < len; i++)
usz slen = temp.len;
usz len = self.out('[')!;
for (usz i = 0; i < slen; i++)
{
if (i != 0) self.out_substr(", ")!;
self.out_str(any { ptr, inner })!;
if (i != 0) len += self.out_substr(", ")!;
len += self.out_str(any { ptr, inner })!;
ptr += size;
}
self.out(']')!;
case BOOL:
return self.out_substr(*(bool*)arg.ptr ? "true" : "false");
len += self.out(']')!;
return len;
default:
if (self.print_with_function(arg)!) return;
return self.out_substr("Invalid type");
}
return self.out_substr("Invalid type");
}
@@ -400,6 +405,25 @@ fn usz! Formatter.vprintf(&self, String format, any[] anys)
self.out_char(current)!;
continue;
case 's':
PrintFlags flags = self.flags;
uint width = self.width;
defer {
self.flags = flags;
self.width = width;
}
self.flags = {};
self.width = 0;
if (flags.left)
{
usz len = self.out_str(current)!;
self.pad(' ', width, len)!;
continue;
}
OutputFn out_fn = self.out_fn;
self.out_fn = (OutputFn)&out_null_fn;
usz len = self.out_str(current)!;
self.out_fn = out_fn;
self.pad(' ', width, len)!;
self.out_str(current)!;
continue;
case 'p':
@@ -437,10 +461,6 @@ fn usz! Formatter.print(&self, String str)
// use null output function
self.out_fn = &out_null_fn;
}
usz len = str.len;
for (usz i = 0; i < len; i++)
{
self.out(str[i])!;
}
foreach (c : str) self.out(c)!;
return self.idx;
}
}