X Tutup
const BITS_PER_BYTE = 8 const { abs, ceil, floor, log2 } = Math const gcd = (a, b) => { let la = a let lb = b while (lb !== 0) { [la, lb] = [lb, la % lb] } return abs(la) } const lcm = (a, b) => (a / gcd(a, b)) * b const genNdxFn = (bitsPerChar) => { // If BITS_PER_BYTEs is a multiple of bitsPerChar, we can slice off an integer number // of chars per byte. if (lcm(bitsPerChar, BITS_PER_BYTE) === BITS_PER_BYTE) { return (chunk, slice, bytes) => { const lShift = bitsPerChar const rShift = BITS_PER_BYTE - bitsPerChar return ((bytes[chunk] << (lShift * slice)) & 0xff) >> rShift } } // Otherwise, while slicing off bits per char, we can possibly straddle two // of bytes, so a more work is involved const slicesPerChunk = lcm(bitsPerChar, BITS_PER_BYTE) / BITS_PER_BYTE return (chunk, slice, bytes) => { const bNum = chunk * slicesPerChunk const offset = (slice * bitsPerChar) / BITS_PER_BYTE const lOffset = floor(offset) const rOffset = ceil(offset) const rShift = BITS_PER_BYTE - bitsPerChar const lShift = (slice * bitsPerChar) % BITS_PER_BYTE let ndx = ((bytes[bNum + lOffset] << lShift) & 0xff) >> rShift const r1Bits = (rOffset + 1) * BITS_PER_BYTE const s1Bits = (slice + 1) * bitsPerChar const rShiftIt = (r1Bits - s1Bits) % BITS_PER_BYTE if (rShift < rShiftIt) { ndx += bytes[bNum + rOffset] >> rShiftIt } return ndx } } class CharSet { constructor(chars) { if (!(typeof chars === 'string' || chars instanceof String)) { throw new Error('Invalid chars: Must be string') } const { length } = chars if (![2, 4, 8, 16, 32, 64].includes(length)) { throw new Error('Invalid char count: must be one of 2,4,8,16,32,64') } // Ensure no repeated characters for (let i = 0; i < length; i += 1) { const c = chars.charAt(i) for (let j = i + 1; j < length; j += 1) { if (c === chars.charAt(j)) { throw new Error('Characters not unique') } } } this.chars = chars this.bitsPerChar = floor(log2(length)) this.length = length this.ndxFn = genNdxFn(this.bitsPerChar) this.charsPerChunk = lcm(this.bitsPerChar, BITS_PER_BYTE) / this.bitsPerChar } bytesNeeded(bitLen) { const count = ceil(bitLen / this.bitsPerChar) return ceil((count * this.bitsPerChar) / BITS_PER_BYTE) } } module.exports = { CharSet }
X Tutup