From ddeb2c33796c98e054fe8b1ebbe127bb6c68ef78 Mon Sep 17 00:00:00 2001 From: Joshua Tenner Date: Thu, 18 Jul 2019 16:01:22 -0400 Subject: [PATCH 1/8] [Implement] Naive Buffer.concat --- assembly/buffer/index.ts | 37 +++++++++++++++++++++++++++++++++++++ assembly/node.d.ts | 2 ++ tests/buffer.spec.ts | 25 +++++++++++++++++++++++++ tests/node.js | 7 ++++--- 4 files changed, 68 insertions(+), 3 deletions(-) diff --git a/assembly/buffer/index.ts b/assembly/buffer/index.ts index 66866bf..c0239a3 100644 --- a/assembly/buffer/index.ts +++ b/assembly/buffer/index.ts @@ -1,6 +1,7 @@ import { BLOCK_MAXSIZE } from "rt/common"; import { E_INVALIDLENGTH, E_INDEXOUTOFRANGE } from "util/error"; import { Uint8Array } from "typedarray"; +import { Array } from "array"; export class Buffer extends Uint8Array { constructor(size: i32) { @@ -11,6 +12,42 @@ export class Buffer extends Uint8Array { return new Buffer(size); } + public static concat(items: T, length: i32): Buffer { + if (!isArray()) { + ERROR("Buffer.concat must accept an Array where T extends Array"); + } + assert(unchecked(items[0]) instanceof Uint8Array); // Can this be a static check? + + let size: usize = 0; + let itemCount = usize(items.length); + let itemsDataStart = items.dataStart; + + for (let i: usize = 0; i < itemCount; i++) { + let item = load(itemsDataStart + (i << alignof())); + if (item == 0) continue; + size += load(item, offsetof("dataLength")); + } + size = min(usize(length), size); + assert(items); + + let buffer = __alloc(size, idof()); + let result = changetype(__alloc(offsetof(), idof())); + + result.data = changetype(buffer); + result.dataStart = changetype(buffer); + let start: usize = result.dataStart; + for (let i: usize = 0; i < itemCount && size > 0; i++) { + let item = load(itemsDataStart + (i << alignof())); + if (item == 0) continue; + let count = min(size, load(item, offsetof("dataLength"))); + memory.copy(start, load(item, offsetof("dataStart")), count); + start += count; + size -= count; + } + + return result; + } + @unsafe public static allocUnsafe(size: i32): Buffer { // Node throws an error if size is less than 0 if (u32(size) > BLOCK_MAXSIZE) throw new RangeError(E_INVALIDLENGTH); diff --git a/assembly/node.d.ts b/assembly/node.d.ts index 80075a8..959e54b 100644 --- a/assembly/node.d.ts +++ b/assembly/node.d.ts @@ -3,4 +3,6 @@ declare class Buffer extends Uint8Array { static alloc(size: i32): Buffer; /** This method allocates a new Buffer of indicated size. This is unsafe because the data is not zeroed. */ static allocUnsafe(size: i32): Buffer; + /** This method concatenates an array of `U extends Uint8Array` objects. */ + static concat(list: T, totalLength: i32): Buffer; } diff --git a/tests/buffer.spec.ts b/tests/buffer.spec.ts index 1596845..4da408c 100644 --- a/tests/buffer.spec.ts +++ b/tests/buffer.spec.ts @@ -42,4 +42,29 @@ describe("buffer", () => { // TODO: expectFn(() => { Buffer.allocUnsafe(-1); }).toThrow(); // TODO: expectFn(() => { Buffer.allocUnsafe(BLOCK_MAXSIZE + 1); }).toThrow(); }); + + test("#concat", () => { + let list: Buffer[] = new Array(0); + for (let i = 0; i < 5; i++) { + let buff = Buffer.alloc(5 - i); + for (let j = 0; j < (5 - i); j++) { + buff[j] = u8(i); + } + list.push(buff); + } + let actual: Buffer = Buffer.concat(list, 15); + + let expected: Buffer = Buffer.alloc(15); + expected[5] = 1; + expected[6] = 1; + expected[7] = 1; + expected[8] = 1; + expected[9] = 2; + expected[10] = 2; + expected[11] = 2; + expected[12] = 3; + expected[13] = 3; + expected[14] = 4; + expect(actual.buffer).toStrictEqual(expected.buffer); + }); }); diff --git a/tests/node.js b/tests/node.js index 5117ef9..7a71d9b 100644 --- a/tests/node.js +++ b/tests/node.js @@ -41,14 +41,15 @@ class Reporter extends EmptyReporter { else process.stdout.write("Test : " + group.name + " -> " + test.name + " ❌ FAIL\n"); if (!test.pass) { - process.stdout.write("Actual : " + test.actual.message + "\n"); - process.stdout.write("Expected : " + test.expected.message + "\n"); + if (test.actual) process.stdout.write("Actual : " + test.actual.message + "\n"); + if (test.expected) process.stdout.write("Expected : " + test.expected.message + "\n"); } if (test.logs.length > 0) { test.logs.forEach((e, i) => { if (i > 0) process.stdout.write("\n"); - process.stdout.write("Log : " + e.value); + if (e.bytes) process.stdout.write("Log : " + Buffer.from(e.bytes).toString("hex")); + else process.stdout.write("Log : " + e.value); }); process.stdout.write("\n"); } From 6f5f8aa718e804c1d3d89361ad803127d0c4d285 Mon Sep 17 00:00:00 2001 From: Joshua Tenner Date: Fri, 19 Jul 2019 12:03:44 -0400 Subject: [PATCH 2/8] [Fix] Switch to Buffer[], remove excess changetype() --- assembly/buffer/index.ts | 11 +++-------- tests/buffer.spec.ts | 25 +++++++++++-------------- 2 files changed, 14 insertions(+), 22 deletions(-) diff --git a/assembly/buffer/index.ts b/assembly/buffer/index.ts index c0239a3..0e554cb 100644 --- a/assembly/buffer/index.ts +++ b/assembly/buffer/index.ts @@ -12,12 +12,7 @@ export class Buffer extends Uint8Array { return new Buffer(size); } - public static concat(items: T, length: i32): Buffer { - if (!isArray()) { - ERROR("Buffer.concat must accept an Array where T extends Array"); - } - assert(unchecked(items[0]) instanceof Uint8Array); // Can this be a static check? - + public static concat(items: Buffer[], length: i32): Buffer { let size: usize = 0; let itemCount = usize(items.length); let itemsDataStart = items.dataStart; @@ -34,7 +29,7 @@ export class Buffer extends Uint8Array { let result = changetype(__alloc(offsetof(), idof())); result.data = changetype(buffer); - result.dataStart = changetype(buffer); + result.dataStart = buffer; let start: usize = result.dataStart; for (let i: usize = 0; i < itemCount && size > 0; i++) { let item = load(itemsDataStart + (i << alignof())); @@ -55,7 +50,7 @@ export class Buffer extends Uint8Array { // This retains the pointer to the result Buffer. let result = changetype(__alloc(offsetof(), idof())); result.data = changetype(buffer); - result.dataStart = changetype(buffer); + result.dataStart = buffer; result.dataLength = size; return result; } diff --git a/tests/buffer.spec.ts b/tests/buffer.spec.ts index 4da408c..b6dfc5a 100644 --- a/tests/buffer.spec.ts +++ b/tests/buffer.spec.ts @@ -1,3 +1,9 @@ +function bufferFrom(values: i32[]): Buffer { + let buffer = new Buffer(values.length); + for (let i = 0; i < values.length; i++) buffer[i] = values[i]; + return buffer; +} + /** * This is the buffer test suite. For each prototype function, put a single test * function call here. @@ -9,8 +15,6 @@ * }); * }); */ -import { BLOCK_MAXSIZE } from "rt/common"; - describe("buffer", () => { test("#constructor", () => { expect(new Buffer(0)).toBeTruthy(); @@ -52,19 +56,12 @@ describe("buffer", () => { } list.push(buff); } - let actual: Buffer = Buffer.concat(list, 15); + let actual: Buffer = Buffer.concat(list, 15); + + let expected: Buffer = bufferFrom([0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 4]); - let expected: Buffer = Buffer.alloc(15); - expected[5] = 1; - expected[6] = 1; - expected[7] = 1; - expected[8] = 1; - expected[9] = 2; - expected[10] = 2; - expected[11] = 2; - expected[12] = 3; - expected[13] = 3; - expected[14] = 4; + // TODO: When as-pect releases 2.2.1 + // expect(actual).toStrictEqual(expected); expect(actual.buffer).toStrictEqual(expected.buffer); }); }); From 5cb8ea9aba0fce03b01ef087ce84b563613a14cc Mon Sep 17 00:00:00 2001 From: Joshua Tenner Date: Fri, 19 Jul 2019 12:13:13 -0400 Subject: [PATCH 3/8] [Types] Update signature --- assembly/node.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assembly/node.d.ts b/assembly/node.d.ts index 959e54b..2a6778c 100644 --- a/assembly/node.d.ts +++ b/assembly/node.d.ts @@ -4,5 +4,5 @@ declare class Buffer extends Uint8Array { /** This method allocates a new Buffer of indicated size. This is unsafe because the data is not zeroed. */ static allocUnsafe(size: i32): Buffer; /** This method concatenates an array of `U extends Uint8Array` objects. */ - static concat(list: T, totalLength: i32): Buffer; + static concat(list: Buffer[], totalLength: i32): Buffer; } From 2a87ef8bac95cd2078e3b18e3d1cac1b0fcfb943 Mon Sep 17 00:00:00 2001 From: Joshua Tenner Date: Wed, 31 Jul 2019 16:40:24 -0400 Subject: [PATCH 4/8] [Cleanup] concat --- assembly/buffer/index.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/assembly/buffer/index.ts b/assembly/buffer/index.ts index 0e554cb..94a2018 100644 --- a/assembly/buffer/index.ts +++ b/assembly/buffer/index.ts @@ -12,9 +12,12 @@ export class Buffer extends Uint8Array { return new Buffer(size); } - public static concat(items: Buffer[], length: i32): Buffer { + public static concat(items: Array, length: i32): Buffer { + // assert the list itself isn't null + assert(items != null); + let size: usize = 0; - let itemCount = usize(items.length); + let itemCount = items.length; let itemsDataStart = items.dataStart; for (let i: usize = 0; i < itemCount; i++) { @@ -22,8 +25,9 @@ export class Buffer extends Uint8Array { if (item == 0) continue; size += load(item, offsetof("dataLength")); } - size = min(usize(length), size); - assert(items); + + // account for passed concat buffer length + size = min(length, size); let buffer = __alloc(size, idof()); let result = changetype(__alloc(offsetof(), idof())); @@ -33,7 +37,7 @@ export class Buffer extends Uint8Array { let start: usize = result.dataStart; for (let i: usize = 0; i < itemCount && size > 0; i++) { let item = load(itemsDataStart + (i << alignof())); - if (item == 0) continue; + if (item == null) continue; let count = min(size, load(item, offsetof("dataLength"))); memory.copy(start, load(item, offsetof("dataStart")), count); start += count; From 98b5665041336503edfaea86a34b709ea771a6d8 Mon Sep 17 00:00:00 2001 From: Joshua Tenner Date: Thu, 12 Mar 2020 15:20:07 -0400 Subject: [PATCH 5/8] add generic parameter --- assembly/buffer/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assembly/buffer/index.ts b/assembly/buffer/index.ts index 2896497..27c5f4b 100644 --- a/assembly/buffer/index.ts +++ b/assembly/buffer/index.ts @@ -12,7 +12,7 @@ export class Buffer extends Uint8Array { return new Buffer(size); } - public static concat(items: Array, length: i32): Buffer { + public static concat(items: Array, length: i32): Buffer { // assert the list itself isn't null assert(items != null); From c4b6c4bf1b7dbf1302755e6e696ec854294e3b6f Mon Sep 17 00:00:00 2001 From: Joshua Tenner Date: Thu, 12 Mar 2020 15:28:43 -0400 Subject: [PATCH 6/8] remove excess type --- assembly/buffer/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/assembly/buffer/index.ts b/assembly/buffer/index.ts index 27c5f4b..9ba7730 100644 --- a/assembly/buffer/index.ts +++ b/assembly/buffer/index.ts @@ -29,7 +29,7 @@ export class Buffer extends Uint8Array { } // account for passed concat buffer length - size = min(length, size); + size = min(length, size); let arrayBuffer = __alloc(size, idof()); let result = __alloc(offsetof(), idof()); @@ -43,7 +43,7 @@ export class Buffer extends Uint8Array { let item = load(itemsDataStart + (i << alignof())); // if Buffer is null, continue if (item == 0) continue; - let count = min(size, load(item, offsetof("byteLength"))); + let count = min(size, load(item, offsetof("byteLength"))); memory.copy(start, load(item, offsetof("dataStart")), count); start += count; size -= count; From 14002b4f1ba4759819d48650460126683fdd2029 Mon Sep 17 00:00:00 2001 From: Joshua Tenner Date: Thu, 12 Mar 2020 16:20:28 -0400 Subject: [PATCH 7/8] update tests, add short path, update types to make length optional --- assembly/buffer/index.ts | 9 +++++---- assembly/node.d.ts | 2 +- tests/buffer.spec.ts | 8 +++----- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/assembly/buffer/index.ts b/assembly/buffer/index.ts index 9ba7730..9152c72 100644 --- a/assembly/buffer/index.ts +++ b/assembly/buffer/index.ts @@ -12,9 +12,9 @@ export class Buffer extends Uint8Array { return new Buffer(size); } - public static concat(items: Array, length: i32): Buffer { - // assert the list itself isn't null - assert(items != null); + public static concat(items: Array, length: i32 = i32.MAX_VALUE): Buffer { + if (items.length == 0) return new Buffer(0); + if (length < 0) throw new Error(E_INDEXOUTOFRANGE); let size: usize = 0; let itemCount = items.length; @@ -36,7 +36,8 @@ export class Buffer extends Uint8Array { // assemble the Buffer store(result, __retain(arrayBuffer), offsetof("buffer")); - store(result, arrayBuffer, offsetof("byteLength")); + store(result, arrayBuffer, offsetof("dataStart")); + store(result, size, offsetof("byteLength")); let start = arrayBuffer; for (let i: usize = 0; i32(i < itemCount) & i32(size > 0); i++) { diff --git a/assembly/node.d.ts b/assembly/node.d.ts index 04de807..656c24c 100644 --- a/assembly/node.d.ts +++ b/assembly/node.d.ts @@ -4,7 +4,7 @@ declare class Buffer extends Uint8Array { /** This method allocates a new Buffer of indicated size. This is unsafe because the data is not zeroed. */ static allocUnsafe(size: i32): Buffer; /** This method concatenates an array of `U extends Uint8Array` objects. */ - static concat(list: Buffer[], totalLength: i32): Buffer; + static concat(list: Buffer[], totalLength?: i32): Buffer; /** This method asserts a value is a Buffer object via `value instanceof Buffer`. */ static isBuffer(value: T): bool; /** Reads a signed integer at the designated offset. */ diff --git a/tests/buffer.spec.ts b/tests/buffer.spec.ts index bbeda36..2a9cd6b 100644 --- a/tests/buffer.spec.ts +++ b/tests/buffer.spec.ts @@ -64,13 +64,11 @@ describe("buffer", () => { } list.push(buff); } - let actual: Buffer = Buffer.concat(list, 15); + let actual = Buffer.concat(list, 15); - let expected: Buffer = create([0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 4]); + let expected = create([0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 4]); - // TODO: When as-pect releases 2.2.1 - // expect(actual).toStrictEqual(expected); - expect(actual.buffer).toStrictEqual(expected.buffer); + expect(actual).toStrictEqual(expected); }); test("#isBuffer", () => { From 4b03b516407673a5c8558b3d5543801c6098b3e9 Mon Sep 17 00:00:00 2001 From: Joshua Tenner Date: Thu, 12 Mar 2020 16:33:19 -0400 Subject: [PATCH 8/8] update test, remove types on expect calls --- tests/buffer.spec.ts | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/tests/buffer.spec.ts b/tests/buffer.spec.ts index 2a9cd6b..93818ef 100644 --- a/tests/buffer.spec.ts +++ b/tests/buffer.spec.ts @@ -36,7 +36,7 @@ describe("buffer", () => { expect(Buffer.alloc(10)).toBeTruthy(); expect(Buffer.alloc(10)).toHaveLength(10); let buff = Buffer.alloc(100); - for (let i = 0; i < buff.length; i++) expect(buff[i]).toBe(0); + for (let i = 0; i < buff.length; i++) expect(buff[i]).toBe(0); expect(buff.buffer).not.toBeNull(); expect(buff.byteLength).toBe(100); expect(() => { Buffer.alloc(-1); }).toThrow(); @@ -56,19 +56,18 @@ describe("buffer", () => { }); test("#concat", () => { - let list: Buffer[] = new Array(0); - for (let i = 0; i < 5; i++) { - let buff = Buffer.alloc(5 - i); - for (let j = 0; j < (5 - i); j++) { - buff[j] = u8(i); - } - list.push(buff); - } - let actual = Buffer.concat(list, 15); + let actual = Buffer.concat([ + create([0, 0, 0, 0, 0]), + create([1, 1, 1, 1]), + create([2, 2, 2]), + create([3, 3]), + create([4]), + create([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]), + ], 15); let expected = create([0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 4]); - expect(actual).toStrictEqual(expected); + expect(actual).toStrictEqual(expected); }); test("#isBuffer", () => { @@ -268,7 +267,7 @@ describe("buffer", () => { expect(buff.writeInt32LE(-559038737)).toBe(4); expect(buff.writeInt32LE(283033613,4)).toBe(8); let result = create([0xEF,0xBE,0xAD,0xDE,0x0d,0xc0,0xde,0x10]); - expect(buff).toStrictEqual(result); + expect(buff).toStrictEqual(result); expect(() => { let newBuff = new Buffer(1); newBuff.writeInt32LE(0);