@gsknnft/bigint-buffer 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/karma.conf.js ADDED
@@ -0,0 +1,62 @@
1
+ const webpack = require('webpack')
2
+ module.exports = function (config) {
3
+ const configuration = {
4
+ browserNoActivityTimeout: 120000,
5
+ frameworks: ['mocha'],
6
+ files: [
7
+ './build/src/*.spec.js'
8
+ ],
9
+ preprocessors: {
10
+ './build/src//*.spec.js': ['webpack', 'env']
11
+ },
12
+ webpack : {
13
+ mode: "production",
14
+ devtool: 'inline-source-map',
15
+ module: {
16
+ // Suppress warning from mocha: "Critical dependency: the request of a dependency is an expression"
17
+ // @see https://webpack.js.org/configuration/module/#module-contexts
18
+ exprContextCritical: false
19
+ },
20
+ // Suppress fatal error: Cannot resolve module 'fs'
21
+ // @relative https://github.com/pugjs/pug-loader/issues/8
22
+ // @see https://github.com/webpack/docs/wiki/Configuration#node
23
+ node: {
24
+ fs: 'empty',
25
+ bindings: 'empty'
26
+ },
27
+ resolve: {
28
+ extensions: ['.ts', '.js', '.json']
29
+ }, plugins: [ new webpack.NormalModuleReplacementPlugin(
30
+ /\.\/index/,
31
+ './build/src/bromwser.js'
32
+ ),
33
+ ],
34
+ },
35
+ singleRun: true,
36
+ reporters: ['mocha'],
37
+ plugins: [
38
+ 'karma-chrome-launcher',
39
+ 'karma-env-preprocessor',
40
+ 'karma-webpack',
41
+ 'karma-mocha',
42
+ 'karma-mocha-reporter'
43
+ ],
44
+ mime: {
45
+ 'text/x-typescript': ['ts','tsx']
46
+ },
47
+ browsers: ['Chrome'],
48
+ customLaunchers: {
49
+ Chrome_travis_ci: {
50
+ base: 'Chrome',
51
+ flags: ['--no-sandbox']
52
+ }
53
+ }
54
+ };
55
+
56
+ if(process.env.TRAVIS) {
57
+ configuration.browsers = ['Chrome_travis_ci'];
58
+ }
59
+
60
+ config.set(configuration);
61
+ }
62
+
package/package.json ADDED
@@ -0,0 +1,98 @@
1
+ {
2
+ "name": "@gsknnft/bigint-buffer",
3
+ "version": "1.2.0",
4
+ "description": "bigint to buffer conversion with native support",
5
+ "main": "dist/index.js",
6
+ "type": "module",
7
+ "browser": {
8
+ "./dist/node.js": "./dist/browser.js"
9
+ },
10
+ "types": "dist/index.d.ts",
11
+ "repository": {
12
+ "type": "git",
13
+ "url": "https://github.com/gsknnft/bigint-buffer.git"
14
+ },
15
+ "bugs": {
16
+ "url": "https://github.com/gsknnft/bigint-buffer/issues"
17
+ },
18
+ "homepage": "https://github.com/gsknnft/bigintbuffer",
19
+ "keywords": [
20
+ "bigint",
21
+ "bignum",
22
+ "tc39-bigint",
23
+ "napi"
24
+ ],
25
+ "license": "Apache-2.0",
26
+ "dependencies": {
27
+ "bindings": "^1.5.0"
28
+ },
29
+ "devDependencies": {
30
+ "@types/benchmark": "^2.1.5",
31
+ "@types/bn.js": "^5.2.0",
32
+ "@types/chai": "^5.2.3",
33
+ "@types/mocha": "^10.0.10",
34
+ "@types/node": "^24.9.1",
35
+ "benchmark": "^2.1.4",
36
+ "bn.js": "^5.2.2",
37
+ "chai": "^4.1.2",
38
+ "coveralls": "^3.1.1",
39
+ "cpy-cli": "^6.0.0",
40
+ "cross-env": "^6.0.3",
41
+ "gts": "^0.8.0",
42
+ "istanbul": "^0.4.1",
43
+ "karma": "^3.0.0",
44
+ "karma-chrome-launcher": "^2.2.0",
45
+ "karma-env-preprocessor": "^0.1.1",
46
+ "karma-mocha": "^1.3.0",
47
+ "karma-mocha-reporter": "^2.2.5",
48
+ "karma-webpack": "^3.0.0",
49
+ "microtime": "^3.0.0",
50
+ "mkdirp": "^0.5.1",
51
+ "mocha": "^5.2.0",
52
+ "pre-commit": "^1.2.2",
53
+ "rollup": "^4.52.5",
54
+ "rollup-plugin-replace": "^2.2.0",
55
+ "ts-loader": "^9.5.4",
56
+ "ts-node": "^10.9.2",
57
+ "typedoc": "^0.28.14",
58
+ "typescript": "5.9.3",
59
+ "webpack": "5.102.1",
60
+ "webpack-cli": "6.0.1"
61
+ },
62
+ "exports": {
63
+ ".": {
64
+ "import": "./dist/index.js",
65
+ "require": "./dist/index.cjs",
66
+ "types": "./dist/index.d.ts"
67
+ }
68
+ },
69
+ "engines": {
70
+ "node": ">=24.0.0"
71
+ },
72
+ "publishConfig": {
73
+ "access": "public"
74
+ },
75
+ "contributors": [
76
+ "Gordon Skinner <gsknnft@gmail.com> (https://github.com/gsknnft)",
77
+ "Michael Wei <mwei@vmware.com> (https://github.com/no2chem)"
78
+ ],
79
+ "scripts": {
80
+ "test": "npm run test:node && npm run test:browser",
81
+ "coverage": "istanbul cover ./test/index.js",
82
+ "coveralls": "npm run coverage && coveralls <coverage/lcov.info",
83
+ "lint": "gts check",
84
+ "install": "npm run rebuild || echo \"Couldn't build bindings. Non-native version used.\"",
85
+ "test:browser": "karma start karma.conf.js",
86
+ "test:node": "mocha -r ts-node/register src/**/*.spec.ts --timeout 40000",
87
+ "benchmark": "node -r ts-node/register src/index.bench.ts",
88
+ "typedoc": "typedoc --out docs $(pwd)/src $(pwd)/helper --target es6 --mode file --tsconfig ./tsconfig.json --excludePrivate --excludeProtected --excludeNotExported --exclude '**/*+(spec|bench).ts'",
89
+ "rebuild": "node-gyp rebuild",
90
+ "check": "gts check",
91
+ "clean": "gts clean",
92
+ "compile": "tsc -p . && rollup -c > dist/node.js && cross-env BROWSER=true rollup -c > dist/browser.js && cpy build/src/*.d.ts dist",
93
+ "compileOG": "mkdirp dist && tsc -p . && rollup -c > dist/node.js && cross-env BROWSER=true rollup -c > dist/browser.js && cpx \"build/src/*.d.ts\" dist",
94
+ "fix": "gts fix",
95
+ "pretest": "npm run compile",
96
+ "posttest": "npm run check"
97
+ }
98
+ }
@@ -0,0 +1,13 @@
1
+ import replace from 'rollup-plugin-replace';
2
+
3
+ export default {
4
+ input: 'build/src/index.js',
5
+ output: {
6
+ format: 'cjs'
7
+ },
8
+ plugins: [
9
+ replace({
10
+ 'process.browser': process.env.BROWSER === "true"
11
+ })
12
+ ]
13
+ };
@@ -0,0 +1,203 @@
1
+
2
+ #define NAPI_EXPERIMENTAL
3
+ #include <node_api.h>
4
+ #include <stdio.h>
5
+ #include <stdlib.h>
6
+ #include <string.h>
7
+ #include <assert.h>
8
+ #include <limits.h>
9
+
10
+ #define BIT_MASK(n) (~( ((~0ull) << ((n)-1)) << 1 ))
11
+
12
+ // The maximum size we'll store on the stack. If we need a larger temporary
13
+ // buffer malloc will be called.
14
+ #define BUFFER_STACK_SIZE 32
15
+
16
+ #if defined(_WIN16) || defined(_WIN32) || defined(_WIN64)
17
+ #define bswap64(x) _byteswap_uint64(x)
18
+ #else
19
+ #define bswap64(x) __builtin_bswap64(x)
20
+ #endif
21
+
22
+ /**
23
+ * Converts a Buffer to bigint.
24
+ * node param 0: buffer
25
+ * node param 1: big_endian (optional boolean)
26
+ *
27
+ * returns bigint
28
+ */
29
+ napi_value toBigInt (napi_env env, napi_callback_info info) {
30
+ napi_value argv[2];
31
+ napi_status status;
32
+ size_t argc = 2;
33
+
34
+ status = napi_get_cb_info(env, info, &argc, argv, NULL, NULL);
35
+ assert(status == napi_ok);
36
+
37
+ if (argc < 1) {
38
+ napi_throw_error(env, "EINVAL", "Too few arguments");
39
+ return NULL;
40
+ }
41
+
42
+ bool big_endian;
43
+ status = napi_get_value_bool(env, argv[1], &big_endian);
44
+ if (status == napi_boolean_expected) { big_endian = false; }
45
+
46
+ uint8_t* buffer;
47
+ size_t len;
48
+ status = napi_get_buffer_info(env, argv[0], (void**) &buffer, &len);
49
+ assert(status == napi_ok);
50
+
51
+ // If len is not divisible by 8 bytes, we'll need to copy
52
+ bool not_64_aligned = (len & 7) != 0;
53
+ size_t overflow_len = not_64_aligned ? 8 - (len & 0x7) : 0;
54
+ // Buffer is managed by VM, so copy it out (TODO: perhaps we can increase refcount?)
55
+ size_t aligned_len = len + overflow_len;
56
+ size_t len_in_words = not_64_aligned ? (len >> 3) + 1 : (len >> 3);
57
+ bool fits_in_stack = aligned_len <= BUFFER_STACK_SIZE;
58
+
59
+ uint8_t copy[BUFFER_STACK_SIZE];
60
+ uint8_t* bufTemp = fits_in_stack ? copy : malloc(aligned_len);
61
+ if (overflow_len > 0) {
62
+ memset(bufTemp + len, 0, overflow_len);
63
+ }
64
+ memcpy(bufTemp, buffer, len);
65
+ uint64_t* as_64_aligned = (uint64_t*) bufTemp;
66
+ size_t overflow_in_bits = overflow_len << 3; // == overflow_len * 8
67
+
68
+ napi_value out;
69
+ // swap
70
+ if (big_endian) {
71
+ if (len_in_words == 1) {
72
+ as_64_aligned[0] = not_64_aligned ? bswap64(as_64_aligned[0]) >> overflow_in_bits : bswap64(as_64_aligned[0]);
73
+ } else {
74
+ uint64_t temp;
75
+ size_t last_word = len_in_words - 1;
76
+ size_t end_ptr = last_word;
77
+ int32_t offset;
78
+ for (offset = 0; offset < (int32_t)(len_in_words / 2); offset++) {
79
+ temp = as_64_aligned[offset];
80
+ as_64_aligned[offset] = as_64_aligned[end_ptr];
81
+ as_64_aligned[end_ptr] = temp;
82
+ end_ptr--;
83
+ }
84
+ uint64_t prev_overflow = 0;
85
+ for (offset = last_word; offset >= 0; offset--) {
86
+ uint64_t as_little_endian = bswap64(as_64_aligned[offset]);
87
+ uint64_t overflow = as_little_endian & BIT_MASK(overflow_in_bits);
88
+ as_64_aligned[offset] = not_64_aligned ? (as_little_endian >> overflow_in_bits) | prev_overflow : as_little_endian;
89
+ prev_overflow = overflow << (64 - overflow_in_bits);
90
+ }
91
+ }
92
+ }
93
+
94
+ status = napi_create_bigint_words(env, 0, len_in_words, as_64_aligned , &out);
95
+ assert(status == napi_ok);
96
+
97
+ if (!fits_in_stack) {
98
+ free(bufTemp);
99
+ }
100
+
101
+ return out;
102
+ }
103
+
104
+ /**
105
+ * Converts a BigInt to a Buffer
106
+ * node param 0: BigInt
107
+ * node param 1: buffer
108
+ * node param 2: big_endian (optional boolean)
109
+ *
110
+ * returns bigint
111
+ */
112
+ napi_value fromBigInt (napi_env env, napi_callback_info info) {
113
+ napi_value argv[3];
114
+ napi_status status;
115
+ size_t argc = 3;
116
+
117
+ status = napi_get_cb_info(env, info, &argc, argv, NULL, NULL);
118
+ assert(status == napi_ok);
119
+
120
+ if (argc < 1) {
121
+ napi_throw_error(env, "EINVAL", "Too few arguments");
122
+ return NULL;
123
+ }
124
+
125
+ size_t byte_width;
126
+ bool big_endian;
127
+ status = napi_get_value_bool(env, argv[2], &big_endian);
128
+ if (status == napi_boolean_expected) { big_endian = false; }
129
+
130
+ size_t word_count;
131
+ status = napi_get_value_bigint_words(env, argv[0], NULL, &word_count, NULL);
132
+ assert(status == napi_ok);
133
+
134
+ uint8_t* raw_buffer;
135
+ status = napi_get_buffer_info(env, argv[1], (void**) &raw_buffer, &byte_width);
136
+ assert(status == napi_ok);
137
+
138
+ if (word_count == 0) {
139
+ memset(raw_buffer, 0, byte_width);
140
+ return argv[1];
141
+ }
142
+
143
+ int sign_bit = 0;
144
+
145
+ bool not_64_aligned = (byte_width & 7) != 0;
146
+ size_t overflow_len = not_64_aligned ? 8 - (byte_width & 0x7) : 0;
147
+ size_t word_width = (byte_width >> 3) + (not_64_aligned ? 1 : 0);
148
+ size_t original_word_width = word_width;
149
+ if (word_count > word_width) {
150
+ word_count = word_width;
151
+ }
152
+ size_t word_width_bytes = (word_count << 3);
153
+ bool fits_in_stack = word_width_bytes <= BUFFER_STACK_SIZE;
154
+
155
+ uint64_t* conv_buffer = (uint64_t*) raw_buffer;
156
+ uint64_t stack_buffer[BUFFER_STACK_SIZE];
157
+ if (not_64_aligned) {
158
+ conv_buffer = fits_in_stack ? stack_buffer : malloc(byte_width + overflow_len);
159
+ }
160
+
161
+ memset(conv_buffer, 0, byte_width + overflow_len);
162
+ status = napi_get_value_bigint_words(env, argv[0], &sign_bit, &word_count, conv_buffer);
163
+ assert(status == napi_ok);
164
+
165
+ if (big_endian) {
166
+ uint64_t temp;
167
+ size_t conv_words = original_word_width;
168
+ size_t last_word = conv_words - 1;
169
+ size_t end_ptr = last_word;
170
+ int32_t offset;
171
+ for (offset = 0; offset < (int32_t)(conv_words / 2); offset++) {
172
+ temp = bswap64(conv_buffer[offset]);
173
+ conv_buffer[offset] = bswap64(conv_buffer[end_ptr]);
174
+ conv_buffer[end_ptr] = temp;
175
+ end_ptr--;
176
+ }
177
+ if (conv_words & 1) {
178
+ conv_buffer[conv_words / 2] = bswap64(conv_buffer[conv_words / 2]);;
179
+ }
180
+ }
181
+ if (not_64_aligned) {
182
+ memcpy(raw_buffer, big_endian ? (uint64_t*)(((uint8_t*)conv_buffer) + (8-(byte_width & 7))) : conv_buffer, byte_width);
183
+ if (!fits_in_stack) {
184
+ free(conv_buffer);
185
+ }
186
+ }
187
+ return argv[1];
188
+ }
189
+
190
+ napi_value init_all (napi_env env, napi_value exports) {
191
+ napi_value bigint_fn;
192
+ napi_value frombigint_fn;
193
+
194
+ napi_create_function(env, NULL, 0, toBigInt, NULL, &bigint_fn);
195
+ napi_create_function(env, NULL, 0, fromBigInt, NULL, &frombigint_fn);
196
+
197
+ napi_set_named_property(env, exports, "toBigInt", bigint_fn);
198
+ napi_set_named_property(env, exports, "fromBigInt", frombigint_fn);
199
+
200
+ return exports;
201
+ }
202
+
203
+ NAPI_MODULE(NODE_GYP_MODULE_NAME, init_all);
@@ -0,0 +1,207 @@
1
+
2
+ import * as benchmark from 'benchmark';
3
+
4
+ import {toBigIntBE, toBigIntLE, toBufferBE, toBufferLE} from './index';
5
+
6
+ const BN = require('bn.js');
7
+
8
+
9
+ // This file contains the benchmark test suite. It includes the benchmark and
10
+ // some lightweight boilerplate code for running benchmark.js. To
11
+ // run the benchmarks, execute `npm run benchmark` from the package directory.
12
+ const suite = new benchmark.Suite();
13
+
14
+ interface BenchmarkRun {
15
+ name: string;
16
+ hz: number;
17
+ stats: benchmark.Stats;
18
+ }
19
+
20
+ // Tests the performance of a no-op.
21
+ suite.add('no-op', () => {});
22
+
23
+ // Test small strings (unaligned)
24
+ const smallHex = 'deadbeef';
25
+ const smallString = `0x${smallHex}`;
26
+ const smallBuf: Buffer = Buffer.from(smallHex, 'hex');
27
+ suite.add('bigint from hex string (small)', () => {
28
+ return BigInt(smallString);
29
+ });
30
+ suite.add('bigint from hex string from buffer (small)', () => {
31
+ return BigInt(`0x${smallBuf.toString('hex')}`);
32
+ });
33
+ suite.add('BN from hex string from buffer (small)', () => {
34
+ return new BN(smallBuf.toString('hex'), 16);
35
+ });
36
+ suite.add('LE bigint-buffer ToBigInt (small)', () => {
37
+ return toBigIntLE(smallBuf);
38
+ });
39
+ suite.add('BE bigint-buffer ToBigInt (small)', () => {
40
+ return toBigIntBE(smallBuf);
41
+ });
42
+
43
+ // Test mid strings (aligned)
44
+ const midHex = 'badc0ffee0ddf00d';
45
+ const midString = `0x${midHex}`;
46
+ const midBuf: Buffer = Buffer.from(midHex, 'hex');
47
+ suite.add('bigint from hex string (mid, aligned)', () => {
48
+ return BigInt(midString);
49
+ });
50
+ suite.add('bigint from hex string from buffer (mid, aligned)', () => {
51
+ return BigInt(`0x${midBuf.toString('hex')}`);
52
+ });
53
+ suite.add('BN from hex string from buffer (mid, aligned)', () => {
54
+ return new BN(midBuf.toString('hex'), 16);
55
+ });
56
+ suite.add('LE bigint-buffer ToBigInt (mid, aligned)', () => {
57
+ return toBigIntLE(midBuf);
58
+ });
59
+ suite.add('BE bigint-buffer ToBigInt (mid, aligned)', () => {
60
+ return toBigIntBE(midBuf);
61
+ });
62
+
63
+ // Test huge strings
64
+ const hugeHex =
65
+ 'badc0ffee0ddf00dbadc0ffee0ddf00dbadc0ffee0ddf00dbadc0ffee0ddf00dbadc0ffee0ddf00dbadc0ffee0ddf00d';
66
+ const hugeString = `0x${hugeHex}`;
67
+ const hugeBuf: Buffer = Buffer.from(hugeHex, 'hex');
68
+ suite.add('bigint from hex string (huge)', () => {
69
+ return BigInt(hugeString);
70
+ });
71
+ suite.add('bigint from hex string from buffer (huge)', () => {
72
+ return BigInt(`0x${hugeBuf.toString('hex')}`);
73
+ });
74
+ suite.add('BN from hex string from buffer (huge)', () => {
75
+ return new BN(hugeBuf.toString('hex'), 16);
76
+ });
77
+ suite.add('LE bigint-buffer ToBigInt (huge)', () => {
78
+ return toBigIntLE(hugeBuf);
79
+ });
80
+ suite.add('BE bigint-buffer ToBigInt (huge)', () => {
81
+ return toBigIntBE(hugeBuf);
82
+ });
83
+
84
+ const bigIntToBufferWithStringBE = (int: bigint, width: number): Buffer => {
85
+ const hex = int.toString(16);
86
+ return Buffer.from(hex.padStart(width * 2, '0').slice(0, width * 2), 'hex');
87
+ };
88
+
89
+ const bigIntToBufferWithStringLE = (int: bigint, width: number): Buffer => {
90
+ const hex = int.toString(16);
91
+ const buffer =
92
+ Buffer.from(hex.padStart(width * 2, '0').slice(0, width * 2), 'hex');
93
+ buffer.reverse();
94
+ return buffer;
95
+ };
96
+
97
+ // Test small toBuffer
98
+ const smallValue = 12345678n;
99
+ suite.add('LE bigint to hex string to buffer (small)', () => {
100
+ return bigIntToBufferWithStringLE(smallValue, 8);
101
+ });
102
+
103
+ suite.add('BE bigint to hex string to buffer (small)', () => {
104
+ return bigIntToBufferWithStringBE(smallValue, 8);
105
+ });
106
+
107
+ const bnSmallValue = new BN('12345678', 10);
108
+ suite.add('BN to buffer (small)', () => {
109
+ return bnSmallValue.toBuffer(8);
110
+ });
111
+
112
+ suite.add('LE bigint-buffer to buffer (small)', () => {
113
+ return toBufferLE(smallValue, 8);
114
+ });
115
+
116
+ suite.add('BE bigint-buffer to buffer (small)', () => {
117
+ return toBufferBE(smallValue, 8);
118
+ });
119
+
120
+
121
+ // Test large toBuffer
122
+ const largeValue =
123
+ 0xbadc0ffee0ddf00dbadc0ffee0ddf00dbadc0ffee0ddf00dbadc0ffee0ddf00dbadc0ffee0ddf00dbadc0ffee0ddf00dn;
124
+ suite.add('LE bigint to hex string to buffer (large)', () => {
125
+ return bigIntToBufferWithStringLE(largeValue, 24);
126
+ });
127
+
128
+ suite.add('BE bigint to hex string to buffer (large)', () => {
129
+ return bigIntToBufferWithStringBE(largeValue, 24);
130
+ });
131
+
132
+ const bnLargeValue = new BN(
133
+ 'badc0ffee0ddf00dbadc0ffee0ddf00dbadc0ffee0ddf00dbadc0ffee0ddf00dbadc0ffee0ddf00dbadc0ffee0ddf00d',
134
+ 16);
135
+ suite.add('BN to buffer (large)', () => {
136
+ return bnLargeValue.toBuffer(24);
137
+ });
138
+
139
+ suite.add('LE bigint-buffer to buffer (large)', () => {
140
+ return toBufferLE(largeValue, 24);
141
+ });
142
+
143
+ suite.add('BE bigint-buffer to buffer (large)', () => {
144
+ return toBufferBE(largeValue, 24);
145
+ });
146
+
147
+ suite.add('LE bigint to hex string to buffer (large)', () => {
148
+ return bigIntToBufferWithStringLE(largeValue, 8);
149
+ });
150
+
151
+ suite.add('BE bigint to hex string to buffer (large)', () => {
152
+ return bigIntToBufferWithStringBE(largeValue, 8);
153
+ });
154
+
155
+ suite.add('LE bigint-buffer to buffer (large, truncated)', () => {
156
+ return toBufferLE(largeValue, 8);
157
+ });
158
+
159
+ suite.add('BE bigint-buffer to buffer (large, truncated)', () => {
160
+ return toBufferBE(largeValue, 8);
161
+ });
162
+
163
+ const b1 = Buffer.from('0123456789ABCDEF0123456789ABCDEF', 'hex');
164
+ const b2 = Buffer.from('0123456789ABCDEF0123456789ABCDEF', 'hex');
165
+ const bn1 = new BN('0123456789ABCDEF0123456789ABCDEF', 'hex');
166
+ const bn2 = new BN('0123456789ABCDEF0123456789ABCDEF', 'hex');
167
+ const n1 = 0x0123456789ABCDEF0123456789ABCDEFn;
168
+ const n2 = 0x0123456789ABCDEF0123456789ABCDEFn;
169
+ suite.add('Buffer equality comparison', () => {
170
+ return b1.compare(b2) === 0;
171
+ });
172
+
173
+ suite.add('BN equality comparison', () => {
174
+ return bn1.eq(bn2);
175
+ });
176
+
177
+ suite.add('bigint equality comparison', () => {
178
+ return n1 === n2;
179
+ });
180
+
181
+ suite.add('BN multiply', () => {
182
+ return bn1.mul(bn2);
183
+ });
184
+
185
+ suite.add('bigint multiply', () => {
186
+ return n1 * n2;
187
+ });
188
+
189
+ //#endregion
190
+
191
+
192
+ // Reporter for each benchmark
193
+ suite.on('cycle', (event: benchmark.Event) => {
194
+ const benchmarkRun: BenchmarkRun = event.target as BenchmarkRun;
195
+ const stats = benchmarkRun.stats as benchmark.Stats;
196
+ const meanInNanos = (stats.mean * 1000000000).toFixed(2);
197
+ const stdDevInNanos = (stats.deviation * 1000000000).toFixed(3);
198
+ const runs = stats.sample.length;
199
+ const ops = benchmarkRun.hz.toFixed(benchmarkRun.hz < 100 ? 2 : 0);
200
+ const err = stats.rme.toFixed(2);
201
+
202
+ console.log(`${benchmarkRun.name}: ${ops}±${err}% ops/s ${meanInNanos}±${
203
+ stdDevInNanos} ns/op (${runs} run${runs === 0 ? '' : 's'})`);
204
+ });
205
+
206
+ // Runs the test suite
207
+ suite.run();