Skip to content

Commit

Permalink
replace unnecessary data movement via buffers with methods to edit si…
Browse files Browse the repository at this point in the history
…ngle bytes in ExpandingBuffer
  • Loading branch information
meszaros-lajos-gyorgy committed Dec 25, 2022
1 parent 5e4b207 commit 86e0973
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 34 deletions.
64 changes: 52 additions & 12 deletions src/ExpandingBuffer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import { Buffer } from 'node:buffer'
import { EMPTY_BUFFER } from './constants'
import { clamp } from './functions'

let cntr = 0

export class ExpandingBuffer {
#heap: Buffer
#startIndex: number = 0
Expand Down Expand Up @@ -33,6 +31,44 @@ export class ExpandingBuffer {
return this.#heap.byteLength
}

/**
* Set a single byte of the stored data
*
* If offset is negative, then the method calculates the index from the end backwards
*/
setByte(offset: number, value: number) {
if (offset < 0) {
if (this.#endIndex + offset < this.#startIndex) {
return
}

this.#heap[this.#endIndex + offset] = value
return
}

if (this.#startIndex + offset >= this.#endIndex) {
this.#heap[this.#startIndex + offset] = value
}
}

appendByte(value: number) {
if (this.#endIndex + 1 < this.heapSize()) {
this.#heap[this.#endIndex] = value
this.#endIndex += 1
return
}

const blockSize = 0x1000

const currentData = this.#getActualData()

this.#heap = Buffer.allocUnsafe((Math.ceil((currentData.byteLength + 1) / blockSize) + 1) * blockSize)
currentData.copy(this.#heap, 0)
this.#heap[currentData.byteLength] = value
this.#startIndex = 0
this.#endIndex = currentData.byteLength + 1
}

append(newData: Buffer) {
if (this.#endIndex + newData.byteLength < this.heapSize()) {
newData.copy(this.#heap, this.#endIndex)
Expand Down Expand Up @@ -113,11 +149,13 @@ export class ExpandingBuffer {
* When the heap gets empty it also resets the indices as a cleanup
*/
dropStart(numberOfBytes: number) {
if (numberOfBytes > 0) {
this.#startIndex += numberOfBytes
if (this.#startIndex >= this.#endIndex) {
this.clear()
}
if (numberOfBytes <= 0) {
return
}

this.#startIndex += numberOfBytes
if (this.#startIndex >= this.#endIndex) {
this.clear()
}
}

Expand All @@ -129,11 +167,13 @@ export class ExpandingBuffer {
* When the heap gets empty it also resets the indices as a cleanup
*/
dropEnd(numberOfBytes: number) {
if (numberOfBytes > 0) {
this.#endIndex -= numberOfBytes
if (this.#startIndex >= this.#endIndex) {
this.clear()
}
if (numberOfBytes <= 0) {
return
}

this.#endIndex -= numberOfBytes
if (this.#startIndex >= this.#endIndex) {
this.clear()
}
}

Expand Down
12 changes: 5 additions & 7 deletions src/Explode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@ export class Explode {
#asciiTable2D34: number[] = repeat(0, 0x100)
#asciiTable2E34: number[] = repeat(0, 0x80)
#asciiTable2EB4: number[] = repeat(0, 0x100)
#reusableByte: Buffer = Buffer.allocUnsafe(1)

constructor(config: Config = {}) {
this.#verbose = config?.verbose ?? false
Expand Down Expand Up @@ -334,27 +333,26 @@ export class Explode {
let nextLiteral = this.#decodeNextLiteral()

while (nextLiteral !== LITERAL_END_STREAM) {
let addition: Buffer

if (nextLiteral >= 0x100) {
const repeatLength = nextLiteral - 0xfe

const minusDistance = this.#decodeDistance(repeatLength)
const availableData = this.#outputBuffer.read(this.#outputBuffer.size() - minusDistance, repeatLength)

let addition: Buffer

if (repeatLength > minusDistance) {
const multipliedData = repeat(availableData, Math.ceil(repeatLength / availableData.length))
addition = Buffer.concat(multipliedData).subarray(0, repeatLength)
} else {
addition = availableData
}

this.#outputBuffer.append(addition)
} else {
this.#reusableByte[0] = nextLiteral
addition = this.#reusableByte
this.#outputBuffer.appendByte(nextLiteral)
}

this.#outputBuffer.append(addition)

this.#backup()

nextLiteral = this.#decodeNextLiteral()
Expand Down
24 changes: 10 additions & 14 deletions src/Implode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
LenBits,
LenCode,
LONGEST_ALLOWED_REPETITION,
SINGLE_ZERO_BUFFER,
} from './constants'
import { InvalidCompressionTypeError, InvalidDictionarySizeError } from './errors'
import { ExpandingBuffer } from './ExpandingBuffer'
Expand Down Expand Up @@ -75,7 +74,6 @@ export class Implode {
#outBits: number = 0
#nChBits: number[] = repeat(0, 0x306)
#nChCodes: number[] = repeat(0, 0x306)
#reusableByte: Buffer = Buffer.allocUnsafe(1)

constructor(compressionType: Compression, dictionarySize: DictionarySize, config: Config) {
if (!(compressionType in Compression) || compressionType === Compression.Unknown) {
Expand Down Expand Up @@ -130,9 +128,7 @@ export class Implode {
instance.#outputBuffer.flushStart(numberOfBytes)

if (instance.#outBits === 0) {
// set last byte to 0
instance.#outputBuffer.dropEnd(1)
instance.#outputBuffer.append(SINGLE_ZERO_BUFFER)
instance.#outputBuffer.setByte(-1, 0)
}

callback(null, output)
Expand Down Expand Up @@ -253,7 +249,8 @@ export class Implode {

// -------------------------------

this.#inputBuffer.dropStart(this.#inputBuffer.size())
// this.#inputBuffer.dropStart(this.#inputBuffer.size())
this.#inputBuffer.clear()
}

if (this.#streamEnded) {
Expand Down Expand Up @@ -338,7 +335,9 @@ export class Implode {
}
}

this.#outputBuffer.append(Buffer.from([this.#compressionType, this.#dictionarySize, 0]))
this.#outputBuffer.appendByte(this.#compressionType)
this.#outputBuffer.appendByte(this.#dictionarySize)
this.#outputBuffer.appendByte(0)
this.#outBits = 0
}

Expand All @@ -352,21 +351,18 @@ export class Implode {
const outBits = this.#outBits

const lastBytes = this.#outputBuffer.readByte(this.#outputBuffer.size() - 1)
this.#outputBuffer.dropEnd(1)
this.#reusableByte[0] = lastBytes | getLowestNBits(8, bitBuffer << outBits)
this.#outputBuffer.append(this.#reusableByte)
this.#outputBuffer.setByte(-1, lastBytes | getLowestNBits(8, bitBuffer << outBits))

this.#outBits = this.#outBits + nBits

if (this.#outBits > 8) {
bitBuffer = bitBuffer >> (8 - outBits)
this.#reusableByte[0] = getLowestNBits(8, bitBuffer)
this.#outputBuffer.append(this.#reusableByte)
this.#outBits = getLowestNBits(3, this.#outBits)
bitBuffer = bitBuffer >> (8 - outBits)
this.#outputBuffer.appendByte(getLowestNBits(8, bitBuffer))
} else {
this.#outBits = getLowestNBits(3, this.#outBits)
if (this.#outBits === 0) {
this.#outputBuffer.append(SINGLE_ZERO_BUFFER)
this.#outputBuffer.appendByte(0)
}
}
}
Expand Down
1 change: 0 additions & 1 deletion src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ export enum DictionarySize {
}

export const EMPTY_BUFFER = Buffer.from([])
export const SINGLE_ZERO_BUFFER = Buffer.from([0])

export const LONGEST_ALLOWED_REPETITION = 0x204

Expand Down

0 comments on commit 86e0973

Please sign in to comment.