Using Bitmasks in JavaScript
2016-03-05
Bitmasks are useful (e.g. for State Machines) and also usable in JavaScript.
Attention: The maximum value for the mask in JS is 2^31-1 (maximum value of int in JS).
Initial usage
No enums available, so use an object instead to create a Bitmask:
var States = {
HINT: 1,
NOTICE: 2,
WARNING: 4,
ERROR: 8,
FATAL: 16
};
And use it like this:
var a = States.NOTICE;
a & States.HINT // returns 0
a & States.NOTICE // returns 2 (States.NOTICE)
Checking values against the mask
Two ways of checking the mask:
if ((a & States.NOTICE) === States.NOTICE) console.log(true);
if (a & States.NOTICE) console.log(true);
As long as the value 0 is not part of the Bitmask, the second way works as expected.
Working with the bitmask
Set combined values:
var a = States.NOTICE | States.FATAL;
a & States.FATAL // returns 16 (States.FATAL)
a & States.NOTICE // returns 2 (States.Notice)
Subtract a value:
var a = States.NOTICE | States.FATAL;
var b = a ^ States.FATAL;
a & States.FATAL # returns 0
The operators |=
and ^=
work as expected.
Pretty printing bitmask values
function StateToString(state) {
if (isNaN(state)) {
return '<isNaN("' + state + '")>';
}
if (state < 1) return '<NONE>';
else {
let iter, result = "";
for (iter in States) {
if (state & States[iter]) result += iter + '&';
}
if (result.length > 0) result = result.substr(0, result.length-1);
else result = '<NONE>';
return result;
}
}
Full example
var States = {
HINT: 1,
NOTICE: 2,
WARNING: 4,
ERROR: 8,
FATAL: 16
};
function StateToString(state) {
if (isNaN(state)) {
return '<isNaN("' + state + '")>';
}
if (state < 1) return '<NONE>';
else {
let iter, result = "";
for (iter in States) {
if (state & States[iter]) result += iter + '&';
}
if (result.length > 0) result = result.substr(0, result.length-1);
else result = '<NONE>';
return result;
}
}
function printState() {
console.log(state + ' => ' + StateToString(state));
}
var state = 'NOTICE'; state= null;
printState(); // <isNaN("NOTICE")>
state = States.NOTICE;
printState(); // 2 => NOTICE
state |= States.WARNING;
printState(); // 6 => NOTICE&WARNING
state ^= States.NOTICE;
printState(); // 4 => WARNING