简体   繁体   中英

How to use bitmasks to store boolean values in JavaScript

I'm a bit confused after reading about how to use bitmasks to store boolean values. I would like to have a set of boolean values and then generate a unique integer for each combination of the values. Here is the current system so far:

var a = 1 << 1
var b = 1 << 2
var c = 1 << 3
var d = 1 << 4

var uniqueint1 = getInt(true, false, false)
var uniqueint2 = getInt(true, true, false)
var uniqueint3 = getInt(true, true, true)
// ...

function getInt(x, y, z) {
  var value = a
  if (x) value = value | b
  if (y) value = value | c
  if (z) value = value | d
  return value
}

But the problem is, I am not sure if I am supposed to handle the "not" case, along the lines of this:

function getInt(x, y, z) {
  var value = a
  if (x) value = value | b
  else value = value ^ b

  if (y) value = value | c
  else value = value ^ c

  if (z) value = value | d
  else value = value ^ z

  return value
}

All I know is that I've seen | , & , and ^ related to bitmasks, and I know to find if a boolean is in the bitmask you do var yes = value & b , but I'm just confused how to generate the bitmask so that it handles both the if (true) and if (false) cases. Not sure if I'm supposed to be using ^ somewhere, or what else I'm doing wrong. Please advise. Thank you!

I am not sure if I am supposed to handle the "not" case

You're not supposed to handle it at all. A bitmask works so that you either have a bit with value 1 if your flag is set or the bit with value 0 if not. Given that your value starts with 0 s everywhere (the integer 0), you just have to set the bit (by OR 1) when your condition is true and you don't have to do anything otherwise.

You could simplify your code to

function getInt(x, y, z) {
  return (0b10 // a
          | (x << 2)   // 0b00100 if x and 0b00000 else
          | (y << 3)   // 0b01000 if y and 0b00000 else
          | (z << 4)); // 0b10000 if z and 0b00000 else
}

A NOT op will invert the bit so it needs to be set in order to be cleared.

(Assuming you want to toggle bits on or off on an existing value:) You can use NOT together with a AND mask to clear off a bit like this:

 var v = 0xff; // value var bit3 = 1<<3; // the bit we want to clear // clear bit 3: v &= ~bit3; // create a AND mask inverting bit 3 and AND with value console.log(v.toString(2)); v &= ~bit3; // will not set the bit even when already cleared console.log(v.toString(2)); 

You can of course also check if the bit is set and then NOT it if it is:

 var v = 0xff; var bit3 = 1<<3; if (v & bit3) v ^= bit3; // NOT bit 3 if set console.log(v.toString(2)); // should not trigger: if (v & bit3) console.log("Whaa"); 

To set it instead, you would use OR regardless of the state:

if (v & bit3) v ^= bit3;   // NOT bit 3 if set
else {v |= bit3};          // set it not set already

If you need to clear several bits at once you can first OR the bits together, then use that with NOT for a AND mask:

 var v = 0xff; var bit1 = 1<<1; var bit3 = 1<<3; // create NOT mask: var mask = bit1 | bit3; // clear bits: v &= ~mask; console.log(v.toString(2)); 

So in the function you could so something like this:

 var a = 0xff; var b = 1 << 2 var c = 1 << 3 var d = 1 << 4 function getInt(x, y, z) { var value = a; value = x ? value | b : value & ~b; value = y ? value | c : value & ~c; value = z ? value | d : value & ~d; return value } // turn off bit c/d (bit index 3 & 4): console.log(getInt(true,false,false).toString(2)); // turn on c, off b/d console.log(getInt(false,true,false).toString(2)); // with same value turn off all, then on c: a = getInt(false, false, false); console.log(getInt(false,true,false).toString(2)); 

By doing var value=1 at the beginning you are already setting value to 2, because 1<<1=2 . I suggest you set value=0 , and remove else value = value ^ c , since that operation does not cause any change when you start with all zeros. Your code would look as follows:

var a = 1 << 1
var b = 1 << 2
var c = 1 << 3
var d = 1 << 4

function getInt(x, y, z) {
  var value = 0
  if (x) value = value | b
  if (y) value = value | c
  if (z) value = value | d
  return value
}

var uniqueint1 = getInt(true, false, false)
var uniqueint2 = getInt(true, true, false)
var uniqueint3 = getInt(true, true, true)
uniqueint1

This prints out 4 , instead of 6 for uniqueint1 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM