Offload functions to worker threads with shared memory primitives for Node.js.
8
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: AtomicInt8, AtomicUint8, AtomicInt16, AtomicUint16, AtomicUint32, AtomicInt64, AtomicUint64

Devin Ivy 0d415a7c ff4c6308

+1032 -1
+10 -1
src/index.ts
··· 2 2 export { Task } from './task.ts'; 3 3 export { workerPool } from './worker-pool.ts'; 4 4 export type { Runner } from './runner.ts'; 5 - export { AtomicInt32 } from './sync/index.ts'; 5 + export { 6 + AtomicInt8, 7 + AtomicUint8, 8 + AtomicInt16, 9 + AtomicUint16, 10 + AtomicInt32, 11 + AtomicUint32, 12 + AtomicInt64, 13 + AtomicUint64, 14 + } from './sync/index.ts';
+46
src/sync/atomic-int16.ts
··· 1 + export class AtomicInt16 { 2 + static readonly byteSize = 2; 3 + private readonly view: Int16Array; 4 + 5 + constructor(buffer?: SharedArrayBuffer, byteOffset?: number) { 6 + const buf = buffer ?? new SharedArrayBuffer(2); 7 + const offset = byteOffset ?? 0; 8 + this.view = new Int16Array(buf, offset, 1); 9 + } 10 + 11 + load(): number { 12 + return Atomics.load(this.view, 0); 13 + } 14 + 15 + store(value: number): void { 16 + Atomics.store(this.view, 0, value); 17 + } 18 + 19 + add(value: number): number { 20 + return Atomics.add(this.view, 0, value); 21 + } 22 + 23 + sub(value: number): number { 24 + return Atomics.sub(this.view, 0, value); 25 + } 26 + 27 + and(value: number): number { 28 + return Atomics.and(this.view, 0, value); 29 + } 30 + 31 + or(value: number): number { 32 + return Atomics.or(this.view, 0, value); 33 + } 34 + 35 + xor(value: number): number { 36 + return Atomics.xor(this.view, 0, value); 37 + } 38 + 39 + exchange(value: number): number { 40 + return Atomics.exchange(this.view, 0, value); 41 + } 42 + 43 + compareExchange(expected: number, replacement: number): number { 44 + return Atomics.compareExchange(this.view, 0, expected, replacement); 45 + } 46 + }
+46
src/sync/atomic-int64.ts
··· 1 + export class AtomicInt64 { 2 + static readonly byteSize = 8; 3 + private readonly view: BigInt64Array; 4 + 5 + constructor(buffer?: SharedArrayBuffer, byteOffset?: number) { 6 + const buf = buffer ?? new SharedArrayBuffer(8); 7 + const offset = byteOffset ?? 0; 8 + this.view = new BigInt64Array(buf, offset, 1); 9 + } 10 + 11 + load(): bigint { 12 + return Atomics.load(this.view, 0); 13 + } 14 + 15 + store(value: bigint): void { 16 + Atomics.store(this.view, 0, value); 17 + } 18 + 19 + add(value: bigint): bigint { 20 + return Atomics.add(this.view, 0, value); 21 + } 22 + 23 + sub(value: bigint): bigint { 24 + return Atomics.sub(this.view, 0, value); 25 + } 26 + 27 + and(value: bigint): bigint { 28 + return Atomics.and(this.view, 0, value); 29 + } 30 + 31 + or(value: bigint): bigint { 32 + return Atomics.or(this.view, 0, value); 33 + } 34 + 35 + xor(value: bigint): bigint { 36 + return Atomics.xor(this.view, 0, value); 37 + } 38 + 39 + exchange(value: bigint): bigint { 40 + return Atomics.exchange(this.view, 0, value); 41 + } 42 + 43 + compareExchange(expected: bigint, replacement: bigint): bigint { 44 + return Atomics.compareExchange(this.view, 0, expected, replacement); 45 + } 46 + }
+46
src/sync/atomic-int8.ts
··· 1 + export class AtomicInt8 { 2 + static readonly byteSize = 1; 3 + private readonly view: Int8Array; 4 + 5 + constructor(buffer?: SharedArrayBuffer, byteOffset?: number) { 6 + const buf = buffer ?? new SharedArrayBuffer(1); 7 + const offset = byteOffset ?? 0; 8 + this.view = new Int8Array(buf, offset, 1); 9 + } 10 + 11 + load(): number { 12 + return Atomics.load(this.view, 0); 13 + } 14 + 15 + store(value: number): void { 16 + Atomics.store(this.view, 0, value); 17 + } 18 + 19 + add(value: number): number { 20 + return Atomics.add(this.view, 0, value); 21 + } 22 + 23 + sub(value: number): number { 24 + return Atomics.sub(this.view, 0, value); 25 + } 26 + 27 + and(value: number): number { 28 + return Atomics.and(this.view, 0, value); 29 + } 30 + 31 + or(value: number): number { 32 + return Atomics.or(this.view, 0, value); 33 + } 34 + 35 + xor(value: number): number { 36 + return Atomics.xor(this.view, 0, value); 37 + } 38 + 39 + exchange(value: number): number { 40 + return Atomics.exchange(this.view, 0, value); 41 + } 42 + 43 + compareExchange(expected: number, replacement: number): number { 44 + return Atomics.compareExchange(this.view, 0, expected, replacement); 45 + } 46 + }
+46
src/sync/atomic-uint16.ts
··· 1 + export class AtomicUint16 { 2 + static readonly byteSize = 2; 3 + private readonly view: Uint16Array; 4 + 5 + constructor(buffer?: SharedArrayBuffer, byteOffset?: number) { 6 + const buf = buffer ?? new SharedArrayBuffer(2); 7 + const offset = byteOffset ?? 0; 8 + this.view = new Uint16Array(buf, offset, 1); 9 + } 10 + 11 + load(): number { 12 + return Atomics.load(this.view, 0); 13 + } 14 + 15 + store(value: number): void { 16 + Atomics.store(this.view, 0, value); 17 + } 18 + 19 + add(value: number): number { 20 + return Atomics.add(this.view, 0, value); 21 + } 22 + 23 + sub(value: number): number { 24 + return Atomics.sub(this.view, 0, value); 25 + } 26 + 27 + and(value: number): number { 28 + return Atomics.and(this.view, 0, value); 29 + } 30 + 31 + or(value: number): number { 32 + return Atomics.or(this.view, 0, value); 33 + } 34 + 35 + xor(value: number): number { 36 + return Atomics.xor(this.view, 0, value); 37 + } 38 + 39 + exchange(value: number): number { 40 + return Atomics.exchange(this.view, 0, value); 41 + } 42 + 43 + compareExchange(expected: number, replacement: number): number { 44 + return Atomics.compareExchange(this.view, 0, expected, replacement); 45 + } 46 + }
+46
src/sync/atomic-uint32.ts
··· 1 + export class AtomicUint32 { 2 + static readonly byteSize = 4; 3 + private readonly view: Uint32Array; 4 + 5 + constructor(buffer?: SharedArrayBuffer, byteOffset?: number) { 6 + const buf = buffer ?? new SharedArrayBuffer(4); 7 + const offset = byteOffset ?? 0; 8 + this.view = new Uint32Array(buf, offset, 1); 9 + } 10 + 11 + load(): number { 12 + return Atomics.load(this.view, 0); 13 + } 14 + 15 + store(value: number): void { 16 + Atomics.store(this.view, 0, value); 17 + } 18 + 19 + add(value: number): number { 20 + return Atomics.add(this.view, 0, value); 21 + } 22 + 23 + sub(value: number): number { 24 + return Atomics.sub(this.view, 0, value); 25 + } 26 + 27 + and(value: number): number { 28 + return Atomics.and(this.view, 0, value); 29 + } 30 + 31 + or(value: number): number { 32 + return Atomics.or(this.view, 0, value); 33 + } 34 + 35 + xor(value: number): number { 36 + return Atomics.xor(this.view, 0, value); 37 + } 38 + 39 + exchange(value: number): number { 40 + return Atomics.exchange(this.view, 0, value); 41 + } 42 + 43 + compareExchange(expected: number, replacement: number): number { 44 + return Atomics.compareExchange(this.view, 0, expected, replacement); 45 + } 46 + }
+46
src/sync/atomic-uint64.ts
··· 1 + export class AtomicUint64 { 2 + static readonly byteSize = 8; 3 + private readonly view: BigUint64Array; 4 + 5 + constructor(buffer?: SharedArrayBuffer, byteOffset?: number) { 6 + const buf = buffer ?? new SharedArrayBuffer(8); 7 + const offset = byteOffset ?? 0; 8 + this.view = new BigUint64Array(buf, offset, 1); 9 + } 10 + 11 + load(): bigint { 12 + return Atomics.load(this.view, 0); 13 + } 14 + 15 + store(value: bigint): void { 16 + Atomics.store(this.view, 0, value); 17 + } 18 + 19 + add(value: bigint): bigint { 20 + return Atomics.add(this.view, 0, value); 21 + } 22 + 23 + sub(value: bigint): bigint { 24 + return Atomics.sub(this.view, 0, value); 25 + } 26 + 27 + and(value: bigint): bigint { 28 + return Atomics.and(this.view, 0, value); 29 + } 30 + 31 + or(value: bigint): bigint { 32 + return Atomics.or(this.view, 0, value); 33 + } 34 + 35 + xor(value: bigint): bigint { 36 + return Atomics.xor(this.view, 0, value); 37 + } 38 + 39 + exchange(value: bigint): bigint { 40 + return Atomics.exchange(this.view, 0, value); 41 + } 42 + 43 + compareExchange(expected: bigint, replacement: bigint): bigint { 44 + return Atomics.compareExchange(this.view, 0, expected, replacement); 45 + } 46 + }
+46
src/sync/atomic-uint8.ts
··· 1 + export class AtomicUint8 { 2 + static readonly byteSize = 1; 3 + private readonly view: Uint8Array; 4 + 5 + constructor(buffer?: SharedArrayBuffer, byteOffset?: number) { 6 + const buf = buffer ?? new SharedArrayBuffer(1); 7 + const offset = byteOffset ?? 0; 8 + this.view = new Uint8Array(buf, offset, 1); 9 + } 10 + 11 + load(): number { 12 + return Atomics.load(this.view, 0); 13 + } 14 + 15 + store(value: number): void { 16 + Atomics.store(this.view, 0, value); 17 + } 18 + 19 + add(value: number): number { 20 + return Atomics.add(this.view, 0, value); 21 + } 22 + 23 + sub(value: number): number { 24 + return Atomics.sub(this.view, 0, value); 25 + } 26 + 27 + and(value: number): number { 28 + return Atomics.and(this.view, 0, value); 29 + } 30 + 31 + or(value: number): number { 32 + return Atomics.or(this.view, 0, value); 33 + } 34 + 35 + xor(value: number): number { 36 + return Atomics.xor(this.view, 0, value); 37 + } 38 + 39 + exchange(value: number): number { 40 + return Atomics.exchange(this.view, 0, value); 41 + } 42 + 43 + compareExchange(expected: number, replacement: number): number { 44 + return Atomics.compareExchange(this.view, 0, expected, replacement); 45 + } 46 + }
+7
src/sync/index.ts
··· 1 + export { AtomicInt8 } from './atomic-int8.ts'; 2 + export { AtomicUint8 } from './atomic-uint8.ts'; 3 + export { AtomicInt16 } from './atomic-int16.ts'; 4 + export { AtomicUint16 } from './atomic-uint16.ts'; 1 5 export { AtomicInt32 } from './atomic-int32.ts'; 6 + export { AtomicUint32 } from './atomic-uint32.ts'; 7 + export { AtomicInt64 } from './atomic-int64.ts'; 8 + export { AtomicUint64 } from './atomic-uint64.ts';
+99
test/sync/atomic-int16.test.ts
··· 1 + import { describe, it } from 'node:test'; 2 + import assert from 'node:assert/strict'; 3 + import { AtomicInt16 } from 'moroutine'; 4 + 5 + describe('AtomicInt16', () => { 6 + it('self-allocates and initializes to zero', () => { 7 + const a = new AtomicInt16(); 8 + assert.equal(a.load(), 0); 9 + }); 10 + 11 + it('stores and loads a value', () => { 12 + const a = new AtomicInt16(); 13 + a.store(1000); 14 + assert.equal(a.load(), 1000); 15 + }); 16 + 17 + it('accepts an external buffer and byteOffset', () => { 18 + const buffer = new SharedArrayBuffer(8); 19 + const a = new AtomicInt16(buffer, 4); 20 + a.store(1000); 21 + const view = new Int16Array(buffer, 4, 1); 22 + assert.equal(view[0], 1000); 23 + }); 24 + 25 + it('defaults byteOffset to 0', () => { 26 + const buffer = new SharedArrayBuffer(2); 27 + const a = new AtomicInt16(buffer); 28 + a.store(7); 29 + assert.equal(new Int16Array(buffer)[0], 7); 30 + }); 31 + 32 + it('exposes static byteSize of 2', () => { 33 + assert.equal(AtomicInt16.byteSize, 2); 34 + }); 35 + 36 + it('add returns previous value and updates', () => { 37 + const a = new AtomicInt16(); 38 + a.store(10); 39 + const prev = a.add(5); 40 + assert.equal(prev, 10); 41 + assert.equal(a.load(), 15); 42 + }); 43 + 44 + it('sub returns previous value and updates', () => { 45 + const a = new AtomicInt16(); 46 + a.store(10); 47 + const prev = a.sub(3); 48 + assert.equal(prev, 10); 49 + assert.equal(a.load(), 7); 50 + }); 51 + 52 + it('and returns previous value and updates', () => { 53 + const a = new AtomicInt16(); 54 + a.store(0b1100); 55 + const prev = a.and(0b1010); 56 + assert.equal(prev, 0b1100); 57 + assert.equal(a.load(), 0b1000); 58 + }); 59 + 60 + it('or returns previous value and updates', () => { 61 + const a = new AtomicInt16(); 62 + a.store(0b1100); 63 + const prev = a.or(0b0011); 64 + assert.equal(prev, 0b1100); 65 + assert.equal(a.load(), 0b1111); 66 + }); 67 + 68 + it('xor returns previous value and updates', () => { 69 + const a = new AtomicInt16(); 70 + a.store(0b1100); 71 + const prev = a.xor(0b1010); 72 + assert.equal(prev, 0b1100); 73 + assert.equal(a.load(), 0b0110); 74 + }); 75 + 76 + it('exchange returns previous value and sets new', () => { 77 + const a = new AtomicInt16(); 78 + a.store(1000); 79 + const prev = a.exchange(2000); 80 + assert.equal(prev, 1000); 81 + assert.equal(a.load(), 2000); 82 + }); 83 + 84 + it('compareExchange succeeds when expected matches', () => { 85 + const a = new AtomicInt16(); 86 + a.store(1000); 87 + const actual = a.compareExchange(1000, 2000); 88 + assert.equal(actual, 1000); 89 + assert.equal(a.load(), 2000); 90 + }); 91 + 92 + it('compareExchange fails when expected does not match', () => { 93 + const a = new AtomicInt16(); 94 + a.store(1000); 95 + const actual = a.compareExchange(0, 2000); 96 + assert.equal(actual, 1000); 97 + assert.equal(a.load(), 1000); 98 + }); 99 + });
+99
test/sync/atomic-int64.test.ts
··· 1 + import { describe, it } from 'node:test'; 2 + import assert from 'node:assert/strict'; 3 + import { AtomicInt64 } from 'moroutine'; 4 + 5 + describe('AtomicInt64', () => { 6 + it('self-allocates and initializes to zero', () => { 7 + const a = new AtomicInt64(); 8 + assert.equal(a.load(), 0n); 9 + }); 10 + 11 + it('stores and loads a value', () => { 12 + const a = new AtomicInt64(); 13 + a.store(9000000000000n); 14 + assert.equal(a.load(), 9000000000000n); 15 + }); 16 + 17 + it('accepts an external buffer and byteOffset', () => { 18 + const buffer = new SharedArrayBuffer(16); 19 + const a = new AtomicInt64(buffer, 8); 20 + a.store(9000000000000n); 21 + const view = new BigInt64Array(buffer, 8, 1); 22 + assert.equal(view[0], 9000000000000n); 23 + }); 24 + 25 + it('defaults byteOffset to 0', () => { 26 + const buffer = new SharedArrayBuffer(8); 27 + const a = new AtomicInt64(buffer); 28 + a.store(7n); 29 + assert.equal(new BigInt64Array(buffer)[0], 7n); 30 + }); 31 + 32 + it('exposes static byteSize of 8', () => { 33 + assert.equal(AtomicInt64.byteSize, 8); 34 + }); 35 + 36 + it('add returns previous value and updates', () => { 37 + const a = new AtomicInt64(); 38 + a.store(10n); 39 + const prev = a.add(5n); 40 + assert.equal(prev, 10n); 41 + assert.equal(a.load(), 15n); 42 + }); 43 + 44 + it('sub returns previous value and updates', () => { 45 + const a = new AtomicInt64(); 46 + a.store(10n); 47 + const prev = a.sub(3n); 48 + assert.equal(prev, 10n); 49 + assert.equal(a.load(), 7n); 50 + }); 51 + 52 + it('and returns previous value and updates', () => { 53 + const a = new AtomicInt64(); 54 + a.store(0b1100n); 55 + const prev = a.and(0b1010n); 56 + assert.equal(prev, 0b1100n); 57 + assert.equal(a.load(), 0b1000n); 58 + }); 59 + 60 + it('or returns previous value and updates', () => { 61 + const a = new AtomicInt64(); 62 + a.store(0b1100n); 63 + const prev = a.or(0b0011n); 64 + assert.equal(prev, 0b1100n); 65 + assert.equal(a.load(), 0b1111n); 66 + }); 67 + 68 + it('xor returns previous value and updates', () => { 69 + const a = new AtomicInt64(); 70 + a.store(0b1100n); 71 + const prev = a.xor(0b1010n); 72 + assert.equal(prev, 0b1100n); 73 + assert.equal(a.load(), 0b0110n); 74 + }); 75 + 76 + it('exchange returns previous value and sets new', () => { 77 + const a = new AtomicInt64(); 78 + a.store(9000000000000n); 79 + const prev = a.exchange(99n); 80 + assert.equal(prev, 9000000000000n); 81 + assert.equal(a.load(), 99n); 82 + }); 83 + 84 + it('compareExchange succeeds when expected matches', () => { 85 + const a = new AtomicInt64(); 86 + a.store(9000000000000n); 87 + const actual = a.compareExchange(9000000000000n, 99n); 88 + assert.equal(actual, 9000000000000n); 89 + assert.equal(a.load(), 99n); 90 + }); 91 + 92 + it('compareExchange fails when expected does not match', () => { 93 + const a = new AtomicInt64(); 94 + a.store(9000000000000n); 95 + const actual = a.compareExchange(0n, 99n); 96 + assert.equal(actual, 9000000000000n); 97 + assert.equal(a.load(), 9000000000000n); 98 + }); 99 + });
+99
test/sync/atomic-int8.test.ts
··· 1 + import { describe, it } from 'node:test'; 2 + import assert from 'node:assert/strict'; 3 + import { AtomicInt8 } from 'moroutine'; 4 + 5 + describe('AtomicInt8', () => { 6 + it('self-allocates and initializes to zero', () => { 7 + const a = new AtomicInt8(); 8 + assert.equal(a.load(), 0); 9 + }); 10 + 11 + it('stores and loads a value', () => { 12 + const a = new AtomicInt8(); 13 + a.store(42); 14 + assert.equal(a.load(), 42); 15 + }); 16 + 17 + it('accepts an external buffer and byteOffset', () => { 18 + const buffer = new SharedArrayBuffer(8); 19 + const a = new AtomicInt8(buffer, 4); 20 + a.store(42); 21 + const view = new Int8Array(buffer, 4, 1); 22 + assert.equal(view[0], 42); 23 + }); 24 + 25 + it('defaults byteOffset to 0', () => { 26 + const buffer = new SharedArrayBuffer(1); 27 + const a = new AtomicInt8(buffer); 28 + a.store(7); 29 + assert.equal(new Int8Array(buffer)[0], 7); 30 + }); 31 + 32 + it('exposes static byteSize of 1', () => { 33 + assert.equal(AtomicInt8.byteSize, 1); 34 + }); 35 + 36 + it('add returns previous value and updates', () => { 37 + const a = new AtomicInt8(); 38 + a.store(10); 39 + const prev = a.add(5); 40 + assert.equal(prev, 10); 41 + assert.equal(a.load(), 15); 42 + }); 43 + 44 + it('sub returns previous value and updates', () => { 45 + const a = new AtomicInt8(); 46 + a.store(10); 47 + const prev = a.sub(3); 48 + assert.equal(prev, 10); 49 + assert.equal(a.load(), 7); 50 + }); 51 + 52 + it('and returns previous value and updates', () => { 53 + const a = new AtomicInt8(); 54 + a.store(0b1100); 55 + const prev = a.and(0b1010); 56 + assert.equal(prev, 0b1100); 57 + assert.equal(a.load(), 0b1000); 58 + }); 59 + 60 + it('or returns previous value and updates', () => { 61 + const a = new AtomicInt8(); 62 + a.store(0b1100); 63 + const prev = a.or(0b0011); 64 + assert.equal(prev, 0b1100); 65 + assert.equal(a.load(), 0b1111); 66 + }); 67 + 68 + it('xor returns previous value and updates', () => { 69 + const a = new AtomicInt8(); 70 + a.store(0b1100); 71 + const prev = a.xor(0b1010); 72 + assert.equal(prev, 0b1100); 73 + assert.equal(a.load(), 0b0110); 74 + }); 75 + 76 + it('exchange returns previous value and sets new', () => { 77 + const a = new AtomicInt8(); 78 + a.store(42); 79 + const prev = a.exchange(99); 80 + assert.equal(prev, 42); 81 + assert.equal(a.load(), 99); 82 + }); 83 + 84 + it('compareExchange succeeds when expected matches', () => { 85 + const a = new AtomicInt8(); 86 + a.store(42); 87 + const actual = a.compareExchange(42, 99); 88 + assert.equal(actual, 42); 89 + assert.equal(a.load(), 99); 90 + }); 91 + 92 + it('compareExchange fails when expected does not match', () => { 93 + const a = new AtomicInt8(); 94 + a.store(42); 95 + const actual = a.compareExchange(0, 99); 96 + assert.equal(actual, 42); 97 + assert.equal(a.load(), 42); 98 + }); 99 + });
+99
test/sync/atomic-uint16.test.ts
··· 1 + import { describe, it } from 'node:test'; 2 + import assert from 'node:assert/strict'; 3 + import { AtomicUint16 } from 'moroutine'; 4 + 5 + describe('AtomicUint16', () => { 6 + it('self-allocates and initializes to zero', () => { 7 + const a = new AtomicUint16(); 8 + assert.equal(a.load(), 0); 9 + }); 10 + 11 + it('stores and loads a value', () => { 12 + const a = new AtomicUint16(); 13 + a.store(50000); 14 + assert.equal(a.load(), 50000); 15 + }); 16 + 17 + it('accepts an external buffer and byteOffset', () => { 18 + const buffer = new SharedArrayBuffer(8); 19 + const a = new AtomicUint16(buffer, 4); 20 + a.store(50000); 21 + const view = new Uint16Array(buffer, 4, 1); 22 + assert.equal(view[0], 50000); 23 + }); 24 + 25 + it('defaults byteOffset to 0', () => { 26 + const buffer = new SharedArrayBuffer(2); 27 + const a = new AtomicUint16(buffer); 28 + a.store(7); 29 + assert.equal(new Uint16Array(buffer)[0], 7); 30 + }); 31 + 32 + it('exposes static byteSize of 2', () => { 33 + assert.equal(AtomicUint16.byteSize, 2); 34 + }); 35 + 36 + it('add returns previous value and updates', () => { 37 + const a = new AtomicUint16(); 38 + a.store(10); 39 + const prev = a.add(5); 40 + assert.equal(prev, 10); 41 + assert.equal(a.load(), 15); 42 + }); 43 + 44 + it('sub returns previous value and updates', () => { 45 + const a = new AtomicUint16(); 46 + a.store(10); 47 + const prev = a.sub(3); 48 + assert.equal(prev, 10); 49 + assert.equal(a.load(), 7); 50 + }); 51 + 52 + it('and returns previous value and updates', () => { 53 + const a = new AtomicUint16(); 54 + a.store(0b1100); 55 + const prev = a.and(0b1010); 56 + assert.equal(prev, 0b1100); 57 + assert.equal(a.load(), 0b1000); 58 + }); 59 + 60 + it('or returns previous value and updates', () => { 61 + const a = new AtomicUint16(); 62 + a.store(0b1100); 63 + const prev = a.or(0b0011); 64 + assert.equal(prev, 0b1100); 65 + assert.equal(a.load(), 0b1111); 66 + }); 67 + 68 + it('xor returns previous value and updates', () => { 69 + const a = new AtomicUint16(); 70 + a.store(0b1100); 71 + const prev = a.xor(0b1010); 72 + assert.equal(prev, 0b1100); 73 + assert.equal(a.load(), 0b0110); 74 + }); 75 + 76 + it('exchange returns previous value and sets new', () => { 77 + const a = new AtomicUint16(); 78 + a.store(50000); 79 + const prev = a.exchange(100); 80 + assert.equal(prev, 50000); 81 + assert.equal(a.load(), 100); 82 + }); 83 + 84 + it('compareExchange succeeds when expected matches', () => { 85 + const a = new AtomicUint16(); 86 + a.store(50000); 87 + const actual = a.compareExchange(50000, 100); 88 + assert.equal(actual, 50000); 89 + assert.equal(a.load(), 100); 90 + }); 91 + 92 + it('compareExchange fails when expected does not match', () => { 93 + const a = new AtomicUint16(); 94 + a.store(50000); 95 + const actual = a.compareExchange(0, 100); 96 + assert.equal(actual, 50000); 97 + assert.equal(a.load(), 50000); 98 + }); 99 + });
+99
test/sync/atomic-uint32.test.ts
··· 1 + import { describe, it } from 'node:test'; 2 + import assert from 'node:assert/strict'; 3 + import { AtomicUint32 } from 'moroutine'; 4 + 5 + describe('AtomicUint32', () => { 6 + it('self-allocates and initializes to zero', () => { 7 + const a = new AtomicUint32(); 8 + assert.equal(a.load(), 0); 9 + }); 10 + 11 + it('stores and loads a value', () => { 12 + const a = new AtomicUint32(); 13 + a.store(3000000000); 14 + assert.equal(a.load(), 3000000000); 15 + }); 16 + 17 + it('accepts an external buffer and byteOffset', () => { 18 + const buffer = new SharedArrayBuffer(16); 19 + const a = new AtomicUint32(buffer, 4); 20 + a.store(3000000000); 21 + const view = new Uint32Array(buffer, 4, 1); 22 + assert.equal(view[0], 3000000000); 23 + }); 24 + 25 + it('defaults byteOffset to 0', () => { 26 + const buffer = new SharedArrayBuffer(4); 27 + const a = new AtomicUint32(buffer); 28 + a.store(7); 29 + assert.equal(new Uint32Array(buffer)[0], 7); 30 + }); 31 + 32 + it('exposes static byteSize of 4', () => { 33 + assert.equal(AtomicUint32.byteSize, 4); 34 + }); 35 + 36 + it('add returns previous value and updates', () => { 37 + const a = new AtomicUint32(); 38 + a.store(10); 39 + const prev = a.add(5); 40 + assert.equal(prev, 10); 41 + assert.equal(a.load(), 15); 42 + }); 43 + 44 + it('sub returns previous value and updates', () => { 45 + const a = new AtomicUint32(); 46 + a.store(10); 47 + const prev = a.sub(3); 48 + assert.equal(prev, 10); 49 + assert.equal(a.load(), 7); 50 + }); 51 + 52 + it('and returns previous value and updates', () => { 53 + const a = new AtomicUint32(); 54 + a.store(0b1100); 55 + const prev = a.and(0b1010); 56 + assert.equal(prev, 0b1100); 57 + assert.equal(a.load(), 0b1000); 58 + }); 59 + 60 + it('or returns previous value and updates', () => { 61 + const a = new AtomicUint32(); 62 + a.store(0b1100); 63 + const prev = a.or(0b0011); 64 + assert.equal(prev, 0b1100); 65 + assert.equal(a.load(), 0b1111); 66 + }); 67 + 68 + it('xor returns previous value and updates', () => { 69 + const a = new AtomicUint32(); 70 + a.store(0b1100); 71 + const prev = a.xor(0b1010); 72 + assert.equal(prev, 0b1100); 73 + assert.equal(a.load(), 0b0110); 74 + }); 75 + 76 + it('exchange returns previous value and sets new', () => { 77 + const a = new AtomicUint32(); 78 + a.store(3000000000); 79 + const prev = a.exchange(99); 80 + assert.equal(prev, 3000000000); 81 + assert.equal(a.load(), 99); 82 + }); 83 + 84 + it('compareExchange succeeds when expected matches', () => { 85 + const a = new AtomicUint32(); 86 + a.store(3000000000); 87 + const actual = a.compareExchange(3000000000, 99); 88 + assert.equal(actual, 3000000000); 89 + assert.equal(a.load(), 99); 90 + }); 91 + 92 + it('compareExchange fails when expected does not match', () => { 93 + const a = new AtomicUint32(); 94 + a.store(3000000000); 95 + const actual = a.compareExchange(0, 99); 96 + assert.equal(actual, 3000000000); 97 + assert.equal(a.load(), 3000000000); 98 + }); 99 + });
+99
test/sync/atomic-uint64.test.ts
··· 1 + import { describe, it } from 'node:test'; 2 + import assert from 'node:assert/strict'; 3 + import { AtomicUint64 } from 'moroutine'; 4 + 5 + describe('AtomicUint64', () => { 6 + it('self-allocates and initializes to zero', () => { 7 + const a = new AtomicUint64(); 8 + assert.equal(a.load(), 0n); 9 + }); 10 + 11 + it('stores and loads a value', () => { 12 + const a = new AtomicUint64(); 13 + a.store(18000000000000000000n); 14 + assert.equal(a.load(), 18000000000000000000n); 15 + }); 16 + 17 + it('accepts an external buffer and byteOffset', () => { 18 + const buffer = new SharedArrayBuffer(16); 19 + const a = new AtomicUint64(buffer, 8); 20 + a.store(18000000000000000000n); 21 + const view = new BigUint64Array(buffer, 8, 1); 22 + assert.equal(view[0], 18000000000000000000n); 23 + }); 24 + 25 + it('defaults byteOffset to 0', () => { 26 + const buffer = new SharedArrayBuffer(8); 27 + const a = new AtomicUint64(buffer); 28 + a.store(7n); 29 + assert.equal(new BigUint64Array(buffer)[0], 7n); 30 + }); 31 + 32 + it('exposes static byteSize of 8', () => { 33 + assert.equal(AtomicUint64.byteSize, 8); 34 + }); 35 + 36 + it('add returns previous value and updates', () => { 37 + const a = new AtomicUint64(); 38 + a.store(10n); 39 + const prev = a.add(5n); 40 + assert.equal(prev, 10n); 41 + assert.equal(a.load(), 15n); 42 + }); 43 + 44 + it('sub returns previous value and updates', () => { 45 + const a = new AtomicUint64(); 46 + a.store(10n); 47 + const prev = a.sub(3n); 48 + assert.equal(prev, 10n); 49 + assert.equal(a.load(), 7n); 50 + }); 51 + 52 + it('and returns previous value and updates', () => { 53 + const a = new AtomicUint64(); 54 + a.store(0b1100n); 55 + const prev = a.and(0b1010n); 56 + assert.equal(prev, 0b1100n); 57 + assert.equal(a.load(), 0b1000n); 58 + }); 59 + 60 + it('or returns previous value and updates', () => { 61 + const a = new AtomicUint64(); 62 + a.store(0b1100n); 63 + const prev = a.or(0b0011n); 64 + assert.equal(prev, 0b1100n); 65 + assert.equal(a.load(), 0b1111n); 66 + }); 67 + 68 + it('xor returns previous value and updates', () => { 69 + const a = new AtomicUint64(); 70 + a.store(0b1100n); 71 + const prev = a.xor(0b1010n); 72 + assert.equal(prev, 0b1100n); 73 + assert.equal(a.load(), 0b0110n); 74 + }); 75 + 76 + it('exchange returns previous value and sets new', () => { 77 + const a = new AtomicUint64(); 78 + a.store(18000000000000000000n); 79 + const prev = a.exchange(99n); 80 + assert.equal(prev, 18000000000000000000n); 81 + assert.equal(a.load(), 99n); 82 + }); 83 + 84 + it('compareExchange succeeds when expected matches', () => { 85 + const a = new AtomicUint64(); 86 + a.store(18000000000000000000n); 87 + const actual = a.compareExchange(18000000000000000000n, 99n); 88 + assert.equal(actual, 18000000000000000000n); 89 + assert.equal(a.load(), 99n); 90 + }); 91 + 92 + it('compareExchange fails when expected does not match', () => { 93 + const a = new AtomicUint64(); 94 + a.store(18000000000000000000n); 95 + const actual = a.compareExchange(0n, 99n); 96 + assert.equal(actual, 18000000000000000000n); 97 + assert.equal(a.load(), 18000000000000000000n); 98 + }); 99 + });
+99
test/sync/atomic-uint8.test.ts
··· 1 + import { describe, it } from 'node:test'; 2 + import assert from 'node:assert/strict'; 3 + import { AtomicUint8 } from 'moroutine'; 4 + 5 + describe('AtomicUint8', () => { 6 + it('self-allocates and initializes to zero', () => { 7 + const a = new AtomicUint8(); 8 + assert.equal(a.load(), 0); 9 + }); 10 + 11 + it('stores and loads a value', () => { 12 + const a = new AtomicUint8(); 13 + a.store(200); 14 + assert.equal(a.load(), 200); 15 + }); 16 + 17 + it('accepts an external buffer and byteOffset', () => { 18 + const buffer = new SharedArrayBuffer(8); 19 + const a = new AtomicUint8(buffer, 4); 20 + a.store(200); 21 + const view = new Uint8Array(buffer, 4, 1); 22 + assert.equal(view[0], 200); 23 + }); 24 + 25 + it('defaults byteOffset to 0', () => { 26 + const buffer = new SharedArrayBuffer(1); 27 + const a = new AtomicUint8(buffer); 28 + a.store(7); 29 + assert.equal(new Uint8Array(buffer)[0], 7); 30 + }); 31 + 32 + it('exposes static byteSize of 1', () => { 33 + assert.equal(AtomicUint8.byteSize, 1); 34 + }); 35 + 36 + it('add returns previous value and updates', () => { 37 + const a = new AtomicUint8(); 38 + a.store(10); 39 + const prev = a.add(5); 40 + assert.equal(prev, 10); 41 + assert.equal(a.load(), 15); 42 + }); 43 + 44 + it('sub returns previous value and updates', () => { 45 + const a = new AtomicUint8(); 46 + a.store(10); 47 + const prev = a.sub(3); 48 + assert.equal(prev, 10); 49 + assert.equal(a.load(), 7); 50 + }); 51 + 52 + it('and returns previous value and updates', () => { 53 + const a = new AtomicUint8(); 54 + a.store(0b1100); 55 + const prev = a.and(0b1010); 56 + assert.equal(prev, 0b1100); 57 + assert.equal(a.load(), 0b1000); 58 + }); 59 + 60 + it('or returns previous value and updates', () => { 61 + const a = new AtomicUint8(); 62 + a.store(0b1100); 63 + const prev = a.or(0b0011); 64 + assert.equal(prev, 0b1100); 65 + assert.equal(a.load(), 0b1111); 66 + }); 67 + 68 + it('xor returns previous value and updates', () => { 69 + const a = new AtomicUint8(); 70 + a.store(0b1100); 71 + const prev = a.xor(0b1010); 72 + assert.equal(prev, 0b1100); 73 + assert.equal(a.load(), 0b0110); 74 + }); 75 + 76 + it('exchange returns previous value and sets new', () => { 77 + const a = new AtomicUint8(); 78 + a.store(200); 79 + const prev = a.exchange(100); 80 + assert.equal(prev, 200); 81 + assert.equal(a.load(), 100); 82 + }); 83 + 84 + it('compareExchange succeeds when expected matches', () => { 85 + const a = new AtomicUint8(); 86 + a.store(200); 87 + const actual = a.compareExchange(200, 100); 88 + assert.equal(actual, 200); 89 + assert.equal(a.load(), 100); 90 + }); 91 + 92 + it('compareExchange fails when expected does not match', () => { 93 + const a = new AtomicUint8(); 94 + a.store(200); 95 + const actual = a.compareExchange(0, 100); 96 + assert.equal(actual, 200); 97 + assert.equal(a.load(), 200); 98 + }); 99 + });