From 458d4a073fd2eea721f963729ab4fa3c6f806a37 Mon Sep 17 00:00:00 2001 From: Karsten Schmidt Date: Tue, 16 Oct 2018 23:09:30 +0100 Subject: [PATCH] feat(binary): add @thi.ng/binary package --- packages/binary/.npmignore | 10 ++ packages/binary/LICENSE | 201 +++++++++++++++++++++++++++++ packages/binary/README.md | 47 +++++++ packages/binary/package.json | 47 +++++++ packages/binary/src/align.ts | 17 +++ packages/binary/src/api.ts | 28 ++++ packages/binary/src/count.ts | 43 ++++++ packages/binary/src/edit.ts | 37 ++++++ packages/binary/src/float.ts | 30 +++++ packages/binary/src/gray.ts | 25 ++++ packages/binary/src/index.ts | 12 ++ packages/binary/src/logic.ts | 43 ++++++ packages/binary/src/mask.ts | 34 +++++ packages/binary/src/pow.ts | 24 ++++ packages/binary/src/rotate.ts | 19 +++ packages/binary/src/splat.ts | 55 ++++++++ packages/binary/src/swizzle.ts | 91 +++++++++++++ packages/binary/test/index.ts | 6 + packages/binary/test/tsconfig.json | 10 ++ packages/binary/tsconfig.json | 9 ++ 20 files changed, 788 insertions(+) create mode 100644 packages/binary/.npmignore create mode 100644 packages/binary/LICENSE create mode 100644 packages/binary/README.md create mode 100644 packages/binary/package.json create mode 100644 packages/binary/src/align.ts create mode 100644 packages/binary/src/api.ts create mode 100644 packages/binary/src/count.ts create mode 100644 packages/binary/src/edit.ts create mode 100644 packages/binary/src/float.ts create mode 100644 packages/binary/src/gray.ts create mode 100644 packages/binary/src/index.ts create mode 100644 packages/binary/src/logic.ts create mode 100644 packages/binary/src/mask.ts create mode 100644 packages/binary/src/pow.ts create mode 100644 packages/binary/src/rotate.ts create mode 100644 packages/binary/src/splat.ts create mode 100644 packages/binary/src/swizzle.ts create mode 100644 packages/binary/test/index.ts create mode 100644 packages/binary/test/tsconfig.json create mode 100644 packages/binary/tsconfig.json diff --git a/packages/binary/.npmignore b/packages/binary/.npmignore new file mode 100644 index 0000000000..d703bda97a --- /dev/null +++ b/packages/binary/.npmignore @@ -0,0 +1,10 @@ +build +coverage +dev +doc +src* +test +.nyc_output +tsconfig.json +*.tgz +*.html diff --git a/packages/binary/LICENSE b/packages/binary/LICENSE new file mode 100644 index 0000000000..8dada3edaf --- /dev/null +++ b/packages/binary/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/binary/README.md b/packages/binary/README.md new file mode 100644 index 0000000000..e5ea94fe48 --- /dev/null +++ b/packages/binary/README.md @@ -0,0 +1,47 @@ +# @thi.ng/binary + +[![npm (scoped)](https://img.shields.io/npm/v/@thi.ng/binary.svg)](https://www.npmjs.com/package/@thi.ng/binary) +![npm downloads](https://img.shields.io/npm/dm/@thi.ng/binary.svg) +[![Twitter Follow](https://img.shields.io/twitter/follow/thing_umbrella.svg?style=flat-square&label=twitter)](https://twitter.com/thing_umbrella) + +This project is part of the +[@thi.ng/umbrella](https://github.com/thi-ng/umbrella/) monorepo. + + + +- [About](#about) +- [Installation](#installation) +- [Dependencies](#dependencies) +- [Usage examples](#usage-examples) +- [Authors](#authors) +- [License](#license) + + + +## About + +Collection of 50+ binary / bitwise operations, conversions, utilities. + +## Installation + +```bash +yarn add @thi.ng/binary +``` + +## Dependencies + +None. + +## Usage examples + +```ts +import * as b from "@thi.ng/binary"; +``` + +## Authors + +- Karsten Schmidt + +## License + +© 2018 Karsten Schmidt // Apache Software License 2.0 diff --git a/packages/binary/package.json b/packages/binary/package.json new file mode 100644 index 0000000000..63a9081ffe --- /dev/null +++ b/packages/binary/package.json @@ -0,0 +1,47 @@ +{ + "name": "@thi.ng/binary", + "version": "0.0.1", + "description": "Assorted binary / bitwise operations, conversions, utilities.", + "main": "./index.js", + "typings": "./index.d.ts", + "repository": { + "type": "git", + "url": "https://github.com/thi-ng/umbrella.git" + }, + "homepage": "https://github.com/thi-ng/umbrella/tree/master/packages/binary", + "author": "Karsten Schmidt ", + "license": "Apache-2.0", + "scripts": { + "build": "yarn run clean && tsc --declaration", + "clean": "rm -rf *.js *.d.ts .nyc_output build coverage doc", + "cover": "yarn test && nyc report --reporter=lcov", + "doc": "node_modules/.bin/typedoc --mode modules --out doc src", + "pub": "yarn run build && yarn publish --access public", + "test": "rm -rf build && tsc -p test && nyc mocha build/test/*.js" + }, + "devDependencies": { + "@types/mocha": "^5.2.5", + "@types/node": "^10.5.5", + "mocha": "^5.2.0", + "nyc": "^12.0.2", + "typedoc": "^0.11.1", + "typescript": "^3.0.1" + }, + "dependencies": {}, + "keywords": [ + "alignment", + "binary", + "bitwise", + "conversion", + "ES6", + "gray code", + "logic", + "math", + "splat", + "swizzle", + "typescript" + ], + "publishConfig": { + "access": "public" + } +} \ No newline at end of file diff --git a/packages/binary/src/align.ts b/packages/binary/src/align.ts new file mode 100644 index 0000000000..244e13c848 --- /dev/null +++ b/packages/binary/src/align.ts @@ -0,0 +1,17 @@ +import { Pow2 } from "./api"; + +/** + * Aligns `addr` to next multiple of `size`. The latter must be a power + * of 2. + * + * @param addr + * @param size + */ +export const align = (addr: number, size: Pow2) => + (size-- , (addr + size) & ~size); + +/** + * Returns true if `addr` is aligned to wordsize `size`. + */ +export const isAligned = (addr: number, size: Pow2) => + !(addr & (size - 1)); diff --git a/packages/binary/src/api.ts b/packages/binary/src/api.ts new file mode 100644 index 0000000000..c1ced3c2b3 --- /dev/null +++ b/packages/binary/src/api.ts @@ -0,0 +1,28 @@ +export type Lane8 = + 0 | 1 | 2 | 3; + +export type Lane4 = + 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7; + +export type Lane2 = + 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | + 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15; + +export type Bit = + 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | + 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | + 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | + 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31; + +export type Pow2 = + 0x1 | 0x2 | 0x4 | 0x8 | + 0x10 | 0x20 | 0x40 | 0x80 | + 0x100 | 0x200 | 0x400 | 0x800 | + 0x1000 | 0x2000 | 0x4000 | 0x8000 | + 0x10000 | 0x20000 | 0x40000 | 0x80000 | + 0x100000 | 0x200000 | 0x400000 | 0x800000 | + 0x1000000 | 0x2000000 | 0x4000000 | 0x8000000 | + 0x10000000 | 0x20000000 | 0x40000000 | 0x80000000; + +export const MASKS = + new Array(33).fill(0).map((_, i) => Math.pow(2, i) - 1); diff --git a/packages/binary/src/count.ts b/packages/binary/src/count.ts new file mode 100644 index 0000000000..518ff022a1 --- /dev/null +++ b/packages/binary/src/count.ts @@ -0,0 +1,43 @@ +/** + * Returns number of 1 bits in `x`. + * + * @param x + */ +export const popCount = (x: number) => ( + x = x - ((x >>> 1) & 0x55555555), + x = (x & 0x33333333) + ((x >>> 2) & 0x33333333), + ((x + (x >>> 4) & 0xf0f0f0f) * 0x1010101) >>> 24 +); + +/** + * https://en.wikipedia.org/wiki/Hamming_distance + * + * @param x + * @param y + */ +export const hammingDist = (x: number, y: number) => + popCount(x ^ y); + +/** + * Math.clz32() polyfill (corrected). + * + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/clz32$revision/1426816 + * + * @param x + */ +export const clz32 = (x: number) => + x !== 0 ? + 31 - ((Math.log(x >>> 0) / Math.LN2) | 0) : + 32; + +export const ctz32 = (x: number) => { + let c = 32; + x &= -x; + x && (c--); + (x & 0x0000ffff) && (c -= 16); + (x & 0x00ff00ff) && (c -= 8); + (x & 0x0f0f0f0f) && (c -= 4); + (x & 0x33333333) && (c -= 2); + (x & 0x55555555) && (c -= 1); + return c; +}; diff --git a/packages/binary/src/edit.ts b/packages/binary/src/edit.ts new file mode 100644 index 0000000000..733af78138 --- /dev/null +++ b/packages/binary/src/edit.ts @@ -0,0 +1,37 @@ +import { Bit } from "./api"; +import { defMask } from "./mask"; + +/** + * Clears bit in given uint `x`. + * + * @param x value + * @param bit bit number (0..31) + */ +export const bitClear = (x: number, bit: Bit) => + (x & ~(1 << bit)) >>> 0; + +/** + * Toggles bit in given uint `x`. + * + * @param x + * @param bit + */ +export const bitFlip = (x: number, bit: Bit) => + (x ^ (1 << bit)) >>> 0; + +/** + * Sets bit in given uint `x`. + * + * @param x value + * @param bit bit number (0..31) + */ +export const bitSet = (x: number, bit: Bit) => + (x | (1 << bit)) >>> 0; + +export const bitSetWindow = (x: number, y: number, from: number, to: number) => { + const m = defMask(from, to); + return (x & ~m) | ((y << (1 << from)) & m); +}; + +export const bitClearWindow = (x: number, from: number, to: number) => + (x & ~defMask(from, to)); diff --git a/packages/binary/src/float.ts b/packages/binary/src/float.ts new file mode 100644 index 0000000000..f6a204a7c2 --- /dev/null +++ b/packages/binary/src/float.ts @@ -0,0 +1,30 @@ +const F32 = new Float32Array(1); +const I32 = new Int32Array(F32.buffer); +const U32 = new Uint32Array(F32.buffer); + +export const floatToIntBits = (x: number) => + (F32[0] = x, I32[0]); + +export const floatToUintBits = (x: number) => + (F32[0] = x, U32[0]); + +export const intBitsToFloat = (x: number) => + (I32[0] = x, F32[0]); + +export const uintBitsToFloat = (x: number) => + (U32[0] = x, F32[0]); + +/** + * Converts given float into a sortable integer representation, using + * raw bitwise conversion via `floatToIntBits()`. + * + * https://github.com/tzaeschke/phtree/blob/master/PhTreeRevisited.pdf + * (page 3) + * + * @param x + */ +export const floatToSortableInt = (x: number) => { + if (x === -0) x = 0; + const i = floatToIntBits(x); + return x < 0 ? (~i) | (1 << 31) : i; +}; diff --git a/packages/binary/src/gray.ts b/packages/binary/src/gray.ts new file mode 100644 index 0000000000..abd891d4a4 --- /dev/null +++ b/packages/binary/src/gray.ts @@ -0,0 +1,25 @@ +/** + * Converts 32bit unsigned int to Gray code (reflected binary). Gray + * codes of successive values always have a Hamming distance of 1 (i.e. + * only 1 bit changes at a time). + * + * https://en.wikipedia.org/wiki/Gray_code + * + * @param x u32 + */ +export const encodeGray32 = (x: number) => + (x ^ (x >>> 1)) >>> 0; + +/** + * Converts 32bit Gray code to binary / unsigned int. + * + * https://en.wikipedia.org/wiki/Gray_code + */ +export const decodeGray32 = (x: number) => { + x = x ^ (x >>> 16); + x = x ^ (x >>> 8); + x = x ^ (x >>> 4); + x = x ^ (x >>> 2); + x = x ^ (x >>> 1); + return x >>> 0; +}; diff --git a/packages/binary/src/index.ts b/packages/binary/src/index.ts new file mode 100644 index 0000000000..06b4af8f41 --- /dev/null +++ b/packages/binary/src/index.ts @@ -0,0 +1,12 @@ +export * from "./api"; +export * from "./align"; +export * from "./count"; +export * from "./edit"; +export * from "./float"; +export * from "./gray"; +export * from "./logic"; +export * from "./mask"; +export * from "./pow"; +export * from "./rotate"; +export * from "./splat"; +export * from "./swizzle"; diff --git a/packages/binary/src/logic.ts b/packages/binary/src/logic.ts new file mode 100644 index 0000000000..4e9e03ee0e --- /dev/null +++ b/packages/binary/src/logic.ts @@ -0,0 +1,43 @@ +import { maskL } from "./mask"; + +export const bitNot = (n: number, x: number) => + maskL(n, ~x); + +export const bitAnd = (n: number, a: number, b: number) => + maskL(n, a & b); + +export const bitNand = (n: number, a: number, b: number) => + maskL(n, ~(a & b)); + +export const bitOr = (n: number, a: number, b: number) => + maskL(n, a | b); + +export const bitNor = (n: number, a: number, b: number) => + maskL(n, ~(a & b)); + +export const bitXor = (n: number, a: number, b: number) => + maskL(n, a ^ b); + +export const bitXnor = (n: number, a: number, b: number) => + maskL(n, ~(a ^ b)); + +export const bitImply = (n: number, a: number, b: number) => + maskL(n, (~a) | b); + +export const bitAoi21 = (n: number, a: number, b: number, c: number) => + maskL(n, ~(a | (b & c))); + +export const bitOai21 = (n: number, a: number, b: number, c: number) => + maskL(n, ~(a & (b | c))); + +export const bitAoi22 = (n: number, a: number, b: number, c: number, d: number) => + maskL(n, ~((a & b) | (c & d))); + +export const bitOai22 = (n: number, a: number, b: number, c: number, d: number) => + maskL(n, ~((a | b) & (c | d))); + +export const bitMux = (n: number, a: number, b: number, s: number) => + maskL(n, (a & ~s) | (b & s)); + +export const bitDemux = (n: number, a: number, b: number, s: number): [number, number] => + [maskL(n, a & ~s), maskL(n, b & s)]; diff --git a/packages/binary/src/mask.ts b/packages/binary/src/mask.ts new file mode 100644 index 0000000000..a929ea38af --- /dev/null +++ b/packages/binary/src/mask.ts @@ -0,0 +1,34 @@ +import { MASKS } from "./api"; + +/** + * Creates bit mask by enabling bit `a` to bit `b-1`, both in range + * 0-32. `b` MUST be >= `a`. + * + * ``` + * defMask(1,31).toString(16) // 7ffffffe + * defMask(3,8).toString(16) // f8 + * ``` + * + * @param a + * @param b + */ +export const defMask = (a: number, b: number) => + ((~MASKS[a]) & MASKS[b]) >>> 0; + +/** + * Returns unsigned version of `x` with only lowest `n` bits. + * + * @param n + * @param x + */ +export const maskL = (n: number, x: number) => + (x & MASKS[n]) >>> 0; + +/** + * Returns unsigned version of `x` with only highest `n` bits. + * + * @param n + * @param x + */ +export const maskH = (n: number, x: number) => + (x & ~MASKS[n]) >>> 0; diff --git a/packages/binary/src/pow.ts b/packages/binary/src/pow.ts new file mode 100644 index 0000000000..e69be6503d --- /dev/null +++ b/packages/binary/src/pow.ts @@ -0,0 +1,24 @@ +// http://graphics.stanford.edu/~seander/bithacks.html + +export const isPow2 = (x: number) => + (!!x) && !(x & (x - 1)); + +export const ceilPow2 = (x: number) => { + x += (x === 0); + --x; + x |= x >>> 1; + x |= x >>> 2; + x |= x >>> 4; + x |= x >>> 8; + x |= x >>> 16; + return x + 1; +}; + +export const floorPow2 = (x: number) => { + x |= x >>> 1; + x |= x >>> 2; + x |= x >>> 4; + x |= x >>> 8; + x |= x >>> 16; + return x - (x >>> 1); +}; diff --git a/packages/binary/src/rotate.ts b/packages/binary/src/rotate.ts new file mode 100644 index 0000000000..61bab66df9 --- /dev/null +++ b/packages/binary/src/rotate.ts @@ -0,0 +1,19 @@ +import { Bit } from "./api"; + +/** + * Rotates `x` `n` bits to the left. + * + * @param x + * @param n + */ +export const rotateLeft = (x: number, n: Bit) => + ((x << n) | (x >>> (32 - n))) >>> 0; + +/** + * Rotates `x` `n` bits to the right. + * + * @param x + * @param n + */ +export const rotateRight = (x: number, n: Bit) => + ((x >>> n) | (x << (32 - n))) >>> 0; diff --git a/packages/binary/src/splat.ts b/packages/binary/src/splat.ts new file mode 100644 index 0000000000..175e6c6dbc --- /dev/null +++ b/packages/binary/src/splat.ts @@ -0,0 +1,55 @@ +/** + * Repeats lowest nibble of `x` as 24 bit uint. + * + * @param x + */ +export const splat4_24 = (x: number) => + (x &= 0xf, splat8_24(x | x << 4)); + +/** + * Repeats lowest nibble of `x` as 32 bit uint. + * + * @param x + */ +export const splat4_32 = (x: number) => + (x &= 0xf, splat8_32(x | x << 4)); + +/** + * Repeats lowest byte of `x` as 24 bit uint. + * + * @param x + */ +export const splat8_24 = (x: number) => + (x & 0xff) * 0x010101; + +/** + * Repeats lowest byte of `x` as 32 bit uint. + * + * @param x + */ +export const splat8_32 = (x: number) => + ((x & 0xff) * 0x01010101) >>> 0; + +/** + * Repeats lowest 16bit of `x` as 32 bit uint. + * + * @param x + */ +export const splat16_32 = (x: number) => + (x &= 0xffff, ((x << 16) | x) >>> 0); + +/** + * Returns true if bits 0-3 are same as bits 4-7. + * + * @param x + */ +export const same4 = (x: number) => + (x >> 4 & 0xf) === (x & 0xf); + +/** + * Returns true if bits 0-7 are same as bits 8-15. + * + * @param x + */ +export const same8 = (x: number) => + (x >> 8 & 0xff) === (x & 0xff); diff --git a/packages/binary/src/swizzle.ts b/packages/binary/src/swizzle.ts new file mode 100644 index 0000000000..cb83e5eec0 --- /dev/null +++ b/packages/binary/src/swizzle.ts @@ -0,0 +1,91 @@ +import { Lane2, Lane4, Lane8 } from "./api"; + +/** + * Extracts 8-bit lane from given 32bit uint. + * + * - Lane #0: bits 24-31 + * - Lane #1: bits 16-23 + * - Lane #2: bits 8-15 + * - Lane #3: bits 0-7 + * + * @param x + * @param l + */ +export const lane8 = (x: number, l: Lane8) => + (x >>> ((3 - l) << 3)) & 0xff; + +/** + * Extracts 4-bit lane from given 32bit uint. + * + * - Lane #0: bits 28-31 + * - Lane #1: bits 24-27 + * - Lane #2: bits 20-23 + * - Lane #3: bits 16-19 + * - Lane #4: bits 12-15 + * - Lane #5: bits 8-11 + * - Lane #6: bits 4-7 + * - Lane #7: bits 0-3 + * + * @param x + * @param l + */ +export const lane4 = (x: number, l: Lane4) => + (x >>> ((7 - l) << 2)) & 0xf; + +export const lane2 = (x: number, l: Lane2) => + (x >>> ((15 - l) << 1)) & 0x3; + +/** + * Re-orders byte lanes in given order (MSB). + * + * ``` + * swizzle(0x12345678, 3, 2, 1, 0) // 0x78563412 + * swizzle(0x12345678, 1, 0, 3, 2) // 0x34127856 + * swizzle(0x12345678, 2, 2, 0, 0) // 0x56561212 + * ``` + * + * @param x + * @param a + * @param b + * @param c + * @param d + */ +export const swizzle8 = (x: number, a: Lane8, b: Lane8, c: Lane8, d: Lane8) => + ( + lane8(x, a) << 24 | + lane8(x, b) << 16 | + lane8(x, c) << 8 | + lane8(x, d) + ) >>> 0; + +/** + * + * @param x + * @param a + * @param b + * @param c + * @param d + * @param e + * @param f + * @param g + * @param h + */ +export const swizzle4 = (x: number, a: Lane4, b: Lane4, c: Lane4, d: Lane4, e: Lane4, f: Lane4, g: Lane4, h: Lane4) => + ( + lane4(x, a) << 28 | + lane4(x, b) << 24 | + lane4(x, c) << 20 | + lane4(x, d) << 16 | + lane4(x, e) << 12 | + lane4(x, f) << 8 | + lane4(x, g) << 4 | + lane4(x, h) + ) >>> 0; + +/** + * Same as `swizzle8(x, 3, 2, 1, 0)`, but faster. + * + * @param x + */ +export const flipBytes = (x: number) => + ((x >>> 24) | (x >> 8 & 0xff00) | (x & 0xff00) << 8 | x << 24) >>> 0; diff --git a/packages/binary/test/index.ts b/packages/binary/test/index.ts new file mode 100644 index 0000000000..9d0e8ad0f9 --- /dev/null +++ b/packages/binary/test/index.ts @@ -0,0 +1,6 @@ +// import * as assert from "assert"; +// import * as b from "../src/index"; + +describe("binary", () => { + it("tests pending"); +}); diff --git a/packages/binary/test/tsconfig.json b/packages/binary/test/tsconfig.json new file mode 100644 index 0000000000..bcf29ace54 --- /dev/null +++ b/packages/binary/test/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../../../tsconfig.json", + "compilerOptions": { + "outDir": "../build" + }, + "include": [ + "./**/*.ts", + "../src/**/*.ts" + ] +} diff --git a/packages/binary/tsconfig.json b/packages/binary/tsconfig.json new file mode 100644 index 0000000000..bd6481a5a6 --- /dev/null +++ b/packages/binary/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "." + }, + "include": [ + "./src/**/*.ts" + ] +}