Giter Site home page Giter Site logo

no2chem / bigint-buffer Goto Github PK

View Code? Open in Web Editor NEW
54.0 4.0 11.0 863 KB

💪🔢 bigint-buffer: Buffer Utilities for TC39 BigInt Proposal

License: Apache License 2.0

Python 0.42% JavaScript 7.07% C 23.52% TypeScript 68.99%
bigint tc39 buffer napi node nodejs typescript

bigint-buffer's Introduction

💪🔢 bigint-buffer: Buffer Utilities for TC39 BigInt Proposal

NPM Package Build Status Coverage Status node

bigint-buffer is a utility converts TC39 Proposed BigInts to and from buffers. This utility is necessary because BigInts, as proposed, do not support direct conversion between Buffers (or UInt8Arrays), but rather require conversion from buffers to hexadecimal strings then to BigInts, which is suboptimal. This utility includes N-API bindings, so under node, conversion is performed without generating a hexadecimal string. In the browser, normal string conversion is used.

Why use BigInts?

BigInts are currently a stage 3 proposal, supported in Node 10 and V8 v6.7. BigInts are primitive arbitrary precision integers, overcoming the limitations of the number type in javascript, which only supports up to 53 bits of precision.

In many applications, manipulating 64, 128 or even 256 bit numbers is quite common. For example, database identifiers are often 128 bits, and hashes are often 256 bits (If you're looking for hashing support, try out bigint-hash). Before BigInts, manipulating these numbers safely required either allocating a Buffer or UInt8Arrays, which is quite expensive compared to a number, since Buffers are allocated on the heap.

BigInts solve this problem by introducing a primitive that can hold arbitrary precision integers, reducing memory pressure and allowing the runtime to better optimize arithmetic operations. This results in significant performance improvements - 10x-100x for simple equality comparisons (using === vs Buffer.compare()):

Buffer equality comparison: 11916844±4.23% ops/s 83.91±17.293 ns/op (91 runs)
bigint equality comparison: 798024851±0.29% ops/s 1.25±0.017 ns/op (91 runs)

Before BigInts, you probably used a library such as the widely used bn.js. bn.js fares a little better than a plain Buffer, but is still 5-10x slower than the bigint:

BN equality comparison: 73255774±0.67% ops/s 13.65±0.442 ns/op (89 runs)

bigints are also much better with arithmetic, here are the results compared to BN for multiplying two 128-bit integers, yielding a 4x improvement:

BN multiply: 4763236±0.49% ops/s 209.94±5.111 ns/op (93 runs)
bigint multiply: 15268666±0.92% ops/s 65.49±2.938 ns/op (92 runs)

So what's the problem?

BigInts, unfortunately lack an efficient way to be converted back and forth between buffers. When dealing with serialized data or legacy node code, you'll often want to generate a BigInt from a buffer, or convert a BigInt to a Buffer in order to send a BigInt over the wire.

Currently, the only method to generate a new BigInt is with the BigInt constructor. Unfortunately, it doesn't support Buffers, though it may in the future:

> BigInt(Buffer.from([1]))
SyntaxError: Cannot convert  to a BigInt

Instead, you need to convert the Buffer to a hexadecimal string of the correct format. For example:

> BigInt(`0x${buf.toString('hex')}`);
1n

These conversions are not only quite expensive, but obviate a lot of the performance gains we get from BigInts. For example, on a large buffer, this conversion can take over 100x the time to do a comparison:

bigint from hex string from buffer (huge): 1230607±1.02% ops/s 812.61±40.013 ns/op (89 runs)

And... bigint-buffer helps how?

bigint-buffer introduces four functions for conversion between buffers and bigints. A small example follows:

import {toBigIntBE, toBigIntLE, toBufferBE, toBufferLE} from 'bigint-buffer';

// Get a big endian buffer of the given width
toBufferBE(0xdeadbeefn, 8);
// ↪ <Buffer 00 00 00 00 de ad be ef>

// Get a little endian buffer of the given width
toBufferLE(0xdeadbeefn, 8);
// ↪ <Buffer ef be ad de 00 00 00 00>

// Get a BigInt from a buffer in big endian format
toBigIntBE(Buffer.from('deadbeef', 'hex'));
// ↪ 3735928559n (0xdeadbeefn)

// Get a BigInt from a buffer in little endian format
toBigIntLE(Buffer.from('deadbeef', 'hex'));
// ↪ 4022250974n (0xefbeadd0en)

bigint-buffer uses N-API native bindings to perform the conversion efficiently without generating the immediate hex strings necessary in pure javascript. This results in a significant performance increase, about 2x for small buffer to bigint conversions, and 8x better than BN:

BN to buffer (small): 981703±68.30% ops/s 1018.64±3194.648 ns/op (81 runs)
bigint from hex string from buffer (small): 2804915±5.00% ops/s 356.52±85.371 ns/op (88 runs)
LE bigint-buffer ToBigInt (small): 5932704±1.62% ops/s 168.56±12.971 ns/op (87 runs)

And about 3.3x for bigint to buffer conversions, and 17x better than BN:

BN to buffer (large): 339437±2.85% ops/s 2946.06±385.504 ns/op (81 runs)
BE bigint to hex string to buffer (large): 1714292±1.35% ops/s 583.33±37.995 ns/op (90 runs)
BE bigint-buffer to buffer (large, truncated): 5977218±4.68% ops/s 167.30±37.284 ns/op (87 runs)

You can run the benchmarks by running npm run benchmark.

Typescript Support

bigint-buffer supplies typescript bindings, but BigInts are still not supported in typescript, though a pull request has been opened, so support should be coming soon. If you are using typescript, @calebsander has put up a pull request and the instructions in this post.

Install

Add bigint-buffer to your project with:

npm install bigint-buffer

Documentation

Basic API documentation can be found here. Note that v1.0.0 changes the name of the original functions to meet style guidelines.

Benchmarks

Benchmarks can be run by executing npm run benchmark from the package directory.

bigint-buffer's People

Contributors

dependabot[bot] avatar ghidosoft avatar no2chem avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

bigint-buffer's Issues

build failed but install success?

I use npm install bigint-buffer in windows, it build failed but install success.
How could build success?
This is the logs.

Microsoft Windows [Version 10.0.17763.348]
(c) 2018 Microsoft Corporation. All rights reserved.

D:\Code\JavaScript\trader>npm install bigint-buffer

> [email protected] install D:\Code\JavaScript\trader\node_modules\bigint-buffer
> npm run rebuild || echo "Couldn't build bindings. Non-native version used."


> [email protected] rebuild D:\Code\JavaScript\trader\node_modules\bigint-buffer
> node-gyp rebuild


D:\Code\JavaScript\trader\node_modules\bigint-buffer>if not defined npm_config_node_gyp (node "D:\Package\Node\node_modules\npm\node_modules\npm-lifecycle\
node-gyp-bin\\..\..\node_modules\node-gyp\bin\node-gyp.js" rebuild )  else (node "D:\Package\Node\node_modules\npm\node_modules\node-gyp\bin\node-gyp.js" r
ebuild )
Building the projects in this solution one at a time. To enable parallel build, please add the "/m" switch.
  bigint-buffer.c
d:\code\javascript\trader\node_modules\bigint-buffer\src\bigint-buffer.c(53): error C2057: expected constant expression [D:\Code\JavaScript\trader\node_mo
dules\bigint-buffer\build\bigint_buffer.vcxproj]
d:\code\javascript\trader\node_modules\bigint-buffer\src\bigint-buffer.c(53): error C2466: cannot allocate an array of constant size 0 [D:\Code\JavaScript
\trader\node_modules\bigint-buffer\build\bigint_buffer.vcxproj]
d:\code\javascript\trader\node_modules\bigint-buffer\src\bigint-buffer.c(53): error C2133: 'copy': unknown size [D:\Code\JavaScript\trader\node_modules\bi
gint-buffer\build\bigint_buffer.vcxproj]
d:\code\javascript\trader\node_modules\bigint-buffer\src\bigint-buffer.c(66): warning C4013: '__builtin_bswap64' undefined; assuming extern returning int 
[D:\Code\JavaScript\trader\node_modules\bigint-buffer\build\bigint_buffer.vcxproj]
d:\code\javascript\trader\node_modules\bigint-buffer\src\bigint-buffer.c(151): error C2057: expected constant expression [D:\Code\JavaScript\trader\node_m
odules\bigint-buffer\build\bigint_buffer.vcxproj]
d:\code\javascript\trader\node_modules\bigint-buffer\src\bigint-buffer.c(151): error C2466: cannot allocate an array of constant size 0 [D:\Code\JavaScrip
t\trader\node_modules\bigint-buffer\build\bigint_buffer.vcxproj]
d:\code\javascript\trader\node_modules\bigint-buffer\src\bigint-buffer.c(151): error C2133: 'stack_buffer': unknown size [D:\Code\JavaScript\trader\node_m
odules\bigint-buffer\build\bigint_buffer.vcxproj]
gyp ERR! build error
gyp ERR! stack Error: `C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin\MSBuild.exe` failed with exit code: 1
gyp ERR! stack     at ChildProcess.onExit (D:\Package\Node\node_modules\npm\node_modules\node-gyp\lib\build.js:262:23)
gyp ERR! stack     at ChildProcess.emit (events.js:189:13)
gyp ERR! stack     at Process.ChildProcess._handle.onexit (internal/child_process.js:248:12)
gyp ERR! System Windows_NT 10.0.17763
gyp ERR! command "D:\\GreenApps\\Node\\node.exe" "D:\\Package\\Node\\node_modules\\npm\\node_modules\\node-gyp\\bin\\node-gyp.js" "rebuild"
gyp ERR! cwd D:\Code\JavaScript\trader\node_modules\bigint-buffer
gyp ERR! node -v v10.15.2
gyp ERR! node-gyp -v v3.8.0
gyp ERR! not ok
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] rebuild: `node-gyp rebuild`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] rebuild script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm WARN Local package.json exists, but node_modules missing, did you mean to install?

npm ERR! A complete log of this run can be found in:
npm ERR!     Z:\Temp\npm-cache\_logs\2019-03-12T03_15_47_934Z-debug.log
"Couldn't build bindings. Non-native version used."
npm WARN @ant-design/[email protected] requires a peer of @ant-design/icons@~1.1.0 but none is installed. You must install peer dependencies yourself.
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: [email protected] (node_modules
\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for [email protected]: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"
x64"})

+ [email protected]

mocha failure

Hi. I am trying to change parquetjs to support 64 bit integers using bigint-buffer. The change seems straightforward and works in client code I have. However, I want to update parquetjs tests to reflect my change, and when I try to run their test I see this failure:

`$ npm test

[email protected] test /home/***/parquetjs
mocha

ParquetCodec::PLAIN
✓ should encode BOOLEAN values
✓ should decode BOOLEAN values
✓ should encode INT32 values
✓ should decode INT32 values
node: ../src/bigint-buffer.c:132: fromBigInt: Assertion status == napi_ok' failed. Aborted (core dumped)
I gather this is something related to native modules, but I'm a n00b in that regard. Any ideas?

Interest in a `bigint-uint8array` library?

Buffer is node only, while Uint8Array is part of ES spec and available on browser and Node. Because of this, I use Uint8Array everywhere rather than Buffer. It would be nice if a library similar to this one existed that supported Uint8Array rather than Buffer.

TypeScript 3.2 support

Finally ts 3.2 supports bigint with esnext target without the need to polyfill BigInt.

would you consider migrating to ts 3.2? tkz

signed/negative bigint are not handled

Apparently the library can't handle negative values (both encoding and decoding)

console.log(toBufferLE(-1n, 1));
console.log(toBufferLE(1n, 1));

outputs
<Buffer 01>
<Buffer 01>

but it should really not be the case.

Fails on node 10.4.0 - 10.6.0 with `symbol lookup error: [...] undefined symbol: napi_create_bigint_words`

BigInt was introduced in node 10.4.0 (which uses V8 v6.7), which is why I started testing at this version.

Test run output:

david @ ~/work/bigint-buffer (master)
└─ $ ▶ npm run test:node

> [email protected] test:node /home/david/work/bigint-buffer
> mocha -r ts-node/register src/**/*.spec.ts --timeout 40000



  Try buffer conversion (little endian)
/home/david/.nvm/versions/node/v10.6.0/bin/node: symbol lookup error: /home/david/work/bigint-buffer/build/Release/bigint_buffer.node: undefined symbol: napi_create_bigint_words
npm ERR! file sh
npm ERR! code ELIFECYCLE
npm ERR! errno ENOENT
npm ERR! syscall spawn
npm ERR! [email protected] test:node: `mocha -r ts-node/register src/**/*.spec.ts --timeout 40000`
npm ERR! spawn ENOENT
npm ERR! 
npm ERR! Failed at the [email protected] test:node script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /home/david/.npm/_logs/2020-04-24T00_49_18_551Z-debug.log

Node versions 10.4.0, 10.4.1, 10.5.0, and 10.6.0 all fail. It does work on 10.7.0 and up.

The project's package.json "engines" section is:

"engines": {
  "node": ">= 10.0.0"
}

Would you like a PR updating the engines section to reflect the actual working node versions?

Core dump when calling toBufferLE with length 0

> bigintBuffer.toBufferLE(8n, 4)
<Buffer 08 00 00 00>
> bigintBuffer.toBufferLE(8n, 0)
node: ../src/bigint-buffer.c:163: fromBigInt: Assertion `status == napi_ok' failed.
Aborted (core dumped)

Node gyp failed

I'am use package bigint-buffer "^1.1.5" in electron application. After update package electron-builder, project don't builded. There is a error.


Error: spawn C:\Program Files\Microsoft Visual Studio\2022\Community\Msbuild\Current\Bin ENOENT
    at Process.ChildProcess._handle.onexit (node:internal/child_process:285:19)
    at onErrorNT (node:internal/child_process:485:16)
    at processTicksAndRejections (node:internal/process/task_queues:83:21)
Emitted 'error' event on ChildProcess instance at:
    at Process.ChildProcess._handle.onexit (node:internal/child_process:291:12)
    at onErrorNT (node:internal/child_process:485:16)
    at processTicksAndRejections (node:internal/process/task_queues:83:21) {
  errno: -4058,
  code: 'ENOENT',
  syscall: 'spawn C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\Msbuild\\Current\\Bin',
  path: 'C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\Msbuild\\Current\\Bin',
  spawnargs: [
    'build/binding.sln',
    '/clp:Verbosity=minimal',
    '/nologo',
    '/p:Configuration=Release;Platform=x64'
  ]
}

  ⨯ node-gyp failed to rebuild 'C:\Users\admin\wd\node_modules\bigint-buffer'  failedTask=build stackTrace=Error: node-gyp
failed to rebuild 'C:\Users\admin\wd\node_modules\bigint-buffer'
    at ChildProcess.<anonymous> (C:\Users\admin\wd\node_modules\@electron\rebuild\src\module-type\node-gyp\node-gyp.ts:131:
16)
    at ChildProcess.emit (node:events:513:28)
    at Process.ChildProcess._handle.onexit (node:internal/child_process:293:12)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.