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
00043
00044
00045 #ifndef _ENUMSET_H_
00046 #define _ENUMSET_H_
00047
00048 #if defined(_MSC_VER)
00049 # pragma comment (exestr, "This software includes material by M.Boerger (http://marcus-boerger.de/)")
00050 # pragma warning(push)
00051 # pragma warning(disable: 4290) // C++ exception specification ignored except to indicate a function is not __declspec(nothrow)
00052 # pragma warning(disable: 4702) // unreachable code
00053 #endif
00054
00055
00056
00057
00058
00059 #ifndef ALLOW_ENUM_ELLIPSIS_CTOR
00060 #define ALLOW_ENUM_ELLIPSIS_CTOR 0
00061 #endif
00062
00063 #include <stdarg.h>
00064 #include <exception>
00065 #include "MboDebugTrace.h"
00066
00067 #ifndef _Ty_list_default
00068
00071 #define _Ty_list_default size_t
00072 #endif
00073
00074 #ifndef _Ty_args_default
00075
00078 #define _Ty_args_default int
00079 #endif
00080
00081
00086 namespace mbo {
00087
00090 class enumset_exception: public mbo::exception {};
00091
00094 class input_range_exception: public enumset_exception {};
00095
00101 class demap_value_exception: public enumset_exception {};
00102
00108 class multi_value_exception: public demap_value_exception {};
00109
00115 class empty_value_exception: public demap_value_exception {};
00116
00122 class operator_na_exception: public enumset_exception {};
00123
00129 class iterator_exception: public enumset_exception {};
00130
00131
00209 template < typename _TEnum
00210 , typename _Ty_list = _Ty_list_default
00211 , typename _Ty_args = _Ty_args_default
00212 >
00213 class enumset
00214 {
00215 typedef enumset<_TEnum, _Ty_list, _Ty_args> _MyType;
00216 public:
00217
00222 typedef _TEnum TEnum;
00223
00228 typedef _Ty_list Ty_list;
00229
00234 typedef _Ty_args Ty_args;
00235
00238 typedef enumset<_TEnum, _Ty_list, _Ty_args> MyType;
00239
00242 enum { invalid_pos = 8 * sizeof(Ty_list) };
00243
00248 static inline enumset from_set(Ty_list list)
00249 {
00250 enumset e;
00251 e.list = list;
00252 return e;
00253 }
00254
00257 inline enumset () : list(0)
00258 {
00259 }
00260
00264 inline enumset (const enumset & set) : list(set.list)
00265 {
00266 }
00267
00268 #if ALLOW_ENUM_ELLIPSIS_CTOR
00269
00275 inline explicit enumset (size_t count, ...)
00276 throw(input_range_exception)
00277 : list(0)
00278 {
00279 va_list args;
00280 Ty_list val;
00281
00282 va_start(args, count);
00283 while (count--)
00284 {
00285 val = (Ty_list)va_arg(args, Ty_args);
00286 list |= map(val);
00287 }
00288 va_end(args);
00289 }
00290 #endif // ALLOW_ENUM_ELLIPSIS_CTOR
00291
00298 inline explicit enumset (size_t count, va_list args)
00299 throw(input_range_exception)
00300 : list(0)
00301 {
00302 Ty_list val;
00303
00304 while (count--)
00305 {
00306 val = (Ty_list)va_arg(args, Ty_args);
00307 list |= map(val);
00308 }
00309 }
00310
00317 inline enumset (const TEnum array[], size_t count)
00318 throw(input_range_exception)
00319 : list(0)
00320 {
00321 while (count)
00322 {
00323 list |= map(array[--count]);
00324 }
00325 }
00326
00331 inline enumset (const TEnum & value)
00332 throw(input_range_exception)
00333 {
00334 list = map(value);
00335 }
00336
00344 inline enumset & __cdecl dyna_set(size_t count, ...)
00345 throw(input_range_exception)
00346 {
00347 va_list args;
00348 Ty_list val;
00349
00350 va_start(args, count);
00351 while (count--)
00352 {
00353 val = (Ty_list)va_arg(args, Ty_args);
00354 list |= map(val);
00355 }
00356 va_end(args);
00357 return *this;
00358 }
00359
00365 inline enumset & set(const TEnum & value, bool set_unset = true)
00366 {
00367 if (set_unset)
00368 {
00369 return *this += value;
00370 }
00371 else
00372 {
00373 return *this -= value;
00374 }
00375 }
00376
00382 inline bool get(const TEnum & value) const
00383 {
00384 return (*this >= value);
00385 }
00386
00392 inline enumset & set_set(Ty_list list)
00393 {
00394 *this = from_set(list);
00395 return *this;
00396 }
00397
00403 inline enumset & flip(const TEnum & value)
00404 {
00405 return set(value, !get(value));
00406 }
00407
00413 inline bool contains(const TEnum & value) const
00414 {
00415 return (*this >= value);
00416 }
00417
00423 inline bool contains(const enumset & set) const
00424 {
00425 return (*this >= set);
00426 }
00427
00434 inline int count() const
00435 {
00436 register int i = 0;
00437 register Ty_list p = 1;
00438
00439 while (p)
00440 {
00441 i += (list & p) ? 1 : 0;
00442 p *=2;
00443 }
00444 return i;
00445 }
00446
00450 inline bool empty() const
00451 {
00452 return count() == 0;
00453 }
00454
00458 inline enumset & clear()
00459 {
00460 list = 0;
00461 return *this;
00462 }
00463
00468 inline enumset & operator = (const TEnum & value)
00469 throw(input_range_exception)
00470 {
00471 list = map(value);
00472 return *this;
00473 }
00474
00479 inline enumset & operator = (const enumset & set)
00480 {
00481 list = set.list;
00482 return *this;
00483 }
00484
00489 inline enumset & operator += (const TEnum & value)
00490 throw(input_range_exception)
00491 {
00492 list |= map(value);
00493 return *this;
00494 }
00495
00500 inline enumset & operator += (const enumset & set)
00501 {
00502 list |= set.list;
00503 return *this;
00504 }
00505
00510 inline enumset operator + (const TEnum & value) const
00511 {
00512 register enumset ret = enumset(*this);
00513 ret += value;
00514 return ret;
00515 }
00516
00521 inline enumset operator + (const enumset & set) const
00522 {
00523 register enumset ret = enumset(*this);
00524 ret += set;
00525 return ret;
00526 }
00527
00532 inline enumset & operator -= (const TEnum &value)
00533 throw(input_range_exception)
00534 {
00535 list &= ~map(value);
00536 return *this;
00537 }
00538
00543 inline enumset & operator -= (const enumset &set)
00544 {
00545 list &= ~set.list;
00546 return *this;
00547 }
00548
00553 inline enumset operator - (const TEnum & value) const
00554 {
00555 enumset ret = enumset(*this);
00556 ret -= value;
00557 return ret;
00558 }
00559
00564 inline enumset operator - (const enumset & set) const
00565 {
00566 enumset ret = enumset(*this);
00567 ret -= set;
00568 return ret;
00569 }
00570
00575 inline enumset & operator *= (const TEnum &value)
00576 throw(input_range_exception)
00577 {
00578 list &= map(value);
00579 return *this;
00580 }
00581
00586 inline enumset & operator *= (const enumset &set)
00587 {
00588 list &= set.list;
00589 return *this;
00590 }
00591
00596 inline enumset operator * (const TEnum & value) const
00597 {
00598 register enumset ret = enumset(*this);
00599 ret *= value;
00600 return ret;
00601 }
00602
00607 inline enumset operator * (const enumset & set) const
00608 {
00609 register enumset ret = enumset(*this);
00610 ret *= set;
00611 return ret;
00612 }
00613
00618 inline enumset & operator ^= (const TEnum &value)
00619 throw(input_range_exception)
00620 {
00621 list ^= map(value);
00622 return *this;
00623 }
00624
00629 inline enumset & operator ^= (const enumset &set)
00630 {
00631 list ^= set.list;
00632 return *this;
00633 }
00634
00639 inline enumset operator ^ (const TEnum & value) const
00640 {
00641 register enumset ret = enumset(*this);
00642 ret ^= value;
00643 return ret;
00644 }
00645
00650 inline enumset operator ^ (const enumset & set) const
00651 {
00652 register enumset ret = enumset(*this);
00653 ret ^= set;
00654 return ret;
00655 }
00656
00661 inline bool operator & (const TEnum & value) const
00662 throw(input_range_exception)
00663 {
00664 return (list & map(value)) != 0;
00665 }
00666
00671 inline bool operator & (const enumset & set) const
00672 {
00673 return (list & set.list) != 0;
00674 }
00675
00680 inline bool operator | (const TEnum & value) const
00681 throw(input_range_exception)
00682 {
00683 return (list | map(value)) != 0;
00684 }
00685
00690 inline bool operator | (const enumset & set) const
00691 {
00692 return (list | set.list) != 0;
00693 }
00694
00699 inline bool operator == (const TEnum & value) const
00700 throw(input_range_exception)
00701 {
00702 return list == map(value);
00703 }
00704
00709 inline bool operator == (const enumset & set) const
00710 {
00711 return list == set.list;
00712 }
00713
00718 inline bool operator != (const TEnum & value) const
00719 throw(input_range_exception)
00720 {
00721 return list != map(value);
00722 }
00723
00728 inline bool operator != (const enumset & set) const
00729 {
00730 return list != set.list;
00731 }
00732
00737 inline bool operator < (const TEnum & ) const
00738 throw(input_range_exception)
00739 {
00740 return list == 0;
00741 }
00742
00747 inline bool operator < (const enumset & set) const
00748 {
00749 return ((list & ~set.list) == 0) && (list != set.list);
00750 }
00751
00756 inline bool operator <= (const TEnum & value) const
00757 throw(input_range_exception)
00758 {
00759 register Ty_list comp = map(value);
00760 return list == 0 || list == comp;
00761 }
00762
00767 inline bool operator <= (const enumset & set) const
00768 {
00769 return (list & ~set.list) == 0;
00770 }
00771
00776 inline bool operator > (const TEnum & value) const
00777 throw(input_range_exception)
00778 {
00779 register Ty_list comp = map(value);
00780 return ((list & comp) == comp) && (list > comp);
00781 }
00782
00787 inline bool operator > (const enumset & set) const
00788 {
00789 return ((list & set.list) == set.list) && (list > set.list);
00790 }
00791
00796 inline bool operator >= (const TEnum & value) const
00797 throw(input_range_exception)
00798 {
00799 register Ty_list comp = map(value);
00800 return (list & comp) == comp;
00801 }
00802
00807 inline bool operator >= (const enumset & set) const
00808 {
00809 return (list & set.list) == set.list;
00810 }
00811
00816 inline Ty_list to_set() const
00817 {
00818 return list;
00819 }
00820
00823 inline operator Ty_list() const
00824 {
00825 return list;
00826 }
00827
00878 inline TEnum to_enum() const
00879 throw(demap_value_exception, multi_value_exception, multi_value_exception)
00880 {
00881 return static_cast<TEnum>(demap(list));
00882 }
00883
00896 inline operator TEnum() const
00897 throw(demap_value_exception, multi_value_exception, multi_value_exception)
00898 {
00899 return static_cast<TEnum>(demap(list));
00900 }
00901
00904 class const_iterator
00905 : public std::iterator<std::bidirectional_iterator_tag, TEnum, Ty_list>
00906 {
00907 public:
00908 typedef enumset<TEnum, Ty_list, Ty_args> MyEnumType;
00909
00910 inline const_iterator(const MyEnumType& tenum, Ty_list pos = 0)
00911 : m_tenum(tenum), m_pos(pos)
00912 {
00913
00914 while (m_pos != invalid_pos
00915 && !(m_tenum.list & MyEnumType::map(m_pos)))
00916 {
00917 ++m_pos;
00918 }
00919 }
00920
00921 inline const TEnum operator * () const throw(iterator_exception)
00922 {
00923 if (m_pos == invalid_pos)
00924 {
00925 throw iterator_exception();
00926 }
00927 return static_cast<TEnum>(m_pos);
00928 }
00929
00930
00931
00932 inline const_iterator & operator ++ ()
00933 {
00934 while ((m_pos + 1) < invalid_pos)
00935 {
00936 if (m_tenum.list & MyEnumType::map(++m_pos))
00937 {
00938 return *this;
00939 }
00940 }
00941 m_pos = invalid_pos;
00942 return *this;
00943 }
00944
00945 inline const_iterator operator ++ (int)
00946 {
00947
00948 const_iterator it = const_iterator(m_array, m_pos);
00949 operator ++ ();
00950 return it;
00951 }
00952
00953 inline const_iterator & operator -- ()
00954 {
00955 while(m_pos && m_pos != invalid_pos)
00956 {
00957 if (m_tenum.list & MyEnumType::map(--m_pos))
00958 {
00959 return *this;
00960 }
00961 }
00962 m_pos = invalid_pos;
00963 return *this;
00964 }
00965
00966 inline const_iterator operator -- (int)
00967 {
00968
00969 const_iterator it = const_iterator(m_array, m_pos);
00970 operator -- ();
00971 return it;
00972 }
00973
00974 inline bool operator == (const_iterator &rhs) const
00975 {
00976 return &m_tenum == &rhs.m_tenum && m_pos == rhs.m_pos;
00977 }
00978
00979 inline bool operator != (const_iterator &rhs) const
00980 {
00981 return !operator == (rhs);
00982 }
00983
00984 inline const_iterator & operator = (const const_iterator & rhs)
00985 {
00986 new (this) const_iterator(rhs.m_tenum, rhs.m_pos);
00987 return *this;
00988 }
00989
00990 protected:
00991 const MyEnumType& m_tenum;
00992 Ty_list m_pos;
00993 };
00994
00995 inline const_iterator begin() const
00996 {
00997 return const_iterator(*this, 0);
00998 }
00999
01000 inline const_iterator end() const
01001 {
01002 return const_iterator(*this, invalid_pos);
01003 }
01004
01005 friend class const_iterator;
01006
01007 private:
01008
01017 inline enumset & operator ~(void)
01018 throw(operator_na_exception)
01019 {
01020 throw operator_na_exception();
01021 }
01022
01025 Ty_list list;
01026
01032 inline static Ty_list map(Ty_list value)
01033 throw(input_range_exception)
01034 {
01035 if (value >= invalid_pos)
01036 {
01037 throw input_range_exception();
01038 }
01039 return (1L << value);
01040 }
01041
01053 inline static Ty_list demap(Ty_list mapping)
01054 throw(demap_value_exception, multi_value_exception, empty_value_exception)
01055 {
01056 register Ty_list i = 0;
01057 register Ty_list p = 1;
01058
01059 while (p)
01060 {
01061 if (mapping & p)
01062 {
01063 if (mapping & (~p))
01064 {
01065 throw multi_value_exception();
01066 }
01067 return i;
01068 }
01069 i++;
01070 p <<= 1;
01071 }
01072 throw empty_value_exception();
01073 return 0;
01074 }
01075
01076 };
01077
01078
01141
01142
01262
01263 };
01264
01265 #ifdef _MSC_VER
01266 # pragma warning(pop)
01267 #endif
01268
01269 #endif // _ENUMSET_H_