123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159 |
- 'use strict';
- var $ = require('./$')
- , hide = require('./$.hide')
- , redefineAll = require('./$.redefine-all')
- , ctx = require('./$.ctx')
- , strictNew = require('./$.strict-new')
- , defined = require('./$.defined')
- , forOf = require('./$.for-of')
- , $iterDefine = require('./$.iter-define')
- , step = require('./$.iter-step')
- , ID = require('./$.uid')('id')
- , $has = require('./$.has')
- , isObject = require('./$.is-object')
- , setSpecies = require('./$.set-species')
- , DESCRIPTORS = require('./$.descriptors')
- , isExtensible = Object.isExtensible || isObject
- , SIZE = DESCRIPTORS ? '_s' : 'size'
- , id = 0;
- var fastKey = function(it, create){
- // return primitive with prefix
- if(!isObject(it))return typeof it == 'symbol' ? it : (typeof it == 'string' ? 'S' : 'P') + it;
- if(!$has(it, ID)){
- // can't set id to frozen object
- if(!isExtensible(it))return 'F';
- // not necessary to add id
- if(!create)return 'E';
- // add missing object id
- hide(it, ID, ++id);
- // return object id with prefix
- } return 'O' + it[ID];
- };
- 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){
- strictNew(that, C, NAME);
- 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 */){
- 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)$.setDesc(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);
- }
- };
|