Question

I use unsigned ints representing a bunch of airplanes in a game. Each plane has two states, flying and grounded. I would like to store this state together with the planes number. What is the "best" way to achieve that? I could use std::maps with the planes and their state in it but that seems overkill and slow. Could it be done using bit flags ? The assigning and testing of the test should be quick.

Pseudo code:

unsigned int Boing = 777;

if( Boing is flying)
 set some bit;

is Boing flying? (how to check for the current state)

Any hint on a simple and fast technique is appreciated!

Was it helpful?

Solution

The fastest and cleanest way is probably to avoid bitfields, and simply define a struct:

struct Plane
{
    bool isFlying;
    unsigned int number;
}

...


std::vector<Plane> planes;
Plane p;
p.isFlying = true;
p.number = 777;
planes.push_back(p);

This method will use more memory than trying to cram the flag into the same word, but will take less work to get/set the fields. Unless you're memory-constrained, I would strongly recommend avoiding trying to pack everything tightly.

You could even consider using an enum rather than a bool for the state.

OTHER TIPS

One simple way would be to just make the number negative if not flying.

struct Stuff
{
  unsigned int Boing: 31;
  unsigned int isFlying: 1;
};

.
.
.

Stuff myStuff;
myStuff.Boing = 777;
myStuff.isFlying = false;

More on bitfields

Assuming you never use the full range of values available in your unsigned int (a reasonable possibility, but far from absolutely certain), you could just limit the range to one fewer bits than an unsigned in contains, and then use the most significant bit to store the "flying" state. In that case, you could do something like:

// This theoretically isn't required to work, but will for most reasonable machines.
unsigned flying_bit = 1 << (CHAR_BITS * sizeof(unsigned));

void take_off(unsigned &plane) {
    plane |= flying_bit;
}

void land(unsigned &plane) { 
    plane &= flying_bit;
}

bool is_flying(unsigned const &plane) { 
    return plane & flying_bit != 0;
}

Another possibility would be to use actual bitfields:

struct plane { 
    uint32_t model: 31;
    uint32_t flying: 1;
};

In this case, you just assign values directly, like:

plane myplane = {777, 0};

myplane.flying = 1; // take off

myplane.flying = 0; // land

Why not just sign your integers? Positive values are flying, negative are not, and zero is invalid.

Use a struct or a class to combine the information "number" and "state", and whatever else you want a plane to be. If you use bit operations on the int (which is possible, just not advisable), changing the state would change the actual number of your plane.

You can pack both the state and the plane number in a unsigned int. Assuming unsigned int is 32bit on your platform

unsigned int myplane;
int planenumber = (myplane & 0xffff ) //can be the plane number
int booleanstate = ((myplane >> 16) & 0xffff) //can be the boolean state

How about a bitset that uses as plane number the bitset index? If you do not need more states then you are done. If you need to you can also use for each state (e.g. crashed, repair needed a separate bitvector so you use exactly one bit for each plane state you actually need.

But I doubt that speed well be your main concern if you deal with a game graphics and physics will eat up most of your CPU time compared to operations on your plane states.

#include <iostream>
#include <boost/dynamic_bitset.hpp>

using namespace boost;

class State
{
public:
    State(int nPlanes):_States(dynamic_bitset<>(nPlanes))
    {
    }

    void SetState(int nPlane, bool bFly)
    {
        _States[nPlane] = bFly;
    }

    void Dump()
    {
        for (boost::dynamic_bitset<>::size_type i = 0; i < _States.size(); ++i)
            std::cout << _States[i];
    }

private:
    dynamic_bitset<> _States;
};


int _tmain(int argc, _TCHAR* argv[])
{
    State planes(500);
    planes.SetState(0, true);
    planes.SetState(5,true);
    planes.Dump();

    return 0;
}

Let's say your unsigned int has 32 bits:

#define SET_FLYING(x)     (x) |= (1<<31)
#define SET_GROUNDED(x)   (x) &= ~(1<<31)
#define IS_FLYING(x)      ((x) & (1<<31))
#define ID(x)             ((x) & ~(1<<31))

If you want to be more c++ stylish, you could write those as inline functions. Anyway, I wrote it more to show you how the bit manipulation is done, rather than whether to implement it as macro or as function.

To make it work with different sizes of int, you could change the 31 to:

instead of 31: ((sizeof(x)<<3)-1)

Which is basically sizeof(x)*8-1

P.S. If anyone wants to tell me "No no! Don't use macros, this is C++, use this overly complicated thing I wrote", save your breath. Just give the -1 and move on.

edit: What I wrote above was the answer to your question: "How to use the sign bit as a flag". If you want to do this in a better way, yet don't expand your memory usage (by adding a bool), you can always write something like this:

struct airplane
{
    unsigned int id: 31;
    unsigned int is_flying: 1;
};

airplane Boing = {777, false};

Then, assigning to and reading from id or is_flying does the bit operations, but they are handled by the compiler.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top