You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					145 lines
				
				4.9 KiB
			
		
		
			
		
	
	
					145 lines
				
				4.9 KiB
			| 
											3 years ago
										 | 'use strict'; | ||
|  | var dP = require('./_object-dp').f; | ||
|  | var create = require('./_object-create'); | ||
|  | var redefineAll = require('./_redefine-all'); | ||
|  | var ctx = require('./_ctx'); | ||
|  | var anInstance = require('./_an-instance'); | ||
|  | var forOf = require('./_for-of'); | ||
|  | var $iterDefine = require('./_iter-define'); | ||
|  | var step = require('./_iter-step'); | ||
|  | var setSpecies = require('./_set-species'); | ||
|  | var DESCRIPTORS = require('./_descriptors'); | ||
|  | var fastKey = require('./_meta').fastKey; | ||
|  | var validate = require('./_validate-collection'); | ||
|  | var SIZE = DESCRIPTORS ? '_s' : 'size'; | ||
|  | 
 | ||
|  | var getEntry = function (that, key) { | ||
|  |   // fast case
 | ||
|  |   var index = fastKey(key); | ||
|  |   var 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._t = NAME;         // collection type
 | ||
|  |       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 = validate(this, NAME), 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 = validate(this, NAME); | ||
|  |         var entry = getEntry(that, key); | ||
|  |         if (entry) { | ||
|  |           var next = entry.n; | ||
|  |           var 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 */) { | ||
|  |         validate(this, NAME); | ||
|  |         var f = ctx(callbackfn, arguments.length > 1 ? arguments[1] : undefined, 3); | ||
|  |         var 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(validate(this, NAME), key); | ||
|  |       } | ||
|  |     }); | ||
|  |     if (DESCRIPTORS) dP(C.prototype, 'size', { | ||
|  |       get: function () { | ||
|  |         return validate(this, NAME)[SIZE]; | ||
|  |       } | ||
|  |     }); | ||
|  |     return C; | ||
|  |   }, | ||
|  |   def: function (that, key, value) { | ||
|  |     var entry = getEntry(that, key); | ||
|  |     var 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 = validate(iterated, NAME); // target
 | ||
|  |       this._k = kind;                     // kind
 | ||
|  |       this._l = undefined;                // previous
 | ||
|  |     }, function () { | ||
|  |       var that = this; | ||
|  |       var kind = that._k; | ||
|  |       var 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); | ||
|  |   } | ||
|  | }; |