The Ultimate JavaScript Module for MemoryEfficient Boolean Management
"From crafting vivid 🎮 1) gaming graphics and compressing 🎞️ 2) media files, to exploring the geometric intricacies of the 🌐 3) digital realm, these tools are the backbone of modern digital artistry. They drive the 💽 4) data compression that fuels our digital conversations, the 📊 5) data mining that unveils hidden patterns, and the 🔍 6) database management that organizes our digital world. They safeguard our networks with robust 🛡️ 7) cryptographic shields, propel the 📡 8) networking channels that connect us, and simulate complex 🧪 9) scientific realities that enhance our understanding of the universe. Lastly, they hold promise in revolutionizing 🩺 10) healthcare, by optimizing medical image processing, promising a future where technology and medicine converge for the betterment of humanity."
 📚 Introduction
 💻 Install
 📤 Import
 🔢 BitArray
 🔐 SetFixed

🔢 BitArray Documentation

🛠️ Constructor: BitArray(s)
 Number, BitArray, Uint32Array (data)

🔍 Properties
 length, idealConstructor, data, dataCopy

🔧 Methods
 readBit, toggleBit, writeBit1, writeBit0, countOnes, countZeros, getMin, getMax, resize, resizeToMax, clear, charge, invert

🛠️ Constructor: BitArray(s)

🔐 SetFixed Documentation

🛠️ Constructor: SetFixed(size)
 Number, BitArray, SetFixed, Array (indexes), Set

🔍 Properties
 size, length, indexes, idealConstructor, bitArray, bitArrayCopy, bitArrayData, bitArrayDataCopy

🔧 Methods
 has, hasnt, add, bulkAdd, bulkAddUnsafe, setFromSetFixed, delete, bulkDelete, optimize, resize, resizeUnsafe, clear, charge, invert

🚀 Turbo methods (3000% times faster)
 addFromSetFixed, addFromSetFixedUnsafe, differentFromSetFixed, differentFromSetFixedUnsafe, sameFromSetFixed, sameFromSetFixedUnsafe, computeSize

🛠️ Constructor: SetFixed(size)
 📝 Example
 👤 About me
🚀 Optimized Efficiency: Leveraging the power of this module, you can ensure unparalleled memory efficiency, especially in applications requiring operations that most other solutions simply can't match. With other systems, you could easily find yourself using up to ten times more system resources. With our solution, you can kiss those inefficiencies goodbye.
🔍 Realworld Applications:
 Data Compression: When you're compressing data and need to keep track of repeated patterns, our module excels. Register whether patterns are stored in a table swiftly and efficiently.
 Drawing Apps: For those seeking rapid pixel selection in drawing applications, this module is your goto. Process pixel selections at lightning speed!
💾 Memory Footprint:
 A staggering 1/4 million entries take up a mere 31kB in memory. 8 millions entries is 1mB and still faaaaster than mad driver in your "homies' hood" tho. (Laugh 2x)
 Engaging with ten 2D pixel selections of 500x500? That's a featherlight 0.3mB for the entire lot.
 Store up to eight thousand boolean values in just 1kB.
🔐 Precision Limitations:
 Designed for a singular purpose: handling boolean values.
 Functions within a fixed index size limited to positive whole numbers.
 Doesn't try to be everything; it just excels at what it's meant to do.
🛠️ Design Efficiency:
 Methods and properties are memoryefficient, with intentional design ensuring that the module remains within its internal state. Only the properties and methods with public "getters" extend beyond.
 Lowlevel operations are precisely tuned for the JavaScript engine, ensuring minimal computation force. We've rigged numbers to avoid bulky double storage, streamlining memory usage further.
🖋️ Bottom Line: If you're into data compression or drawing applications, this kind of solution is almost indispensable. With its precise focus and memory efficiency, it's time to elevate your operations to the next level with our module.
npm install @asaitama/booleanarray
// First load `/dist/browser.min.js` (16 kB)
var BitArrayClass = window.BitArray; // Optional
var SetFixedClass = window.SetFixed; // Optional
// Weight around 31 kB in memory for ~ 1/4 million entries
// All instances use Uint32Arrays. A chunck (4 bytes).
// Chuncks contains 32 bits storing as much "potential boolean" as the number of bits
var mySetFixedInstance = new SetFixed(new BitArray(512*512));
// You can also use "@asaitama/booleanarray/dist/index.min.js"
import { BitArray, SetFixed } from "@asaitama/booleanarray";
BitArray is a useful data structure that allows you to manipulate an array of bits efficiently. This object is perfect for situations where you need to work with bits directly. For instance, it can be useful in coding problems related to bit manipulation or when dealing with binary data. It provides methods to read, write, clear and set individual bits, as well as other utility functions.
SetFixed is a set data structure implemented using the BitArray object. This is an efficient and compact data structure for storing nonrepeated elements. SetFixed provides a variety of methods to manipulate the set such as adding, devaring, checking for membership, and iterating over the set.
The BitArray object provides an efficient bitlevel manipulation of a typed array. It offers methods for setting, getting and manipulating individual bits within the array.
The constructor function takes a parameter s
, which represents the size of the BitArray. This is used to initialize the internal Uint32Array. The function also initializes the M_OR_
and M_AND_
Uint32Arrays, which are used as masks for setting and clearing bits.
var ba = new BitArray(64);
var ba_copy = new BitArray(ba);
This getter function returns the length of the BitArray.
var bitArray = new BitArray(64);
var length = bitArray.length;
console.log(length);
This getter function returns the data used in the inside of the BitArray. It contains bits within uint32, and the last element of the Uint32Array is the length used
var bitArray = new BitArray(64);
var uint32a = bitArray.data  bitArray.dataCopy;
console.log(uint32a);
This getter function returns the ideal TypedArray
constructor of the BitArray based on it's given length.
// All positives bit's indexes can fit within a 1 Byte number
var bitArraySmall = new BitArray(22);
var uint8array = new bitArraySmall.idealConstructor(10);
// All positives bit's indexes can fit within a 2 Byte number
var bitArrayMedium = new BitArray(55555);
var uint16array = new bitArrayMedium.idealConstructor(10);
// Fit within a 4 Byte number (it is used by the class named SetFixed...)
var setFixedBig = new SetFixed(7777777+1); // 8 millions entries is OKAY (1 mB)
setFixedBig.bulkAdd([1, 22, 333, 4444, 55555, 666666, 7777777]);
setFixedBig.delete(22);
// Indexes are computed "on the fly" (FAAAAAAST)
var uint32array = setFixedBig.indexes;
console.log(uint32array); // // Uint32Array.of(1, 333, 4444, 55555, 666666, 7777777)
This getter function returns a function that reads the bit at index i
, returning a boolean indicating whether the bit is set.
var result = ba.readBit(4);
This getter function returns a function that reads and toggle (invert the value of) the bit at index i
, returning a boolean indicating whether the bit has become positive or negative.
// It returns true if the new value is one, and false if it is now zero
var result = ba.toggleBit(4);
This getter function returns a function that sets the bit at index i
to 1.
ba.writeBit1(4);
This getter function returns a function that sets the bit at index i
to 0.
ba.writeBit0(4);
Those getter functions returns either function that return the number of positive or nullish values in it.
ba.countOnes();
ba.countZeros();
Those getter functions returns either function that return the first or latest bit set to one, if none is in it 1
will be returned.
ba.getMax();
ba.getMin();
Those getter functions returns either function that resize the BitArray to a defined length or the last bits set to one.
ba.resize(128);
ba.resizeToMax();
This getter function returns a function that clears all bits in the BitArray.
ba.clear();
This getter function returns a function that sets all bits in the BitArray to 1.
ba.charge();
This getter function returns a function that sets all bits to the opposed value fast (it uses bits level operations on Uint32).
ba.invert();
The SetFixed object provides a set data structure that allows efficient addition, devarion, and checks for membership. It offers methods for setting, getting and manipulating individual elements within the set.
The constructor function takes a parameter size, which represents the size of the SetFixed. This is used to initialize the internal BitArray. If size is an object (presumably an arraylike object), then the SetFixed is initialized with those elements.
// The size is fixed but it will be increased if you use `.add(index)`
var setFixedNew = new SetFixed(64);
// Copy the SetFixed very fast (no indexing needed)
var setFixedCopy = new SetFixed(setFixedNew);
// It has however the need to count the number of positive values when one is giving a BitArray's instance
var setFixedNew1 = new SetFixed(new BitArray(64));
// Do not use float, non positive integer, or bigint
var setFixedNew2 = new SetFixed([69, 777, 0x09, 666, 22, 57, 333]);
// Without making a copy of bitArrayData (which is a Uint32Array) changes are applied to both
var setFixedNew2Mirror = new SetFixed(new BitArray(setFixedNew2.bitArrayData));
var setFixedNew2Copy = new SetFixed(new BitArray(setFixedNew2.bitArrayDataCopy));
This getter function returns the size of the SetFixed set, which is the number of elements in the set.
var setFixed = new SetFixed(64);
setFixed.add(4);
console.log(setFixed.size); // 1
This getter function returns the length of the BitArray used internally.
var setFixed = new SetFixed(64);
console.log(setFixed.length); // 64
This getter function returns an array of the indices of the bits that are set within the BitArray.
var setFixed = new SetFixed(64);
console.log(setFixed.indexes); // [] (Uint8Array or Uint16Array or even Uint32Array)
This static function returns a new SetFixed
instance from exported data.
var setFixed = new SetFixed(64);
var copy = true; // Do copy the data
var data = setFixed.export(copy) // Either BitArrayData or BitArrayDataCopy
var setFixed2 = SetFixed.import(data);
This getter function returns a function that return the data you need to import/export it.
var setFixed = new SetFixed(64);
var copy = true; // Do copy the data
var data = setFixed.export(copy) // Either BitArrayData or BitArrayDataCopy
var setFixed2 = SetFixed.import(data);
This getter function returns a function that checks if a given index i is set within the BitArray.
var setFixed = new SetFixed(64);
console.log(setFixed.has(4)); // true or false
console.log(setFixed.hasnt(4)); // true or false
This getter function returns a function that adds a given index i to the SetFixed. If the index given is beyond the capacity of the instance, it will be resized correctly with a margin. Don't worry about resizing or memory consumption, it is far more efficient than a traditional new Set() instance object if you deal with indexes below 1/4 million (indexes from 0 to 250000 will represent only a few 31kB in memory)
However, be careful, if you create a setFixed with a length of 70000 (which is alright) but then add the index 999999, the new length of the setFixed instance will be the max index set to one.
It is as much as 23x faster and 46x lighter for the JS Engine when used for managing pixel art selection state on canvas of 512x512 pixels than "new Set()" but is limited to entire integer within a range!!!
var setFixed = new SetFixed(64);
var setFixedCopy = new SetFixed(setFixed);
setFixed.add(100); // It will extend the BitArray used if it is too small (only)
setFixed.addUnsafe(57); // It will only work if it doesn't overflow it's capacity
setFixed.bulkAdd([1, 2, 3, 4, 5]);
setFixedCopy.clearAndBulkAdd(setFixed.indexes);
setFixed.clearAndBulkAddUnsafe(setFixedCopy.indexes); // Works like if it were replacing it
setFixed.setFromSetFixed(setFixedCopy); // Replace it (FAST)
This getter function returns a function that deletes a given index i from the SetFixed.
var setFixed = new SetFixed(64);
setFixed.delete(4);
setFixed.bulkDelete;([1, 2, 3, 4, 5]);
This getter function returns a function that resize the data store in the bitArray of the SetFixed to the max element's index. It can be called when you think you have a too large range of possibilities for indexes.
var setFixed = new SetFixed(256);
setFixed.add(100);
setFixed.optimize();
// setFixed.length is now 100, setFixed.size is still one
This getter function returns a function that resize the data store in the bitArray of the SetFixed. The unsafe version won't check to update the size (the number of bits set to one).
var setFixed = new SetFixed(64);
setFixed.resize(128);
// setFixed.length is now 128
This getter function returns a function that clears all elements in the SetFixed.
var setFixed = new SetFixed(64);
setFixed.clear();
This getter function returns a function that sets all bits in the BitArray to 1.
var setFixed = new SetFixed(64);
setFixed.charge();
This getter function returns a function that invert all bits in the BitArray.
var setFixed = new SetFixed(64);
setFixed.invert();
New in V 4.0.0 & beyond
The subsequent methods execute operations at the "32bit level" within a single integer action across all 32bit unsigned integers sequentially. This approach is, though untested, presumed to be 32+ times faster.
Every 32 bits involve one binary operation and one writing action. Binary operations are significantly quicker than additions or multiplications since computers inherently process numbers more efficiently in binary (base 2) format.
It uses setFixed.bitArrayData
which uses bitArray.data
to perform all the operations. As well as "shared" typed arrays you can also obtain a copy using setFixed.bitArrayDataCopy
or bitArray.dataCopy
.
The unsafe versions doesn't count the number of bits being positive, you can update the
size
value of the instance manually if you called unsafe turbo methods. It is feasible by callingsetFixed.computeSize()
which usesbitArray.countOnes()
as well as it could have being usingbitArray.countZeros()
.
This method is used to add the data from another SetFixed
instance.
Parameters:

sf: The primary
SetFixed
instance from which data will be added. 
sf2 (optional): An additional
SetFixed
instance. If provided, its data will be merged alongsidesf
. 
sf3 (optional): An additional
SetFixed
instance. If provided, its data will be merged alongsidesf2
. 
sf4 (optional): An additional
SetFixed
instance. If provided, its data will be merged alongsidesf3
.
If you provide more than one SetFixed, you'll need to provide the SetFixed's instance you are using to call this method to include it.
Usage:
var setFixed = new SetFixed(64);
setFixed.addFromSetFixed(sf, sf2, sf3, sf4);
Behavior:
 Adds the bit array data from the provided
sf
(andsf2
if available).  Computes the number of bits set to
1
.
This method computes the bit difference based on the data from another SetFixed
instance.
Parameters:

sf: The primary
SetFixed
instance from which difference will be computed. 
sf2 (optional): An additional
SetFixed
instance. If provided, its data will be used alongsidesf
.
Usage:
var setFixed = new SetFixed(64);
setFixed.differentFromSetFixed(sf, sf2);
Behavior:
 Computes the bit difference from the provided
sf
(andsf2
if available).  Computes the number of bits set to
1
.
This method computes the bit intersection based on the data from another SetFixed
instance.
Parameters:

sf: The primary
SetFixed
instance from which intersection will be computed. 
sf2 (optional): An additional
SetFixed
instance. If provided, its data will be used alongsidesf
.
Usage:
var setFixed = new SetFixed(64);
setFixed.sameFromSetFixed(sf, sf2);
Behavior:
 Computes the bit intersection from the provided
sf
(andsf2
if available).  Computes the number of bits set to
1
.
The SmartRunLengthCompress and SmartRunLengthDecompress functions utilize the SetFixed and BitArray data structures to implement a highly efficient form of runlength encoding. By using a 1bit matchmaking system, SetFixed in conjunction with BitArray facilitates compression that's almost 8 times more spaceefficient for nonrepeating values, while only consuming an eighth more space for multiple repetitions. This enables the compression of image data, particularly suitable for pixel art with similar colors, into a much more compact form. The design leverages the concept of a "lazy" runlength algorithm, where lengths are not always mandatory, and values without specific lengths are set to false (0) in the bitarray. Thus, it provides a unique and optimized approach to data compression, which balances space savings with the ability to handle both repeating and nonrepeating values.
function SmartRunLengthCompress(data_uintX) {
var lengths = new Uint8Array(data_uintX.length);
var lengths_l = 0;
var values_constructor_bits = data_uintX instanceof Uint32Array ? 32: data_uintX instanceof Uint16Array ? 16: 8;
var values_constructor = values_constructor_bits === 32 ? Uint32Array: values_constructor_bits === 16 ? Uint16Array: Uint8Array;
var values = new values_constructor(data_uintX.length);
var values_l = 0;
var values_using_compression = new SetFixed(data_uintX.length);
var current = data_uintX[0], latest = data_uintX[1], repeated = 1;
var i = 1, l = data_uintX.length;
for(; (i0) < (l0); i = i + 10){
latest = data_uintX[i];
if((latest0) != (current0)  (repeated0) >= 0xFF){ // The value is new or surpass chunk length
if((repeated0) > 1){
// We set the index of the current value to hold a length
values_using_compression.add(irepeated);
// We add the number of repetition inside the lengths array
lengths[lengths_l] = repeated0
lengths_l = lengths_l+10;
// We add the value inside the values array
values[values_l] = (current0)>>>0;
values_l = values_l+10;
}else {
// We add the value inside the values array
values[values_l] = (current0)>>>0;
values_l = values_l+10;
}
repeated = 1;
current = (latest0)>>>0;
}else { // The value is repeated
repeated = repeated+10;
}
}
if((repeated0) > 1){
// We set the index of the current value to hold a length
values_using_compression.add(i1)
// We add the number of repetition inside the lengths array
lengths[lengths_l] = repeated0
lengths_l = lengths_l+10;
// We add the value inside the values array
values[values_l] = (current0)>>>0;
values_l = values_l+10;
}else {
// We add the value inside the values array
values[values_l] = (current0)>>>0;
values_l = values_l+10;
}
return {
bits: values_constructor_bits,
lengths: lengths.slice(0, lengths_l),
values: values.slice(0, values_l),
matchmaking: values_using_compression.export()
};
}
function SmartRunLengthDecompress(object) {
var constructor = object.bits === 32 ? Uint32Array: object.bits === 16 ? Uint16Array: Uint8Array;
var lengths = object.lengths;
var values = object.values;
var matchmaking = SetFixed.import(object.matchmaking);
var total_length = values.length  lengths.length; // values that aren't alone
for(var i = 0, l = lengths.length; (i0) < (l0); i = i + 10){
total_length = (total_length+lengths[i]0)>>>0; // values that are repeated
}
var output = new constructor(total_length), v = 0, l = 0;
for(var i = 0; (i0) < (total_length0);){
if(matchmaking.has(i)){
output.fill(values[v], i, i+lengths[l]0);
i = i + lengths[l]  0;
l = l + 1 0;
}else {
output[i] = values[v];
i = i + 1 0;
}
v = v + 1 0;
}
return output;
}
.................. ..
.......
.....
......... ...
...... . .#######+.
.... . .##########+.
.....+#++###+++++++#+
....######+.++.
.. .#######+++++++++##+
... +######++##+##+.##+.
.. .#######++..###.
...########+++++####.
...+########+++##++.####
...##########+++++.#####.
...#########++#########+.
..###########+++++.+###### ...
.##############++#######. .
"Philosophy is the science of estimating values, yet technology is the value of estimating science. My design is my voice while my code is my weapon of choice..."
I am (sometimes) open to work^^ ==> https://www.linkedin.com/in/matiasaffolter/