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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3181 - (hide 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 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 schoenebeck 3171 #include <string.h> // for strdup()
30 schoenebeck 3169
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 schoenebeck 3172 static type##InfoRegistrator g_##type##InfoRegistrator
50 schoenebeck 3169
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 schoenebeck 3181 size_t enumCount(String typeName) {
191 schoenebeck 3169 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 schoenebeck 3181 size_t enumCount(const std::type_info& type) {
207     return enumCount(RAW_CPP_TYPENAME(type));
208 schoenebeck 3169 }
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