• entries
628
1454
• views
1012218

Free code!

149 views

I originally dropped this in a thread in For Beginners, but after thinking about it for a minute I decided maybe someone else could find it handy too, so I'll stick a copy here where it will get a little better visibility.

This is a simple C++ wrapper class for handling bitmasks. It's missing a few more-or-less non-critical features (like the ability to test two Bitmask objects against each other, for instance) but the basics are there, and it works pretty well. It's certainly safer than just globbing some &|^ operator cruft all through the code, and definitely more readable. With a couple of exceptions (mainly tweaked comments) it's straight from the code library I use at work.

/* * bitmask.h *  * This wrapper provides a checked, typesafe mechanism for * storing bitmasks. Each bit's value is defined in an enum * separately, and the enum is provided to the template. * The storage size of the bitmask can be explicitly set as * well using template parameters. * * Note that this object has literally no overhead versus * simply writing the bitfield ops by hand in raw code: the * storage of each instance is minimal and controlled by the * templated storage type; there are no virtual members and * therefore no vtabl for the objects; and all operations * are inlined by the compiler so there is no function call * overhead for manipulating or checking the bitmask. * */#pragma oncetemplateclass Bitmask{public:	Bitmask(Holder defval = 0) : Bitfield(defval) { }	// Sets all bitmask bits which are set in "flags"	inline void Set(FlagEnum flags)	{ Bitfield |= flags; }	// Clears all bitmask bits which are set in "flags"	inline void Clear(FlagEnum flags)	{ Bitfield &= (~flags); }	// Return true if ANY of the bits set in "flags" are	// also set for the bitmask	inline bool Test(FlagEnum flags) const	{ return ((Bitfield & flags) != 0); }	// Return true only if ALL bits set in "flags" are	// also set for the bitmask	inline bool TestAllFlags(FlagEnum flags) const	{ return ((Bitfield & flags) == flags); }protected:	Holder Bitfield;};

Here's a quick sample usage, adapting nobodynews' example from the original thread:
#include "bitmask.h"enum WindowAppearanceFlags : unsigned{   WA_FullScreen = 0x001,   WA_ScrollBarX = 0x002,   WA_ScrollBarY = 0x004,   WA_NoResize = 0x008,   WA_NoMinimize = 0x010};typedef Bitmask<unsigned, WindowAppearanceFlags> WindowAppearanceBitmask;void Foo(){   WindowAppearanceBitmask foomask;   foomask.Set(WA_FullScreen | WA_NoResize);   // Do stuff   if(foomask.Test(WA_NoMinimize))   {       // etc.   }}

No idea if anyone will find that useful or not, but hey, can't hurt [smile]

  foomask.Set(WA_FullScreen | WA_NoResize);


won't compile without warnings, since 'WA_FullScreen | WS_NoResize' is of type unsigned, not of your enumeration type. But if you accept these kinds of warnings, you're basically accepting the same kind of unsafety as when using the holder data type directly. (Hint: what you need to do is overload | etc. for your enumeration type).

Good catch - that was an oversight in my translation of the example usage.

I personally just use multiple Set() calls, since overloading | for all the dozens of enums in practical use is just annoying.

Also, in the places I use it, combinations of fields usually have specific meanings - so e.g. if I need to test FlagA and FlagB at the same time, there's a good reason why. In that case, I just set up an additional enum constant FlagAB that has the bits set for both A and B. That way I can descriptively refer to the combination, rely on type safety, and don't have to mess with lots of operator overloads. The only downside to that trick is that you have to be careful when shuffling the constants around.

Neat trick, but I've tended to solve the readability of such constructs (often used when checking D3D caps bits) via macros. Yes, I know thats A Bad Thing™, but it works [razz]

Cheers,
Jack

Holy crap. I'm not sure what's more surprising: that I'm referenced in someone's journal or that I actually have been reading that journal off and on for a few weeks.

Edit: Like the code, by the way. I'm definately saving this post for future reference.

Create an account

Register a new account