| 'use strict'; |
| var dP = require('./_object-dp').f |
| , create = require('./_object-create') |
| , hide = require('./_hide') |
| , redefineAll = require('./_redefine-all') |
| , ctx = require('./_ctx') |
| , anInstance = require('./_an-instance') |
| , defined = require('./_defined') |
| , forOf = require('./_for-of') |
| , $iterDefine = require('./_iter-define') |
| , step = require('./_iter-step') |
| , setSpecies = require('./_set-species') |
| , DESCRIPTORS = require('./_descriptors') |
| , fastKey = require('./_meta').fastKey |
| , SIZE = DESCRIPTORS ? '_s' : 'size'; |
| |
| var getEntry = function(that, key){ |
| // fast case |
| var index = fastKey(key), entry; |
| if(index !== 'F')return that._i[index]; |
| // frozen object case |
| for(entry = that._f; entry; entry = entry.n){ |
| if(entry.k == key)return entry; |
| } |
| }; |
| |
| module.exports = { |
| getConstructor: function(wrapper, NAME, IS_MAP, ADDER){ |
| var C = wrapper(function(that, iterable){ |
| anInstance(that, C, NAME, '_i'); |
| that._i = create(null); // index |
| that._f = undefined; // first entry |
| that._l = undefined; // last entry |
| that[SIZE] = 0; // size |
| if(iterable != undefined)forOf(iterable, IS_MAP, that[ADDER], that); |
| }); |
| redefineAll(C.prototype, { |
| // 23.1.3.1 Map.prototype.clear() |
| // 23.2.3.2 Set.prototype.clear() |
| clear: function clear(){ |
| for(var that = this, data = that._i, entry = that._f; entry; entry = entry.n){ |
| entry.r = true; |
| if(entry.p)entry.p = entry.p.n = undefined; |
| delete data[entry.i]; |
| } |
| that._f = that._l = undefined; |
| that[SIZE] = 0; |
| }, |
| // 23.1.3.3 Map.prototype.delete(key) |
| // 23.2.3.4 Set.prototype.delete(value) |
| 'delete': function(key){ |
| var that = this |
| , entry = getEntry(that, key); |
| if(entry){ |
| var next = entry.n |
| , prev = entry.p; |
| delete that._i[entry.i]; |
| entry.r = true; |
| if(prev)prev.n = next; |
| if(next)next.p = prev; |
| if(that._f == entry)that._f = next; |
| if(that._l == entry)that._l = prev; |
| that[SIZE]--; |
| } return !!entry; |
| }, |
| // 23.2.3.6 Set.prototype.forEach(callbackfn, thisArg = undefined) |
| // 23.1.3.5 Map.prototype.forEach(callbackfn, thisArg = undefined) |
| forEach: function forEach(callbackfn /*, that = undefined */){ |
| anInstance(this, C, 'forEach'); |
| var f = ctx(callbackfn, arguments.length > 1 ? arguments[1] : undefined, 3) |
| , entry; |
| while(entry = entry ? entry.n : this._f){ |
| f(entry.v, entry.k, this); |
| // revert to the last existing entry |
| while(entry && entry.r)entry = entry.p; |
| } |
| }, |
| // 23.1.3.7 Map.prototype.has(key) |
| // 23.2.3.7 Set.prototype.has(value) |
| has: function has(key){ |
| return !!getEntry(this, key); |
| } |
| }); |
| if(DESCRIPTORS)dP(C.prototype, 'size', { |
| get: function(){ |
| return defined(this[SIZE]); |
| } |
| }); |
| return C; |
| }, |
| def: function(that, key, value){ |
| var entry = getEntry(that, key) |
| , prev, index; |
| // change existing entry |
| if(entry){ |
| entry.v = value; |
| // create new entry |
| } else { |
| that._l = entry = { |
| i: index = fastKey(key, true), // <- index |
| k: key, // <- key |
| v: value, // <- value |
| p: prev = that._l, // <- previous entry |
| n: undefined, // <- next entry |
| r: false // <- removed |
| }; |
| if(!that._f)that._f = entry; |
| if(prev)prev.n = entry; |
| that[SIZE]++; |
| // add to index |
| if(index !== 'F')that._i[index] = entry; |
| } return that; |
| }, |
| getEntry: getEntry, |
| setStrong: function(C, NAME, IS_MAP){ |
| // add .keys, .values, .entries, [@@iterator] |
| // 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 |
| $iterDefine(C, NAME, function(iterated, kind){ |
| this._t = iterated; // target |
| this._k = kind; // kind |
| this._l = undefined; // previous |
| }, function(){ |
| var that = this |
| , kind = that._k |
| , entry = that._l; |
| // revert to the last existing entry |
| while(entry && entry.r)entry = entry.p; |
| // get next entry |
| if(!that._t || !(that._l = entry = entry ? entry.n : that._t._f)){ |
| // or finish the iteration |
| that._t = undefined; |
| return step(1); |
| } |
| // return step by kind |
| if(kind == 'keys' )return step(0, entry.k); |
| if(kind == 'values')return step(0, entry.v); |
| return step(0, [entry.k, entry.v]); |
| }, IS_MAP ? 'entries' : 'values' , !IS_MAP, true); |
| |
| // add [@@species], 23.1.2.2, 23.2.2.2 |
| setSpecies(NAME); |
| } |
| }; |