00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00029 #ifndef _GG_Flags_h_
00030 #define _GG_Flags_h_
00031
00032 #include <boost/lexical_cast.hpp>
00033 #include <boost/serialization/access.hpp>
00034 #include <boost/serialization/nvp.hpp>
00035
00036 #include <iosfwd>
00037 #include <map>
00038 #include <set>
00039 #include <stdexcept>
00040
00041
00042 namespace GG {
00043
00044 namespace detail {
00045 inline int OneBits(unsigned int num)
00046 {
00047 int retval = 0;
00048 const int NUM_BITS = sizeof(num) * 8;
00049 for (int i = 0; i < NUM_BITS; ++i) {
00050 if (num & 1)
00051 ++retval;
00052 num >>= 1;
00053 }
00054 return retval;
00055 }
00056 }
00057
00058
00060 template <class T>
00061 struct is_flag_type : boost::mpl::false_ {};
00062
00063
00067 #define GG_FLAG_TYPE(name) \
00068 class name; \
00069 \
00070 template <> \
00071 struct is_flag_type<name> : boost::mpl::true_ {}; \
00072 \
00073 class name \
00074 { \
00075 public: \
00076 name() : m_value(0) {} \
00077 explicit name(unsigned int value) : \
00078 m_value(value) \
00079 { \
00080 if (1 < detail::OneBits(value)) \
00081 throw std::invalid_argument( \
00082 "Non-bitflag passed to " #name " constructor"); \
00083 } \
00084 bool operator==(name rhs) const \
00085 { return m_value == rhs.m_value; } \
00086 bool operator!=(name rhs) const \
00087 { return m_value != rhs.m_value; } \
00088 bool operator<(name rhs) const \
00089 { return m_value < rhs.m_value; } \
00090 private: \
00091 unsigned int m_value; \
00092 friend class Flags<name>; \
00093 \
00094 friend class boost::serialization::access; \
00095 template <class Archive> \
00096 void serialize(Archive& ar, const unsigned int version) \
00097 { ar & BOOST_SERIALIZATION_NVP(m_value); } \
00098 }; \
00099 \
00100 template <> \
00101 FlagSpec<name>& FlagSpec<name>::instance(); \
00102 \
00103 inline std::ostream& operator<<(std::ostream& os, name n) \
00104 { \
00105 os << FlagSpec<name>::instance().ToString(n); \
00106 return os; \
00107 } \
00108 \
00109 inline std::istream& operator>>(std::istream& is, name& n) \
00110 { \
00111 std::string str; \
00112 is >> str; \
00113 n = FlagSpec<name>::instance().FromString(str); \
00114 return is; \
00115 }
00116
00117
00119 #define GG_FLAGSPEC_IMPL(name) \
00120 template <> \
00121 FlagSpec<name>& FlagSpec<name>::instance() \
00122 { \
00123 static FlagSpec retval; \
00124 return retval; \
00125 }
00126
00127
00138 template <class FlagType>
00139 class GG_API FlagSpec
00140 {
00141 public:
00142
00143
00144 BOOST_MPL_ASSERT((is_flag_type<FlagType>));
00145
00147 typedef typename std::set<FlagType>::iterator iterator;
00149 typedef typename std::set<FlagType>::const_iterator const_iterator;
00150
00152
00153 GG_ABSTRACT_EXCEPTION(Exception);
00154
00156 GG_CONCRETE_EXCEPTION(UnknownFlag, GG::FlagSpec, Exception);
00157
00159 GG_CONCRETE_EXCEPTION(UnknownString, GG::FlagSpec, Exception);
00161
00163 static FlagSpec& instance();
00164
00166
00167 bool contains(FlagType flag) const
00168 { return find(flag) != end(); }
00171 bool permanent(FlagType flag) const
00172 { return m_permanent.find(flag) != m_permanent.end(); }
00174 const_iterator find(FlagType flag) const
00175 { return m_flags.find(flag); }
00177 const_iterator begin() const
00178 { return m_flags.begin(); }
00180 const_iterator end() const
00181 { return m_flags.end(); }
00184 const std::string& ToString(FlagType flag) const
00185 {
00186 typename std::map<FlagType, std::string>::const_iterator it = m_strings.find(flag);
00187 if (it == m_strings.end())
00188 throw UnknownFlag("Could not find string corresponding to unknown flag");
00189 return it->second;
00190 }
00193 FlagType FromString(const std::string& str) const
00194 {
00195 for (typename std::map<FlagType, std::string>::const_iterator it = m_strings.begin();
00196 it != m_strings.end();
00197 ++it) {
00198 if (it->second == str)
00199 return it->first;
00200 }
00201 throw UnknownString("Could not find flag corresponding to unknown string");
00202 return FlagType(0);
00203 }
00205
00207
00210 void insert(FlagType flag, const std::string& name, bool permanent = false)
00211 {
00212 bool insert_successful = m_flags.insert(flag).second;
00213 assert(insert_successful);
00214 if (permanent)
00215 m_permanent.insert(flag);
00216 m_strings[flag] = name;
00217 }
00221 bool erase(FlagType flag)
00222 {
00223 bool retval = true;
00224 if (permanent(flag)) {
00225 retval = false;
00226 } else {
00227 m_flags.erase(flag);
00228 m_permanent.erase(flag);
00229 m_strings.erase(flag);
00230 }
00231 return retval;
00232 }
00234
00235 private:
00236 FlagSpec() {}
00237
00238 std::set<FlagType> m_flags;
00239 std::set<FlagType> m_permanent;
00240 std::map<FlagType, std::string> m_strings;
00241 };
00242
00243
00244 template <class FlagType>
00245 class Flags;
00246
00247 template <class FlagType>
00248 std::ostream& operator<<(std::ostream& os, Flags<FlagType> flags);
00249
00252 template <class FlagType>
00253 class Flags
00254 {
00255 private:
00256 struct ConvertibleToBoolDummy {int _;};
00257
00258 public:
00259
00260
00261 BOOST_MPL_ASSERT((is_flag_type<FlagType>));
00262
00264
00265 GG_ABSTRACT_EXCEPTION(Exception);
00266
00268 GG_CONCRETE_EXCEPTION(UnknownFlag, GG::Flags, Exception);
00270
00272
00273 Flags() : m_flags(0) {}
00276 Flags(FlagType flag) :
00277 m_flags(flag.m_value)
00278 {
00279 if (!FlagSpec<FlagType>::instance().contains(flag))
00280 throw UnknownFlag("Invalid flag with value " + boost::lexical_cast<std::string>(flag.m_value));
00281 }
00283
00285
00287 operator int ConvertibleToBoolDummy::* () const
00288 { return m_flags ? &ConvertibleToBoolDummy::_ : 0; }
00290 bool operator==(Flags<FlagType> rhs) const
00291 { return m_flags == rhs.m_flags; }
00293 bool operator!=(Flags<FlagType> rhs) const
00294 { return m_flags != rhs.m_flags; }
00297 bool operator<(Flags<FlagType> rhs) const
00298 { return m_flags < rhs.m_flags; }
00300
00302
00303 Flags<FlagType>& operator|=(Flags<FlagType> rhs)
00304 {
00305 m_flags |= rhs.m_flags;
00306 return *this;
00307 }
00309 Flags<FlagType>& operator&=(Flags<FlagType> rhs)
00310 {
00311 m_flags &= rhs.m_flags;
00312 return *this;
00313 }
00315 Flags<FlagType>& operator^=(Flags<FlagType> rhs)
00316 {
00317 m_flags ^= rhs.m_flags;
00318 return *this;
00319 }
00321
00322 private:
00323 unsigned int m_flags;
00324
00325 friend std::ostream& operator<<<>(std::ostream& os, Flags<FlagType> flags);
00326
00327 friend class boost::serialization::access;
00328 template <class Archive>
00329 void serialize(Archive& ar, const unsigned int version);
00330 };
00331
00333 template <class FlagType>
00334 std::ostream& operator<<(std::ostream& os, Flags<FlagType> flags)
00335 {
00336 unsigned int flags_data = flags.m_flags;
00337 bool flag_printed = false;
00338 for (unsigned int i = 0; i < sizeof(flags_data) * 8; ++i) {
00339 if (flags_data & 1) {
00340 if (flag_printed)
00341 os << " | ";
00342 os << FlagSpec<FlagType>::instance().ToString(FlagType(1 << i));
00343 flag_printed = true;
00344 }
00345 flags_data >>= 1;
00346 }
00347 return os;
00348 }
00349
00351 template <class FlagType>
00352 Flags<FlagType> operator|(Flags<FlagType> lhs, Flags<FlagType> rhs)
00353 {
00354 Flags<FlagType> retval(lhs);
00355 retval |= rhs;
00356 return retval;
00357 }
00358
00360 template <class FlagType>
00361 Flags<FlagType> operator|(Flags<FlagType> lhs, FlagType rhs)
00362 { return lhs | Flags<FlagType>(rhs); }
00363
00365 template <class FlagType>
00366 Flags<FlagType> operator|(FlagType lhs, Flags<FlagType> rhs)
00367 { return Flags<FlagType>(lhs) | rhs; }
00368
00370 template <class FlagType>
00371 typename boost::enable_if<
00372 is_flag_type<FlagType>,
00373 Flags<FlagType>
00374 >::type
00375 operator|(FlagType lhs, FlagType rhs)
00376 { return Flags<FlagType>(lhs) | Flags<FlagType>(rhs); }
00377
00379 template <class FlagType>
00380 Flags<FlagType> operator&(Flags<FlagType> lhs, Flags<FlagType> rhs)
00381 {
00382 Flags<FlagType> retval(lhs);
00383 retval &= rhs;
00384 return retval;
00385 }
00386
00388 template <class FlagType>
00389 Flags<FlagType> operator&(Flags<FlagType> lhs, FlagType rhs)
00390 { return lhs & Flags<FlagType>(rhs); }
00391
00393 template <class FlagType>
00394 Flags<FlagType> operator&(FlagType lhs, Flags<FlagType> rhs)
00395 { return Flags<FlagType>(lhs) & rhs; }
00396
00398 template <class FlagType>
00399 typename boost::enable_if<
00400 is_flag_type<FlagType>,
00401 Flags<FlagType>
00402 >::type
00403 operator&(FlagType lhs, FlagType rhs)
00404 { return Flags<FlagType>(lhs) & Flags<FlagType>(rhs); }
00405
00407 template <class FlagType>
00408 Flags<FlagType> operator^(Flags<FlagType> lhs, Flags<FlagType> rhs)
00409 {
00410 Flags<FlagType> retval(lhs);
00411 retval ^= rhs;
00412 return retval;
00413 }
00414
00416 template <class FlagType>
00417 Flags<FlagType> operator^(Flags<FlagType> lhs, FlagType rhs)
00418 { return lhs ^ Flags<FlagType>(rhs); }
00419
00421 template <class FlagType>
00422 Flags<FlagType> operator^(FlagType lhs, Flags<FlagType> rhs)
00423 { return Flags<FlagType>(lhs) ^ rhs; }
00424
00426 template <class FlagType>
00427 typename boost::enable_if<
00428 is_flag_type<FlagType>,
00429 Flags<FlagType>
00430 >::type
00431 operator^(FlagType lhs, FlagType rhs)
00432 { return Flags<FlagType>(lhs) ^ Flags<FlagType>(rhs); }
00433
00435 template <class FlagType>
00436 Flags<FlagType> operator~(Flags<FlagType> flags)
00437 {
00438 Flags<FlagType> retval;
00439 const FlagSpec<FlagType>& spec = FlagSpec<FlagType>::instance();
00440 for (typename FlagSpec<FlagType>::const_iterator it = spec.begin(); it != spec.end(); ++it) {
00441 if (!(*it & flags))
00442 retval |= *it;
00443 }
00444 return retval;
00445 }
00446
00448 template <class FlagType>
00449 typename boost::enable_if<
00450 is_flag_type<FlagType>,
00451 Flags<FlagType>
00452 >::type
00453 operator~(FlagType flag)
00454 { return ~Flags<FlagType>(flag); }
00455
00456 }
00457
00458 template <class FlagType>
00459 template <class Archive>
00460 void GG::Flags<FlagType>::serialize(Archive& ar, const unsigned int version)
00461 { ar & BOOST_SERIALIZATION_NVP(m_flags); }
00462
00463 #endif // _GG_Flags_h_