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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3181 - (show annotations) (download)
Sun May 14 17:08:42 2017 UTC (6 years, 11 months ago) by schoenebeck
File size: 13067 byte(s)
* Just some minor API cosmetics: renamed recently added
  enum reflections API function countEmum() -> enumCount().
* Bumped version (4.0.0.svn22).

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

  ViewVC Help
Powered by ViewVC