enumset.h

Go to the documentation of this file.
00001 /*****************************************************************************
00002 * Copyright (c) 2001 - 2008 Marcus Boerger.  All rights reserved.
00003 *
00004 * This library is free software; you can redistribute it and/or
00005 * modify it under the terms of the GNU Lesser General Public
00006 * License as published by the Free Software Foundation; either
00007 * version 2.1 of the License, or (at your option) any later version.
00008 *
00009 * This library is distributed in the hope that it will be useful,
00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012 * Lesser General Public License for more details.
00013 *
00014 * You should have received a copy of the GNU Lesser General Public
00015 * License along with this library; if not, write to the Free Software
00016 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00017 * ========================================================================= */
00018 
00019 /* ------------------------------------------------------------------------ */
00020 /* Name:      enumset.h
00021  *
00022  * Requires:  
00023  * - Mbo.h
00024  * - MboDebugTrace.h
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 // The ellipsis constructor cannot be used with other calling conventions
00056 // than __cdecl. However you cannot change the calling convention of 
00057 // constructors. Hence we must disable this feature when changing the
00058 // calling convention is an option.
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; // only zero possible then
00741     }
00742 
00747     inline bool operator < (const enumset & set) const 
00748     {
00749         return ((list & ~set.list) == 0) && (list != set.list); // no other but at least one less (e.g. !=)
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; // zero or same bit
00761     }
00762 
00767     inline bool operator <= (const enumset & set) const 
00768     {
00769         return (list & ~set.list) == 0; // no other bit is set
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); // comp and one additional bit
00781     }
00782 
00787     inline bool operator > (const enumset & set) const 
00788     {
00789         return ((list & set.list) == set.list) && (list > set.list); // all from set plus one additional
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; // at least comp is set
00801     }
00802 
00807     inline bool operator >= (const enumset & set) const
00808     {
00809         return (list & set.list) == set.list; // at least all of set
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             /* forward to first element or invalid_pos */
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         /* no -> operator */
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             /* postfix operator return an unchanged copy prior to the operaration */
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             /* postfix operator return an unchanged copy prior to the operaration */
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 /* not TEnum see comment */ 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 }; // template class enumset
01077 
01078 /****************************************************************************//**************************************************************************/
01141 
01142 /****************************************************************************//**************************************************************************/
01262 
01263 }; // namespace mbo
01264 
01265 #ifdef _MSC_VER
01266 # pragma warning(pop)
01267 #endif
01268 
01269 #endif // _ENUMSET_H_

  Hosted on code.google.com  
© Marcus Börger
Generated on Fri Jan 18 21:21:07 2008 for MBO-lib by doxygen 1.5.4