diff --git a/lib/std/bits.c3 b/lib/std/bits.c3 index 459f5d596..1be9b18ae 100644 --- a/lib/std/bits.c3 +++ b/lib/std/bits.c3 @@ -13,159 +13,159 @@ macro bswap(i) @builtin => $$bswap(i); macro uint[<*>].popcount(self) => $$popcount(self); macro uint[<*>].ctz(self) => $$ctz(self); macro uint[<*>].clz(self) => $$clz(self); -macro uint[<*>] uint[<*>].fshl(uint[<*>] hi, uint[<*>] lo, uint[<*>] shift) => $$fshl(hi, lo, shift); -macro uint[<*>] uint[<*>].fshr(uint[<*>] hi, uint[<*>] lo, uint[<*>] shift) => $$fshr(hi, lo, shift); +macro uint[<*>] uint[<*>].fshl(hi, uint[<*>] lo, uint[<*>] shift) => $$fshl(hi, lo, shift); +macro uint[<*>] uint[<*>].fshr(hi, uint[<*>] lo, uint[<*>] shift) => $$fshr(hi, lo, shift); macro uint[<*>] uint[<*>].rotl(self, uint[<*>] shift) => $$fshl(self, self, shift); macro uint[<*>] uint[<*>].rotr(self, uint[<*>] shift) => $$fshr(self, self, shift); macro int[<*>].popcount(self) => $$popcount(self); macro int[<*>].ctz(self) => $$ctz(self); macro int[<*>].clz(self) => $$clz(self); -macro int[<*>] int[<*>].fshl(int[<*>] hi, int[<*>] lo, int[<*>] shift) => $$fshl(hi, lo, shift); -macro int[<*>] int[<*>].fshr(int[<*>] hi, int[<*>] lo, int[<*>] shift) => $$fshr(hi, lo, shift); +macro int[<*>] int[<*>].fshl(hi, int[<*>] lo, int[<*>] shift) => $$fshl(hi, lo, shift); +macro int[<*>] int[<*>].fshr(hi, int[<*>] lo, int[<*>] shift) => $$fshr(hi, lo, shift); macro int[<*>] int[<*>].rotl(self, int[<*>] shift) => $$fshl(self, self, shift); macro int[<*>] int[<*>].rotr(self, int[<*>] shift) => $$fshr(self, self, shift); -macro ushort[<*>].popcount(ushort[<*>] self) => $$popcount(self); -macro ushort[<*>].ctz(ushort[<*>] self) => $$ctz(self); -macro ushort[<*>].clz(ushort[<*>] self) => $$clz(self); -macro ushort[<*>] ushort[<*>].fshl(ushort[<*>] hi, ushort[<*>] lo, ushort[<*>] shift) => $$fshl(hi, lo, shift); -macro ushort[<*>] ushort[<*>].fshr(ushort[<*>] hi, ushort[<*>] lo, ushort[<*>] shift) => $$fshr(hi, lo, shift); -macro ushort[<*>] ushort[<*>].rotl(ushort[<*>] self, ushort[<*>] shift) => $$fshl(self, self, shift); -macro ushort[<*>] ushort[<*>].rotr(ushort[<*>] self, ushort[<*>] shift) => $$fshr(self, self, shift); +macro ushort[<*>].popcount(self) => $$popcount(self); +macro ushort[<*>].ctz(self) => $$ctz(self); +macro ushort[<*>].clz(self) => $$clz(self); +macro ushort[<*>] ushort[<*>].fshl(hi, ushort[<*>] lo, ushort[<*>] shift) => $$fshl(hi, lo, shift); +macro ushort[<*>] ushort[<*>].fshr(hi, ushort[<*>] lo, ushort[<*>] shift) => $$fshr(hi, lo, shift); +macro ushort[<*>] ushort[<*>].rotl(self, ushort[<*>] shift) => $$fshl(self, self, shift); +macro ushort[<*>] ushort[<*>].rotr(self, ushort[<*>] shift) => $$fshr(self, self, shift); -macro short[<*>].popcount(short[<*>] self) => $$popcount(self); -macro short[<*>].ctz(short[<*>] self) => $$ctz(self); -macro short[<*>].clz(short[<*>] self) => $$clz(self); -macro short[<*>] short[<*>].fshl(short[<*>] hi, short[<*>] lo, short[<*>] shift) => $$fshl(hi, lo, shift); -macro short[<*>] short[<*>].fshr(short[<*>] hi, short[<*>] lo, short[<*>] shift) => $$fshr(hi, lo, shift); -macro short[<*>] short[<*>].rotl(short[<*>] self, short[<*>] shift) => $$fshl(self, self, shift); -macro short[<*>] short[<*>].rotr(short[<*>] self, short[<*>] shift) => $$fshr(self, self, shift); +macro short[<*>].popcount(self) => $$popcount(self); +macro short[<*>].ctz(self) => $$ctz(self); +macro short[<*>].clz(self) => $$clz(self); +macro short[<*>] short[<*>].fshl(hi, short[<*>] lo, short[<*>] shift) => $$fshl(hi, lo, shift); +macro short[<*>] short[<*>].fshr(hi, short[<*>] lo, short[<*>] shift) => $$fshr(hi, lo, shift); +macro short[<*>] short[<*>].rotl(self, short[<*>] shift) => $$fshl(self, self, shift); +macro short[<*>] short[<*>].rotr(self, short[<*>] shift) => $$fshr(self, self, shift); -macro char[<*>].popcount(char[<*>] self) => $$popcount(self); -macro char[<*>].ctz(char[<*>] self) => $$ctz(self); -macro char[<*>].clz(char[<*>] self) => $$clz(self); -macro char[<*>] char[<*>].fshl(char[<*>] hi, char[<*>] lo, char[<*>] shift) => $$fshl(hi, lo, shift); -macro char[<*>] char[<*>].fshr(char[<*>] hi, char[<*>] lo, char[<*>] shift) => $$fshr(hi, lo, shift); -macro char[<*>] char[<*>].rotl(char[<*>] self, char[<*>] shift) => $$fshl(self, self, shift); -macro char[<*>] char[<*>].rotr(char[<*>] self, char[<*>] shift) => $$fshr(self, self, shift); +macro char[<*>].popcount(self) => $$popcount(self); +macro char[<*>].ctz(self) => $$ctz(self); +macro char[<*>].clz(self) => $$clz(self); +macro char[<*>] char[<*>].fshl(hi, char[<*>] lo, char[<*>] shift) => $$fshl(hi, lo, shift); +macro char[<*>] char[<*>].fshr(hi, char[<*>] lo, char[<*>] shift) => $$fshr(hi, lo, shift); +macro char[<*>] char[<*>].rotl(self, char[<*>] shift) => $$fshl(self, self, shift); +macro char[<*>] char[<*>].rotr(self, char[<*>] shift) => $$fshr(self, self, shift); -macro ichar[<*>].popcount(ichar[<*>] self) => $$popcount(self); -macro ichar[<*>].ctz(ichar[<*>] self) => $$ctz(self); -macro ichar[<*>].clz(ichar[<*>] self) => $$clz(self); -macro ichar[<*>] ichar[<*>].fshl(ichar[<*>] hi, ichar[<*>] lo, ichar[<*>] shift) => $$fshl(hi, lo, shift); -macro ichar[<*>] ichar[<*>].fshr(ichar[<*>] hi, ichar[<*>] lo, ichar[<*>] shift) => $$fshr(hi, lo, shift); -macro ichar[<*>] ichar[<*>].rotl(ichar[<*>] self, ichar[<*>] shift) => $$fshl(self, self, shift); -macro ichar[<*>] ichar[<*>].rotr(ichar[<*>] self, ichar[<*>] shift) => $$fshr(self, self, shift); +macro ichar[<*>].popcount(self) => $$popcount(self); +macro ichar[<*>].ctz(self) => $$ctz(self); +macro ichar[<*>].clz(self) => $$clz(self); +macro ichar[<*>] ichar[<*>].fshl(hi, ichar[<*>] lo, ichar[<*>] shift) => $$fshl(hi, lo, shift); +macro ichar[<*>] ichar[<*>].fshr(hi, ichar[<*>] lo, ichar[<*>] shift) => $$fshr(hi, lo, shift); +macro ichar[<*>] ichar[<*>].rotl(self, ichar[<*>] shift) => $$fshl(self, self, shift); +macro ichar[<*>] ichar[<*>].rotr(self, ichar[<*>] shift) => $$fshr(self, self, shift); -macro ulong[<*>].popcount(ulong[<*>] self) => $$popcount(self); -macro ulong[<*>].ctz(ulong[<*>] self) => $$ctz(self); -macro ulong[<*>].clz(ulong[<*>] self) => $$clz(self); -macro ulong[<*>] ulong[<*>].fshl(ulong[<*>] hi, ulong[<*>] lo, ulong[<*>] shift) => $$fshl(hi, lo, shift); -macro ulong[<*>] ulong[<*>].fshr(ulong[<*>] hi, ulong[<*>] lo, ulong[<*>] shift) => $$fshr(hi, lo, shift); -macro ulong[<*>] ulong[<*>].rotl(ulong[<*>] self, ulong[<*>] shift) => $$fshl(self, self, shift); -macro ulong[<*>] ulong[<*>].rotr(ulong[<*>] self, ulong[<*>] shift) => $$fshr(self, self, shift); +macro ulong[<*>].popcount(self) => $$popcount(self); +macro ulong[<*>].ctz(self) => $$ctz(self); +macro ulong[<*>].clz(self) => $$clz(self); +macro ulong[<*>] ulong[<*>].fshl(hi, ulong[<*>] lo, ulong[<*>] shift) => $$fshl(hi, lo, shift); +macro ulong[<*>] ulong[<*>].fshr(hi, ulong[<*>] lo, ulong[<*>] shift) => $$fshr(hi, lo, shift); +macro ulong[<*>] ulong[<*>].rotl(self, ulong[<*>] shift) => $$fshl(self, self, shift); +macro ulong[<*>] ulong[<*>].rotr(self, ulong[<*>] shift) => $$fshr(self, self, shift); -macro long[<*>].popcount(long[<*>] self) => $$popcount(self); -macro long[<*>].ctz(long[<*>] self) => $$ctz(self); -macro long[<*>].clz(long[<*>] self) => $$clz(self); -macro long[<*>] long[<*>].fshl(long[<*>] hi, long[<*>] lo, long[<*>] shift) => $$fshl(hi, lo, shift); -macro long[<*>] long[<*>].fshr(long[<*>] hi, long[<*>] lo, long[<*>] shift) => $$fshr(hi, lo, shift); -macro long[<*>] long[<*>].rotl(long[<*>] self, long[<*>] shift) => $$fshl(self, self, shift); -macro long[<*>] long[<*>].rotr(long[<*>] self, long[<*>] shift) => $$fshr(self, self, shift); +macro long[<*>].popcount(self) => $$popcount(self); +macro long[<*>].ctz(self) => $$ctz(self); +macro long[<*>].clz(self) => $$clz(self); +macro long[<*>] long[<*>].fshl(hi, long[<*>] lo, long[<*>] shift) => $$fshl(hi, lo, shift); +macro long[<*>] long[<*>].fshr(hi, long[<*>] lo, long[<*>] shift) => $$fshr(hi, lo, shift); +macro long[<*>] long[<*>].rotl(self, long[<*>] shift) => $$fshl(self, self, shift); +macro long[<*>] long[<*>].rotr(self, long[<*>] shift) => $$fshr(self, self, shift); -macro uint128[<*>].popcount(uint128[<*>] self) => $$popcount(self); -macro uint128[<*>].ctz(uint128[<*>] self) => $$ctz(self); -macro uint128[<*>].clz(uint128[<*>] self) => $$clz(self); -macro uint128[<*>] uint128[<*>].fshl(uint128[<*>] hi, uint128[<*>] lo, uint128[<*>] shift) => $$fshl(hi, lo, shift); -macro uint128[<*>] uint128[<*>].fshr(uint128[<*>] hi, uint128[<*>] lo, uint128[<*>] shift) => $$fshr(hi, lo, shift); -macro uint128[<*>] uint128[<*>].rotl(uint128[<*>] self, uint128[<*>] shift) => $$fshl(self, self, shift); -macro uint128[<*>] uint128[<*>].rotr(uint128[<*>] self, uint128[<*>] shift) => $$fshr(self, self, shift); +macro uint128[<*>].popcount(self) => $$popcount(self); +macro uint128[<*>].ctz(self) => $$ctz(self); +macro uint128[<*>].clz(self) => $$clz(self); +macro uint128[<*>] uint128[<*>].fshl(hi, uint128[<*>] lo, uint128[<*>] shift) => $$fshl(hi, lo, shift); +macro uint128[<*>] uint128[<*>].fshr(hi, uint128[<*>] lo, uint128[<*>] shift) => $$fshr(hi, lo, shift); +macro uint128[<*>] uint128[<*>].rotl(self, uint128[<*>] shift) => $$fshl(self, self, shift); +macro uint128[<*>] uint128[<*>].rotr(self, uint128[<*>] shift) => $$fshr(self, self, shift); -macro int128[<*>].popcount(int128[<*>] self) => $$popcount(self); -macro int128[<*>].ctz(int128[<*>] self) => $$ctz(self); -macro int128[<*>].clz(int128[<*>] self) => $$clz(self); -macro int128[<*>] int128[<*>].fshl(int128[<*>] hi, int128[<*>] lo, int128[<*>] shift) => $$fshl(hi, lo, shift); -macro int128[<*>] int128[<*>].fshr(int128[<*>] hi, int128[<*>] lo, int128[<*>] shift) => $$fshr(hi, lo, shift); -macro int128[<*>] int128[<*>].rotl(int128[<*>] self, int128[<*>] shift) => $$fshl(self, self, shift); -macro int128[<*>] int128[<*>].rotr(int128[<*>] self, int128[<*>] shift) => $$fshr(self, self, shift); +macro int128[<*>].popcount(self) => $$popcount(self); +macro int128[<*>].ctz(self) => $$ctz(self); +macro int128[<*>].clz(self) => $$clz(self); +macro int128[<*>] int128[<*>].fshl(hi, int128[<*>] lo, int128[<*>] shift) => $$fshl(hi, lo, shift); +macro int128[<*>] int128[<*>].fshr(hi, int128[<*>] lo, int128[<*>] shift) => $$fshr(hi, lo, shift); +macro int128[<*>] int128[<*>].rotl(self, int128[<*>] shift) => $$fshl(self, self, shift); +macro int128[<*>] int128[<*>].rotr(self, int128[<*>] shift) => $$fshr(self, self, shift); macro uint.popcount(self) => $$popcount(self); macro uint.ctz(self) => $$ctz(self); macro uint.clz(self) => $$clz(self); -macro uint uint.fshl(uint hi, uint lo, uint shift) => $$fshl(hi, lo, shift); -macro uint uint.fshr(uint hi, uint lo, uint shift) => $$fshr(hi, lo, shift); -macro uint uint.rotl(uint self, uint shift) => $$fshl(self, self, shift); -macro uint uint.rotr(uint self, uint shift) => $$fshr(self, self, shift); +macro uint uint.fshl(hi, uint lo, uint shift) => $$fshl(hi, lo, shift); +macro uint uint.fshr(hi, uint lo, uint shift) => $$fshr(hi, lo, shift); +macro uint uint.rotl(self, uint shift) => $$fshl(self, self, shift); +macro uint uint.rotr(self, uint shift) => $$fshr(self, self, shift); macro int.popcount(self) => $$popcount(self); macro int.ctz(self) => $$ctz(self); macro int.clz(self) => $$clz(self); -macro int int.fshl(int hi, int lo, int shift) => $$fshl(hi, lo, shift); -macro int int.fshr(int hi, int lo, int shift) => $$fshr(hi, lo, shift); -macro int int.rotl(int self, int shift) => $$fshl(self, self, shift); -macro int int.rotr(int self, int shift) => $$fshr(self, self, shift); +macro int int.fshl(hi, int lo, int shift) => $$fshl(hi, lo, shift); +macro int int.fshr(hi, int lo, int shift) => $$fshr(hi, lo, shift); +macro int int.rotl(self, int shift) => $$fshl(self, self, shift); +macro int int.rotr(self, int shift) => $$fshr(self, self, shift); macro ushort.popcount(self) => $$popcount(self); macro ushort.ctz(self) => $$ctz(self); macro ushort.clz(self) => $$clz(self); -macro ushort ushort.fshl(ushort hi, ushort lo, ushort shift) => $$fshl(hi, lo, shift); -macro ushort ushort.fshr(ushort hi, ushort lo, ushort shift) => $$fshr(hi, lo, shift); -macro ushort ushort.rotl(ushort self, ushort shift) => $$fshl(self, self, shift); -macro ushort ushort.rotr(ushort self, ushort shift) => $$fshr(self, self, shift); +macro ushort ushort.fshl(hi, ushort lo, ushort shift) => $$fshl(hi, lo, shift); +macro ushort ushort.fshr(hi, ushort lo, ushort shift) => $$fshr(hi, lo, shift); +macro ushort ushort.rotl(self, ushort shift) => $$fshl(self, self, shift); +macro ushort ushort.rotr(self, ushort shift) => $$fshr(self, self, shift); macro short.popcount(self) => $$popcount(self); macro short.ctz(self) => $$ctz(self); macro short.clz(self) => $$clz(self); -macro short short.fshl(short hi, short lo, short shift) => $$fshl(hi, lo, shift); -macro short short.fshr(short hi, short lo, short shift) => $$fshr(hi, lo, shift); -macro short short.rotl(short self, short shift) => $$fshl(self, self, shift); -macro short short.rotr(short self, short shift) => $$fshr(self, self, shift); +macro short short.fshl(hi, short lo, short shift) => $$fshl(hi, lo, shift); +macro short short.fshr(hi, short lo, short shift) => $$fshr(hi, lo, shift); +macro short short.rotl(self, short shift) => $$fshl(self, self, shift); +macro short short.rotr(self, short shift) => $$fshr(self, self, shift); macro char.popcount(self) => $$popcount(self); macro char.ctz(self) => $$ctz(self); macro char.clz(self) => $$clz(self); -macro char char.fshl(char hi, char lo, char shift) => $$fshl(hi, lo, shift); -macro char char.fshr(char hi, char lo, char shift) => $$fshr(hi, lo, shift); -macro char char.rotl(char self, char shift) => $$fshl(self, self, shift); -macro char char.rotr(char self, char shift) => $$fshr(self, self, shift); +macro char char.fshl(hi, char lo, char shift) => $$fshl(hi, lo, shift); +macro char char.fshr(hi, char lo, char shift) => $$fshr(hi, lo, shift); +macro char char.rotl(self, char shift) => $$fshl(self, self, shift); +macro char char.rotr(self, char shift) => $$fshr(self, self, shift); macro ichar.popcount(self) => $$popcount(self); macro ichar.ctz(self) => $$ctz(self); macro ichar.clz(self) => $$clz(self); -macro ichar ichar.fshl(ichar hi, ichar lo, ichar shift) => $$fshl(hi, lo, shift); -macro ichar ichar.fshr(ichar hi, ichar lo, ichar shift) => $$fshr(hi, lo, shift); -macro ichar ichar.rotl(ichar self, ichar shift) => $$fshl(self, self, shift); -macro ichar ichar.rotr(ichar self, ichar shift) => $$fshr(self, self, shift); +macro ichar ichar.fshl(hi, ichar lo, ichar shift) => $$fshl(hi, lo, shift); +macro ichar ichar.fshr(hi, ichar lo, ichar shift) => $$fshr(hi, lo, shift); +macro ichar ichar.rotl(self, ichar shift) => $$fshl(self, self, shift); +macro ichar ichar.rotr(self, ichar shift) => $$fshr(self, self, shift); macro ulong.popcount(self) => $$popcount(self); macro ulong.ctz(self) => $$ctz(self); macro ulong.clz(self) => $$clz(self); -macro ulong ulong.fshl(ulong hi, ulong lo, ulong shift) => $$fshl(hi, lo, shift); -macro ulong ulong.fshr(ulong hi, ulong lo, ulong shift) => $$fshr(hi, lo, shift); -macro ulong ulong.rotl(ulong self, ulong shift) => $$fshl(self, self, shift); -macro ulong ulong.rotr(ulong self, ulong shift) => $$fshr(self, self, shift); +macro ulong ulong.fshl(hi, ulong lo, ulong shift) => $$fshl(hi, lo, shift); +macro ulong ulong.fshr(hi, ulong lo, ulong shift) => $$fshr(hi, lo, shift); +macro ulong ulong.rotl(self, ulong shift) => $$fshl(self, self, shift); +macro ulong ulong.rotr(self, ulong shift) => $$fshr(self, self, shift); macro long.popcount(self) => $$popcount(self); macro long.ctz(self) => $$ctz(self); macro long.clz(self) => $$clz(self); -macro long long.fshl(long hi, long lo, long shift) => $$fshl(hi, lo, shift); -macro long long.fshr(long hi, long lo, long shift) => $$fshr(hi, lo, shift); -macro long long.rotl(long self, long shift) => $$fshl(self, self, shift); -macro long long.rotr(long self, long shift) => $$fshr(self, self, shift); +macro long long.fshl(hi, long lo, long shift) => $$fshl(hi, lo, shift); +macro long long.fshr(hi, long lo, long shift) => $$fshr(hi, lo, shift); +macro long long.rotl(self, long shift) => $$fshl(self, self, shift); +macro long long.rotr(self, long shift) => $$fshr(self, self, shift); macro uint128.popcount(self) => $$popcount(self); macro uint128.ctz(self) => $$ctz(self); macro uint128.clz(self) => $$clz(self); -macro uint128 uint128.fshl(uint128 hi, uint128 lo, uint128 shift) => $$fshl(hi, lo, shift); -macro uint128 uint128.fshr(uint128 hi, uint128 lo, uint128 shift) => $$fshr(hi, lo, shift); +macro uint128 uint128.fshl(hi, uint128 lo, uint128 shift) => $$fshl(hi, lo, shift); +macro uint128 uint128.fshr(hi, uint128 lo, uint128 shift) => $$fshr(hi, lo, shift); macro uint128 uint128.rotl(self, uint128 shift) => $$fshl(self, self, shift); macro uint128 uint128.rotr(self, uint128 shift) => $$fshr(self, self, shift); macro int128.popcount(self) => $$popcount(self); macro int128.ctz(self) => $$ctz(self); macro int128.clz(self) => $$clz(self); -macro int128 int128.fshl(int128 hi, int128 lo, int128 shift) => $$fshl(hi, lo, shift); -macro int128 int128.fshr(int128 hi, int128 lo, int128 shift) => $$fshr(hi, lo, shift); +macro int128 int128.fshl(hi, int128 lo, int128 shift) => $$fshl(hi, lo, shift); +macro int128 int128.fshr(hi, int128 lo, int128 shift) => $$fshr(hi, lo, shift); macro int128 int128.rotl(self, int128 shift) => $$fshl(self, self, shift); macro int128 int128.rotr(self, int128 shift) => $$fshr(self, self, shift); diff --git a/lib/std/io/path.c3 b/lib/std/io/path.c3 index 1b8a00fab..3e5677420 100644 --- a/lib/std/io/path.c3 +++ b/lib/std/io/path.c3 @@ -409,19 +409,26 @@ fn String Path.root_directory(self) def PathWalker = fn bool(Path, bool is_dir, void*); -fn bool! Path.walk(self, PathWalker w, void* data, Allocator* using = mem::heap()) +/* + * Walk the path recursively. PathWalker is run on every file and + * directory found. Return true to abort the walk. + */ +fn bool! Path.walk(self, PathWalker w, void* data) { - Path abs = self.absolute(using)!; - defer abs.free(); - PathList files = ls(abs, .using = using)!; - foreach (f : files) + const PATH_MAX = 512; + @stack_mem(PATH_MAX; Allocator* using) { - if (f.as_str() == "." || f.as_str() == "..") continue; - f = abs.append(f.as_str(), using)!; - bool is_directory = is_dir(f); - if (w(f, is_directory, data)) return true; - if (is_directory && f.walk(w, data, using)!) return true; - } + Path abs = self.absolute(using)!; + PathList files = ls(abs, .using = using)!; + foreach (f : files) + { + if (f.as_str() == "." || f.as_str() == "..") continue; + f = abs.append(f.as_str(), using)!; + bool is_directory = is_dir(f); + if (w(f, is_directory, data)) return true; + if (is_directory && f.walk(w, data)!) return true; + } + }; return false; } diff --git a/lib/std/io/stream/buffer.c3 b/lib/std/io/stream/buffer.c3 index 8fd674025..84d6b0bd2 100644 --- a/lib/std/io/stream/buffer.c3 +++ b/lib/std/io/stream/buffer.c3 @@ -29,7 +29,7 @@ StreamInterface readbuffer_interface = { .read_byte_fn = fn(s) => ((ReadBuffer*)s.data).read_byte(), }; -fn String ReadBuffer.as_str(&self) +fn String ReadBuffer.as_str(&self) @inline { return (String)self.bytes[self.read_idx:self.write_idx - self.read_idx]; } @@ -60,7 +60,7 @@ fn char! ReadBuffer.read_byte(&self) return c; } -fn void! ReadBuffer.refill(&self) @local +fn void! ReadBuffer.refill(&self) @local @inline { self.read_idx = 0; self.write_idx = self.stream.read(self.bytes)!; @@ -95,7 +95,7 @@ StreamInterface writebuffer_interface = { .write_byte_fn = fn(s, char c) => ((WriteBuffer*)s.data).write_byte(c), }; -fn String WriteBuffer.as_str(&self) +fn String WriteBuffer.as_str(&self) @inline { return (String)self.bytes[:self.index]; } diff --git a/lib/std/io/stream/bytebuffer.c3 b/lib/std/io/stream/bytebuffer.c3 new file mode 100644 index 000000000..abeb4e499 --- /dev/null +++ b/lib/std/io/stream/bytebuffer.c3 @@ -0,0 +1,132 @@ +module std::io; +import std::math; + +struct ByteBuffer +{ + Allocator* allocator; + usz max_read; + char[] bytes; + usz read_idx; + usz write_idx; + bool has_last; +} + +/** + * ByteBuffer provides a streamable read/write buffer. + * max_read defines how many bytes might be kept before its internal buffer is shrinked. + * @require self.bytes.len == 0 "Buffer already initialized." + **/ +fn void! ByteBuffer.init(&self, usz max_read, usz initial_capacity = 16, Allocator* using = mem::heap()) +{ + *self = { .allocator = using, .max_read = max_read }; + initial_capacity = max(initial_capacity, 16); + self.grow(initial_capacity)!; +} + +fn void! ByteBuffer.tinit(&self, usz max_read, usz initial_capacity = 16) +{ + self.init(max_read, initial_capacity, mem::temp())!; +} + +fn void! ByteBuffer.free(&self) +{ + self.allocator.free(self.bytes)!; + *self = {}; +} + +fn Stream ByteBuffer.as_stream(&self) +{ + return { .fns = &bytebuffer_interface, .data = self }; +} + +StreamInterface bytebuffer_interface = { + .write_fn = fn(s, char[] bytes) => ((ByteBuffer*)s.data).write(bytes), + .write_byte_fn = fn(s, c) => ((ByteBuffer*)s.data).write_byte(c), + .read_fn = fn(s, char[] bytes) => ((ByteBuffer*)s.data).read(bytes), + .read_byte_fn = fn(s) => ((ByteBuffer*)s.data).read_byte(), + .pushback_byte_fn = fn(s) => ((ByteBuffer*)s.data).pushback_byte(), + .available_fn = fn(s) => ((ByteBuffer*)s.data).available(), +}; + +fn usz! ByteBuffer.write(&self, char[] bytes) +{ + usz cap = self.bytes.len - self.write_idx; + if (cap < bytes.len) self.grow(bytes.len)!; + self.bytes[self.write_idx:bytes.len] = bytes[..]; + self.write_idx += bytes.len; + return bytes.len; +} + +fn void! ByteBuffer.write_byte(&self, char c) +{ + usz cap = self.bytes.len - self.write_idx; + if (cap == 0) self.grow(1)!; + self.bytes[self.write_idx] = c; + self.write_idx++; +} + +fn usz! ByteBuffer.read(&self, char[] bytes) +{ + usz readable = self.write_idx - self.read_idx; + if (readable == 0) + { + self.has_last = false; + return IoError.EOF?; + } + usz n = min(readable, bytes.len); + bytes[:n] = self.bytes[self.read_idx:n]; + self.read_idx += n; + self.has_last = n > 0; + self.shrink(); + return n; +} + +fn char! ByteBuffer.read_byte(&self) +{ + usz readable = self.write_idx - self.read_idx; + if (readable == 0) + { + self.has_last = false; + return IoError.EOF?; + } + char c = self.bytes[self.read_idx]; + self.read_idx++; + self.has_last = true; + self.shrink(); + return c; +} + +/* + * Only the last byte of a successful read can be pushed back. + */ +fn void! ByteBuffer.pushback_byte(&self) +{ + if (!self.has_last) return IoError.EOF?; + assert(self.read_idx > 0); + self.read_idx--; + self.has_last = false; +} + +fn usz! ByteBuffer.available(&self) @inline +{ + return self.write_idx - self.read_idx; +} + +fn void! ByteBuffer.grow(&self, usz n) +{ + n = math::next_power_of_2(n); + char* p = realloc_aligned(self.bytes, n, .alignment = char.alignof, .using = self.allocator)!; + self.bytes = p[:n]; +} + +macro ByteBuffer.shrink(&self) +{ + if (self.read_idx >= self.max_read) + { + // Drop the read data besides the last byte (for pushback_byte). + usz readable = self.write_idx - self.read_idx; + self.bytes[:1 + readable] = self.bytes[self.read_idx - 1:1 + readable]; + self.write_idx = 1 + readable; + self.read_idx = 1; + } +} \ No newline at end of file diff --git a/lib/std/io/stream/bytereader.c3 b/lib/std/io/stream/bytereader.c3 index 6afd64e8b..2148999dd 100644 --- a/lib/std/io/stream/bytereader.c3 +++ b/lib/std/io/stream/bytereader.c3 @@ -1,5 +1,4 @@ module std::io; -import std::math; struct ByteReader { @@ -20,7 +19,7 @@ fn Stream ByteReader.as_stream(&self) fn usz! ByteReader.read(&self, char[] bytes) { if (self.index >= self.bytes.len) return IoError.EOF?; - usz len = math::min(self.bytes.len - self.index, bytes.len); + usz len = min(self.bytes.len - self.index, bytes.len); if (len == 0) return 0; mem::copy(bytes.ptr, &self.bytes[self.index], len); self.index += len; @@ -62,9 +61,9 @@ fn usz! ByteReader.write_stream(&self, Stream writer) return written; } -fn usz ByteReader.available(&self) +fn usz ByteReader.available(&self) @inline { - return math::max((isz)0, (isz)self.bytes.len - self.index); + return max(0, self.bytes.len - self.index); } StreamInterface bytereader_interface = { diff --git a/lib/std/io/stream/bytewriter.c3 b/lib/std/io/stream/bytewriter.c3 index def706707..e7bcd752a 100644 --- a/lib/std/io/stream/bytewriter.c3 +++ b/lib/std/io/stream/bytewriter.c3 @@ -44,7 +44,7 @@ fn void ByteWriter.destroy(&self) *self = { }; } -fn String ByteWriter.as_str(&self) +fn String ByteWriter.as_str(&self) @inline { return (String)self.bytes[:self.index]; } diff --git a/lib/std/io/stream/limitreader.c3 b/lib/std/io/stream/limitreader.c3 index 1f732662d..4e10dcdbc 100644 --- a/lib/std/io/stream/limitreader.c3 +++ b/lib/std/io/stream/limitreader.c3 @@ -25,7 +25,7 @@ fn Stream LimitReader.as_stream(&self) return { .fns = &limitreader_interface, .data = self }; } -fn usz LimitReader.available(&self) +fn usz LimitReader.available(&self) @inline { return self.limit; } diff --git a/test/unit/stdlib/io/bytebuffer.c3 b/test/unit/stdlib/io/bytebuffer.c3 new file mode 100644 index 000000000..055a882ad --- /dev/null +++ b/test/unit/stdlib/io/bytebuffer.c3 @@ -0,0 +1,29 @@ +module bytebuffer_test @test; +import std::io; + +fn void! write_read_test() +{ + ByteBuffer buffer; + buffer.init(0)!; + + buffer.write("hello")!; + + char[8] bytes; + usz n = buffer.read(bytes[..])!; + assert(n == 5); + assert((String)bytes[:n] == "hello"); + + buffer.write("hello world")!; + n = buffer.read(bytes[..])!; + assert(n == bytes.len); + assert((String)bytes[:n] == "hello wo"); + assert(buffer.read_idx == 1); + + char c = buffer.read_byte()!; + assert(c == 'r'); + buffer.pushback_byte()!; + + n = buffer.read(bytes[..])!; + assert((String)bytes[:n] == "rld"); + assert(buffer.read_idx == 1); +} \ No newline at end of file