Repository: brockwhittaker/BitArray.js
Branch: master
Commit: 89c4a6a54404
Files: 4
Total size: 9.0 KB
Directory structure:
gitextract_0gvc6z21/
├── bits.js
├── perf-test.js
├── readme.md
└── tests.js
================================================
FILE CONTENTS
================================================
================================================
FILE: bits.js
================================================
const BitArray = (() => {
// The BitArray is a simple bit flag implementation that utilizes standard arrays
// (for expandability) and Uint32Array types for memory efficiency.
// Every value is assumed either true or false (inclusive of uninitialized values),
// however a warning is given if a particular block does not exist yet.
const BitArray = function (opts) {
// if the opts aren't specified, let's just make it an object so we can
// safely OR its properties below.
if (!opts) {
opts = {};
}
// an internal map of Uint32Array blocks.
// this has the fault of becoming a hole-d array, which could be bad.
// perhaps give the option to use objects rather than arrays?
this.map = [];
// the size of a block inside of the map of Uint32Array objects.
this.binSize = opts.binSize || 100;
};
BitArray.prototype = {
// get a flag by its ID.
get: function (id) {
let b = this.binSize;
// faster than `Math.floor`.
// this gets the zone (bin) of Uint32Arrays (primary array index).
let z = ~~(id / (b * 32));
// if a value is inside a block that has already been created, we cannot
// *really* tell whether a value has been set, but if the block doesn't
// exist yet then it definitely doesn't.
if (!this.map[z]) {
console.warn(`A value at the index '${id}' does not exist.`);
return false;
}
// the bin of Uint32Array objects that we're looking in.
let bin = this.map[z];
// the actual Uint32Array the boolean exists within.
// secondary array index.
let slot = ~~((id % (b * 32)) / 32);
// id & 31 is equivalent to id % 32
// 1 << n is equal to 2 ^ x
//
// for any mod n where n = 2^i, modulo is simply keeping the lower order
// bits 0 through i - 1
// 00100100 | 36
// AND 00011111 | 31
// ==> 00000100 | 4
return !!(bin[slot] & (1 << (id & 31)));
},
// set a Boolean value into an ID.
set: function (id, val) {
// this code is copied from above because this function call is expensive
// (adds 20%) and can't really be inlined by JIT.
let b = this.binSize;
let z = ~~(id / (b * 32));
if (!this.map[z]) {
this.map[z] = new Uint32Array(b);
}
let bin = this.map[z];
let slot = ~~((id % (b * 32)) / 32);
if (val) {
// if the value is truthy, use |= which will OR update the flag.
// 01010001
// OR 00100000
// ==> 01110001
bin[slot] |= 1 << (id & 31);
} else {
// if the value is falsy, use &= ~FLAG to negate the flag.
// 01010001
// AND 11101111
// ==> 01000001
bin[slot] &= ~(1 << (id & 31));
}
return bin[slot];
},
// flip a bit to the opposite of its current value.
// this will initialize flags that don't exist yet and set them to "true".
flip: function (id) {
let b = this.binSize;
let z = ~~(id / (b * 32));
if (!this.map[z]) {
this.map[z] = new Uint32Array(b);
}
let bin = this.map[z];
let slot = ~~((id % (b * 32)) / 32);
// flip the particular flag.
// 01000100
// FLIP 00000100
// ===> 01000000
bin[slot] ^= 1 << (id & 31);
return bin[slot];
}
};
return BitArray;
})();
if (typeof module !== "undefined" && module.exports) {
module.exports = BitArray;
}
================================================
FILE: perf-test.js
================================================
const v8 = require("v8"),
BitArray = require("./bits");
let compare = {
standard: () => {
const arr = [];
for (let x = 0; x < 1e7; x++) {
arr[x] = !!Math.round(Math.random());
}
return arr;
},
fixedArray: () => {
const arr = new Array(1e7);
for (let x = 0; x < 1e7; x++) {
arr[x] = !!Math.round(Math.random());
}
return arr;
},
Uint8Array: () => {
const arr = new Uint8Array(1e7);
for (let x = 0; x < 1e7; x++) {
arr[x] = !!Math.round(Math.random());
}
return arr;
},
bitArray: () => {
const arr = new BitArray({ binSize: 1000 });
for (let x = 0; x < 1e7; x++) {
arr.set(x, !!Math.round(Math.random()));
}
return arr;
}
};
const TEST = "bitArray";
const s1 = v8.getHeapStatistics(),
d = new Date();
let arr = compare[TEST]();
console.log(new Date() - d, v8.getHeapStatistics().total_heap_size - s1.total_heap_size);
================================================
FILE: readme.md
================================================
# BitArray.js
BitArray.js is a micro-library that creates an array of booleans with less than 2% of the memory consumption of an array of booleans.
BitArray weighs in at just 0.85kb compressed and 0.35kb gzipped, which makes it extremely lightweight to add to any project.
## Tests
There are three tests for speed vs. memory consumption:
1. Creating an array with 10m elements and adding a boolean to each index.
```js
const arr = [];
for (let x = 0; x < 1e7; x++) {
arr[x] = !!Math.round(Math.random());
}
return arr;
```
2. Creating an array with a pre-assigned length of 10m and adding a boolean to each index.
```js
const arr = new Array(1e7);
for (let x = 0; x < 1e7; x++) {
arr[x] = !!Math.round(Math.random());
}
return arr;
```
3. Testing the BitArray.
```js
const arr = new BitArray();
for (let x = 0; x < 1e7; x++) {
arr.set(x, !!Math.round(Math.random()));
}
return arr;
```
### Results
| Structure | Time | Heap Size | % Memory |
| -------------- | ----- | ---------- | -------- |
| Dynamic Array | 740ms | 335,155,200 | 100% |
| Pre-Init Array | 267ms | 81,068,032 | 24.19% |
| BitArray | 479ms | 4,194,304 | 1.25% |
## Methods
The BitArray class only has three methods currently: `get`, `set`, and `flip`.
## Usage
Below is a quick demo of all the cases this can be used with:
```js
let array = new BitArray();
array.get(0); // false
array.set(0, true); // true
array.get(0); // true
array.flip(0); // false
```
## Under the Hood
The booleans are stored in a nested array with the signature of `Array<Uint32Array>`. The array is flexible in length whereas the `Uint32Array` by default is fixed. Each boolean is stored as a bit inside of a 32-bit integer.
## Customization
One option is given, which is `binSize`. This is the size of a `Uint32Array` (a bin of integers). With smaller sets of only a few dozen booleans it would be beneficial to use a small bin size like 1 or 2. When dealing with millions of booleans however, you can do some napkin math to figure out how large the `Uint32Array` should be (given that less separate arrays means less seperate overhead and pointers in memory).
Each integer fits 32 booleans, so a bin of 100 `Uint32Array` objects would be capable of storing 3,200 flags.
### Example
Below is an example of setting the binSize to be 1000:
```js
let binSize = 1e3;
const array = new BitArray({ binSize });
```
## Contribute
If you have a contribution you'd like to make, submit a pull request! Try to match the style of the code written – it should have the appearance of being written by a single author.
================================================
FILE: tests.js
================================================
const BitArray = require("./bits");
const Test = () => {
const results = {
pass: 0,
fail: 0
};
console.log("\nStarting tests...\n");
return {
assert: {
equal: (v1, v2) => {
let flag = v1 === v2,
str = flag ? `SUCCESS: ${v1} === ${v2}` : `ERROR: ${v1} !== ${v2}`;
if (flag) results.pass++;
else results.fail++;
console.log(str);
if (!flag) {
let err = new Error().stack;
console.log(err.split(/\n/)[2]);
}
}
},
results: () => {
console.log(`\nPASSED: ${results.pass}\nFAILED: ${results.fail}\n`);
if (results.pass && !results.fail) {
console.log("All tests passed successfully!\n");
}
}
};
}
const bits = new BitArray(),
test = Test();
// simple bit initialization.
bits.set(0, true);
bits.set(1, false);
bits.set(2000, true);
bits.set(3, true);
test.assert.equal(bits.get(0), true);
test.assert.equal(bits.get(1), false);
test.assert.equal(bits.get(2000), true);
test.assert.equal(bits.get(3), true);
// test flipping the value of the bit.
bits.flip(3);
// test multi-resetting of bit.
bits.set(234809, true);
bits.set(234809, false);
bits.flip(234809);
test.assert.equal(bits.get(3), false);
test.assert.equal(bits.get(234809), true);
console.log(test.results());
gitextract_0gvc6z21/ ├── bits.js ├── perf-test.js ├── readme.md └── tests.js
SYMBOL INDEX (1 symbols across 1 files) FILE: perf-test.js constant TEST (line 46) | const TEST = "bitArray";
Condensed preview — 4 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (10K chars).
[
{
"path": "bits.js",
"chars": 3998,
"preview": "const BitArray = (() => {\n // The BitArray is a simple bit flag implementation that utilizes standard arrays\n // ("
},
{
"path": "perf-test.js",
"chars": 1050,
"preview": "const v8 = require(\"v8\"),\n BitArray = require(\"./bits\");\n\nlet compare = {\n standard: () => {\n const arr ="
},
{
"path": "readme.md",
"chars": 2639,
"preview": "# BitArray.js\n\nBitArray.js is a micro-library that creates an array of booleans with less than 2% of the memory consumpt"
},
{
"path": "tests.js",
"chars": 1496,
"preview": "const BitArray = require(\"./bits\");\n\nconst Test = () => {\n const results = {\n pass: 0,\n fail: 0\n };\n"
}
]
About this extraction
This page contains the full source code of the brockwhittaker/BitArray.js GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 4 files (9.0 KB), approximately 2.5k tokens, and a symbol index with 1 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.