1

I'm currently reading the "SFML game development" book and in Chapter 4 - Input Handling in the sub-chapter "Receiver Category", paragraph n°2; we've got this:

"We define an enum to refer to the different categories. Each category except None is initialized with an integer that has one bit set to 1 , and the rest are set to 0 :"


namespace Category
{
   enum Type
   {
     None = 0,
     Scene = 1 << 0,
     PlayerAircraft = 1 << 1,
     AlliedAircraft = 1 << 2
     EnemyAircraft = 1 << 3,
   };
}

I'm not really comfortable with bitwise operators and binary operations in general; so I don't understand that part "Each category except None is initialized with an integer that has one bit set to 1 , and the rest are set to 0 :".

If each category (except None) is initialized as said above, what is "the rest" set to 0 ?!

Note: After double-reading I think I understand that each member of the enum is a byte and so, the first bit of those is set to 1 and the other bits of the same byte are set to 0. So, Scene = 0b1, PlayerAircraft = 0b10 (one bit = 1, the other = 0), etc... so if I would have write : PlayerAircraft = 2 << 1 PlayerAircraft would have been equal to 0b11? am I right or I'm missing something?

Further in the chapter; we've got a if condition checking if the requested category is the same as the scene node one; without going off-subject; I didn't understand that part. Since it uses a AND (or & if you prefer) bitwise operator; how could it check if the scene node category is the same as the requested one? I've check on Wikipedia how it works but I didn't fully get it.

Here's the code

void SceneNode::onCommand(const Command& command, sf::Time dt)
{
   if(command.category & getCategory()) //The part I don't understand
     command.action(*this, dt);
/* ... */
}

I don't get it...

Voilà, thank you in advance and I hope my first post in here isn't too messy and that I have provided enough informations. If not, I will edit! :)

PS: Sorry for the lame English, I'm not awake enough today.

1
  • 1<<0 evaluates to 1 (00000001). 1<<1 evaluates to 2 (00000010). 1<<2 evaluates to 4 (00000100). 1<<3 evaluates to 8 (00001000). It is bit shifting, you can consider it as multiplying/dividing by two by left/right shifting respectively. I'm assuming this is being done so they can use a bitmask with this enum later. Commented Jun 26, 2014 at 22:08

4 Answers 4

1

What's operator<<?

Understanding operator<<, in this case, is very easy. What's on the left of the operator is the current value object; what's on the right is how many left shifts we should perform.

So for example, given a byte corresponding to 1:

0 0 0 0 0 0 0 1

a single shift to left would lead to:

0 0 0 0 0 0 1 0

Now, if we think of 1 as 2 ^ 0, at every left shift we are incrementing the exponent. Therefore the above byte is equal to 2 ^ 1 and so on:

0 0 0 0 0 0 0 1 // 2 ^ 0 = 1
0 0 0 0 0 0 1 0 // 2 ^ 1 = 2
0 0 0 0 0 1 0 0 // 2 ^ 2 = 4
0 0 0 0 1 0 0 0 // 2 ^ 3 = 8
...

What's operator&?

The binary operator& is the bitwise AND. For each corresponding bit of two bit sets, the resulting bit is 1 if both bits are 1, 0 otherwise. You can use it to check if, in a given bitset, a specific category is present. For example, let's consider category:

0 0 0 0 0 1 0 0

and let's consider a bitset that represents category 1 and 2, but not our category 3:

0 0 0 0 0 0 1 1

The bitwise AND between the two would give 0 (which is implicitly convertible to false):

0 0 0 0 0 1 0 0 &
0 0 0 0 0 0 1 1 =
0 0 0 0 0 0 0 0

On the other hand, if our bit set (now representing the first and third category) contained our category:

0 0 0 0 0 1 0 0 &
0 0 0 0 0 1 0 1 =
0 0 0 0 0 1 0 0

you would have a bitset representing a bit different from 0 (and therefore implicitly convertible to true).

Conclusion

If you represent every category as a single bit in a bit set, you can easily represent a group of categories in a single bit set.

Let's say that we want to represent the four letters A, C, G, T. We could assign a single bit in a bit set of length four:

0 0 0 1 // A
0 0 1 0 // C
0 1 0 0 // G
1 0 0 0 // T

Now let's forge a bitset that represents letters A and G:

0 1 0 1 // A + G

We can check if a given letter is in the bit set via &.

Is there an A?

0 1 0 1 & // A + G
0 0 0 1 = // A
0 0 0 1   // 1 ~ true

Yes, there is. Is there a C?

0 1 0 1 & // A + G
0 0 1 0 = // C
0 0 0 0   // 0 ~ false

Nope. Is there a G?

0 1 0 1 & // A + G
0 1 0 0 = // G
0 1 0 0   // 4 ~ true

Yes, there's. And finally, is there a T?

0 1 0 1 & // A + G
1 0 0 0 = // T
0 0 0 0   // 0 ~ false

No, there's not.

In general

Generally speaking, given a bit set a and the bit set b for the category we want to check for existence in a, the result of & can only be of two kinds:

  1. 0
  2. the value assigned to the category (a power of two)

In C++, testing for:

if (a & b)

can also be specified as:

if ((a & b) == a)

Practical example

Now you should be able to understand that given an enum like:

enum type
    { none              = 0
    , scene             = 1 << 0
    , player_aircraft   = 1 << 1
    , allied_aircraft   = 1 << 2
    , enemy_aircraft    = 1 << 3 };

and these variables:

auto a = scene;
auto b = enemy_aircraft;
auto c = player_aircraft;

the following:

    std::cout << "a is of type: " << ((a & scene) ? "scene" : "not scene") << '\n';    
    std::cout << "b is of type: " << ((b & enemy_aircraft) ? "enemy_aircraft" : "not enemy_aircraft") << '\n'; 
    std::cout << "c is of type: " << ((c & player_aircraft) ? "player_aircraft" : "not player_aircraft") << '\n'; 

will print:

a is of type: scene

b is of type: enemy_aircraft

c is of type: player_aircraft

Live demo

Sign up to request clarification or add additional context in comments.

1 Comment

@flaco The author is not me; it's @StackedCrooked. :D
0

The << operator performs left shift operation. Examples:

1 << 0 (00000001 in binary)

1 << 1 (00000010 in binary)

1 << 2 (00000100 in binary)

so if I would have write : PlayerAircraft = 2 << 1 PlayerAircraft would have been equal to 0b11? am I right or I'm missing something?

2 is 00000010 in binary so 2 << 1 is 4 (00000100 in binary).

Comments

0

& is the bitwise operator AND. The result of its applaying is equal to 1 if both bits (the left and the right operands of the operator) are also equal to 1. Otherwise the result is 0.

Let assume for example that sf::Time dt has value AlliedAircraft defined as AlliedAircraft = 1 << 2 that is equivalent to binary literal 0b100. So if command.category is also contains AlliedAircraft then the result of the operator & will be the same value 0b100

0b100
&
0b100
=====
0b100

So as 0b100 is not equal to zero then the condition in the if statement will be equal to true.

Let's assume that command.category contains for example PlayerAircraft that defined as PlayerAircraft = 1 << 1 that in turn is equivalent to binary literal 0b010 In this case we will get

0b010
&
0b100
=====
0b000

The result value will be equal to zero and the corresponding condition will be equal to false.

Comments

0

This is not really initialisation - the enumeration item are compile time constants, and the bitwise expressions are evaluated at compile time.

The binary representation of each member will be:

 None           : 00000000
 Scene          : 00000001
 PlayerAircraft : 00000010
 AlliedAircraft : 00000100
 EnemyAircraft  : 00001000

Though the actual number of bits will be larger - I have shown only the least significant 8 bits the rest will be zero.

Enumerations of this type might be used when a value may simultaneously represent multiple values - for example the combination of PlayerAircraft | Scene has a unique value 00000011; though not that PlayerAircraft | Scene has type int rather than Type, and it is not clear in this case that this is the purpose of the bit masks.

The use of the bit shift constant expression is probably merely to make it clear that a single bit is being set for each enumeration. You might just as well write:

 None           = 0x00,
 Scene          = 0x01,
 PlayerAircraft = 0x02,
 AlliedAircraft = 0x04,
 EnemyAircraft  : 0x08

Hexadecimal notation is often used because it is a succinct notation for binary values as one digit corresponds exactly to 4 binary digits.

To test whether an individual bit in a binary value is set, you bitwise-& the value with the mask you want to test for. For example:

value      : 1001
Scene Mask : 0001
-----------------
         & : 0000  // Non-zero - value Scene bit is set


value       : 1001
Player Mask : 0010
------------------
          & : 0000  // Zero - Value Palyer bit is not set

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.