Flags.h

Go to the documentation of this file.
00001 // -*- C++ -*-
00002 /* GG is a GUI for SDL and OpenGL.
00003    Copyright (C) 2007 T. Zachary Laine
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public License
00007    as published by the Free Software Foundation; either version 2.1
00008    of the License, or (at your option) any later version.
00009    
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014     
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with this library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA
00019 
00020    If you do not wish to comply with the terms of the LGPL please
00021    contact the author as other terms are available for a fee.
00022     
00023    Zach Laine
00024    whatwasthataddress@hotmail.com */
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     // If you have received an error message directing you to the line below, it means you probably have tried to use
00143     // this class with a FlagsType that is not a type generated by GG_FLAG_TYPE.  Use that to generate new flag types.
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     // If you have received an error message directing you to the line below, it means you probably have tried to use
00260     // this class with a FlagsType that is not a type generated by GG_FLAG_TYPE.  Use that to generate new flag types.
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 } // namespace GG
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_

Generated on Wed Mar 26 14:35:41 2008 for GG by  doxygen 1.5.2