Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/third_party/closure/goog/structs/structs.js
4501 views
1
/**
2
* @license
3
* Copyright The Closure Library Authors.
4
* SPDX-License-Identifier: Apache-2.0
5
*/
6
7
/**
8
* @fileoverview Generics method for collection-like classes and objects.
9
*
10
*
11
* This file contains functions to work with collections. It supports using
12
* Map, Set, Array and Object and other classes that implement collection-like
13
* methods.
14
* @suppress {strictMissingProperties}
15
*/
16
17
18
goog.provide('goog.structs');
19
20
goog.require('goog.array');
21
goog.require('goog.object');
22
23
goog.require('goog.utils');
24
25
26
// We treat an object as a dictionary if it has getKeys or it is an object that
27
// isn't arrayLike.
28
29
30
/**
31
* Returns the number of values in the collection-like object.
32
* @param {Object} col The collection-like object.
33
* @return {number} The number of values in the collection-like object.
34
*/
35
goog.structs.getCount = function(col) {
36
'use strict';
37
if (col.getCount && typeof col.getCount == 'function') {
38
return col.getCount();
39
}
40
if (goog.utils.isArrayLike(col) || typeof col === 'string') {
41
return col.length;
42
}
43
return goog.object.getCount(col);
44
};
45
46
47
/**
48
* Returns the values of the collection-like object.
49
* @param {Object} col The collection-like object.
50
* @return {!Array<?>} The values in the collection-like object.
51
*/
52
goog.structs.getValues = function(col) {
53
'use strict';
54
if (col.getValues && typeof col.getValues == 'function') {
55
return col.getValues();
56
}
57
// ES6 Map and Set both define a values function that returns an iterator.
58
// The typeof check allows the compiler to remove the Map and Set polyfills
59
// if they are otherwise unused throughout the entire binary.
60
if ((typeof Map !== 'undefined' && col instanceof Map) ||
61
(typeof Set !== 'undefined' && col instanceof Set)) {
62
return Array.from(col.values());
63
}
64
if (typeof col === 'string') {
65
return col.split('');
66
}
67
if (goog.utils.isArrayLike(col)) {
68
var rv = [];
69
var l = col.length;
70
for (var i = 0; i < l; i++) {
71
rv.push(col[i]);
72
}
73
return rv;
74
}
75
return goog.object.getValues(col);
76
};
77
78
79
/**
80
* Returns the keys of the collection. Some collections have no notion of
81
* keys/indexes and this function will return undefined in those cases.
82
* @param {Object} col The collection-like object.
83
* @return {!Array|undefined} The keys in the collection.
84
*/
85
goog.structs.getKeys = function(col) {
86
'use strict';
87
if (col.getKeys && typeof col.getKeys == 'function') {
88
return col.getKeys();
89
}
90
// if we have getValues but no getKeys we know this is a key-less collection
91
if (col.getValues && typeof col.getValues == 'function') {
92
return undefined;
93
}
94
// ES6 Map and Set both define a keys function that returns an iterator. For
95
// Sets this iterates over the same values as the values iterator.
96
// The typeof check allows the compiler to remove the Map and Set polyfills
97
// if they are otherwise unused throughout the entire binary.
98
if (typeof Map !== 'undefined' && col instanceof Map) {
99
return Array.from(col.keys());
100
}
101
// Unlike the native Set, goog.structs.Set does not expose keys as the values.
102
if (typeof Set !== 'undefined' && col instanceof Set) {
103
return undefined;
104
}
105
if (goog.utils.isArrayLike(col) || typeof col === 'string') {
106
var rv = [];
107
var l = col.length;
108
for (var i = 0; i < l; i++) {
109
rv.push(i);
110
}
111
return rv;
112
}
113
114
return goog.object.getKeys(col);
115
};
116
117
118
/**
119
* Whether the collection contains the given value. This is O(n) and uses
120
* equals (==) to test the existence.
121
* @param {Object} col The collection-like object.
122
* @param {*} val The value to check for.
123
* @return {boolean} True if the map contains the value.
124
*/
125
goog.structs.contains = function(col, val) {
126
'use strict';
127
if (col.contains && typeof col.contains == 'function') {
128
return col.contains(val);
129
}
130
if (col.containsValue && typeof col.containsValue == 'function') {
131
return col.containsValue(val);
132
}
133
if (goog.utils.isArrayLike(col) || typeof col === 'string') {
134
return goog.array.contains(/** @type {!Array<?>} */ (col), val);
135
}
136
return goog.object.containsValue(col, val);
137
};
138
139
140
/**
141
* Whether the collection is empty.
142
* @param {Object} col The collection-like object.
143
* @return {boolean} True if empty.
144
*/
145
goog.structs.isEmpty = function(col) {
146
'use strict';
147
if (col.isEmpty && typeof col.isEmpty == 'function') {
148
return col.isEmpty();
149
}
150
151
// We do not use goog.string.isEmptyOrWhitespace because here we treat the
152
// string as
153
// collection and as such even whitespace matters
154
155
if (goog.utils.isArrayLike(col) || typeof col === 'string') {
156
return /** @type {!Array<?>} */ (col).length === 0;
157
}
158
return goog.object.isEmpty(col);
159
};
160
161
162
/**
163
* Removes all the elements from the collection.
164
* @param {Object} col The collection-like object.
165
* @return {void}
166
*/
167
goog.structs.clear = function(col) {
168
'use strict';
169
// NOTE(arv): This should not contain strings because strings are immutable
170
if (col.clear && typeof col.clear == 'function') {
171
col.clear();
172
} else if (goog.utils.isArrayLike(col)) {
173
goog.array.clear(/** @type {IArrayLike<?>} */ (col));
174
} else {
175
goog.object.clear(col);
176
}
177
};
178
179
180
/**
181
* Calls a function for each value in a collection. The function takes
182
* three arguments; the value, the key and the collection.
183
*
184
* @param {S} col The collection-like object.
185
* @param {function(this:T,?,?,S):?} f The function to call for every value.
186
* This function takes
187
* 3 arguments (the value, the key or undefined if the collection has no
188
* notion of keys, and the collection) and the return value is irrelevant.
189
* @param {T=} opt_obj The object to be used as the value of 'this'
190
* within `f`.
191
* @return {void}
192
* @template T,S
193
* @deprecated Use a more specific method, e.g. native Array.prototype.forEach,
194
* or for-of.
195
*/
196
goog.structs.forEach = function(col, f, opt_obj) {
197
'use strict';
198
if (col.forEach && typeof col.forEach == 'function') {
199
col.forEach(f, opt_obj);
200
} else if (goog.utils.isArrayLike(col) || typeof col === 'string') {
201
Array.prototype.forEach.call(/** @type {!Array<?>} */ (col), f, opt_obj);
202
} else {
203
var keys = goog.structs.getKeys(col);
204
var values = goog.structs.getValues(col);
205
var l = values.length;
206
for (var i = 0; i < l; i++) {
207
f.call(/** @type {?} */ (opt_obj), values[i], keys && keys[i], col);
208
}
209
}
210
};
211
212
213
/**
214
* Calls a function for every value in the collection. When a call returns true,
215
* adds the value to a new collection (Array is returned by default).
216
*
217
* @param {S} col The collection-like object.
218
* @param {function(this:T,?,?,S):boolean} f The function to call for every
219
* value. This function takes
220
* 3 arguments (the value, the key or undefined if the collection has no
221
* notion of keys, and the collection) and should return a Boolean. If the
222
* return value is true the value is added to the result collection. If it
223
* is false the value is not included.
224
* @param {T=} opt_obj The object to be used as the value of 'this'
225
* within `f`.
226
* @return {!Object|!Array<?>} A new collection where the passed values are
227
* present. If col is a key-less collection an array is returned. If col
228
* has keys and values a plain old JS object is returned.
229
* @template T,S
230
*/
231
goog.structs.filter = function(col, f, opt_obj) {
232
'use strict';
233
if (typeof col.filter == 'function') {
234
return col.filter(f, opt_obj);
235
}
236
if (goog.utils.isArrayLike(col) || typeof col === 'string') {
237
return Array.prototype.filter.call(
238
/** @type {!Array<?>} */ (col), f, opt_obj);
239
}
240
241
var rv;
242
var keys = goog.structs.getKeys(col);
243
var values = goog.structs.getValues(col);
244
var l = values.length;
245
if (keys) {
246
rv = {};
247
for (var i = 0; i < l; i++) {
248
if (f.call(/** @type {?} */ (opt_obj), values[i], keys[i], col)) {
249
rv[keys[i]] = values[i];
250
}
251
}
252
} else {
253
// We should not use Array#filter here since we want to make sure that
254
// the index is undefined as well as make sure that col is passed to the
255
// function.
256
rv = [];
257
for (var i = 0; i < l; i++) {
258
if (f.call(opt_obj, values[i], undefined, col)) {
259
rv.push(values[i]);
260
}
261
}
262
}
263
return rv;
264
};
265
266
267
/**
268
* Calls a function for every value in the collection and adds the result into a
269
* new collection (defaults to creating a new Array).
270
*
271
* @param {S} col The collection-like object.
272
* @param {function(this:T,?,?,S):V} f The function to call for every value.
273
* This function takes 3 arguments (the value, the key or undefined if the
274
* collection has no notion of keys, and the collection) and should return
275
* something. The result will be used as the value in the new collection.
276
* @param {T=} opt_obj The object to be used as the value of 'this'
277
* within `f`.
278
* @return {!Object<V>|!Array<V>} A new collection with the new values. If
279
* col is a key-less collection an array is returned. If col has keys and
280
* values a plain old JS object is returned.
281
* @template T,S,V
282
*/
283
goog.structs.map = function(col, f, opt_obj) {
284
'use strict';
285
if (typeof col.map == 'function') {
286
return col.map(f, opt_obj);
287
}
288
if (goog.utils.isArrayLike(col) || typeof col === 'string') {
289
return Array.prototype.map.call(/** @type {!Array<?>} */ (col), f, opt_obj);
290
}
291
292
var rv;
293
var keys = goog.structs.getKeys(col);
294
var values = goog.structs.getValues(col);
295
var l = values.length;
296
if (keys) {
297
rv = {};
298
for (var i = 0; i < l; i++) {
299
rv[keys[i]] = f.call(/** @type {?} */ (opt_obj), values[i], keys[i], col);
300
}
301
} else {
302
// We should not use Array#map here since we want to make sure that
303
// the index is undefined as well as make sure that col is passed to the
304
// function.
305
rv = [];
306
for (var i = 0; i < l; i++) {
307
rv[i] = f.call(/** @type {?} */ (opt_obj), values[i], undefined, col);
308
}
309
}
310
return rv;
311
};
312
313
314
/**
315
* Calls f for each value in a collection. If any call returns true this returns
316
* true (without checking the rest). If all returns false this returns false.
317
*
318
* @param {S} col The collection-like object.
319
* @param {function(this:T,?,?,S):boolean} f The function to call for every
320
* value. This function takes 3 arguments (the value, the key or undefined
321
* if the collection has no notion of keys, and the collection) and should
322
* return a boolean.
323
* @param {T=} opt_obj The object to be used as the value of 'this'
324
* within `f`.
325
* @return {boolean} True if any value passes the test.
326
* @template T,S
327
*/
328
goog.structs.some = function(col, f, opt_obj) {
329
'use strict';
330
if (typeof col.some == 'function') {
331
return col.some(f, opt_obj);
332
}
333
if (goog.utils.isArrayLike(col) || typeof col === 'string') {
334
return Array.prototype.some.call(
335
/** @type {!Array<?>} */ (col), f, opt_obj);
336
}
337
var keys = goog.structs.getKeys(col);
338
var values = goog.structs.getValues(col);
339
var l = values.length;
340
for (var i = 0; i < l; i++) {
341
if (f.call(/** @type {?} */ (opt_obj), values[i], keys && keys[i], col)) {
342
return true;
343
}
344
}
345
return false;
346
};
347
348
349
/**
350
* Calls f for each value in a collection. If all calls return true this return
351
* true this returns true. If any returns false this returns false at this point
352
* and does not continue to check the remaining values.
353
*
354
* @param {S} col The collection-like object.
355
* @param {function(this:T,?,?,S):boolean} f The function to call for every
356
* value. This function takes 3 arguments (the value, the key or
357
* undefined if the collection has no notion of keys, and the collection)
358
* and should return a boolean.
359
* @param {T=} opt_obj The object to be used as the value of 'this'
360
* within `f`.
361
* @return {boolean} True if all key-value pairs pass the test.
362
* @template T,S
363
*/
364
goog.structs.every = function(col, f, opt_obj) {
365
'use strict';
366
if (typeof col.every == 'function') {
367
return col.every(f, opt_obj);
368
}
369
if (goog.utils.isArrayLike(col) || typeof col === 'string') {
370
return Array.prototype.every.call(
371
/** @type {!Array<?>} */ (col), f, opt_obj);
372
}
373
var keys = goog.structs.getKeys(col);
374
var values = goog.structs.getValues(col);
375
var l = values.length;
376
for (var i = 0; i < l; i++) {
377
if (!f.call(/** @type {?} */ (opt_obj), values[i], keys && keys[i], col)) {
378
return false;
379
}
380
}
381
return true;
382
};
383
384