Map.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. // shared pointer
  2. var i
  3. // shortcuts
  4. var defineProperty = Object.defineProperty
  5. function is (a, b) { return (a === b) || (a !== a && b !== b) } // eslint-disable-line
  6. export default createCollection({
  7. // WeakMap#delete(key:void*):boolean
  8. 'delete': sharedDelete,
  9. // :was Map#get(key:void*[, d3fault:void*]):void*
  10. // Map#has(key:void*):boolean
  11. has: mapHas,
  12. // Map#get(key:void*):boolean
  13. get: sharedGet,
  14. // Map#set(key:void*, value:void*):void
  15. set: sharedSet,
  16. // Map#keys(void):Iterator
  17. keys: sharedKeys,
  18. // Map#values(void):Iterator
  19. values: sharedValues,
  20. // Map#entries(void):Iterator
  21. entries: mapEntries,
  22. // Map#forEach(callback:Function, context:void*):void ==> callback.call(context, key, value, mapObject) === not in specs`
  23. forEach: sharedForEach,
  24. // Map#clear():
  25. clear: sharedClear
  26. })
  27. /**
  28. * ES6 collection constructor
  29. * @return {Function} a collection class
  30. */
  31. function createCollection (proto, objectOnly) {
  32. function Collection (a) {
  33. if (!this || this.constructor !== Collection) return new Collection(a)
  34. this._keys = []
  35. this._values = []
  36. this._itp = [] // iteration pointers
  37. this.objectOnly = objectOnly
  38. // parse initial iterable argument passed
  39. if (a) init.call(this, a)
  40. }
  41. // define size for non object-only collections
  42. if (!objectOnly) {
  43. defineProperty(proto, 'size', {
  44. get: sharedSize
  45. })
  46. }
  47. // set prototype
  48. proto.constructor = Collection
  49. Collection.prototype = proto
  50. return Collection
  51. }
  52. /** parse initial iterable argument passed */
  53. function init (a) {
  54. // init Set argument, like `[1,2,3,{}]`
  55. if (this.add) a.forEach(this.add, this)
  56. // init Map argument like `[[1,2], [{}, 4]]`
  57. else a.forEach(function (a) { this.set(a[0], a[1]) }, this)
  58. }
  59. /** delete */
  60. function sharedDelete (key) {
  61. if (this.has(key)) {
  62. this._keys.splice(i, 1)
  63. this._values.splice(i, 1)
  64. // update iteration pointers
  65. this._itp.forEach(function (p) { if (i < p[0]) p[0]-- })
  66. }
  67. // Aurora here does it while Canary doesn't
  68. return i > -1
  69. }
  70. function sharedGet (key) {
  71. return this.has(key) ? this._values[i] : undefined
  72. }
  73. function has (list, key) {
  74. if (this.objectOnly && key !== Object(key)) throw new TypeError('Invalid value used as weak collection key')
  75. // NaN or 0 passed
  76. if (key !== key || key === 0) for (i = list.length; i-- && !is(list[i], key);) {} // eslint-disable-line
  77. else i = list.indexOf(key)
  78. return i > -1
  79. }
  80. function mapHas (value) {
  81. return has.call(this, this._keys, value)
  82. }
  83. /** @chainable */
  84. function sharedSet (key, value) {
  85. this.has(key) ? this._values[i] = value : this._values[this._keys.push(key) - 1] = value
  86. return this
  87. }
  88. function sharedClear () {
  89. (this._keys || 0).length =
  90. this._values.length = 0
  91. }
  92. /** keys, values, and iterate related methods */
  93. function sharedKeys () {
  94. return sharedIterator(this._itp, this._keys)
  95. }
  96. function sharedValues () {
  97. return sharedIterator(this._itp, this._values)
  98. }
  99. function mapEntries () {
  100. return sharedIterator(this._itp, this._keys, this._values)
  101. }
  102. function sharedIterator (itp, array, array2) {
  103. var p = [0]
  104. var done = false
  105. itp.push(p)
  106. return {
  107. next: function () {
  108. var v
  109. var k = p[0]
  110. if (!done && k < array.length) {
  111. v = array2 ? [array[k], array2[k]] : array[k]
  112. p[0]++
  113. } else {
  114. done = true
  115. itp.splice(itp.indexOf(p), 1)
  116. }
  117. return { done: done, value: v }
  118. }
  119. }
  120. }
  121. function sharedSize () {
  122. return this._values.length
  123. }
  124. function sharedForEach (callback, context) {
  125. var it = this.entries()
  126. for (;;) {
  127. var r = it.next()
  128. if (r.done) break
  129. callback.call(context, r.value[1], r.value[0], this)
  130. }
  131. }