Set.js
4.89 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
/**
* 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