es6-collections.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. (function (exports) {'use strict';
  2. //shared pointer
  3. var i;
  4. //shortcuts
  5. var defineProperty = Object.defineProperty, is = function(a,b) { return isNaN(a)? isNaN(b): a === b; };
  6. //Polyfill global objects
  7. if (typeof WeakMap == 'undefined') {
  8. exports.WeakMap = createCollection({
  9. // WeakMap#delete(key:void*):boolean
  10. 'delete': sharedDelete,
  11. // WeakMap#clear():
  12. clear: sharedClear,
  13. // WeakMap#get(key:void*):void*
  14. get: sharedGet,
  15. // WeakMap#has(key:void*):boolean
  16. has: mapHas,
  17. // WeakMap#set(key:void*, value:void*):void
  18. set: sharedSet
  19. }, true);
  20. }
  21. if (typeof Map == 'undefined' || typeof ((new Map).values) !== 'function' || !(new Map).values().next) {
  22. exports.Map = createCollection({
  23. // WeakMap#delete(key:void*):boolean
  24. 'delete': sharedDelete,
  25. //:was Map#get(key:void*[, d3fault:void*]):void*
  26. // Map#has(key:void*):boolean
  27. has: mapHas,
  28. // Map#get(key:void*):boolean
  29. get: sharedGet,
  30. // Map#set(key:void*, value:void*):void
  31. set: sharedSet,
  32. // Map#keys(void):Iterator
  33. keys: sharedKeys,
  34. // Map#values(void):Iterator
  35. values: sharedValues,
  36. // Map#entries(void):Iterator
  37. entries: mapEntries,
  38. // Map#forEach(callback:Function, context:void*):void ==> callback.call(context, key, value, mapObject) === not in specs`
  39. forEach: sharedForEach,
  40. // Map#clear():
  41. clear: sharedClear
  42. });
  43. }
  44. if (typeof Set == 'undefined' || typeof ((new Set).values) !== 'function' || !(new Set).values().next) {
  45. exports.Set = createCollection({
  46. // Set#has(value:void*):boolean
  47. has: setHas,
  48. // Set#add(value:void*):boolean
  49. add: sharedAdd,
  50. // Set#delete(key:void*):boolean
  51. 'delete': sharedDelete,
  52. // Set#clear():
  53. clear: sharedClear,
  54. // Set#keys(void):Iterator
  55. keys: sharedValues, // specs actually say "the same function object as the initial value of the values property"
  56. // Set#values(void):Iterator
  57. values: sharedValues,
  58. // Set#entries(void):Iterator
  59. entries: setEntries,
  60. // Set#forEach(callback:Function, context:void*):void ==> callback.call(context, value, index) === not in specs
  61. forEach: sharedForEach
  62. });
  63. }
  64. if (typeof WeakSet == 'undefined') {
  65. exports.WeakSet = createCollection({
  66. // WeakSet#delete(key:void*):boolean
  67. 'delete': sharedDelete,
  68. // WeakSet#add(value:void*):boolean
  69. add: sharedAdd,
  70. // WeakSet#clear():
  71. clear: sharedClear,
  72. // WeakSet#has(value:void*):boolean
  73. has: setHas
  74. }, true);
  75. }
  76. /**
  77. * ES6 collection constructor
  78. * @return {Function} a collection class
  79. */
  80. function createCollection(proto, objectOnly){
  81. function Collection(a){
  82. if (!this || this.constructor !== Collection) return new Collection(a);
  83. this._keys = [];
  84. this._values = [];
  85. this._itp = []; // iteration pointers
  86. this.objectOnly = objectOnly;
  87. //parse initial iterable argument passed
  88. if (a) init.call(this, a);
  89. }
  90. //define size for non object-only collections
  91. if (!objectOnly) {
  92. defineProperty(proto, 'size', {
  93. get: sharedSize
  94. });
  95. }
  96. //set prototype
  97. proto.constructor = Collection;
  98. Collection.prototype = proto;
  99. return Collection;
  100. }
  101. /** parse initial iterable argument passed */
  102. function init(a){
  103. var i;
  104. //init Set argument, like `[1,2,3,{}]`
  105. if (this.add)
  106. a.forEach(this.add, this);
  107. //init Map argument like `[[1,2], [{}, 4]]`
  108. else
  109. a.forEach(function(a){this.set(a[0],a[1])}, this);
  110. }
  111. /** delete */
  112. function sharedDelete(key) {
  113. if (this.has(key)) {
  114. this._keys.splice(i, 1);
  115. this._values.splice(i, 1);
  116. // update iteration pointers
  117. this._itp.forEach(function(p) { if (i < p[0]) p[0]--; });
  118. }
  119. // Aurora here does it while Canary doesn't
  120. return -1 < i;
  121. };
  122. function sharedGet(key) {
  123. return this.has(key) ? this._values[i] : undefined;
  124. }
  125. function has(list, key) {
  126. if (this.objectOnly && key !== Object(key))
  127. throw new TypeError("Invalid value used as weak collection key");
  128. //NaN or 0 passed
  129. if (key != key || key === 0) for (i = list.length; i-- && !is(list[i], key);){}
  130. else i = list.indexOf(key);
  131. return -1 < i;
  132. }
  133. function setHas(value) {
  134. return has.call(this, this._values, value);
  135. }
  136. function mapHas(value) {
  137. return has.call(this, this._keys, value);
  138. }
  139. /** @chainable */
  140. function sharedSet(key, value) {
  141. this.has(key) ?
  142. this._values[i] = value
  143. :
  144. this._values[this._keys.push(key) - 1] = value
  145. ;
  146. return this;
  147. }
  148. /** @chainable */
  149. function sharedAdd(value) {
  150. if (!this.has(value)) this._values.push(value);
  151. return this;
  152. }
  153. function sharedClear() {
  154. this._values.length = 0;
  155. }
  156. /** keys, values, and iterate related methods */
  157. function sharedKeys() {
  158. return sharedIterator(this._itp, this._keys);
  159. }
  160. function sharedValues() {
  161. return sharedIterator(this._itp, this._values);
  162. }
  163. function mapEntries() {
  164. return sharedIterator(this._itp, this._keys, this._values);
  165. }
  166. function setEntries() {
  167. return sharedIterator(this._itp, this._values, this._values);
  168. }
  169. function sharedIterator(itp, array, array2) {
  170. var p = [0], done = false;
  171. itp.push(p);
  172. return {
  173. next: function() {
  174. var v, k = p[0];
  175. if (!done && k < array.length) {
  176. v = array2 ? [array[k], array2[k]]: array[k];
  177. p[0]++;
  178. } else {
  179. done = true;
  180. itp.splice(itp.indexOf(p), 1);
  181. }
  182. return { done: done, value: v };
  183. }
  184. };
  185. }
  186. function sharedSize() {
  187. return this._values.length;
  188. }
  189. function sharedForEach(callback, context) {
  190. var it = this.entries();
  191. for (;;) {
  192. var r = it.next();
  193. if (r.done) break;
  194. callback.call(context, r.value[1], r.value[0], this);
  195. }
  196. }
  197. })(typeof exports != 'undefined' && typeof global != 'undefined' ? global : window );