/** * Copyright (c) 2015-present, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * * @providesModule Set * @preventMunge * @typechecks */ /* eslint-disable no-extend-native */ 'use strict'; var Map = require('Map'); var _shouldPolyfillES6Collection = require('_shouldPolyfillES6Collection'); var toIterator = require('toIterator'); module.exports = (function(global) { // Since our implementation is spec-compliant for the most part we can safely // delegate to a built-in version if exists and is implemented correctly. // Firefox had gotten a few implementation details wrong across different // versions so we guard against that. // These checks are adapted from es6-shim https://fburl.com/34437854 if (!_shouldPolyfillES6Collection('Set')) { return global.Set; } /** * == ES6 Set Collection == * * This module is meant to implement a Set collection as described in chapter * 23.2 of the ES6 specification. * * Set objects are collections of unique values. Where values can be any * JavaScript value. * https://people.mozilla.org/~jorendorff/es6-draft.html#sec-map-objects * * There only two -- rather small -- diviations from the spec: * * 1. The use of frozen objects as keys. @see Map module for more on this. * * 2. The `size` property on a map object is a regular property and not a * computed property on the prototype as described by the spec. * The reason being is that we simply want to support ES3 environments * which doesn't implement computed properties. * * == Usage == * * var set = new set(iterable); * * set.set(value); * set.has(value); // true * set.delete(value); // true * * var iterator = set.keys(); * iterator.next(); // {value: value, done: false} * * var iterator = set.values(); * iterator.next(); // {value: value, done: false} * * var iterator = set.entries(); * iterator.next(); // {value: [value, value], done: false} * * set.forEach(function(value, value){ this === thisArg }, thisArg); * * set.clear(); // resets set. */ class Set { /** * 23.2.1.1 * * Takes an optional `iterable` (which is basically any object that * implements a Symbol.iterator (@@iterator) method). That is a collection * of values used to instantiate the set. * * @param {*} iterable */ constructor(iterable) { if (this == null || (typeof this !== 'object' && typeof this !== 'function')) { throw new TypeError('Wrong set object type.'); } initSet(this); if (iterable != null) { var it = toIterator(iterable); var next; while (!(next = it.next()).done) { this.add(next.value); } } } /** * 23.2.3.1 * * If it doesn't already exist in the collection a `value` is added. * * @param {*} value * @return {set} */ add(value) { this._map.set(value, value); this.size = this._map.size; return this; } /** * 23.2.3.2 * * Clears the set. */ clear() { initSet(this); } /** * 23.2.3.4 * * Deletes a `value` from the collection if it exists. * Returns true if the value was found and deleted and false otherwise. * * @param {*} value * @return {boolean} */ delete(value) { var ret = this._map.delete(value); this.size = this._map.size; return ret; } /** * 23.2.3.5 * * Returns an iterator over a collection of [value, value] tuples. */ entries() { return this._map.entries(); } /** * 23.2.3.6 * * Iterate over the collection calling `callback` with (value, value, set). * * @param {function} callback */ forEach(callback) { var thisArg = arguments[1]; var it = this._map.keys(); var next; while (!(next = it.next()).done) { callback.call(thisArg, next.value, next.value, this); } } /** * 23.2.3.7 * * Iterate over the collection calling `callback` with (value, value, set). * * @param {*} value * @return {boolean} */ has(value) { return this._map.has(value); } /** * 23.2.3.7 * * Returns an iterator over the colleciton of values. */ values() { return this._map.values(); } } // 23.2.3.11 Set.prototype[toIterator.ITERATOR_SYMBOL] = Set.prototype.values; // 23.2.3.7 Set.prototype.keys = Set.prototype.values; function initSet(set) { set._map = new Map(); set.size = set._map.size; } return Set; })(Function('return this')()); // eslint-disable-line no-new-func