You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
160 lines
3.6 KiB
160 lines
3.6 KiB
module.exports = Pager |
|
|
|
function Pager (pageSize, opts) { |
|
if (!(this instanceof Pager)) return new Pager(pageSize, opts) |
|
|
|
this.length = 0 |
|
this.updates = [] |
|
this.path = new Uint16Array(4) |
|
this.pages = new Array(32768) |
|
this.maxPages = this.pages.length |
|
this.level = 0 |
|
this.pageSize = pageSize || 1024 |
|
this.deduplicate = opts ? opts.deduplicate : null |
|
this.zeros = this.deduplicate ? alloc(this.deduplicate.length) : null |
|
} |
|
|
|
Pager.prototype.updated = function (page) { |
|
while (this.deduplicate && page.buffer[page.deduplicate] === this.deduplicate[page.deduplicate]) { |
|
page.deduplicate++ |
|
if (page.deduplicate === this.deduplicate.length) { |
|
page.deduplicate = 0 |
|
if (page.buffer.equals && page.buffer.equals(this.deduplicate)) page.buffer = this.deduplicate |
|
break |
|
} |
|
} |
|
if (page.updated || !this.updates) return |
|
page.updated = true |
|
this.updates.push(page) |
|
} |
|
|
|
Pager.prototype.lastUpdate = function () { |
|
if (!this.updates || !this.updates.length) return null |
|
var page = this.updates.pop() |
|
page.updated = false |
|
return page |
|
} |
|
|
|
Pager.prototype._array = function (i, noAllocate) { |
|
if (i >= this.maxPages) { |
|
if (noAllocate) return |
|
grow(this, i) |
|
} |
|
|
|
factor(i, this.path) |
|
|
|
var arr = this.pages |
|
|
|
for (var j = this.level; j > 0; j--) { |
|
var p = this.path[j] |
|
var next = arr[p] |
|
|
|
if (!next) { |
|
if (noAllocate) return |
|
next = arr[p] = new Array(32768) |
|
} |
|
|
|
arr = next |
|
} |
|
|
|
return arr |
|
} |
|
|
|
Pager.prototype.get = function (i, noAllocate) { |
|
var arr = this._array(i, noAllocate) |
|
var first = this.path[0] |
|
var page = arr && arr[first] |
|
|
|
if (!page && !noAllocate) { |
|
page = arr[first] = new Page(i, alloc(this.pageSize)) |
|
if (i >= this.length) this.length = i + 1 |
|
} |
|
|
|
if (page && page.buffer === this.deduplicate && this.deduplicate && !noAllocate) { |
|
page.buffer = copy(page.buffer) |
|
page.deduplicate = 0 |
|
} |
|
|
|
return page |
|
} |
|
|
|
Pager.prototype.set = function (i, buf) { |
|
var arr = this._array(i, false) |
|
var first = this.path[0] |
|
|
|
if (i >= this.length) this.length = i + 1 |
|
|
|
if (!buf || (this.zeros && buf.equals && buf.equals(this.zeros))) { |
|
arr[first] = undefined |
|
return |
|
} |
|
|
|
if (this.deduplicate && buf.equals && buf.equals(this.deduplicate)) { |
|
buf = this.deduplicate |
|
} |
|
|
|
var page = arr[first] |
|
var b = truncate(buf, this.pageSize) |
|
|
|
if (page) page.buffer = b |
|
else arr[first] = new Page(i, b) |
|
} |
|
|
|
Pager.prototype.toBuffer = function () { |
|
var list = new Array(this.length) |
|
var empty = alloc(this.pageSize) |
|
var ptr = 0 |
|
|
|
while (ptr < list.length) { |
|
var arr = this._array(ptr, true) |
|
for (var i = 0; i < 32768 && ptr < list.length; i++) { |
|
list[ptr++] = (arr && arr[i]) ? arr[i].buffer : empty |
|
} |
|
} |
|
|
|
return Buffer.concat(list) |
|
} |
|
|
|
function grow (pager, index) { |
|
while (pager.maxPages < index) { |
|
var old = pager.pages |
|
pager.pages = new Array(32768) |
|
pager.pages[0] = old |
|
pager.level++ |
|
pager.maxPages *= 32768 |
|
} |
|
} |
|
|
|
function truncate (buf, len) { |
|
if (buf.length === len) return buf |
|
if (buf.length > len) return buf.slice(0, len) |
|
var cpy = alloc(len) |
|
buf.copy(cpy) |
|
return cpy |
|
} |
|
|
|
function alloc (size) { |
|
if (Buffer.alloc) return Buffer.alloc(size) |
|
var buf = new Buffer(size) |
|
buf.fill(0) |
|
return buf |
|
} |
|
|
|
function copy (buf) { |
|
var cpy = Buffer.allocUnsafe ? Buffer.allocUnsafe(buf.length) : new Buffer(buf.length) |
|
buf.copy(cpy) |
|
return cpy |
|
} |
|
|
|
function Page (i, buf) { |
|
this.offset = i * buf.length |
|
this.buffer = buf |
|
this.updated = false |
|
this.deduplicate = 0 |
|
} |
|
|
|
function factor (n, out) { |
|
n = (n - (out[0] = (n & 32767))) / 32768 |
|
n = (n - (out[1] = (n & 32767))) / 32768 |
|
out[3] = ((n - (out[2] = (n & 32767))) / 32768) & 32767 |
|
}
|
|
|