//============================ // Project: Open Code Foundation Classes (OCFC) // Version: 1.0.0 // File: enum.hpp // Written by Nabla // Copyright @ 2007 Nabla. All rights reserved. //============================ // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #ifndef OCFCSENTRY_ENUM_HPP # define OCFCSENTRY_ENUM_HPP #include #include #include #include #include #include #include namespace ocfc { template struct enum_item { typedef typename _E::type enum_type; enum_type m_eValue; LPCTSTR m_szValue; inline enum_type value() const NO_THROW { return m_eValue; } inline LPCTSTR str() const NO_THROW { return m_szValue; } }; template class enum_list; template class enum_iterator : public boost::iterator_facade, _EnumItem const, boost::single_pass_traversal_tag> { public: typedef _EnumItem item_type; private: item_type const* __m_pItem; item_type const* __m_pLastItem; public: inline enum_iterator() NO_THROW : __m_pItem(NULL), __m_pLastItem(NULL) {} enum_iterator(const enum_iterator& __x) NO_THROW : __m_pItem(__x.__m_pItem), __m_pLastItem(__x.__m_pLastItem) {} virtual ~enum_iterator() NO_THROW {} protected: inline enum_iterator(item_type const* __pFirstItem, item_type const* __pLastItem) NO_THROW : __m_pItem(__pFirstItem), __m_pLastItem(__pLastItem) {} private: item_type const& dereference() const NO_THROW { ASSERT(__m_pItem != NULL); return *__m_pItem; } void increment() NO_THROW { if (__m_pItem != NULL) { if (__m_pItem == __m_pLastItem) __m_pItem = NULL; else ++__m_pItem; } } bool equal(const enum_iterator& __x) const NO_THROW { return __m_pItem == __x.__m_pItem; } friend class boost::iterator_core_access; friend class enum_list; }; template class enum_list { public: typedef _EnumItem item_type; typedef typename item_type::enum_type enum_type; typedef enum_iterator const_iterator; typedef size_t size_type; typedef size_type index_type; private: item_type const* __m_aItem; size_type __m_nSize; public: inline enum_list(item_type const* __aItem, size_type __nSize) NO_THROW : __m_aItem(__aItem), __m_nSize(__nSize) { ASSERT(__aItem != NULL && __nSize > 0); } inline ~enum_list() NO_THROW {} inline item_type const& at(index_type __i) const NO_THROW { ASSERT(__i < __m_nSize); return __m_aItem[__i]; } inline size_type size() const NO_THROW { return __m_nSize; } inline const_iterator begin() const NO_THROW { return const_iterator(&__m_aItem[0], &__m_aItem[__m_nSize - 1]); } inline const_iterator end() const NO_THROW { return const_iterator(); } inline item_type const& front() const NO_THROW { return __m_aItem[0]; } inline item_type const& back() const NO_THROW { return __m_aItem[__m_nSize - 1]; } bool valid(int __nValue) const NO_THROW { item_type const* __pe = __m_aItem; bool __bRet = false; for (index_type __i = 0; !__bRet && __i < __m_nSize; ++__i, ++__pe) __bRet = (__nValue == __pe->value()); return __bRet; } bool valid(LPCTSTR __szValue) const { ASSERT(__szValue != NULL); item_type const* __pe = __m_aItem; bool __bRet = false; for (index_type __i = 0; !__bRet && __i < __m_nSize; ++__i, ++__pe) __bRet = (t_strnocasecmp(__szValue, __pe->str()) == 0); return __bRet; } index_type index(int __nValue) const { item_type const* __pe = __m_aItem; for (index_type __i = 0; __i < __m_nSize; ++__i, ++__pe) { if (__nValue == __pe->value()) return __i; } LOG_DEBUG(_T("fail to convert enum value = ") << __nValue << _T(" to an enum of type ") << typeid(enum_type).name()); THROW_RUNTIME_OUT_OF_RANGE_EXCEPTION(); return 0; // just to silent the compiler because this section cannot be reached } index_type index(LPCTSTR __szValue) const { ASSERT(__szValue != NULL); item_type const* __pe = __m_aItem; for (index_type __i = 0; __i < __m_nSize; ++__i, ++__pe) { if (t_strnocasecmp(__szValue, __pe->str()) == 0) return __i; } LOG_DEBUG(_T("fail to convert enum description = ") << OS_SQUOTE(__szValue) << _T(" to an enum of type ") << typeid(enum_type).name()); THROW_RUNTIME_OUT_OF_RANGE_EXCEPTION(); return 0; // just to silent the compiler because this section cannot be reached } }; template > struct enum_traits : public _E { typedef _EnumItem item_type; typedef typename item_type::enum_type enum_type; typedef enum_list item_list; typedef typename item_list::size_type size_type; typedef typename item_list::index_type index_type; typedef typename item_list::const_iterator const_iterator; static item_list const& enums(); }; template struct basic_enum_incrementor : std::binary_function { // typedef typename _EnumTraits::index_type index_type; // index_type operator ()(index_type __nCur, int __nOffset) const NO_THROW; }; template struct enum_linear_incrementor : public basic_enum_incrementor<_EnumTraits> { typedef typename _EnumTraits::index_type index_type; typedef typename _EnumTraits::enum_type enum_type; index_type operator ()(index_type __nCur, int __nOffset) const NO_THROW { int __n = __nCur + __nOffset; if (__n < 0 || __n >= (int)_EnumTraits::enums().size()) { LOG_DEBUG(_T("Incrementation would yield invalid enum of type ") << typeid(enum_type).name()); THROW_RUNTIME_OUT_OF_RANGE_EXCEPTION(); } return static_cast(__n); } }; template struct enum_wrapped_incrementor : public basic_enum_incrementor<_EnumTraits> { typedef typename _EnumTraits::index_type index_type; index_type operator ()(index_type __nCur, int __nOffset) const NO_THROW { int __n = (__nCur + __nOffset) % _EnumTraits::enums().size(); return static_cast(__n); } }; template struct enum_bounded_incrementor : public basic_enum_incrementor<_EnumTraits> { typedef typename _EnumTraits::index_type index_type; index_type operator ()(index_type __nCur, int __nOffset) const NO_THROW { int __n = __nCur + __nOffset; if (__n < 0) __n = 0; else { int __nCount = _EnumTraits::enums().size(); if (__n >= __nCount) __n = __nCount - 1; } return static_cast(__n); } }; template > class basic_enum : public _EnumTraits { public: typedef _Incrementor incrementor_type; typedef _EnumTraits traits_type; typedef typename traits_type::enum_type enum_type; typedef typename traits_type::item_type item_type; typedef typename traits_type::const_iterator const_iterator; typedef typename traits_type::size_type size_type; typedef typename traits_type::index_type index_type; private: incrementor_type __m_fnInc; index_type __m_nIndex; public: inline basic_enum(incrementor_type __fn = incrementor_type()) NO_THROW : __m_fnInc(__fn), __m_nIndex(0) {} basic_enum(const basic_enum& __x, incrementor_type __fn = incrementor_type()) NO_THROW : __m_fnInc(__fn), __m_nIndex(__x.__m_nIndex) {} basic_enum(enum_type __eValue, incrementor_type __fn = incrementor_type()) : __m_fnInc(__fn) { value(__eValue); } basic_enum(int __nValue, incrementor_type __fn = incrementor_type()) : __m_fnInc(__fn) { value(__nValue); } basic_enum(LPCTSTR __szValue, incrementor_type __fn = incrementor_type()) : __m_fnInc(__fn) { value(__szValue); } basic_enum(const string& __sValue, incrementor_type __fn = incrementor_type()) : __m_fnInc(__fn) { value(__sValue); } virtual ~basic_enum() NO_THROW {} inline basic_enum& operator = (const basic_enum& __x) { __m_nIndex = __x.__m_nIndex; return *this; } inline basic_enum& operator = (enum_type __eValue) { value(__eValue); return *this; } inline basic_enum& operator = (int __nValue) { value(__nValue); return *this; } inline basic_enum& operator = (LPCSTR __szValue) { value(__szValue); return *this; } inline basic_enum& operator = (const string& __sValue) { value(__sValue); return *this; } inline basic_enum& operator ++() { _offset(1); return *this; } inline basic_enum& operator --() { _offset(-1); return *this; } inline basic_enum operator ++(int) { basic_enum __tmp(*this); _offset(1); return __tmp; } inline basic_enum operator --(int) { basic_enum __tmp(*this); _offset(-1); return __tmp; } inline basic_enum& operator +=(int __nValue) { _offset(__nValue); return *this; } inline basic_enum& operator -=(int __nValue) { _offset(- __nValue); return *this; } inline int compare (const basic_enum& __x) const NO_THROW { return compare(__x.value()); } inline bool operator == (const basic_enum& __x) const NO_THROW { return compare(__x) == 0; } inline bool operator != (const basic_enum& __x) const NO_THROW { return compare(__x) != 0; } inline bool operator > (const basic_enum& __x) const NO_THROW { return compare(__x) > 0; } inline bool operator >= (const basic_enum& __x) const NO_THROW { return compare(__x) >= 0; } inline bool operator < (const basic_enum& __x) const NO_THROW { return compare(__x) < 0; } inline bool operator <= (const basic_enum& __x) const NO_THROW { return compare(__x) <= 0; } inline int compare (enum_type __eValue) const NO_THROW { return value() - __eValue; } inline bool operator == (enum_type __eValue) const NO_THROW { return compare(__eValue) == 0; } inline bool operator != (enum_type __eValue) const NO_THROW { return compare(__eValue) != 0; } inline bool operator > (enum_type __eValue) const NO_THROW { return compare(__eValue) > 0; } inline bool operator >= (enum_type __eValue) const NO_THROW { return compare(__eValue) >= 0; } inline bool operator < (enum_type __eValue) const NO_THROW { return compare(__eValue) < 0; } inline bool operator <= (enum_type __eValue) const NO_THROW { return compare(__eValue) <= 0; } inline item_type const* operator ->() const NO_THROW { return &_item(); } inline operator enum_type() const NO_THROW { return value(); } inline enum_type value() const NO_THROW { return _item().value(); } inline enum_type operator *() const NO_THROW { return value(); } inline LPCTSTR str() const NO_THROW { return _item().str(); } inline void value(enum_type __eValue) { __m_nIndex = traits_type::enums().index(static_cast(__eValue)); ASSERT(_valid(__m_nIndex)); } inline void value(int __nValue) { __m_nIndex = traits_type::enums().index(__nValue); ASSERT(_valid(__m_nIndex)); } inline void value(LPCSTR __szValue) { __m_nIndex = traits_type::enums().index(__szValue); ASSERT(_valid(__m_nIndex)); } inline void value(const string& __sValue) { __m_nIndex = traits_type::enums().index(__sValue.c_str()); ASSERT(_valid(__m_nIndex)); } static item_type const& front() NO_THROW { return traits_type::enums().front(); } static item_type const& back() NO_THROW { return traits_type::enums().back(); } static enum_type min() NO_THROW { return front().value(); } static enum_type max() NO_THROW { return back().value(); } static size_type size() NO_THROW { return traits_type::enums().size(); } static const_iterator begin() NO_THROW { return traits_type::enums().begin(); } static const_iterator end() NO_THROW { return traits_type::enums().end(); } static bool valid_int(int __nValue) NO_THROW { return traits_type::enums().valid(__nValue); } static bool valid_lpctstr(LPCTSTR __szValue) NO_THROW { return traits_type::enums().valid(__szValue); } static bool valid_string(const string& __sValue) NO_THROW { return traits_type::enums().valid(__sValue.c_str()); } void load(ibstream& __in) { index_type __nIndex; __in >> __nIndex; // verify consistency of index if (!_valid(__nIndex)) { LOG_DEBUG(_T("invalid enum value index read from stream")); THROW_CORRUPTED_STREAM_EXCEPTION(); } __m_nIndex = __nIndex; } inline void save(obstream& __out) const { __out << __m_nIndex; } protected: inline item_type const& _item() const NO_THROW { return traits_type::enums().at(__m_nIndex); } inline bool _valid(index_type __nIndex) { return __nIndex < size(); } inline void _offset(int __n) { __m_nIndex = __m_fnInc(__m_nIndex, __n); ASSERT(_valid(__m_nIndex)); } }; // // in your header // // DECLARE_C_ENUM(my_enum, FIRST=0, SECOND) // typedef enum_traits my_enum_traits; // typedef basic_enum my_enums; // // in your code // // IMPLEMENT_ENUM_TRAITS(my_enum_traits, ENUM_ITEM(FIRST), ENUM_ITEM(SECOND)) #define C_ENUM(cls) cls ##_c_enum #define ENUM_TRAITS(cls) cls ##_traits #define DECLARE_C_ENUM(_Cls, values...) \ struct C_ENUM(_Cls) \ { \ enum type { values }; \ }; \ /**/ #define DECLARE_ENUM(_Cls, values...) \ DECLARE_C_ENUM(_Cls, values) \ typedef ocfc::enum_traits ENUM_TRAITS(_Cls); \ typedef ocfc::basic_enum _Cls; \ /**/ #define DECLARE_ENUM_EX(_Cls, _EnumItem, values...) \ DECLARE_C_ENUM(_Cls, values) \ typedef ocfc::enum_traits > ENUM_TRAITS(_Cls); \ typedef ocfc::basic_enum _Cls; \ /**/ #define ENUM_ITEM(value, data...) {value, _TT(# value), ##data} #define OCFC_IMPLEMENT_ENUM_TRAITS(cls_traits, enum_items...) \ template<> cls_traits::item_list const& \ cls_traits::enums() { \ static item_type const __g_aItem[] = { enum_items }; \ static item_list __g_items(__g_aItem, ARRAY_SIZE(__g_aItem)); \ return __g_items; \ } \ /**/ #define IMPLEMENT_ENUM_TRAITS(cls_traits, enum_items...) \ namespace ocfc { \ OCFC_IMPLEMENT_ENUM_TRAITS(cls_traits, enum_items) \ } \ /**/ #define OCFC_IMPLEMENT_ENUM(_Cls, enum_items...) OCFC_IMPLEMENT_ENUM_TRAITS(ENUM_TRAITS(_Cls), enum_items) #define IMPLEMENT_ENUM(_Cls, enum_items...) IMPLEMENT_ENUM_TRAITS(ENUM_TRAITS(_Cls), enum_items) //============================ // Implement persistence //============================ template inline _Stream& operator << (_Stream& __out, const basic_enum<_EnumTraits, _Incrementor>& __x) { __x.save(__out); return __out; } template inline _Stream& operator >> (_Stream& __in, basic_enum<_EnumTraits, _Incrementor>& __x) { __x.load(__in); return __in; } } // namespace ocfc #endif // OCFCSENTRY_ENUM_HPP