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