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';
16 var getEntry = function(that, key){
18 var index = fastKey(key), entry;
19 if(index !== 'F')return that._i[index];
21 for(entry = that._f; entry; entry = entry.n){
22 if(entry.k == key)return entry;
27 getConstructor: function(wrapper, NAME, IS_MAP, ADDER){
28 var C = wrapper(function(that, iterable){
29 anInstance(that, C, NAME, '_i');
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);
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 = this, data = that._i, entry = that._f; entry; entry = entry.n){
42 if(entry.p)entry.p = entry.p.n = undefined;
45 that._f = that._l = undefined;
48 // 23.1.3.3 Map.prototype.delete(key)
49 // 23.2.3.4 Set.prototype.delete(value)
50 'delete': function(key){
52 , entry = getEntry(that, key);
56 delete that._i[entry.i];
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;
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 anInstance(this, C, 'forEach');
69 var f = ctx(callbackfn, arguments.length > 1 ? arguments[1] : undefined, 3)
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;
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(this, key);
83 if(DESCRIPTORS)dP(C.prototype, 'size', {
85 return defined(this[SIZE]);
90 def: function(that, key, value){
91 var entry = getEntry(that, key)
93 // change existing entry
99 i: index = fastKey(key, true), // <- index
101 v: value, // <- value
102 p: prev = that._l, // <- previous entry
103 n: undefined, // <- next entry
104 r: false // <- removed
106 if(!that._f)that._f = entry;
107 if(prev)prev.n = entry;
110 if(index !== 'F')that._i[index] = entry;
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 = iterated; // target
119 this._k = kind; // kind
120 this._l = undefined; // previous
125 // revert to the last existing entry
126 while(entry && entry.r)entry = entry.p;
128 if(!that._t || !(that._l = entry = entry ? entry.n : that._t._f)){
129 // or finish the iteration
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);
139 // add [@@species], 23.1.2.2, 23.2.2.2