Skip to content

Commit

Permalink
Merge pull request #27 from krigga/improve-perf
Browse files Browse the repository at this point in the history
Improve performance
  • Loading branch information
dvlkv authored Feb 26, 2024
2 parents f4ed489 + 66d2c76 commit 5ae4b2f
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 77 deletions.
70 changes: 29 additions & 41 deletions src/boc/BitBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,65 +88,53 @@ export class BitBuilder {
* @param bits number of bits to write
*/
writeUint(value: bigint | number, bits: number) {

// Special case for 8 bits
if (bits === 8 && this._length % 8 === 0) {
let v = Number(value);
if (v < 0 || v > 255 || !Number.isSafeInteger(v)) {
throw Error(`value is out of range for ${bits} bits. Got ${value}`);
}
this._buffer[this._length / 8] = Number(value);
this._length += 8;
return;
}

// Special case for 16 bits
if (bits === 16 && this._length % 8 === 0) {
let v = Number(value);
if (v < 0 || v > 65536 || !Number.isSafeInteger(v)) {
throw Error(`value is out of range for ${bits} bits. Got ${value}`);
}
this._buffer[this._length / 8] = v >> 8;
this._buffer[this._length / 8 + 1] = v & 0xff;
this._length += 16;
return;
}

// Generic case
let v = BigInt(value);
if (bits < 0 || !Number.isSafeInteger(bits)) {
throw Error(`invalid bit length. Got ${bits}`);
}

// Corner case for zero bits
const v = BigInt(value);

if (bits === 0) {
if (value !== 0n) {
if (v !== 0n) {
throw Error(`value is not zero for ${bits} bits. Got ${value}`);
} else {
return;
}
}

// Check input
let vBits = (1n << BigInt(bits));
const vBits = (1n << BigInt(bits));
if (v < 0 || v >= vBits) {
throw Error(`bitLength is too small for a value ${value}. Got ${bits}`);
}

// Convert number to bits
let b: boolean[] = [];
while (v > 0) {
b.push(v % 2n === 1n);
v /= 2n;
if (this._length + bits > this._buffer.length * 8) {
throw new Error("BitBuilder overflow");
}

const tillByte = 8 - (this._length % 8);
if (tillByte > 0) {
const bidx = Math.floor(this._length / 8);
if (bits < tillByte) {
const wb = Number(v);
this._buffer[bidx] |= wb << (tillByte - bits);
this._length += bits;
} else {
const wb = Number(v >> BigInt(bits - tillByte));
this._buffer[bidx] |= wb;
this._length += tillByte;
}
}
bits -= tillByte;

// Write bits
for (let i = 0; i < bits; i++) {
let off = bits - i - 1;
if (off < b.length) {
this.writeBit(b[off]);
while (bits > 0) {
if (bits >= 8) {
this._buffer[this._length / 8] = Number((v >> BigInt(bits - 8)) & 0xffn);
this._length += 8;
bits -= 8;
} else {
this.writeBit(false);
this._buffer[this._length / 8] = Number((v << BigInt(8 - bits)) & 0xffn);
this._length += bits;
bits = 0;
}
}
}
Expand Down
7 changes: 4 additions & 3 deletions src/boc/cell/utils/topologicalSort.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export function topologicalSort(src: Cell) {
for (let c of allCells.get(hash)!.refs) {
visit(c);
}
sorted.unshift(hash);
sorted.push(hash);
tempMark.delete(hash);
notPermCells.delete(hash);
}
Expand All @@ -51,11 +51,12 @@ export function topologicalSort(src: Cell) {

let indexes = new Map<string, number>();
for (let i = 0; i < sorted.length; i++) {
indexes.set(sorted[i], i);
indexes.set(sorted[sorted.length-i-1], i);
}

let result: { cell: Cell, refs: number[] }[] = [];
for (let ent of sorted) {
for (let i = sorted.length - 1; i >= 0; i--) {
let ent = sorted[i];
const rrr = allCells.get(ent)!;
result.push({ cell: rrr.cell, refs: rrr.refs.map((v) => indexes.get(v)!) });
}
Expand Down
39 changes: 18 additions & 21 deletions src/dict/serializeDict.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,18 +49,17 @@ function removePrefixMap<T>(src: Map<string, T>, length: number) {
}
}

function forkMap<T>(src: Map<string, T>) {
function forkMap<T>(src: Map<string, T>, prefixLen: number) {
if (src.size === 0) {
throw Error('Internal inconsistency');
}
let left = new Map<string, T>();
let right = new Map<string, T>();
for (let k of src.keys()) {
let d = src.get(k)!;
if (k.startsWith('0')) {
left.set(k.substr(1), d);
for (let [k, d] of src.entries()) {
if (k[prefixLen] === '0') {
left.set(k, d);
} else {
right.set(k.substr(1), d);
right.set(k, d);
}
}
if (left.size === 0) {
Expand All @@ -72,27 +71,27 @@ function forkMap<T>(src: Map<string, T>) {
return { left, right };
}

function buildNode<T>(src: Map<string, T>): Node<T> {
function buildNode<T>(src: Map<string, T>, prefixLen: number): Node<T> {
if (src.size === 0) {
throw Error('Internal inconsistency');
}
if (src.size === 1) {
return { type: 'leaf', value: Array.from(src.values())[0] };
}
let { left, right } = forkMap(src);
let { left, right } = forkMap(src, prefixLen);
return {
type: 'fork',
left: buildEdge(left),
right: buildEdge(right)
left: buildEdge(left, prefixLen + 1),
right: buildEdge(right, prefixLen + 1)
}
}

function buildEdge<T>(src: Map<string, T>): Edge<T> {
function buildEdge<T>(src: Map<string, T>, prefixLen = 0): Edge<T> {
if (src.size === 0) {
throw Error('Internal inconsistency');
}
const label = findCommonPrefix(Array.from(src.keys()));
return { label, node: buildNode(removePrefixMap(src, label.length)) };
const label = findCommonPrefix(Array.from(src.keys()), prefixLen);
return { label, node: buildNode(src, label.length + prefixLen) };
}

export function buildTree<T>(src: Map<bigint, T>, keyLength: number) {
Expand Down Expand Up @@ -123,8 +122,8 @@ export function writeLabelShort(src: string, to: Builder) {
to.storeBit(0);

// Value
for (let i = 0; i < src.length; i++) {
to.storeBit(src[i] === '1');
if (src.length > 0) {
to.storeUint(BigInt('0b' + src), src.length);
}
return to;
}
Expand All @@ -143,8 +142,8 @@ export function writeLabelLong(src: string, keyLength: number, to: Builder) {
to.storeUint(src.length, length);

// Value
for (let i = 0; i < src.length; i++) {
to.storeBit(src[i] === '1');
if (src.length > 0) {
to.storeUint(BigInt('0b' + src), src.length);
}
return to;
}
Expand Down Expand Up @@ -207,11 +206,9 @@ function writeLabel(src: string, keyLength: number, to: Builder) {
let type = detectLabelType(src, keyLength);
if (type === 'short') {
writeLabelShort(src, to);
}
if (type === 'long') {
} else if (type === 'long') {
writeLabelLong(src, keyLength, to);
}
if (type === 'same') {
} else if (type === 'same') {
writeLabelSame(src[0] === '1', src.length, keyLength, to);
}
}
Expand Down
25 changes: 13 additions & 12 deletions src/dict/utils/findCommonPrefix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,25 @@
* LICENSE file in the root directory of this source tree.
*/

export function findCommonPrefix(src: string[]) {
export function findCommonPrefix(src: string[], startPos = 0) {

// Corner cases
if (src.length === 0) {
return '';
}
if (src.length === 1) {
return src[0];
}

// Searching for prefix
const sorted = [...src].sort();
let size = 0;
for (let i = 0; i < sorted[0].length; i++) {
if (sorted[0][i] !== sorted[sorted.length - 1][i]) {
break;
let r = src[0].slice(startPos);

for (let i = 1; i < src.length; i++) {
const s = src[i];
while (s.indexOf(r, startPos) !== startPos) {
r = r.substring(0, r.length - 1);

if (r === '') {
return r;
}
}
size++;
}
return src[0].slice(0, size);

return r;
}

0 comments on commit 5ae4b2f

Please sign in to comment.