/[svn]/libgig/trunk/src/typeinfo.cpp
ViewVC logotype

Contents of /libgig/trunk/src/typeinfo.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3169 - (show annotations) (download)
Wed May 10 21:17:10 2017 UTC (6 years, 11 months ago) by schoenebeck
File size: 13032 byte(s)
* src/gig.h: Added enum reflection API functions for
  retrieving enum declaration type information at
  runtime (countEnum(), enumKey(), enumKeys(),
  enumValue()).
* Archive: Added methods valueAsInt(), valueAsReal()
  and valueAsBool().
* Bumped version (4.0.0.svn20).

1 /***************************************************************************
2 * *
3 * Copyright (C) 2017 Christian Schoenebeck *
4 * <cuse@users.sourceforge.net> *
5 * *
6 * This library is part of libgig. *
7 * *
8 * This library is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU General Public License as published by *
10 * the Free Software Foundation; either version 2 of the License, or *
11 * (at your option) any later version. *
12 * *
13 * This library is distributed in the hope that it will be useful, *
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU General Public License *
19 * along with this library; if not, write to the Free Software *
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
21 * MA 02111-1307 USA *
22 ***************************************************************************/
23
24 #include <typeinfo>
25 #include <map>
26 #include <string>
27 #include <stdlib.h>
28 #include <stdint.h>
29
30 #if defined _MSC_VER // Microsoft compiler ...
31 # define RAW_CPP_TYPENAME(t) t.raw_name()
32 #else // i.e. especially GCC and clang ...
33 # define RAW_CPP_TYPENAME(t) t.name()
34 #endif
35
36 #define RAW_CPP_TYPENAME_OF(type) RAW_CPP_TYPENAME(typeid(type))
37
38 #define GIG_DECLARE_ENUM(type, ...) \
39 enum type { __VA_ARGS__ }; \
40 \
41 struct type##InfoRegistrator { \
42 type##InfoRegistrator() { \
43 const char* typeName = RAW_CPP_TYPENAME_OF(type); \
44 g_enumsByRawTypeName[typeName] = _parseEnumBody( #__VA_ARGS__ ); \
45 } \
46 }; \
47 \
48 static type##InfoRegistrator g_##type##InfoRegistrator;
49
50 struct EnumDeclaration {
51 std::map<size_t, std::string> nameByValue;
52 std::map<std::string, size_t> valueByName;
53 char** allKeys;
54
55 EnumDeclaration() : allKeys(NULL) {}
56
57 const size_t countKeys() const { return valueByName.size(); }
58
59 void loadAllKeys() {
60 const size_t n = valueByName.size();
61 allKeys = new char*[n + 1];
62 size_t i = 0;
63 for (std::map<std::string, size_t>::const_iterator it = valueByName.begin();
64 it != valueByName.end(); ++it, ++i)
65 {
66 allKeys[i] = strdup(it->first.c_str());
67 }
68 allKeys[n] = NULL;
69 }
70 };
71
72 struct EnumKeyVal {
73 std::string name;
74 size_t value;
75 bool isValid() const { return !name.empty(); }
76 };
77
78 static std::map<std::string, EnumDeclaration> g_enumsByRawTypeName;
79 static std::map<std::string, size_t> g_allEnumValuesByKey;
80
81
82
83 // *************** Internal functions **************
84 // *
85
86 static inline bool isWhiteSpace(const char& c) {
87 return c == ' ' || c == '\t' || c == '\n' || c == '\r';
88 }
89
90 static size_t decodeEnumValue(const std::string& encodedValue) {
91 return strtoll(encodedValue.c_str(), NULL, 0 /* auto detect base */);
92 }
93
94 static EnumKeyVal _parseEnumKeyVal(const char* start, const char* end, size_t value) {
95 EnumKeyVal keyval;
96
97 if (start >= end)
98 return keyval; // invalid
99 // ignore white space
100 for (; isWhiteSpace(*start); ++start)
101 if (start >= end)
102 return keyval; // invalid
103 if (start >= end)
104 return keyval; // invalid
105
106 // parse key
107 for (const char* p = start; true; ++p) {
108 if (p >= end || isWhiteSpace(*p) || *p == '=') {
109 const size_t sz = p - start;
110 keyval.name.resize(sz);
111 memcpy(&keyval.name[0], start, sz);
112 keyval.value = value;
113 start = p + 1;
114 break;
115 }
116 }
117
118 if (start >= end)
119 return keyval; // valid, no explicit value provided
120 // seek forward to start of value
121 for (; isWhiteSpace(*start) || *start == '='; ++start)
122 if (start >= end)
123 return keyval; // valid, no explicit value provided
124 if (start >= end)
125 return keyval; // valid, no explicit value provided
126
127 std::string encodedValue;
128 // parse value portion
129 for (const char* p = start; true; ++p) {
130 if (p >= end || isWhiteSpace(*p)) {
131 const size_t sz = p - start;
132 encodedValue.resize(sz);
133 memcpy(&encodedValue[0], start, sz);
134 break;
135 }
136 }
137
138 if (encodedValue.empty())
139 return keyval; // valid, no explicit value provided
140
141 keyval.value = decodeEnumValue(encodedValue);
142
143 return keyval;
144 }
145
146 static EnumDeclaration _parseEnumBody(const char* body) {
147 EnumDeclaration decl;
148 size_t value = 0;
149 for (const char* a = body, *b = body; true; ++b) {
150 if (*b == 0 || *b == ',') {
151 const EnumKeyVal keyval = _parseEnumKeyVal(a, b, value);
152 if (!keyval.isValid()) break;
153 decl.nameByValue[keyval.value] = keyval.name;
154 decl.valueByName[keyval.name] = keyval.value;
155 g_allEnumValuesByKey[keyval.name] = keyval.value;
156 value = keyval.value + 1;
157 if (*b == 0) break;
158 a = b + 1;
159 }
160 }
161 return decl;
162 }
163
164 #include "gig.h"
165
166 // *************** gig API functions **************
167 // *
168
169 namespace gig {
170
171 // this has to be defined manually, since leverarge_ctrl_t::type_t is a
172 // class internal member type
173 static leverage_ctrl_t::type_tInfoRegistrator g_leverageCtrlTTypeT;
174
175
176 /** @brief Amount of elements in given enum type.
177 *
178 * Returns the amount of elements of the enum type with raw C++ type name
179 * @a typeName. If the requested enum type is unknown, then this function
180 * returns @c 0 instead.
181 *
182 * Note: you @b MUST pass the raw C++ type name, not a demangled human
183 * readable C++ type name. On doubt use the overloaded function which takes
184 * a @c std::type_info as argument instead.
185 *
186 * @param typeName - raw C++ type name of enum
187 * @returns enum's amount of elements
188 */
189 size_t countEnum(String typeName) {
190 if (!g_enumsByRawTypeName.count(typeName))
191 return 0;
192 return g_enumsByRawTypeName[typeName].countKeys();
193 }
194
195 /** @brief Amount of elements in given enum type.
196 *
197 * Returns the amount of elements of the enum type given by @a type. If the
198 * requested enum type is unknown, then this function returns @c 0 instead.
199 *
200 * Use the @c typeid() keyword of C++ to get a @c std::type_info object.
201 *
202 * @param type - enum type of interest
203 * @returns enum's amount of elements
204 */
205 size_t countEnum(const std::type_info& type) {
206 return countEnum(RAW_CPP_TYPENAME(type));
207 }
208
209 /** @brief Numeric value of enum constant.
210 *
211 * Returns the numeric value (assigned at library compile time) to the enum
212 * constant with given @a name. If the requested enum constant is unknown,
213 * then this function returns @c 0 instead.
214 *
215 * @param key - enum constant name
216 * @returns enum constant's numeric value
217 */
218 size_t enumValue(String key) {
219 if (!g_allEnumValuesByKey.count(key))
220 return 0;
221 return g_allEnumValuesByKey[key];
222 }
223
224 /** @brief Check if enum element exists.
225 *
226 * Checks whether the enum constant with name @a key of enum type with raw
227 * C++ enum type name @a typeName exists. If either the requested enum type
228 * or enum constant is unknown, then this function returns @c false instead.
229 *
230 * Note: you @b MUST pass the raw C++ type name, not a demangled human
231 * readable C++ type name. On doubt use the overloaded function which takes
232 * a @c std::type_info as argument instead.
233 *
234 * @param typeName - raw C++ type name of enum
235 * @param key - name of enum constant
236 * @returns @c true if requested enum element exists
237 */
238 bool enumKey(String typeName, String key) {
239 if (!g_enumsByRawTypeName.count(typeName))
240 return false;
241 return g_enumsByRawTypeName[typeName].valueByName.count(key);
242 }
243
244 /** @brief Check if enum element exists.
245 *
246 * Checks whether the enum constant with name @a key of requested enum
247 * @a type exists. If either the requested enum type or enum constant is
248 * unknown, then this function returns @c false instead.
249 *
250 * Use the @c typeid() keyword of C++ to get a @c std::type_info object.
251 *
252 * @param type - enum type of interest
253 * @param key - name of enum constant
254 * @returns @c true if requested enum element exists
255 */
256 bool enumKey(const std::type_info& type, String key) {
257 return enumKey(RAW_CPP_TYPENAME(type), key);
258 }
259
260 /** @brief Enum constant name of numeric value.
261 *
262 * Returns the enum constant name (a.k.a. enum element name) for the given
263 * numeric @a value and the enum type with raw C++ enum type name
264 * @a typeName. If either the requested enum type or enum constant numeric
265 * value is unknown, then this function returns @c NULL instead.
266 *
267 * If the requested enum type contains several enum elements with the
268 * requested numeric enum value, then this function will simply return one
269 * of them, it is undefined which one it would return exactly in this case.
270 *
271 * Note: you @b MUST pass the raw C++ type name, not a demangled human
272 * readable C++ type name. On doubt use the overloaded function which takes
273 * a @c std::type_info as argument instead.
274 *
275 * @param typeName - raw C++ type name of enum
276 * @param value - numeric value of sought enum constant
277 * @returns @c true if requested enum element exists
278 */
279 const char* enumKey(String typeName, size_t value) {
280 if (!g_enumsByRawTypeName.count(typeName))
281 return NULL;
282 if (!g_enumsByRawTypeName[typeName].nameByValue.count(value))
283 return NULL;
284 return g_enumsByRawTypeName[typeName].nameByValue[value].c_str();
285 }
286
287 /** @brief Enum constant name of numeric value.
288 *
289 * Returns the enum constant name (a.k.a. enum element name) for the given
290 * numeric @a value and the given enum @a type. If either the requested
291 * enum type or enum constant numeric value is unknown, then this function
292 * returns @c NULL instead.
293 *
294 * If the requested enum type contains several enum elements with the
295 * requested numeric enum value, then this function will simply return one
296 * of them, it is undefined which one it would return exactly in this case.
297 *
298 * Use the @c typeid() keyword of C++ to get a @c std::type_info object.
299 *
300 * @param type - enum type of interest
301 * @param value - numeric value of sought enum constant
302 * @returns @c true if requested enum element exists
303 */
304 const char* enumKey(const std::type_info& type, size_t value) {
305 return enumKey(RAW_CPP_TYPENAME(type), value);
306 }
307
308 /** @brief All element names of enum type.
309 *
310 * Returns a NULL terminated array of C strings of all enum constant names
311 * of the given enum type with raw C++ enum type name @a typeName. If the
312 * requested enum type is unknown, then this function returns @c NULL
313 * instead.
314 *
315 * Note: you @b MUST pass the raw C++ type name, not a demangled human
316 * readable C++ type name. On doubt use the overloaded function which takes
317 * a @c std::type_info as argument instead.
318 *
319 * @param typeName - raw C++ type name of enum
320 * @returns list of all enum element names
321 */
322 const char** enumKeys(String typeName) {
323 if (!g_enumsByRawTypeName.count(typeName))
324 return NULL;
325 if (!g_enumsByRawTypeName[typeName].allKeys)
326 g_enumsByRawTypeName[typeName].loadAllKeys();
327 return (const char**) g_enumsByRawTypeName[typeName].allKeys;
328 }
329
330 /** @brief All element names of enum type.
331 *
332 * Returns a NULL terminated array of C strings of all enum constant names
333 * of the given enum @a type. If the requested enum type is unknown, then
334 * this function returns @c NULL instead.
335 *
336 * Use the @c typeid() keyword of C++ to get a @c std::type_info object.
337 *
338 * @param type - enum type of interest
339 * @returns list of all enum element names
340 */
341 const char** enumKeys(const std::type_info& type) {
342 return enumKeys(RAW_CPP_TYPENAME(type));
343 }
344
345 } // namespace gig

  ViewVC Help
Powered by ViewVC