es6-harmony
Version:
An equivalent implementation of ES6 in pure ES5 for old JavaScript engines
1,458 lines (1,275 loc) • 85.3 kB
JavaScript
/*!
* ES6 Harmony v0.2.4
* This module provides an equivalent implementation of ES6(Harmony)
* in pure ES5 and creates an ES6 environment for old browsers or
* JavaScript engines that natively does not support ES6.
*
* @license Copyright (c) 2017-2018 Rousan Ali, MIT License
*
* Codebase: https://github.com/rousan/es6-harmony
* Date: 28th Jan, 2018
*/
(function (global, factory) {
"use strict";
if (typeof module === "object" && typeof module.exports === "object") {
// For the environment like NodeJS, CommonJS etc where module or
// module.exports objects are available to export ES6 APIs.
module.exports = factory(global);
} else {
// For browser context, where global object is window
// and the ES6 APIs is exported as 'ES6' property of window object
global.ES6 = factory(global);
}
/* window is for browser environment and global is for NodeJS environment */
})(typeof window !== "undefined" ? window : global, function (global) {
"use strict";
var defineProperty = Object.defineProperty;
var defineProperties = Object.defineProperties;
var symbolHiddenCounter = 0;
var globalSymbolRegistry = [];
var slice = Array.prototype.slice;
var stringSlice = String.prototype.slice;
var stringIndexOf = String.prototype.indexOf;
var isArray = Array.isArray;
var objectToString = Object.prototype.toString;
var push = Array.prototype.push;
var match = String.prototype.match;
var globalIsFinite = isFinite;
var floor = Math.floor;
var max = Math.max;
var min = Math.min;
var create = Object.create;
var stringMaxLength = Infinity;
var symbolBucket = create(null);
var symbolNamePattern = /^@@_____(\d+)_____$/;
var emptyFunction = function () {};
var simpleFunction = function (arg) {
return arg;
};
var isCallable = function (fn) {
return typeof fn === 'function';
};
var isConstructor = function (fn) {
return isCallable(fn);
};
var Iterator = function () {};
var ArrayIterator = function ArrayIterator(array, flag) {
this._array = array;
this._flag = flag;
this._nextIndex = 0;
};
var StringIterator = function StringIterator(string, flag) {
this._string = string;
this._flag = flag;
this._nextIndex = 0;
};
var MapIterator = function MapIterator(map, flag) {
this._map = map;
this._flag = flag;
this._currentEntry = null;
this._done = false;
};
var SetIterator = function SetIterator(set, flag) {
this._set = set;
this._flag = flag;
this._currentEntry = null;
this._done = false;
};
// This method will be implemented later,
// now `false` just for development purpose
var isES6Running = function() {
return false;
};
var isObject = function (value) {
return value !== null && (typeof value === "object" || typeof value === "function");
};
var addToMessageQueue = function (fn, thisArg) {
if (!isCallable(fn))
throw new TypeError(fn + " is not a function");
var args = slice.call(arguments, 2);
setTimeout(function () {
fn.apply(thisArg, args);
});
};
var es6FunctionPrototypeHasInstanceSymbol = function (instance) {
if (typeof this !== "function")
return false;
return instance instanceof this;
};
var es6InstanceOfOperator = function instanceOf(object, constructor) {
if (!isObject(constructor))
throw new TypeError("Right-hand side of 'instanceof' is not an object");
var hasInstanceSymbolProp = constructor[Symbol.hasInstance];
if (typeof hasInstanceSymbolProp === "undefined") {
return object instanceof constructor;
} else if(typeof hasInstanceSymbolProp !== "function") {
throw new TypeError(typeof hasInstanceSymbolProp + " is not a function");
} else {
return hasInstanceSymbolProp.call(constructor, object);
}
};
// Generates name for a symbol instance and this name will be used as
// property key for property symbols internally.
var generateSymbolName = function (id) {
return "@@_____" + id + "_____";
};
// Generates id for next Symbol instance
var getNextSymbolId = function () {
return symbolHiddenCounter++;
};
var setupSymbolInternals = function (symbol, desc) {
defineProperties(symbol, {
_description: {
value: desc
},
_isSymbol: {
value: true
},
_id: {
value: getNextSymbolId()
}
});
return symbol;
};
var checkSymbolInternals = function (symbol) {
return symbol._isSymbol === true && typeof symbol._id === "number" && typeof symbol._description === "string";
};
var isSymbol = function (symbol) {
return symbol instanceof Symbol && checkSymbolInternals(symbol);
};
var symbolFor = function (key) {
key = String(key);
var registryLength = globalSymbolRegistry.length,
record,
i = 0;
for(; i<registryLength; ++i) {
record = globalSymbolRegistry[i];
if (record.key === key)
return record.symbol;
}
record = {
key: key,
symbol: Symbol(key)
};
globalSymbolRegistry.push(record);
return record.symbol;
};
var symbolKeyFor = function (symbol) {
if (!ES6.isSymbol(symbol))
throw new TypeError(String(symbol) + " is not a symbol");
var registryLength = globalSymbolRegistry.length,
record,
i = 0;
for(; i<registryLength; ++i) {
record = globalSymbolRegistry[i];
if (record.symbol === symbol)
return record.key;
}
};
/* It affects array1 and appends array2 at the end of array1 */
var appendArray = function (array1, array2) {
// Returns immediately if these are not array or not array-like objects
if (!(typeof array1.length === "number" && array1.length >= 0 && typeof array2.length === "number" && array2.length >= 0))
return;
var length1 = Math.floor(array1.length),
length2 = Math.floor(array2.length),
i = 0;
array1.length = length1 + length2;
for (; i<length2; ++i)
if (array2.hasOwnProperty(i))
array1[length1 + i] = array2[i];
};
var es6ObjectPrototypeToString = function toString() {
if (this === undefined || this === null)
return objectToString.call(this);
// Add support for @@toStringTag symbol
if (typeof this[Symbol.toStringTag] === "string")
return "[object " + this[Symbol.toStringTag] + "]";
else
return objectToString.call(this);
};
var es6ArrayPrototypeConcat = function concat() {
if (this === undefined || this === null)
throw new TypeError("Array.prototype.concat called on null or undefined");
// Boxing 'this' value to wrapper object
var self = Object(this),
targets = slice.call(arguments),
outputs = []; // Later it may affected by Symbol
targets.unshift(self);
targets.forEach(function (target) {
// If target is primitive then just push
if (!isObject(target))
outputs.push(target);
// Here Symbol.isConcatSpreadable support is added
else if (typeof target[Symbol.isConcatSpreadable] !== "undefined") {
if (target[Symbol.isConcatSpreadable]) {
appendArray(outputs, target);
} else {
outputs.push(target);
}
} else if (isArray(target)) {
appendArray(outputs, target);
} else {
outputs.push(target);
}
});
return outputs;
};
var es6ForOfLoop = function forOf(iterable, callback, thisArg) {
callback = typeof callback !== "function" ? emptyFunction : callback;
if (typeof iterable[Symbol.iterator] !== "function")
throw new TypeError("Iterable[Symbol.iterator] is not a function");
var iterator = iterable[Symbol.iterator](),
iterationResult;
if (typeof iterator.next !== "function")
throw new TypeError(".iterator.next is not a function");
while (true) {
iterationResult = iterator.next();
if (!isObject(iterationResult))
throw new TypeError("Iterator result " + iterationResult + " is not an object");
if (iterationResult.done)
break;
callback.call(thisArg, iterationResult.value);
}
};
// Provides simple inheritance functionality
var simpleInheritance = function (child, parent) {
if (typeof child !== "function" || typeof parent !== "function")
throw new TypeError("Child and Parent must be function type");
child.prototype = Object.create(parent.prototype);
child.prototype.constructor = child;
};
// Behaves as Symbol function in ES6, take description and returns an unique object,
// but in ES6 this function returns 'symbol' primitive typed value.
// Its type is 'object' not 'symbol'.
// There is no wrapping in this case i.e. Object(sym) = sym.
var Symbol = function Symbol(desc) {
desc = typeof desc === "undefined" ? "" : String(desc);
if(this instanceof Symbol)
throw new TypeError("Symbol is not a constructor");
var newInstance = setupSymbolInternals(Object.create(Symbol.prototype), desc);
symbolBucket[newInstance._id] = newInstance;
return newInstance;
};
defineProperties(Symbol, {
"for": {
value: symbolFor,
writable: true,
configurable: true
},
"keyFor": {
value: symbolKeyFor,
writable: true,
configurable: true
},
"hasInstance": {
value: Symbol("Symbol.hasInstance")
},
"isConcatSpreadable": {
value: Symbol("Symbol.isConcatSpreadable")
},
"iterator": {
value: Symbol("Symbol.iterator")
},
"toStringTag": {
value: Symbol("Symbol.toStringTag")
}
});
// In ES6, this function returns like 'Symbol(<desc>)', but in this case
// this function returns the symbol's internal name to work properly.
Symbol.prototype.toString = function () {
return generateSymbolName(this._id);
};
// Returns itself but in ES6 It returns 'symbol' typed value.
Symbol.prototype.valueOf = function () {
return this;
};
// Make Iterator like iterable
defineProperty(Iterator.prototype, Symbol.iterator.toString(), {
value: function () {return this;},
writable: true,
configurable: true
});
simpleInheritance(ArrayIterator, Iterator);
simpleInheritance(StringIterator, Iterator);
simpleInheritance(MapIterator, Iterator);
simpleInheritance(SetIterator, Iterator);
defineProperty(ArrayIterator.prototype, Symbol.toStringTag.toString(), {
value: "Array Iterator",
configurable: true
});
defineProperty(StringIterator.prototype, Symbol.toStringTag.toString(), {
value: "String Iterator",
configurable: true
});
defineProperty(MapIterator.prototype, Symbol.toStringTag.toString(), {
value: "Map Iterator",
configurable: true
});
defineProperty(SetIterator.prototype, Symbol.toStringTag.toString(), {
value: "Set Iterator",
configurable: true
});
// This iterator works on any Array or TypedArray or array-like objects
ArrayIterator.prototype.next = function next() {
if (!(this instanceof ArrayIterator))
throw new TypeError("Method Array Iterator.prototype.next called on incompatible receiver " + String(this));
var self = this,
nextValue;
if (self._nextIndex === -1) {
return {
done: true,
value: undefined
};
}
if (!(typeof self._array.length === "number" && self._array.length >= 0)) {
self._nextIndex = -1;
return {
done: true,
value: undefined
};
}
// _flag = 1 for [index, value]
// _flag = 2 for [value]
// _flag = 3 for [index]
if (self._nextIndex < Math.floor(self._array.length)) {
if (self._flag === 1)
nextValue = [self._nextIndex, self._array[self._nextIndex]];
else if (self._flag === 2)
nextValue = self._array[self._nextIndex];
else if (self._flag === 3)
nextValue = self._nextIndex;
self._nextIndex++;
return {
done: false,
value: nextValue
};
} else {
self._nextIndex = -1;
return {
done: true,
value: undefined
};
}
};
StringIterator.prototype.next = function next() {
if (!(this instanceof StringIterator))
throw new TypeError("Method String Iterator.prototype.next called on incompatible receiver " + String(this));
var self = this,
stringObject = new String(this._string),
nextValue;
if (self._nextIndex === -1) {
return {
done: true,
value: undefined
};
}
if (self._nextIndex < stringObject.length) {
nextValue = stringObject[self._nextIndex];
self._nextIndex++;
return {
done: false,
value: nextValue
};
} else {
self._nextIndex = -1;
return {
done: true,
value: undefined
};
}
};
MapIterator.prototype.next = function next() {
if (!(this instanceof MapIterator))
throw new TypeError("Method Map Iterator.prototype.next called on incompatible receiver " + String(this));
var self = this,
nextValue;
if (self._done) {
return {
done: true,
value: undefined
};
}
if (self._currentEntry === null)
self._currentEntry = self._map._head;
else
self._currentEntry = self._currentEntry.next;
if (self._currentEntry === null) {
self._done = true;
return {
done: true,
value: undefined
};
}
// _flag = 1 for [key, value]
// _flag = 2 for [value]
// _flag = 3 for [key]
if (self._flag === 1)
nextValue = [self._currentEntry.key, self._currentEntry.value];
else if (self._flag === 2)
nextValue = self._currentEntry.value;
else if (self._flag === 3)
nextValue = self._currentEntry.key;
return {
done: false,
value: nextValue
};
};
SetIterator.prototype.next = function next() {
if (!(this instanceof SetIterator))
throw new TypeError("Method Set Iterator.prototype.next called on incompatible receiver " + String(this));
var self = this,
nextValue;
if (self._done) {
return {
done: true,
value: undefined
};
}
if (self._currentEntry === null)
self._currentEntry = self._set._head;
else
self._currentEntry = self._currentEntry.next;
if (self._currentEntry === null) {
self._done = true;
return {
done: true,
value: undefined
};
}
// _flag = 1 for [value, value]
// _flag = 2 for [value]
if (self._flag === 1)
nextValue = [self._currentEntry.value, self._currentEntry.value];
else if (self._flag === 2)
nextValue = self._currentEntry.value;
return {
done: false,
value: nextValue
};
};
var es6ArrayPrototypeIteratorSymbol = function values() {
if (this === undefined || this === null)
throw new TypeError("Cannot convert undefined or null to object");
var self = Object(this);
return new ArrayIterator(self, 2);
};
var es6StringPrototypeIteratorSymbol = function values() {
if (this === undefined || this === null)
throw new TypeError("String.prototype[Symbol.iterator] called on null or undefined");
return new StringIterator(String(this), 0);
};
var es6ArrayPrototypeEntries = function entries() {
if (this === undefined || this === null)
throw new TypeError("Cannot convert undefined or null to object");
var self = Object(this);
return new ArrayIterator(self, 1);
};
var es6ArrayPrototypeKeys = function keys() {
if (this === undefined || this === null)
throw new TypeError("Cannot convert undefined or null to object");
var self = Object(this);
return new ArrayIterator(self, 3);
};
var SpreadOperatorImpl = function (target, thisArg) {
this._target = target;
this._values = [];
this._thisArg = thisArg;
};
// All the arguments must be iterable
SpreadOperatorImpl.prototype.spread = function () {
var self = this;
slice.call(arguments).forEach(function (iterable) {
ES6.forOf(iterable, function (value) {
self._values.push(value);
});
});
return self;
};
SpreadOperatorImpl.prototype.add = function () {
var self = this;
slice.call(arguments).forEach(function (value) {
self._values.push(value);
});
return self;
};
SpreadOperatorImpl.prototype.call = function (thisArg) {
if (typeof this._target !== "function")
throw new TypeError("Target is not a function");
thisArg = arguments.length <= 0 ? this._thisArg : thisArg;
return this._target.apply(thisArg, this._values);
};
SpreadOperatorImpl.prototype.new = function () {
if (typeof this._target !== "function")
throw new TypeError("Target is not a constructor");
var temp,
returnValue;
temp = Object.create(this._target.prototype);
returnValue = this._target.apply(temp, this._values);
return isObject(returnValue) ? returnValue : temp;
};
// Affects the target array
SpreadOperatorImpl.prototype.array = function () {
if (!isArray(this._target))
throw new TypeError("Target is not a array");
push.apply(this._target, this._values);
return this._target;
};
// Target must be Array or function
var es6SpreadOperator = function spreadOperator(target, thisArg) {
if (!(typeof target === "function" || isArray(target)))
throw new TypeError("Spread operator only supports on array and function objects at this moment");
return new SpreadOperatorImpl(target, thisArg);
};
/*
var es6Match = function (regexp) {
if (this === undefined || this === null)
throw new TypeError("String.prototype.match called on null or undefined");
if (regexp === undefined || regexp === null)
return match.call(this, new RegExp(regexp));
regexp = Object(regexp);
var matchSymbol = regexp[Symbol.match];
if (typeof matchSymbol !== "undefined") {
if (typeof matchSymbol !== "function")
throw new TypeError(typeof matchSymbol + " is not a function");
else {
return matchSymbol.call(regexp, this);
}
} else {
return match.call(this, new RegExp(String(regexp)));
}
};
*/
var es6ArrayFrom = function from(arrayLike, mapFn, thisArg) {
var constructor,
i = 0,
length,
outputs;
// Use the generic constructor
constructor = !isConstructor(this) ? Array : this;
if (arrayLike === undefined || arrayLike === null)
throw new TypeError("Cannot convert undefined or null to object");
arrayLike = Object(arrayLike);
if (mapFn === undefined)
mapFn = simpleFunction;
else if (!isCallable(mapFn))
throw new TypeError(mapFn + " is not a function");
if (typeof arrayLike[Symbol.iterator] === "undefined") {
if (!(typeof arrayLike.length === "number" && arrayLike.length >= 0)) {
outputs = new constructor(0);
outputs.length = 0;
return outputs;
}
length = Math.floor(arrayLike.length);
outputs = new constructor(length);
outputs.length = length;
for(; i < length; ++i)
outputs[i] = mapFn.call(thisArg, arrayLike[i]);
} else {
outputs = new constructor();
outputs.length = 0;
ES6.forOf(arrayLike, function (value) {
outputs.length++;
outputs[outputs.length - 1] = mapFn.call(thisArg, value);
});
}
return outputs;
};
var es6ArrayOf = function of() {
var constructor,
outputs,
length,
i = 0;
// Use the generic constructor
constructor = !isConstructor(this) ? Array : this;
length = arguments.length;
outputs = new constructor(length);
outputs.length = length;
for(; i < length; ++i) {
outputs[i] = arguments[i];
}
return outputs;
};
var es6ArrayPrototypeFill = function fill(value, start, end) {
if (this === undefined || this === null)
throw new TypeError("Array.prototype.fill called on null or undefined");
var self = Object(this),
i = 0,
length;
if (typeof self.length === "number" && self.length >= 0) {
length = Math.floor(self.length);
start = start === undefined ? 0 : Math.floor(Number(start));
end = end === undefined ? length : Math.floor(Number(end));
start = start < 0 ? start + length : start;
end = end < 0 ? end + length : end;
start = start < 0 ? 0 : start;
end = end > length ? length : end;
for(i = start; i < end; ++i)
self[i] = value;
}
return self;
};
var es6ArrayPrototypeFind = function find(callback, thisArg) {
if (this === undefined || this === null)
throw new TypeError("Array.prototype.find called on null or undefined");
if (!isCallable(callback))
throw new TypeError(callback + " is not a function");
var self = Object(this),
i = 0,
length;
if (typeof self.length === "number" && self.length >= 0) {
length = Math.floor(self.length);
for (; i < length; ++i) {
if (callback.call(thisArg, self[i], i, self))
return self[i];
}
}
};
var es6ArrayPrototypeFindIndex = function findIndex(callback, thisArg) {
if (this === undefined || this === null)
throw new TypeError("Array.prototype.findIndex called on null or undefined");
if (!isCallable(callback))
throw new TypeError(callback + " is not a function");
var self = Object(this),
i = 0,
length;
if (typeof self.length === "number" && self.length >= 0) {
length = Math.floor(self.length);
for (; i < length; ++i) {
if (callback.call(thisArg, self[i], i, self))
return i;
}
}
return -1;
};
var es6ArrayPrototypeCopyWithin = function copyWithin(target, start) {
if (this == undefined || this === null) {
throw new TypeError("Array.prototype.copyWithin called on null or undefined");
}
var self = Object(this),
length = self.length >>> 0,
relativeTarget = target >> 0,
to = relativeTarget < 0 ? max(length + relativeTarget, 0) : min(relativeTarget, length),
relativeStart = start >> 0,
from = relativeStart < 0 ? max(length + relativeStart, 0) : min(relativeStart, length),
end = arguments[2],
relativeEnd = end === undefined ? length : end >> 0,
final = relativeEnd < 0 ? max(length + relativeEnd, 0) : min(relativeEnd, length),
count = min(final - from, length - to),
direction = 1;
if (from < to && to < (from + count)) {
direction = -1;
from += count - 1;
to += count - 1;
}
while (count > 0) {
if (from in self) {
self[to] = self[from];
} else {
delete self[to];
}
from += direction;
to += direction;
count--;
}
return self;
};
// Returns hash for primitive typed key like this:
// undefined or null => I___toString(key)
// number => N___toString(key)
// string => S___toString(key)
// boolean => B___toString(key)
//
// But returns null for object typed key.
var hash = function (key) {
// String(0) === String(-0)
// String(NaN) === String(NaN)
var strKey = String(key);
if (key === undefined || key === null)
return "I___" + strKey;
else if (typeof key === "number")
return "N___" + strKey;
else if (typeof key === "string")
return "S___" + strKey;
else if (typeof key === "boolean")
return "B___" + strKey;
else
return null; /* For object key */
};
var Map = function Map(iterable) {
if (!(this instanceof Map) || isMap(this))
throw new TypeError("Constructor Map requires 'new'");
setupMapInternals(this);
if (iterable !== null && iterable !== undefined) {
ES6.forOf(iterable, function (entry) {
if (!isObject(entry))
throw new TypeError("Iterator value " + entry + " is not an entry object");
this.set(entry[0], entry[1]);
}, this);
}
};
// WARNING: This method puts a link in the key object to reduce time complexity to O(1).
// So, after map.set(key, value) call, if the linker property of the key object is deleted
// then map.has(key) will returns false.
// Time complexity: O(1) for all cases(there is no worst case, same for both primitive and object key).
// Space complexity is O(n) for all cases.
Map.prototype.set = function set(key, value) {
if (!isMap(this))
throw new TypeError("Method Map.prototype.set called on incompatible receiver " + this);
var keyHash = hash(key),
objectHash = this._objectHash,
entry;
if (keyHash === null) {
if (typeof key[objectHash] === "number" && this._data.objects[key[objectHash]] instanceof MapEntry) {
entry = this._data.objects[key[objectHash]];
entry.value = value;
return this;
}
entry = new MapEntry(key, value);
this._data.objects.push(entry);
defineProperty(key, objectHash.toString(), {
value: this._data.objects.length - 1,
configurable: true
});
this._size++;
} else {
if (this._data.primitives[keyHash] instanceof MapEntry) {
entry = this._data.primitives[keyHash];
entry.value = value;
return this;
}
entry = new MapEntry(key, value);
this._data.primitives[keyHash] = entry;
this._size++;
}
if (this._head === null) {
this._head = entry;
entry.next = null;
entry.prev = null;
}
if (this._tail === null)
this._tail = this._head;
else {
this._tail.next = entry;
entry.prev = this._tail;
entry.next = null;
this._tail = entry;
}
return this;
};
// Time complexity: O(1) for all cases(there is no worst case, same for both primitive and object key).
// Space complexity is O(1)
Map.prototype.has = function has(key) {
if (!isMap(this))
throw new TypeError("Method Map.prototype.has called on incompatible receiver " + this);
var keyHash = hash(key),
objectHash = this._objectHash;
if (keyHash === null)
return typeof key[objectHash] === "number" && this._data.objects[key[objectHash]] instanceof MapEntry;
else
return this._data.primitives[keyHash] instanceof MapEntry;
};
// Time complexity: O(1) for all cases(there is no worst case, same for both primitive and object key).
// Space complexity is O(1)
Map.prototype.get = function get(key) {
if (!isMap(this))
throw new TypeError("Method Map.prototype.get called on incompatible receiver " + this);
var keyHash = hash(key),
objectHash = this._objectHash;
if (keyHash === null) {
if (typeof key[objectHash] === "number" && this._data.objects[key[objectHash]] instanceof MapEntry)
return this._data.objects[key[objectHash]].value;
} else {
if (this._data.primitives[keyHash] instanceof MapEntry)
return this._data.primitives[keyHash].value;
}
};
// Time complexity: O(n)
// Space complexity is O(1)
Map.prototype.clear = function clear() {
if (!isMap(this))
throw new TypeError("Method Map.prototype.clear called on incompatible receiver " + this);
var entry;
// Clear all primitive keys
Object.getOwnPropertyNames(this._data.primitives).forEach(function (prop) {
if (this._data.primitives[prop] instanceof MapEntry) {
entry = this._data.primitives[prop];
delete this._data.primitives[prop];
entry.next = null;
entry.prev = null;
}
}, this);
// Clear all object keys
Object.getOwnPropertyNames(this._data.objects).forEach(function (prop) {
if (this._data.objects[prop] instanceof MapEntry) {
entry = this._data.objects[prop];
delete this._data.objects[prop];
delete entry.key[this._objectHash];
entry.next = null;
entry.prev = null;
}
}, this);
this._data.objects.length = 0;
// Free head and tail MapEntry
this._head = null;
this._tail = null;
this._size = 0;
};
// Time complexity: O(1) for all cases(there is no worst case, same for both primitive and object key).
// Space complexity is O(1)
Map.prototype.delete = function (key) {
if (!isMap(this))
throw new TypeError("Method Map.prototype.delete called on incompatible receiver " + this);
var keyHash = hash(key),
objectHash = this._objectHash,
entry;
if (keyHash === null) {
if (typeof key[objectHash] === "number" && this._data.objects[key[objectHash]] instanceof MapEntry) {
entry = this._data.objects[key[objectHash]];
delete this._data.objects[key[objectHash]];
delete entry.key[objectHash];
} else
return false;
} else {
if (this._data.primitives[keyHash] instanceof MapEntry) {
entry = this._data.primitives[keyHash];
delete this._data.primitives[keyHash];
} else {
return false;
}
}
if (entry.prev !== null && entry.next !== null) {
entry.prev.next = entry.next;
entry.next.prev = entry.prev;
entry.next = null;
entry.prev = null;
} else if(entry.prev === null && entry.next !== null) {
this._head = entry.next;
entry.next.prev = null;
entry.next = null;
} if (entry.prev !== null && entry.next === null) {
this._tail = entry.prev;
entry.prev.next = null;
entry.prev = null;
} else {
this._head = null;
this._tail = null;
}
this._size--;
return true;
};
defineProperty(Map.prototype, "size", {
get: function size() {
if (!isMap(this))
throw new TypeError("Method Map.prototype.size called on incompatible receiver " + this);
return this._size;
},
configurable: true
});
Map.prototype.entries = function entries() {
if (!isMap(this))
throw new TypeError("Method Map.prototype.entries called on incompatible receiver " + this);
return new MapIterator(this, 1);
};
Map.prototype.values = function values() {
if (!isMap(this))
throw new TypeError("Method Map.prototype.values called on incompatible receiver " + this);
return new MapIterator(this, 2);
};
Map.prototype.keys = function keys() {
if (!isMap(this))
throw new TypeError("Method Map.prototype.keys called on incompatible receiver " + this);
return new MapIterator(this, 3);
};
Map.prototype.forEach = function forEach(callback, thisArg) {
if (!isMap(this))
throw new TypeError("Method Map.prototype.forEach called on incompatible receiver " + this);
if (!isCallable(callback))
throw new TypeError(callback + " is not a function");
var currentEntry = this._head;
while(currentEntry !== null) {
callback.call(thisArg, currentEntry.value, currentEntry.key, this);
currentEntry = currentEntry.next;
}
};
Map.prototype[Symbol.iterator] = Map.prototype.entries;
defineProperty(Map.prototype, Symbol.toStringTag.toString(), {
value: "Map",
configurable: true
});
var setupMapInternals = function (map) {
defineProperties(map, {
_isMap: {
value: true
},
_head: {
value: null,
writable: true
},
_tail: {
value: null,
writable: true
},
_objectHash: {
value: Symbol("Hash(map)")
},
_size: {
value: 0,
writable: true
},
_data: {
value: create(null, {
primitives: {
value: create(null) /* [[Prototype]] must be null */
},
objects: {
value: []
}
})
}
});
};
var checkMapInternals = function (map) {
return map._isMap === true
&& (map._head === null || map._head instanceof MapEntry)
&& (map._tail === null || map._tail instanceof MapEntry)
&& ES6.isSymbol(map._objectHash)
&& typeof map._size === "number"
&& isObject(map._data)
&& isObject(map._data.primitives)
&& isArray(map._data.objects);
};
var isMap = function (map) {
return map instanceof Map && checkMapInternals(map);
};
var MapEntry = function MapEntry(key, value) {
this.key = key;
this.value = value;
this.next = null;
this.prev = null;
};
var Set = function Set(iterable) {
if (!(this instanceof Set) || isSet(this))
throw new TypeError("Constructor Set requires 'new'");
setupSetInternals(this);
if (iterable !== null && iterable !== undefined) {
ES6.forOf(iterable, function (entry) {
this.add(entry);
}, this);
}
};
// WARNING: This method puts a link in the value object to reduce time complexity to O(1).
// So, after set.add(value) call, if the linker property of the value object is deleted
// then set.has(value) will returns false.
// Time complexity: O(1) for all cases(there is no worst case, same for both primitive and object value).
// Space complexity is O(n) for all cases.
Set.prototype.add = function add(value) {
if (!isSet(this))
throw new TypeError("Method Set.prototype.add called on incompatible receiver " + this);
var valueHash = hash(value),
objectHash = this._objectHash,
entry;
if (valueHash === null) {
if (typeof value[objectHash] === "number" && this._data.objects[value[objectHash]] instanceof SetEntry) {
// If the value is already present then just return 'this'
return this;
}
entry = new SetEntry(value);
this._data.objects.push(entry);
defineProperty(value, objectHash.toString(), {
value: this._data.objects.length - 1,
configurable: true
});
this._size++;
} else {
if (this._data.primitives[valueHash] instanceof SetEntry) {
// If the value is already present then just return 'this'
return this;
}
entry = new SetEntry(value);
this._data.primitives[valueHash] = entry;
this._size++;
}
if (this._head === null) {
this._head = entry;
entry.next = null;
entry.prev = null;
}
if (this._tail === null)
this._tail = this._head;
else {
this._tail.next = entry;
entry.prev = this._tail;
entry.next = null;
this._tail = entry;
}
return this;
};
// Time complexity: O(1) for all cases(there is no worst case, same for both primitive and object value).
// Space complexity is O(1)
Set.prototype.has = function has(value) {
if (!isSet(this))
throw new TypeError("Method Set.prototype.has called on incompatible receiver " + this);
var valueHash = hash(value),
objectHash = this._objectHash;
if (valueHash === null)
return typeof value[objectHash] === "number" && this._data.objects[value[objectHash]] instanceof SetEntry;
else
return this._data.primitives[valueHash] instanceof SetEntry;
};
// Time complexity: O(n)
// Space complexity is O(1)
Set.prototype.clear = function clear() {
if (!isSet(this))
throw new TypeError("Method Set.prototype.clear called on incompatible receiver " + this);
var entry;
// Clear all primitive values
Object.getOwnPropertyNames(this._data.primitives).forEach(function (prop) {
if (this._data.primitives[prop] instanceof SetEntry) {
entry = this._data.primitives[prop];
delete this._data.primitives[prop];
entry.next = null;
entry.prev = null;
}
}, this);
// Clear all object values
Object.getOwnPropertyNames(this._data.objects).forEach(function (prop) {
if (this._data.objects[prop] instanceof SetEntry) {
entry = this._data.objects[prop];
delete this._data.objects[prop];
delete entry.value[this._objectHash];
entry.next = null;
entry.prev = null;
}
}, this);
this._data.objects.length = 0;
// Free head and tail MapEntry
this._head = null;
this._tail = null;
this._size = 0;
};
// Time complexity: O(1) for all cases(there is no worst case, same for both primitive and object value).
// Space complexity is O(1)
Set.prototype.delete = function (value) {
if (!isSet(this))
throw new TypeError("Method Set.prototype.delete called on incompatible receiver " + this);
var valueHash = hash(value),
objectHash = this._objectHash,
entry;
if (valueHash === null) {
if (typeof value[objectHash] === "number" && this._data.objects[value[objectHash]] instanceof SetEntry) {
entry = this._data.objects[value[objectHash]];
delete this._data.objects[value[objectHash]];
delete entry.value[objectHash];
} else
return false;
} else {
if (this._data.primitives[valueHash] instanceof SetEntry) {
entry = this._data.primitives[valueHash];
delete this._data.primitives[valueHash];
} else {
return false;
}
}
if (entry.prev !== null && entry.next !== null) {
entry.prev.next = entry.next;
entry.next.prev = entry.prev;
entry.next = null;
entry.prev = null;
} else if(entry.prev === null && entry.next !== null) {
this._head = entry.next;
entry.next.prev = null;
entry.next = null;
} if (entry.prev !== null && entry.next === null) {
this._tail = entry.prev;
entry.prev.next = null;
entry.prev = null;
} else {
this._head = null;
this._tail = null;
}
this._size--;
return true;
};
Set.prototype.entries = function entries() {
if (!isSet(this))
throw new TypeError("Method Set.prototype.entries called on incompatible receiver " + this);
return new SetIterator(this, 1);
};
Set.prototype.values = function values() {
if (!isSet(this))
throw new TypeError("Method Set.prototype.values called on incompatible receiver " + this);
return new SetIterator(this, 2);
};
Set.prototype.keys = Set.prototype.values;
Set.prototype[Symbol.iterator] = Set.prototype.values;
defineProperty(Set.prototype, "size", {
get: function size() {
if (!isSet(this))
throw new TypeError("Method Set.prototype.size called on incompatible receiver " + this);
return this._size;
},
configurable: true
});
Set.prototype.forEach = function forEach(callback, thisArg) {
if (!isSet(this))
throw new TypeError("Method Set.prototype.forEach called on incompatible receiver " + this);
if (!isCallable(callback))
throw new TypeError(callback + " is not a function");
var currentEntry = this._head;
while(currentEntry !== null) {
callback.call(thisArg, currentEntry.value, currentEntry.value, this);
currentEntry = currentEntry.next;
}
};
defineProperty(Set.prototype, Symbol.toStringTag.toString(), {
value: "Set",
configurable: true
});
var setupSetInternals = function (set) {
defineProperties(set, {
_isSet: {
value: true
},
_head: {
value: null,
writable: true
},
_tail: {
value: null,
writable: true
},
_objectHash: {
value: Symbol("Hash(set)")
},
_size: {
value: 0,
writable: true
},
_data: {
value: create(null, {
primitives: {
value: create(null) /* [[Prototype]] must be null */
},
objects: {
value: []
}
})
}
});
};
var checkSetInternals = function (set) {
return set._isSet === true
&& (set._head === null || set._head instanceof SetEntry)
&& (set._tail === null || set._tail instanceof SetEntry)
&& ES6.isSymbol(set._objectHash)
&& typeof set._size === "number"
&& isObject(set._data)
&& isObject(set._data.primitives)
&& isArray(set._data.objects);
};
var SetEntry = function SetEntry(value) {
this.value = value;
this.next = null;
this.prev = null;
};
var isSet = function (set) {
return set instanceof Set && checkSetInternals(set);
};
var WeakMap = function WeakMap(iterable) {
if (!(this instanceof WeakMap) || isWeakMap(this))
throw new TypeError("Constructor WeakMap requires 'new'");
setupWeakMapInternals(this);
if (iterable !== null && iterable !== undefined) {
ES6.forOf(iterable, function (entry) {
if (!isObject(entry))
throw new TypeError("Iterator value " + entry + " is not an entry object");
this.set(entry[0], entry[1]);
}, this);
}
};
var setupWeakMapInternals = function (weakMap) {
defineProperties(weakMap, {
_isWeakMap: {
value: true
},
_objectHash: {
value: Symbol("Hash(weakmap)")
},
_values: {
value: []
}
});
};
defineProperty(WeakMap.prototype, Symbol.toStringTag.toString(), {
value: "WeakMap",
configurable: true
});
var checkWeakMapInternals = function (weakMap) {
return weakMap._isWeakMap === true
&& ES6.isSymbol(weakMap._objectHash)
&& isArray(weakMap._values);
};
var isWeakMap = function (weakMap) {
return weakMap instanceof WeakMap && checkWeakMapInternals(weakMap);
};
// WARNING: This method puts a link in the key object to reduce time complexity to O(1).
// So, after weakMap.set(key, value) call, if the linker property of the key object is deleted
// then weakMap.has(key) will return false.
// Time complexity: O(1) for all cases(there is no worst case)
// Space complexity is O(n) for all cases.
WeakMap.prototype.set = function set(key, value) {
if (!isWeakMap(this))
throw new TypeError("Method WeakMap.prototype.set called on incompatible receiver " + this);
// No symbol is allowed in WeakMap as key
if (!isObject(key) || ES6.isSymbol(key))
throw new TypeError("Invalid value used as weak map key");
var objectHash = this._objectHash;
if (typeof key[objectHash] === "number" && this._values.hasOwnProperty(key[objectHash])) {
this._values[key[objectHash]] = value;
} else {
this._values.push(value);
defineProperty(key, objectHash.toString(), {
value: this._values.length - 1,
configurable: true
});
}
return this;
};
// Time complexity: O(1) for all cases(there is no worst case)
// Space complexity is O(1)
WeakMap.prototype.get = function get(key) {
if (!isWeakMap(this))
throw new TypeError("Method WeakMap.prototype.get called on incompatible receiver " + this);
if (!isObject(key) || ES6.isSymbol(key))
return;
var objectHash = this._objectHash;
if (typeof key[objectHash] === "number" && this._values.hasOwnProperty(key[objectHash]))
return this._values[key[objectHash]];
};
// Time complexity: O(1) for all cases(there is no worst case)
// Space complexity is O(1)
WeakMap.prototype.has = function has(key) {
if (!isWeakMap(this))
throw new TypeError("Method WeakMap.prototype.has called on incompatible receiver " + this);
if (!isObject(key) || ES6.isSymbol(key))
return false;
var objectHash = this._objectHash;
return typeof key[objectHash] === "number" && this._values.hasOwnProperty(key[objectHash]);
};
// Time complexity: O(1) for all cases(there is no worst case)
// Space complexity is O(1)
WeakMap.prototype.delete = function (key) {
if (!isWeakMap(this))
throw new TypeError("Method WeakMap.prototype.delete called on incompatible receiver " + this);
if (!isObject(key) || ES6.isSymbol(key))
return false;
var objectHash = this._objectHash;
if (typeof key[objectHash] === "number" && this._values.hasOwnProperty(key[objectHash])) {
delete this._values[key[objectHash]];
delete key[objectHash];
return true;
} else
return false;
};
var WeakSet = function WeakSet(ite