diff options
Diffstat (limited to 'libraries/eina/src/include/eina_magic.h')
-rw-r--r-- | libraries/eina/src/include/eina_magic.h | 322 |
1 files changed, 322 insertions, 0 deletions
diff --git a/libraries/eina/src/include/eina_magic.h b/libraries/eina/src/include/eina_magic.h new file mode 100644 index 0000000..44cd4e9 --- /dev/null +++ b/libraries/eina/src/include/eina_magic.h | |||
@@ -0,0 +1,322 @@ | |||
1 | /* EINA - EFL data type library | ||
2 | * Copyright (C) 2008 Cedric Bail | ||
3 | * | ||
4 | * This library is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU Lesser General Public | ||
6 | * License as published by the Free Software Foundation; either | ||
7 | * version 2.1 of the License, or (at your option) any later version. | ||
8 | * | ||
9 | * This library is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | * Lesser General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU Lesser General Public | ||
15 | * License along with this library; | ||
16 | * if not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #ifndef EINA_MAGIC_H_ | ||
20 | #define EINA_MAGIC_H_ | ||
21 | |||
22 | #include "eina_config.h" | ||
23 | #include "eina_types.h" | ||
24 | |||
25 | /** | ||
26 | * @page eina_magic_example_01_page | ||
27 | * @dontinclude eina_magic_01.c | ||
28 | * | ||
29 | * Whenever using Eina we must include it: | ||
30 | * @skipline #include | ||
31 | * | ||
32 | * For this example we are going to define two classes, person and pilot, and | ||
33 | * since every pilot is a person we use inheritance. To be type safe we are | ||
34 | * going to add EINA_MAGIC to our classes: | ||
35 | * @until struct _pilot pilot | ||
36 | * @note The values of BASETYPE_MAGIC and SUBTYPE_MAGIC have no meaning, the | ||
37 | * only important thing about them is that they be unique. | ||
38 | * | ||
39 | * Here we have a function to create a perso given a name, nothing too fancy: | ||
40 | * @until } | ||
41 | * | ||
42 | * And now the counterpart, a function the free a person. | ||
43 | * @until { | ||
44 | * Before we start releasing resources we check that the pointer we were given | ||
45 | * actually points to a person, and if not we will print an error message and | ||
46 | * quit: | ||
47 | * @until } | ||
48 | * @note EINA_MAGIC_FAIL is a macro that make's it easy to print an appropriate | ||
49 | * (and consistent) error message. | ||
50 | * Now knowing that ptr is indeed of type person we prooced to set EINA_MAGIC to | ||
51 | * EINA_MAGIC_NONE and free alocated memory: | ||
52 | * @until } | ||
53 | * @note Setting EINA_MAGIC to EINA_MAGIC_NONE is important to prevent the | ||
54 | * struct from being used after freed. | ||
55 | * | ||
56 | * Now we have our function to create a pilot, this one is a little more complex | ||
57 | * because we need to set EINA_MAGIC for the pilot and pilot->base, this is very | ||
58 | * important so that checking the EINA_MAGIC of (person*)my_pilot will work: | ||
59 | * @until } | ||
60 | * | ||
61 | * The function to free a pilot is not too different from the one that frees a | ||
62 | * person: | ||
63 | * @until } | ||
64 | * @until } | ||
65 | * | ||
66 | * We also create functions to print a person or a pilot that check the type of | ||
67 | * the pointers they receive: | ||
68 | * @until } | ||
69 | * @until } | ||
70 | * | ||
71 | * And on to our main function where we declare some variables and initialize | ||
72 | * Eina: | ||
73 | * @until eina_init | ||
74 | * | ||
75 | * For Eina to be able to provide more informative error messages we are going | ||
76 | * to give names to our EINA_MAGIC types: | ||
77 | * @until string_set | ||
78 | * | ||
79 | * Since our types won't live longer than the scope of the current function we | ||
80 | * can set the name without eina making a copy of the string: | ||
81 | * @until static_set | ||
82 | * | ||
83 | * Now we create a person, a pilot and print both as persons: | ||
84 | * @until person * | ||
85 | * | ||
86 | * Now we try to print both as pilots, which will obvisouly not work since base | ||
87 | * is not a pilot: | ||
88 | * @until pilot(sub | ||
89 | * | ||
90 | * That's all folks: | ||
91 | * @until } | ||
92 | * | ||
93 | * See full source @ref eina_magic_example_01_c "here". | ||
94 | */ | ||
95 | /** | ||
96 | * @page eina_magic_example_01_c Eina_Magic | ||
97 | * @include eina_magic_01.c | ||
98 | * @example eina_magic_01.c | ||
99 | */ | ||
100 | /** | ||
101 | * @addtogroup Eina_Tools_Group Tools | ||
102 | * | ||
103 | * @{ | ||
104 | */ | ||
105 | /** | ||
106 | * @defgroup Eina_Magic_Group Magic | ||
107 | * | ||
108 | * @brief Eina_Magic provides run-time type-checking. | ||
109 | * | ||
110 | * C is a weak statically typed language, in other words, it will just check for | ||
111 | * types during compile time and any cast will make the compiler believe the | ||
112 | * type is correct. | ||
113 | * | ||
114 | * In real world code we often need to deal with casts, either explicit or | ||
115 | * implicit by means of @c void*. We also need to resort to casts when doing | ||
116 | * inheritance in C. | ||
117 | * | ||
118 | * Eina_Magic give us a way to do casts and still be certain of the type we are | ||
119 | * opearting on. | ||
120 | * | ||
121 | * @note It should be noted that it is considered good practice to @b disable | ||
122 | * Eina_Magic for production code. The reasoning is that any Eina_Magic errors | ||
123 | * should have been caught during testing and therefore there is no reason to | ||
124 | * incur the performance downside of Eina_Magic. | ||
125 | * | ||
126 | * An @ref eina_magic_example_01_page "example" should elucidate matters. | ||
127 | * | ||
128 | * @{ | ||
129 | */ | ||
130 | |||
131 | /** | ||
132 | * An abstract type for a magic number. | ||
133 | */ | ||
134 | typedef unsigned int Eina_Magic; | ||
135 | |||
136 | /** | ||
137 | * @brief Return the string associated to the given magic identifier. | ||
138 | * | ||
139 | * @param magic The magic identifier. | ||
140 | * @return The string associated to the identifier. | ||
141 | * | ||
142 | * This function returns the string associated to @p magic. Even if none are | ||
143 | * found this function still returns non @c NULL, in this case an identifier | ||
144 | * such as "(none)", "(undefined)" or "(unknown)". | ||
145 | * | ||
146 | * The following identifiers may be returned whenever magic is | ||
147 | * invalid, with their meanings: | ||
148 | * | ||
149 | * - (none): no magic was registered exists at all. | ||
150 | * - (undefined): magic was registered and found, but no string associated. | ||
151 | * - (unknown): magic was not found in the registry. | ||
152 | * | ||
153 | * @warning The returned value must not be freed. | ||
154 | */ | ||
155 | EAPI const char *eina_magic_string_get(Eina_Magic magic) EINA_WARN_UNUSED_RESULT; | ||
156 | /** | ||
157 | * @brief Set the string associated to the given magic identifier. | ||
158 | * | ||
159 | * @param magic The magic identifier. | ||
160 | * @param magic_name The string associated to the identifier, must not | ||
161 | * be @c NULL. | ||
162 | * | ||
163 | * @return #EINA_TRUE on success, #EINA_FALSE on failure. | ||
164 | * | ||
165 | * This function sets the string @p magic_name to @p magic. It is not | ||
166 | * checked if number or string are already set, in which case you will end with | ||
167 | * duplicates. Internally, eina will make a copy of @p magic_name. | ||
168 | * | ||
169 | * @see eina_magic_string_static_set() | ||
170 | */ | ||
171 | EAPI Eina_Bool eina_magic_string_set(Eina_Magic magic, | ||
172 | const char *magic_name) EINA_ARG_NONNULL(2); | ||
173 | |||
174 | /** | ||
175 | * @brief Set the string associated to the given magic identifier. | ||
176 | * | ||
177 | * @param magic The magic identifier. | ||
178 | * @param magic_name The string associated to the identifier, must not be | ||
179 | * @c NULL. | ||
180 | * | ||
181 | * @return #EINA_TRUE on success, #EINA_FALSE on failure. | ||
182 | * | ||
183 | * This function sets the string @p magic_name to @p magic. It is not checked if | ||
184 | * number or string are already set, in which case you might end with | ||
185 | * duplicates. Eina will @b not make a copy of @p magic_name, this means that | ||
186 | * @p magic_name has to be a valid pointer for as long as @p magic is used. | ||
187 | * | ||
188 | * @see eina_magic_string_set() | ||
189 | */ | ||
190 | EAPI Eina_Bool eina_magic_string_static_set(Eina_Magic magic, | ||
191 | const char *magic_name) EINA_ARG_NONNULL(2); | ||
192 | |||
193 | /** | ||
194 | * @def EINA_MAGIC_NONE | ||
195 | * Random value for specifying that a structure using the magic | ||
196 | * feature has already been freed. It is used by eina_magic_fail(). | ||
197 | * | ||
198 | * If the magic feature of Eina is disabled, #EINA_MAGIC_NONE is just | ||
199 | * @c 0. | ||
200 | */ | ||
201 | #define EINA_MAGIC_NONE 0x1234fedc | ||
202 | |||
203 | #ifdef EINA_MAGIC_DEBUG | ||
204 | |||
205 | /** | ||
206 | * @def EINA_MAGIC | ||
207 | * Declaration of a variable of type #Eina_Magic. To put in a structure | ||
208 | * when one wants to use the magic feature of Eina with the functions | ||
209 | * of that structure, like that: | ||
210 | * | ||
211 | * @code | ||
212 | * struct Foo | ||
213 | * { | ||
214 | * int i; | ||
215 | * | ||
216 | * EINA_MAGIC | ||
217 | * }; | ||
218 | * @endcode | ||
219 | * | ||
220 | * If the magic feature of Eina is disabled, #EINA_MAGIC does nothing. | ||
221 | */ | ||
222 | #define EINA_MAGIC Eina_Magic __magic; | ||
223 | |||
224 | /** | ||
225 | * @def EINA_MAGIC_SET(d, m) | ||
226 | * Set the magic number of @p d to @p m. @p d must be a valid pointer | ||
227 | * to a structure holding an Eina magic number declaration. Use | ||
228 | * #EINA_MAGIC to add such declaration. | ||
229 | * | ||
230 | * If the magic feature of Eina is disabled, #EINA_MAGIC_CHECK is just | ||
231 | * the value @c 0. | ||
232 | */ | ||
233 | #define EINA_MAGIC_SET(d, m) (d)->__magic = (m) | ||
234 | |||
235 | /** | ||
236 | * @def EINA_MAGIC_CHECK(d, m) | ||
237 | * Test if @p d is @c NULL or not, and if not @c NULL, if | ||
238 | * @p d->__eina_magic is equal to @p m. @p d must be a structure that | ||
239 | * holds an Eina magic number declaration. Use #EINA_MAGIC to add such | ||
240 | * declaration. | ||
241 | * | ||
242 | * If the magic feature of Eina is disabled, #EINA_MAGIC_CHECK is just | ||
243 | * the value @c 1. | ||
244 | */ | ||
245 | #define EINA_MAGIC_CHECK(d, m) ((d) && ((d)->__magic == (m))) | ||
246 | |||
247 | /** | ||
248 | * @def EINA_MAGIC_FAIL(d, m) | ||
249 | * Call eina_magic_fail() with the parameters @p d, @p d->__magic, @p | ||
250 | * m, __FILE__, __FUNCTION__ and __LINE__. @p d must be a structure that | ||
251 | * holds an Eina magic number declaration. Use #EINA_MAGIC to add such | ||
252 | * declaration. | ||
253 | * | ||
254 | * If the magic feature of Eina is disabled, #EINA_MAGIC_FAIL does | ||
255 | * nothing. | ||
256 | */ | ||
257 | #define EINA_MAGIC_FAIL(d, m) \ | ||
258 | eina_magic_fail((void *)(d), \ | ||
259 | (d) ? (d)->__magic : 0, \ | ||
260 | (m), \ | ||
261 | __FILE__, \ | ||
262 | __FUNCTION__, \ | ||
263 | __LINE__); | ||
264 | |||
265 | /** | ||
266 | * @brief Display a message or abort if a magic check failed. | ||
267 | * | ||
268 | * @param d The checked data pointer. | ||
269 | * @param m The magic identifer to check. | ||
270 | * @param req_m The requested magic identifier to check. | ||
271 | * @param file The file in which the magic check failed. | ||
272 | * @param fnc The function in which the magic check failed. | ||
273 | * @param line The line at which the magic check failed. | ||
274 | * | ||
275 | * @warning You should @b strongly consider using @ref EINA_MAGIC_FAIL(d, m) | ||
276 | * instead. | ||
277 | * | ||
278 | * This function displays an error message if a magic check has | ||
279 | * failed, using the following logic in the following order: | ||
280 | * @li If @p d is @c NULL, a message warns about a @c NULL pointer. | ||
281 | * @li Otherwise, if @p m is equal to #EINA_MAGIC_NONE, a message | ||
282 | * warns about a handle that was already freed. | ||
283 | * @li Otherwise, if @p m is equal to @p req_m, a message warns about | ||
284 | * a handle that is of wrong type. | ||
285 | * @li Otherwise, a message warns you about ab-using that function... | ||
286 | * | ||
287 | * If the environment variable EINA_LOG_ABORT is set, abort() is | ||
288 | * called and the program stops. It is useful for debugging programs | ||
289 | * with gdb. | ||
290 | */ | ||
291 | EAPI void eina_magic_fail(void *d, Eina_Magic m, Eina_Magic req_m, | ||
292 | const char *file, const char *fnc, | ||
293 | int line) EINA_ARG_NONNULL(4, 5); | ||
294 | |||
295 | #else | ||
296 | |||
297 | /** | ||
298 | * @cond LOCAL | ||
299 | */ | ||
300 | |||
301 | #define EINA_MAGIC | ||
302 | #define EINA_MAGIC_SET(d, m) ((void)0) | ||
303 | #define EINA_MAGIC_CHECK(d, m) (1) | ||
304 | #define EINA_MAGIC_FAIL(d, m) ((void)0) | ||
305 | |||
306 | #define eina_magic_fail(d, m, req_m, file, fnx, line) ((void)0) | ||
307 | |||
308 | /** | ||
309 | * @endcond | ||
310 | */ | ||
311 | |||
312 | #endif | ||
313 | |||
314 | /** | ||
315 | * @} | ||
316 | */ | ||
317 | |||
318 | /** | ||
319 | * @} | ||
320 | */ | ||
321 | |||
322 | #endif /* EINA_MAGIC_H_ */ | ||