Flags.h
Go to the documentation of this file.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 <GG/Exception.h>
00033
00034 #include <boost/lexical_cast.hpp>
00035 #include <boost/serialization/access.hpp>
00036 #include <boost/serialization/nvp.hpp>
00037
00038 #include <iosfwd>
00039 #include <map>
00040 #include <set>
00041
00042
00043 namespace GG {
00044
00045 namespace detail {
00046 inline std::size_t OneBits(unsigned int num)
00047 {
00048 std::size_t retval = 0;
00049 const std::size_t NUM_BITS = sizeof(num) * 8;
00050 for (std::size_t i = 0; i < NUM_BITS; ++i) {
00051 if (num & 1)
00052 ++retval;
00053 num >>= 1;
00054 }
00055 return retval;
00056 }
00057 }
00058
00059
00062 template <class T>
00063 struct is_flag_type : boost::mpl::false_ {};
00064
00065
00073 #define GG_FLAG_TYPE(name) \
00074 class name; \
00075 \
00076 template <> \
00077 struct is_flag_type<name> : boost::mpl::true_ {}; \
00078 \
00079 class name \
00080 { \
00081 public: \
00082 name() : m_value(0) {} \
00083 explicit name(unsigned int value) : \
00084 m_value(value) \
00085 { \
00086 if (1u < detail::OneBits(value)) \
00087 throw std::invalid_argument( \
00088 "Non-bitflag passed to " #name " constructor"); \
00089 } \
00090 bool operator==(name rhs) const \
00091 { return m_value == rhs.m_value; } \
00092 bool operator!=(name rhs) const \
00093 { return m_value != rhs.m_value; } \
00094 bool operator<(name rhs) const \
00095 { return m_value < rhs.m_value; } \
00096 private: \
00097 unsigned int m_value; \
00098 friend class Flags<name>; \
00099 \
00100 friend class boost::serialization::access; \
00101 template <class Archive> \
00102 void serialize(Archive& ar, const unsigned int version) \
00103 { ar & BOOST_SERIALIZATION_NVP(m_value); } \
00104 }; \
00105 \
00106 template <> \
00107 FlagSpec<name>& FlagSpec<name>::instance(); \
00108 \
00109 inline std::ostream& operator<<(std::ostream& os, name n) \
00110 { \
00111 os << FlagSpec<name>::instance().ToString(n); \
00112 return os; \
00113 } \
00114 \
00115 inline std::istream& operator>>(std::istream& is, name& n) \
00116 { \
00117 std::string str; \
00118 is >> str; \
00119 n = FlagSpec<name>::instance().FromString(str); \
00120 return is; \
00121 }
00122
00123
00126 #define GG_FLAGSPEC_IMPL(name) \
00127 template <> \
00128 FlagSpec<name>& FlagSpec<name>::instance() \
00129 { \
00130 static FlagSpec retval; \
00131 return retval; \
00132 }
00133
00134
00152 template <class FlagType>
00153 class GG_API FlagSpec
00154 {
00155 public:
00156
00157
00158
00159
00160 BOOST_MPL_ASSERT((is_flag_type<FlagType>));
00161
00163 typedef typename std::set<FlagType>::iterator iterator;
00165 typedef typename std::set<FlagType>::const_iterator const_iterator;
00166
00168
00169 GG_ABSTRACT_EXCEPTION(Exception);
00170
00172 GG_CONCRETE_EXCEPTION(UnknownFlag, GG::FlagSpec, Exception);
00173
00175 GG_CONCRETE_EXCEPTION(UnknownString, GG::FlagSpec, Exception);
00177
00179 static FlagSpec& instance();
00180
00182
00183 bool contains(FlagType flag) const
00184 { return find(flag) != end(); }
00187 bool permanent(FlagType flag) const
00188 { return m_permanent.find(flag) != m_permanent.end(); }
00191 const_iterator find(FlagType flag) const
00192 { return m_flags.find(flag); }
00194 const_iterator begin() const
00195 { return m_flags.begin(); }
00197 const_iterator end() const
00198 { return m_flags.end(); }
00202 const std::string& ToString(FlagType flag) const
00203 {
00204 typename std::map<FlagType, std::string>::const_iterator it = m_strings.find(flag);
00205 if (it == m_strings.end())
00206 throw UnknownFlag("Could not find string corresponding to unknown flag");
00207 return it->second;
00208 }
00211 FlagType FromString(const std::string& str) const
00212 {
00213 for (typename std::map<FlagType, std::string>::const_iterator it = m_strings.begin();
00214 it != m_strings.end();
00215 ++it) {
00216 if (it->second == str)
00217 return it->first;
00218 }
00219 throw UnknownString("Could not find flag corresponding to unknown string");
00220 return FlagType(0);
00221 }
00223
00225
00229 void insert(FlagType flag, const std::string& name, bool permanent = false)
00230 {
00231 bool insert_successful = m_flags.insert(flag).second;
00232 assert(insert_successful);
00233 if (permanent)
00234 m_permanent.insert(flag);
00235 m_strings[flag] = name;
00236 }
00242 bool erase(FlagType flag)
00243 {
00244 bool retval = true;
00245 if (permanent(flag)) {
00246 retval = false;
00247 } else {
00248 m_flags.erase(flag);
00249 m_permanent.erase(flag);
00250 m_strings.erase(flag);
00251 }
00252 return retval;
00253 }
00255
00256 private:
00257 FlagSpec() {}
00258
00259 std::set<FlagType> m_flags;
00260 std::set<FlagType> m_permanent;
00261 std::map<FlagType, std::string> m_strings;
00262 };
00263
00264
00265 template <class FlagType>
00266 class Flags;
00267
00268 template <class FlagType>
00269 std::ostream& operator<<(std::ostream& os, Flags<FlagType> flags);
00270
00275 template <class FlagType>
00276 class Flags
00277 {
00278 private:
00279 struct ConvertibleToBoolDummy {int _;};
00280
00281 public:
00282
00283
00284
00285
00286 BOOST_MPL_ASSERT((is_flag_type<FlagType>));
00287
00289
00290 GG_ABSTRACT_EXCEPTION(Exception);
00291
00293 GG_CONCRETE_EXCEPTION(UnknownFlag, GG::Flags, Exception);
00295
00297
00298 Flags() : m_flags(0) {}
00302 Flags(FlagType flag) :
00303 m_flags(flag.m_value)
00304 {
00305 if (!FlagSpec<FlagType>::instance().contains(flag))
00306 throw UnknownFlag("Invalid flag with value " + boost::lexical_cast<std::string>(flag.m_value));
00307 }
00309
00311
00314 operator int ConvertibleToBoolDummy::* () const
00315 { return m_flags ? &ConvertibleToBoolDummy::_ : 0; }
00317 bool operator==(Flags<FlagType> rhs) const
00318 { return m_flags == rhs.m_flags; }
00320 bool operator!=(Flags<FlagType> rhs) const
00321 { return m_flags != rhs.m_flags; }
00325 bool operator<(Flags<FlagType> rhs) const
00326 { return m_flags < rhs.m_flags; }
00328
00330
00332 Flags<FlagType>& operator|=(Flags<FlagType> rhs)
00333 {
00334 m_flags |= rhs.m_flags;
00335 return *this;
00336 }
00339 Flags<FlagType>& operator&=(Flags<FlagType> rhs)
00340 {
00341 m_flags &= rhs.m_flags;
00342 return *this;
00343 }
00346 Flags<FlagType>& operator^=(Flags<FlagType> rhs)
00347 {
00348 m_flags ^= rhs.m_flags;
00349 return *this;
00350 }
00352
00353 private:
00354 unsigned int m_flags;
00355
00356 friend std::ostream& operator<<<>(std::ostream& os, Flags<FlagType> flags);
00357
00358 friend class boost::serialization::access;
00359 template <class Archive>
00360 void serialize(Archive& ar, const unsigned int version);
00361 };
00362
00364 template <class FlagType>
00365 std::ostream& operator<<(std::ostream& os, Flags<FlagType> flags)
00366 {
00367 unsigned int flags_data = flags.m_flags;
00368 bool flag_printed = false;
00369 for (std::size_t i = 0; i < sizeof(flags_data) * 8; ++i) {
00370 if (flags_data & 1) {
00371 if (flag_printed)
00372 os << " | ";
00373 os << FlagSpec<FlagType>::instance().ToString(FlagType(1 << i));
00374 flag_printed = true;
00375 }
00376 flags_data >>= 1;
00377 }
00378 return os;
00379 }
00380
00383 template <class FlagType>
00384 Flags<FlagType> operator|(Flags<FlagType> lhs, Flags<FlagType> rhs)
00385 {
00386 Flags<FlagType> retval(lhs);
00387 retval |= rhs;
00388 return retval;
00389 }
00390
00393 template <class FlagType>
00394 Flags<FlagType> operator|(Flags<FlagType> lhs, FlagType rhs)
00395 { return lhs | Flags<FlagType>(rhs); }
00396
00399 template <class FlagType>
00400 Flags<FlagType> operator|(FlagType lhs, Flags<FlagType> rhs)
00401 { return Flags<FlagType>(lhs) | rhs; }
00402
00405 template <class FlagType>
00406 typename boost::enable_if<
00407 is_flag_type<FlagType>,
00408 Flags<FlagType>
00409 >::type
00410 operator|(FlagType lhs, FlagType rhs)
00411 { return Flags<FlagType>(lhs) | Flags<FlagType>(rhs); }
00412
00415 template <class FlagType>
00416 Flags<FlagType> operator&(Flags<FlagType> lhs, Flags<FlagType> rhs)
00417 {
00418 Flags<FlagType> retval(lhs);
00419 retval &= rhs;
00420 return retval;
00421 }
00422
00425 template <class FlagType>
00426 Flags<FlagType> operator&(Flags<FlagType> lhs, FlagType rhs)
00427 { return lhs & Flags<FlagType>(rhs); }
00428
00431 template <class FlagType>
00432 Flags<FlagType> operator&(FlagType lhs, Flags<FlagType> rhs)
00433 { return Flags<FlagType>(lhs) & rhs; }
00434
00437 template <class FlagType>
00438 typename boost::enable_if<
00439 is_flag_type<FlagType>,
00440 Flags<FlagType>
00441 >::type
00442 operator&(FlagType lhs, FlagType rhs)
00443 { return Flags<FlagType>(lhs) & Flags<FlagType>(rhs); }
00444
00447 template <class FlagType>
00448 Flags<FlagType> operator^(Flags<FlagType> lhs, Flags<FlagType> rhs)
00449 {
00450 Flags<FlagType> retval(lhs);
00451 retval ^= rhs;
00452 return retval;
00453 }
00454
00457 template <class FlagType>
00458 Flags<FlagType> operator^(Flags<FlagType> lhs, FlagType rhs)
00459 { return lhs ^ Flags<FlagType>(rhs); }
00460
00463 template <class FlagType>
00464 Flags<FlagType> operator^(FlagType lhs, Flags<FlagType> rhs)
00465 { return Flags<FlagType>(lhs) ^ rhs; }
00466
00469 template <class FlagType>
00470 typename boost::enable_if<
00471 is_flag_type<FlagType>,
00472 Flags<FlagType>
00473 >::type
00474 operator^(FlagType lhs, FlagType rhs)
00475 { return Flags<FlagType>(lhs) ^ Flags<FlagType>(rhs); }
00476
00479 template <class FlagType>
00480 Flags<FlagType> operator~(Flags<FlagType> flags)
00481 {
00482 Flags<FlagType> retval;
00483 const FlagSpec<FlagType>& spec = FlagSpec<FlagType>::instance();
00484 for (typename FlagSpec<FlagType>::const_iterator it = spec.begin(); it != spec.end(); ++it) {
00485 if (!(*it & flags))
00486 retval |= *it;
00487 }
00488 return retval;
00489 }
00490
00493 template <class FlagType>
00494 typename boost::enable_if<
00495 is_flag_type<FlagType>,
00496 Flags<FlagType>
00497 >::type
00498 operator~(FlagType flag)
00499 { return ~Flags<FlagType>(flag); }
00500
00501 }
00502
00503 template <class FlagType>
00504 template <class Archive>
00505 void GG::Flags<FlagType>::serialize(Archive& ar, const unsigned int version)
00506 { ar & BOOST_SERIALIZATION_NVP(m_flags); }
00507
00508 #endif // _GG_Flags_h_