-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 4d069a6
Showing
11 changed files
with
768 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
name: Unit Tests | ||
on: workflow_call | ||
jobs: | ||
unit-tests: | ||
runs-on: '${{ matrix.os }}' | ||
timeout-minutes: 10 | ||
strategy: | ||
matrix: | ||
os: | ||
- 'ubuntu-22.04' | ||
node-version: | ||
- 22.x | ||
- 20.x | ||
- 18.x | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- name: 'Install node.js ${{ matrix.node-version }}' | ||
uses: actions/setup-node@v3 | ||
with: | ||
node-version: '${{ matrix.node-version }}' | ||
- name: Run unit tests | ||
run: | | ||
npm install | ||
npm test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
name: Continuous Integration | ||
on: pull_request | ||
jobs: | ||
unit-tests: | ||
# only run this job for forks | ||
if: github.event.pull_request.head.repo.full_name != github.repository | ||
uses: ./.github/workflows/_test.yml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
name: Continuous Integration | ||
on: push | ||
jobs: | ||
unit-tests: | ||
uses: ./.github/workflows/_test.yml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
node_modules | ||
package-lock.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"semi": false, | ||
"singleQuote": true, | ||
"printWidth": 120 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
import type { uint8 } from './uint8' | ||
|
||
/** | ||
* @module uint64 | ||
* | ||
* 64-bit integer manipulation/conversion methods | ||
*/ | ||
|
||
/** | ||
* valid returns false if i is the wrong type or exceeds 64 bits | ||
*/ | ||
export const valid = (i: bigint): boolean => { | ||
return typeof i === 'bigint' && BigInt.asUintN(64, i) == i | ||
} | ||
|
||
/** | ||
* byte returns the byte at offset n (left-to-right) | ||
*/ | ||
export const byte = (i: bigint, o: offset): uint8 => { | ||
const offset = BigInt((7 - o) * 8) | ||
const mask = 0b11111111n << offset | ||
return Number((i & mask) >> offset) as uint8 | ||
} | ||
|
||
/** | ||
* trailingZeros8 returns the number of trailing zero bits in byte | ||
*/ | ||
const trailingZeros8 = (byte: uint8): number => { | ||
const lsb = byte & -byte | ||
if (lsb === 0) return 8 | ||
return 31 - Math.clz32(lsb) | ||
} | ||
|
||
/** | ||
* trailingZeros returns the number of trailing zero bits in an uint64 | ||
*/ | ||
export const trailingZeros = (i: bigint): position => { | ||
for (let n = 7; n >= 0; n--) { | ||
const z = trailingZeros8(byte(i, n as offset)) | ||
if (z < 8) return ((7 - n) * 8 + z) as position | ||
} | ||
return 64 as position | ||
} | ||
|
||
/** | ||
* flip flip the bit at position p in uint64 | ||
*/ | ||
export const flip = (i: bigint, p: position): bigint => { | ||
return i ^ (1n << BigInt(p)) | ||
} | ||
|
||
/** | ||
* set sets the bit at position p in uint64 to v | ||
*/ | ||
export const set = (i: bigint, p: position, v: bit): bigint => { | ||
const mask = 1n << BigInt(p) | ||
return v ? i | mask : i & ~mask | ||
} | ||
|
||
/** | ||
* setTrailingBits fills the rightmost n bits in uint64 with v | ||
*/ | ||
export const setTrailingBits = (i: bigint, p: position, v: bit): bigint => { | ||
const mask = (1n << BigInt(p + 1)) - 1n | ||
return v ? i | mask : i & ~mask | ||
} | ||
|
||
/** | ||
* lsb returns the least significant bit that is set | ||
*/ | ||
export const lsb = (i: bigint) => i & -i | ||
|
||
/** | ||
* marshal writes an uint64 to an Uint8Array | ||
*/ | ||
export const marshal = (i: bigint): Uint8Array => { | ||
const arr = new Uint8Array(8) | ||
new DataView(arr.buffer, 0, 8).setBigUint64(0, i, false) | ||
return arr | ||
} | ||
|
||
/** | ||
* unmarshal reads an uint64 from an Uint8Array | ||
*/ | ||
export const unmarshal = (arr: Uint8Array): bigint => { | ||
return new DataView(arr.buffer, 0, 8).getBigUint64(0, false) | ||
} | ||
|
||
/** | ||
* toBinaryString returns the binary string representation of an uint64 | ||
*/ | ||
export const toBinaryString = (i: bigint): string => i.toString(2).padStart(64, '0') | ||
|
||
/** | ||
* Types | ||
*/ | ||
|
||
/** bit value */ | ||
export type bit = 0 | 1 | ||
|
||
/** byte offset */ | ||
export type offset = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | ||
|
||
/** bit position */ | ||
export type position = | ||
| 0 | ||
| 1 | ||
| 2 | ||
| 3 | ||
| 4 | ||
| 5 | ||
| 6 | ||
| 7 | ||
| 8 | ||
| 9 | ||
| 10 | ||
| 11 | ||
| 12 | ||
| 13 | ||
| 14 | ||
| 15 | ||
| 16 | ||
| 17 | ||
| 18 | ||
| 19 | ||
| 20 | ||
| 21 | ||
| 22 | ||
| 23 | ||
| 24 | ||
| 25 | ||
| 26 | ||
| 27 | ||
| 28 | ||
| 29 | ||
| 30 | ||
| 31 | ||
| 32 | ||
| 33 | ||
| 34 | ||
| 35 | ||
| 36 | ||
| 37 | ||
| 38 | ||
| 39 | ||
| 40 | ||
| 41 | ||
| 42 | ||
| 43 | ||
| 44 | ||
| 45 | ||
| 46 | ||
| 47 | ||
| 48 | ||
| 49 | ||
| 50 | ||
| 51 | ||
| 52 | ||
| 53 | ||
| 54 | ||
| 55 | ||
| 56 | ||
| 57 | ||
| 58 | ||
| 59 | ||
| 60 | ||
| 61 | ||
| 62 | ||
| 63 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import test from 'node:test' | ||
import { equal } from 'node:assert/strict' | ||
import * as uint64 from './uint64.ts' | ||
|
||
test('flip', (t) => { | ||
const i = 0b0000000000000000000000000000000000000000000000000000000000000000n | ||
equal(uint64.flip(i, 0), 0b0000000000000000000000000000000000000000000000000000000000000001n) | ||
equal(uint64.flip(i, 1), 0b0000000000000000000000000000000000000000000000000000000000000010n) | ||
equal(uint64.flip(i, 7), 0b0000000000000000000000000000000000000000000000000000000010000000n) | ||
equal(uint64.flip(i, 9), 0b0000000000000000000000000000000000000000000000000000001000000000n) | ||
equal(uint64.flip(i, 61), 0b0010000000000000000000000000000000000000000000000000000000000000n) | ||
equal(uint64.flip(i, 63), 0b1000000000000000000000000000000000000000000000000000000000000000n) | ||
}) | ||
|
||
test('byte', (t) => { | ||
const i = 0b1111111101111111001111110001111100001111000001110000001100000001n | ||
equal(uint64.byte(i, 0), 0b11111111) | ||
equal(uint64.byte(i, 1), 0b01111111) | ||
equal(uint64.byte(i, 2), 0b00111111) | ||
equal(uint64.byte(i, 3), 0b00011111) | ||
equal(uint64.byte(i, 4), 0b00001111) | ||
equal(uint64.byte(i, 5), 0b00000111) | ||
equal(uint64.byte(i, 6), 0b00000011) | ||
equal(uint64.byte(i, 7), 0b00000001) | ||
}) | ||
|
||
test('trailingZeros', (t) => { | ||
equal(uint64.trailingZeros(0b0000000000000000000000000000000000000000000000000000000000000001n), 0) | ||
equal(uint64.trailingZeros(0b0000000000000000000000000000000000000000000000000000000000000010n), 1) | ||
equal(uint64.trailingZeros(0b0000000000000000000000000000000000000000000000000000000000000100n), 2) | ||
equal(uint64.trailingZeros(0b0000000000000000000000000000000000000000000000000000000000001000n), 3) | ||
equal(uint64.trailingZeros(0b0000000000000000000000000000000000000000000000000000000000010000n), 4) | ||
equal(uint64.trailingZeros(0b0000000000000000000000000000000000000000000000000000000000100000n), 5) | ||
equal(uint64.trailingZeros(0b0000000000000000000000000000000000000000000000000000000001000000n), 6) | ||
equal(uint64.trailingZeros(0b0000000000000000000000000000000000000000000000000000000010000000n), 7) | ||
equal(uint64.trailingZeros(0b0000000000000000000000000000000000000000000000000000000100000000n), 8) | ||
equal(uint64.trailingZeros(0b0000000000000000000000000000000010000000000000000000000000000000n), 31) | ||
equal(uint64.trailingZeros(0b0000000000000000000000000000000001000000000000000000000000000000n), 30) | ||
equal(uint64.trailingZeros(0b0000000000000000000000000000000000100000000000000000000000000000n), 29) | ||
equal(uint64.trailingZeros(0b0000000000000000000000000000000000010000000000000000000000000000n), 28) | ||
equal(uint64.trailingZeros(0b0000000000000000000000000000000000001000000000000000000000000000n), 27) | ||
equal(uint64.trailingZeros(0b0000000000000000000000000000000000000100000000000000000000000000n), 26) | ||
equal(uint64.trailingZeros(0b0000000000000000000000000000000000000010000000000000000000000000n), 25) | ||
equal(uint64.trailingZeros(0b0000000000000000000000000000000000000001000000000000000000000000n), 24) | ||
equal(uint64.trailingZeros(0b0000000000000000000000000000000000000000000000000000000000000000n), 64) | ||
}) | ||
|
||
test('setTrailingBits', (t) => { | ||
const i = 0b0000000000000000000000000000000000000000000000000000000000000000n | ||
equal(uint64.setTrailingBits(i, 0, 1), 0b0000000000000000000000000000000000000000000000000000000000000001n) | ||
equal(uint64.setTrailingBits(i, 1, 1), 0b0000000000000000000000000000000000000000000000000000000000000011n) | ||
equal(uint64.setTrailingBits(i, 2, 1), 0b0000000000000000000000000000000000000000000000000000000000000111n) | ||
equal(uint64.setTrailingBits(i, 5, 1), 0b0000000000000000000000000000000000000000000000000000000000111111n) | ||
equal(uint64.setTrailingBits(i, 63, 1), 0b1111111111111111111111111111111111111111111111111111111111111111n) | ||
}) | ||
|
||
test('setBit', (t) => { | ||
equal(uint64.set(0b00000000000000000000000000000000n, 0, 1), 0b00000000000000000000000000000001n) | ||
equal(uint64.set(0b00000000000000000000000000000000n, 1, 1), 0b00000000000000000000000000000010n) | ||
equal(uint64.set(0b00000000000000000000000000000000n, 9, 1), 0b00000000000000000000001000000000n) | ||
equal(uint64.set(0b00000000000000000000000000000000n, 17, 1), 0b00000000000000100000000000000000n) | ||
equal(uint64.set(0b00000000000000000000000000000000n, 25, 1), 0b00000010000000000000000000000000n) | ||
equal(uint64.set(0b00000000000000000000000000000000n, 31, 1), 0b10000000000000000000000000000000n) | ||
equal(uint64.set(0b11111111111111111111111111111111n, 0, 0), 0b11111111111111111111111111111110n) | ||
equal(uint64.set(0b11111111111111111111111111111111n, 1, 0), 0b11111111111111111111111111111101n) | ||
equal(uint64.set(0b11111111111111111111111111111111n, 9, 0), 0b11111111111111111111110111111111n) | ||
equal(uint64.set(0b11111111111111111111111111111111n, 17, 0), 0b11111111111111011111111111111111n) | ||
equal(uint64.set(0b11111111111111111111111111111111n, 25, 0), 0b11111101111111111111111111111111n) | ||
equal(uint64.set(0b11111111111111111111111111111111n, 31, 0), 0b01111111111111111111111111111111n) | ||
}) |
Oops, something went wrong.