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_