UNPKG

@aggris2/ssz

Version:

Simple Serialize

146 lines 6.07 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ArrayBasicTreeViewDU = void 0; const persistent_merkle_tree_1 = require("@chainsafe/persistent-merkle-tree"); const abstract_1 = require("./abstract"); class ArrayBasicTreeViewDU extends abstract_1.TreeViewDU { constructor(type, _rootNode, cache) { super(); this.type = type; this._rootNode = _rootNode; this.nodesChanged = new Set(); this.dirtyLength = false; if (cache) { this.nodes = cache.nodes; this._length = cache.length; this.nodesPopulated = cache.nodesPopulated; } else { this.nodes = []; this._length = this.type.tree_getLength(_rootNode); this.nodesPopulated = false; } } /** * Number of elements in the array. Equal to un-commited length of the array */ get length() { return this._length; } get node() { return this._rootNode; } get cache() { return { nodes: this.nodes, length: this._length, nodesPopulated: this.nodesPopulated, }; } /** * Get element at `index`. Returns the Basic element type value directly */ get(index) { // First walk through the tree to get the root node for that index const chunkIndex = Math.floor(index / this.type.itemsPerChunk); let node = this.nodes[chunkIndex]; if (node === undefined) { node = persistent_merkle_tree_1.getNodeAtDepth(this._rootNode, this.type.depth, chunkIndex); this.nodes[chunkIndex] = node; } return this.type.elementType.tree_getFromPackedNode(node, index); } /** * Set Basic element type `value` at `index` */ set(index, value) { if (index >= this._length) { throw Error(`Error setting index over length ${index} > ${this._length}`); } const chunkIndex = Math.floor(index / this.type.itemsPerChunk); // Create new node if current leafNode is not dirty let nodeChanged; if (this.nodesChanged.has(chunkIndex)) { // TODO: This assumes that node has already been populated nodeChanged = this.nodes[chunkIndex]; } else { const nodePrev = (this.nodes[chunkIndex] ?? persistent_merkle_tree_1.getNodeAtDepth(this._rootNode, this.type.depth, chunkIndex)); nodeChanged = nodePrev.clone(); // Store the changed node in the nodes cache this.nodes[chunkIndex] = nodeChanged; this.nodesChanged.add(chunkIndex); } this.type.elementType.tree_setToPackedNode(nodeChanged, index, value); } /** * Get all values of this array as Basic element type values, from index zero to `this.length - 1` */ getAll() { if (!this.nodesPopulated) { const nodesPrev = this.nodes; const chunksNode = this.type.tree_getChunksNode(this.node); const chunkCount = Math.ceil(this._length / this.type.itemsPerChunk); this.nodes = persistent_merkle_tree_1.getNodesAtDepth(chunksNode, this.type.chunkDepth, 0, chunkCount); // Re-apply changed nodes for (const index of this.nodesChanged) { this.nodes[index] = nodesPrev[index]; } this.nodesPopulated = true; } const values = new Array(this._length); const itemsPerChunk = this.type.itemsPerChunk; // Prevent many access in for loop below const lenFullNodes = Math.floor(this._length / itemsPerChunk); const remainder = this._length % itemsPerChunk; // TODO Optimize: caching the variables used in the loop above it for (let n = 0; n < lenFullNodes; n++) { const leafNode = this.nodes[n]; // TODO: Implement add a fast bulk packed element reader in the elementType // ``` // abstract getValuesFromPackedNode(leafNode: LeafNode, output: V[], indexOffset: number): void; // ``` // if performance here is a problem for (let i = 0; i < itemsPerChunk; i++) { values[n * itemsPerChunk + i] = this.type.elementType.tree_getFromPackedNode(leafNode, i); } } if (remainder > 0) { const leafNode = this.nodes[lenFullNodes]; for (let i = 0; i < remainder; i++) { values[lenFullNodes * itemsPerChunk + i] = this.type.elementType.tree_getFromPackedNode(leafNode, i); } } return values; } commit() { if (this.nodesChanged.size === 0) { return; } // Numerical sort ascending const indexes = Array.from(this.nodesChanged.keys()).sort((a, b) => a - b); const nodes = new Array(indexes.length); for (let i = 0; i < indexes.length; i++) { nodes[i] = this.nodes[indexes[i]]; } const chunksNode = this.type.tree_getChunksNode(this._rootNode); // TODO: Ensure fast setNodesAtDepth() method is correct const newChunksNode = persistent_merkle_tree_1.setNodesAtDepth(chunksNode, this.type.chunkDepth, indexes, nodes); this._rootNode = this.type.tree_setChunksNode(this._rootNode, newChunksNode, this.dirtyLength ? this._length : undefined); this.nodesChanged.clear(); this.dirtyLength = false; } clearCache() { this.nodes = []; this.nodesPopulated = false; // Must clear nodesChanged, otherwise a subsequent commit call will break, because it assumes a node is there this.nodesChanged.clear(); // Reset cached length only if it has been mutated if (this.dirtyLength) { this._length = this.type.tree_getLength(this._rootNode); this.dirtyLength = false; } } } exports.ArrayBasicTreeViewDU = ArrayBasicTreeViewDU; //# sourceMappingURL=arrayBasic.js.map