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.
		
		
		
		
		
			
		
			
				
					161 lines
				
				3.6 KiB
			
		
		
			
		
	
	
					161 lines
				
				3.6 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								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
							 | 
						||
| 
								 | 
							
								}
							 |