_collection-strong.js 4.7 KB

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