Last active
January 19, 2023 20:27
-
-
Save fabiospampinato/ac7e3e0186f2651196678c55608ffd29 to your computer and use it in GitHub Desktop.
A rough implementation of the LZW algorithm
This file contains hidden or 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
import * as assert from 'node:assert'; | |
import Buffer from 'node:buffer'; | |
import fs from 'node:fs'; | |
import {deflateSync, inflateSync} from 'fflate'; | |
import * as LZW from '@amoutonbrady/lz-string' | |
import * as Huffy from 'huffy'; | |
import Base64 from 'radix64-encoding'; | |
const encoder = new TextEncoder (); | |
const decoder = new TextDecoder ( 'utf-8', { ignoreBOM: true } ); | |
// const packBytes = x => x; | |
// const unpackBytes = x => x; | |
// const packBytes = x => Huffy.compress ( new Uint8Array ( new Uint32Array ( x ).buffer ) ); | |
// const unpackBytes = x => new Uint32Array ( Huffy.decompress ( x ).buffer ); | |
const packBytes = x => { | |
const buffer = new ArrayBuffer ( x.length * 2 ); | |
const view = new DataView ( buffer ); | |
for ( let i = 0; i < x.length; i++ ) { | |
view.setUint16 ( i * 2, x[i] ); | |
} | |
const uint8 = Base64.encode ( Huffy.compress ( new Uint8Array ( buffer ) ) ); | |
return uint8; | |
}; | |
const unpackBytes = x => { | |
x = Huffy.decompress ( Base64.decode ( x ) ); | |
const buffer = new Array ( x.length / 2 ); | |
const view = new DataView ( x.buffer ); | |
for ( let i = 0; i < x.length; i += 2 ) { | |
buffer[i / 2] = view.getUint16 ( i ); | |
} | |
return buffer; | |
}; | |
const DICTIONARY_BASE = 256; | |
const DICTIONARY_LIMIT = ( 2 ** 19 ) - 1; | |
const compressStr = str => { | |
const u8 = encoder.encode ( str ); | |
return compressBuffer ( u8 ); | |
}; | |
const compressBuffer = buffer => { | |
let $VALUE = Symbol(); | |
let dictionary = {}; | |
let dictionaryRoot = dictionary; | |
let dictionarySize = DICTIONARY_BASE; | |
let current = ''; | |
let result = []; | |
for ( let i = 0; i < DICTIONARY_BASE; i++ ) { | |
dictionary[i] = { | |
[$VALUE]: i | |
}; | |
} | |
for ( let i = 0, l = buffer.length; i < l; i++ ) { | |
let charCode = buffer[i]; | |
let next = charCode; | |
let valueNext = dictionary[next]; | |
let isLimit = ( dictionarySize >= DICTIONARY_LIMIT ); | |
if ( valueNext !== undefined && !isLimit ) { | |
current = next; | |
dictionary = valueNext; | |
} else { | |
result.push ( dictionary[$VALUE] ); | |
if ( !isLimit ) { | |
dictionary[next] = { | |
[$VALUE]: dictionarySize++ | |
}; | |
} else { | |
} | |
current = charCode; | |
dictionary = dictionaryRoot[charCode]; | |
} | |
} | |
if ( current ) { | |
result.push ( dictionary[$VALUE] ); | |
} | |
// console.log('dic size',JSON.stringify ( Array.from ( Object.entries ( dictionary ) ) ).length ); | |
// console.log('data size', result.length); | |
// console.log('dictionarySize', dictionarySize); | |
// return result; | |
// return Huffy.compress ( new Uint8Array ( new Uint32Array ( result ).buffer ) ); | |
return packBytes ( result ); | |
}; | |
const decompressStr = str => { | |
return decoder.decode ( decompressBuffer ( str ) ); | |
}; | |
const decompressBuffer = buffer => { | |
buffer = unpackBytes ( buffer ); | |
// buffer = new Uint32Array ( Huffy.decompress ( buffer ).buffer ); | |
// buffer = buffer; | |
const dictionary = []; | |
let w = String.fromCharCode ( buffer[0] ); | |
let result = w; | |
let entry = ''; | |
let dictionarySize = 256; | |
for ( let i = 0; i < 256; i++ ) { | |
dictionary[i] = String.fromCharCode ( i ); | |
} | |
for ( let i = 1, l = buffer.length; i < l; i++ ) { | |
const idx = buffer[i]; | |
const value = dictionary[idx]; | |
if ( value ) { | |
entry = value; | |
} else { | |
if ( idx === dictionarySize ) { | |
entry = w + w.charAt ( 0 ); | |
} else { | |
throw new Error ( 'Impossible' ); | |
} | |
} | |
result += entry; | |
// if ( dictionarySize < DICTIONARY_LIMIT ) { | |
dictionary[dictionarySize++] = w + entry.charAt(0); | |
// } | |
w = entry; | |
} | |
// console.log({ dictionarySize }); | |
const u8 = new Uint8Array ( result.length ); | |
result.split ( '' ).forEach ( ( char, i ) => { | |
u8[i] = char.charCodeAt ( 0 ); | |
}); | |
// console.log('dic size',JSON.stringify ( Array.from ( dictionary ) ).length ); | |
// console.log('data size', result.length); | |
// console.log('dictionarySize', dictionarySize); | |
return u8; | |
}; | |
const compress = str => { | |
return compressStr ( str ); | |
}; | |
const decompress = arr => { | |
return decompressStr ( arr ); | |
}; | |
const compress_4_ = str => { | |
const u8 = encoder.encode ( str ); | |
let $VALUE = Symbol(); | |
let dictionary = {}; | |
let dictionaryRoot = dictionary; | |
let dictionarySize = DICTIONARY_BASE; | |
let current = ''; | |
let result = []; | |
for ( let i = 0; i < DICTIONARY_BASE; i++ ) { | |
dictionary[i] = { | |
[$VALUE]: i | |
}; | |
} | |
for ( let i = 0, l = u8.length; i < l; i++ ) { | |
let charCode = u8[i]; | |
let next = charCode; | |
let valueNext = dictionary[next]; | |
let isLimit = ( dictionarySize >= DICTIONARY_LIMIT ); | |
if ( valueNext !== undefined && !isLimit ) { | |
current = next; | |
dictionary = valueNext; | |
} else { | |
result.push ( dictionary[$VALUE] ); | |
if ( !isLimit ) { | |
dictionary[next] = { | |
[$VALUE]: dictionarySize++ | |
}; | |
} | |
current = charCode; | |
dictionary = dictionaryRoot[charCode]; | |
} | |
} | |
if ( current ) { | |
result.push ( dictionary[$VALUE] ); | |
} | |
console.log('dic size',JSON.stringify ( Array.from ( Object.entries ( dictionary ) ) ).length ); | |
console.log('data size', result.length); | |
console.log('dictionarySize', dictionarySize); | |
return result; | |
}; | |
const decompress_4_ = arr => { | |
let dictionary = []; | |
let dictionarySize = DICTIONARY_BASE; | |
let w = String.fromCharCode ( arr[0] ); | |
let result = w; | |
let entry = ''; | |
for ( let i = 1, l = arr.length; i < l; i++ ) { | |
const idx = arr[i]; | |
const value = ( idx < DICTIONARY_BASE ) ? String.fromCharCode ( idx ) : dictionary[idx]; | |
if ( value ) { | |
entry = value; | |
} else { | |
if ( idx === dictionarySize ) { | |
entry = w + w[0]; | |
} else { | |
throw new Error ( 'Impossible' ); | |
} | |
} | |
result += entry; | |
if ( dictionarySize < DICTIONARY_LIMIT ) { | |
dictionary[dictionarySize++] = w + entry[0]; | |
} | |
w = entry; | |
} | |
console.log('dic size',JSON.stringify ( Array.from ( dictionary ) ).length ); | |
console.log('data size', result.length); | |
console.log('dictionarySize', dictionarySize); | |
return result; | |
}; | |
const compress_3_ = str => { | |
let $VALUE = Symbol(); | |
let dictionary = {}; | |
let dictionaryRoot = dictionary; | |
let dictionarySize = DICTIONARY_BASE; | |
let current = ''; | |
let result = []; | |
for ( let i = 0; i < DICTIONARY_BASE; i++ ) { | |
const code = String.fromCharCode ( i ); | |
dictionary[code] = { | |
[$VALUE]: i | |
}; | |
} | |
for ( let i = 0, l = str.length; i < l; i++ ) { | |
let char = str[i]; | |
let next = char; | |
let valueNext = dictionary[next]; | |
let isLimit = ( dictionarySize >= DICTIONARY_LIMIT ); | |
if ( valueNext !== undefined && !isLimit ) { | |
current = next; | |
dictionary = valueNext; | |
} else { | |
result.push ( dictionary[$VALUE] ); | |
if ( !isLimit ) { | |
dictionary[next] = { | |
[$VALUE]: dictionarySize++ | |
}; | |
} | |
current = char; | |
dictionary = dictionaryRoot[char]; | |
} | |
} | |
if ( current ) { | |
result.push ( dictionary[$VALUE] ); | |
} | |
console.log('dic size',JSON.stringify ( Array.from ( Object.entries ( dictionary ) ) ).length ); | |
console.log('data size', result.length); | |
console.log('dictionarySize', dictionarySize); | |
return result; | |
}; | |
const decompress_3_ = arr => { | |
let dictionary = []; | |
let dictionarySize = DICTIONARY_BASE; | |
let w = String.fromCharCode ( arr[0] ); | |
let result = w; | |
let entry = ''; | |
for ( let i = 1, l = arr.length; i < l; i++ ) { | |
const idx = arr[i]; | |
const value = ( idx < DICTIONARY_BASE ) ? String.fromCharCode ( idx ) : dictionary[idx]; | |
if ( value ) { | |
entry = value; | |
} else { | |
if ( idx === dictionarySize ) { | |
entry = w + w[0]; | |
} else { | |
throw new Error ( 'Impossible' ); | |
} | |
} | |
result += entry; | |
if ( dictionarySize < DICTIONARY_LIMIT ) { | |
dictionary[dictionarySize++] = w + entry[0]; | |
} | |
w = entry; | |
} | |
console.log('dic size',JSON.stringify ( Array.from ( dictionary ) ).length ); | |
console.log('data size', result.length); | |
console.log('dictionarySize', dictionarySize); | |
return result; | |
}; | |
const compress_2_ = str => { | |
let $VALUE = Symbol(); | |
let dictionaryArr = []; | |
let dictionary = {}; | |
let dictionaryRoot = dictionary; | |
let dictionarySize = 65536; | |
let current = ''; | |
let result = []; | |
for ( let i = 0; i < 65536; i++ ) { | |
const code = String.fromCharCode ( i ); | |
dictionary[code] = { | |
[$VALUE]: i | |
}; | |
} | |
for ( let i = 0, l = str.length; i < l; i++ ) { | |
let char = str[i]; | |
let next = char; | |
let valueNext = dictionary[next]; | |
if ( valueNext !== undefined && dictionarySize < DICTIONARY_LIMIT ) { | |
current = next; | |
dictionary = valueNext; | |
} else { | |
result.push ( dictionary[$VALUE] ); | |
dictionary[next] = { | |
[$VALUE]: dictionarySize++ | |
}; | |
current = char; | |
dictionary = dictionaryRoot[char]; | |
} | |
} | |
if ( current ) { | |
result.push ( dictionary[$VALUE] ); | |
} | |
console.log('dic size',JSON.stringify ( Array.from ( Object.entries ( dictionary ) ) ).length ); | |
console.log ( 'data size', result.length ); | |
console.log('dictionarySize', dictionarySize); | |
// console.log ( '>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>', result.length, fromCharCodes ( result ).length ); | |
return charcodes2string ( result ); | |
// console.log ( result ); | |
return result; | |
}; | |
const decompress_2_ = arr => { | |
arr = string2charcodes ( arr ); | |
let dictionary = []; | |
let dictionarySize = 65536; | |
let w = String.fromCharCode ( arr[0] ); | |
let result = w; | |
let entry = ''; | |
for ( let i = 1, l = arr.length; i < l; i++ ) { | |
const idx = arr[i]; | |
const value = ( idx < 65536 ) ? String.fromCharCode ( idx ) : dictionary[idx]; | |
if ( value ) { | |
entry = value; | |
} else { | |
if ( idx === dictionarySize ) { | |
entry = w + w[0]; | |
} else { | |
throw new Error ( 'Impossible' ); | |
} | |
} | |
result += entry; | |
if ( dictionarySize < DICTIONARY_LIMIT ) { | |
dictionary[dictionarySize++] = w + entry[0]; | |
} | |
w = entry; | |
} | |
console.log('dic size',JSON.stringify ( Array.from ( dictionary ) ).length ); | |
console.log ( 'data size', result.length ); | |
console.log('dictionarySize', dictionarySize); | |
return result; | |
// return fromCharCodes ( result ); | |
}; | |
const compress_1_ = str => { | |
let $VALUE = Symbol(); | |
let dictionary = {}; | |
let dictionaryRoot = dictionary; | |
let ditionarySize = 65536; | |
let current = ''; | |
let result = []; | |
for ( let i = 0; i < 65536; i++ ) { | |
const code = String.fromCharCode ( i ); | |
dictionary[code] = { | |
[$VALUE]: i | |
}; | |
} | |
for ( let i = 0, l = str.length; i < l; i++ ) { | |
let char = str[i]; | |
let next = char; | |
let valueNext = dictionary[next]; | |
if ( valueNext !== undefined ) { | |
current = next; | |
dictionary = valueNext; | |
} else { | |
result.push ( dictionary[$VALUE] ); | |
dictionary[next] = { | |
[$VALUE]: ditionarySize++ | |
}; | |
current = char; | |
dictionary = dictionaryRoot[char]; | |
} | |
} | |
if ( current ) { | |
result.push ( dictionary[$VALUE] ); | |
} | |
console.log('dic size',JSON.stringify ( Array.from ( Object.entries ( dictionary ) ) ).length ); | |
console.log ( 'data size', result.length ); | |
console.log({ditionarySize}) | |
const resultString = fromCharCodes ( result ); | |
// let resultString = ''; | |
// for ( let i = 0, l = result.length; i < l; i++ ) { | |
// resultString += String.fromCharCode ( result[i] ); | |
// } | |
// return result; | |
return resultString; | |
}; | |
const decompress_1_ = str => { | |
let dictionary = {}; | |
let dictionarySize = 65536; | |
let w = str[0]; | |
let result = w; | |
let entry = ''; | |
for ( let i = 1, l = str.length; i < l; i++ ) { | |
const char = str[i]; | |
const value = ( char.length === 1 ) ? char : dictionary[char.charCodeAt ( 0 )]; | |
if ( value ) { | |
entry = value; | |
} else { | |
// if ( char.charCodeAt ( 0 ) === dictionarySize ) { | |
entry = w + w[0]; | |
// } else { | |
// throw new Error ( 'Impossible' ); | |
// } | |
} | |
result += entry; | |
dictionary[dictionarySize++] = w + entry[0]; | |
w = entry; | |
} | |
// console.log('dic size',JSON.stringify ( Array.from ( dictionary ) ).length ); | |
// console.log ( 'data size', result.length ); | |
// console.log({ditionarySize}) | |
console.log ( {dictionarySize} ); | |
return result; | |
}; | |
const compress______ = str => { | |
let $VALUE = Symbol(); | |
let dictionary = {}; | |
let dictionaryRoot = dictionary; | |
let ditionarySize = 65536; | |
let current = ''; | |
let result = []; | |
for ( let i = 0; i < 65536; i++ ) { | |
const code = String.fromCharCode ( i ); | |
dictionary[code] = { | |
[$VALUE]: i | |
}; | |
} | |
for ( let i = 0, l = str.length; i < l; i++ ) { | |
let char = str[i]; | |
let next = char; | |
let valueNext = dictionary[next]; | |
if ( valueNext !== undefined ) { | |
current = next; | |
dictionary = valueNext; | |
} else { | |
result.push ( dictionary[$VALUE] ); | |
dictionary[next] = { | |
[$VALUE]: ditionarySize++ | |
}; | |
current = char; | |
dictionary = dictionaryRoot[char]; | |
} | |
} | |
if ( current ) { | |
result.push ( dictionary[$VALUE] ); | |
} | |
console.log('dic size',JSON.stringify ( Array.from ( Object.entries ( dictionary ) ) ).length ); | |
console.log ( 'data size', result.length ); | |
console.log({ditionarySize}) | |
return result; | |
}; | |
const decompress______ = arr => { | |
let dictionary = []; | |
let dictionarySize = 65536; | |
let w = String.fromCharCode ( arr[0] ); | |
let result = w; | |
let entry = ''; | |
for ( let i = 1, l = arr.length; i < l; i++ ) { | |
const idx = arr[i]; | |
const value = ( idx < 65536 ) ? String.fromCharCode ( idx ) : dictionary[idx]; | |
if ( value ) { | |
entry = value; | |
} else { | |
if ( idx === dictionarySize ) { | |
entry = w + w[0]; | |
} else { | |
throw new Error ( 'Impossible' ); | |
} | |
} | |
result += entry; | |
dictionary[dictionarySize++] = w + entry[0]; | |
w = entry; | |
} | |
// console.log('dic size',JSON.stringify ( Array.from ( dictionary ) ).length ); | |
// console.log ( 'data size', result.length ); | |
// console.log({ditionarySize}) | |
console.log ( {dictionarySize} ); | |
return result; | |
}; | |
const compress_____ = str => { | |
class Dictionary extends Map { | |
get ( idx ) { | |
if ( idx.length === 1 ) { | |
return idx.charCodeAt ( 0 ); | |
} | |
return super.get ( idx ); | |
} | |
} | |
let dictionary = new Dictionary (); | |
let ditionarySize = 65536; | |
let current = ''; | |
let result = []; | |
for ( let i = 0, l = str.length; i < l; i++ ) { | |
let char = str[i]; | |
let next = current + char; | |
let valueNext = dictionary.get ( next ); | |
if ( valueNext !== undefined ) { | |
current = next; | |
} else { | |
result.push ( dictionary.get ( current ) ); | |
dictionary.set ( next, ditionarySize++ ); | |
current = char; | |
} | |
} | |
if ( current ) { | |
result.push ( dictionary.get ( current ) ); | |
} | |
// console.log('dic size',JSON.stringify ( Array.from ( dictionary.entries () ) ).length ); | |
// console.log ( 'data size', result.length ); | |
// console.log({ditionarySize}) | |
return result; | |
}; | |
const decompress_____ = arr => { | |
let dictionary = []; | |
let dictionarySize = 65536; | |
let w = String.fromCharCode ( arr[0] ); | |
let result = w; | |
let entry = ''; | |
for ( let i = 1, l = arr.length; i < l; i++ ) { | |
const idx = arr[i]; | |
const value = ( idx < 65536 ) ? String.fromCharCode ( idx ) : dictionary[idx]; | |
if ( value ) { | |
entry = value; | |
} else { | |
if ( idx === dictionarySize ) { | |
entry = w + w.charAt ( 0 ); | |
} else { | |
throw new Error ( 'Impossible' ); | |
} | |
} | |
result += entry; | |
dictionary[dictionarySize++] = w + entry.charAt(0); | |
w = entry; | |
} | |
return result; | |
}; | |
const compress____ = str => { | |
class Dictionary extends Map { | |
get ( idx ) { | |
if ( idx.length === 1 ) { | |
return idx.charCodeAt ( 0 ); | |
} | |
return super.get ( idx ); | |
} | |
} | |
let dictionary = new Dictionary (); | |
let ditionarySize = 65536; | |
let current = ''; | |
let result = []; | |
for ( let i = 0, l = str.length; i < l; i++ ) { | |
let char = str[i]; | |
let next = current + char; | |
let valueNext = dictionary.get ( next ); | |
if ( valueNext !== undefined ) { | |
current = next; | |
} else { | |
result.push ( dictionary.get ( current ) ); | |
dictionary.set ( next, ditionarySize++ ); | |
current = char; | |
} | |
} | |
if ( current ) { | |
result.push ( dictionary.get ( current ) ); | |
} | |
// console.log('dic size',JSON.stringify ( Array.from ( dictionary.entries () ) ).length ); | |
// console.log ( 'data size', result.length ); | |
// console.log({ditionarySize}) | |
return result; | |
}; | |
const decompress____ = arr => { | |
// class Dictionary extends Array { | |
// at ( idx ) { | |
// if ( idx < 65536 ) { | |
// return String.fromCharCode ( idx ); | |
// } | |
// return this[idx]; | |
// } | |
// } | |
// const dictionary = new Dictionary ( 65536 ).fill ( 0 ); | |
const dictionary = []; | |
// const dictionary = []; | |
let w = String.fromCharCode ( arr[0] ); | |
let result = w; | |
let entry = ''; | |
let dictionarySize = 65536; | |
// for ( let i = 0; i < 65536; i++ ) { | |
// dictionary[i] = String.fromCharCode ( i ); | |
// } | |
for ( let i = 1, l = arr.length; i < l; i++ ) { | |
const idx = arr[i]; | |
// const value = dictionary[idx]; | |
// const value = dictionary.at ( idx ); | |
const value = ( idx < 65536 ) ? String.fromCharCode ( idx ) : dictionary[idx]; | |
if ( value ) { | |
entry = value; | |
} else { | |
if ( idx === dictionarySize ) { | |
entry = w + w.charAt ( 0 ); | |
} else { | |
throw new Error ( 'Impossible' ); | |
} | |
} | |
result += entry; | |
dictionary[dictionarySize++] = w + entry.charAt(0); | |
w = entry; | |
} | |
return result; | |
}; | |
const compress___ = str => { | |
let dictionary = new Map (); | |
let ditionarySize = 256; | |
let result = []; | |
let current = ''; | |
for ( let i = 0; i < 256; i++ ) { | |
const code = String.fromCharCode ( i ); | |
dictionary.set ( code, i ); | |
} | |
for ( let i = 0, l = str.length; i < l; i++ ) { | |
let char = str[i]; | |
let next = current + char; | |
let valueNext = dictionary.get ( next ); | |
if ( valueNext !== undefined ) { | |
current = next; | |
} else { | |
result.push ( dictionary.get ( current ) ); | |
dictionary.set ( next, ditionarySize++ ); | |
current = char; | |
} | |
} | |
if ( current ) { | |
result.push ( dictionary.get ( current ) ); | |
} | |
// console.log('dic size',JSON.stringify ( Array.from ( dictionary.entries () ) ).length ); | |
// console.log ( 'data size', result.length ); | |
// console.log({ditionarySize}) | |
return result; | |
}; | |
const decompress___ = arr => { | |
const dictionary = []; | |
let w = String.fromCharCode ( arr[0] ); | |
let result = w; | |
let entry = ''; | |
let dictionarySize = 256; | |
for ( let i = 0; i < 256; i++ ) { | |
dictionary[i] = String.fromCharCode ( i ); | |
} | |
for ( let i = 1, l = arr.length; i < l; i++ ) { | |
const idx = arr[i]; | |
const value = dictionary[idx]; | |
if ( value ) { | |
entry = value; | |
} else { | |
if ( idx === dictionarySize ) { | |
entry = w + w[0]; | |
} else { | |
throw new Error ( 'Impossible' ); | |
} | |
} | |
result += entry; | |
// if ( !value || value.length < MAX_KEY_LENGTH ) { | |
dictionary[dictionarySize++] = w + entry[0]; | |
w = entry; | |
// } else { | |
// console.log ( JSON.stringify(dictionary) ); | |
// process.exit(1) | |
// w = ''; | |
// entry = ''; | |
// } | |
} | |
// console.log({ dictionarySize }); | |
const u8 = new Uint8Array ( result.length ); | |
result.split ( '' ).forEach ( ( char, i ) => { | |
u8[i] = char.charCodeAt ( 0 ); | |
}); | |
return decoder.decode ( u8 ); | |
}; | |
const compress__ = str => { | |
const u8 = encoder.encode ( str ); | |
const dictionary = new Map (); | |
const result = []; | |
let current = ''; | |
let ditionarySize = 256; | |
for ( let i = 0; i < 256; i++ ) { | |
const code = String.fromCharCode ( i ); | |
dictionary.set ( code, i ); | |
} | |
for ( let i = 0, l = u8.length; i < l; i++ ) { | |
let char = String.fromCharCode ( u8[i] ); | |
let next = current + char; | |
let valueNext = dictionary.get ( next ); | |
if ( valueNext !== undefined ) { | |
// console.log ( i, char, current || '_', next ); | |
// if ( next.length >= MAX_KEY_LENGTH ) { | |
// console.count ( 'asd' ); | |
// result.push ( valueNext ); | |
// current = ''; | |
// console.count('asd') | |
// current = next; | |
// } else { | |
current = next; | |
// } | |
} else { | |
// console.log ( i, char, current || '_', next, '[NEW]!' ); | |
result.push ( dictionary.get ( current ) ); | |
dictionary.set ( next, ditionarySize++ ); | |
current = char; | |
} | |
} | |
if ( current ) { | |
result.push ( dictionary.get ( current ) ); | |
} | |
// console.log('dic size',JSON.stringify ( Array.from ( dictionary.entries () ) ).length ); | |
// console.log ( 'data size', result.length ); | |
// console.log({ditionarySize}) | |
return result; | |
}; | |
const decompress__ = arr => { | |
const dictionary = []; | |
let w = String.fromCharCode ( arr[0] ); | |
let result = w; | |
let entry = ''; | |
let dictionarySize = 256; | |
for ( let i = 0; i < 256; i++ ) { | |
dictionary[i] = String.fromCharCode ( i ); | |
} | |
for ( let i = 1, l = arr.length; i < l; i++ ) { | |
const idx = arr[i]; | |
const value = dictionary[idx]; | |
if ( value ) { | |
entry = value; | |
} else { | |
if ( idx === dictionarySize ) { | |
entry = w + w.charAt ( 0 ); | |
} else { | |
throw new Error ( 'Impossible' ); | |
} | |
} | |
result += entry; | |
// if ( !value || value.length < MAX_KEY_LENGTH ) { | |
dictionary[dictionarySize++] = w + entry.charAt(0); | |
w = entry; | |
// } else { | |
// console.log ( JSON.stringify(dictionary) ); | |
// process.exit(1) | |
// w = ''; | |
// entry = ''; | |
// } | |
} | |
// console.log({ dictionarySize }); | |
const u8 = new Uint8Array ( result.length ); | |
result.split ( '' ).forEach ( ( char, i ) => { | |
u8[i] = char.charCodeAt ( 0 ); | |
}); | |
return decoder.decode ( u8 ); | |
}; | |
const compress_ = str => { | |
const u8 = encoder.encode ( str ); | |
const dictionary = new Map (); | |
const result = []; | |
let current = ''; | |
let ditionarySize = 256; | |
for ( let i = 0; i < 256; i++ ) { | |
const code = String.fromCharCode ( i ); | |
dictionary.set ( code, i ); | |
} | |
for ( let i = 0, l = u8.length; i < l; i++ ) { | |
let char = String.fromCharCode ( u8[i] ); | |
let next = current + char; | |
let valueNext = dictionary.get ( next ); | |
if ( valueNext !== undefined ) { | |
current = next; | |
} else { | |
result.push ( dictionary.get ( current ) ); | |
dictionary.set ( next, ditionarySize++ ); | |
current = char; | |
} | |
} | |
if ( current ) { | |
result.push ( dictionary.get ( current ) ); | |
} | |
return result; | |
}; | |
const decompress_ = arr => { | |
const dictionary = []; | |
let w = String.fromCharCode ( arr[0] ); | |
let result = w; | |
let entry = ''; | |
let dictSize = 256; | |
for ( let i = 0; i < 256; i++ ) { | |
dictionary[i] = String.fromCharCode ( i ); | |
} | |
for ( let i = 1, l = arr.length; i < l; i++ ) { | |
const k = arr[i]; | |
if ( dictionary[k] ) { | |
entry = dictionary[k]; | |
} else { | |
if ( k === dictSize ) { | |
entry = w + w.charAt ( 0 ); | |
} else { | |
throw new Error ( 'Impossible' ); | |
} | |
} | |
result += entry; | |
dictionary[dictSize++] = w + entry.charAt(0); | |
w = entry; | |
} | |
const u8 = new Uint8Array ( result.length ); | |
result.split ( '' ).forEach ( ( char, i ) => { | |
u8[i] = char.charCodeAt ( 0 ); | |
}); | |
return decoder.decode ( u8 ); | |
}; | |
// const input = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; | |
// const input8 = encoder.encode ( input ); | |
const input = '[electron] {"config":"{\"skeleton\":{\"css\":\".layout,.layout-header,.layout-footer,.layout-content{border-color:rgb(214,214,214) !important}html.has-sidebar .sidebar{border-left-width:0px !important}html:not(.has-sidebar):not(.has-panel-left) .mainbar,html.is-zen .mainbar{border-left-width:0px !important}.mainbar{background-color:rgb(255,255,255) !important;color:rgb(31,31,31) !important}.mainbar .toolbar:not(.viewlet-toolbar){background-color:rgb(245,245,245) !important;color:rgb(31,31,31) !important}.sidebar{background-color:rgb(255,255,255) !important;color:rgb(31,31,31) !important}.statusbar{background-color:rgb(245,245,245) !important;color:rgb(31,31,31) !important}.viewbar{background-color:rgb(27,29,31) !important;color:rgb(255,255,255) !important}.app{background-color:rgb(240,240,240) !important;border-color:rgba(0,0,0,0) !important;color:rgb(31,31,31) !important}.layout{position:relative;display:flex;align-items:stretch}.layout > *{margin-bottom:0px !important}.layout-header,.layout-content,.layout-footer{border-radius:0px;flex-shrink:0}.layout-header{background-color:rgb(51,62,69);border-color:rgb(16,20,22);color:rgb(255,255,255)}.layout-content{padding:0.625rem;flex-grow:1}.layout-footer{background-color:rgb(51,62,69);border-color:rgb(16,20,22);color:rgb(255,255,255)}.layout{height:100%}.layout .layout{height:auto}.layout .layout:not(:last-child),.layout .multiple > .layout:last-child,.layout .tagbox-tags > .layout:last-child{margin-bottom:0.625rem}.layout-content{height:0px;overflow:auto;padding:0px}.layout.horizontal{flex-direction:row;overflow:hidden}.layout.vertical,.layout:not(.vertical):not(.horizontal){flex-direction:column;overflow:auto}*{border-color:inherit}*,::before,::after{box-sizing:inherit}html{box-sizing:border-box}*,::before,::after{flex-shrink:1}html{font-family:sans-serif;line-height:1.15;text-size-adjust:100%}body{margin:0px}html{height:100%;font-size:16px;-webkit-tap-highlight-color:transparent}body{font-family:-apple-system,BlinkMacSystemFont,\\\"Segoe UI\\\",Roboto,Oxygen,Ubuntu,Cantarell,\\\"Fira Sans\\\",\\\"Droid Sans\\\",\\\"Helvetica Neue\\\",Arial,sans-serif;font-size:1rem;line-height:1.375;height:100%}body{user-select:none !important}body,input,textarea{font-family:-apple-system,BlinkMacSystemFont,\\\"Segoe UI\\\",Roboto,Oxygen,Ubuntu,Cantarell,\\\"Fira Sans\\\",\\\"Droid Sans\\\",\\\"Helvetica Neue\\\",Arial,sans-serif,\\\"Twemoji Color Emoji\\\";font-size:16px}*{transition:opacity 0.15s ease 0s}.toolbar{display:flex;align-items:center;justify-content:center;box-sizing:content-box;z-index:1;transition:none 0s ease 0s;overflow:hidden !important;padding:0px 0.625rem !important}.toolbar.layout-header,.toolbar:not(.layout-footer){height:38px;border-bottom-width:1px;border-bottom-style:solid}html.mac:not(.has-titlebar) .toolbar.layout-header:not(.viewlet-toolbar),html.mac:not(.has-titlebar) .modal.open .toolbar.card-header{app-region:drag}.layout-content{position:relative}.app > .layout{overflow:hidden !important}.layout.column{overflow:hidden !important}.layout.column + .layout.column{border-left-width:1px;border-left-style:solid}body{counter-reset:katexEqnNo 0 mmlEqnNo 0}.preview-wrapper{position:relative;overflow:hidden !important}.mainbar{flex:4 4 300px;min-width:300px}.sidebar,.panel{flex:1 1 165px;min-width:165px;max-width:550px}.statusbar{height:26px;overflow:hidden;flex-wrap:nowrap;padding:0px 0.625rem;z-index:10000;font-variant-numeric:tabular-nums;box-sizing:content-box;border-style:solid;border-width:1px 0px 0px !important}.viewbar{display:flex;flex-direction:column;flex:0 0 68px;min-width:68px;max-width:68px;box-sizing:content-box;app-region:drag}.app{width:100%;height:100%;overflow:hidden !important}html.mac.electron:not(.is-fullscreen) .app{border-radius:4.5px}@font-face{font-family:\\\"Twemoji Color Emoji\\\";font-style:normal;font-weight:400;font-display:block;src:url(\\\"fonts/twemoji-cff2_colr_1.otf\\\") format(\\\"opentype\\\")}:root{--sash-size:4px}\",\"html\":\"<div class=\\\"layout vertical\\\" data-id=\\\"view\\\"><div data-layout-id=\\\"app\\\" class=\\\"layout horizontal layout-content\\\"><div class=\\\"layout column viewbar\\\" style=\\\"width: 68px;\\\"></div><div class=\\\"layout column sidebar\\\" data-id=\\\"help\\\" style=\\\"width: 253px; flex-basis: 253px;\\\"></div><div class=\\\"layout column mainbar\\\" data-id=\\\"help\\\" style=\\\"width: 447px; flex-basis: 447px;\\\"><div class=\\\"layout-header toolbar\\\"></div><div class=\\\"preview-wrapper layout-content\\\" data-id=\\\"help-cheatsheet\\\"></div><div class=\\\"layout-footer statusbar no-wrap\\\"></div></div></div></div>\"}}","process":"{\"arch\":\"arm64\",\"platform\":\"darwin\",\"cwd\":\"/Users/fabio/Code/fabiospampinato/notable-private\",\"execPath\":\"/Users/fabio/Code/fabiospampinato/notable-private/node_modules/electron/dist/Electron.app/Contents/MacOS/Electron\",\"env\":{\"DEV\":true,\"TEST\":false,\"NODE_ENV\":\"development\"},\"versions\":{\"chrome\":\"106.0.5249.119\",\"electron\":\"21.2.0\",\"node\":\"16.16.0\",\"v8\":\"10.6.194.18-electron.0\"}}","isARM64Translation":false,"cwd":false,"wid":1}'; | |
const input8 = encoder.encode ( input ); | |
// const input = fs.readFileSync ( './wap.txt' ).toString (); | |
// const input8 = new Uint8Array ( fs.readFileSync ( './wap.txt' ) ); | |
console.time('lzw.compress'); | |
const comp = compress(input); | |
console.timeEnd('lzw.compress'); | |
console.time('lzw.decompress'); | |
const decomp = decompress(comp); | |
console.timeEnd('lzw.decompress'); | |
console.log ( 'Ratio:', comp.length / input.length ); | |
// console.log ( input === decomp ); | |
// assert.deepEqual ( input, decomp ); | |
// console.log ( input.length, comp.length, decomp.length ); | |
// console.log ( input ); | |
// console.log ( '>>>>>>>>>>>>>>>>>>>>>>>>>>>' ); | |
// console.log ( decomp ); | |
try { | |
assert.deepStrictEqual ( input, decomp ); | |
} catch { | |
throw new Error ( 'Wrong!' ); | |
} | |
console.log ( '=======================' ); | |
console.time('fflate.compress'); | |
const comp2 = deflateSync(input8); | |
console.timeEnd('fflate.compress'); | |
console.time('fflate.decompress'); | |
const decomp2 = inflateSync(comp2); | |
console.timeEnd('fflate.decompress'); | |
console.log ( 'Ratio:', comp2.length / input8.length ); | |
console.log ( '=======================' ); | |
console.time('lz.compress'); | |
const comp3 = LZW.compressToURL(input); | |
console.timeEnd('lz.compress'); | |
console.time('lz.decompress'); | |
const decomp3 = LZW.decompressFromURL(comp3); | |
console.timeEnd('lz.decompress'); | |
console.log ( 'Ratio:', comp3.length / input.length ); | |
console.log ( '=======================' ); | |
console.time('huffy.compress'); | |
const comp4 = Huffy.compress(input8); | |
console.timeEnd('huffy.compress'); | |
console.time('huffy.decompress'); | |
const decomp4 = Huffy.decompress(comp4); | |
console.timeEnd('huffy.decompress'); | |
console.log ( 'Ratio:', comp4.length / input8.length ); | |
console.log ( '=======================' ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment