enumstring.hpp 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. // EnumString - A utility to provide stringizing support for C++ enums
  2. // Author: Francis Xavier Joseph Pulikotil
  3. //
  4. // This code is free software: you can do whatever you want with it,
  5. // although I would appreciate if you gave credit where it's due.
  6. //
  7. // This code is distributed in the hope that it will be useful,
  8. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. //
  11. // downloaded on 2010/07/10 http://www.codeproject.com/kb/cpp/C___enums_to_strings.aspx
  12. #ifndef ENUMSTRING_HEADER
  13. #define ENUMSTRING_HEADER
  14. /* Usage example
  15. // WeekEnd enumeration
  16. enum WeekEnd
  17. {
  18. Sunday = 1,
  19. Saturday = 7
  20. };
  21. // String support for WeekEnd
  22. Begin_Enum_String( WeekEnd )
  23. {
  24. Enum_String( Sunday );
  25. Enum_String( Saturday );
  26. }
  27. End_Enum_String;
  28. // Convert from WeekEnd to string
  29. const std::string &str = EnumString<WeekEnd>::From( Saturday );
  30. // str should now be "Saturday"
  31. // Convert from string to WeekEnd
  32. WeekEnd w;
  33. EnumString<WeekEnd>::To( w, "Sunday" );
  34. // w should now be Sunday
  35. */
  36. #include <string>
  37. #include <map>
  38. #include <cassert>
  39. // Helper macros
  40. #define Begin_Enum_String(EnumerationName) \
  41. template <> struct EnumString<EnumerationName> : \
  42. public EnumStringBase< EnumString<EnumerationName>, EnumerationName > \
  43. { \
  44. static void RegisterEnumerators()
  45. // {
  46. #define Enum_String(EnumeratorName) \
  47. RegisterEnumerator( EnumeratorName, #EnumeratorName );
  48. // }
  49. #define End_Enum_String \
  50. }
  51. // The EnumString base class
  52. template <class DerivedType, class EnumType>
  53. class EnumStringBase
  54. {
  55. // Types
  56. protected:
  57. typedef std::map<std::string, EnumType> AssocMap;
  58. protected:
  59. // Constructor / Destructor
  60. explicit EnumStringBase();
  61. ~EnumStringBase();
  62. private:
  63. // Copy Constructor / Assignment Operator
  64. EnumStringBase(const EnumStringBase &);
  65. const EnumStringBase &operator =(const EnumStringBase &);
  66. // Functions
  67. private:
  68. static AssocMap &GetMap();
  69. protected:
  70. // Use this helper function to register each enumerator
  71. // and its string representation.
  72. static void RegisterEnumerator(const EnumType e, const std::string &eStr);
  73. public:
  74. // Converts from an enumerator to a string.
  75. // Returns an empty string if the enumerator was not registered.
  76. static const std::string &From(const EnumType e);
  77. // Converts from a string to an enumerator.
  78. // Returns true if the conversion is successful; false otherwise.
  79. static const bool To(EnumType &e, const std::string &str);
  80. };
  81. // The EnumString class
  82. // Note: Specialize this class for each enumeration, and implement
  83. // the RegisterEnumerators() function.
  84. template <class EnumType>
  85. struct EnumString : public EnumStringBase< EnumString<EnumType>, EnumType >
  86. {
  87. static void RegisterEnumerators();
  88. };
  89. // Function definitions
  90. template <class D, class E>
  91. typename EnumStringBase<D,E>::AssocMap &EnumStringBase<D,E>::GetMap()
  92. {
  93. // A static map of associations from strings to enumerators
  94. static AssocMap assocMap;
  95. static bool bFirstAccess = true;
  96. // If this is the first time we're accessing the map, then populate it.
  97. if( bFirstAccess )
  98. {
  99. bFirstAccess = false;
  100. D::RegisterEnumerators();
  101. assert( !assocMap.empty() );
  102. }
  103. return assocMap;
  104. }
  105. template <class D, class E>
  106. void EnumStringBase<D,E>::RegisterEnumerator(const E e, const std::string &eStr)
  107. {
  108. const bool bRegistered = GetMap().insert( typename AssocMap::value_type( eStr, e ) ).second;
  109. assert( bRegistered );
  110. (void)sizeof( bRegistered ); // This is to avoid the pesky 'unused variable' warning in Release Builds.
  111. }
  112. template <class D, class E>
  113. const std::string &EnumStringBase<D,E>::From(const E e)
  114. {
  115. for(;;) // Code block
  116. {
  117. // Search for the enumerator in our map
  118. typename AssocMap::const_iterator i;
  119. for(i = GetMap().begin(); i != GetMap().end(); ++i)
  120. if( (*i).second == e )
  121. break;
  122. // If we didn't find it, we can't do this conversion
  123. if( i == GetMap().end() )
  124. break;
  125. // Keep searching and see if we find another one with the same value
  126. typename AssocMap::const_iterator j( i );
  127. for(++j; j != GetMap().end(); ++j)
  128. if( (*j).second == e )
  129. break;
  130. // If we found another one with the same value, we can't do this conversion
  131. if( j != GetMap().end() )
  132. break;
  133. // We found exactly one string which matches the required enumerator
  134. return (*i).first;
  135. }
  136. // We couldn't do this conversion; return an empty string.
  137. static const std::string dummy;
  138. return dummy;
  139. }
  140. template <class D, class E>
  141. const bool EnumStringBase<D,E>::To(E &e, const std::string &str)
  142. {
  143. // Search for the string in our map.
  144. const typename AssocMap::const_iterator itr( GetMap().find( str ) );
  145. // If we have it, then return the associated enumerator.
  146. if( itr != GetMap().end() )
  147. {
  148. e = (*itr).second;
  149. return true;
  150. }
  151. // We don't have it; the conversion failed.
  152. return false;
  153. }
  154. #endif