1 // -*- C++ -*- 2 /* GG is a GUI for OpenGL. 3 Copyright (C) 2003-2008 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 26 /** \file Enum.h \brief Contains the utility classes and macros that allow for 27 easy conversion to and from an enum value and its textual 28 representation. */ 29 30 #ifndef _GG_Enum_h_ 31 #define _GG_Enum_h_ 32 33 #include <cstdlib> 34 #include <iostream> 35 #include <map> 36 #include <sstream> 37 #include <string> 38 #include <climits> 39 40 #include <boost/algorithm/string/trim.hpp> 41 42 namespace GG { 43 44 #define GG_ENUM_NAME_BUFFER_SIZE 80 45 46 /** This class is not meant for public consumption. 47 * Access this class through the functions generated 48 * in the GG_ENUM or GG_CLASS_ENUM macro invocation. */ 49 template <typename EnumType> 50 class EnumMap { 51 public: 52 const std::string& operator[](EnumType value) const; 53 EnumType operator[](const std::string& name) const; 54 55 void Insert(int& default_value, const std::string& entry); 56 size_t size() const; 57 58 static const EnumType BAD_VALUE = (EnumType)INT_MIN; 59 private: 60 std::map<std::string, EnumType> m_name_to_value_map; 61 std::map<EnumType, std::string> m_value_to_name_map; 62 }; 63 64 /** Do not call this function directly. 65 * Instead, rely on the functions generated 66 * by the GG_ENUM or GG_CLASS_ENUM macro invocations. */ 67 template <typename EnumType> GetEnumMap()68 EnumMap<EnumType>& GetEnumMap() { 69 static EnumMap<EnumType> map; 70 return map; 71 } 72 73 /** Do not call this function directly. 74 * Instead, rely on the functions generated 75 * by the GG_ENUM or GG_CLASS_ENUM macro invocations. */ 76 template <typename EnumType> BuildEnumMap(EnumMap<EnumType> & map,const std::string & enum_name,const char * comma_separated_names)77 void BuildEnumMap(EnumMap<EnumType>& map, const std::string& enum_name, const char* comma_separated_names) { 78 std::stringstream name_stream(comma_separated_names); 79 80 int default_value = 0; 81 std::string name; 82 while (std::getline(name_stream, name, ',')) { 83 map.Insert(default_value, name); 84 } 85 } 86 87 /** An enum macro for use inside classes. 88 * Enables << and >> for your enum, 89 * all of which will exist in whatever namespace this 90 * macro is used. */ 91 #define GG_CLASS_ENUM(EnumName, ...) \ 92 enum EnumName : int { \ 93 __VA_ARGS__ \ 94 }; \ 95 \ 96 friend inline std::istream& operator>>(std::istream& is, EnumName& value) { \ 97 ::GG::EnumMap<EnumName>& map = ::GG::GetEnumMap<EnumName>(); \ 98 if (map.size() == 0) \ 99 ::GG::BuildEnumMap(map, #EnumName, #__VA_ARGS__); \ 100 \ 101 std::string name; \ 102 is >> name; \ 103 value = map[name]; \ 104 return is; \ 105 } \ 106 \ 107 friend inline std::ostream& operator<<(std::ostream& os, EnumName value) { \ 108 ::GG::EnumMap<EnumName>& map = ::GG::GetEnumMap<EnumName>(); \ 109 if (map.size() == 0) \ 110 ::GG::BuildEnumMap(map, #EnumName, #__VA_ARGS__); \ 111 \ 112 const std::string& name = map[value]; \ 113 return os << name; \ 114 } \ 115 116 /** An enum macro for use outside of classes. 117 * Enables << and >> for your enum, 118 * all of which will exist in whatever namespace this 119 * macro is used. */ 120 #define GG_ENUM(EnumName, ...) \ 121 enum EnumName : int { \ 122 __VA_ARGS__ \ 123 }; \ 124 \ 125 inline std::istream& operator>>(std::istream& is, EnumName& value) { \ 126 ::GG::EnumMap<EnumName>& map = ::GG::GetEnumMap<EnumName>(); \ 127 if (map.size() == 0) \ 128 ::GG::BuildEnumMap(map, #EnumName, #__VA_ARGS__); \ 129 \ 130 std::string name; \ 131 is >> name; \ 132 value = map[name]; \ 133 return is; \ 134 } \ 135 \ 136 inline std::ostream& operator<<(std::ostream& os, EnumName value) { \ 137 ::GG::EnumMap<EnumName>& map = ::GG::GetEnumMap<EnumName>(); \ 138 if (map.size() == 0) \ 139 ::GG::BuildEnumMap(map, #EnumName, #__VA_ARGS__); \ 140 \ 141 const std::string& name = map[value]; \ 142 return os << name; \ 143 } \ 144 145 ///////////// 146 // EnumMap // 147 ///////////// 148 template <typename EnumType> 149 const std::string& EnumMap<EnumType>::operator[](EnumType value) const { 150 auto it = m_value_to_name_map.find(value); 151 if (it != m_value_to_name_map.end()) { 152 return it->second; 153 } else { 154 static std::string none("None"); 155 return none; 156 } 157 } 158 159 template <typename EnumType> 160 EnumType EnumMap<EnumType>::operator[](const std::string& name) const { 161 auto it = m_name_to_value_map.find(name); 162 if (it != m_name_to_value_map.end()) { 163 return it->second; 164 } else { 165 return BAD_VALUE; 166 } 167 } 168 169 template <typename EnumType> size()170 size_t EnumMap<EnumType>::size() const { 171 return m_name_to_value_map.size(); 172 } 173 174 template <typename EnumType> Insert(int & default_value,const std::string & entry)175 void EnumMap<EnumType>::Insert(int& default_value, const std::string& entry) { 176 std::stringstream name_and_value(entry); 177 178 std::string name; 179 std::getline(name_and_value, name, '='); 180 181 std::string value_str; 182 EnumType value; 183 if (std::getline(name_and_value, value_str)) { 184 value = (EnumType)strtol(value_str.c_str(), nullptr, 0); 185 } 186 else { 187 value = (EnumType)default_value; 188 } 189 190 boost::trim(name); 191 192 m_name_to_value_map[name] = value; 193 m_value_to_name_map[value] = name; 194 default_value = value + 1; 195 } 196 197 } // namespace GG 198 199 #endif 200