ton-assembly
Version:
TON assembler and disassembler
198 lines • 5.55 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.findCommonPrefix = findCommonPrefix;
exports.buildTree = buildTree;
exports.writeLabelShort = writeLabelShort;
exports.writeLabelLong = writeLabelLong;
exports.writeLabelSame = writeLabelSame;
exports.detectLabelType = detectLabelType;
exports.serializeDict = serializeDict;
const runtime_1 = require("../runtime");
//
// Tree Build
//
function findCommonPrefix(src, startPos = 0) {
// Corner cases
if (src.length === 0) {
return "";
}
const first = src[0];
if (first === undefined)
return "";
let r = first.slice(startPos);
for (let i = 1; i < src.length; i++) {
const s = src[i];
if (s === undefined) {
break;
}
while (s.indexOf(r, startPos) !== startPos) {
r = r.substring(0, r.length - 1);
if (r === "") {
return r;
}
}
}
return r;
}
function pad(src, size) {
while (src.length < size) {
src = "0" + src;
}
return src;
}
function forkMap(src, prefixLen) {
const left = new Map();
const right = new Map();
for (const [key, value] of src.entries()) {
if (key[prefixLen] === "0") {
left.set(key, value);
}
else {
right.set(key, value);
}
}
return { left, right };
}
function buildNode(src, prefixLen) {
if (src.size === 1) {
const first = [...src.values()][0];
if (!first) {
throw new Error("impossible");
}
return { type: "leaf", value: first };
}
const { left, right } = forkMap(src, prefixLen);
return {
type: "fork",
left: buildEdge(left, prefixLen + 1),
right: buildEdge(right, prefixLen + 1),
};
}
function buildEdge(src, prefixLen = 0) {
const label = findCommonPrefix([...src.keys()], prefixLen);
return {
label,
node: buildNode(src, label.length + prefixLen),
};
}
function buildTree(src, keyLength) {
const converted = new Map();
for (const k of src.keys()) {
const padded = pad(k.toString(2), keyLength);
converted.set(padded, src.get(k));
}
return buildEdge(converted);
}
//
// Serialization
//
function writeLabelShort(src, to) {
// Header
to.storeBit(0);
// Unary length
for (let i = 0; i < src.length; i++) {
to.storeBit(1);
}
to.storeBit(0);
// Value
if (src.length > 0) {
to.storeUint(BigInt("0b" + src), src.length);
}
return to;
}
function labelShortLength(src) {
return 1 + src.length + 1 + src.length;
}
function writeLabelLong(src, keyLength, to) {
// Header
to.storeBit(1);
to.storeBit(0);
// Length
let length = Math.ceil(Math.log2(keyLength + 1));
to.storeUint(src.length, length);
// Value
if (src.length > 0) {
to.storeUint(BigInt("0b" + src), src.length);
}
return to;
}
function labelLongLength(src, keyLength) {
return 1 + 1 + Math.ceil(Math.log2(keyLength + 1)) + src.length;
}
function writeLabelSame(value, length, keyLength, to) {
// Header
to.storeBit(1);
to.storeBit(1);
// Value
to.storeBit(value);
// Length
const lenLen = Math.ceil(Math.log2(keyLength + 1));
to.storeUint(length, lenLen);
}
function labelSameLength(keyLength) {
return 1 + 1 + 1 + Math.ceil(Math.log2(keyLength + 1));
}
function isSame(src) {
if (src.length === 0 || src.length === 1) {
return true;
}
for (let i = 1; i < src.length; i++) {
if (src[i] !== src[0]) {
return false;
}
}
return true;
}
function detectLabelType(src, keyLength) {
let kind = "short";
let kindLength = labelShortLength(src);
let longLength = labelLongLength(src, keyLength);
if (longLength < kindLength) {
kindLength = longLength;
kind = "long";
}
if (isSame(src)) {
let sameLength = labelSameLength(keyLength);
if (sameLength < kindLength) {
kind = "same";
}
}
return kind;
}
function writeLabel(src, keyLength, to) {
const type = detectLabelType(src, keyLength);
if (type === "short") {
writeLabelShort(src, to);
}
else if (type === "long") {
writeLabelLong(src, keyLength, to);
}
else if (type === "same") {
writeLabelSame(src[0] === "1", src.length, keyLength, to);
}
}
function writeNode(src, keyLength, serializer, to) {
if (src.type === "leaf") {
serializer(src.value, to);
}
if (src.type === "fork") {
const leftBuilder = new runtime_1.CodeBuilder();
const rightBuilder = new runtime_1.CodeBuilder();
writeEdge(src.left, keyLength - 1, serializer, leftBuilder);
writeEdge(src.right, keyLength - 1, serializer, rightBuilder);
to.storeRef(leftBuilder.asCell());
to.storeRef(rightBuilder.asCell());
// save dictionary info collected for left and right cells
to.pushDictionaryInfo(...leftBuilder.getDictionaryInfo());
to.pushDictionaryInfo(...rightBuilder.getDictionaryInfo());
}
}
function writeEdge(src, keyLength, serializer, to) {
writeLabel(src.label, keyLength, to);
writeNode(src.node, keyLength - src.label.length, serializer, to);
}
function serializeDict(src, keyLength, serializer, to) {
const tree = buildTree(src, keyLength);
writeEdge(tree, keyLength, serializer, to);
}
//# sourceMappingURL=serializeDict.js.map