index.js 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. 'use strict'
  2. class Hoopy extends Array {
  3. constructor (size) {
  4. let index, isIndexOverflowed
  5. if (! isPositiveInteger(size)) {
  6. throw new TypeError('Argument `size` must be a positive integer.')
  7. }
  8. super(size)
  9. this.grow = by => {
  10. if (! isPositiveInteger(by)) {
  11. throw new TypeError('Argument `by` must be a positive integer.')
  12. }
  13. let i
  14. const newSize = size + by
  15. for (i = size; i < newSize; ++i) {
  16. this[i] = undefined
  17. }
  18. if (isIndexOverflowed) {
  19. for (i = 0; i <= index; ++i) {
  20. let j = size + i
  21. if (j >= newSize) {
  22. j %= newSize
  23. }
  24. this[j] = this[i]
  25. this[i] = undefined
  26. }
  27. }
  28. size = newSize
  29. }
  30. return new Proxy(this, {
  31. get (target, key) {
  32. if (isInteger(key)) {
  33. return target[getIndex(key, size)]
  34. }
  35. return target[key]
  36. },
  37. set (target, key, value) {
  38. if (isInteger(key)) {
  39. index = getIndex(key, size)
  40. target[index] = value
  41. if (Math.abs(key) >= size) {
  42. isIndexOverflowed = true
  43. } else {
  44. isIndexOverflowed = false
  45. }
  46. } else {
  47. target[key] = value
  48. }
  49. return true
  50. }
  51. })
  52. }
  53. }
  54. function isPositiveInteger (thing) {
  55. return isInteger(thing) && thing > 0
  56. }
  57. function isInteger (thing) {
  58. try {
  59. return +thing % 1 === 0
  60. } catch (error) {
  61. // Coercing symbols to numbers throws an error
  62. }
  63. return false
  64. }
  65. function getIndex (key, size) {
  66. if (key === 0) {
  67. return 0
  68. }
  69. if (key < 0) {
  70. return (size - Math.abs(key)) % size
  71. }
  72. return key % size
  73. }
  74. function nop () {
  75. throw new Error('Not implemented')
  76. }
  77. Hoopy.prototype.push = nop
  78. Hoopy.prototype.pop = nop
  79. Hoopy.prototype.shift = nop
  80. Hoopy.prototype.unshift = nop
  81. module.exports = Hoopy