Last active
August 29, 2015 14:02
-
-
Save coderforlife/6d8bac451d49dd1a0c81 to your computer and use it in GitHub Desktop.
C++Flags
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "Flags.hpp" | |
#include <iostream> | |
BOOST_FLAGS_WITH_VALUES(MyFlags, std::uint8_t, A, 1, B, 2, AB, 3, C, 4); | |
BOOST_FLAGS(MyDefaultFlags, AX, BX, CX, DX, EX, FX, GX, HX); | |
namespace MyNS | |
{ | |
BOOST_FLAGS(MyFlags, M, N, O, P, Q); | |
} | |
// To be in a class, one must separate declarartion from definition | |
// This must be also done when the declaration is in a shared header file | |
class MyClass | |
{ | |
public: BOOST_FLAGS_DECL(MyFlags, M, N, O, P, Q); | |
}; | |
BOOST_FLAGS_DEFN(MyClass::MyFlags, M, N, O, P, Q); | |
int main(int argc, char** argv) | |
{ | |
{ | |
MyFlags A = MyFlags::A; | |
MyFlags B = MyFlags::B; | |
MyFlags C = MyFlags::C; | |
MyFlags None = MyFlags::None; | |
std::cout << (int)+A << " " << (int)+B << " " << (int)+MyFlags::AB << " " << (int)+C << " " << (int)+(A|C) << std::endl; | |
std::cout << (int)+None << " " << (int)+~None << std::endl; | |
std::cout << (int)+(A&B) << " " << (int)+(A & MyFlags::AB) << std::endl; | |
std::cout << std::endl; | |
std::cout << A << " " << B << " " << C << " " << MyFlags::AB << " " << (A|C) << std::endl; | |
std::cout << None << " " << ~None << std::endl; | |
std::cout << (A&B) << " " << (A & MyFlags::AB) << std::endl; | |
std::cout << std::endl; | |
std::cout << MyFlags::from_name("A") << " " << MyFlags::from_name("B") << " " << MyFlags::from_name("C") << " " << MyFlags::from_name("AB") << " " << MyFlags::from_name("A|C") << std::endl; | |
std::cout << MyFlags::from_name("None") << " " << MyFlags::from_name(" A | B | C ") << std::endl; | |
std::cout << std::endl; | |
for (auto i = MyFlags::members().begin(), end = MyFlags::members().end(); i != end; ++i) { std::cout << i->name() << " " << *i << " " << (int)+*i << std::endl; } | |
std::cout << std::endl; | |
} | |
{ | |
MyDefaultFlags A = MyDefaultFlags::AX; | |
MyDefaultFlags B = MyDefaultFlags::BX; | |
MyDefaultFlags C = MyDefaultFlags::CX; | |
//MyDefaultFlags D = MyDefaultFlags::DX; | |
//MyDefaultFlags E = MyDefaultFlags::EX; | |
//MyDefaultFlags F = MyDefaultFlags::FX; | |
//MyDefaultFlags G = MyDefaultFlags::GX; | |
MyDefaultFlags H = MyDefaultFlags::HX; | |
MyDefaultFlags None = MyDefaultFlags::None; | |
std::cout << (int)+A << " " << (int)+B << " " << (int)+C << " " << (int)+H << " " << (int)+(A|C) << std::endl; | |
std::cout << (int)+None << " " << (int)+~None << std::endl; | |
std::cout << (int)+(A&B) << " " << (int)+(A&H) << std::endl; | |
std::cout << std::endl; | |
std::cout << A << " " << B << " " << C << " " << H << " " << (A|C) << std::endl; | |
std::cout << None << " " << ~None << std::endl; | |
std::cout << (A&B) << " " << (A & H) << std::endl; | |
std::cout << std::endl; | |
std::cout << MyDefaultFlags::from_name("AX") << " " << MyDefaultFlags::from_name("BX") << " " << MyDefaultFlags::from_name("CX") << " " << MyDefaultFlags::from_name("HX") << " " << MyDefaultFlags::from_name("AX|CX") << std::endl; | |
std::cout << MyDefaultFlags::from_name("None") << " " << MyDefaultFlags::from_name(" AX | BX | CX ") << std::endl; | |
std::cout << std::endl; | |
auto m = MyDefaultFlags::members(); | |
for (auto i = m.begin(), end = m.end(); i != end; ++i) { std::cout << i->name() << " " << *i << " " << (int)+*i << std::endl; } | |
std::cout << std::endl; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <boost/config.hpp> | |
#include <stdexcept> | |
#include <iostream> | |
#include <utility> | |
#include <cstdint> | |
#include <cstring> | |
#include <cctype> | |
#include <string> | |
#include <array> | |
// TODO: one day make all flags names and None constexpr, but this can't be done until the C++ standard is clarified | |
/////////////////////////////////////////////////////////////////////////////// | |
// Type-safe, bit-wise flags, for representing many true/false options in a | |
// compact variable. Uses template and macro magic to make them easy to use and | |
// safe. This uses many C++11 features including constexpr, variadic templates, | |
// explicit cast operators, and initializer lists. If any of these are missing, | |
// they are emulated with some side-effect. See the end for details. | |
// | |
// You create a flags type by using the FLAGS and FLAGS_WITH_VALUES macros: | |
// | |
// FLAGS(TYPE_NAME, FLAG_NAME_1, FLAG_NAME_2, ...) | |
// FLAGS_WITH_VALUES(TYPE_NAME, BASE_TYPE, NAME_1, VAL_1, NAME_2, VAL_2, ...) | |
// | |
// The FLAGS macro creates a new class named TYPE_NAME with static members with | |
// the given flag names, each having a unique power of two value. The base | |
// integral type is determined by the number of flags given. | |
// | |
// The FLAGS_WITH_VALUES macro allows you to specify the value for each flag. | |
// Like FLAGS, it creates a new class named TYPE_NAME. The base integral type | |
// is given by BASE_TYPE. The names and values for the flags are given | |
// alternating. Every flag must have a value after it. | |
// | |
// FLAGS() and FLAGS_WITH_VALUES() cannot be used inside a class directly or | |
// within a header without multiply-defined symbols. To do either of these | |
// you need to seperate declarations and defininitions, an example is: | |
// | |
// class MyClass { FLAGS_DECL(MyFlags, A, B, C); }; // in header file | |
// FLAGS_DEFN(MyClass::MyFlags, A, B, C); // in source file | |
// | |
// The created flags class can then be explicitly constructed from a value of | |
// the integral base type, from another instance of the flags, or | |
// default-constructed with no flags set. All given flag names along with | |
// a special "None" name are available as static members of the class as well. | |
// Flags instances can also be can also be obtained using strings with their | |
// names through the from_name static methods. | |
// Flags instances behave much like you would expect them to, supporting the | |
// basic bit-wise operators. Additionally the flags can be converted to | |
// strings and directly output to ostreams. | |
// | |
// Flags have the following static members (all are const): | |
// Flags * - all of the named flags | |
// Flags None - Flags instance representing no flags set (a value of 0) | |
// | |
// Flags have the following member functions (all are const): | |
// const char* const rawname() - the flag name, "None", or NULL if not a named flag | |
// std::string name() - the flag name, "None", or a "|" joined list of named flags (e.g. "A|B") | |
// | |
// Flags have the following std::ostream adapter: | |
// std::ostream& operator<< (std::ostream& s, const Flags& b) - writes the result of name() to the stream | |
// | |
// Flags have the following static functions: | |
// Flags from_name(std::string name) - Gets a Flags from its string representation, supporting all return values from name() in addition to whitespace padding around each flag-name (e.g. "A | B") | |
// Flags from_name(const char* name) - Same as above but with a null-terminated C-style string | |
// Flags from_name(const char* name, size_t len) - Same as above but with a C-style string of a given length len | |
// std::array<Flags,*> members() - a collection of all named flags | |
// | |
// Flags support many operators (all non-compound are const and constexpr): | |
// explicit operator base_type() - Explicitly cast to the integral base type | |
// base_type operator +() - Get the integral base type | |
// explicit operator bool() - Explicitly cast to bool, true when at least one flag is set | |
// bool operator!() - True when no flags are set | |
// bool operator==(MyFlags) - True when both MyFlags have the same set of flags set | |
// bool operator!=(MyFlags) - True when the MyFlags do not have the same flags set | |
// MyFlags operator~() - Flips every bit that is covered by a flag | |
// MyFlags operator&(MyFlags) [and &=] - Only keeps the flags set that both MyFlags have set | |
// MyFlags operator|(MyFlags) [and |=] - Keeps the flags set that either MyFlags have set | |
// MyFlags operator^(MyFlags) [and ^=] - Keeps the flags that are set in one but not the other | |
// | |
// The overhead of individual flags is minimal, each flags only contains a | |
// single variable of the integral base type. However, the class as a whole | |
// keeps a lot of static data but still it should be not so large and since | |
// it is not copied anywhere. | |
// | |
// Flags cannot have the following names (or any C++ keyword): | |
// _mask, _count, _name, _values, _x, | |
// super_type, base_type, type, name, rawname, from_name, members, None | |
// This list is not necessarily complete but should be close. | |
// | |
// Emulated C++11 Features Side-Effects: | |
// variadic templates: takes more run-time memory (up to 2 kb), does not | |
// detect illegal flag values (=0) during creation | |
// explicit cast operators: cannot explicitly cast to base type (use + | |
// instead) and 'slow' and problematic bool casting | |
// constexpr: lacking some optimizations, minor though | |
/////////////////////////////////////////////////////////////////////////////// | |
// Gets around a bug in MSVC when passing __VA_ARGS__ to another macro | |
#ifdef _MSC_VER | |
#define BOOST_FLAGS___EXPAND(x) x | |
#else | |
#define BOOST_FLAGS___EXPAND(...) __VA_ARGS__ | |
#endif | |
#ifdef BOOST_NO_CXX11_CONSTEXPR | |
#define BOOST_FLAGS___INIT_IF_NO_CONSTEXPR(...) = { __VA_ARGS__ } | |
#define BOOST_FLAGS___INIT_IF_HAS_CONSTEXPR(...) | |
#else | |
#define BOOST_FLAGS___INIT_IF_NO_CONSTEXPR(...) | |
#define BOOST_FLAGS___INIT_IF_HAS_CONSTEXPR(...) = { __VA_ARGS__ } | |
#endif | |
namespace detail | |
{ | |
#ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES | |
#define Values(B, A) \ | |
B V1 A, B V2 A, B V3 A, B V4 A, B V5 A, B V6 A, B V7 A, B V8 A, \ | |
B V9 A, B V10 A, B V11 A, B V12 A, B V13 A, B V14 A, B V15 A, B V16 A, \ | |
B V17 A, B V18 A, B V19 A, B V20 A, B V21 A, B V22 A, B V23 A, B V24 A, \ | |
B V25 A, B V26 A, B V27 A, B V28 A, B V29 A, B V30 A, B V31 A, B V32 A | |
#endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES | |
#ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES | |
template <class BaseType, class FlagsType, size_t Count, Values(BaseType, = 0)> | |
#else // BOOST_NO_CXX11_VARIADIC_TEMPLATES | |
template <class BaseType, class FlagsType, size_t, BaseType... Values> | |
#endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES | |
class flags_base | |
{ | |
public: | |
typedef BaseType base_type; | |
typedef FlagsType type; | |
static const type None; // no flags set | |
protected: | |
// Flag value (only non-static variable) | |
base_type _x; | |
#ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES | |
// Number of named flags | |
static BOOST_CONSTEXPR const size_t _count = Count; | |
// OR flag values together to get the mask of all flags | |
static BOOST_CONSTEXPR const base_type _mask = | |
V1 | V2 | V3 | V4 | V5 | V6 | V7 | V8 | | |
V9 | V10 | V11 | V12 | V13 | V14 | V15 | V16 | | |
V17 | V18 | V19 | V20 | V21 | V22 | V23 | V24 | | |
V25 | V26 | V27 | V28 | V29 | V30 | V31 | V32; | |
// Keep track of all flag values | |
static BOOST_CONSTEXPR const base_type _values[32] | |
BOOST_FLAGS___INIT_IF_HAS_CONSTEXPR(Values(, )); | |
#else // BOOST_NO_CXX11_VARIADIC_TEMPLATES | |
// Number of named flags | |
static BOOST_CONSTEXPR const size_t _count = sizeof...(Values); | |
// Recursively OR flag values together to get the mask of all flags | |
template<base_type... Vs> struct _or; | |
template<base_type V> | |
struct _or<V> | |
{ | |
static_assert(V != 0, "No flag may have a value of 0"); | |
static BOOST_CONSTEXPR const base_type x = V; | |
}; | |
template<base_type V, base_type... Vs> | |
struct _or<V, Vs...> | |
{ | |
static_assert(V != 0, "No flag may have a value of 0"); | |
static BOOST_CONSTEXPR const base_type x = V | _or<Vs...>::x; | |
}; | |
static BOOST_CONSTEXPR const base_type _mask = _or<Values...>::x; | |
// Keep track of all flag values | |
static BOOST_CONSTEXPR const base_type _values[_count] | |
BOOST_FLAGS___INIT_IF_HAS_CONSTEXPR(Values...); | |
#endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES | |
public: | |
static const std::array<type, _count>& members() | |
{ | |
#ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES | |
static std::array<type, _count> m; | |
if (m[0] == type::None) | |
{ | |
for (size_t i = 0; i < type::_count; ++i) | |
{ | |
m[i] = type(type::_values[i]); | |
} | |
} | |
#else // BOOST_NO_CXX11_VARIADIC_TEMPLATES | |
static const std::array<type, _count> m = { type(Values)... }; | |
#endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES | |
return m; | |
} | |
///// Constructors and casts ///// | |
inline BOOST_CONSTEXPR flags_base() : _x(0) { } | |
inline BOOST_CONSTEXPR flags_base(const type& b) : _x(b._x) { } | |
inline explicit flags_base(base_type b) : _x(b) | |
{ | |
if ((b | type::_mask) != type::_mask) | |
{ | |
throw std::domain_error("Flag value outside mask"); | |
} | |
} | |
inline BOOST_CONSTEXPR base_type operator+() const { return this->_x; } | |
#ifdef BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS | |
private: | |
struct _dummy { void nonnull() {}; }; | |
typedef void (_dummy::*_safe_bool)(); | |
public: | |
inline BOOST_CONSTEXPR operator _safe_bool() const | |
{ | |
return this->_x != 0 ? &_dummy::nonnull : 0; | |
} | |
// no cast to base_type since it can't be explicit, use unary + operator instead | |
#else // BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS | |
inline BOOST_CONSTEXPR explicit operator bool() const { return _x != 0; } | |
inline BOOST_CONSTEXPR explicit operator base_type() const { return _x; } | |
#endif // BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS | |
///// Bit-wise operators ///// | |
inline BOOST_CONSTEXPR bool operator!() const { return this->_x == 0; } | |
inline BOOST_CONSTEXPR bool operator==(const type b) const { return _x == b._x; } | |
inline BOOST_CONSTEXPR bool operator!=(const type b) const { return _x != b._x; } | |
inline BOOST_CONSTEXPR type operator ~() const { return type(~_x & type::_mask); } | |
inline BOOST_CONSTEXPR type operator & (const type b) const { return type(_x & b._x); } | |
inline BOOST_CONSTEXPR type operator | (const type b) const { return type(_x | b._x); } | |
inline BOOST_CONSTEXPR type operator ^ (const type b) const { return type(_x ^ b._x); } | |
inline type& operator &=(const type b) { _x &= b._x; return *static_cast<type*>(this); } | |
inline type& operator |=(const type b) { _x |= b._x; return *static_cast<type*>(this); } | |
inline type& operator ^=(const type b) { _x ^= b._x; return *static_cast<type*>(this); } | |
///// String/flag conversions ///// | |
// Returns "None", a predefined name, or NULL | |
inline const char* const rawname() const | |
{ | |
if (this->_x == 0) { return "None"; } | |
for (size_t i = 0; i < _count; ++i) | |
{ | |
if (this->_x == type::_values[i]) { return type::_name(i); } | |
} | |
return NULL; | |
} | |
// Returns "None", a predefined name, or a string composed of predefined | |
// names separated by a pipe "|". | |
inline const std::string name() const | |
{ | |
const char* const n = this->rawname(); | |
if (n) { return n; } | |
std::string s = ""; | |
for (size_t i = 0; i < type::_count; ++i) | |
{ | |
if ((this->_x & type::_values[i]) == type::_values[i]) | |
{ | |
if (s.size()) { s += '|'; } | |
s += type::_name(i); | |
} | |
} | |
return s; | |
} | |
friend inline std::ostream& operator<< (std::ostream& s, const type& b) | |
{ | |
return s << b.name(); | |
} | |
// Reverses "name()" accepting predefined names and "None" separated by | |
// a pipe "|" while ignoring whitespace before and after each name - | |
// throws std::invalid_argument if a name is not valid. | |
static inline type from_name(const char *name, size_t len) | |
{ | |
// Remove leading and trailing whitespace | |
while (*name && std::isspace(*name)) { ++name; --len; } | |
while (len>0 && std::isspace(name[len - 1])) { --len; } | |
const char *pipe = (const char*)std::memchr(name, '|', len); | |
if (pipe == NULL) | |
{ | |
// No "pipe", we have a single name | |
if (len == 4 && !std::strncmp(name, "None", 4)) { return type(0); } | |
for (size_t i = 0; i < type::_count; ++i) | |
{ | |
const char* n = type::_name(i); | |
if (len == std::strlen(n) && !std::strncmp(name, n, len)) | |
{ | |
return type(type::_values[i]); | |
} | |
} | |
throw std::invalid_argument( | |
"Flags name '" + std::string(name, len) + "' not found"); | |
} | |
// There is a pipe, split string up at pipes and process each part | |
type b = type::from_name(name, pipe - name); | |
len -= pipe - name; | |
name = pipe + 1; | |
while ((pipe = (const char*)std::memchr(name, '|', len)) != NULL) | |
{ | |
b |= type::from_name(name, pipe - name); | |
len -= pipe - name; | |
name = pipe + 1; | |
} | |
b |= type::from_name(name, len - 1); | |
return b; | |
} | |
static inline type from_name(const char * name) | |
{ | |
return type::from_name(name, std::strlen(name)); | |
} | |
static inline type from_name(const std::string name) | |
{ | |
return type::from_name(name.c_str(), name.size()); | |
} | |
}; | |
#ifdef BOOST_NO_CXX11_VARIADIC_TEMPLATES | |
// Define values | |
template <class B, class F, size_t C, Values(B, )> | |
BOOST_CONSTEXPR const B flags_base<B, F, C, Values(, )>::_values[32] | |
BOOST_FLAGS___INIT_IF_NO_CONSTEXPR(Values(, )); | |
// Define the None flag | |
template <class B, class F, size_t C, Values(B, )> const F flags_base<B, F, C, Values(, )>::None; | |
#undef Values | |
#else // BOOST_NO_CXX11_VARIADIC_TEMPLATES | |
// Define values | |
template <class B, class F, size_t C, B... V> | |
BOOST_CONSTEXPR const B flags_base<B, F, C, V...>::_values[flags_base<B, F, C, V...>::_count] | |
BOOST_FLAGS___INIT_IF_NO_CONSTEXPR(V...); | |
// Define the None flag | |
template <class B, class F, size_t C, B... V> const F flags_base<B, F, C, V...>::None; | |
#endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES | |
} | |
////////// Helper macros ////////// | |
// GET_ARG_32(0, __VA_ARGS__, ...) Gets the 32nd argument from __VA_ARGS__+... | |
#define BOOST_FLAGS___GET_ARG_32(X,X32,X31,X30,X29,X28,X27,X26,X25,X24,X23,X22,X21,X20,X19,X18,X17,X16,X15,X14,X13,X12,X11,X10,X9,X8,X7,X6,X5,X4,X3,X2,X1,N,...) N | |
// GET_ARG_64(0, __VA_ARGS__, ...) Gets the 64th argument from __VA_ARGS__+... | |
#define BOOST_FLAGS___GET_ARG_64(X,X64,X63,X62,X61,X60,X59,X58,X57,X56,X55,X54,X53,X52,X51,X50,X49,X48,X47,X46,X45,X44,X43,X42,X41,X40,X39,X38,X37,X36,X35,X34,X33,X32,X31,X30,X29,X28,X27,X26,X25,X24,X23,X22,X21,X20,X19,X18,X17,X16,X15,X14,X13,X12,X11,X10,X9,X8,X7,X6,X5,X4,X3,X2,X1,N,...) N | |
// NUM_ARGS(...) evaluates to the number of the passed-in arguments | |
#define BOOST_FLAGS___NUM_ARGS(...) \ | |
BOOST_FLAGS___EXPAND(BOOST_FLAGS___GET_ARG_64(0,__VA_ARGS__, \ | |
64,63,62,61,60,59,58,57,56,55,54,53,52,51,50,49, \ | |
48,47,46,45,44,43,42,41,40,39,38,37,36,35,34,33, \ | |
32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17, \ | |
16,15,14,13,12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)) | |
// BASE_TYPE(...) evaluates to the base type that will fit the number of flags given by the var args | |
#define BOOST_FLAGS___BASE_TYPE(...) \ | |
BOOST_FLAGS___EXPAND(BOOST_FLAGS___GET_ARG_32(0,__VA_ARGS__, \ | |
::std::uint32_t,::std::uint32_t,::std::uint32_t,::std::uint32_t, \ | |
::std::uint32_t,::std::uint32_t,::std::uint32_t,::std::uint32_t, \ | |
::std::uint32_t,::std::uint32_t,::std::uint32_t,::std::uint32_t, \ | |
::std::uint32_t,::std::uint32_t,::std::uint32_t,::std::uint32_t, \ | |
::std::uint16_t,::std::uint16_t,::std::uint16_t,::std::uint16_t, \ | |
::std::uint16_t,::std::uint16_t,::std::uint16_t,::std::uint16_t, \ | |
::std::uint8_t, ::std::uint8_t, ::std::uint8_t, ::std::uint8_t, \ | |
::std::uint8_t, ::std::uint8_t, ::std::uint8_t, ::std::uint8_t)) /* TODO: last one as bool? */ | |
// POW2(...) evaluates to the maximum power of 2 that will be given to a flag for the given var args | |
#define BOOST_FLAGS___POW2(...) \ | |
BOOST_FLAGS___EXPAND(BOOST_FLAGS___GET_ARG_32(0,__VA_ARGS__, \ | |
0x80000000, 0x40000000, 0x20000000, 0x10000000, \ | |
0x08000000, 0x04000000, 0x02000000, 0x01000000, \ | |
0x00800000, 0x00400000, 0x00200000, 0x00100000, \ | |
0x00080000, 0x00040000, 0x00020000, 0x00010000, \ | |
0x00008000, 0x00004000, 0x00002000, 0x00001000, \ | |
0x00000800, 0x00000400, 0x00000200, 0x00000100, \ | |
0x00000080, 0x00000040, 0x00000020, 0x00000010, \ | |
0x00000008, 0x00000004, 0x00000002, 0x00000001)) | |
////////// NVLIST: expands a list of name-values using an X macro ////////// | |
// X is a macro that takes the NAME of the class, and a flag name-value pair | |
// T is the type of the flags class | |
// S is a separator between items (once evaluated with ()) | |
// N is the length of the list | |
#define BOOST_FLAGS___NVLIST(X,T,S,N,...) BOOST_FLAGS___EXPAND(BOOST_FLAGS___NVL##N(X,T,S,__VA_ARGS__)) | |
#define BOOST_FLAGS___NVL2(X,T,S,N,V) X(T,N,V) | |
#define BOOST_FLAGS___NVL4(X,T,S,N,V,...) X(T,N,V)S()BOOST_FLAGS___EXPAND(BOOST_FLAGS___NVL2(X,T,S,__VA_ARGS__)) | |
#define BOOST_FLAGS___NVL6(X,T,S,N,V,...) X(T,N,V)S()BOOST_FLAGS___EXPAND(BOOST_FLAGS___NVL4(X,T,S,__VA_ARGS__)) | |
#define BOOST_FLAGS___NVL8(X,T,S,N,V,...) X(T,N,V)S()BOOST_FLAGS___EXPAND(BOOST_FLAGS___NVL6(X,T,S,__VA_ARGS__)) | |
#define BOOST_FLAGS___NVL10(X,T,S,N,V,...) X(T,N,V)S()BOOST_FLAGS___EXPAND(BOOST_FLAGS___NVL8(X,T,S,__VA_ARGS__)) | |
#define BOOST_FLAGS___NVL12(X,T,S,N,V,...) X(T,N,V)S()BOOST_FLAGS___EXPAND(BOOST_FLAGS___NVL10(X,T,S,__VA_ARGS__)) | |
#define BOOST_FLAGS___NVL14(X,T,S,N,V,...) X(T,N,V)S()BOOST_FLAGS___EXPAND(BOOST_FLAGS___NVL12(X,T,S,__VA_ARGS__)) | |
#define BOOST_FLAGS___NVL16(X,T,S,N,V,...) X(T,N,V)S()BOOST_FLAGS___EXPAND(BOOST_FLAGS___NVL14(X,T,S,__VA_ARGS__)) | |
#define BOOST_FLAGS___NVL18(X,T,S,N,V,...) X(T,N,V)S()BOOST_FLAGS___EXPAND(BOOST_FLAGS___NVL16(X,T,S,__VA_ARGS__)) | |
#define BOOST_FLAGS___NVL20(X,T,S,N,V,...) X(T,N,V)S()BOOST_FLAGS___EXPAND(BOOST_FLAGS___NVL18(X,T,S,__VA_ARGS__)) | |
#define BOOST_FLAGS___NVL22(X,T,S,N,V,...) X(T,N,V)S()BOOST_FLAGS___EXPAND(BOOST_FLAGS___NVL20(X,T,S,__VA_ARGS__)) | |
#define BOOST_FLAGS___NVL24(X,T,S,N,V,...) X(T,N,V)S()BOOST_FLAGS___EXPAND(BOOST_FLAGS___NVL22(X,T,S,__VA_ARGS__)) | |
#define BOOST_FLAGS___NVL26(X,T,S,N,V,...) X(T,N,V)S()BOOST_FLAGS___EXPAND(BOOST_FLAGS___NVL24(X,T,S,__VA_ARGS__)) | |
#define BOOST_FLAGS___NVL28(X,T,S,N,V,...) X(T,N,V)S()BOOST_FLAGS___EXPAND(BOOST_FLAGS___NVL26(X,T,S,__VA_ARGS__)) | |
#define BOOST_FLAGS___NVL30(X,T,S,N,V,...) X(T,N,V)S()BOOST_FLAGS___EXPAND(BOOST_FLAGS___NVL28(X,T,S,__VA_ARGS__)) | |
#define BOOST_FLAGS___NVL32(X,T,S,N,V,...) X(T,N,V)S()BOOST_FLAGS___EXPAND(BOOST_FLAGS___NVL30(X,T,S,__VA_ARGS__)) | |
#define BOOST_FLAGS___NVL34(X,T,S,N,V,...) X(T,N,V)S()BOOST_FLAGS___EXPAND(BOOST_FLAGS___NVL32(X,T,S,__VA_ARGS__)) | |
#define BOOST_FLAGS___NVL36(X,T,S,N,V,...) X(T,N,V)S()BOOST_FLAGS___EXPAND(BOOST_FLAGS___NVL34(X,T,S,__VA_ARGS__)) | |
#define BOOST_FLAGS___NVL38(X,T,S,N,V,...) X(T,N,V)S()BOOST_FLAGS___EXPAND(BOOST_FLAGS___NVL36(X,T,S,__VA_ARGS__)) | |
#define BOOST_FLAGS___NVL40(X,T,S,N,V,...) X(T,N,V)S()BOOST_FLAGS___EXPAND(BOOST_FLAGS___NVL38(X,T,S,__VA_ARGS__)) | |
#define BOOST_FLAGS___NVL42(X,T,S,N,V,...) X(T,N,V)S()BOOST_FLAGS___EXPAND(BOOST_FLAGS___NVL40(X,T,S,__VA_ARGS__)) | |
#define BOOST_FLAGS___NVL44(X,T,S,N,V,...) X(T,N,V)S()BOOST_FLAGS___EXPAND(BOOST_FLAGS___NVL42(X,T,S,__VA_ARGS__)) | |
#define BOOST_FLAGS___NVL46(X,T,S,N,V,...) X(T,N,V)S()BOOST_FLAGS___EXPAND(BOOST_FLAGS___NVL44(X,T,S,__VA_ARGS__)) | |
#define BOOST_FLAGS___NVL48(X,T,S,N,V,...) X(T,N,V)S()BOOST_FLAGS___EXPAND(BOOST_FLAGS___NVL46(X,T,S,__VA_ARGS__)) | |
#define BOOST_FLAGS___NVL50(X,T,S,N,V,...) X(T,N,V)S()BOOST_FLAGS___EXPAND(BOOST_FLAGS___NVL48(X,T,S,__VA_ARGS__)) | |
#define BOOST_FLAGS___NVL52(X,T,S,N,V,...) X(T,N,V)S()BOOST_FLAGS___EXPAND(BOOST_FLAGS___NVL50(X,T,S,__VA_ARGS__)) | |
#define BOOST_FLAGS___NVL54(X,T,S,N,V,...) X(T,N,V)S()BOOST_FLAGS___EXPAND(BOOST_FLAGS___NVL52(X,T,S,__VA_ARGS__)) | |
#define BOOST_FLAGS___NVL56(X,T,S,N,V,...) X(T,N,V)S()BOOST_FLAGS___EXPAND(BOOST_FLAGS___NVL54(X,T,S,__VA_ARGS__)) | |
#define BOOST_FLAGS___NVL58(X,T,S,N,V,...) X(T,N,V)S()BOOST_FLAGS___EXPAND(BOOST_FLAGS___NVL56(X,T,S,__VA_ARGS__)) | |
#define BOOST_FLAGS___NVL60(X,T,S,N,V,...) X(T,N,V)S()BOOST_FLAGS___EXPAND(BOOST_FLAGS___NVL58(X,T,S,__VA_ARGS__)) | |
#define BOOST_FLAGS___NVL62(X,T,S,N,V,...) X(T,N,V)S()BOOST_FLAGS___EXPAND(BOOST_FLAGS___NVL60(X,T,S,__VA_ARGS__)) | |
#define BOOST_FLAGS___NVL64(X,T,S,N,V,...) X(T,N,V)S()BOOST_FLAGS___EXPAND(BOOST_FLAGS___NVL62(X,T,S,__VA_ARGS__)) | |
// Separators for NVLIST | |
#define BOOST_FLAGS___COMMA() , | |
#define BOOST_FLAGS___SEMICOLON() ; | |
// X-macros for NVLIST | |
#define BOOST_FLAGS___XNAME(T, N, V) #N | |
#define BOOST_FLAGS___XVALUE(T, N, V) V | |
#define BOOST_FLAGS___XDECL(T, N, V) static const type N | |
#define BOOST_FLAGS___XDEFN(T, N, V) const T T::N(V) | |
////////// CREATE: Create the actual flags class ////////// | |
// T is the typename of the new flags-class | |
// BT is the base typename for the flags | |
// N is the number of flags (== NUM_ARGS(__VA_ARGS__)) | |
// First stage of creation expands __VA_ARGS__ into all necessary forms | |
#define BOOST_FLAGS___CREATE_DECL(T, BT, N, ...) \ | |
BOOST_FLAGS___CREATE2_DECL(T, BT, N, \ | |
BOOST_FLAGS___NVLIST(BOOST_FLAGS___XNAME, T, BOOST_FLAGS___COMMA, N, __VA_ARGS__), \ | |
BOOST_FLAGS___NVLIST(BOOST_FLAGS___XVALUE, T, BOOST_FLAGS___COMMA, N, __VA_ARGS__), \ | |
BOOST_FLAGS___NVLIST(BOOST_FLAGS___XDECL, T, BOOST_FLAGS___SEMICOLON, N, __VA_ARGS__) \ | |
) | |
#define BOOST_FLAGS___CREATE_DEFN(T, BT, N, ...) \ | |
BOOST_FLAGS___NVLIST(BOOST_FLAGS___XDEFN, T, BOOST_FLAGS___SEMICOLON, N, __VA_ARGS__) | |
// Second stage no longer needs __VA_ARGS__ | |
#define BOOST_FLAGS___CREATE2_DECL(T, BT, N, NAMES, VALS, DECS) \ | |
class T : public ::detail::flags_base<BT, T, N / 2, VALS> \ | |
{ \ | |
typedef ::detail::flags_base<BT, T, N / 2, VALS> super_type; \ | |
friend super_type; \ | |
static_assert(std::is_integral<BT>::value, \ | |
"Flags base type must be integral"); \ | |
static_assert(N != 0, \ | |
"Must have at least one flag name"); \ | |
static_assert(((N&1)==0) && (super_type::_count*2==N), \ | |
"Number of flag names and values must be the same"); \ | |
inline static const char* _name(size_t i) \ | |
{ \ | |
static const char* const n[type::_count] = { NAMES }; \ | |
return n[i]; \ | |
} \ | |
public: \ | |
typedef BT base_type; \ | |
typedef T type; \ | |
inline BOOST_CONSTEXPR T() : super_type() { } \ | |
inline BOOST_CONSTEXPR T(const type& b) : super_type(b) { } \ | |
inline explicit T(base_type b) : super_type(b) { } \ | |
inline type& operator=(const type& b) { _x = b._x; return *this; } \ | |
DECS; \ | |
}; | |
////////// ADDVAL: Adds powers of two between each flag name ////////// | |
#define BOOST_FLAGS___ADDVAL(MAX,N,...) BOOST_FLAGS___EXPAND(BOOST_FLAGS___ADDVAL_(MAX,N,__VA_ARGS__)) | |
#define BOOST_FLAGS___ADDVAL_(M,N,...) BOOST_FLAGS___EXPAND(BOOST_FLAGS___ADDVAL##N(M,__VA_ARGS__)) /* indirection layer */ | |
#define BOOST_FLAGS___ADDVAL1(M,N) N,M | |
#define BOOST_FLAGS___ADDVAL2(M,N,...) N,(M>>1),BOOST_FLAGS___EXPAND(BOOST_FLAGS___ADDVAL1(M,__VA_ARGS__)) | |
#define BOOST_FLAGS___ADDVAL3(M,N,...) N,(M>>2),BOOST_FLAGS___EXPAND(BOOST_FLAGS___ADDVAL2(M,__VA_ARGS__)) | |
#define BOOST_FLAGS___ADDVAL4(M,N,...) N,(M>>3),BOOST_FLAGS___EXPAND(BOOST_FLAGS___ADDVAL3(M,__VA_ARGS__)) | |
#define BOOST_FLAGS___ADDVAL5(M,N,...) N,(M>>4),BOOST_FLAGS___EXPAND(BOOST_FLAGS___ADDVAL4(M,__VA_ARGS__)) | |
#define BOOST_FLAGS___ADDVAL6(M,N,...) N,(M>>5),BOOST_FLAGS___EXPAND(BOOST_FLAGS___ADDVAL5(M,__VA_ARGS__)) | |
#define BOOST_FLAGS___ADDVAL7(M,N,...) N,(M>>6),BOOST_FLAGS___EXPAND(BOOST_FLAGS___ADDVAL6(M,__VA_ARGS__)) | |
#define BOOST_FLAGS___ADDVAL8(M,N,...) N,(M>>7),BOOST_FLAGS___EXPAND(BOOST_FLAGS___ADDVAL7(M,__VA_ARGS__)) | |
#define BOOST_FLAGS___ADDVAL9(M,N,...) N,(M>>8),BOOST_FLAGS___EXPAND(BOOST_FLAGS___ADDVAL8(M,__VA_ARGS__)) | |
#define BOOST_FLAGS___ADDVAL10(M,N,...) N,(M>>9),BOOST_FLAGS___EXPAND(BOOST_FLAGS___ADDVAL9(M,__VA_ARGS__)) | |
#define BOOST_FLAGS___ADDVAL11(M,N,...) N,(M>>10),BOOST_FLAGS___EXPAND(BOOST_FLAGS___ADDVAL10(M,__VA_ARGS__)) | |
#define BOOST_FLAGS___ADDVAL12(M,N,...) N,(M>>11),BOOST_FLAGS___EXPAND(BOOST_FLAGS___ADDVAL11(M,__VA_ARGS__)) | |
#define BOOST_FLAGS___ADDVAL13(M,N,...) N,(M>>12),BOOST_FLAGS___EXPAND(BOOST_FLAGS___ADDVAL12(M,__VA_ARGS__)) | |
#define BOOST_FLAGS___ADDVAL14(M,N,...) N,(M>>13),BOOST_FLAGS___EXPAND(BOOST_FLAGS___ADDVAL13(M,__VA_ARGS__)) | |
#define BOOST_FLAGS___ADDVAL15(M,N,...) N,(M>>14),BOOST_FLAGS___EXPAND(BOOST_FLAGS___ADDVAL14(M,__VA_ARGS__)) | |
#define BOOST_FLAGS___ADDVAL16(M,N,...) N,(M>>15),BOOST_FLAGS___EXPAND(BOOST_FLAGS___ADDVAL15(M,__VA_ARGS__)) | |
#define BOOST_FLAGS___ADDVAL17(M,N,...) N,(M>>16),BOOST_FLAGS___EXPAND(BOOST_FLAGS___ADDVAL16(M,__VA_ARGS__)) | |
#define BOOST_FLAGS___ADDVAL18(M,N,...) N,(M>>17),BOOST_FLAGS___EXPAND(BOOST_FLAGS___ADDVAL17(M,__VA_ARGS__)) | |
#define BOOST_FLAGS___ADDVAL19(M,N,...) N,(M>>18),BOOST_FLAGS___EXPAND(BOOST_FLAGS___ADDVAL18(M,__VA_ARGS__)) | |
#define BOOST_FLAGS___ADDVAL20(M,N,...) N,(M>>19),BOOST_FLAGS___EXPAND(BOOST_FLAGS___ADDVAL19(M,__VA_ARGS__)) | |
#define BOOST_FLAGS___ADDVAL21(M,N,...) N,(M>>20),BOOST_FLAGS___EXPAND(BOOST_FLAGS___ADDVAL20(M,__VA_ARGS__)) | |
#define BOOST_FLAGS___ADDVAL22(M,N,...) N,(M>>21),BOOST_FLAGS___EXPAND(BOOST_FLAGS___ADDVAL21(M,__VA_ARGS__)) | |
#define BOOST_FLAGS___ADDVAL23(M,N,...) N,(M>>22),BOOST_FLAGS___EXPAND(BOOST_FLAGS___ADDVAL22(M,__VA_ARGS__)) | |
#define BOOST_FLAGS___ADDVAL24(M,N,...) N,(M>>23),BOOST_FLAGS___EXPAND(BOOST_FLAGS___ADDVAL23(M,__VA_ARGS__)) | |
#define BOOST_FLAGS___ADDVAL25(M,N,...) N,(M>>24),BOOST_FLAGS___EXPAND(BOOST_FLAGS___ADDVAL24(M,__VA_ARGS__)) | |
#define BOOST_FLAGS___ADDVAL26(M,N,...) N,(M>>25),BOOST_FLAGS___EXPAND(BOOST_FLAGS___ADDVAL25(M,__VA_ARGS__)) | |
#define BOOST_FLAGS___ADDVAL27(M,N,...) N,(M>>26),BOOST_FLAGS___EXPAND(BOOST_FLAGS___ADDVAL26(M,__VA_ARGS__)) | |
#define BOOST_FLAGS___ADDVAL28(M,N,...) N,(M>>27),BOOST_FLAGS___EXPAND(BOOST_FLAGS___ADDVAL27(M,__VA_ARGS__)) | |
#define BOOST_FLAGS___ADDVAL29(M,N,...) N,(M>>28),BOOST_FLAGS___EXPAND(BOOST_FLAGS___ADDVAL28(M,__VA_ARGS__)) | |
#define BOOST_FLAGS___ADDVAL30(M,N,...) N,(M>>29),BOOST_FLAGS___EXPAND(BOOST_FLAGS___ADDVAL29(M,__VA_ARGS__)) | |
#define BOOST_FLAGS___ADDVAL31(M,N,...) N,(M>>30),BOOST_FLAGS___EXPAND(BOOST_FLAGS___ADDVAL30(M,__VA_ARGS__)) | |
#define BOOST_FLAGS___ADDVAL32(M,N,...) N,(M>>31),BOOST_FLAGS___EXPAND(BOOST_FLAGS___ADDVAL31(M,__VA_ARGS__)) | |
#define BOOST_FLAGS___ADDVALS_AND_CREATE(X, TYPE_NAME, ...) \ | |
BOOST_FLAGS___EXPAND(X( \ | |
TYPE_NAME, \ | |
BOOST_FLAGS___BASE_TYPE(__VA_ARGS__), \ | |
BOOST_FLAGS___ADDVAL( \ | |
BOOST_FLAGS___POW2(__VA_ARGS__), \ | |
BOOST_FLAGS___NUM_ARGS(__VA_ARGS__), \ | |
__VA_ARGS__ \ | |
) \ | |
)) | |
////////// Create a set of flags with the given values ////////// | |
#define BOOST_FLAGS_WITH_VALUES(TYPE_NAME, BASE_TYPE, ...) \ | |
BOOST_FLAGS___CREATE_DECL( \ | |
TYPE_NAME, BASE_TYPE, BOOST_FLAGS___NUM_ARGS(__VA_ARGS__), __VA_ARGS__ \ | |
) \ | |
BOOST_FLAGS___CREATE_DEFN( \ | |
TYPE_NAME, BASE_TYPE, BOOST_FLAGS___NUM_ARGS(__VA_ARGS__), __VA_ARGS__ \ | |
) | |
#define BOOST_FLAGS_WITH_VALUES_DECL(TYPE_NAME, BASE_TYPE, ...) \ | |
BOOST_FLAGS___CREATE_DECL( \ | |
TYPE_NAME, BASE_TYPE, BOOST_FLAGS___NUM_ARGS(__VA_ARGS__), __VA_ARGS__ \ | |
) | |
#define BOOST_FLAGS_WITH_VALUES_DEFN(TYPE_NAME, BASE_TYPE, ...) \ | |
BOOST_FLAGS___CREATE_DEFN( \ | |
TYPE_NAME, BASE_TYPE, BOOST_FLAGS___NUM_ARGS(__VA_ARGS__), __VA_ARGS__ \ | |
) | |
////////// Create a set of flags with default powers-of-two values ////////// | |
#define BOOST_FLAGS(TYPE_NAME, ...) \ | |
BOOST_FLAGS___ADDVALS_AND_CREATE(BOOST_FLAGS_WITH_VALUES, TYPE_NAME, __VA_ARGS__) | |
#define BOOST_FLAGS_DECL(TYPE_NAME, ...) \ | |
BOOST_FLAGS___ADDVALS_AND_CREATE(BOOST_FLAGS_WITH_VALUES_DECL, TYPE_NAME, __VA_ARGS__) | |
#define BOOST_FLAGS_DEFN(TYPE_NAME, ...) \ | |
BOOST_FLAGS___ADDVALS_AND_CREATE(BOOST_FLAGS_WITH_VALUES_DEFN, TYPE_NAME, __VA_ARGS__) |
Added support for separating declaration from definition, allowing the flags to be declared in a class and avoiding multilply-defined symbols. One day, a clarification of constexpr may alleviate this need.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Large overhaul, having the same API as before (except for creation), much more portable, and less code. The MSVC-specific version is combined into the main version, simply detecting for support of variadic templates. Tested and working with gcc 4.8.2, clang 3.4, mingw-w64 4.8.2, msvc 2010, and msvc 2013.