index.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. module.exports = Pager
  2. function Pager (pageSize, opts) {
  3. if (!(this instanceof Pager)) return new Pager(pageSize, opts)
  4. this.length = 0
  5. this.updates = []
  6. this.pages = new Array(16)
  7. this.pageSize = pageSize || 1024
  8. this.deduplicate = opts ? opts.deduplicate : null
  9. this.zeros = this.deduplicate ? alloc(this.deduplicate.length) : null
  10. }
  11. Pager.prototype.updated = function (page) {
  12. while (this.deduplicate && page.buffer[page.deduplicate] === this.deduplicate[page.deduplicate]) {
  13. page.deduplicate++
  14. if (page.deduplicate === this.deduplicate.length) {
  15. page.deduplicate = 0
  16. if (page.buffer.equals && page.buffer.equals(this.deduplicate)) page.buffer = this.deduplicate
  17. break
  18. }
  19. }
  20. if (page.updated || !this.updates) return
  21. page.updated = true
  22. this.updates.push(page)
  23. }
  24. Pager.prototype.lastUpdate = function () {
  25. if (!this.updates || !this.updates.length) return null
  26. var page = this.updates.pop()
  27. page.updated = false
  28. return page
  29. }
  30. Pager.prototype.get = function (i, noAllocate) {
  31. if (i >= this.pages.length) {
  32. if (noAllocate) return
  33. this.pages = grow(this.pages, i, this.length)
  34. }
  35. var page = this.pages[i]
  36. if (!page && !noAllocate) {
  37. page = this.pages[i] = new Page(i, alloc(this.pageSize))
  38. if (i >= this.length) this.length = i + 1
  39. }
  40. if (page && page.buffer === this.deduplicate && this.deduplicate && !noAllocate) {
  41. page.buffer = copy(page.buffer)
  42. page.deduplicate = 0
  43. }
  44. return page
  45. }
  46. Pager.prototype.set = function (i, buf) {
  47. if (i >= this.pages.length) this.pages = grow(this.pages, i, this.length)
  48. if (i >= this.length) this.length = i + 1
  49. if (!buf || (this.zeros && buf.equals && buf.equals(this.zeros))) {
  50. this.pages[i] = undefined
  51. return
  52. }
  53. if (this.deduplicate && buf.equals && buf.equals(this.deduplicate)) {
  54. buf = this.deduplicate
  55. }
  56. var page = this.pages[i]
  57. var b = truncate(buf, this.pageSize)
  58. if (page) page.buffer = b
  59. else this.pages[i] = new Page(i, b)
  60. }
  61. Pager.prototype.toBuffer = function () {
  62. var list = new Array(this.length)
  63. var empty = alloc(this.pageSize)
  64. for (var i = 0; i < list.length; i++) {
  65. list[i] = this.pages[i] ? this.pages[i].buffer : empty
  66. }
  67. return Buffer.concat(list)
  68. }
  69. function grow (list, index, len) {
  70. var nlen = list.length * 2
  71. while (nlen <= index) nlen *= 2
  72. var twice = new Array(nlen)
  73. for (var i = 0; i < len; i++) twice[i] = list[i]
  74. return twice
  75. }
  76. function truncate (buf, len) {
  77. if (buf.length === len) return buf
  78. if (buf.length > len) return buf.slice(0, len)
  79. var cpy = alloc(len)
  80. buf.copy(cpy)
  81. return cpy
  82. }
  83. function alloc (size) {
  84. if (Buffer.alloc) return Buffer.alloc(size)
  85. var buf = new Buffer(size)
  86. buf.fill(0)
  87. return buf
  88. }
  89. function copy (buf) {
  90. var cpy = Buffer.allocUnsafe ? Buffer.allocUnsafe(buf.length) : new Buffer(buf.length)
  91. buf.copy(cpy)
  92. return cpy
  93. }
  94. function Page (i, buf) {
  95. this.offset = i * buf.length
  96. this.buffer = buf
  97. this.updated = false
  98. this.deduplicate = 0
  99. }