diff --git a/lib/mining/miner.js b/lib/mining/miner.js index 83380ff1..66ff68b7 100644 --- a/lib/mining/miner.js +++ b/lib/mining/miner.js @@ -10,6 +10,7 @@ var assert = require('assert'); var util = require('../utils/util'); var co = require('../utils/co'); +var Heap = require('../utils/heap'); var AsyncObject = require('../utils/asyncobject'); var Address = require('../primitives/address'); var MinerBlock = require('./minerblock'); @@ -368,7 +369,7 @@ Miner.prototype.getAddress = function getAddress() { Miner.prototype.build = function build(attempt) { var depMap = {}; var block = attempt.block; - var queue = new Queue(cmpRate); + var queue = new Heap(cmpRate); var priority = this.priorityWeight > 0; var i, j, entry, item, tx, hash, input; var prev, deps, hashes, weight, sigops; @@ -438,7 +439,7 @@ Miner.prototype.build = function build(attempt) { if (weight > this.options.priorityWeight || item.priority < this.options.priorityThreshold) { queue.set(cmpRate); - queue.sort(); + queue.init(); priority = false; queue.push(item); continue; @@ -615,45 +616,6 @@ MinerOptions.fromOptions = function fromOptions(options) { return new MinerOptions().fromOptions(options); }; -/** - * Queue - * @constructor - * @ignore - */ - -function Queue(cmp) { - if (!(this instanceof Queue)) - return new Queue(cmp); - - this.cmp = null; - this.items = []; - this.set(cmp); -} - -Queue.prototype.size = function size() { - return this.items.length; -}; - -Queue.prototype.push = function push(item) { - assert(this.cmp, 'No comparator for queue.'); - util.binaryInsert(this.items, item, this.cmp); -}; - -Queue.prototype.pop = function pop() { - return this.items.pop(); -}; - -Queue.prototype.set = function set(cmp) { - assert(cmp == null || typeof cmp === 'function', - 'Comparator must be a function.'); - this.cmp = cmp || null; -}; - -Queue.prototype.sort = function sort() { - assert(this.cmp, 'No comparator for queue.'); - this.items.sort(this.cmp); -}; - /* * Helpers */ diff --git a/lib/utils/heap.js b/lib/utils/heap.js new file mode 100644 index 00000000..afcc0eb2 --- /dev/null +++ b/lib/utils/heap.js @@ -0,0 +1,235 @@ +/*! + * heap.js - heap object for bcoin + * Copyright (c) 2014-2017, Christopher Jeffrey (MIT License). + * https://github.com/bcoin-org/bcoin + */ + +'use strict'; + +var assert = require('assert'); + +/** + * Priority Queue + * @alias module:utils.Heap + * @constructor + * @param {Function?} cmp + */ + +function Heap(cmp) { + if (!(this instanceof Heap)) + return new Heap(cmp); + + this.cmp = null; + this.items = []; + this.set(cmp); +} + +/** + * Initialize and sort heap. + */ + +Heap.prototype.init = function init() { + var n = this.items.length; + var i; + + if (n <= 1) + return; + + for (i = (n / 2 | 0) - 1; i >= 0; i--) + this.down(i, n); +}; + +/** + * Get heap size. + * @returns {Number} + */ + +Heap.prototype.size = function size() { + return this.items.length; +}; + +/** + * Set comparator. + * @param {Function} cmp + */ + +Heap.prototype.set = function set(cmp) { + assert(cmp == null || typeof cmp === 'function', + 'Comparator must be a function.'); + this.cmp = cmp || null; +}; + +/** + * Push item onto heap. + * @param {Object} item + * @returns {Number} + */ + +Heap.prototype.push = function push(item) { + this.items.push(item); + this.up(this.items.length - 1); + return this.items.length; +}; + +/** + * Pop next item off of heap. + * @param {Object} item + * @returns {Object} + */ + +Heap.prototype.pop = function pop(item) { + var n; + + if (this.items.length === 0) + return; + + n = this.items.length - 1; + + this.swap(0, n); + this.down(0, n); + + return this.items.pop(); +}; + +/** + * Remove item from heap. + * @param {Number} i + * @returns {Object} + */ + +Heap.prototype.remove = function remove(i) { + var n; + + if (this.items.length === 0) + return; + + n = this.items.length - 1; + + if (n !== i) { + this.swap(i, n); + this.down(i, n); + this.up(i); + } + + return this.items.pop(); +}; + +/** + * Swap indicies. + * @private + * @param {Number} a + * @param {Number} b + */ + +Heap.prototype.swap = function swap(a, b) { + var x = this.items[a]; + var y = this.items[b]; + this.items[a] = y; + this.items[b] = x; +}; + +/** + * Compare indicies. + * @private + * @param {Number} i + * @param {Number} j + * @returns {Boolean} + */ + +Heap.prototype.less = function less(i, j) { + return this.cmp(this.items[i], this.items[j]) >= 0; +}; + +/** + * Bubble item down. + * @private + * @param {Number} i + * @param {Number} n + */ + +Heap.prototype.down = function down(i, n) { + var j, l, r; + + for (;;) { + l = 2 * i + 1; + + assert(l >= 0); + + if (l < 0 || l >= n) + break; + + j = l; + r = l + 1; + + if (r < n && !this.less(l, r)) + j = r; + + if (!this.less(j, i)) + break; + + this.swap(i, j); + i = j; + } +}; + +/** + * Bubble item up. + * @private + * @param {Number} i + */ + +Heap.prototype.up = function up(i) { + var j; + + for (;;) { + j = (i - 1) / 2 | 0; + + assert(j >= 0); + + if (j < 0 || j === i) + break; + + if (!this.less(i, j)) + break; + + this.swap(j, i); + i = j; + } +}; + +/** + * Convert heap to sorted array. + * @returns {Object[]} + */ + +Heap.prototype.toArray = function toArray() { + var heap = new Heap(this.cmp); + var result = []; + + heap.items = this.items.slice(); + + while (heap.size() > 0) + result.push(heap.pop()); + + return result.reverse(); +}; + +/** + * Instantiate heap from array and comparator. + * @param {Function} cmp + * @param {Object[]} items + * @returns {Heap} + */ + +Heap.fromArray = function fromArray(cmp, items) { + var heap = new Heap(cmp); + heap.items = items; + heap.init(); + return heap; +}; + +/* + * Expose + */ + +module.exports = Heap;