| 'use strict'; |
| var redefineAll = require('../internals/redefine-all'); |
| var getWeakData = require('../internals/internal-metadata').getWeakData; |
| var anObject = require('../internals/an-object'); |
| var isObject = require('../internals/is-object'); |
| var anInstance = require('../internals/an-instance'); |
| var iterate = require('../internals/iterate'); |
| var ArrayIterationModule = require('../internals/array-iteration'); |
| var $has = require('../internals/has'); |
| var InternalStateModule = require('../internals/internal-state'); |
| |
| var setInternalState = InternalStateModule.set; |
| var internalStateGetterFor = InternalStateModule.getterFor; |
| var find = ArrayIterationModule.find; |
| var findIndex = ArrayIterationModule.findIndex; |
| var id = 0; |
| |
| // fallback for uncaught frozen keys |
| var uncaughtFrozenStore = function (store) { |
| return store.frozen || (store.frozen = new UncaughtFrozenStore()); |
| }; |
| |
| var UncaughtFrozenStore = function () { |
| this.entries = []; |
| }; |
| |
| var findUncaughtFrozen = function (store, key) { |
| return find(store.entries, function (it) { |
| return it[0] === key; |
| }); |
| }; |
| |
| UncaughtFrozenStore.prototype = { |
| get: function (key) { |
| var entry = findUncaughtFrozen(this, key); |
| if (entry) return entry[1]; |
| }, |
| has: function (key) { |
| return !!findUncaughtFrozen(this, key); |
| }, |
| set: function (key, value) { |
| var entry = findUncaughtFrozen(this, key); |
| if (entry) entry[1] = value; |
| else this.entries.push([key, value]); |
| }, |
| 'delete': function (key) { |
| var index = findIndex(this.entries, function (it) { |
| return it[0] === key; |
| }); |
| if (~index) this.entries.splice(index, 1); |
| return !!~index; |
| } |
| }; |
| |
| module.exports = { |
| getConstructor: function (wrapper, CONSTRUCTOR_NAME, IS_MAP, ADDER) { |
| var C = wrapper(function (that, iterable) { |
| anInstance(that, C, CONSTRUCTOR_NAME); |
| setInternalState(that, { |
| type: CONSTRUCTOR_NAME, |
| id: id++, |
| frozen: undefined |
| }); |
| if (iterable != undefined) iterate(iterable, that[ADDER], that, IS_MAP); |
| }); |
| |
| var getInternalState = internalStateGetterFor(CONSTRUCTOR_NAME); |
| |
| var define = function (that, key, value) { |
| var state = getInternalState(that); |
| var data = getWeakData(anObject(key), true); |
| if (data === true) uncaughtFrozenStore(state).set(key, value); |
| else data[state.id] = value; |
| return that; |
| }; |
| |
| redefineAll(C.prototype, { |
| // 23.3.3.2 WeakMap.prototype.delete(key) |
| // 23.4.3.3 WeakSet.prototype.delete(value) |
| 'delete': function (key) { |
| var state = getInternalState(this); |
| if (!isObject(key)) return false; |
| var data = getWeakData(key); |
| if (data === true) return uncaughtFrozenStore(state)['delete'](key); |
| return data && $has(data, state.id) && delete data[state.id]; |
| }, |
| // 23.3.3.4 WeakMap.prototype.has(key) |
| // 23.4.3.4 WeakSet.prototype.has(value) |
| has: function has(key) { |
| var state = getInternalState(this); |
| if (!isObject(key)) return false; |
| var data = getWeakData(key); |
| if (data === true) return uncaughtFrozenStore(state).has(key); |
| return data && $has(data, state.id); |
| } |
| }); |
| |
| redefineAll(C.prototype, IS_MAP ? { |
| // 23.3.3.3 WeakMap.prototype.get(key) |
| get: function get(key) { |
| var state = getInternalState(this); |
| if (isObject(key)) { |
| var data = getWeakData(key); |
| if (data === true) return uncaughtFrozenStore(state).get(key); |
| return data ? data[state.id] : undefined; |
| } |
| }, |
| // 23.3.3.5 WeakMap.prototype.set(key, value) |
| set: function set(key, value) { |
| return define(this, key, value); |
| } |
| } : { |
| // 23.4.3.1 WeakSet.prototype.add(value) |
| add: function add(value) { |
| return define(this, value, true); |
| } |
| }); |
| |
| return C; |
| } |
| }; |