169 lines
5.8 KiB
JavaScript
169 lines
5.8 KiB
JavaScript
|
"use strict";
|
||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||
|
exports.CompressionTable = void 0;
|
||
|
const JsonPackExtension_1 = require("../JsonPackExtension");
|
||
|
const isSafeInteger = Number.isSafeInteger;
|
||
|
class CompressionTable {
|
||
|
constructor() {
|
||
|
this.integers = new Set();
|
||
|
this.nonIntegers = new Set();
|
||
|
this.table = [];
|
||
|
this.map = new Map();
|
||
|
}
|
||
|
static create(value) {
|
||
|
const table = new CompressionTable();
|
||
|
table.walk(value);
|
||
|
table.finalize();
|
||
|
return table;
|
||
|
}
|
||
|
addInteger(int) {
|
||
|
this.integers.add(int);
|
||
|
}
|
||
|
addLiteral(value) {
|
||
|
if (isSafeInteger(value)) {
|
||
|
this.addInteger(value);
|
||
|
return;
|
||
|
}
|
||
|
this.nonIntegers.add(value);
|
||
|
}
|
||
|
walk(value) {
|
||
|
switch (typeof value) {
|
||
|
case 'object': {
|
||
|
if (!value)
|
||
|
return this.addLiteral(null);
|
||
|
const constructor = value.constructor;
|
||
|
switch (constructor) {
|
||
|
case Object: {
|
||
|
const obj = value;
|
||
|
for (const key in obj) {
|
||
|
this.addLiteral(key);
|
||
|
this.walk(obj[key]);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
case Array: {
|
||
|
const arr = value;
|
||
|
const len = arr.length;
|
||
|
for (let i = 0; i < len; i++)
|
||
|
this.walk(arr[i]);
|
||
|
break;
|
||
|
}
|
||
|
case Map: {
|
||
|
const map = value;
|
||
|
map.forEach((value, key) => {
|
||
|
this.walk(key);
|
||
|
this.walk(value);
|
||
|
});
|
||
|
break;
|
||
|
}
|
||
|
case Set: {
|
||
|
const set = value;
|
||
|
set.forEach((value) => {
|
||
|
this.walk(value);
|
||
|
});
|
||
|
break;
|
||
|
}
|
||
|
case JsonPackExtension_1.JsonPackExtension: {
|
||
|
const ext = value;
|
||
|
this.addInteger(ext.tag);
|
||
|
this.walk(ext.val);
|
||
|
}
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
default:
|
||
|
return this.addLiteral(value);
|
||
|
}
|
||
|
}
|
||
|
finalize() {
|
||
|
const integers = Array.from(this.integers);
|
||
|
integers.sort((a, b) => a - b);
|
||
|
const len = integers.length;
|
||
|
const table = this.table;
|
||
|
const map = this.map;
|
||
|
if (len > 0) {
|
||
|
const first = integers[0];
|
||
|
table.push(first);
|
||
|
map.set(first, 0);
|
||
|
let last = first;
|
||
|
for (let i = 1; i < len; i++) {
|
||
|
const int = integers[i];
|
||
|
table.push(int - last);
|
||
|
map.set(int, i);
|
||
|
last = int;
|
||
|
}
|
||
|
}
|
||
|
const nonIntegers = Array.from(this.nonIntegers);
|
||
|
nonIntegers.sort();
|
||
|
const lenNonIntegers = nonIntegers.length;
|
||
|
for (let i = 0; i < lenNonIntegers; i++) {
|
||
|
const value = nonIntegers[i];
|
||
|
table.push(value);
|
||
|
map.set(value, len + i);
|
||
|
}
|
||
|
this.integers.clear();
|
||
|
this.nonIntegers.clear();
|
||
|
}
|
||
|
getIndex(value) {
|
||
|
const index = this.map.get(value);
|
||
|
if (index === undefined)
|
||
|
throw new Error(`Value [${value}] not found in compression table.`);
|
||
|
return index;
|
||
|
}
|
||
|
getTable() {
|
||
|
return this.table;
|
||
|
}
|
||
|
compress(value) {
|
||
|
switch (typeof value) {
|
||
|
case 'object': {
|
||
|
if (!value)
|
||
|
return this.getIndex(null);
|
||
|
const constructor = value.constructor;
|
||
|
switch (constructor) {
|
||
|
case Object: {
|
||
|
const obj = value;
|
||
|
const newObj = {};
|
||
|
for (const key in obj)
|
||
|
newObj[this.getIndex(key)] = this.compress(obj[key]);
|
||
|
return newObj;
|
||
|
}
|
||
|
case Array: {
|
||
|
const arr = value;
|
||
|
const newArr = [];
|
||
|
const len = arr.length;
|
||
|
for (let i = 0; i < len; i++)
|
||
|
newArr.push(this.compress(arr[i]));
|
||
|
return newArr;
|
||
|
}
|
||
|
case Map: {
|
||
|
const map = value;
|
||
|
const newMap = new Map();
|
||
|
map.forEach((value, key) => {
|
||
|
newMap.set(this.compress(key), this.compress(value));
|
||
|
});
|
||
|
return newMap;
|
||
|
}
|
||
|
case Set: {
|
||
|
const set = value;
|
||
|
const newSet = new Set();
|
||
|
set.forEach((value) => {
|
||
|
newSet.add(this.compress(value));
|
||
|
});
|
||
|
break;
|
||
|
}
|
||
|
case JsonPackExtension_1.JsonPackExtension: {
|
||
|
const ext = value;
|
||
|
const newExt = new JsonPackExtension_1.JsonPackExtension(this.getIndex(ext.tag), this.compress(ext.val));
|
||
|
return newExt;
|
||
|
}
|
||
|
}
|
||
|
throw new Error('UNEXPECTED_OBJECT');
|
||
|
}
|
||
|
default: {
|
||
|
return this.getIndex(value);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
exports.CompressionTable = CompressionTable;
|
||
|
//# sourceMappingURL=CompressionTable.js.map
|