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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3169 - (hide annotations) (download)
Wed May 10 21:17:10 2017 UTC (6 years, 10 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 schoenebeck 3169 /***************************************************************************
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