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@gmail.com */
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     // If you have received an error message directing you to the line below,
00157     // it means you probably have tried to use this class with a FlagsType
00158     // that is not a type generated by GG_FLAG_TYPE.  Use that to generate new
00159     // flag types.
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     // If you have received an error message directing you to the line below,
00283     // it means you probably have tried to use this class with a FlagsType
00284     // that is not a type generated by GG_FLAG_TYPE.  Use that to generate new
00285     // flag types.
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 } // namespace GG
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_

Generated on Sat Mar 26 07:08:37 2011 for GG by  doxygen 1.5.9