• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

satisfactory-dev / benchmark.js / 21284075930

23 Jan 2026 10:13AM UTC coverage: 94.567% (+0.2%) from 94.336%
21284075930

push

github

SignpostMarv
rebuild docs

388 of 437 branches covered (88.79%)

Branch coverage included in aggregate %.

2693 of 2821 relevant lines covered (95.46%)

603.43 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.57
/benchmark.js
1
/*!
2✔
2
 * Benchmark.js
2✔
3
 * Copyright 2026 SignpostMarv
2✔
4
 * Copyright 2010-2016 Mathias Bynens
2✔
5
 * Based on JSLitmus.js, copyright Robert Kieffer
2✔
6
 * Modified by John-David Dalton
2✔
7
 * Available under MIT license
2✔
8
 */
2✔
9
;(function() {
2✔
10
  'use strict';
2✔
11

2✔
12
  /** Used to determine if values are of the language type Object. */
2✔
13
  var objectTypes = {
2✔
14
    'function': true,
2✔
15
    'object': true
2✔
16
  };
2✔
17

2✔
18
  /** Detect free variable `exports`. */
2✔
19
  var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports;
2✔
20

2✔
21
  /** Detect free variable `module`. */
2✔
22
  var freeModule = objectTypes[typeof module] && module && !module.nodeType && module;
2✔
23

2✔
24
  /** Used to assign each benchmark an incremented id. */
2✔
25
  var counter = 0;
2✔
26

2✔
27
  /** Detect the popular CommonJS extension `module.exports`. */
2✔
28
  var moduleExports = freeModule && freeModule.exports === freeExports && freeExports;
2✔
29

2✔
30
  /** Used to detect primitive types. */
2✔
31
  var rePrimitive = /^(?:boolean|number|string|undefined)$/;
2✔
32

2✔
33
  /** Used to make every compiled test unique. */
2✔
34
  var uidCounter = 0;
2✔
35

2✔
36
  /** Used to avoid hz of Infinity. */
2✔
37
  var divisors = {
2✔
38
    '1': 4096,
2✔
39
    '2': 512,
2✔
40
    '3': 64,
2✔
41
    '4': 8,
2✔
42
    '5': 0
2✔
43
  };
2✔
44

2✔
45
  /**
2✔
46
   * T-Distribution two-tailed critical values for 95% confidence.
2✔
47
   * For more info see http://www.itl.nist.gov/div898/handbook/eda/section3/eda3672.htm.
2✔
48
   */
2✔
49
  var tTable = {
2✔
50
    '1':  12.706, '2':  4.303, '3':  3.182, '4':  2.776, '5':  2.571, '6':  2.447,
2✔
51
    '7':  2.365,  '8':  2.306, '9':  2.262, '10': 2.228, '11': 2.201, '12': 2.179,
2✔
52
    '13': 2.16,   '14': 2.145, '15': 2.131, '16': 2.12,  '17': 2.11,  '18': 2.101,
2✔
53
    '19': 2.093,  '20': 2.086, '21': 2.08,  '22': 2.074, '23': 2.069, '24': 2.064,
2✔
54
    '25': 2.06,   '26': 2.056, '27': 2.052, '28': 2.048, '29': 2.045, '30': 2.042,
2✔
55
    'infinity': 1.96
2✔
56
  };
2✔
57

2✔
58
  /**
2✔
59
   * Critical Mann-Whitney U-values for 95% confidence.
2✔
60
   * For more info see http://www.saburchill.com/IBbiology/stats/003.html.
2✔
61
   */
2✔
62
  var uTable = {
2✔
63
    '5':  [0, 1, 2],
2✔
64
    '6':  [1, 2, 3, 5],
2✔
65
    '7':  [1, 3, 5, 6, 8],
2✔
66
    '8':  [2, 4, 6, 8, 10, 13],
2✔
67
    '9':  [2, 4, 7, 10, 12, 15, 17],
2✔
68
    '10': [3, 5, 8, 11, 14, 17, 20, 23],
2✔
69
    '11': [3, 6, 9, 13, 16, 19, 23, 26, 30],
2✔
70
    '12': [4, 7, 11, 14, 18, 22, 26, 29, 33, 37],
2✔
71
    '13': [4, 8, 12, 16, 20, 24, 28, 33, 37, 41, 45],
2✔
72
    '14': [5, 9, 13, 17, 22, 26, 31, 36, 40, 45, 50, 55],
2✔
73
    '15': [5, 10, 14, 19, 24, 29, 34, 39, 44, 49, 54, 59, 64],
2✔
74
    '16': [6, 11, 15, 21, 26, 31, 37, 42, 47, 53, 59, 64, 70, 75],
2✔
75
    '17': [6, 11, 17, 22, 28, 34, 39, 45, 51, 57, 63, 67, 75, 81, 87],
2✔
76
    '18': [7, 12, 18, 24, 30, 36, 42, 48, 55, 61, 67, 74, 80, 86, 93, 99],
2✔
77
    '19': [7, 13, 19, 25, 32, 38, 45, 52, 58, 65, 72, 78, 85, 92, 99, 106, 113],
2✔
78
    '20': [8, 14, 20, 27, 34, 41, 48, 55, 62, 69, 76, 83, 90, 98, 105, 112, 119, 127],
2✔
79
    '21': [8, 15, 22, 29, 36, 43, 50, 58, 65, 73, 80, 88, 96, 103, 111, 119, 126, 134, 142],
2✔
80
    '22': [9, 16, 23, 30, 38, 45, 53, 61, 69, 77, 85, 93, 101, 109, 117, 125, 133, 141, 150, 158],
2✔
81
    '23': [9, 17, 24, 32, 40, 48, 56, 64, 73, 81, 89, 98, 106, 115, 123, 132, 140, 149, 157, 166, 175],
2✔
82
    '24': [10, 17, 25, 33, 42, 50, 59, 67, 76, 85, 94, 102, 111, 120, 129, 138, 147, 156, 165, 174, 183, 192],
2✔
83
    '25': [10, 18, 27, 35, 44, 53, 62, 71, 80, 89, 98, 107, 117, 126, 135, 145, 154, 163, 173, 182, 192, 201, 211],
2✔
84
    '26': [11, 19, 28, 37, 46, 55, 64, 74, 83, 93, 102, 112, 122, 132, 141, 151, 161, 171, 181, 191, 200, 210, 220, 230],
2✔
85
    '27': [11, 20, 29, 38, 48, 57, 67, 77, 87, 97, 107, 118, 125, 138, 147, 158, 168, 178, 188, 199, 209, 219, 230, 240, 250],
2✔
86
    '28': [12, 21, 30, 40, 50, 60, 70, 80, 90, 101, 111, 122, 132, 143, 154, 164, 175, 186, 196, 207, 218, 228, 239, 250, 261, 272],
2✔
87
    '29': [13, 22, 32, 42, 52, 62, 73, 83, 94, 105, 116, 127, 138, 149, 160, 171, 182, 193, 204, 215, 226, 238, 249, 260, 271, 282, 294],
2✔
88
    '30': [13, 23, 33, 43, 54, 65, 76, 87, 98, 109, 120, 131, 143, 154, 166, 177, 189, 200, 212, 223, 235, 247, 258, 270, 282, 293, 305, 317]
2✔
89
  };
2✔
90

2✔
91
  /*--------------------------------------------------------------------------*/
2✔
92

2✔
93
  /**
2✔
94
   * no need to reference noop()
2✔
95
   *
2✔
96
   * @private
2✔
97
   */
2✔
98
  function noop() {
2✔
99
    /** empty */
1,072✔
100
  }
1,072✔
101

2✔
102
  /**
2✔
103
   * @param {*} maybe
2✔
104
   * @param {string} prop
2✔
105
   *
2✔
106
   * @returns {boolean}
2✔
107
   */
2✔
108
  function has(maybe, prop) {
2✔
109
    const canHaveProps = maybe && (typeof maybe === 'object' || typeof maybe === 'function');
18,540✔
110

18,540✔
111
    return canHaveProps && maybe.hasOwnProperty(prop);
18,540✔
112
  }
18,540✔
113

2✔
114
  /**
2✔
115
   * @param {RegExp} regex
2✔
116
   * @param {string} str
2✔
117
   *
2✔
118
   * @returns {string|null}
2✔
119
   */
2✔
120
  function getResult(regex, str) {
2✔
121
    const match = regex.exec(str);
260✔
122

260✔
123
    if (!match) {
260!
124
      return null;
×
125
    }
×
126

260✔
127
    return match[1];
260✔
128
  }
260✔
129

2✔
130
  /** Detect DOM document object. */
2✔
131
  var doc = isHostType(globalThis, 'document') && globalThis.document;
2✔
132

2✔
133
  /** Used to access Node.js's high resolution timer. */
2✔
134
  var processObject = isHostType(globalThis, 'process') && globalThis.process;
2✔
135

2✔
136
  /** Used to prevent a `removeChild` memory leak in IE < 9. */
2✔
137
  var trash = doc && doc.createElement('div');
2✔
138

2✔
139
  /** Used to integrity check compiled tests. */
2✔
140
  var uid = 'uid' + (+Date.now());
2✔
141

2✔
142
  /** Used to avoid infinite recursion when methods call each other. */
2✔
143
  var calledBy = {};
2✔
144

2✔
145
  /**
2✔
146
   * A class used to flag environments/features.
2✔
147
   *
2✔
148
   * @memberOf Benchmark
2✔
149
   */
2✔
150
  class Support {
2✔
151
    /**
2✔
152
     * @type {boolean|undefined}
2✔
153
     */
2✔
154
    static #browser;
2✔
155

1✔
156
    /**
1✔
157
     * @type {boolean|undefined}
1✔
158
     */
1✔
159
    static #decompilation;
2✔
160

2✔
161
    /**
2✔
162
     * Detect if running in a browser environment.
2✔
163
     *
2✔
164
     * @returns {boolean}
2✔
165
     */
2✔
166
    static get browser() {
2✔
167
      if (this.#browser == undefined) {
261✔
168
        this.#browser = doc && isHostType(globalThis, 'navigator');
2✔
169
      }
2✔
170

261✔
171
      return this.#browser;
261✔
172
    }
261✔
173

2✔
174
    /**
2✔
175
     * Detect if the Timers API exists.
2✔
176
     *
2✔
177
     * @returns {boolean}
2✔
178
     */
2✔
179
    static get timeout() {
2✔
180
      return true;
640✔
181
    }
640✔
182

2✔
183
    /**
2✔
184
     * Detect if function decompilation is supported.
2✔
185
     *
2✔
186
     * @returns {boolean}
2✔
187
     */
2✔
188
    static get decompilation() {
2✔
189
      if (this.#decompilation == undefined) {
553✔
190
        try {
2✔
191
          // Safari 2.x removes commas in object literals from `Function#toString` results.
2✔
192
          // See http://webk.it/11609 for more details.
2✔
193
          // Firefox 3.6 and Opera 9.25 strip grouping parentheses from `Function#toString` results.
2✔
194
          // See http://bugzil.la/559438 for more details.
2✔
195
          this.#decompilation = Function(
2✔
196
            ('return (' + (function(x) { return { 'x': '' + (1 + x) + '', 'y': 0 }; }) + ')')
2✔
197
            // Avoid issues with code added by Istanbul.
2✔
198
            .replace(/__cov__[^;]+;/g, '')
2✔
199
          )()(0).x === '1';
2✔
200
        } catch {
2!
201
          this.#decompilation = false;
×
202
        }
×
203
      }
2✔
204

553✔
205
      return this.#decompilation;
553✔
206
    }
553✔
207
  }
2✔
208

2✔
209
  /*------------------------------------------------------------------------*/
2✔
210

2✔
211
  /**
2✔
212
   * A specialized version of lodash's `cloneDeep` which only clones arrays and plain
2✔
213
   * objects assigning all other values by reference.
2✔
214
   *
2✔
215
   * @private
2✔
216
   * @param {*} value The value to clone.
2✔
217
   * @returns {*} The cloned value.
2✔
218
   */
2✔
219
  var cloneDeep = (value) => {
2✔
220
    if (Array.isArray(value)) {
69,593✔
221
      return [...value];
2,155✔
222
    } else if (value && typeof value === 'object') {
69,593✔
223
      return Object.fromEntries(
6,680✔
224
        Object.entries(value)
6,680✔
225
          .map(([key, value]) => [key, cloneDeep(value)]),
6,680✔
226
      );
6,680✔
227
    }
6,680✔
228

60,758✔
229
    return value;
60,758✔
230
  };
2✔
231

2✔
232
  /**
2✔
233
   * Creates a function from the given arguments string and body.
2✔
234
   *
2✔
235
   * @private
2✔
236
   * @param {string} args The comma separated function arguments.
2✔
237
   * @param {string} body The function body.
2✔
238
   * @returns {Function} The new function.
2✔
239
   */
2✔
240
  function createFunction() {
2✔
241
    // Lazy define.
2✔
242
    createFunction = function(args, body) {
2✔
243
      var result,
452✔
244
          anchor = Benchmark,
452✔
245
          prop = uid + 'createFunction';
452✔
246

452✔
247
      runScript('Benchmark.' + prop + '=function(' + args + '){' + body + '}');
452✔
248
      result = anchor[prop];
452✔
249
      delete anchor[prop];
452✔
250
      return result;
452✔
251
    };
2✔
252

2✔
253
    // Fix JaegerMonkey bug.
2✔
254
    // For more information see http://bugzil.la/639720.
2✔
255
    createFunction = Support.browser && (createFunction('', 'return"' + uid + '"') || noop)() == uid ? createFunction : Function;
2!
256
    return createFunction.apply(null, arguments);
2✔
257
  }
2✔
258

2✔
259
  /**
2✔
260
   * Delay the execution of a function based on the benchmark's `delay` property.
2✔
261
   *
2✔
262
   * @private
2✔
263
   * @param {Object} bench The benchmark instance.
2✔
264
   * @param {Object} fn The function to execute.
2✔
265
   */
2✔
266
  function delay(bench, fn) {
2✔
267
    bench._timerId = setTimeout(() => fn(), bench.delay * 1e3);
286✔
268
  }
286✔
269

2✔
270
  /**
2✔
271
   * Destroys the given element.
2✔
272
   *
2✔
273
   * @private
2✔
274
   * @param {Element} element The element to destroy.
2✔
275
   */
2✔
276
  function destroyElement(element) {
2✔
277
    trash.appendChild(element);
581✔
278
    trash.innerHTML = '';
581✔
279
  }
581✔
280

2✔
281
  /**
2✔
282
   * Gets the name of the first argument from a function's source.
2✔
283
   *
2✔
284
   * @private
2✔
285
   * @param {Function} fn The function.
2✔
286
   * @returns {string} The argument name.
2✔
287
   */
2✔
288
  function getFirstArgument(fn) {
2✔
289
    return (
96✔
290
      !has(fn, 'toString') &&
96✔
291
      (
96✔
292
        /^[\s(]*function[^(]*\(([^\s,)]+)/.exec(fn) ||
96✔
293
        0
36✔
294
      )[1]
96✔
295
    ) || '';
96✔
296
  }
96✔
297

2✔
298
  /**
2✔
299
   * Computes the arithmetic mean of a sample.
2✔
300
   *
2✔
301
   * @private
2✔
302
   * @param {[number, ...number[]]} sample The sample.
2✔
303
   * @returns {number} The mean.
2✔
304
   */
2✔
305
  function getMean(sample) {
2✔
306
    return sample.reduce((sum, x) => sum + x, 0) / sample.length;
244✔
307
  }
244✔
308

2✔
309
  /**
2✔
310
   * Gets the source code of a function.
2✔
311
   *
2✔
312
   * @private
2✔
313
   * @param {Function} fn The function.
2✔
314
   * @returns {string} The function's source code.
2✔
315
   */
2✔
316
  function getSource(fn) {
2✔
317
    var result = '';
522✔
318
    if (isStringable(fn)) {
522✔
319
      result = String(fn);
262✔
320
    } else if (Support.decompilation) {
390✔
321
      // Escape the `{` for Firefox 1.
260✔
322
      result = getResult(/^[^{]+\{([\s\S]*)\}\s*$/, fn);
260✔
323
    }
260✔
324
    // Trim string.
522✔
325
    result = (result || '').replace(/^\s+|\s+$/g, '');
522✔
326

522✔
327
    // Detect strings containing only the "use strict" directive.
522✔
328
    return /^(?:\/\*+[\w\W]*?\*\/|\/\/.*?[\n\r\u2028\u2029]|\s)*(["'])use strict\1;?$/.test(result)
522✔
329
      ? ''
522!
330
      : result;
522✔
331
  }
522✔
332

2✔
333
  /**
2✔
334
   * Host objects can return type values that are different from their actual
2✔
335
   * data type. The objects we are concerned with usually return non-primitive
2✔
336
   * types of "object", "function", or "unknown".
2✔
337
   *
2✔
338
   * @private
2✔
339
   * @param {*} object The owner of the property.
2✔
340
   * @param {string} property The property to check.
2✔
341
   * @returns {boolean} Returns `true` if the property value is a non-primitive, else `false`.
2✔
342
   */
2✔
343
  function isHostType(object, property) {
2✔
344
    if (object == null) {
5!
345
      return false;
×
346
    }
×
347
    var type = typeof object[property];
5✔
348
    return !rePrimitive.test(type) && (type != 'object' || !!object[property]);
5✔
349
  }
5✔
350

2✔
351
  /**
2✔
352
   * Checks if a value can be safely coerced to a string.
2✔
353
   *
2✔
354
   * @private
2✔
355
   * @param {*} value The value to check.
2✔
356
   * @returns {boolean} Returns `true` if the value can be coerced, else `false`.
2✔
357
   */
2✔
358
  function isStringable(value) {
2✔
359
    if (null === value) {
870!
360
      return false;
×
361
    }
×
362

870✔
363
    return (typeof value === 'string') || (has(value, 'toString') && (typeof value.toString === 'function'));
870✔
364
  }
870✔
365

2✔
366
  /**
2✔
367
   * Runs a snippet of JavaScript via script injection.
2✔
368
   *
2✔
369
   * @private
2✔
370
   * @param {string} code The code to run.
2✔
371
   */
2✔
372
  function runScript(code) {
2✔
373
    var anchor = Benchmark,
581✔
374
        script = doc.createElement('script'),
581✔
375
        sibling = doc.getElementsByTagName('script')[0],
581✔
376
        parent = sibling.parentNode,
581✔
377
        prop = uid + 'runScript',
581✔
378
        prefix = '(' + 'Benchmark.' + prop + '||function(){})();';
581✔
379

581✔
380
    // Firefox 2.0.0.2 cannot use script injection as intended because it executes
581✔
381
    // asynchronously, but that's OK because script injection is only used to avoid
581✔
382
    // the previously commented JaegerMonkey bug.
581✔
383
    try {
581✔
384
      // Remove the inserted script *before* running the code to avoid differences
581✔
385
      // in the expected script element count/order of the document.
581✔
386
      script.appendChild(doc.createTextNode(prefix + code));
581✔
387
      anchor[prop] = function() { destroyElement(script); };
581✔
388
    } catch(e) {
581!
389
      parent = parent.cloneNode(false);
×
390
      sibling = null;
×
391
      script.text = code;
×
392
    }
×
393
    parent.insertBefore(script, sibling);
581✔
394
    delete anchor[prop];
581✔
395
  }
581✔
396

2✔
397
  class Timer {
2✔
398
    /**
7✔
399
     * The timer namespace object or constructor.
7✔
400
     *
7✔
401
     * @readonly
7✔
402
     *
7✔
403
     * @type {Function|Object}
7✔
404
     */
7✔
405
    ns;
7✔
406

2✔
407
    #start = null;
2✔
408

2✔
409
    /**
2✔
410
     * Starts the deferred timer.
2✔
411
     *
2✔
412
     * @param {Object} deferred The deferred instance.
2✔
413
     */
2✔
414
    get start() {
2✔
415
      if (null === this.#start) {
52✔
416
        this.#start = createFunction(
2✔
417
          interpolate('o#'),
2✔
418
          interpolate('var n#=this.ns,${begin};o#.elapsed=0;o#.timeStamp=s#')
2✔
419
        );
2✔
420
      }
2✔
421

52✔
422
      return this.#start;
52✔
423
    }
52✔
424

2✔
425
    #stop = null;
2✔
426

2✔
427
    /**
2✔
428
     * Stops the deferred timer.
2✔
429
     *
2✔
430
     * @param {Object} deferred The deferred instance.
2✔
431
     */
2✔
432
    get stop() {
2✔
433
      if (null === this.#stop) {
52✔
434
        this.#stop = createFunction(
2✔
435
          interpolate('o#'),
2✔
436
          interpolate('var n#=this.ns,s#=o#.timeStamp,${end};o#.elapsed=r#')
2✔
437
        );
2✔
438
      }
2✔
439

52✔
440
      return this.#stop;
52✔
441
    }
52✔
442

2✔
443
    /**
2✔
444
     * @readonly
2✔
445
     *
2✔
446
     * @type {number}
2✔
447
     */
2✔
448
    res;
2✔
449

2✔
450
    /**
2✔
451
     * @readonly
2✔
452
     *
2✔
453
     * @type {'ms'|'us'|'ns'}
2✔
454
     */
2✔
455
    unit;
7✔
456

7✔
457
    /**
7✔
458
     *
7✔
459
     * @param {Timer['ns']} ns
7✔
460
     * @param {Timer['res']} res
7✔
461
     * @param {Timer['unit']} unit
7✔
462
     */
7✔
463
    constructor (
7✔
464
      ns,
9✔
465
      res,
9✔
466
      unit,
9✔
467
    ) {
9✔
468
      this.ns = ns;
9✔
469
      this.res = res;
9✔
470
      this.unit = unit;
9✔
471
    }
9✔
472

7✔
473
    /**
7✔
474
     * @type {Timer|undefined}
7✔
475
     */
7✔
476
    static #timer;
7✔
477

1✔
478
    /**
1✔
479
     * @type {Object<now, () => number>}
1✔
480
     */
1✔
481
    static #highestDefaultTimer = performance;
1✔
482

1✔
483
    /**
1✔
484
     * A high-precision timer such as the one provided by microtime
1✔
485
     *
1✔
486
     * @type {Object<now, () => number>|undefined}
1✔
487
     */
1✔
488
    static #usTimer;
1✔
489

1✔
490
    static #allowHrtime = true;
7✔
491

7✔
492
    /**
7✔
493
     * @param {Object} options
7✔
494
     * @param {Object<now, () => number>} [options.highestDefaultTimer]
7✔
495
     * @param {Object<now, () => number>} [options.usTimer] A high-precision timer such as the one provided by microtime
7✔
496
     * @param {boolean} [options.allowHrtime] If process.hrtime is available, controls whether it is used.
7✔
497
     */
7✔
498
    static changeContext({
7✔
499
      highestDefaultTimer = performance,
4✔
500
      usTimer = undefined,
4✔
501
      allowHrtime = true,
4✔
502
    } = {}) {
4✔
503
      this.#timer = undefined;
4✔
504
      this.#highestDefaultTimer = highestDefaultTimer;
4✔
505
      this.#usTimer = usTimer;
4✔
506
      this.#allowHrtime = allowHrtime;
4✔
507
    }
4✔
508

7✔
509
    /**
7✔
510
     * Gets the current timer's minimum resolution (secs).
7✔
511
     *
7✔
512
     * @param {Timer['unit']} unit
7✔
513
     * @param {Timer['ns']} ns
7✔
514
     */
7✔
515
    static #getRes(unit, ns) {
7✔
516
      var measured,
9✔
517
          begin,
9✔
518
          count = 30,
9✔
519
          divisor = 1e3,
9✔
520
          sample = [];
9✔
521

9✔
522
      // Get average smallest measurable time.
9✔
523
      while (count--) {
9✔
524
        if (unit == 'us') {
270✔
525
          divisor = 1e6;
60✔
526
          if (ns.stop) {
60!
527
            ns.start();
×
528
            while (!(measured = ns.microseconds())) {}
×
529
          } else {
60✔
530
            begin = ns();
60✔
531
            while (!(measured = ns() - begin)) {}
60✔
532
          }
60✔
533
        }
60✔
534
        else if (unit == 'ns') {
210✔
535
          divisor = 1e9;
60✔
536
          begin = (begin = ns())[0] + (begin[1] / divisor);
60✔
537
          while (!(measured = ((measured = ns())[0] + (measured[1] / divisor)) - begin)) {}
60!
538
          divisor = 1;
60✔
539
        }
60✔
540
        else if (ns.now) {
150✔
541
          begin = (+ns.now());
150✔
542
          while (!(measured = (+ns.now()) - begin)) {}
150✔
543
        }
150✔
544
        else {
×
545
          begin = new ns().getTime();
×
546
          while (!(measured = new ns().getTime() - begin)) {}
×
547
        }
×
548
        // Check for broken timers.
270✔
549
        if (measured > 0) {
270✔
550
          sample.push(measured);
270✔
551
        } else {
270!
552
          sample.push(Infinity);
×
553
          break;
×
554
        }
×
555
      }
270✔
556
      // Convert to seconds.
9✔
557
      return getMean(sample) / divisor;
9✔
558
    }
9✔
559

7✔
560
    /**
7✔
561
     * Timer object used by `clock()` and `Deferred#resolve`.
7✔
562
     *
7✔
563
     * @returns {Timer}
7✔
564
     */
7✔
565
    static get timer() {
7✔
566
      if (undefined === this.#timer) {
48✔
567
        /** @type {[Timer, ...Timer[]]} */
5✔
568
        const timers = [
5✔
569
          new Timer(
5✔
570
            this.#highestDefaultTimer,
5✔
571
            Math.max(0.0015, this.#getRes('ms', this.#highestDefaultTimer)),
5✔
572
            'ms',
5✔
573
          ),
5✔
574
        ];
5✔
575

5✔
576
        // Detect Chrome's microsecond timer:
5✔
577
        // enable benchmarking via the --enable-benchmarking command
5✔
578
        // line switch in at least Chrome 7 to use chrome.Interval
5✔
579
        try {
5✔
580
          const instance = new (globalThis.chrome || globalThis.chromium).Interval;
5✔
581
          if (instance) {
5!
582
            timers.push(new Timer(
×
583
              instance,
×
584
              this.#getRes('us', instance),
×
585
              'us',
×
586
            ));
×
587
          }
×
588
        } catch(e) {}
5✔
589

5✔
590
        // Detect Node.js's nanosecond resolution timer available in Node.js >= 0.8.
5✔
591
        if (
5✔
592
          this.#allowHrtime &&
5✔
593
          processObject &&
5✔
594
          typeof processObject.hrtime == 'function'
2✔
595
        ) {
5✔
596
          timers.push(new Timer(
2✔
597
            processObject.hrtime,
2✔
598
            this.#getRes('ns', processObject.hrtime),
2✔
599
            'ns',
2✔
600
          ));
2✔
601
        }
2✔
602
        // Detect a supplied us-scale timer
5✔
603
        if (this.#usTimer && typeof this.#usTimer == 'function') {
5✔
604
          timers.push(new Timer(
2✔
605
            this.#usTimer,
2✔
606
            this.#getRes('us', this.#usTimer),
2✔
607
            'us',
2✔
608
          ));
2✔
609
        }
2✔
610
        // Pick timer with highest resolution.
5✔
611
        const timer = timers.sort(({res: a}, {res: b}) => {
5✔
612
          return a - b;
6✔
613
        })[0];
5✔
614

5✔
615
        // Error if there are no working timers.
5✔
616
        if (timer.res == Infinity) {
5!
617
          throw new Error('Benchmark.js was unable to find a working timer.');
×
618
        }
×
619

5✔
620
        this.#timer = timer;
5✔
621
      }
5✔
622

48✔
623
      return this.#timer;
48✔
624
    }
48✔
625
  }
7✔
626

2✔
627
  /*------------------------------------------------------------------------*/
2✔
628

2✔
629
  /**
2✔
630
   * Abstract class handling events for both Benchmark and Suite
2✔
631
   *
2✔
632
   * @abstract
2✔
633
   */
2✔
634
  class EventTarget {
2✔
635
    /**
2✔
636
     * Executes all registered listeners of the specified event type.
2✔
637
     *
2✔
638
     * @param {Event} event The event type or object.
2✔
639
     * @param {...*} [args] Arguments to invoke the listener with.
2✔
640
     * @returns {*} Returns the return value of the last listener executed.
2✔
641
     */
2✔
642
    emit(event) {
2✔
643
      var listeners,
2,057✔
644
          object = this,
2,057✔
645
          events = object.events,
2,057✔
646
          args = (arguments[0] = event, arguments);
2,057✔
647

2,057✔
648
      event.currentTarget || (event.currentTarget = object);
2,057✔
649
      event.target || (event.target = object);
2,057✔
650
      delete event.result;
2,057✔
651

2,057✔
652
      if (events && (listeners = has(events, event.type) && events[event.type])) {
2,057✔
653
        for (const listener of [...listeners]) {
1,133✔
654
          if ((event.result = listener.apply(object, args)) === false) {
939✔
655
            event.cancelled = true;
8✔
656
          }
8✔
657
          if (event.aborted) {
939✔
658
            break;
202✔
659
          }
202✔
660
        }
939✔
661
      }
1,133✔
662
      return event.result;
2,057✔
663
    }
2,057✔
664

2✔
665
    /**
2✔
666
     * Returns an array of event listeners for a given type that can be manipulated
2✔
667
     * to add or remove listeners.
2✔
668
     *
2✔
669
     * @param {string} type The event type.
2✔
670
     * @returns {Array} The listeners array.
2✔
671
     */
2✔
672
    listeners(type) {
2✔
673
      var object = this,
8✔
674
          events = object.events || (object.events = {});
8✔
675

8✔
676
      return has(events, type) ? events[type] : (events[type] = []);
8✔
677
    }
8✔
678

2✔
679
    /**
2✔
680
     * Unregisters a listener for the specified event type(s),
2✔
681
     * or unregisters all listeners for the specified event type(s),
2✔
682
     * or unregisters all listeners for all event types.
2✔
683
     *
2✔
684
     * @param {string} [type] The event type.
2✔
685
     * @param {Function} [listener] The function to unregister.
2✔
686
     * @returns {Object} The current instance.
2✔
687
     * @example
2✔
688
     *
2✔
689
     * // unregister a listener for an event type
2✔
690
     * bench.off('cycle', listener);
2✔
691
     *
2✔
692
     * // unregister a listener for multiple event types
2✔
693
     * bench.off('start cycle', listener);
2✔
694
     *
2✔
695
     * // unregister all listeners for an event type
2✔
696
     * bench.off('cycle');
2✔
697
     *
2✔
698
     * // unregister all listeners for multiple event types
2✔
699
     * bench.off('start cycle complete');
2✔
700
     *
2✔
701
     * // unregister all listeners for all event types
2✔
702
     * bench.off();
2✔
703
     */
2✔
704
    off(type, listener) {
2✔
705
      var object = this,
244✔
706
          events = object.events;
244✔
707

244✔
708
      if (!events) {
244✔
709
        return object;
4✔
710
      }
4✔
711

240✔
712
      const loopOver = type ? type.split(' ') : events;
244✔
713

244✔
714
      const entries = Array.isArray(loopOver)
244✔
715
        ? loopOver.map((value, key) => [key, value])
244✔
716
        : Object.entries(loopOver);
244✔
717

244✔
718
      entries.forEach(function([type, listeners]) {
244✔
719
        var index;
256✔
720
        if (typeof listeners == 'string') {
256✔
721
          type = listeners;
238✔
722
          listeners = has(events, type) && events[type];
238✔
723
        }
238✔
724
        if (listeners) {
256✔
725
          if (listener) {
252✔
726
            index = listeners.indexOf(listener);
226✔
727
            if (index > -1) {
226✔
728
              listeners.splice(index, 1);
226✔
729
            }
226✔
730
          } else {
252✔
731
            listeners.length = 0;
26✔
732
          }
26✔
733
        }
252✔
734
      });
244✔
735
      return object;
244✔
736
    }
244✔
737

2✔
738
    /**
2✔
739
     * Registers a listener for the specified event type(s).
2✔
740
     *
2✔
741
     * @param {string} type The event type.
2✔
742
     * @param {Function} listener The function to register.
2✔
743
     * @returns {Object} The current instance.
2✔
744
     * @example
2✔
745
     *
2✔
746
     * // register a listener for an event type
2✔
747
     * bench.on('cycle', listener);
2✔
748
     *
2✔
749
     * // register a listener for multiple event types
2✔
750
     * bench.on('start cycle', listener);
2✔
751
     */
2✔
752
    on(type, listener) {
2✔
753
      var object = this,
390✔
754
          events = object.events || (object.events = {});
390✔
755

390✔
756
      type.split(' ').forEach((type) => {
390✔
757
        (has(events, type)
394✔
758
          ? events[type]
394✔
759
          : (events[type] = [])
394✔
760
        ).push(listener);
394✔
761
      });
390✔
762
      return object;
390✔
763
    }
390✔
764

2✔
765
    /**
2✔
766
     * A helper function for setting options/event handlers.
2✔
767
     *
2✔
768
     * @protected
2✔
769
     * @param {Object} object The benchmark or suite instance.
2✔
770
     * @param {Object} [options={}] Options object.
2✔
771
     */
2✔
772
    setOptions(object, options) {
2✔
773
      options = object.options = Object.assign({}, cloneDeep(object.constructor.options), cloneDeep(options));
838✔
774

838✔
775
      Object.entries(options).forEach(([key, value]) => {
838✔
776
        if (value != null) {
14,974✔
777
          // Add event listeners.
9,391✔
778
          if (/^on[A-Z]/.test(key)) {
9,391✔
779
            key.split(' ').forEach((key) => {
60✔
780
              object.on(key.slice(2).toLowerCase(), value);
60✔
781
            });
60✔
782
          } else if (
9,391✔
783
            !has(object, key) || (
9,331✔
784
              object instanceof Benchmark &&
3,274✔
785
              key in Benchmark.defaultValues
3,274✔
786
            )
3,274✔
787
          ) {
9,331✔
788
            object[key] = cloneDeep(value);
9,064✔
789
          }
9,064✔
790
        }
9,391✔
791
      });
838✔
792
    }
838✔
793

2✔
794
    /**
2✔
795
     * Converts a Suite or Suite-like object/array to an array of values
2✔
796
     *
2✔
797
     * @param {(unknown[])|Suite|Object<number|'length', unknown>} array
2✔
798
     *
2✔
799
     * @returns {(unknown[])|(Benchmark[])}
2✔
800
     */
2✔
801
    static asArray(array) {
2✔
802
      if (Array.isArray(array)) {
84✔
803
        return [...array];
52✔
804
      } else if (array instanceof Suite) {
84✔
805
        return array.benchmarks;
32✔
806
      }
32✔
807

×
808
      return Object.keys(array || Object.create(null))
84✔
809
        .filter((maybe) => /^\d+$/.test(maybe))
84✔
810
        .map((key) => array[key]);
84✔
811
    }
84✔
812
  }
2✔
813

2✔
814
  /*------------------------------------------------------------------------*/
2✔
815

2✔
816
  class Benchmark extends EventTarget {
2✔
817
    /**
382✔
818
     * The number of times a test was executed.
382✔
819
     *
382✔
820
     * @type {number}
382✔
821
     */
382✔
822
    count = Benchmark.defaultValues.count;
382✔
823

380✔
824
    /**
380✔
825
     * The number of cycles performed while benchmarking.
380✔
826
     *
380✔
827
     * @type {number}
380✔
828
     */
380✔
829
    cycles = Benchmark.defaultValues.cycles;
380✔
830

380✔
831
    /**
380✔
832
     * The number of executions per second.
380✔
833
     *
380✔
834
     * @type {number}
380✔
835
     */
380✔
836
    hz = Benchmark.defaultValues.hz;
380✔
837

380✔
838
    /**
380✔
839
     * The compiled test function.
380✔
840
     *
380✔
841
     * @type {Function|string}
380✔
842
     */
380✔
843
    compiled = Benchmark.defaultValues.compiled;
380✔
844

380✔
845
    /**
380✔
846
     * The error object if the test failed.
380✔
847
     *
380✔
848
     * @type {Object|undefined}
380✔
849
     */
380✔
850
    error = Benchmark.defaultValues.error;
380✔
851

380✔
852
    /**
380✔
853
     * The test to benchmark.
380✔
854
     *
380✔
855
     * @type {Function|string}
380✔
856
     */
380✔
857
    fn = Benchmark.defaultValues.fn;
380✔
858

380✔
859
    /**
380✔
860
     * A flag to indicate if the benchmark is aborted.
380✔
861
     *
380✔
862
     * @type {boolean}
380✔
863
     */
380✔
864
    aborted = Benchmark.defaultValues.aborted;
380✔
865

380✔
866
    /**
380✔
867
     * A flag to indicate if the benchmark is running.
380✔
868
     *
380✔
869
     * @type {boolean}
380✔
870
     */
380✔
871
    running = Benchmark.defaultValues.running;
380✔
872

380✔
873
    /**
380✔
874
     * Compiled into the test and executed immediately **before** the test loop.
380✔
875
     *
380✔
876
     * @type {Function|string}
380✔
877
     * @example
380✔
878
     *
380✔
879
     * // basic usage
380✔
880
     * var bench = Benchmark({
380✔
881
     *   'setup': function() {
380✔
882
     *     var c = this.count,
380✔
883
     *         element = document.getElementById('container');
380✔
884
     *     while (c--) {
380✔
885
     *       element.appendChild(document.createElement('div'));
380✔
886
     *     }
380✔
887
     *   },
380✔
888
     *   'fn': function() {
380✔
889
     *     element.removeChild(element.lastChild);
380✔
890
     *   }
380✔
891
     * });
380✔
892
     *
380✔
893
     * // compiles to something like:
380✔
894
     * var c = this.count,
380✔
895
     *     element = document.getElementById('container');
380✔
896
     * while (c--) {
380✔
897
     *   element.appendChild(document.createElement('div'));
380✔
898
     * }
380✔
899
     * var start = new Date;
380✔
900
     * while (count--) {
380✔
901
     *   element.removeChild(element.lastChild);
380✔
902
     * }
380✔
903
     * var end = new Date - start;
380✔
904
     *
380✔
905
     * // or using strings
380✔
906
     * var bench = Benchmark({
380✔
907
     *   'setup': '\
380✔
908
     *     var a = 0;\n\
380✔
909
     *     (function() {\n\
380✔
910
     *       (function() {\n\
380✔
911
     *         (function() {',
380✔
912
     *   'fn': 'a += 1;',
380✔
913
     *   'teardown': '\
380✔
914
     *          }())\n\
380✔
915
     *        }())\n\
380✔
916
     *      }())'
380✔
917
     * });
380✔
918
     *
380✔
919
     * // compiles to something like:
380✔
920
     * var a = 0;
380✔
921
     * (function() {
380✔
922
     *   (function() {
380✔
923
     *     (function() {
380✔
924
     *       var start = new Date;
380✔
925
     *       while (count--) {
380✔
926
     *         a += 1;
380✔
927
     *       }
380✔
928
     *       var end = new Date - start;
380✔
929
     *     }())
380✔
930
     *   }())
380✔
931
     * }())
380✔
932
     */
380✔
933
    setup = Benchmark.defaultValues.setup;
380✔
934

380✔
935
    /**
380✔
936
     * Compiled into the test and executed immediately **after** the test loop.
380✔
937
     *
380✔
938
     * @type {Function|string}
380✔
939
     */
380✔
940
    teardown = Benchmark.defaultValues.teardown;
380✔
941

380✔
942
    /**
380✔
943
     * An object of stats including mean, margin or error, and standard deviation.
380✔
944
     *
380✔
945
     * @type Object
380✔
946
     */
380✔
947
    stats = {
380✔
948
      /**
380✔
949
       * The margin of error.
380✔
950
       *
380✔
951
       * @type {number}
380✔
952
       */
380✔
953
      moe: Benchmark.defaultValues.stats.moe,
380✔
954

380✔
955
      /**
380✔
956
       * The relative margin of error (expressed as a percentage of the mean).
380✔
957
       *
380✔
958
       * @type {number}
380✔
959
       */
380✔
960
      rme: Benchmark.defaultValues.stats.rme,
380✔
961

380✔
962
      /**
380✔
963
       * The standard error of the mean.
380✔
964
       *
380✔
965
       * @type {number}
380✔
966
       */
380✔
967
      sem: Benchmark.defaultValues.stats.sem,
380✔
968

380✔
969
      /**
380✔
970
       * The sample standard deviation.
380✔
971
       *
380✔
972
       * @type {number}
380✔
973
       */
380✔
974
      deviation: Benchmark.defaultValues.stats.deviation,
380✔
975

380✔
976
      /**
380✔
977
       * The sample arithmetic mean (secs).
380✔
978
       *
380✔
979
       * @type number
380✔
980
       */
380✔
981
      mean: Benchmark.defaultValues.stats.mean,
380✔
982

380✔
983
      /**
380✔
984
       * The array of sampled periods.
380✔
985
       *
380✔
986
       * @type Array
380✔
987
       */
380✔
988
      sample: [...Benchmark.defaultValues.stats.sample],
380✔
989

380✔
990
      /**
380✔
991
       * The sample variance.
380✔
992
       *
380✔
993
       * @type number
380✔
994
       */
380✔
995
      variance: Benchmark.defaultValues.stats.variance,
380✔
996
    };
380✔
997

380✔
998
    /**
380✔
999
     * An object of timing data including cycle, elapsed, period, start, and stop.
380✔
1000
     *
380✔
1001
     * @type Object
380✔
1002
     */
380✔
1003
    times = {
380✔
1004
      /**
380✔
1005
       * The time taken to complete the last cycle (secs).
380✔
1006
       *
380✔
1007
       * @type number
380✔
1008
       */
380✔
1009
      cycle: Benchmark.defaultValues.times.cycle,
380✔
1010

380✔
1011
      /**
380✔
1012
       * The time taken to complete the benchmark (secs).
380✔
1013
       *
380✔
1014
       * @type number
380✔
1015
       */
380✔
1016
      elapsed: Benchmark.defaultValues.times.elapsed,
380✔
1017

380✔
1018
      /**
380✔
1019
       * The time taken to execute the test once (secs).
380✔
1020
       *
380✔
1021
       * @type number
380✔
1022
       */
380✔
1023
      period: Benchmark.defaultValues.times.period,
380✔
1024

380✔
1025
      /**
380✔
1026
       * A timestamp of when the benchmark started (ms).
380✔
1027
       *
380✔
1028
       * @type number
380✔
1029
       */
380✔
1030
      timeStamp: Benchmark.defaultValues.times.timeStamp,
380✔
1031
    };
382✔
1032

382✔
1033
    /**
382✔
1034
     * The default options copied by benchmark instances.
382✔
1035
     *
382✔
1036
     * @type {Object}
382✔
1037
     */
382✔
1038
    static options = {
382✔
1039
      /**
1✔
1040
       * A flag to indicate that benchmark cycles will execute asynchronously
1✔
1041
       * by default.
1✔
1042
       *
1✔
1043
       * @type boolean
1✔
1044
       */
1✔
1045
      'async': false,
1✔
1046

1✔
1047
      /**
1✔
1048
       * A flag to indicate that the benchmark clock is deferred.
1✔
1049
       *
1✔
1050
       * @type boolean
1✔
1051
       */
1✔
1052
      'defer': false,
1✔
1053

1✔
1054
      /**
1✔
1055
       * The delay between test cycles (secs).
1✔
1056
       * @type number
1✔
1057
       */
1✔
1058
      'delay': 0.005,
1✔
1059

1✔
1060
      /**
1✔
1061
       * Displayed by `Benchmark#toString` when a `name` is not available
1✔
1062
       * (auto-generated if absent).
1✔
1063
       *
1✔
1064
       * @type string
1✔
1065
       */
1✔
1066
      'id': undefined,
1✔
1067

1✔
1068
      /**
1✔
1069
       * The default number of times to execute a test on a benchmark's first cycle.
1✔
1070
       *
1✔
1071
       * @type number
1✔
1072
       */
1✔
1073
      'initCount': 1,
1✔
1074

1✔
1075
      /**
1✔
1076
       * The maximum time a benchmark is allowed to run before finishing (secs).
1✔
1077
       *
1✔
1078
       * Note: Cycle delays aren't counted toward the maximum time.
1✔
1079
       *
1✔
1080
       * @type number
1✔
1081
       */
1✔
1082
      'maxTime': 5,
1✔
1083

1✔
1084
      /**
1✔
1085
       * The minimum sample size required to perform statistical analysis.
1✔
1086
       *
1✔
1087
       * @type number
1✔
1088
       */
1✔
1089
      'minSamples': 5,
1✔
1090

1✔
1091
      /**
1✔
1092
       * The time needed to reduce the percent uncertainty of measurement to 1% (secs).
1✔
1093
       *
1✔
1094
       * @type number
1✔
1095
       */
1✔
1096
      'minTime': 0,
1✔
1097

1✔
1098
      /**
1✔
1099
       * The name of the benchmark.
1✔
1100
       *
1✔
1101
       * @type string
1✔
1102
       */
1✔
1103
      'name': undefined,
1✔
1104

1✔
1105
      /**
1✔
1106
       * An event listener called when the benchmark is aborted.
1✔
1107
       *
1✔
1108
       * @type Function
1✔
1109
       */
1✔
1110
      'onAbort': undefined,
1✔
1111

1✔
1112
      /**
1✔
1113
       * An event listener called when the benchmark completes running.
1✔
1114
       *
1✔
1115
       * @type Function
1✔
1116
       */
1✔
1117
      'onComplete': undefined,
1✔
1118

1✔
1119
      /**
1✔
1120
       * An event listener called after each run cycle.
1✔
1121
       *
1✔
1122
       * @type Function
1✔
1123
       */
1✔
1124
      'onCycle': undefined,
1✔
1125

1✔
1126
      /**
1✔
1127
       * An event listener called when a test errors.
1✔
1128
       *
1✔
1129
       * @type Function
1✔
1130
       */
1✔
1131
      'onError': undefined,
1✔
1132

1✔
1133
      /**
1✔
1134
       * An event listener called when the benchmark is reset.
1✔
1135
       *
1✔
1136
       * @type Function
1✔
1137
       */
1✔
1138
      'onReset': undefined,
1✔
1139

1✔
1140
      /**
1✔
1141
       * An event listener called when the benchmark starts running.
1✔
1142
       *
1✔
1143
       * @type Function
1✔
1144
       */
1✔
1145
      'onStart': undefined
1✔
1146
    };
1✔
1147

1✔
1148
    /**
1✔
1149
     * The semantic version number.
1✔
1150
     *
1✔
1151
     * @type string
1✔
1152
     *
1✔
1153
     * @todo replace with json-derived version built from npm version/git hash
1✔
1154
     */
1✔
1155
    static version = '2.1.4';
1✔
1156

1✔
1157
    static get Event() {
1✔
1158
      return Event;
36✔
1159
    }
36✔
1160

1✔
1161
    static get Suite() {
1✔
1162
      return Suite;
38✔
1163
    }
38✔
1164

1✔
1165
    static get Timer() {
1✔
1166
      return Timer;
10✔
1167
    }
10✔
1168

1✔
1169
    /**
1✔
1170
     * The default values for Benchmark instance properties
1✔
1171
     *
1✔
1172
     * @returns {Object}
1✔
1173
     */
1✔
1174
    static defaultValues = Object.freeze({
1✔
1175
      count: 0,
1✔
1176
      cycles: 0,
1✔
1177
      hz: 0,
1✔
1178
      compiled: undefined,
1✔
1179
      error: undefined,
1✔
1180
      fn: undefined,
1✔
1181
      aborted: false,
1✔
1182
      running: false,
1✔
1183
      setup: noop,
1✔
1184
      teardown: noop,
1✔
1185
      stats: {
1✔
1186
        moe: 0,
1✔
1187
        rme: 0,
1✔
1188
        sem: 0,
1✔
1189
        deviation: 0,
1✔
1190
        mean: 0,
1✔
1191
        sample: [],
1✔
1192
        variance: 0,
1✔
1193
      },
1✔
1194
      times: {
1✔
1195
        cycle: 0,
1✔
1196
        elapsed: 0,
1✔
1197
        period: 0,
1✔
1198
        timeStamp: 0,
1✔
1199
      },
1✔
1200
    })
1✔
1201

382✔
1202
    /**
382✔
1203
     * A generic `Array#filter` like method.
382✔
1204
     *
382✔
1205
     * @param {Array} array The array to iterate over.
382✔
1206
     * @param {Function|string} callback The function/alias called per iteration.
382✔
1207
     * @returns {Array} A new array of values that passed callback filter.
382✔
1208
     * @example
382✔
1209
     *
382✔
1210
     * // get odd numbers
382✔
1211
     * Benchmark.filter([1, 2, 3, 4, 5], function(n) {
382✔
1212
     *   return n % 2;
382✔
1213
     * }); // -> [1, 3, 5];
382✔
1214
     *
382✔
1215
     * // get fastest benchmarks
382✔
1216
     * Benchmark.filter(benches, 'fastest');
382✔
1217
     *
382✔
1218
     * // get slowest benchmarks
382✔
1219
     * Benchmark.filter(benches, 'slowest');
382✔
1220
     *
382✔
1221
     * // get benchmarks that completed without erroring
382✔
1222
     * Benchmark.filter(benches, 'successful');
382✔
1223
     */
382✔
1224
    static filter(array, callback) {
382✔
1225
      if (callback === 'successful') {
34✔
1226
        // Callback to exclude those that are errored, unrun, or have hz of Infinity.
14✔
1227
        callback = function(bench) {
14✔
1228
          return bench.cycles && Number.isFinite(bench.hz) && !bench.error;
34✔
1229
        };
14✔
1230
      }
14✔
1231
      else if (callback === 'fastest' || callback === 'slowest') {
20✔
1232
        // Get successful, sort by period + margin of error, and filter fastest/slowest.
12✔
1233
        var result = this.filter(array, 'successful').sort(function(a, b) {
12✔
1234
          a = a.stats; b = b.stats;
12✔
1235
          return (a.mean + a.moe > b.mean + b.moe ? 1 : -1) * (callback === 'fastest' ? 1 : -1);
12!
1236
        });
12✔
1237

12✔
1238
        return result.filter((bench) => {
12✔
1239
          return result[0].compare(bench) == 0;
24✔
1240
        });
12✔
1241
      }
12✔
1242

22✔
1243
      if (array instanceof Suite) {
34✔
1244
        return array.benchmarks.filter((benchmark, index) => callback(benchmark, index, array));
6✔
1245
      }
6✔
1246

16✔
1247
      if (!Array.isArray(array)) {
34✔
1248
        const {
4✔
1249
          isArrayLike,
4✔
1250
          result,
4✔
1251
        } = Object.entries(array)
4✔
1252
          .filter(([key, value]) => callback(
4✔
1253
            value,
20✔
1254
            (typeof key === 'string' && /^\d+/.test(key))
20✔
1255
              ? parseInt(key, 10)
20✔
1256
              : key,
20✔
1257
            array,
20✔
1258
          ))
4✔
1259
          .reduce(
4✔
1260
            (was, [key, value]) => {
4✔
1261
              if (typeof key === 'string' && /^\d+/.test(key)) {
6✔
1262
                ++was.currentIndex;
6✔
1263

6✔
1264
                was.result[was.currentIndex] = value;
6✔
1265
              } else {
6!
1266
                was.result[key] = value;
×
1267
                was.isArrayLike = false;
×
1268
              }
×
1269

6✔
1270
              return was;
6✔
1271
            },
4✔
1272
            {
4✔
1273
              currentIndex: -1,
4✔
1274
              result: Object.create(null),
4✔
1275
              isArrayLike: true,
4✔
1276
            },
4✔
1277
          );
4✔
1278

4✔
1279
          return isArrayLike ? Object.values(result) : result;
4!
1280
      }
4✔
1281

12✔
1282
      return array.filter(callback);
12✔
1283
    }
34✔
1284

382✔
1285
    /**
382✔
1286
     * Converts a number to a more readable comma-separated string representation.
382✔
1287
     *
382✔
1288
     * @param {number} number The number to convert.
382✔
1289
     * @returns {string} The more readable string representation.
382✔
1290
     */
382✔
1291
    static formatNumber(number) {
382✔
1292
      number = String(number).split('.');
19,279✔
1293
      return number[0].replace(/(?=(?:\d{3})+$)(?!\b)/g, ',') +
19,279✔
1294
        (number[1] ? '.' + number[1] : '');
19,279✔
1295
    }
19,279✔
1296

382✔
1297
    /**
382✔
1298
     * Invokes a method on all items in an array.
382✔
1299
     *
382✔
1300
     * @param {Array} benches Array of benchmarks to iterate over.
382✔
1301
     * @param {Object|string} name The name of the method to invoke OR options object.
382✔
1302
     * @param {...*} [args] Arguments to invoke the method with.
382✔
1303
     * @returns {Array} A new array of values returned from each method invoked.
382✔
1304
     * @example
382✔
1305
     *
382✔
1306
     * // invoke `reset` on all benchmarks
382✔
1307
     * Benchmark.invoke(benches, 'reset');
382✔
1308
     *
382✔
1309
     * // invoke `emit` with arguments
382✔
1310
     * Benchmark.invoke(benches, 'emit', 'complete', listener);
382✔
1311
     *
382✔
1312
     * // invoke `run(true)`, treat benchmarks as a queue, and register invoke callbacks
382✔
1313
     * Benchmark.invoke(benches, {
382✔
1314
     *
382✔
1315
     *   // invoke the `run` method
382✔
1316
     *   'name': 'run',
382✔
1317
     *
382✔
1318
     *   // pass a single argument
382✔
1319
     *   'args': true,
382✔
1320
     *
382✔
1321
     *   // treat as queue, removing benchmarks from front of `benches` until empty
382✔
1322
     *   'queued': true,
382✔
1323
     *
382✔
1324
     *   // called before any benchmarks have been invoked.
382✔
1325
     *   'onStart': onStart,
382✔
1326
     *
382✔
1327
     *   // called between invoking benchmarks
382✔
1328
     *   'onCycle': onCycle,
382✔
1329
     *
382✔
1330
     *   // called after all benchmarks have been invoked.
382✔
1331
     *   'onComplete': onComplete
382✔
1332
     * });
382✔
1333
     */
382✔
1334
    static invoke(benches, name) {
382✔
1335
      var args,
70✔
1336
          bench,
70✔
1337
          queued,
70✔
1338
          index = -1,
70✔
1339
          eventProps = { 'currentTarget': benches },
70✔
1340
          options = { 'onStart': noop, 'onCycle': noop, 'onComplete': noop },
70✔
1341
          result = this.asArray(benches);
70✔
1342

70✔
1343
      /**
70✔
1344
       * Invokes the method of the current object and if synchronous, fetches the next.
70✔
1345
       */
70✔
1346
      function execute() {
70✔
1347
        var listeners,
289✔
1348
            async = isAsync(bench);
289✔
1349

289✔
1350
        if (async) {
289✔
1351
          // Use `getNext` as the first listener.
198✔
1352
          bench.on('complete', getNext);
198✔
1353
          listeners = bench.events.complete;
198✔
1354
          listeners.splice(0, 0, listeners.pop());
198✔
1355
        }
198✔
1356
        // Execute method.
289✔
1357
        result[index] = (typeof (bench ? bench[name] : undefined) === 'function')
289!
1358
          ? bench[name].apply(bench, args)
289✔
1359
          : undefined;
289!
1360
        // If synchronous return `true` until finished.
289✔
1361
        return !async && getNext();
289✔
1362
      }
289✔
1363

70✔
1364
      /**
70✔
1365
       * Fetches the next bench or executes `onComplete` callback.
70✔
1366
       */
70✔
1367
      function getNext(event) {
70✔
1368
        var cycleEvent,
289✔
1369
            last = bench,
289✔
1370
            async = isAsync(last);
289✔
1371

289✔
1372
        if (async) {
289✔
1373
          last.off('complete', getNext);
198✔
1374
          last.emit(new Event('complete'));
198✔
1375
        }
198✔
1376
        // Emit "cycle" event.
289✔
1377
        eventProps.type = 'cycle';
289✔
1378
        eventProps.target = last;
289✔
1379
        cycleEvent = new Event(eventProps);
289✔
1380
        options.onCycle.call(benches._benchmarks, cycleEvent);
289✔
1381

289✔
1382
        // Choose next benchmark if not exiting early.
289✔
1383
        if (!cycleEvent.aborted && raiseIndex() !== false) {
289✔
1384
          bench = queued ? benches[0] : result[index];
221✔
1385
          if (isAsync(bench)) {
221✔
1386
            delay(bench, execute);
160✔
1387
          }
160✔
1388
          else if (async) {
61!
1389
            // Resume execution if previously asynchronous but now synchronous.
×
1390
            while (execute()) {}
×
1391
          }
×
1392
          else {
61✔
1393
            // Continue synchronous execution.
61✔
1394
            return true;
61✔
1395
          }
61✔
1396
        } else {
289✔
1397
          // Emit "complete" event.
68✔
1398
          eventProps.type = 'complete';
68✔
1399
          options.onComplete.call(benches, new Event(eventProps));
68✔
1400
        }
68✔
1401
        // When used as a listener `event.aborted = true` will cancel the rest of
228✔
1402
        // the "complete" listeners because they were already called above and when
228✔
1403
        // used as part of `getNext` the `return false` will exit the execution while-loop.
228✔
1404
        if (event) {
289✔
1405
          event.aborted = true;
198✔
1406
        } else {
289✔
1407
          return false;
30✔
1408
        }
30✔
1409
      }
289✔
1410

70✔
1411
      /**
70✔
1412
       * Checks if invoking `Benchmark#run` with asynchronous cycles.
70✔
1413
       */
70✔
1414
      function isAsync(object) {
70✔
1415
        // Avoid using `instanceof` here because of IE memory leak issues with host objects.
867✔
1416
        var async = args[0] && args[0].async;
867✔
1417
        return name == 'run' && (object instanceof Benchmark) &&
867✔
1418
          ((async == null ? object.options.async : async) && Support.timeout || object.defer);
867✔
1419
      }
867✔
1420

70✔
1421
      /**
70✔
1422
       * Raises `index` to the next defined index or returns `false`.
70✔
1423
       */
70✔
1424
      function raiseIndex() {
70✔
1425
        index++;
305✔
1426

305✔
1427
        // If queued remove the previous bench.
305✔
1428
        if (queued && index > 0) {
305✔
1429
          benches.shift();
207✔
1430
        }
207✔
1431
        // If we reached the last index then return `false`.
305✔
1432
        return (queued ? benches.length : index < result.length)
305✔
1433
          ? index
305✔
1434
          : (index = false);
305✔
1435
      }
305✔
1436
      // Juggle arguments.
70✔
1437
      if ((typeof name === 'string')) {
70✔
1438
        // 2 arguments (array, name).
4✔
1439
        args = Array.prototype.slice.call(arguments, 2);
4✔
1440
      } else {
70✔
1441
        // 2 arguments (array, options).
66✔
1442
        options = Object.assign(options, name);
66✔
1443
        name = options.name;
66✔
1444
        args = Array.isArray(args = 'args' in options ? options.args : []) ? args : [args];
66!
1445
        queued = options.queued;
66✔
1446
      }
66✔
1447
      // Start iterating over the array.
70✔
1448
      if (raiseIndex() !== false) {
70✔
1449
        // Emit "start" event.
70✔
1450

70✔
1451
        bench = (result instanceof Suite ? result.benchmarks : result)[index];
70!
1452
        eventProps.type = 'start';
70✔
1453
        eventProps.target = bench;
70✔
1454
        options.onStart.call(benches, new Event(eventProps));
70✔
1455

70✔
1456
        // End early if the suite was aborted in an "onStart" listener.
70✔
1457
        if (name == 'run' && (benches instanceof Suite) && benches.aborted) {
70✔
1458
          // Emit "cycle" event.
2✔
1459
          eventProps.type = 'cycle';
2✔
1460
          options.onCycle.call(benches.benchmarks, new Event(eventProps));
2✔
1461
          // Emit "complete" event.
2✔
1462
          eventProps.type = 'complete';
2✔
1463
          options.onComplete.call(benches, new Event(eventProps));
2✔
1464
        }
2✔
1465
        // Start method execution.
68✔
1466
        else {
68✔
1467
          if (isAsync(bench)) {
68✔
1468
            delay(bench, execute);
38✔
1469
          } else {
68✔
1470
            while (execute()) {}
30✔
1471
          }
30✔
1472
        }
68✔
1473
      }
70✔
1474
      return result;
70✔
1475
    }
70✔
1476

382✔
1477
    /**
382✔
1478
     * Creates a string of joined array values or object key-value pairs.
382✔
1479
     *
382✔
1480
     * @param {Array|Object} object The object to operate on.
382✔
1481
     * @param {string} [separator1=','] The separator used between key-value pairs.
382✔
1482
     * @param {string} [separator2=': '] The separator used between keys and values.
382✔
1483
     * @returns {string} The joined result.
382✔
1484
     */
382✔
1485
    static join(object, separator1, separator2) {
382✔
1486
      var result = [],
×
1487
          length = (object = Object(object)).length,
×
1488
          arrayLike = length === length >>> 0;
×
1489

×
1490
      separator2 || (separator2 = ': ');
×
1491

×
1492
      const entries = (
×
1493
        Array.isArray(object)
×
1494
          ? object.map((value, key) => [key, value])
×
1495
          : Object.entries(object).filter(([key]) => has(object, key) && (!arrayLike || key !== 'length'))
×
1496
      );
×
1497

×
1498
      entries.forEach(([key, value]) => {
×
1499
        result.push(arrayLike ? value : key + separator2 + value);
×
1500
      });
×
1501

×
1502
      return result.join(separator1 || ',');
×
1503
    }
×
1504

382✔
1505
    /**
382✔
1506
     * The Benchmark constructor.
382✔
1507
     *
382✔
1508
     * @param {string} name A name to identify the benchmark.
382✔
1509
     * @param {Function|string} fn The test to benchmark.
382✔
1510
     * @param {Object} [options={}] Options object.
382✔
1511
     * @example
382✔
1512
     *
382✔
1513
     * // basic usage (the `new` operator is optional)
382✔
1514
     * var bench = new Benchmark(fn);
382✔
1515
     *
382✔
1516
     * // or using a name first
382✔
1517
     * var bench = new Benchmark('foo', fn);
382✔
1518
     *
382✔
1519
     * // or with options
382✔
1520
     * var bench = new Benchmark('foo', fn, {
382✔
1521
     *
382✔
1522
     *   // displayed by `Benchmark#toString` if `name` is not available
382✔
1523
     *   'id': 'xyz',
382✔
1524
     *
382✔
1525
     *   // called when the benchmark starts running
382✔
1526
     *   'onStart': onStart,
382✔
1527
     *
382✔
1528
     *   // called after each run cycle
382✔
1529
     *   'onCycle': onCycle,
382✔
1530
     *
382✔
1531
     *   // called when aborted
382✔
1532
     *   'onAbort': onAbort,
382✔
1533
     *
382✔
1534
     *   // called when a test errors
382✔
1535
     *   'onError': onError,
382✔
1536
     *
382✔
1537
     *   // called when reset
382✔
1538
     *   'onReset': onReset,
382✔
1539
     *
382✔
1540
     *   // called when the benchmark completes running
382✔
1541
     *   'onComplete': onComplete,
382✔
1542
     *
382✔
1543
     *   // compiled/called before the test loop
382✔
1544
     *   'setup': setup,
382✔
1545
     *
382✔
1546
     *   // compiled/called after the test loop
382✔
1547
     *   'teardown': teardown
382✔
1548
     * });
382✔
1549
     *
382✔
1550
     * // or name and options
382✔
1551
     * var bench = new Benchmark('foo', {
382✔
1552
     *
382✔
1553
     *   // a flag to indicate the benchmark is deferred
382✔
1554
     *   'defer': true,
382✔
1555
     *
382✔
1556
     *   // benchmark test function
382✔
1557
     *   'fn': function(deferred) {
382✔
1558
     *     // call `Deferred#resolve` when the deferred test is finished
382✔
1559
     *     deferred.resolve();
382✔
1560
     *   }
382✔
1561
     * });
382✔
1562
     *
382✔
1563
     * // or options only
382✔
1564
     * var bench = new Benchmark({
382✔
1565
     *
382✔
1566
     *   // benchmark name
382✔
1567
     *   'name': 'foo',
382✔
1568
     *
382✔
1569
     *   // benchmark test as a string
382✔
1570
     *   'fn': '[1,2,3,4].sort()'
382✔
1571
     * });
382✔
1572
     *
382✔
1573
     * // a test's `this` binding is set to the benchmark instance
382✔
1574
     * var bench = new Benchmark('foo', function() {
382✔
1575
     *   'My name is '.concat(this.name); // "My name is foo"
382✔
1576
     * });
382✔
1577
     */
382✔
1578
    constructor(name, fn, options) {
382✔
1579
      super();
762✔
1580
      var bench = this;
762✔
1581

762✔
1582
      // Juggle arguments.
762✔
1583
      if (typeof name === 'object') {
762✔
1584
        // 1 argument (options).
305✔
1585
        options = name;
305✔
1586
      }
305✔
1587
      else if (typeof name === 'function') {
457✔
1588
        // 2 arguments (fn, options).
12✔
1589
        options = fn;
12✔
1590
        fn = name;
12✔
1591
      }
12✔
1592
      else if (typeof fn === 'object') {
445✔
1593
        // 2 arguments (name, options).
6✔
1594
        options = fn;
6✔
1595
        fn = null;
6✔
1596
        bench.name = name;
6✔
1597
      }
6✔
1598
      else {
439✔
1599
        // 3 arguments (name, fn [, options]).
439✔
1600
        bench.name = name;
439✔
1601
      }
439✔
1602
      this.setOptions(bench, options);
762✔
1603

762✔
1604
      bench.id || (bench.id = ++counter);
762✔
1605
      bench.fn == null && (bench.fn = fn);
762✔
1606

762✔
1607
      bench.stats = cloneDeep(bench.stats);
762✔
1608
      bench.times = cloneDeep(bench.times);
762✔
1609
    }
762✔
1610

382✔
1611
    /**
382✔
1612
     * Aborts the benchmark without recording times.
382✔
1613
     *
382✔
1614
     * @returns {Object} The benchmark instance.
382✔
1615
     */
382✔
1616
    abort() {
382✔
1617
      var event,
68✔
1618
          bench = this,
68✔
1619
          resetting = calledBy.reset;
68✔
1620

68✔
1621
      if (bench.running) {
68✔
1622
        event = new Event('abort');
48✔
1623
        bench.emit(event);
48✔
1624
        if (!event.cancelled || resetting) {
48!
1625
          // Avoid infinite recursion.
48✔
1626
          calledBy.abort = true;
48✔
1627
          bench.reset();
48✔
1628
          delete calledBy.abort;
48✔
1629

48✔
1630
          if (Support.timeout) {
48✔
1631
            clearTimeout(bench._timerId);
48✔
1632
            delete bench._timerId;
48✔
1633
          }
48✔
1634
          if (!resetting) {
48✔
1635
            bench.aborted = true;
48✔
1636
            bench.running = false;
48✔
1637
          }
48✔
1638
        }
48✔
1639
      }
48✔
1640
      return bench;
68✔
1641
    }
68✔
1642

382✔
1643
    /**
382✔
1644
     * Creates a new benchmark using the same test and options.
382✔
1645
     *
382✔
1646
     * @param {Object} options Options object to overwrite cloned options.
382✔
1647
     * @returns {Object} The new benchmark instance.
382✔
1648
     * @example
382✔
1649
     *
382✔
1650
     * var bizarro = bench.clone({
382✔
1651
     *   'name': 'doppelganger'
382✔
1652
     * });
382✔
1653
     */
382✔
1654
    clone(options) {
382✔
1655
      var bench = this,
265✔
1656
          result = new bench.constructor(Object.assign({}, bench, options));
265✔
1657

265✔
1658
      // Correct the `options` object.
265✔
1659
      result.options = Object.assign({}, cloneDeep(bench.options), cloneDeep(options));
265✔
1660

265✔
1661
      for (const property of Object.keys(Benchmark.defaultValues)) {
265✔
1662
        if (undefined === result[property]) {
3,180✔
1663
          result[property] = cloneDeep(bench[property]);
305✔
1664
        }
305✔
1665
      }
3,180✔
1666

265✔
1667
      // Copy own custom properties.
265✔
1668
      Object.entries(bench).forEach(([key, value]) => {
265✔
1669
        if (!has(result, key)) {
6,021✔
1670
          result[key] = cloneDeep(value);
2✔
1671
        }
2✔
1672
      });
265✔
1673

265✔
1674
      return result;
265✔
1675
    }
265✔
1676

382✔
1677
    /**
382✔
1678
     * Determines if a benchmark is faster than another.
382✔
1679
     *
382✔
1680
     * @param {Object} other The benchmark to compare.
382✔
1681
     * @returns {number} Returns `-1` if slower, `1` if faster, and `0` if indeterminate.
382✔
1682
     */
382✔
1683
    compare(other) {
382✔
1684
      var bench = this;
34✔
1685

34✔
1686
      // Exit early if comparing the same benchmark.
34✔
1687
      if (bench == other) {
34✔
1688
        return 0;
14✔
1689
      }
14✔
1690
      var critical,
20✔
1691
          zStat,
20✔
1692
          sample1 = bench.stats.sample,
20✔
1693
          sample2 = other.stats.sample,
20✔
1694
          size1 = sample1.length,
20✔
1695
          size2 = sample2.length,
20✔
1696
          maxSize = Math.max(size1, size2),
20✔
1697
          minSize = Math.min(size1, size2),
20✔
1698
          u1 = getU(sample1, sample2),
20✔
1699
          u2 = getU(sample2, sample1),
20✔
1700
          u = Math.min(u1, u2);
20✔
1701

20✔
1702
      function getScore(xA, sampleB) {
20✔
1703
        return sampleB.reduce((total, xB) => {
405✔
1704
          return total + (xB > xA ? 0 : xB < xA ? 1 : 0.5);
5,090!
1705
        }, 0);
405✔
1706
      }
405✔
1707

20✔
1708
      function getU(sampleA, sampleB) {
20✔
1709
        return sampleA.reduce((total, xA) => {
40✔
1710
          return total + getScore(xA, sampleB);
405✔
1711
        }, 0);
40✔
1712
      }
40✔
1713

20✔
1714
      function getZ(u) {
20✔
1715
        return (u - ((size1 * size2) / 2)) / Math.sqrt((size1 * size2 * (size1 + size2 + 1)) / 12);
8✔
1716
      }
8✔
1717
      // Reject the null hypothesis the two samples come from the
20✔
1718
      // same population (i.e. have the same median) if...
20✔
1719
      if (size1 + size2 > 30) {
34✔
1720
        // ...the z-stat is greater than 1.96 or less than -1.96
8✔
1721
        // http://www.statisticslectures.com/topics/mannwhitneyu/
8✔
1722
        zStat = getZ(u);
8✔
1723
        return Math.abs(zStat) > 1.96 ? (u == u1 ? 1 : -1) : 0;
8!
1724
      }
8✔
1725
      // ...the U value is less than or equal the critical U value.
12✔
1726
      critical = maxSize < 5 || minSize < 3 ? 0 : uTable[maxSize][minSize - 3];
34!
1727
      return u <= critical ? (u == u1 ? 1 : -1) : 0;
34!
1728
    }
34✔
1729

382✔
1730
    /**
382✔
1731
     * Reset properties and abort if running.
382✔
1732
     *
382✔
1733
     * @returns {Object} The benchmark instance.
382✔
1734
     */
382✔
1735
    reset() {
382✔
1736
      var bench = this;
361✔
1737
      if (bench.running && !calledBy.abort) {
361!
1738
        // No worries, `reset()` is called within `abort()`.
×
1739
        calledBy.reset = true;
×
1740
        bench.abort();
×
1741
        delete calledBy.reset;
×
1742
        return bench;
×
1743
      }
×
1744
      var event,
361✔
1745
          index = 0,
361✔
1746
          changes = [],
361✔
1747
          queue = [];
361✔
1748

361✔
1749
      const blank = new Benchmark();
361✔
1750

361✔
1751
      // A non-recursive solution to check if properties have changed.
361✔
1752
      // For more information see http://www.jslab.dk/articles/non.recursive.preorder.traversal.part4.
361✔
1753
      var data = {
361✔
1754
        'destination': bench,
361✔
1755
        'source': Object.assign(
361✔
1756
          {},
361✔
1757
          cloneDeep(bench.constructor.prototype),
361✔
1758
          cloneDeep(Benchmark.defaultValues),
361✔
1759
          cloneDeep(bench.options)
361✔
1760
        )
361✔
1761
      };
361✔
1762

361✔
1763
      do {
361✔
1764
        Object.entries(data.source).forEach(([key, value]) => {
1,444✔
1765
          var changed,
13,649✔
1766
              destination = data.destination,
13,649✔
1767
              currValue = destination[key];
13,649✔
1768

13,649✔
1769
          // Skip pseudo private properties and event listeners.
13,649✔
1770
          if (/^_|^events$|^on[A-Z]/.test(key)) {
13,649✔
1771
            return;
2,097✔
1772
          }
2,097✔
1773
          if ((value && typeof value == 'object')) {
13,649✔
1774
            if (Array.isArray(value)) {
1,083✔
1775
              // Check if an array value has changed to a non-array value.
361✔
1776
              if (!Array.isArray(currValue)) {
361!
1777
                changed = true;
×
1778
                currValue = [];
×
1779
              }
×
1780
              // Check if an array has changed its length.
361✔
1781
              if (currValue.length != value.length) {
361✔
1782
                changed = true;
215✔
1783
                currValue = currValue.slice(0, value.length);
215✔
1784
                currValue.length = value.length;
215✔
1785
              }
215✔
1786
            }
361✔
1787
            // Check if an object has changed to a non-object value.
722✔
1788
            else if (!(currValue && typeof currValue == 'object')) {
722!
1789
              changed = true;
×
1790
              currValue = {};
×
1791
            }
×
1792
            // Register a changed object.
1,083✔
1793
            if (changed) {
1,083✔
1794
              changes.push({ 'destination': destination, 'key': key, 'value': currValue });
215✔
1795
            }
215✔
1796
            queue.push({ 'destination': currValue, 'source': value });
1,083✔
1797
          }
1,083✔
1798
          // Register a changed primitive.
10,469✔
1799
          else if (
10,469✔
1800
            !(currValue === value) &&
10,469✔
1801
            value !== undefined
4,042✔
1802
          ) {
10,469✔
1803
            changes.push({ 'destination': destination, 'key': key, 'value': value });
2,979✔
1804
          }
2,979✔
1805
        });
1,444✔
1806
      }
1,444✔
1807
      while ((data = queue[index++]));
361✔
1808

361✔
1809
      // If changed emit the `reset` event and if it isn't cancelled reset the benchmark.
361✔
1810
      if (changes.length &&
361✔
1811
          (bench.emit(event = new Event('reset')), !event.cancelled)) {
361✔
1812
        changes.forEach((data) => {
319✔
1813
          data.destination[data.key] = data.value;
3,194✔
1814
        });
319✔
1815
      }
319✔
1816
      return bench;
361✔
1817
    }
361✔
1818

382✔
1819
    /**
382✔
1820
     * Displays relevant benchmark information when coerced to a string.
382✔
1821
     *
382✔
1822
     * @returns {string} A string representation of the benchmark instance.
382✔
1823
     */
382✔
1824
    toString() {
382✔
1825
      var bench = this,
19,271✔
1826
          error = bench.error,
19,271✔
1827
          hz = bench.hz,
19,271✔
1828
          id = bench.id,
19,271✔
1829
          stats = bench.stats,
19,271✔
1830
          size = stats.sample.length,
19,271✔
1831
          pm = '\xb1',
19,271✔
1832
          result = bench.name || (Number.isNaN(id) ? id : '<Test #' + id + '>');
19,271!
1833

19,271✔
1834
      if (error) {
19,271!
1835
        var errorStr;
×
1836
        if (!(error && (typeof error === 'object' || typeof error === 'function'))) {
×
1837
          errorStr = String(error);
×
1838
        } else if (!(error instanceof Error)) {
×
1839
          errorStr = Benchmark.join(error);
×
1840
        } else {
×
1841
          // Error#name and Error#message properties are non-enumerable.
×
1842
          errorStr = Benchmark.join(Object.assign({ 'name': error.name, 'message': error.message }, error));
×
1843
        }
×
1844
        result += ': ' + errorStr;
×
1845
      }
×
1846
      else {
19,271✔
1847
        result += ' x ' + Benchmark.formatNumber(hz.toFixed(hz < 100 ? 2 : 0)) + ' ops/sec ' + pm +
19,271!
1848
          stats.rme.toFixed(2) + '% (' + size + ' run' + (size == 1 ? '' : 's') + ' sampled)';
19,271!
1849
      }
19,271✔
1850
      return result;
19,271✔
1851
    }
19,271✔
1852

382✔
1853
    /**
382✔
1854
     * Runs the benchmark.
382✔
1855
     *
382✔
1856
     * @param {Object} [options={}] Options object.
382✔
1857
     * @returns {Object} The benchmark instance.
382✔
1858
     * @example
382✔
1859
     *
382✔
1860
     * // basic usage
382✔
1861
     * bench.run();
382✔
1862
     *
382✔
1863
     * // or with options
382✔
1864
     * bench.run({ 'async': true });
382✔
1865
     */
382✔
1866
    run(options) {
382✔
1867
      var bench = this,
311✔
1868
          event = new Event('start');
311✔
1869

311✔
1870
      const timer = options?.timer || Timer.timer;
311✔
1871

311✔
1872
      // Set `running` to `false` so `reset()` won't call `abort()`.
311✔
1873
      bench.running = false;
311✔
1874
      bench.reset();
311✔
1875
      bench.running = true;
311✔
1876

311✔
1877
      bench.count = bench.initCount;
311✔
1878
      bench.times.timeStamp = (+Date.now());
311✔
1879
      bench.emit(event);
311✔
1880

311✔
1881
      if (!event.cancelled) {
311✔
1882
        options = { 'async': ((options = options && options.async) == null ? bench.async : options) && Support.timeout };
311✔
1883

311✔
1884
        options.timer = timer;
311✔
1885

311✔
1886
        // For clones created within `compute()`.
311✔
1887
        if (bench._original) {
311✔
1888
          if (bench.defer) {
259✔
1889
            new Deferred(bench, timer);
48✔
1890
          } else {
259✔
1891
            cycle(bench, options);
211✔
1892
          }
211✔
1893
        }
259✔
1894
        // For original benchmarks.
52✔
1895
        else {
52✔
1896
          compute(bench, options);
52✔
1897
        }
52✔
1898
      }
311✔
1899
      return bench;
311✔
1900
    }
311✔
1901
  }
382✔
1902

2✔
1903
  class Deferred {
2✔
1904
    /**
24✔
1905
     * The Timer instance.
24✔
1906
     *
24✔
1907
     * @type {Timer}
24✔
1908
     */
24✔
1909
    #timer;
24✔
1910

24✔
1911
    /**
24✔
1912
     * The deferred benchmark instance.
24✔
1913
     *
24✔
1914
     * @type {Object}
24✔
1915
     */
24✔
1916
    benchmark = null;
24✔
1917

24✔
1918
    /**
24✔
1919
     * The number of deferred cycles performed while benchmarking.
24✔
1920
     *
24✔
1921
     * @type {number}
24✔
1922
     */
24✔
1923
    cycles = 0;
24✔
1924

24✔
1925
    /**
24✔
1926
     * The time taken to complete the deferred benchmark (secs).
24✔
1927
     *
24✔
1928
     * @type {number}
24✔
1929
     */
24✔
1930
    elapsed = 0;
24✔
1931

24✔
1932
    /**
24✔
1933
     * A timestamp of when the deferred benchmark started (ms).
24✔
1934
     *
24✔
1935
     * @type {number}
24✔
1936
     */
24✔
1937
    timeStamp = 0;
24✔
1938

24✔
1939
    /**
24✔
1940
     * The Deferred constructor.
24✔
1941
     *
24✔
1942
     * @memberOf Benchmark
24✔
1943
     * @param {Benchmark} clone The cloned benchmark instance.
24✔
1944
     * @param {Timer} timer The timer instance.
24✔
1945
     */
24✔
1946
    constructor(clone, timer) {
24✔
1947
      this.benchmark = clone;
48✔
1948
      this.#timer = timer;
48✔
1949
      clock(this, timer);
48✔
1950
    }
48✔
1951

24✔
1952
    /**
24✔
1953
     * Handles cycling/completing the deferred benchmark.
24✔
1954
     */
24✔
1955
    resolve() {
24✔
1956
      var deferred = this,
250✔
1957
          clone = deferred.benchmark,
250✔
1958
          bench = clone._original;
250✔
1959

250✔
1960
      if (bench.aborted) {
250!
1961
        // cycle() -> clone cycle/complete event -> compute()'s invoked bench.run() cycle/complete.
×
1962
        deferred.teardown();
×
1963
        clone.running = false;
×
1964
        cycle(deferred, {timer: this.#timer});
×
1965
      }
×
1966
      else if (++deferred.cycles < clone.count) {
250✔
1967
        clone.compiled.call(deferred, globalThis, this.#timer);
198✔
1968
      }
198✔
1969
      else {
52✔
1970
        this.#timer.stop(deferred);
52✔
1971
        deferred.teardown();
52✔
1972
        delay(clone, () => { cycle(deferred, {timer: this.#timer}); });
52✔
1973
      }
52✔
1974
    }
250✔
1975
  }
24✔
1976

2✔
1977
  class Event {
2✔
1978
    /**
1,057✔
1979
     * A flag to indicate if the emitters listener iteration is aborted.
1,057✔
1980
     *
1,057✔
1981
     * @type boolean
1,057✔
1982
     */
1,057✔
1983
    aborted = false;
1,057✔
1984

1,033✔
1985
    /**
1,033✔
1986
     * A flag to indicate if the default action is cancelled.
1,033✔
1987
     *
1,033✔
1988
     * @type boolean
1,033✔
1989
     */
1,033✔
1990
    cancelled = false;
1,033✔
1991

1,033✔
1992
    /**
1,033✔
1993
     * The object whose listeners are currently being processed.
1,033✔
1994
     *
1,033✔
1995
     * @type Object
1,033✔
1996
     */
1,033✔
1997
    currentTarget = undefined;
1,033✔
1998

1,033✔
1999
    /**
1,033✔
2000
     * The return value of the last executed listener.
1,033✔
2001
     *
1,033✔
2002
     * @type Mixed
1,033✔
2003
     */
1,033✔
2004
    result = undefined;
1,033✔
2005

1,033✔
2006
    /**
1,033✔
2007
     * The object to which the event was originally emitted.
1,033✔
2008
     *
1,033✔
2009
     * @type Object
1,033✔
2010
     */
1,033✔
2011
    target = undefined;
1,033✔
2012

1,033✔
2013
    /**
1,033✔
2014
     * A timestamp of when the event was created (ms).
1,033✔
2015
     *
1,033✔
2016
     * @type number
1,033✔
2017
     */
1,033✔
2018
    timeStamp = 0;
1,033✔
2019

1,033✔
2020
    /**
1,033✔
2021
     * The event type.
1,033✔
2022
     *
1,033✔
2023
     * @type string
1,033✔
2024
     */
1,033✔
2025
    type;
1,057✔
2026

1,057✔
2027
    /**
1,057✔
2028
     * The Event constructor.
1,057✔
2029
     *
1,057✔
2030
     * @memberOf Benchmark
1,057✔
2031
     * @param {Object|string} type The event type.
1,057✔
2032
     */
1,057✔
2033
    constructor(type) {
1,057✔
2034
      Object.assign(this, {
2,090✔
2035
          timeStamp: +Date.now(),
2,090✔
2036
          ...(
2,090✔
2037
            typeof type === 'string'
2,090✔
2038
              ? {type}
2,090✔
2039
              : type
2,090✔
2040
          ),
2,090✔
2041
      });
2,090✔
2042
    }
2,090✔
2043
  }
1,057✔
2044

2✔
2045
  class Suite extends EventTarget {
2✔
2046
    /**
38✔
2047
     * The default options copied by suite instances.
38✔
2048
     *
38✔
2049
     * @type {Object}
38✔
2050
     */
38✔
2051
    static options = {
38✔
2052

2✔
2053
      /**
2✔
2054
       * The name of the suite.
2✔
2055
       *
2✔
2056
       * @type {string|string}
2✔
2057
       */
2✔
2058
      'name': undefined
2✔
2059
    }
2✔
2060

38✔
2061
    /**
38✔
2062
     * A flag to indicate if the suite is aborted.
38✔
2063
     *
38✔
2064
     * @type {boolean}
38✔
2065
     */
38✔
2066
    aborted = false;
38✔
2067

38✔
2068
    /**
38✔
2069
     * A flag to indicate if the suite is running.
38✔
2070
     *
38✔
2071
     * @type {boolean}
38✔
2072
     */
38✔
2073
    running = false;
38✔
2074

38✔
2075
    /**
38✔
2076
     * The Suite constructor.
38✔
2077
     *
38✔
2078
     * @memberOf Benchmark
38✔
2079
     * @param {string} name A name to identify the suite.
38✔
2080
     * @param {Object} [options={}] Options object.
38✔
2081
     * @example
38✔
2082
     *
38✔
2083
     * // basic usage (the `new` operator is optional)
38✔
2084
     * var suite = new Benchmark.Suite;
38✔
2085
     *
38✔
2086
     * // or using a name first
38✔
2087
     * var suite = new Benchmark.Suite('foo');
38✔
2088
     *
38✔
2089
     * // or with options
38✔
2090
     * var suite = new Benchmark.Suite('foo', {
38✔
2091
     *
38✔
2092
     *   // called when the suite starts running
38✔
2093
     *   'onStart': onStart,
38✔
2094
     *
38✔
2095
     *   // called between running benchmarks
38✔
2096
     *   'onCycle': onCycle,
38✔
2097
     *
38✔
2098
     *   // called when aborted
38✔
2099
     *   'onAbort': onAbort,
38✔
2100
     *
38✔
2101
     *   // called when a test errors
38✔
2102
     *   'onError': onError,
38✔
2103
     *
38✔
2104
     *   // called when reset
38✔
2105
     *   'onReset': onReset,
38✔
2106
     *
38✔
2107
     *   // called when the suite completes running
38✔
2108
     *   'onComplete': onComplete
38✔
2109
     * });
38✔
2110
     */
38✔
2111
    constructor(name, options) {
38✔
2112
      super();
76✔
2113
      var suite = this;
76✔
2114

76✔
2115
      this._benchmarks = [];
76✔
2116
      // Juggle arguments.
76✔
2117
      if (typeof name === 'object') {
76✔
2118
        // 1 argument (options).
10✔
2119
        options = name;
10✔
2120
      } else {
76✔
2121
        // 2 arguments (name [, options]).
66✔
2122
        suite.name = name;
66✔
2123
      }
66✔
2124
      this.setOptions(suite, options);
76✔
2125

76✔
2126
      this.reverse = () => {
76✔
2127
        this._benchmarks.reverse();
2✔
2128

2✔
2129
        return this;
2✔
2130
      }
2✔
2131

76✔
2132
      this.shift = () => {
76✔
2133
        return this._benchmarks.shift();
6✔
2134
      }
6✔
2135
    }
76✔
2136

38✔
2137
    get benchmarks() {
38✔
2138
      return [...this._benchmarks];
40✔
2139
    }
40✔
2140

38✔
2141
    /**
38✔
2142
     * The number of benchmarks in the suite.
38✔
2143
     *
38✔
2144
     * @type {number}
38✔
2145
     */
38✔
2146
    get length() {
38✔
2147
      return this._benchmarks.length;
10✔
2148
    }
10✔
2149

38✔
2150
    /**
38✔
2151
     * Sets the length of the benchmarks array for the Suite instance.
38✔
2152
     *
38✔
2153
     * Useful for truncating the array.
38✔
2154
     */
38✔
2155
    set length(value) {
38✔
2156
      if (undefined === this._benchmarks) {
2!
2157
        this._benchmarks = [];
×
2158
      }
×
2159

2✔
2160
      this._benchmarks.length = value;
2✔
2161
    }
2✔
2162

38✔
2163
    /**
38✔
2164
     * Aborts all benchmarks in the suite.
38✔
2165
     *
38✔
2166
     * @returns {Object} The suite instance.
38✔
2167
     */
38✔
2168
    abort() {
38✔
2169
      var event,
8✔
2170
          suite = this,
8✔
2171
          resetting = calledBy.resetSuite;
8✔
2172

8✔
2173
      if (suite.running) {
8✔
2174
        event = new Event('abort');
6✔
2175
        suite.emit(event);
6✔
2176
        if (!event.cancelled || resetting) {
6!
2177
          // Avoid infinite recursion.
6✔
2178
          calledBy.abortSuite = true;
6✔
2179
          suite.reset();
6✔
2180
          delete calledBy.abortSuite;
6✔
2181

6✔
2182
          if (!resetting) {
6✔
2183
            suite.aborted = true;
4✔
2184
            Benchmark.invoke(suite, 'abort');
4✔
2185
          }
4✔
2186
        }
6✔
2187
      }
6✔
2188
      return suite;
8✔
2189
    }
8✔
2190

38✔
2191
    /**
38✔
2192
     * Adds a test to the benchmark suite.
38✔
2193
     *
38✔
2194
     * @param {string} name A name to identify the benchmark.
38✔
2195
     * @param {Function|string} fn The test to benchmark.
38✔
2196
     * @param {Object} [options={}] Options object.
38✔
2197
     * @returns {Object} The suite instance.
38✔
2198
     * @example
38✔
2199
     *
38✔
2200
     * // basic usage
38✔
2201
     * suite.add(fn);
38✔
2202
     *
38✔
2203
     * // or using a name first
38✔
2204
     * suite.add('foo', fn);
38✔
2205
     *
38✔
2206
     * // or with options
38✔
2207
     * suite.add('foo', fn, {
38✔
2208
     *   'onCycle': onCycle,
38✔
2209
     *   'onComplete': onComplete
38✔
2210
     * });
38✔
2211
     *
38✔
2212
     * // or name and options
38✔
2213
     * suite.add('foo', {
38✔
2214
     *   'fn': fn,
38✔
2215
     *   'onCycle': onCycle,
38✔
2216
     *   'onComplete': onComplete
38✔
2217
     * });
38✔
2218
     *
38✔
2219
     * // or options only
38✔
2220
     * suite.add({
38✔
2221
     *   'name': 'foo',
38✔
2222
     *   'fn': fn,
38✔
2223
     *   'onCycle': onCycle,
38✔
2224
     *   'onComplete': onComplete
38✔
2225
     * });
38✔
2226
     */
38✔
2227
    add(name, fn, options) {
38✔
2228
      var suite = this,
32✔
2229
          bench = new Benchmark(name, fn, options),
32✔
2230
          event = new Event({ 'type': 'add', 'target': bench });
32✔
2231

32✔
2232
      if (suite.emit(event), !event.cancelled) {
32✔
2233
        this._benchmarks.push(bench);
32✔
2234
      }
32✔
2235
      return suite;
32✔
2236
    }
32✔
2237

38✔
2238
    /**
38✔
2239
     * Creates a new suite with cloned benchmarks.
38✔
2240
     *
38✔
2241
     * @param {Object} options Options object to overwrite cloned options.
38✔
2242
     * @returns {Object} The new suite instance.
38✔
2243
     */
38✔
2244
    clone(options) {
38✔
2245
      var suite = this,
×
2246
          result = new suite.constructor(Object.assign({}, suite.options, options));
×
2247

×
2248
      // Copy own properties.
×
2249
      Object.entries(suite).forEach(([key, value]) => {
×
2250
        if (!has(result, key)) {
×
2251
          result[key] = (typeof value?.clone === 'function')
×
2252
            ? value.clone()
×
2253
            : cloneDeep(value);
×
2254
        }
×
2255
      });
×
2256
      return result;
×
2257
    }
×
2258

38✔
2259
    /**
38✔
2260
     * An `Array#filter` like method.
38✔
2261
     *
38✔
2262
     * @param {Function|string} callback The function/alias called per iteration.
38✔
2263
     * @returns {Object} A new suite of benchmarks that passed callback filter.
38✔
2264
     */
38✔
2265
    filter(callback) {
38✔
2266
      var suite = this,
6✔
2267
          result = new suite.constructor(suite.options);
6✔
2268

6✔
2269
      const cb = Benchmark.filter(this, callback);
6✔
2270

6✔
2271
      result._benchmarks.push(...cb);
6✔
2272

6✔
2273
      return result;
6✔
2274
    }
6✔
2275

38✔
2276
    /**
38✔
2277
     * Resets all benchmarks in the suite.
38✔
2278
     *
38✔
2279
     * @returns {Object} The suite instance.
38✔
2280
     */
38✔
2281
    reset() {
38✔
2282
      var event,
24✔
2283
          suite = this,
24✔
2284
          aborting = calledBy.abortSuite;
24✔
2285

24✔
2286
      if (suite.running && !aborting) {
24✔
2287
        // No worries, `resetSuite()` is called within `abortSuite()`.
2✔
2288
        calledBy.resetSuite = true;
2✔
2289
        suite.abort();
2✔
2290
        delete calledBy.resetSuite;
2✔
2291
      }
2✔
2292
      // Reset if the state has changed.
22✔
2293
      else if ((suite.aborted || suite.running) &&
22✔
2294
          (suite.emit(event = new Event('reset')), !event.cancelled)) {
22✔
2295
        suite.aborted = suite.running = false;
6✔
2296
        if (!aborting) {
6!
2297
          Benchmark.invoke(suite, 'reset');
×
2298
        }
×
2299
      }
6✔
2300
      return suite;
24✔
2301
    }
24✔
2302

38✔
2303
    /**
38✔
2304
     * Runs the suite.
38✔
2305
     *
38✔
2306
     * @param {Object} [options={}] Options object.
38✔
2307
     * @returns {Object} The suite instance.
38✔
2308
     * @example
38✔
2309
     *
38✔
2310
     * // basic usage
38✔
2311
     * suite.run();
38✔
2312
     *
38✔
2313
     * // or with options
38✔
2314
     * suite.run({ 'async': true, 'queued': true });
38✔
2315
     */
38✔
2316
    run(options) {
38✔
2317
      var suite = this;
14✔
2318

14✔
2319
      suite.reset();
14✔
2320
      suite.running = true;
14✔
2321
      options || (options = {});
14✔
2322
      options.timer = options?.timer || Timer.timer;
14✔
2323

14✔
2324
      Benchmark.invoke(suite, {
14✔
2325
        'name': 'run',
14✔
2326
        'args': options,
14✔
2327
        'queued': options.queued,
14✔
2328
        'onStart': function(event) {
14✔
2329
          suite.emit(event);
14✔
2330
        },
14✔
2331
        'onCycle': function(event) {
14✔
2332
          var bench = event.target;
26✔
2333
          if (bench.error) {
26✔
2334
            suite.emit(new Event({ 'type': 'error', 'target': bench }));
8✔
2335
          }
8✔
2336
          suite.emit(event);
26✔
2337
          event.aborted = suite.aborted;
26✔
2338
        },
14✔
2339
        'onComplete': function(event) {
14✔
2340
          suite.running = false;
14✔
2341
          suite.emit(event);
14✔
2342
        }
14✔
2343
      });
14✔
2344
      return suite;
14✔
2345
    }
14✔
2346
  }
38✔
2347

2✔
2348
  /*------------------------------------------------------------------------*/
2✔
2349

2✔
2350
  const templateData = {};
2✔
2351

2✔
2352
  /**
2✔
2353
   * Clocks the time taken to execute a test per cycle (secs).
2✔
2354
   *
2✔
2355
   * @private
2✔
2356
   * @param {Object} clone The benchmark instance.
2✔
2357
   * @returns {number} The time taken.
2✔
2358
   */
2✔
2359
  function clock(clone, timer) {
2✔
2360
    // Lazy define for hi-res timers.
2✔
2361
    clock = function(clone, timer) {
2✔
2362
      var deferred;
348✔
2363

348✔
2364
      if (clone instanceof Deferred) {
348✔
2365
        deferred = clone;
48✔
2366
        clone = deferred.benchmark;
48✔
2367
      }
48✔
2368
      var bench = clone._original,
348✔
2369
          stringable = isStringable(bench.fn),
348✔
2370
          count = bench.count = clone.count,
348✔
2371
          decompilable = stringable || (Support.decompilation && (clone.setup !== noop || clone.teardown !== noop)),
348✔
2372
          id = bench.id,
348✔
2373
          name = bench.name || (typeof id == 'number' ? '<Test #' + id + '>' : id),
348!
2374
          result = 0;
348✔
2375

348✔
2376
      // Init `minTime` if needed.
348✔
2377
      clone.minTime = bench.minTime || (bench.minTime = bench.options.minTime = Benchmark.options.minTime);
348✔
2378

348✔
2379
      // Compile in setup/teardown functions and the test loop.
348✔
2380
      // Create a new compiled test, instead of using the cached `bench.compiled`,
348✔
2381
      // to avoid potential engine optimizations enabled over the life of the test.
348✔
2382
      var funcBody = deferred
348✔
2383
        ? 'var d#=this,${fnArg}=d#,m#=d#.benchmark._original,f#=m#.fn,su#=m#.setup,td#=m#.teardown;' +
348✔
2384
          // When `deferred.cycles` is `0` then...
48✔
2385
          'if(!d#.cycles){' +
48✔
2386
          // set `deferred.fn`,
48✔
2387
          'd#.fn=function(){var ${fnArg}=d#;if(typeof f#=="function"){try{${fn}\n}catch(e#){f#(d#)}}else{${fn}\n}};' +
48✔
2388
          // set `deferred.teardown`,
48✔
2389
          'd#.teardown=function(){d#.cycles=0;if(typeof td#=="function"){try{${teardown}\n}catch(e#){td#()}}else{${teardown}\n}};' +
48✔
2390
          // execute the benchmark's `setup`,
48✔
2391
          'if(typeof su#=="function"){try{${setup}\n}catch(e#){su#()}}else{${setup}\n};' +
48✔
2392
          // start timer,
48✔
2393
          't#.start(d#);' +
48✔
2394
          // and then execute `deferred.fn` and return a dummy object.
48✔
2395
          '}d#.fn();return{uid:"${uid}"}'
48✔
2396

348✔
2397
        : 'var r#,s#,m#=this,f#=m#.fn,i#=m#.count,n#=t#.ns;${setup}\n${begin};' +
348✔
2398
          'while(i#--){${fn}\n}${end};${teardown}\nreturn{elapsed:r#,uid:"${uid}"}';
348✔
2399

348✔
2400
      var compiled = bench.compiled = clone.compiled = createCompiled(bench, decompilable, deferred, funcBody),
348✔
2401
          isEmpty = !(templateData.fn || stringable);
348✔
2402

348✔
2403
      try {
348✔
2404
        if (isEmpty) {
348!
2405
          // Firefox may remove dead code from `Function#toString` results.
×
2406
          // For more information see http://bugzil.la/536085.
×
2407
          throw new Error('The test "' + name + '" is empty. This may be the result of dead code removal.');
×
2408
        }
×
2409
        else if (!deferred) {
348✔
2410
          // Pretest to determine if compiled code exits early, usually by a
300✔
2411
          // rogue `return` statement, by checking for a return object with the uid.
300✔
2412
          bench.count = 1;
300✔
2413
          compiled = decompilable && (compiled.call(bench, globalThis, timer) || {}).uid == templateData.uid && compiled;
300✔
2414
          bench.count = count;
300✔
2415
        }
300✔
2416
      } catch(e) {
348✔
2417
        compiled = null;
10✔
2418
        clone.error = e || new Error(String(e));
10!
2419
        bench.count = count;
10✔
2420
      }
10✔
2421
      // Fallback when a test exits early or errors during pretest.
348✔
2422
      if (!compiled && !deferred && !isEmpty) {
348✔
2423
        funcBody = (
267✔
2424
          stringable || (decompilable && !clone.error)
267✔
2425
            ? 'function f#(){${fn}\n}var r#,s#,m#=this,i#=m#.count'
267✔
2426
            : 'var r#,s#,m#=this,f#=m#.fn,i#=m#.count'
267✔
2427
          ) +
267✔
2428
          ',n#=t#.ns;${setup}\n${begin};m#.f#=f#;while(i#--){m#.f#()}${end};' +
267✔
2429
          'delete m#.f#;${teardown}\nreturn{elapsed:r#}';
267✔
2430

267✔
2431
        compiled = createCompiled(bench, decompilable, deferred, funcBody);
267✔
2432

267✔
2433
        try {
267✔
2434
          // Pretest one more time to check for errors.
267✔
2435
          bench.count = 1;
267✔
2436
          compiled.call(bench, globalThis, timer);
267✔
2437
          bench.count = count;
267✔
2438
          delete clone.error;
267✔
2439
        }
267✔
2440
        catch(e) {
267✔
2441
          bench.count = count;
16✔
2442
          if (!clone.error) {
16✔
2443
            clone.error = e || new Error(String(e));
6✔
2444
          }
6✔
2445
        }
16✔
2446
      }
267✔
2447
      // If no errors run the full test loop.
348✔
2448
      if (!clone.error) {
348✔
2449
        compiled = bench.compiled = clone.compiled = createCompiled(bench, decompilable, deferred, funcBody);
332✔
2450
        result = compiled.call(deferred || bench, globalThis, timer).elapsed;
332✔
2451
      }
332✔
2452
      return result;
348✔
2453
    };
2✔
2454

2✔
2455
    /*----------------------------------------------------------------------*/
2✔
2456

2✔
2457
    /**
2✔
2458
     * Creates a compiled function from the given function `body`.
2✔
2459
     */
2✔
2460
    function createCompiled(bench, decompilable, deferred, body) {
2✔
2461
      var fn = bench.fn,
947✔
2462
          fnArg = deferred ? getFirstArgument(fn) || 'deferred' : '';
947✔
2463

947✔
2464
      templateData.uid = uid + uidCounter++;
947✔
2465

947✔
2466
      Object.assign(templateData, {
947✔
2467
        'setup': decompilable ? getSource(bench.setup) : interpolate('m#.setup()'),
947✔
2468
        'fn': decompilable ? getSource(fn) : interpolate('m#.fn(' + fnArg + ')'),
947✔
2469
        'fnArg': fnArg,
947✔
2470
        'teardown': decompilable ? getSource(bench.teardown) : interpolate('m#.teardown()')
947✔
2471
      });
947✔
2472

947✔
2473
      // Use API of chosen timer.
947✔
2474
      if (timer.unit == 'ns') {
947✔
2475
        Object.assign(templateData, {
498✔
2476
          'begin': interpolate('s#=n#()'),
498✔
2477
          'end': interpolate('r#=n#(s#);r#=r#[0]+(r#[1]/1e9)')
498✔
2478
        });
498✔
2479
      }
498✔
2480
      else if (timer.unit == 'us') {
449!
2481
        if (timer.ns.stop) {
×
2482
          Object.assign(templateData, {
×
2483
            'begin': interpolate('s#=n#.start()'),
×
2484
            'end': interpolate('r#=n#.microseconds()/1e6')
×
2485
          });
×
2486
        } else {
×
2487
          Object.assign(templateData, {
×
2488
            'begin': interpolate('s#=n#()'),
×
2489
            'end': interpolate('r#=(n#()-s#)/1e6')
×
2490
          });
×
2491
        }
×
2492
      }
×
2493
      else if (timer.ns.now) {
449✔
2494
        Object.assign(templateData, {
449✔
2495
          'begin': interpolate('s#=(+n#.now())'),
449✔
2496
          'end': interpolate('r#=((+n#.now())-s#)/1e3')
449✔
2497
        });
449✔
2498
      }
449✔
2499
      else {
×
2500
        Object.assign(templateData, {
×
2501
          'begin': interpolate('s#=new n#().getTime()'),
×
2502
          'end': interpolate('r#=(new n#().getTime()-s#)/1e3')
×
2503
        });
×
2504
      }
×
2505

947✔
2506
      // Create compiled test.
947✔
2507
      return createFunction(
947✔
2508
        interpolate('window,t#'),
947✔
2509
        'var global = window, clearTimeout = global.clearTimeout, setTimeout = global.setTimeout;\n' +
947✔
2510
        interpolate(body)
947✔
2511
      );
947✔
2512
    }
947✔
2513

2✔
2514
    /*----------------------------------------------------------------------*/
2✔
2515

2✔
2516
    // Resolve time span required to achieve a percent uncertainty of at most 1%.
2✔
2517
    // For more information see http://spiff.rit.edu/classes/phys273/uncert/uncert.html.
2✔
2518
    Benchmark.options.minTime || (Benchmark.options.minTime = Math.max(timer.res / 2 / 0.01, 0.05));
2✔
2519
    return clock.apply(null, [clone, timer]);
2✔
2520
  }
2✔
2521

2✔
2522
  /**
2✔
2523
   * Interpolates a given template string.
2✔
2524
   */
2✔
2525
  function interpolate(string) {
2✔
2526
    function tagged(_, string) {
6,115✔
2527
      let result = string;
6,115✔
2528

6,115✔
2529
      for (const [key, value] of Object.entries(templateData)) {
6,115✔
2530
        result = result.replaceAll(`\${${key}}`, value);
42,761✔
2531
      }
42,761✔
2532

6,115✔
2533
      return result;
6,115✔
2534
    }
6,115✔
2535

6,115✔
2536
    // Replaces all occurrences of `#` with a unique number and template tokens with content.
6,115✔
2537
    return tagged`${string.replace(/\#/g, /\d+/.exec(templateData.uid))}`;
6,115✔
2538
  }
6,115✔
2539

2✔
2540
  /*------------------------------------------------------------------------*/
2✔
2541

2✔
2542
  /**
2✔
2543
   * Computes stats on benchmark results.
2✔
2544
   *
2✔
2545
   * @private
2✔
2546
   * @param {Object} bench The benchmark instance.
2✔
2547
   * @param {Object} options The options object.
2✔
2548
   */
2✔
2549
  function compute(bench, options) {
2✔
2550
    const {timer} = options;
52✔
2551

52✔
2552
    var async = options.async,
52✔
2553
        elapsed = 0,
52✔
2554
        initCount = bench.initCount,
52✔
2555
        minSamples = bench.minSamples,
52✔
2556
        queue = [],
52✔
2557
        sample = bench.stats.sample;
52✔
2558

52✔
2559
    /**
52✔
2560
     * Adds a clone to the queue.
52✔
2561
     */
52✔
2562
    function enqueue() {
52✔
2563
      queue.push(Object.assign(bench.clone(), {
259✔
2564
        '_original': bench,
259✔
2565
        'events': {
259✔
2566
          'abort': [update],
259✔
2567
          'cycle': [update],
259✔
2568
          'error': [update],
259✔
2569
          'start': [update]
259✔
2570
        }
259✔
2571
      }));
259✔
2572
    }
259✔
2573

52✔
2574
    /**
52✔
2575
     * Updates the clone/original benchmarks to keep their data in sync.
52✔
2576
     */
52✔
2577
    function update(event) {
52✔
2578
      var clone = this,
643✔
2579
          type = event.type;
643✔
2580

643✔
2581
      if (bench.running) {
643✔
2582
        if (type == 'start') {
619✔
2583
          // Note: `clone.minTime` prop is inited in `clock()`.
259✔
2584
          clone.count = bench.initCount;
259✔
2585
        }
259✔
2586
        else {
360✔
2587
          if (type == 'error') {
360✔
2588
            bench.error = clone.error;
16✔
2589
          }
16✔
2590
          if (type == 'abort') {
360✔
2591
            bench.abort();
16✔
2592
            bench.emit(new Event('cycle'));
16✔
2593
          } else {
360✔
2594
            event.currentTarget = event.target = bench;
344✔
2595
            bench.emit(event);
344✔
2596
          }
344✔
2597
        }
360✔
2598
      } else if (bench.aborted) {
643✔
2599
        // Clear abort listeners to avoid triggering bench's abort/cycle again.
24✔
2600
        clone.events.abort.length = 0;
24✔
2601
        clone.abort();
24✔
2602
      }
24✔
2603
    }
643✔
2604

52✔
2605
    /**
52✔
2606
     * Determines if more clones should be queued or if cycling should stop.
52✔
2607
     */
52✔
2608
    function evaluate(event) {
52✔
2609
      var critical,
259✔
2610
          df,
259✔
2611
          mean,
259✔
2612
          moe,
259✔
2613
          rme,
259✔
2614
          sd,
259✔
2615
          sem,
259✔
2616
          variance,
259✔
2617
          clone = event.target,
259✔
2618
          done = bench.aborted,
259✔
2619
          now = (+Date.now()),
259✔
2620
          size = sample.push(clone.times.period),
259✔
2621
          maxedOut = size >= minSamples && (elapsed += now - clone.times.timeStamp) / 1e3 > bench.maxTime,
259✔
2622
          times = bench.times,
259✔
2623
          varOf = function(sum, x) { return sum + Math.pow(x - mean, 2); };
259✔
2624

259✔
2625
      // Exit early for aborted or unclockable tests.
259✔
2626
      if (done || clone.hz == Infinity) {
259✔
2627
        maxedOut = !(size = sample.length = queue.length = 0);
24✔
2628
      }
24✔
2629

259✔
2630
      if (!done) {
259✔
2631
        // Compute the sample mean (estimate of the population mean).
235✔
2632
        mean = getMean(sample);
235✔
2633
        // Compute the sample variance (estimate of the population variance).
235✔
2634
        variance = sample.reduce(varOf, 0) / (size - 1) || 0;
235✔
2635
        // Compute the sample standard deviation (estimate of the population standard deviation).
235✔
2636
        sd = Math.sqrt(variance);
235✔
2637
        // Compute the standard error of the mean (a.k.a. the standard deviation of the sampling distribution of the sample mean).
235✔
2638
        sem = sd / Math.sqrt(size);
235✔
2639
        // Compute the degrees of freedom.
235✔
2640
        df = size - 1;
235✔
2641
        // Compute the critical value.
235✔
2642
        critical = tTable[Math.round(df) || 1] || tTable.infinity;
235!
2643
        // Compute the margin of error.
235✔
2644
        moe = sem * critical;
235✔
2645
        // Compute the relative margin of error.
235✔
2646
        rme = (moe / mean) * 100 || 0;
235✔
2647

235✔
2648
        Object.assign(bench.stats, {
235✔
2649
          'deviation': sd,
235✔
2650
          'mean': mean,
235✔
2651
          'moe': moe,
235✔
2652
          'rme': rme,
235✔
2653
          'sem': sem,
235✔
2654
          'variance': variance
235✔
2655
        });
235✔
2656

235✔
2657
        // Abort the cycle loop when the minimum sample size has been collected
235✔
2658
        // and the elapsed time exceeds the maximum time allowed per benchmark.
235✔
2659
        // We don't count cycle delays toward the max time because delays may be
235✔
2660
        // increased by browsers that clamp timeouts for inactive tabs. For more
235✔
2661
        // information see https://developer.mozilla.org/en/window.setTimeout#Inactive_tabs.
235✔
2662
        if (maxedOut) {
235✔
2663
          // Reset the `initCount` in case the benchmark is rerun.
28✔
2664
          bench.initCount = initCount;
28✔
2665
          bench.running = false;
28✔
2666
          done = true;
28✔
2667
          times.elapsed = (now - times.timeStamp) / 1e3;
28✔
2668
        }
28✔
2669
        if (bench.hz != Infinity) {
235✔
2670
          bench.hz = 1 / mean;
235✔
2671
          times.cycle = mean * bench.count;
235✔
2672
          times.period = mean;
235✔
2673
        }
235✔
2674
      }
235✔
2675
      // If time permits, increase sample size to reduce the margin of error.
259✔
2676
      if (queue.length < 2 && !maxedOut) {
259✔
2677
        enqueue();
207✔
2678
      }
207✔
2679
      // Abort the `invoke` cycle when done.
259✔
2680
      event.aborted = done;
259✔
2681
    }
259✔
2682

52✔
2683
    // Init queue and begin.
52✔
2684
    enqueue();
52✔
2685
    Benchmark.invoke(queue, {
52✔
2686
      'name': 'run',
52✔
2687
      'args': { async, timer },
52✔
2688
      'queued': true,
52✔
2689
      'onCycle': evaluate,
52✔
2690
      'onComplete': function() { bench.emit(new Event('complete')); }
52✔
2691
    });
52✔
2692
  }
52✔
2693

2✔
2694
  /*------------------------------------------------------------------------*/
2✔
2695

2✔
2696
  /**
2✔
2697
   * Cycles a benchmark until a run `count` can be established.
2✔
2698
   *
2✔
2699
   * @private
2✔
2700
   * @param {Object} clone The cloned benchmark instance.
2✔
2701
   * @param {Object} options The options object.
2✔
2702
   */
2✔
2703
  function cycle(clone, options) {
2✔
2704
    const {timer} = options;
352✔
2705

352✔
2706
    var deferred;
352✔
2707
    if (clone instanceof Deferred) {
352✔
2708
      deferred = clone;
52✔
2709
      clone = clone.benchmark;
52✔
2710
    }
52✔
2711
    var clocked,
352✔
2712
        cycles,
352✔
2713
        divisor,
352✔
2714
        event,
352✔
2715
        minTime,
352✔
2716
        period,
352✔
2717
        async = options.async,
352✔
2718
        bench = clone._original,
352✔
2719
        count = clone.count,
352✔
2720
        times = clone.times;
352✔
2721

352✔
2722
    // Continue, if not aborted between cycles.
352✔
2723
    if (clone.running) {
352✔
2724
      // `minTime` is set to `Benchmark.options.minTime` in `clock()`.
352✔
2725
      cycles = ++clone.cycles;
352✔
2726
      clocked = deferred ? deferred.elapsed : clock(clone, timer);
352✔
2727
      minTime = clone.minTime;
352✔
2728

352✔
2729
      if (cycles > bench.cycles) {
352✔
2730
        bench.cycles = cycles;
126✔
2731
      }
126✔
2732
      if (clone.error) {
352✔
2733
        event = new Event('error');
16✔
2734
        event.message = clone.error;
16✔
2735
        clone.emit(event);
16✔
2736
        if (!event.cancelled) {
16✔
2737
          clone.abort();
16✔
2738
        }
16✔
2739
      }
16✔
2740
    }
352✔
2741
    // Continue, if not errored.
352✔
2742
    if (clone.running) {
352✔
2743
      // Compute the time taken to complete last test cycle.
336✔
2744
      bench.times.cycle = times.cycle = clocked;
336✔
2745
      // Compute the seconds per operation.
336✔
2746
      period = bench.times.period = times.period = clocked / count;
336✔
2747
      // Compute the ops per second.
336✔
2748
      bench.hz = clone.hz = 1 / period;
336✔
2749
      // Avoid working our way up to this next time.
336✔
2750
      bench.initCount = clone.initCount = count;
336✔
2751
      // Do we need to do another cycle?
336✔
2752
      clone.running = clocked < minTime;
336✔
2753

336✔
2754
      if (clone.running) {
336✔
2755
        // Tests may clock at `0` when `initCount` is a small number,
101✔
2756
        // to avoid that we set its count to something a bit higher.
101✔
2757
        if (!clocked && (divisor = divisors[clone.cycles]) != null) {
101✔
2758
          count = Math.floor(4e6 / divisor);
10✔
2759
        }
10✔
2760
        // Calculate how many more iterations it will take to achieve the `minTime`.
101✔
2761
        if (count <= clone.count) {
101✔
2762
          count += Math.ceil((minTime - clocked) / period);
91✔
2763
        }
91✔
2764
        clone.running = count != Infinity;
101✔
2765
      }
101✔
2766
    }
336✔
2767
    // Should we exit early?
352✔
2768
    event = new Event('cycle');
352✔
2769
    clone.emit(event);
352✔
2770
    if (event.aborted) {
352!
2771
      clone.abort();
×
2772
    }
×
2773
    // Figure out what to do next.
352✔
2774
    if (clone.running) {
352✔
2775
      // Start a new cycle.
93✔
2776
      clone.count = count;
93✔
2777
      if (deferred) {
93✔
2778
        clone.compiled.call(deferred, globalThis, timer);
4✔
2779
      } else if (async) {
93✔
2780
        delay(clone, function() { cycle(clone, options); });
36✔
2781
      } else {
89✔
2782
        cycle(clone, {timer});
53✔
2783
      }
53✔
2784
    }
93✔
2785
    else {
259✔
2786
      // Fix TraceMonkey bug associated with clock fallbacks.
259✔
2787
      // For more information see http://bugzil.la/509069.
259✔
2788
      if (Support.browser) {
259✔
2789
        runScript(uid + '=1;delete ' + uid);
129✔
2790
      }
129✔
2791
      // We're done.
259✔
2792
      clone.emit(new Event('complete'));
259✔
2793
    }
259✔
2794
  }
352✔
2795

2✔
2796
  /*--------------------------------------------------------------------------*/
2✔
2797

2✔
2798
  // Export Benchmark.
2✔
2799
  // Some AMD build optimizers, like r.js, check for condition patterns like the following:
2✔
2800
  if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) {
2!
2801
    // Define as an anonymous module so, through path mapping, it can be aliased.
×
2802
    define(function() {
×
2803
      return Benchmark;
×
2804
    });
×
2805
  }
×
2806
  else {
2✔
2807
    // Check for `exports` after `define` in case a build optimizer adds an `exports` object.
2✔
2808
    if (freeExports && freeModule) {
2✔
2809
      // Export for Node.js.
1✔
2810
      if (moduleExports) {
1✔
2811
        (freeModule.exports = Benchmark).Benchmark = Benchmark;
1✔
2812
      }
1✔
2813
      // Export for CommonJS support.
1✔
2814
      freeExports.Benchmark = Benchmark;
1✔
2815
    }
1✔
2816
    else {
1✔
2817
      // Export to the global object.
1✔
2818
      globalThis.Benchmark = Benchmark;
1✔
2819
    }
1✔
2820
  }
2✔
2821
}.call(globalThis));
2✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc