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);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								};
							 |