UNPKG

ton-assembly

Version:

TON assembler and disassembler

198 lines 5.55 kB
"use strict"; 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