_collection-strong.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. 'use strict';
  2. var dP = require('./_object-dp').f;
  3. var create = require('./_object-create');
  4. var redefineAll = require('./_redefine-all');
  5. var ctx = require('./_ctx');
  6. var anInstance = require('./_an-instance');
  7. var forOf = require('./_for-of');
  8. var $iterDefine = require('./_iter-define');
  9. var step = require('./_iter-step');
  10. var setSpecies = require('./_set-species');
  11. var DESCRIPTORS = require('./_descriptors');
  12. var fastKey = require('./_meta').fastKey;
  13. var validate = require('./_validate-collection');
  14. var SIZE = DESCRIPTORS ? '_s' : 'size';
  15. var getEntry = function (that, key) {
  16. // fast case
  17. var index = fastKey(key);
  18. var entry;
  19. if (index !== 'F') return that._i[index];
  20. // frozen object case
  21. for (entry = that._f; entry; entry = entry.n) {
  22. if (entry.k == key) return entry;
  23. }
  24. };
  25. module.exports = {
  26. getConstructor: function (wrapper, NAME, IS_MAP, ADDER) {
  27. var C = wrapper(function (that, iterable) {
  28. anInstance(that, C, NAME, '_i');
  29. that._t = NAME; // collection type
  30. that._i = create(null); // index
  31. that._f = undefined; // first entry
  32. that._l = undefined; // last entry
  33. that[SIZE] = 0; // size
  34. if (iterable != undefined) forOf(iterable, IS_MAP, that[ADDER], that);
  35. });
  36. redefineAll(C.prototype, {
  37. // 23.1.3.1 Map.prototype.clear()
  38. // 23.2.3.2 Set.prototype.clear()
  39. clear: function clear() {
  40. for (var that = validate(this, NAME), data = that._i, entry = that._f; entry; entry = entry.n) {
  41. entry.r = true;
  42. if (entry.p) entry.p = entry.p.n = undefined;
  43. delete data[entry.i];
  44. }
  45. that._f = that._l = undefined;
  46. that[SIZE] = 0;
  47. },
  48. // 23.1.3.3 Map.prototype.delete(key)
  49. // 23.2.3.4 Set.prototype.delete(value)
  50. 'delete': function (key) {
  51. var that = validate(this, NAME);
  52. var entry = getEntry(that, key);
  53. if (entry) {
  54. var next = entry.n;
  55. var prev = entry.p;
  56. delete that._i[entry.i];
  57. entry.r = true;
  58. if (prev) prev.n = next;
  59. if (next) next.p = prev;
  60. if (that._f == entry) that._f = next;
  61. if (that._l == entry) that._l = prev;
  62. that[SIZE]--;
  63. } return !!entry;
  64. },
  65. // 23.2.3.6 Set.prototype.forEach(callbackfn, thisArg = undefined)
  66. // 23.1.3.5 Map.prototype.forEach(callbackfn, thisArg = undefined)
  67. forEach: function forEach(callbackfn /* , that = undefined */) {
  68. validate(this, NAME);
  69. var f = ctx(callbackfn, arguments.length > 1 ? arguments[1] : undefined, 3);
  70. var entry;
  71. while (entry = entry ? entry.n : this._f) {
  72. f(entry.v, entry.k, this);
  73. // revert to the last existing entry
  74. while (entry && entry.r) entry = entry.p;
  75. }
  76. },
  77. // 23.1.3.7 Map.prototype.has(key)
  78. // 23.2.3.7 Set.prototype.has(value)
  79. has: function has(key) {
  80. return !!getEntry(validate(this, NAME), key);
  81. }
  82. });
  83. if (DESCRIPTORS) dP(C.prototype, 'size', {
  84. get: function () {
  85. return validate(this, NAME)[SIZE];
  86. }
  87. });
  88. return C;
  89. },
  90. def: function (that, key, value) {
  91. var entry = getEntry(that, key);
  92. var prev, index;
  93. // change existing entry
  94. if (entry) {
  95. entry.v = value;
  96. // create new entry
  97. } else {
  98. that._l = entry = {
  99. i: index = fastKey(key, true), // <- index
  100. k: key, // <- key
  101. v: value, // <- value
  102. p: prev = that._l, // <- previous entry
  103. n: undefined, // <- next entry
  104. r: false // <- removed
  105. };
  106. if (!that._f) that._f = entry;
  107. if (prev) prev.n = entry;
  108. that[SIZE]++;
  109. // add to index
  110. if (index !== 'F') that._i[index] = entry;
  111. } return that;
  112. },
  113. getEntry: getEntry,
  114. setStrong: function (C, NAME, IS_MAP) {
  115. // add .keys, .values, .entries, [@@iterator]
  116. // 23.1.3.4, 23.1.3.8, 23.1.3.11, 23.1.3.12, 23.2.3.5, 23.2.3.8, 23.2.3.10, 23.2.3.11
  117. $iterDefine(C, NAME, function (iterated, kind) {
  118. this._t = validate(iterated, NAME); // target
  119. this._k = kind; // kind
  120. this._l = undefined; // previous
  121. }, function () {
  122. var that = this;
  123. var kind = that._k;
  124. var entry = that._l;
  125. // revert to the last existing entry
  126. while (entry && entry.r) entry = entry.p;
  127. // get next entry
  128. if (!that._t || !(that._l = entry = entry ? entry.n : that._t._f)) {
  129. // or finish the iteration
  130. that._t = undefined;
  131. return step(1);
  132. }
  133. // return step by kind
  134. if (kind == 'keys') return step(0, entry.k);
  135. if (kind == 'values') return step(0, entry.v);
  136. return step(0, [entry.k, entry.v]);
  137. }, IS_MAP ? 'entries' : 'values', !IS_MAP, true);
  138. // add [@@species], 23.1.2.2, 23.2.2.2
  139. setSpecies(NAME);
  140. }
  141. };