Last time I wrote a class for a bitfield and a macro that allowed us to automatically size the bitfield storage based on size of flag set and platform storage sizes. And that’s great and all, but we only went from something like Bitflag<unsigned int> m_flags to something like Bitflag<BITFLAG_SIZE(28)> m_flags. It’s better from the perspective of what I was writing about in that last post, but you still have a hardcoded 28 sitting there, completely detached from the flag set it is trying to describe. Wouldn’t it be great if you could feed your flag set directly into the BITFLAG_SIZE macro, and then changes to the flag set automatically change the macro, which changes the type? Why, yes, yes it would.
So, can we do it? Absolutely! But, before we get to that answer, we’re going to take a detour through enums.
I love enums. Especially unscoped enums wrapped inside of their own namespaces. I use them all the time. Most of that usage is to describe entries in a statically sized array, along the lines of this:
namespace CommandListLayers { enum Layer { Read, Pivot, Write, NumberOf }; }
I have a system that uses an array of 3 command lists to move render data between the game thread and the render thread; the read layer, the write layer, and the pivot layer. I can initialize the array with CommandListLayers::NumberOf, and any code I write can deal with each of the layers via the associated enumerator. It’s clean and it’s easy. I really like the NumberOf trick, but it’s also kind of tedious to always insert it at the end. Or, being the stupid human that I am, maybe I forget to do it. Who knows! So, one day I came up with this dumb macro.
#define ARRAY_ENUM_BUILDER(name1, name2, ...) \ namespace name1 { \ enum name2 { \ __VA_ARGS__, \ NumberOf \ }; \ }
And that allows the enum declaration to look like this.
ARRAY_ENUM_BUILDER( CommandListLayers, Layer, Read, Pivot, Write )
So, I declared the namespace and enum name, all enumerator entries, and the NumberOf gets tacked onto the end with the correct value. Great! So, what does this have to do with my Bitflag class and the BITFLAG_SIZE macro? Well, given the enum stuff I was already doing in my code, the next logical step was to do something like this.
namespace ProcessToggleFlags { enum Flags { Lighting = (1 << 0), DepthOfField = (1 << 1), Wireframe = (1 << 2), DebugLines = (1 << 3), DebugText = (1 << 4), NumberOf = 5 }; }
So, this is a little less great. I have to manually assign a value to NumberOf since it would otherwise take the next integral value beyond (1 << 4), which isn’t 5, which is what I would want NumberOf to be in this case. So, the macro as it exists for building enums that describe arrays isn’t going to cut it. That’s where this template code comes in!
namespace enum_helpers { template <unsigned long long T> struct enum_size { static const unsigned long long count = enum_size<(T >> 1)>::count + 1; }; template <> struct enum_size<0> { static const unsigned long long count = 0; }; }
Using that template code, I can now create a new macro specifically to build enums for bitfields. And that macro looks like this.
#define BITFLAG_ENUM_BUILDER(name1, name2, ...) \ namespace name1 { \ enum name2 : unsigned long long { \ __VA_ARGS__, \ Last, \ NumberOf = enum_helpers::enum_size<Last - 1>::count \ }; \ }
Which allows my enum to becomes this.
BITFLAG_ENUM_BUILDER( ProcessToggleFlags, Flags, Lighting = (1 << 0), DepthOfField = (1 << 1), Wireframe = (1 << 2), DebugLines = (1 << 3), DebugText = (1 << 4) )
It works more or less the same as the ARRAY_ENUM_BUILDER macro, but it tacks on a Last entry with the sole purpose of being the parameter into the enum_size template, giving us the correct value for NumberOf when dealing with bit flags. So, that’s great, right? Now we can move from Bitflag<BITFLAG_SIZE(28)> m_flags to Bitflag<BITFLAG_SIZE(ProcessToggleFlags::NumberOf)> m_flags. And that’s definitely better. More or less where I want to be with this.
However, there are still some things I’d like to improve. It would be nice if I could get the element count from __VA_ARGS__ or iterate over the contents. Then I could generate the type of the enum, insert the shift values, and any necessary suffixes on the 1’s from inside the macro. And it isn’t like it’s completely undoable, but it moves into the realm of really gross macro code. Code I will probably end up writing for myself, but it’s not overly scaleable so I didn’t want to include it here.
But, that’s it. This template and 2 macros make my life a lot easier. Hopefully it will do the same for someone else. Here is the download link if you want all of the source: EnumHelpers.hpp. And if anyone has suggestions for improvements (especially for doing the things I mentioned in the previous paragraph!), I’d love to hear those.
Until next time!
My solution for the craziness that is enum values representing bits is a little different – maybe it will help you. Apologies in advance for any weird formatting or typos – doing this on my phone.
I have a file that is just the named enum values I want wrapped in a macro taking 1 parameter. An example of this would be something like
LAYER_VALUE(Game)
LAYER_VALUE(Render)
Note the lack of comma or semicolons – it’s important.
Then in the file where you wish to define your enum, you can simply expand those as enum entries, ie:
#define LAYER_VALUE( VAL ) _HELPER_##VAL ,
namespace _HelperLayerValues
{
enum _HelperType
{
#include “theotherfile.inl”
_NumberOf
};
#define LAYER_VALUE( VAL ) VAL = ( 1 << _HELPER_##VAL ) , enum Type { #include "theotherfile.inl" NumberOf = _NumberOf }; } You could also just put the helper enum in a nested namespace if you prefer. Using this approach you avoid using templates and variadic macros by using a macro redefinition and multiple include trick instead. Which is preferable depends on the situation, but I like my approach because if you later want to do some logic for each value, you can much more easily access them independently and use the same redefinition and include trick to have it expand into actual logic.