Enumeration used as a set of bits

One of the most compact ways to represent styles is using bits. Generally programmes use to use integer constants or typedefs for this task. I will show a way that I consider better to express a set of bits. The idea is to add bit operations to an enum type. The main advantage is that using enums and operators we have a clear concept and it avoids type mixture. Using int / longs /defines you can mix everything.

Use:


enum FontStyle
{
   FontStyleNormal    = 1 << 0,
   FontStyleBold      = 1 << 1,
   FontStyleItalic    = 1 << 2,
   FontStyleUnderline = 1 << 3
};

DECLARE_BITSET_ENUM(FontStyle);

int main()
{
  FontStyle style = FontStyleBold | FontStyleItalic;
  // style = (1 << 1); error C2440: '=' : cannot convert from 'int' to 'FontStyle
}
DECLARE_BITSET_ENUM code


 #define DECLARE_BITSET_ENUM(EnumName) \
   inline EnumName operator | (EnumName a, EnumName b) {\
   return static_cast<EnumName>(  static_cast<long>(a) |\
     static_cast<long>(b));\
 }\
 inline EnumName& operator|=(EnumName& a, EnumName b) {\
   a = static_cast<EnumName>(a | b); \
   return a; \
 }\
 inline EnumName operator~ (EnumName a) { \
  return static_cast<EnumName>(~static_cast<long>(a)); \
 }\
 inline EnumName operator& (EnumName a, EnumName b) {\
   return static_cast<EnumName>(static_cast<long>(a) & \
     static_cast<long>(b)); \
 }\
 inline EnumName& operator&=(EnumName& a, EnumName b) {\
   a = static_cast<EnumName>(a & b); \
   return a; \
 }
 

More functions hand-made for each enum to be used as model


 #define FONTSTYLE_SIZE (4)

// #include <string
std::wstring ToStringW(FontStyle e)
{ 
    const wchar_t* strs[FONTSTYLE_SIZE] = {L"FontStyleNormal",
                                           L"FontStyleBold",
                                           L"FontStyleItalic",
                                           L"FontStyleUnderline"};
    std::wstring str;
    int count = 0;
    for (int i = 0 ; i < FONTSTYLE_SIZE; i++)
    {
        if (e & (1 << i))
        {
            if (count > 0)
            str += L" | ";
            str += strs[i];
            count++;
        }
    }
    return str;
}

// #include <string
std::string ToString(FontStyle e)
{ 
    const char* strs[FONTSTYLE_SIZE] = {"FontStyleNormal",
                                        "FontStyleBold",
                                        "FontStyleItalic",
                                        "FontStyleUnderline"};
    std::string str;
    int count = 0;
    for (int i = 0 ; i < FONTSTYLE_SIZE; i++)
    {
        if (e & (1 << i))
        {
            if (count > 0)
            str += " | ";
            str += strs[i];
            count++;
        }
    }
    return str;
}
// #include <ostream
std::wostream& operator << (std::wostream& os, FontStyle e)
{ 
    const wchar_t* strs[FONTSTYLE_SIZE] = {L"FontStyleNormal",
                                           L"FontStyleBold",
                                           L"FontStyleItalic",
                                           L"FontStyle"};
    int count = 0;
    for (int i = 0 ; i < FONTSTYLE_SIZE; i++)
    {
        if (e & (1 << i))
        {
            if (count > 0)
            os << L" | ";
            os << strs[i];
            count++;
        }
    }
    return os;
}

// #include <ostream
std::ostream& operator << (std::ostream& os, FontStyle e)
{ 
    const char* strs[FONTSTYLE_SIZE] = {"FontStyleNormal",
                                        "FontStyleBold",
                                        "FontStyleItalic",
                                        "FontStyle"};
    int count = 0;
    for (int i = 0 ; i < FONTSTYLE_SIZE; i++)
    {
        if (e & (1 << i))
        {
            if (count > 0)
            os << " | ";
            os << strs[i];
            count++;
        }
    }
    return os;
}


inline bool IsValidFontStyle(long v)
{
    return (v & (FontStyleNormal | 
                 FontStyleBold | 
                 FontStyleItalic | 
                 FontStyleUnderline)) == v;
}

inline bool HasOneFontStyle(FontStyle e)
{
    return e == FontStyleNormal || 
           e == FontStyleBold   || 
           e == FontStyleItalic || 
           e == FontStyleUnderline;
}

inline void Add(FontStyle& e, FontStyle items)
{
    e |= items;
}

inline void Remove(FontStyle& e, FontStyle items)
{
    e &= ~items;
}

inline bool HasAll(FontStyle e, FontStyle items)
{
    return (e & items) == items;
}

inline bool HasAny(FontStyle e, FontStyle items)
{
    return e & items;
}

The river puzzle code was made using this type of construction.

Extra functions included


#define DECLARE_BITSET_ENUM(EnumName) \
   inline EnumName operator | (EnumName a, EnumName b) {\
   return static_cast<EnumName>(  static_cast<long>(a) |\
     static_cast<long>(b));\
 }\
 inline EnumName& operator|=(EnumName& a, EnumName b) {\
   a = static_cast<EnumName>(a | b); \
   return a; \
 }\
 inline EnumName operator~ (EnumName a) { \
  return static_cast<EnumName>(~static_cast<long>(a)); \
 }\
 inline EnumName operator& (EnumName a, EnumName b) {\
   return static_cast<EnumName>(static_cast<long>(a) & \
     static_cast<long>(b)); \
 }\
 inline EnumName& operator&=(EnumName& a, EnumName b) {\
   a = static_cast<EnumName>(a & b); \
   return a; \
 }\
inline void Add(EnumName& e, EnumName items)\
{\
    e |= items;\
}\
inline void Remove(EnumName& e, EnumName items)\
{\
    e &= ~items;\
}\
inline bool HasAll(EnumName e, EnumName items)\
{\
    return (e & items) == items;\
}\
inline bool HasAny(EnumName e, EnumName items)\
{\
    return (e & items) != 0;\
}

From string sample

enum LineStyle
{
  Solid,
  Dash,
  Dot
};

LineStyle FromString(const char* psz, LineStyle def)
{
  LineStyle result;
  if (_stricmp(psz, "Solid") == 0)
    result = Solid;
  else if (_stricmp(psz, "Dash") == 0)
    result = Dash;
  else if (_stricmp(psz, "Dot") == 0)
    result = Dot;
  else
    result = def;

  return result;
}

LineStyle FromString(const wchar_t* psz, LineStyle def)
{
  LineStyle result;
  if (_wcsicmp(psz, L"Solid") == 0)
    result = Solid;
  else if (_wcsicmp(psz, L"Dash") == 0)
    result = Dash;
  else if (_wcsicmp(psz, L"Dot") == 0)
    result = Dot;
  else
    result = def;

  return result;
}

History

FromString added 4/11/2010