GG: Flags.h Source File

GG

- Main Page
- Related Pages
- Namespaces
- Classes
- Files

- File List
- File Members

Flags.h
Go to the documentation of this file.
1 // -*- C++ -*-
2 /* GG is a GUI for SDL and OpenGL.
3 Copyright (C) 2007 T. Zachary Laine
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public License
7 as published by the Free Software Foundation; either version 2.1
8 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free
17 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA
19
20 If you do not wish to comply with the terms of the LGPL please
21 contact the author as other terms are available for a fee.
22
23 Zach Laine
24 whatwasthataddress@gmail.com */
25
29 #ifndef _GG_Flags_h_
30 #define _GG_Flags_h_
31
32 #include <GG/Exception.h>
33
34 #include <boost/utility/enable_if.hpp>
35 #include <boost/lexical_cast.hpp>
36 #include <boost/mpl/assert.hpp>
37
38 #include <cassert>
39 #include <iosfwd>
40 #include <map>
41 #include <set>
42
43
44 namespace GG {
45
46 namespace detail {
47 inline std::size_t OneBits(unsigned int num)
48 {
49 std::size_t retval = 0;
50 const std::size_t NUM_BITS = sizeof(num) * 8;
51 for (std::size_t i = 0; i < NUM_BITS; ++i) {
52 if (num & 1)
53 ++retval;
54 num >>= 1;
55 }
56 return retval;
57 }
58 }
59
60
63 template <class T>
64 struct is_flag_type : boost::mpl::false_ {};
65
66
74 #define GG_FLAG_TYPE(name) \
75 class name; \
76 \
77 template <> \
78 struct is_flag_type<name> : boost::mpl::true_ {}; \
79 \
80 class name \
81 { \
82 public: \
83 name() : m_value(0) {} \
84 explicit name(unsigned int value) : \
85 m_value(value) \
86 { \
87 if (1u < detail::OneBits(value)) \
88 throw std::invalid_argument( \
89 "Non-bitflag passed to " #name " constructor"); \
90 } \
91 bool operator==(name rhs) const \
92 { return m_value == rhs.m_value; } \
93 bool operator!=(name rhs) const \
94 { return m_value != rhs.m_value; } \
95 bool operator<(name rhs) const \
96 { return m_value < rhs.m_value; } \
97 private: \
98 unsigned int m_value; \
99 friend class Flags<name>; \
100 }; \
101 \
102 template <> \
103 FlagSpec<name>& FlagSpec<name>::instance(); \
104 \
105 inline std::ostream& operator<<(std::ostream& os, name n) \
106 { \
107 os << FlagSpec<name>::instance().ToString(n); \
108 return os; \
109 } \
110 \
111 inline std::istream& operator>>(std::istream& is, name& n) \
112 { \
113 std::string str; \
114 is >> str; \
115 n = FlagSpec<name>::instance().FromString(str); \
116 return is; \
117 }
118
119
122 #define GG_FLAGSPEC_IMPL(name) \
123 template <> \
124 FlagSpec<name>& FlagSpec<name>::instance() \
125 { \
126 static FlagSpec retval; \
127 return retval; \
128 }
129
130
148 template <class FlagType>
149 class GG_API FlagSpec
150 {
151 public:
152 // If you have received an error message directing you to the line below,
153 // it means you probably have tried to use this class with a FlagsType
154 // that is not a type generated by GG_FLAG_TYPE. Use that to generate new
155 // flag types.
156 BOOST_MPL_ASSERT((is_flag_type<FlagType>));
157
159 typedef typename std::set<FlagType>::iterator iterator;
161 typedef typename std::set<FlagType>::const_iterator const_iterator;
162
164
165 GG_ABSTRACT_EXCEPTION(Exception);
166
168 GG_CONCRETE_EXCEPTION(UnknownFlag, GG::FlagSpec, Exception);
169
171 GG_CONCRETE_EXCEPTION(UnknownString, GG::FlagSpec, Exception);
173
175 static FlagSpec& instance();
176
178
179 bool contains(FlagType flag) const
180 { return find(flag) != end(); }
183 bool permanent(FlagType flag) const
184 { return m_permanent.find(flag) != m_permanent.end(); }
187 const_iterator find(FlagType flag) const
188 { return m_flags.find(flag); }
190 const_iterator begin() const
191 { return m_flags.begin(); }
193 const_iterator end() const
194 { return m_flags.end(); }
198 const std::string& ToString(FlagType flag) const
199 {
200 typename std::map<FlagType, std::string>::const_iterator it = m_strings.find(flag);
201 if (it == m_strings.end())
202 throw UnknownFlag("Could not find string corresponding to unknown flag");
203 return it->second;
204 }
207 FlagType FromString(const std::string& str) const
208 {
209 for (typename std::map<FlagType, std::string>::const_iterator it = m_strings.begin();
210 it != m_strings.end();
211 ++it) {
212 if (it->second == str)
213 return it->first;
214 }
215 throw UnknownString("Could not find flag corresponding to unknown string");
216 return FlagType(0);
217 }
219
221
225 void insert(FlagType flag, const std::string& name, bool permanent = false)
226 {
227 #ifndef NDEBUG
228 bool insert_successful =
229 #endif
230 m_flags.insert(flag).second;
231 assert(insert_successful);
232 if (permanent)
233 m_permanent.insert(flag);
234 m_strings[flag] = name;
235 }
241 bool erase(FlagType flag)
242 {
243 bool retval = true;
244 if (permanent(flag)) {
245 retval = false;
246 } else {
247 m_flags.erase(flag);
248 m_permanent.erase(flag);
249 m_strings.erase(flag);
250 }
251 return retval;
252 }
254
255 private:
256 FlagSpec() {}
257
258 std::set<FlagType> m_flags;
259 std::set<FlagType> m_permanent;
260 std::map<FlagType, std::string> m_strings;
261 };
262
263
264 template <class FlagType>
265 class Flags;
266
267 template <class FlagType>
268 std::ostream& operator<<(std::ostream& os, Flags<FlagType> flags);
269
274 template <class FlagType>
275 class Flags
276 {
277 private:
278 struct ConvertibleToBoolDummy {int _;};
279
280 public:
281 // If you have received an error message directing you to the line below,
282 // it means you probably have tried to use this class with a FlagsType
283 // that is not a type generated by GG_FLAG_TYPE. Use that to generate new
284 // flag types.
285 BOOST_MPL_ASSERT((is_flag_type<FlagType>));
286
288
289 GG_ABSTRACT_EXCEPTION(Exception);
290
292 GG_CONCRETE_EXCEPTION(UnknownFlag, GG::Flags, Exception);
294
296
297 Flags() : m_flags(0) {}
301 Flags(FlagType flag) :
302 m_flags(flag.m_value)
303 {
304 if (!FlagSpec<FlagType>::instance().contains(flag))
305 throw UnknownFlag("Invalid flag with value " + boost::lexical_cast<std::string>(flag.m_value));
306 }
308
310
313 operator int ConvertibleToBoolDummy::* () const
314 { return m_flags ? &ConvertibleToBoolDummy::_ : 0; }
316 bool operator==(Flags<FlagType> rhs) const
317 { return m_flags == rhs.m_flags; }
319 bool operator!=(Flags<FlagType> rhs) const
320 { return m_flags != rhs.m_flags; }
324 bool operator<(Flags<FlagType> rhs) const
325 { return m_flags < rhs.m_flags; }
327
329
331 Flags<FlagType>& operator|=(Flags<FlagType> rhs)
332 {
333 m_flags |= rhs.m_flags;
334 return *this;
335 }
338 Flags<FlagType>& operator&=(Flags<FlagType> rhs)
339 {
340 m_flags &= rhs.m_flags;
341 return *this;
342 }
345 Flags<FlagType>& operator^=(Flags<FlagType> rhs)
346 {
347 m_flags ^= rhs.m_flags;
348 return *this;
349 }
351
352 private:
353 unsigned int m_flags;
354
355 friend std::ostream& operator<<<>(std::ostream& os, Flags<FlagType> flags);
356 };
357
359 template <class FlagType>
360 std::ostream& operator<<(std::ostream& os, Flags<FlagType> flags)
361 {
362 unsigned int flags_data = flags.m_flags;
363 bool flag_printed = false;
364 for (std::size_t i = 0; i < sizeof(flags_data) * 8; ++i) {
365 if (flags_data & 1) {
366 if (flag_printed)
367 os << " | ";
368 os << FlagSpec<FlagType>::instance().ToString(FlagType(1 << i));
369 flag_printed = true;
370 }
371 flags_data >>= 1;
372 }
373 return os;
374 }
375
378 template <class FlagType>
379 Flags<FlagType> operator|(Flags<FlagType> lhs, Flags<FlagType> rhs)
380 {
381 Flags<FlagType> retval(lhs);
382 retval |= rhs;
383 return retval;
384 }
385
388 template <class FlagType>
389 Flags<FlagType> operator|(Flags<FlagType> lhs, FlagType rhs)
390 { return lhs | Flags<FlagType>(rhs); }
391
394 template <class FlagType>
395 Flags<FlagType> operator|(FlagType lhs, Flags<FlagType> rhs)
396 { return Flags<FlagType>(lhs) | rhs; }
397
400 template <class FlagType>
401 typename boost::enable_if<
402 is_flag_type<FlagType>,
403 Flags<FlagType>
404 >::type
405 operator|(FlagType lhs, FlagType rhs)
406 { return Flags<FlagType>(lhs) | Flags<FlagType>(rhs); }
407
410 template <class FlagType>
411 Flags<FlagType> operator&(Flags<FlagType> lhs, Flags<FlagType> rhs)
412 {
413 Flags<FlagType> retval(lhs);
414 retval &= rhs;
415 return retval;
416 }
417
420 template <class FlagType>
421 Flags<FlagType> operator&(Flags<FlagType> lhs, FlagType rhs)
422 { return lhs & Flags<FlagType>(rhs); }
423
426 template <class FlagType>
427 Flags<FlagType> operator&(FlagType lhs, Flags<FlagType> rhs)
428 { return Flags<FlagType>(lhs) & rhs; }
429
432 template <class FlagType>
433 typename boost::enable_if<
434 is_flag_type<FlagType>,
435 Flags<FlagType>
436 >::type
437 operator&(FlagType lhs, FlagType rhs)
438 { return Flags<FlagType>(lhs) & Flags<FlagType>(rhs); }
439
442 template <class FlagType>
443 Flags<FlagType> operator^(Flags<FlagType> lhs, Flags<FlagType> rhs)
444 {
445 Flags<FlagType> retval(lhs);
446 retval ^= rhs;
447 return retval;
448 }
449
452 template <class FlagType>
453 Flags<FlagType> operator^(Flags<FlagType> lhs, FlagType rhs)
454 { return lhs ^ Flags<FlagType>(rhs); }
455
458 template <class FlagType>
459 Flags<FlagType> operator^(FlagType lhs, Flags<FlagType> rhs)
460 { return Flags<FlagType>(lhs) ^ rhs; }
461
464 template <class FlagType>
465 typename boost::enable_if<
466 is_flag_type<FlagType>,
467 Flags<FlagType>
468 >::type
469 operator^(FlagType lhs, FlagType rhs)
470 { return Flags<FlagType>(lhs) ^ Flags<FlagType>(rhs); }
471
474 template <class FlagType>
475 Flags<FlagType> operator~(Flags<FlagType> flags)
476 {
477 Flags<FlagType> retval;
478 const FlagSpec<FlagType>& spec = FlagSpec<FlagType>::instance();
479 for (typename FlagSpec<FlagType>::const_iterator it = spec.begin(); it != spec.end(); ++it) {
480 if (!(*it & flags))
481 retval |= *it;
482 }
483 return retval;
484 }
485
488 template <class FlagType>
489 typename boost::enable_if<
490 is_flag_type<FlagType>,
491 Flags<FlagType>
492 >::type
493 operator~(FlagType flag)
494 { return ~Flags<FlagType>(flag); }
495
496 } // namespace GG
497
498 #endif