UNPKG

gun

Version:

A realtime, decentralized, offline-first, graph data synchronization engine.

1,590 lines (1,468 loc) 114 kB
/*! * Benchmark.js v1.0.0 <http://benchmarkjs.com/> * Copyright 2010-2012 Mathias Bynens <http://mths.be/> * Based on JSLitmus.js, copyright Robert Kieffer <http://broofa.com/> * Modified by John-David Dalton <http://allyoucanleet.com/> * Available under MIT license <http://mths.be/mit> */ ;(function(window, undefined) { 'use strict'; /** Used to assign each benchmark an incrimented id */ var counter = 0; /** Detect DOM document object */ var doc = isHostType(window, 'document') && document; /** Detect free variable `define` */ var freeDefine = typeof define == 'function' && typeof define.amd == 'object' && define.amd && define; /** Detect free variable `exports` */ var freeExports = typeof exports == 'object' && exports && (typeof global == 'object' && global && global == global.global && (window = global), exports); /** Detect free variable `require` */ var freeRequire = typeof require == 'function' && require; /** Used to crawl all properties regardless of enumerability */ var getAllKeys = Object.getOwnPropertyNames; /** Used to get property descriptors */ var getDescriptor = Object.getOwnPropertyDescriptor; /** Used in case an object doesn't have its own method */ var hasOwnProperty = {}.hasOwnProperty; /** Used to check if an object is extensible */ var isExtensible = Object.isExtensible || function() { return true; }; /** Used to access Wade Simmons' Node microtime module */ var microtimeObject = req('microtime'); /** Used to access the browser's high resolution timer */ var perfObject = isHostType(window, 'performance') && performance; /** Used to call the browser's high resolution timer */ var perfName = perfObject && ( perfObject.now && 'now' || perfObject.webkitNow && 'webkitNow' ); /** Used to access Node's high resolution timer */ var processObject = isHostType(window, 'process') && process; /** Used to check if an own property is enumerable */ var propertyIsEnumerable = {}.propertyIsEnumerable; /** Used to set property descriptors */ var setDescriptor = Object.defineProperty; /** Used to resolve a value's internal [[Class]] */ var toString = {}.toString; /** Used to prevent a `removeChild` memory leak in IE < 9 */ var trash = doc && doc.createElement('div'); /** Used to integrity check compiled tests */ var uid = 'uid' + (+new Date); /** Used to avoid infinite recursion when methods call each other */ var calledBy = {}; /** Used to avoid hz of Infinity */ var divisors = { '1': 4096, '2': 512, '3': 64, '4': 8, '5': 0 }; /** * T-Distribution two-tailed critical values for 95% confidence * http://www.itl.nist.gov/div898/handbook/eda/section3/eda3672.htm */ var tTable = { '1': 12.706,'2': 4.303, '3': 3.182, '4': 2.776, '5': 2.571, '6': 2.447, '7': 2.365, '8': 2.306, '9': 2.262, '10': 2.228, '11': 2.201, '12': 2.179, '13': 2.16, '14': 2.145, '15': 2.131, '16': 2.12, '17': 2.11, '18': 2.101, '19': 2.093, '20': 2.086, '21': 2.08, '22': 2.074, '23': 2.069, '24': 2.064, '25': 2.06, '26': 2.056, '27': 2.052, '28': 2.048, '29': 2.045, '30': 2.042, 'infinity': 1.96 }; /** * Critical Mann-Whitney U-values for 95% confidence * http://www.saburchill.com/IBbiology/stats/003.html */ var uTable = { '5': [0, 1, 2], '6': [1, 2, 3, 5], '7': [1, 3, 5, 6, 8], '8': [2, 4, 6, 8, 10, 13], '9': [2, 4, 7, 10, 12, 15, 17], '10': [3, 5, 8, 11, 14, 17, 20, 23], '11': [3, 6, 9, 13, 16, 19, 23, 26, 30], '12': [4, 7, 11, 14, 18, 22, 26, 29, 33, 37], '13': [4, 8, 12, 16, 20, 24, 28, 33, 37, 41, 45], '14': [5, 9, 13, 17, 22, 26, 31, 36, 40, 45, 50, 55], '15': [5, 10, 14, 19, 24, 29, 34, 39, 44, 49, 54, 59, 64], '16': [6, 11, 15, 21, 26, 31, 37, 42, 47, 53, 59, 64, 70, 75], '17': [6, 11, 17, 22, 28, 34, 39, 45, 51, 57, 63, 67, 75, 81, 87], '18': [7, 12, 18, 24, 30, 36, 42, 48, 55, 61, 67, 74, 80, 86, 93, 99], '19': [7, 13, 19, 25, 32, 38, 45, 52, 58, 65, 72, 78, 85, 92, 99, 106, 113], '20': [8, 14, 20, 27, 34, 41, 48, 55, 62, 69, 76, 83, 90, 98, 105, 112, 119, 127], '21': [8, 15, 22, 29, 36, 43, 50, 58, 65, 73, 80, 88, 96, 103, 111, 119, 126, 134, 142], '22': [9, 16, 23, 30, 38, 45, 53, 61, 69, 77, 85, 93, 101, 109, 117, 125, 133, 141, 150, 158], '23': [9, 17, 24, 32, 40, 48, 56, 64, 73, 81, 89, 98, 106, 115, 123, 132, 140, 149, 157, 166, 175], '24': [10, 17, 25, 33, 42, 50, 59, 67, 76, 85, 94, 102, 111, 120, 129, 138, 147, 156, 165, 174, 183, 192], '25': [10, 18, 27, 35, 44, 53, 62, 71, 80, 89, 98, 107, 117, 126, 135, 145, 154, 163, 173, 182, 192, 201, 211], '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], '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], '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], '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], '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] }; /** * An object used to flag environments/features. * * @static * @memberOf Benchmark * @type Object */ var support = {}; (function() { /** * Detect Adobe AIR. * * @memberOf Benchmark.support * @type Boolean */ support.air = isClassOf(window.runtime, 'ScriptBridgingProxyObject'); /** * Detect if `arguments` objects have the correct internal [[Class]] value. * * @memberOf Benchmark.support * @type Boolean */ support.argumentsClass = isClassOf(arguments, 'Arguments'); /** * Detect if in a browser environment. * * @memberOf Benchmark.support * @type Boolean */ support.browser = doc && isHostType(window, 'navigator'); /** * Detect if strings support accessing characters by index. * * @memberOf Benchmark.support * @type Boolean */ support.charByIndex = // IE 8 supports indexes on string literals but not string objects ('x'[0] + Object('x')[0]) == 'xx'; /** * Detect if strings have indexes as own properties. * * @memberOf Benchmark.support * @type Boolean */ support.charByOwnIndex = // Narwhal, Rhino, RingoJS, IE 8, and Opera < 10.52 support indexes on // strings but don't detect them as own properties support.charByIndex && hasKey('x', '0'); /** * Detect if Java is enabled/exposed. * * @memberOf Benchmark.support * @type Boolean */ support.java = isClassOf(window.java, 'JavaPackage'); /** * Detect if the Timers API exists. * * @memberOf Benchmark.support * @type Boolean */ support.timeout = isHostType(window, 'setTimeout') && isHostType(window, 'clearTimeout'); /** * Detect if functions support decompilation. * * @name decompilation * @memberOf Benchmark.support * @type Boolean */ try { // Safari 2.x removes commas in object literals // from Function#toString results // http://webk.it/11609 // Firefox 3.6 and Opera 9.25 strip grouping // parentheses from Function#toString results // http://bugzil.la/559438 support.decompilation = Function( 'return (' + (function(x) { return { 'x': '' + (1 + x) + '', 'y': 0 }; }) + ')' )()(0).x === '1'; } catch(e) { support.decompilation = false; } /** * Detect ES5+ property descriptor API. * * @name descriptors * @memberOf Benchmark.support * @type Boolean */ try { var o = {}; support.descriptors = (setDescriptor(o, o, o), 'value' in getDescriptor(o, o)); } catch(e) { support.descriptors = false; } /** * Detect ES5+ Object.getOwnPropertyNames(). * * @name getAllKeys * @memberOf Benchmark.support * @type Boolean */ try { support.getAllKeys = /\bvalueOf\b/.test(getAllKeys(Object.prototype)); } catch(e) { support.getAllKeys = false; } /** * Detect if own properties are iterated before inherited properties (all but IE < 9). * * @name iteratesOwnLast * @memberOf Benchmark.support * @type Boolean */ support.iteratesOwnFirst = (function() { var props = []; function ctor() { this.x = 1; } ctor.prototype = { 'y': 1 }; for (var prop in new ctor) { props.push(prop); } return props[0] == 'x'; }()); /** * Detect if a node's [[Class]] is resolvable (all but IE < 9) * and that the JS engine errors when attempting to coerce an object to a * string without a `toString` property value of `typeof` "function". * * @name nodeClass * @memberOf Benchmark.support * @type Boolean */ try { support.nodeClass = ({ 'toString': 0 } + '', toString.call(doc || 0) != '[object Object]'); } catch(e) { support.nodeClass = true; } }()); /** * Timer object used by `clock()` and `Deferred#resolve`. * * @private * @type Object */ var timer = { /** * The timer namespace object or constructor. * * @private * @memberOf timer * @type Function|Object */ 'ns': Date, /** * Starts the deferred timer. * * @private * @memberOf timer * @param {Object} deferred The deferred instance. */ 'start': null, // lazy defined in `clock()` /** * Stops the deferred timer. * * @private * @memberOf timer * @param {Object} deferred The deferred instance. */ 'stop': null // lazy defined in `clock()` }; /** Shortcut for inverse results */ var noArgumentsClass = !support.argumentsClass, noCharByIndex = !support.charByIndex, noCharByOwnIndex = !support.charByOwnIndex; /** Math shortcuts */ var abs = Math.abs, floor = Math.floor, max = Math.max, min = Math.min, pow = Math.pow, sqrt = Math.sqrt; /*--------------------------------------------------------------------------*/ /** * The Benchmark constructor. * * @constructor * @param {String} name A name to identify the benchmark. * @param {Function|String} fn The test to benchmark. * @param {Object} [options={}] Options object. * @example * * // basic usage (the `new` operator is optional) * var bench = new Benchmark(fn); * * // or using a name first * var bench = new Benchmark('foo', fn); * * // or with options * var bench = new Benchmark('foo', fn, { * * // displayed by Benchmark#toString if `name` is not available * 'id': 'xyz', * * // called when the benchmark starts running * 'onStart': onStart, * * // called after each run cycle * 'onCycle': onCycle, * * // called when aborted * 'onAbort': onAbort, * * // called when a test errors * 'onError': onError, * * // called when reset * 'onReset': onReset, * * // called when the benchmark completes running * 'onComplete': onComplete, * * // compiled/called before the test loop * 'setup': setup, * * // compiled/called after the test loop * 'teardown': teardown * }); * * // or name and options * var bench = new Benchmark('foo', { * * // a flag to indicate the benchmark is deferred * 'defer': true, * * // benchmark test function * 'fn': function(deferred) { * // call resolve() when the deferred test is finished * deferred.resolve(); * } * }); * * // or options only * var bench = new Benchmark({ * * // benchmark name * 'name': 'foo', * * // benchmark test as a string * 'fn': '[1,2,3,4].sort()' * }); * * // a test's `this` binding is set to the benchmark instance * var bench = new Benchmark('foo', function() { * 'My name is '.concat(this.name); // My name is foo * }); */ function Benchmark(name, fn, options) { var me = this; // allow instance creation without the `new` operator if (me == null || me.constructor != Benchmark) { return new Benchmark(name, fn, options); } // juggle arguments if (isClassOf(name, 'Object')) { // 1 argument (options) options = name; } else if (isClassOf(name, 'Function')) { // 2 arguments (fn, options) options = fn; fn = name; } else if (isClassOf(fn, 'Object')) { // 2 arguments (name, options) options = fn; fn = null; me.name = name; } else { // 3 arguments (name, fn [, options]) me.name = name; } setOptions(me, options); me.id || (me.id = ++counter); me.fn == null && (me.fn = fn); me.stats = deepClone(me.stats); me.times = deepClone(me.times); } /** * The Deferred constructor. * * @constructor * @memberOf Benchmark * @param {Object} clone The cloned benchmark instance. */ function Deferred(clone) { var me = this; if (me == null || me.constructor != Deferred) { return new Deferred(clone); } me.benchmark = clone; clock(me); } /** * The Event constructor. * * @constructor * @memberOf Benchmark * @param {String|Object} type The event type. */ function Event(type) { var me = this; return (me == null || me.constructor != Event) ? new Event(type) : (type instanceof Event) ? type : extend(me, { 'timeStamp': +new Date }, typeof type == 'string' ? { 'type': type } : type); } /** * The Suite constructor. * * @constructor * @memberOf Benchmark * @param {String} name A name to identify the suite. * @param {Object} [options={}] Options object. * @example * * // basic usage (the `new` operator is optional) * var suite = new Benchmark.Suite; * * // or using a name first * var suite = new Benchmark.Suite('foo'); * * // or with options * var suite = new Benchmark.Suite('foo', { * * // called when the suite starts running * 'onStart': onStart, * * // called between running benchmarks * 'onCycle': onCycle, * * // called when aborted * 'onAbort': onAbort, * * // called when a test errors * 'onError': onError, * * // called when reset * 'onReset': onReset, * * // called when the suite completes running * 'onComplete': onComplete * }); */ function Suite(name, options) { var me = this; // allow instance creation without the `new` operator if (me == null || me.constructor != Suite) { return new Suite(name, options); } // juggle arguments if (isClassOf(name, 'Object')) { // 1 argument (options) options = name; } else { // 2 arguments (name [, options]) me.name = name; } setOptions(me, options); } /*--------------------------------------------------------------------------*/ /** * Note: Some array methods have been implemented in plain JavaScript to avoid * bugs in IE, Opera, Rhino, and Mobile Safari. * * IE compatibility mode and IE < 9 have buggy Array `shift()` and `splice()` * functions that fail to remove the last element, `object[0]`, of * array-like-objects even though the `length` property is set to `0`. * The `shift()` method is buggy in IE 8 compatibility mode, while `splice()` * is buggy regardless of mode in IE < 9 and buggy in compatibility mode in IE 9. * * In Opera < 9.50 and some older/beta Mobile Safari versions using `unshift()` * generically to augment the `arguments` object will pave the value at index 0 * without incrimenting the other values's indexes. * https://github.com/documentcloud/underscore/issues/9 * * Rhino and environments it powers, like Narwhal and RingoJS, may have * buggy Array `concat()`, `reverse()`, `shift()`, `slice()`, `splice()` and * `unshift()` functions that make sparse arrays non-sparse by assigning the * undefined indexes a value of undefined. * https://github.com/mozilla/rhino/commit/702abfed3f8ca043b2636efd31c14ba7552603dd */ /** * Creates an array containing the elements of the host array followed by the * elements of each argument in order. * * @memberOf Benchmark.Suite * @returns {Array} The new array. */ function concat() { var value, j = -1, length = arguments.length, result = slice.call(this), index = result.length; while (++j < length) { value = arguments[j]; if (isClassOf(value, 'Array')) { for (var k = 0, l = value.length; k < l; k++, index++) { if (k in value) { result[index] = value[k]; } } } else { result[index++] = value; } } return result; } /** * Utility function used by `shift()`, `splice()`, and `unshift()`. * * @private * @param {Number} start The index to start inserting elements. * @param {Number} deleteCount The number of elements to delete from the insert point. * @param {Array} elements The elements to insert. * @returns {Array} An array of deleted elements. */ function insert(start, deleteCount, elements) { // `result` should have its length set to the `deleteCount` // see https://bugs.ecmascript.org/show_bug.cgi?id=332 var deleteEnd = start + deleteCount, elementCount = elements ? elements.length : 0, index = start - 1, length = start + elementCount, object = this, result = Array(deleteCount), tail = slice.call(object, deleteEnd); // delete elements from the array while (++index < deleteEnd) { if (index in object) { result[index - start] = object[index]; delete object[index]; } } // insert elements index = start - 1; while (++index < length) { object[index] = elements[index - start]; } // append tail elements start = index--; length = max(0, (object.length >>> 0) - deleteCount + elementCount); while (++index < length) { if ((index - start) in tail) { object[index] = tail[index - start]; } else if (index in object) { delete object[index]; } } // delete excess elements deleteCount = deleteCount > elementCount ? deleteCount - elementCount : 0; while (deleteCount--) { index = length + deleteCount; if (index in object) { delete object[index]; } } object.length = length; return result; } /** * Rearrange the host array's elements in reverse order. * * @memberOf Benchmark.Suite * @returns {Array} The reversed array. */ function reverse() { var upperIndex, value, index = -1, object = Object(this), length = object.length >>> 0, middle = floor(length / 2); if (length > 1) { while (++index < middle) { upperIndex = length - index - 1; value = upperIndex in object ? object[upperIndex] : uid; if (index in object) { object[upperIndex] = object[index]; } else { delete object[upperIndex]; } if (value != uid) { object[index] = value; } else { delete object[index]; } } } return object; } /** * Removes the first element of the host array and returns it. * * @memberOf Benchmark.Suite * @returns {Mixed} The first element of the array. */ function shift() { return insert.call(this, 0, 1)[0]; } /** * Creates an array of the host array's elements from the start index up to, * but not including, the end index. * * @memberOf Benchmark.Suite * @param {Number} start The starting index. * @param {Number} end The end index. * @returns {Array} The new array. */ function slice(start, end) { var index = -1, object = Object(this), length = object.length >>> 0, result = []; start = toInteger(start); start = start < 0 ? max(length + start, 0) : min(start, length); start--; end = end == null ? length : toInteger(end); end = end < 0 ? max(length + end, 0) : min(end, length); while ((++index, ++start) < end) { if (start in object) { result[index] = object[start]; } } return result; } /** * Allows removing a range of elements and/or inserting elements into the * host array. * * @memberOf Benchmark.Suite * @param {Number} start The start index. * @param {Number} deleteCount The number of elements to delete. * @param {Mixed} [val1, val2, ...] values to insert at the `start` index. * @returns {Array} An array of removed elements. */ function splice(start, deleteCount) { var object = Object(this), length = object.length >>> 0; start = toInteger(start); start = start < 0 ? max(length + start, 0) : min(start, length); // support the de-facto SpiderMonkey extension // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/splice#Parameters // https://bugs.ecmascript.org/show_bug.cgi?id=429 deleteCount = arguments.length == 1 ? length - start : min(max(toInteger(deleteCount), 0), length - start); return insert.call(object, start, deleteCount, slice.call(arguments, 2)); } /** * Converts the specified `value` to an integer. * * @private * @param {Mixed} value The value to convert. * @returns {Number} The resulting integer. */ function toInteger(value) { value = +value; return value === 0 || !isFinite(value) ? value || 0 : value - (value % 1); } /** * Appends arguments to the host array. * * @memberOf Benchmark.Suite * @returns {Number} The new length. */ function unshift() { var object = Object(this); insert.call(object, 0, 0, arguments); return object.length; } /*--------------------------------------------------------------------------*/ /** * A generic `Function#bind` like method. * * @private * @param {Function} fn The function to be bound to `thisArg`. * @param {Mixed} thisArg The `this` binding for the given function. * @returns {Function} The bound function. */ function bind(fn, thisArg) { return function() { fn.apply(thisArg, arguments); }; } /** * Creates a function from the given arguments string and body. * * @private * @param {String} args The comma separated function arguments. * @param {String} body The function body. * @returns {Function} The new function. */ function createFunction() { // lazy define createFunction = function(args, body) { var result, anchor = freeDefine ? define.amd : Benchmark, prop = uid + 'createFunction'; runScript((freeDefine ? 'define.amd.' : 'Benchmark.') + prop + '=function(' + args + '){' + body + '}'); result = anchor[prop]; delete anchor[prop]; return result; }; // fix JaegerMonkey bug // http://bugzil.la/639720 createFunction = support.browser && (createFunction('', 'return"' + uid + '"') || noop)() == uid ? createFunction : Function; return createFunction.apply(null, arguments); } /** * Delay the execution of a function based on the benchmark's `delay` property. * * @private * @param {Object} bench The benchmark instance. * @param {Object} fn The function to execute. */ function delay(bench, fn) { bench._timerId = setTimeout(fn, bench.delay * 1e3); } /** * Destroys the given element. * * @private * @param {Element} element The element to destroy. */ function destroyElement(element) { trash.appendChild(element); trash.innerHTML = ''; } /** * Iterates over an object's properties, executing the `callback` for each. * Callbacks may terminate the loop by explicitly returning `false`. * * @private * @param {Object} object The object to iterate over. * @param {Function} callback The function executed per own property. * @param {Object} options The options object. * @returns {Object} Returns the object iterated over. */ function forProps() { var forShadowed, skipSeen, forArgs = true, shadowed = ['constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'valueOf']; (function(enumFlag, key) { // must use a non-native constructor to catch the Safari 2 issue function Klass() { this.valueOf = 0; }; Klass.prototype.valueOf = 0; // check various for-in bugs for (key in new Klass) { enumFlag += key == 'valueOf' ? 1 : 0; } // check if `arguments` objects have non-enumerable indexes for (key in arguments) { key == '0' && (forArgs = false); } // Safari 2 iterates over shadowed properties twice // http://replay.waybackmachine.org/20090428222941/http://tobielangel.com/2007/1/29/for-in-loop-broken-in-safari/ skipSeen = enumFlag == 2; // IE < 9 incorrectly makes an object's properties non-enumerable if they have // the same name as other non-enumerable properties in its prototype chain. forShadowed = !enumFlag; }(0)); // lazy define forProps = function(object, callback, options) { options || (options = {}); var result = object; object = Object(object); var ctor, key, keys, skipCtor, done = !result, which = options.which, allFlag = which == 'all', index = -1, iteratee = object, length = object.length, ownFlag = allFlag || which == 'own', seen = {}, skipProto = isClassOf(object, 'Function'), thisArg = options.bind; if (thisArg !== undefined) { callback = bind(callback, thisArg); } // iterate all properties if (allFlag && support.getAllKeys) { for (index = 0, keys = getAllKeys(object), length = keys.length; index < length; index++) { key = keys[index]; if (callback(object[key], key, object) === false) { break; } } } // else iterate only enumerable properties else { for (key in object) { // Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1 // (if the prototype or a property on the prototype has been set) // incorrectly set a function's `prototype` property [[Enumerable]] value // to `true`. Because of this we standardize on skipping the `prototype` // property of functions regardless of their [[Enumerable]] value. if ((done = !(skipProto && key == 'prototype') && !(skipSeen && (hasKey(seen, key) || !(seen[key] = true))) && (!ownFlag || ownFlag && hasKey(object, key)) && callback(object[key], key, object) === false)) { break; } } // in IE < 9 strings don't support accessing characters by index if (!done && (forArgs && isArguments(object) || ((noCharByIndex || noCharByOwnIndex) && isClassOf(object, 'String') && (iteratee = noCharByIndex ? object.split('') : object)))) { while (++index < length) { if ((done = callback(iteratee[index], String(index), object) === false)) { break; } } } if (!done && forShadowed) { // Because IE < 9 can't set the `[[Enumerable]]` attribute of an existing // property and the `constructor` property of a prototype defaults to // non-enumerable, we manually skip the `constructor` property when we // think we are iterating over a `prototype` object. ctor = object.constructor; skipCtor = ctor && ctor.prototype && ctor.prototype.constructor === ctor; for (index = 0; index < 7; index++) { key = shadowed[index]; if (!(skipCtor && key == 'constructor') && hasKey(object, key) && callback(object[key], key, object) === false) { break; } } } } return result; }; return forProps.apply(null, arguments); } /** * Gets the name of the first argument from a function's source. * * @private * @param {Function} fn The function. * @returns {String} The argument name. */ function getFirstArgument(fn) { return (!hasKey(fn, 'toString') && (/^[\s(]*function[^(]*\(([^\s,)]+)/.exec(fn) || 0)[1]) || ''; } /** * Computes the arithmetic mean of a sample. * * @private * @param {Array} sample The sample. * @returns {Number} The mean. */ function getMean(sample) { return reduce(sample, function(sum, x) { return sum + x; }) / sample.length || 0; } /** * Gets the source code of a function. * * @private * @param {Function} fn The function. * @param {String} altSource A string used when a function's source code is unretrievable. * @returns {String} The function's source code. */ function getSource(fn, altSource) { var result = altSource; if (isStringable(fn)) { result = String(fn); } else if (support.decompilation) { // escape the `{` for Firefox 1 result = (/^[^{]+\{([\s\S]*)}\s*$/.exec(fn) || 0)[1]; } // trim string result = (result || '').replace(/^\s+|\s+$/g, ''); // detect strings containing only the "use strict" directive return /^(?:\/\*+[\w|\W]*?\*\/|\/\/.*?[\n\r\u2028\u2029]|\s)*(["'])use strict\1;?$/.test(result) ? '' : result; } /** * Checks if a value is an `arguments` object. * * @private * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true` if the value is an `arguments` object, else `false`. */ function isArguments() { // lazy define isArguments = function(value) { return toString.call(value) == '[object Arguments]'; }; if (noArgumentsClass) { isArguments = function(value) { return hasKey(value, 'callee') && !(propertyIsEnumerable && propertyIsEnumerable.call(value, 'callee')); }; } return isArguments(arguments[0]); } /** * Checks if an object is of the specified class. * * @private * @param {Mixed} value The value to check. * @param {String} name The name of the class. * @returns {Boolean} Returns `true` if the value is of the specified class, else `false`. */ function isClassOf(value, name) { return value != null && toString.call(value) == '[object ' + name + ']'; } /** * Host objects can return type values that are different from their actual * data type. The objects we are concerned with usually return non-primitive * types of object, function, or unknown. * * @private * @param {Mixed} object The owner of the property. * @param {String} property The property to check. * @returns {Boolean} Returns `true` if the property value is a non-primitive, else `false`. */ function isHostType(object, property) { var type = object != null ? typeof object[property] : 'number'; return !/^(?:boolean|number|string|undefined)$/.test(type) && (type == 'object' ? !!object[property] : true); } /** * Checks if a given `value` is an object created by the `Object` constructor * assuming objects created by the `Object` constructor have no inherited * enumerable properties and that there are no `Object.prototype` extensions. * * @private * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true` if the `value` is a plain `Object` object, else `false`. */ function isPlainObject(value) { // avoid non-objects and false positives for `arguments` objects in IE < 9 var result = false; if (!(value && typeof value == 'object') || isArguments(value)) { return result; } // IE < 9 presents DOM nodes as `Object` objects except they have `toString` // methods that are `typeof` "string" and still can coerce nodes to strings. // Also check that the constructor is `Object` (i.e. `Object instanceof Object`) var ctor = value.constructor; if ((support.nodeClass || !(typeof value.toString != 'function' && typeof (value + '') == 'string')) && (!isClassOf(ctor, 'Function') || ctor instanceof ctor)) { // In most environments an object's own properties are iterated before // its inherited properties. If the last iterated property is an object's // own property then there are no inherited enumerable properties. if (support.iteratesOwnFirst) { forProps(value, function(subValue, subKey) { result = subKey; }); return result === false || hasKey(value, result); } // IE < 9 iterates inherited properties before own properties. If the first // iterated property is an object's own property then there are no inherited // enumerable properties. forProps(value, function(subValue, subKey) { result = !hasKey(value, subKey); return false; }); return result === false; } return result; } /** * Checks if a value can be safely coerced to a string. * * @private * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true` if the value can be coerced, else `false`. */ function isStringable(value) { return hasKey(value, 'toString') || isClassOf(value, 'String'); } /** * Wraps a function and passes `this` to the original function as the * first argument. * * @private * @param {Function} fn The function to be wrapped. * @returns {Function} The new function. */ function methodize(fn) { return function() { var args = [this]; args.push.apply(args, arguments); return fn.apply(null, args); }; } /** * A no-operation function. * * @private */ function noop() { // no operation performed } /** * A wrapper around require() to suppress `module missing` errors. * * @private * @param {String} id The module id. * @returns {Mixed} The exported module or `null`. */ function req(id) { try { var result = freeExports && freeRequire(id); } catch(e) { } return result || null; } /** * Runs a snippet of JavaScript via script injection. * * @private * @param {String} code The code to run. */ function runScript(code) { var anchor = freeDefine ? define.amd : Benchmark, script = doc.createElement('script'), sibling = doc.getElementsByTagName('script')[0], parent = sibling.parentNode, prop = uid + 'runScript', prefix = '(' + (freeDefine ? 'define.amd.' : 'Benchmark.') + prop + '||function(){})();'; // Firefox 2.0.0.2 cannot use script injection as intended because it executes // asynchronously, but that's OK because script injection is only used to avoid // the previously commented JaegerMonkey bug. try { // remove the inserted script *before* running the code to avoid differences // in the expected script element count/order of the document. script.appendChild(doc.createTextNode(prefix + code)); anchor[prop] = function() { destroyElement(script); }; } catch(e) { parent = parent.cloneNode(false); sibling = null; script.text = code; } parent.insertBefore(script, sibling); delete anchor[prop]; } /** * A helper function for setting options/event handlers. * * @private * @param {Object} bench The benchmark instance. * @param {Object} [options={}] Options object. */ function setOptions(bench, options) { options = extend({}, bench.constructor.options, options); bench.options = forOwn(options, function(value, key) { if (value != null) { // add event listeners if (/^on[A-Z]/.test(key)) { forEach(key.split(' '), function(key) { bench.on(key.slice(2).toLowerCase(), value); }); } else if (!hasKey(bench, key)) { bench[key] = deepClone(value); } } }); } /*--------------------------------------------------------------------------*/ /** * Handles cycling/completing the deferred benchmark. * * @memberOf Benchmark.Deferred */ function resolve() { var me = this, clone = me.benchmark, bench = clone._original; if (bench.aborted) { // cycle() -> clone cycle/complete event -> compute()'s invoked bench.run() cycle/complete me.teardown(); clone.running = false; cycle(me); } else if (++me.cycles < clone.count) { // continue the test loop if (support.timeout) { // use setTimeout to avoid a call stack overflow if called recursively setTimeout(function() { clone.compiled.call(me, timer); }, 0); } else { clone.compiled.call(me, timer); } } else { timer.stop(me); me.teardown(); delay(clone, function() { cycle(me); }); } } /*--------------------------------------------------------------------------*/ /** * A deep clone utility. * * @static * @memberOf Benchmark * @param {Mixed} value The value to clone. * @returns {Mixed} The cloned value. */ function deepClone(value) { var accessor, circular, clone, ctor, descriptor, extensible, key, length, markerKey, parent, result, source, subIndex, data = { 'value': value }, index = 0, marked = [], queue = { 'length': 0 }, unmarked = []; /** * An easily detectable decorator for cloned values. */ function Marker(object) { this.raw = object; } /** * The callback used by `forProps()`. */ function forPropsCallback(subValue, subKey) { // exit early to avoid cloning the marker if (subValue && subValue.constructor == Marker) { return; } // add objects to the queue if (subValue === Object(subValue)) { queue[queue.length++] = { 'key': subKey, 'parent': clone, 'source': value }; } // assign non-objects else { try { // will throw an error in strict mode if the property is read-only clone[subKey] = subValue; } catch(e) { } } } /** * Gets an available marker key for the given object. */ function getMarkerKey(object) { // avoid collisions with existing keys var result = uid; while (object[result] && object[result].constructor != Marker) { result += 1; } return result; } do { key = data.key; parent = data.parent; source = data.source; clone = value = source ? source[key] : data.value; accessor = circular = descriptor = false; // create a basic clone to filter out functions, DOM elements, and // other non `Object` objects if (value === Object(value)) { // use custom deep clone function if available if (isClassOf(value.deepClone, 'Function')) { clone = value.deepClone(); } else { ctor = value.constructor; switch (toString.call(value)) { case '[object Array]': clone = new ctor(value.length); break; case '[object Boolean]': clone = new ctor(value == true); break; case '[object Date]': clone = new ctor(+value); break; case '[object Object]': isPlainObject(value) && (clone = {}); break; case '[object Number]': case '[object String]': clone = new ctor(value); break; case '[object RegExp]': clone = ctor(value.source, (value.global ? 'g' : '') + (value.ignoreCase ? 'i' : '') + (value.multiline ? 'm' : '')); } } // continue clone if `value` doesn't have an accessor descriptor // http://es5.github.com/#x8.10.1 if (clone && clone != value && !(descriptor = source && support.descriptors && getDescriptor(source, key), accessor = descriptor && (descriptor.get || descriptor.set))) { // use an existing clone (circular reference) if ((extensible = isExtensible(value))) { markerKey = getMarkerKey(value); if (value[markerKey]) { circular = clone = value[markerKey].raw; } } else { // for frozen/sealed objects for (subIndex = 0, length = unmarked.length; subIndex < length; subIndex++) { data = unmarked[subIndex]; if (data.object === value) { circular = clone = data.clone; break; } } } if (!circular) { // mark object to allow quickly detecting circular references and tie it to its clone if (extensible) { value[markerKey] = new Marker(clone); marked.push({ 'key': markerKey, 'object': value }); } else { // for frozen/sealed objects unmarked.push({ 'clone': clone, 'object': value }); } // iterate over object properties forProps(value, forPropsCallback, { 'which': 'all' }); } } } if (parent) { // for custom property descriptors if (accessor || (descriptor && !(descriptor.configurable && descriptor.enumerable && descriptor.writable))) { if ('value' in descriptor) { descriptor.value = clone; } setDescriptor(parent, key, descriptor); } // for default property descriptors else { parent[key] = clone; } } else { result = clone; } } while ((data = queue[index++])); // remove markers for (index = 0, length = marked.length; index < length; index++) { data = marked[index]; delete data.object[data.key]; } return result; } /** * An iteration utility for arrays and objects. * Callbacks may terminate the loop by explicitly returning `false`. * * @static * @memberOf Benchmark * @param {Array|Object} object The object to iterate over. * @param {Function} callback The function called per iteration. * @param {Mixed} thisArg The `this` binding for the callback. * @returns {Array|Object} Returns the object iterated over. */ function each(object, callback, thisArg) { var result = object; object = Object(object); var fn = callback, index = -1, length = object.length, isSnapshot = !!(object.snapshotItem && (length = object.snapshotLength)), isSplittable = (noCharByIndex || noCharByOwnIndex) && isClassOf(object, 'String'), isConvertable = isSnapshot || isSplittable || 'item' in object, origObject = object; // in Opera < 10.5 `hasKey(object, 'length')` returns `false` for NodeLists if (length === length >>> 0) { if (isConvertable) { // the third argument of the callback is the original non-array object callback = function(value, index) { return fn.call(this, value, index, origObject); }; // in IE < 9 strings don't support accessing characters by index if (isSplittable) { object = object.split(''); } else { object = []; while (++index < length) { // in Safari 2 `index in object` is always `false` for NodeLists object[index] = isSnapshot ? result.snapshotItem(index) : result[index]; } } } forEach(object, callback, thisArg); } else { forOwn(object, callback, thisArg); } return result; } /** * Copies enumerable properties from the source(s) object to the destination object. * * @static * @memberOf Benchmark * @param {Object} destination The destination object. * @param {Object} [source={}] The source object. * @returns {Object} The destination object. */ function extend(destination, source) { // Chrome < 14 incorrectly sets `destination` to `undefined` when we `delete arguments[0]` // http://code.google.com/p/v8/issues/detail?id=839 var result = destination; delete arguments[0]; forEach(arguments, function(source) { forProps(source, function(value, key) { result[key] = value; }); }); return result; } /** * A generic `Array#filter` like method. * * @static * @memberOf Benchmark * @param {Array} array The array to iterate over. * @param {Function|String} callback The function/alias called per iteration. * @param {Mixed} thisArg The `this` binding for the callback. * @returns {Array} A new array of values that passed callback filter. * @example * * // get odd numbers * Benchmark.filter([1, 2, 3, 4, 5], function(n) { * return n % 2; * }); // -> [1, 3, 5]; * * // get fastest benchmarks * Benchmark.filter(benches, 'fastest'); * * // get slowest benchmarks * Benchmark.filter(benches, 'slowest'); * * // get benchmarks that completed without erroring * Benchmark.filter(benches, 'successful'); */ function filter(array, callback, thisArg) { var result; if (callback == 'successful') { // callback to exclude those that are errored, unrun, or have hz of Infinity callback = function(bench) { return bench.cycles && isFinite(bench.hz); }; } else if (callback == 'fastest' || callback == 'slowest') { // get successful, sort by period + margin of error, and filter fastest/slowest result = filter(array, 'successful').sort(function(a, b) { a = a.stats; b = b.stats; return (a.mean + a.moe > b.mean + b.moe ? 1 : -1) * (callback == 'fastest' ? 1 : -1); }); result = filter(result, function(bench) { return result[0].compare(bench) == 0; }); } return result || reduce(array, function(result, value, index) { return callback.call(thisArg, value, index, array) ? (result.push(value), result) : result; }, []); } /** * A generic `Array#forEach` like method. * Callbacks may terminate the loop by explicitly returning `false`. * * @static * @memberOf Benchmark * @param {Array} array The array to iterate over. * @param {Function} callback The function called per iteration. * @param {Mixed} thisArg The `this` binding for the callback. * @returns {Array} Returns the array iterated over. */ function forEach(array, callback, thisArg) { var index = -1, length = (array = Object(array)).length >>> 0; if (thisArg !== undefined) { callback = bind(callback, thisArg); } while (++index < length) { if (index in array && callback(array[index], index, array) === false) { break; } } return array; } /** * Iterates over an object's own properties, executing the `callback` for each. * Callbacks may terminate the loop by explicitly returning `false`. * * @static * @memberOf Benchmark * @param {Object} object The object to iterate over. * @param {Function} callback The function executed per own property. * @param {Mixed} thisArg The `this` binding for the callback. * @returns {Object} Returns the object iterated over. */ function forOwn(object, callback, thisArg) { return forProps(object, callback, { 'bind': thisArg, 'which': 'own' }); } /** * Converts a number to a more readable comma-separated string representation. * * @static * @memberOf Benchmark * @param {Number} number The number to convert. * @returns {String} The more readable string representation. */ function formatNumber(number) { number = String(number).split('.'); return number[0].replace(/(?=(?:\d{3})+$)(?!\b)/g, ',') + (number[1] ? '.' + number[1] : ''); } /** * Checks if an object has the specified key as a direct property. * * @static * @memberOf Benchmark * @param {Object} object The object to check. * @param {String} key The key to check for. * @returns {Boolean} Returns `true` if key is a direct property, else `false`. */ function hasKey() { // lazy define for worst case fallback (not as accurate) hasKey = function(object, key) { var parent = object != null && (object.constructor || Object).prototype; return !!parent && key in Object(object) && !(key in parent && object[key] === parent[key]); }; // for modern browsers if (isClassOf(hasOwnProperty, 'Function')) { hasKey = function(object, key) { return object != null && hasOwnProperty.call(object, key); }; } // for Safari 2 else if ({}.__proto__ == Object.prototype) { hasKey = function(object, key) { var result = false; if (object != null) { object = Object(object); object.__proto__ = [object.