Question

I want to know how can I mask a value so I can set up configurations. Let's supose I have constants Options.A = 0, Options.B = 1 and so on...

builder.setOption( Option.A & Option.C ); // Or should I use '|' operator?

This would mean that

Option.A    Option.B    Option.C    Option.D
    1           0           1           0

Since 1010 is binary for number 10, it would mean that builder.option = 10;, but in the actual implementation I'd have a switch case that would compare it like:

// inside builder.someFunction();
switch(this.option) {
    case Option.A & Option.C:

Note: please correct me if this is not how you use bitwise operators to mask values, I have read a lot and don't understand it well, so if this is wrong I'm probably gonna need an example like this with switch-case.

PS: I took for example a line of code from Android framework that goes like this:

view.gravity = Gravity.TOP | Gravity.LEFT;

That's a similar behavior I want to achieve.

Was it helpful?

Solution

First, for theory:

(1)We ignore data types, suppose you have 4 options:

Option.A    Option.B    Option.C    Option.D

Then you need to use a 4bit-width variable to represent them. Suppose Option.A is the highest(Left-most) bit and the Option.D is the lowest(Right-most). Then this variable looks:

Option.A    Option.B    Option.C    Option.D
  bit3        bit2        bit1        bit0 

Its range is 0000~1111, represents 2^4 = 16 different combinations.

(2)For bit operations, you should firstly define the mask for each option:

var Mask.A = 1000;
var Mask.B = 0100;
var Mask.C = 0010;
var Mask.D = 0001;

<1>If you want to represent a value which has Option.B and Option.C, you can use OR operation:

var v_B_and_C = Mask.B | Mask.C = 0100 | 0010 = 0110;

<2>If you want to check whether a value contains Option.B, use AND, then compare the result:

var some_v = 1101;
var result = some_v & Mask.B = 1101 & 0100 = 0100;
if(result != 0000) {// Contains Option.B! }
else {// ==0000. Not contains Option.B! }

<3>If you want to reverse a value, you can use NOT/XOR :

var some_v = 0011;
var reversion_v = ~some_v = ~0011 = 1100;
// you can also use XOR(^) between a value and an all-1 constant
var reversion_v = some_v ^ 1111 = 0011 ^ 1111 = 1100;

<4>If you want to know the difference between two values, can use XOR:

var v_1 = 1100, v_2 = 0110;
var diff = v_1 ^ v_2 = 1100 ^ 0110 = 1010 // Means bit3, bit1 are different!

<5>For other usage, ref: Bitwise Operation

Second, for practice in Java:

(1)The 1st thing you need to make clear is that how many Options(bits) you need to represent? Because different data types has different width(represent different range):

  • short: 2Bytes, 16bit, represents 2^16 = 65536 combinations.
  • int: 4Bytes, 32bit, represents 2^32 = 4294967296 combinations.
  • long: 8Bytes, 64bit, represents 2^64 = 18446744073709551616 combinations.

If you need more than 64 Options, you may need to use array(int[]/long[]), or an convenient class: java.util.BitSet

(2)If you want to implement yourself by array, use the bitwise operation keywords(&,|,^,~,<<<,>>>). There is a tips to print out an int in binary format:

int i = 0x80000000;
System.out.println(Integer.toBinaryString(i));
// Print: 10000000000000000000000000000000

(3)I recommend use the java.util.BitSet class, unless you have reasons that must implement yourself. Example:

import java.util.BitSet;

public class Main {
   public static void main(String[] args) {
      // Create a BitSet object, which can store 128 Options.
      BitSet bs = new BitSet(128);
      bs.set(0);// equal to bs.set(0,true), set bit0 to 1.
      bs.set(64,true); // Set bit64

      // Returns the long array used in BitSet
      long[] longs = bs.toLongArray();

      System.out.println(longs.length);  // 2
      System.out.println(longs[0]); // 1
      System.out.println(longs[1]); // 1
      System.out.println(longs[0] ==longs[1]);  // true
   }
}

Other usage, see the java docs

OTHER TIPS

I have never implemented this but it occurs to me something like this:

For the first question, yes you would need to use | (instead of &) to accumulate the options correctly

if you are gonna accumulate options inside one variable, then to check which options are ON I would use a for:

for(int i=0;i<32;i++){
    if(i&options){//check if i-th option is ON
        option_function(i);
    }
}

and inside option_function() do the switch case.

void option_function(int i){
    switch(i) {
        case Option.A:
            ....
}

}

Why not create a class thats easier to read and uses standard API's?

public class Permissions { 

    final BitSet permissions;

    public Permissions() {
        permissions = new BitSet();
    }

    public void setPermission(int p) {
        permissions.set(p);
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top