Why use a bitflag?
- They require less memory.
- Bitwise operations take much less execution time than other operations.
- With the small amount of space they require, you can greatly reduce server traffic.
What is a bitflag? A bitflag is an integer that represents multiple cases of true and false.
In order to understand this, you might take a look at an integer in binary. First of all, how do you read a binary value?
0000 is 0
0001 is 1
0010 is 2
0011 is 2+1
0100 is 4
0101 is 4+1
0111 is 4+2+1
Do you see a pattern of the powers of two emerging? If you don't, I suggest you go get a catscan.
Each value in a binary number on computers is a bit. The bit is either on (1) or off (0).
Amazingly, we have operators to manipulate numbers at the bit level.
& (bitwise and), &= (bitwise and assignment)
| (bitwise or), |= (bitwise or assignment)
xor (bitwise exclusive or), unfortunately gscript lacks xor assignment
<< (left bitshift), <<= (left bitshift assignment)
>> (signed right bitshift), >>= (signed right bitshift assignment)
unfortunately, gscript lacks unsigned right bitshift/assignment.
What can we do with these operators
Let's look at different cases (pretending we're working in 8 bits):
~4
00000100 (4 in binary)
11111011 (~4)
The inversion operator makes all the 0s into 1s and all the 1s into 0s.
4 & 5
00000100 (4 in binary)
00000101 (5 in binary)
00000100 (4 & 5)
If the bits are both on, then the bit in the outcome is on.
4 | 5
00000100
00000101
00000101 (4 | 5)
If either of the bits are on, then the bit in the outcome is on.
4 xor 5
00000100
00000101
00000001 (4 xor 5)
If the bit is one or the other but not both, the bit is on in the outcome.
4 << 1
00000100
00001000 (4 << 1)
What does this do? It shifts all the bits left one and fills in with 0. This is also identical to multiplying by a power of 2, the right operand being the power.
4 >> 1
00000100
00000010 (4 >> 1)
This shifts all the bits right one, and fills in the last bit with a copy of the previous last bit (which in this case would be 0). Other than the last bit, this would be identical to integer division by a power of 2.
This is because the last bit is the SIGN bit.
11111111 would be -1.
11111110 would be -2, and so on.
If you right shifted either of these examples by more than one, the outcome would be -1. If you wanted to fill in the last bit with a 0, you'd need to use an unsigned bit, which gscript lacks.
PHP Code:
//Okay, let's say you want to make constants for a bit flag.
INFECTED = (1 << 0); //player has a virus (1)
IMMUNE = (1 << 1); //player is immune to the virus (2)
SICK = (1 << 2); //player is sick due to the virus (4)
FATAL = (1 << 3); //the virus is fatal to the player (8)
//and so on...
//This makes it so that each constant represents a particular bit.
//You could also make a constant represent all of the bits.
ALLBITS = -1;
//So now that we have our constants sorted out, we will initialize a bitflag.
player.clientr.flag = 0;
//how do we put different values in the flag?
player.clientr.flag |= INFECTED; //(sets a bit, or leaves it set)
player.clientr.flag &= ~INFECTED; //(unsets a bit or leaves it unset)
player.clientr.flag = player.clientr.flag xor INFECTED; //(using the xor operator will toggle the bit)
//The player should be infected.
//How do we check to see if the player is infected?
if (player.clientr.flag & INFECTED == INFECTED)
doInfectionStuff();
//You can also check for multiple bits at once.
temp.mask = INFECTED | SICK;
if (player.clientr.flag & temp.mask == temp.mask)
doMaskStuff();
//What if you just need one of the bits your checking in the mask to be true?
if (player.clientr.flag & temp.maks != 0)
doOtherStuff();
//What if you want to know what the first set or first unset bit are?
this.firstset = c & (~c + 1); // can also be written c & -c;
this.firstunset = ~c & (c + 1);
That pretty much covers the whole concept. Also, keep in mind that you have 32 whole bits you can use for one flag in gscript, not just 4 or 8.
Here are some other neat tricks that you should only use for integers.
var * 2^n;
is equivalent to
var << n;
var / 2^n;
is equivalent to
var >> n; (integer division, 3>>1 returns 1, not 1.5)
var % (2^n);
is equivalent to
var & (2^n - 1);
-var is equivalent to (~var + 1)... though this isn't so useful.
var = var xor var;
is equivalent to and for some computers even faster than
var = 0;
Here's a useful one though. Swapping two numbers without a temp value.
PHP Code:
if (var1 != var2) {
var1 = var1 xor var2;
var2 = var2 xor var1;
var1 = var1 xor var2;
}
The body without the if branch would work for all values, except for when you're trying to swap a number with itself. This would mean, in essence that var1 is the same variable as var2. The example of this that is most often encountered is by swapping arr[i] and arr[j], when i==j.
I hope you join me in my protest for an unsigned bitshift operator (>>>) and a xor assignment operator, and that you can all use bitflags after reading this.