Skip to content

Commit

Permalink
s2: cellid
Browse files Browse the repository at this point in the history
  • Loading branch information
missinglink committed Jul 17, 2024
0 parents commit 2c8b999
Show file tree
Hide file tree
Showing 11 changed files with 768 additions and 0 deletions.
24 changes: 24 additions & 0 deletions .github/workflows/_test.yml
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
7 changes: 7 additions & 0 deletions .github/workflows/pull_request.yml
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
5 changes: 5 additions & 0 deletions .github/workflows/push.yml
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
package-lock.json
5 changes: 5 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"semi": false,
"singleQuote": true,
"printWidth": 120
}
169 changes: 169 additions & 0 deletions int/uint64.ts
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 = (i: bigint, 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
70 changes: 70 additions & 0 deletions int/uint64_test.ts
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)
})
Loading

0 comments on commit 2c8b999

Please sign in to comment.