Skip to content

Commit

Permalink
[lib/util] Use Range<byte> in DataWriter
Browse files Browse the repository at this point in the history
  • Loading branch information
titzer committed Aug 15, 2024
1 parent 76a1347 commit 6222dc3
Show file tree
Hide file tree
Showing 13 changed files with 60 additions and 49 deletions.
2 changes: 1 addition & 1 deletion aeneas/src/mach/MachDataWriter.v3
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class MachDataWriter extends DataWriter {
}
def putmd(w: MachDataWriter) {
var p = this.pos;
putk(w.data, 0, w.end());
putr(w.alias());
for (l = w.refs; l != null; l = l.tail) {
var t = l.head;
refs = List.new((t.0, t.1 + p, t.2 + p), refs);
Expand Down
2 changes: 1 addition & 1 deletion aeneas/src/os/Linux.v3
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ class LinuxTarget extends Target {
var fd = System.fileOpen(file, false);
if (fd < 0) return prog.ERROR.OutputError(file);
// write the entire file from the buffer array
System.fileWriteK(fd, w.data, 0, w.end());
System.write(fd, w.alias());
System.fileClose(fd);
// change permissions to make binary executable
compiler.makeExecutable(file);
Expand Down
13 changes: 6 additions & 7 deletions aeneas/src/util/IO.v3
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,14 @@ class Buffer {
// Create a new buffer with {bufSize} bytes which flushes to {ffunc}.
new(bufSize, ffunc) {
var array = Array<byte>.new(bufSize);
writer = DataWriter.new().reset(array, 0, array.length);
writer = DataWriter.new().reset(array, 0, 0);
writer.refill = refill;
}
// Refill the {writer} with {size} bytes when full.
private def refill(writer: DataWriter, size: int) -> DataWriter {
if (size > writer.data.length) {
// a larger buffer is necessary
var ndata = Arrays.grow(writer.data, size + writer.data.length);
writer.reset(ndata, writer.pos, ndata.length);
writer.grow(size + writer.data.length);
} else {
// current buffer will suffice, but need to flush it
flush();
Expand All @@ -42,10 +41,10 @@ class Buffer {
}
// Flush any remaining data to the flush function.
def flush() {
if (writer.pos > 0) {
total = total + writer.pos;
ffunc(writer.data, 0, writer.pos);
writer.at(0);
var data = writer.extract(); // XXX: use alias() and refactor ffunc
if (data.length > 0) {
total += data.length;
ffunc(data, 0, data.length);
}
}
// Get the writer which can output to this buffer.
Expand Down
2 changes: 1 addition & 1 deletion aeneas/src/wasm/WasmTarget.v3
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,7 @@ class WasmTarget extends Target {
prog.ERROR.OutputError(fileName);
return null;
}
System.fileWriteK(fd, out.data, 0, out.end());
System.write(fd, out.alias());
System.fileClose(fd);
return out;
}
Expand Down
4 changes: 2 additions & 2 deletions aeneas/src/wasm/WasmType.v3
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ class WasmTypeTable(wasmType: Type -> WasmType) {
index = ++count;
rawMap[(before, len)] = index;
} else { // found, remove the new entry and remove the old one
buf.reset(buf.data, before, before);
buf.trim(before);
}
typeMap[sig] = index;
return u32.!(index - 1);
Expand All @@ -146,6 +146,6 @@ class WasmTypeTable(wasmType: Type -> WasmType) {
return true;
}
def emit(out: DataWriter) {
out.putk(buf.atEnd().data, 0, buf.pos);
out.putr(buf.alias());
}
}
2 changes: 1 addition & 1 deletion aeneas/src/x86-64/X86_64Darwin.v3
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ class X86_64DarwinTarget extends Target {
var fd = System.fileOpen(file, false);
if (fd < 0) return prog.ERROR.OutputError(file);
// write the entire file from the buffer array
System.fileWriteK(fd, w.data, 0, w.end());
System.write(fd, w.alias());
System.fileClose(fd);
// change permissions to make binary executable
compiler.makeExecutable(file);
Expand Down
2 changes: 1 addition & 1 deletion aeneas/src/x86/X86Darwin.v3
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ class X86DarwinTarget extends Target {
var fd = System.fileOpen(file, false);
if (fd < 0) return prog.ERROR.OutputError(file);
// write the entire file from the buffer array
System.fileWriteK(fd, w.data, 0, w.end());
System.write(fd, w.alias());
System.fileClose(fd);
// change permissions to make binary executable
compiler.makeExecutable(file);
Expand Down
2 changes: 1 addition & 1 deletion aeneas/test/BufferTest.v3
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def x(v: DataWriter, expect: string) {

def error(pos: int, expect: string) {
var dl = data.length, el = expect.length;
var b = StringBuilder.new().puts("x86 asm produced ");
var b = StringBuilder.new().puts("buffer has ");
var j = 0;
while (j < pos && j < dl) {
b.putx_8(data[j]); // append correct data
Expand Down
2 changes: 1 addition & 1 deletion bin/dev/aeneas
Original file line number Diff line number Diff line change
Expand Up @@ -428,7 +428,7 @@ function run_unit() {
else
TESTS="aeneas/test/*.v3"
fi
execute $V3C_LINK -fp -run $SRCS $TESTS $V3C_OPTS -version
execute $V3C_LINK -fp $V3C_OPTS -run $SRCS $TESTS -version
popd > /dev/null
}

Expand Down
31 changes: 17 additions & 14 deletions lib/util/DataWriter.v3
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
// can be overridden by changing the {refill} function. E.g. the {refill}
// function can be overridden to stream already-written bytes to I/O.
class DataWriter {
def var data: Array<byte>; // array containing data
def var data: Range<byte>; // array containing data
def var pos: int; // current position
private var max: int; // the maximum position ever accessed
var refill = DataWriter.growI2X; // refill behavior
Expand Down Expand Up @@ -177,40 +177,43 @@ class DataWriter {
if (data == null) {
data = Array<byte>.new(10 + nlength);
} else if (nlength > data.length) {
data = Arrays.grow(data, data.length * 2 + nlength);
data = Ranges.grow(data, data.length * 2 + nlength);
}
}
// Grow the internal storage of this data writer to the new length.
def grow(nlength: int) -> this {
if (data == null) data = Array<byte>.new(nlength);
else if (nlength > data.length) data = Arrays.grow(data, nlength);
else if (nlength > data.length) data = Ranges.grow(data, nlength);
}
// Get an alias for all data between {0} and {end()}.
def alias() -> Range<byte> {
return data[0 ... end()];
}
// Copy this data into a new, appropriately-sized array.
def copy() -> Array<byte> {
if (data == null) return [];
return Arrays.copy(data, Array<byte>.new(pos));
return Ranges.dup(data[0 ... end()]);
}
// Extract all data from this writer, leaving it empty.
// (This can be more efficient than copy() if the array is sized exactly)
def extract() -> Array<byte> {
if (data == null) return [];
var result = data;
if (pos != result.length) result = Arrays.copy(result, Array<byte>.new(pos)); // TODO: should this be max?
var result = Ranges.dup(data[0 ... end()]);
data = null;
pos = 0;
// TODO: max = 0; ?
pos = max = 0;
return result;
}
// Trim the data in this buffer to {npos} length.
def trim(npos: int) {
pos = max = npos;
}
// Send the data of this writer to the given function, avoiding an intermediate copy.
// Note that it is implementation dependent if {f} is called multiple times, e.g. if
// the internal storage is fragmented.
def send<R>(f: Range<byte> -> R) -> R {
return if(data != null, f(data[0 ... pos])); // TODO: should this be max?
var r = alias();
return if(r.length > 0, f(r));
}
// Clear all bytes to 0 and reset the position.
def clear() -> this {
pos = 0;
if (data == null) return;
pos = max = 0;
var x = data;
for (i < x.length) x[i] = 0;
}
Expand Down
9 changes: 9 additions & 0 deletions lib/util/Ranges.v3
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,13 @@ component Ranges {
r[r.length - i - 1] = tmp;
}
}
// Grow a {range} if it is smaller than {size}, returning either {range} or a new one.
def grow<T>(range: Range<T>, size: int) -> Range<T> {
if (size > range.length) {
var n = Array<T>.new(size), max = range.length;
for (i < max) n[i] = range[i];
return n;
}
return range;
}
}
30 changes: 15 additions & 15 deletions test/lib/DataWriterTest.v3
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,16 @@ def assertWrite<T>(t: LibTest, write: (DataWriter, T) -> DataWriter, val: T, byt
var w = DataWriter.new();

write(w, val); // first write
t.assertk(bytes, w.data, 0);
t.assertk(bytes, w.data);
var pos = w.pos;

write(w, val); // second write
t.assertk(bytes, w.data, pos);
t.assertk(bytes, w.data[pos ...]);
Arrays.copyInto(BG, FG, 0);
w.reset(FG, 4, FG.length);

write(w, val); // third write
t.assertk(bytes, w.data, 4);
t.assertk(bytes, w.data[4 ...]);
}

def tup2<T, U>(
Expand Down Expand Up @@ -320,10 +320,10 @@ def test_skipleb(t: LibTest) {
w.at(9);

w.at(1).overwrite_uleb32(1);
t.assertk([0x11, 0x81, 0x80, 0x80, 0x80, 0, 0x77], w.data, 0);
t.assertk([0x11, 0x81, 0x80, 0x80, 0x80, 0, 0x77], w.data);

w.at(1).overwrite_uleb32(1234567890);
t.assertk([0x11, 0xD2, 0x85, 0xD8, 0xCC, 0x04, 0x77], w.data, 0);
t.assertk([0x11, 0xD2, 0x85, 0xD8, 0xCC, 0x04, 0x77], w.data);

t.asserteq(9, w.atEnd().pos);
}
Expand All @@ -333,44 +333,44 @@ def test_range_32(t: LibTest) {
var data = Array<byte>.new(5);

DataWriters.write_range_i8(data, 0x88);
t.assertk([0x88, 0, 0, 0, 0], data, 0);
t.assertk([0x88, 0, 0, 0, 0], data);

DataWriters.write_range_u8(data[2 ...], 0x77);
t.assertk([0x88, 0, 0x77, 0, 0], data, 0);
t.assertk([0x88, 0, 0x77, 0, 0], data);

DataWriters.write_range_i16(data[3 ...], 0x3344);
t.assertk([0x88, 0, 0x77, 0x44, 0x33], data, 0);
t.assertk([0x88, 0, 0x77, 0x44, 0x33], data);

DataWriters.write_range_u16(data[2 ...], 0xAABB);
t.assertk([0x88, 0, 0xBB, 0xAA, 0x33], data, 0);
t.assertk([0x88, 0, 0xBB, 0xAA, 0x33], data);

DataWriters.write_range_i32(data, 0xFFEEDDCC);
t.assertk([0xCC, 0xDD, 0xEE, 0xFF, 0x33], data, 0);
t.assertk([0xCC, 0xDD, 0xEE, 0xFF, 0x33], data);

DataWriters.write_range_u32(data[1 ...], 0x11223344);
t.assertk([0xCC, 0x44, 0x33, 0x22, 0x11], data, 0);
t.assertk([0xCC, 0x44, 0x33, 0x22, 0x11], data);
}

def test_range_64(t: LibTest) {
var data = Array<byte>.new(9);

DataWriters.write_range_i64(data, 0x99887766_55443322);
t.assertk([0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00], data, 0);
t.assertk([0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x00], data);

DataWriters.write_range_u64(data[1 ...], 0x11223344_55667788);
t.assertk([0x22, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11], data, 0);
t.assertk([0x22, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11], data);
}

def test_range_float(t: LibTest) {
var data = Array<byte>.new(5);

DataWriters.write_range_float(data, float.view(0x55443322));
t.assertk([0x22, 0x33, 0x44, 0x55, 0x00], data, 0);
t.assertk([0x22, 0x33, 0x44, 0x55, 0x00], data);
}

def test_range_double(t: LibTest) {
var data = Array<byte>.new(9);

DataWriters.write_range_double(data[1 ...], double.view(0x11223344_55667788));
t.assertk([0x00, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11], data, 0);
t.assertk([0x00, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11], data);
}
8 changes: 4 additions & 4 deletions test/lib/main.v3
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,12 @@ class LibTest(prefix: string, name: string, func: LibTest -> void, tail: LibTest
for (i < a.length) if (a[i] != b[i]) return false;
return true;
}
def assertk(expected: string, got: Array<byte>, goffset: int) {
def assertk(expected: string, got: Range<byte>) {
if (got == null) return fail("expected string, got null");
if (got.length < (goffset + expected.length)) return fail("not enough data");
if (got.length < expected.length) return fail("not enough data");
for (i < expected.length) {
if (expected[i] != got[goffset + i]) {
return fail(Strings.format3("expected data[%d] == %x, got %x", i, expected[i], got[goffset + i]));
if (expected[i] != got[i]) {
return fail(Strings.format3("expected data[%d] == %x, got %x", i, expected[i], got[i]));
}
}
}
Expand Down

0 comments on commit 6222dc3

Please sign in to comment.