Skip to content

Commit

Permalink
Remove long
Browse files Browse the repository at this point in the history
  • Loading branch information
cmdcolin committed Dec 17, 2024
1 parent 33b299d commit a4f995b
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 141 deletions.
2 changes: 0 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,9 @@
],
"dependencies": {
"generic-filehandle2": "^1.0.0",
"long": "^4.0.0",
"pako": "^1.0.11"
},
"devDependencies": {
"@types/long": "^4.0.1",
"@types/node": "^18.11.16",
"@types/pako": "^2.0.0",
"@typescript-eslint/eslint-plugin": "^8.16.0",
Expand Down
73 changes: 36 additions & 37 deletions src/gziIndex.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
import Long from 'long'
import { LocalFile, GenericFilehandle } from 'generic-filehandle2'

// const COMPRESSED_POSITION = 0
const UNCOMPRESSED_POSITION = 1

const TWO_PWR_16_DBL = 1 << 16
const TWO_PWR_32_DBL = TWO_PWR_16_DBL * TWO_PWR_16_DBL

// extracted from long.js, license Apache 2.0 https://github.com/dcodeIO/long.js
function longFromBytesUnsignedLE(bytes: Uint8Array) {
const low =
bytes[0]! | (bytes[1]! << 8) | (bytes[2]! << 16) | (bytes[3]! << 24)
const high =
bytes[4]! | (bytes[5]! << 8) | (bytes[6]! << 16) | (bytes[7]! << 24)
return (high >>> 0) * TWO_PWR_32_DBL + (low >>> 0)
}

export default class GziIndex {
filehandle: GenericFilehandle

index?: any
index?: Promise<[number, number][]>

constructor({
filehandle,
Expand All @@ -25,29 +36,19 @@ export default class GziIndex {
}
}

_readLongWithOverflow(buf: Uint8Array, offset = 0, unsigned = true) {
//@ts-ignore
const long = Long.fromBytesLE(buf.slice(offset, offset + 8), unsigned)
if (
long.greaterThan(Number.MAX_SAFE_INTEGER) ||
long.lessThan(Number.MIN_SAFE_INTEGER)
) {
throw new TypeError('integer overflow')
}

return long.toNumber()
}

_getIndex() {
if (!this.index) {
this.index = this._readIndex()
this.index = this._readIndex().catch((e: unknown) => {
this.index = undefined
throw e
})
}
return this.index
}

async _readIndex(): Promise<[number, number][]> {
const buf = await this.filehandle.read(8, 0)
const numEntries = this._readLongWithOverflow(buf, 0, true)
const numEntries = longFromBytesUnsignedLE(buf.subarray(0, 8))
if (!numEntries) {
return [[0, 0]]
}
Expand All @@ -62,13 +63,11 @@ export default class GziIndex {
}
const buf2 = await this.filehandle.read(bufSize, 8)
for (let entryNumber = 0; entryNumber < numEntries; entryNumber += 1) {
const compressedPosition = this._readLongWithOverflow(
buf2,
entryNumber * 16,
const compressedPosition = longFromBytesUnsignedLE(
buf2.subarray(entryNumber * 16, entryNumber * 16 + 8),
)
const uncompressedPosition = this._readLongWithOverflow(
buf2,
entryNumber * 16 + 8,
const uncompressedPosition = longFromBytesUnsignedLE(
buf2.subarray(entryNumber * 16 + 8, entryNumber * 16 + 16),
)
entries[entryNumber + 1] = [compressedPosition, uncompressedPosition]
}
Expand All @@ -78,10 +77,7 @@ export default class GziIndex {

async getLastBlock() {
const entries = await this._getIndex()
if (!entries.length) {
return undefined
}
return entries[entries.length - 1]
return entries.at(-1)
}

async getRelevantBlocksForRead(length: number, position: number) {
Expand All @@ -94,32 +90,32 @@ export default class GziIndex {

// binary search to find the block that the
// read starts in and extend forward from that
const compare = (entry: any, nextEntry: any) => {
const compare = (entry: [number, number], nextEntry?: [number, number]) => {
const uncompressedPosition = entry[UNCOMPRESSED_POSITION]
const nextUncompressedPosition = nextEntry
? nextEntry[UNCOMPRESSED_POSITION]
: Infinity
// block overlaps read start
if (
uncompressedPosition <= position &&
nextUncompressedPosition > position
) {
// block overlaps read start
return 0
} else if (uncompressedPosition < position) {
// block is before read start
}
if (uncompressedPosition < position) {
return -1
} else {
// block is after read start
return 1
}
// block is after read start
return 1
}

let lowerBound = 0
let upperBound = entries.length - 1
let searchPosition = Math.floor(entries.length / 2)

let comparison = compare(
entries[searchPosition],
entries[searchPosition]!,
entries[searchPosition + 1],
)
while (comparison !== 0) {
Expand All @@ -129,19 +125,22 @@ export default class GziIndex {
lowerBound = searchPosition + 1
}
searchPosition = Math.ceil((upperBound - lowerBound) / 2) + lowerBound
comparison = compare(entries[searchPosition], entries[searchPosition + 1])
comparison = compare(
entries[searchPosition]!,
entries[searchPosition + 1],
)
}

// here's where we read forward
relevant.push(entries[searchPosition])
let i = searchPosition + 1
for (; i < entries.length; i += 1) {
relevant.push(entries[i])
if (entries[i][UNCOMPRESSED_POSITION] >= endPosition) {
if (entries[i]![UNCOMPRESSED_POSITION] >= endPosition) {
break
}
}
if (relevant[relevant.length - 1][UNCOMPRESSED_POSITION] < endPosition) {
if (relevant[relevant.length - 1]![UNCOMPRESSED_POSITION] < endPosition) {
relevant.push([])
}
return relevant
Expand Down
Loading

0 comments on commit a4f995b

Please sign in to comment.