| [229e3c] | 1 | /* | 
|---|
|  | 2 | * Assert.hpp | 
|---|
|  | 3 | * | 
|---|
|  | 4 | *  Created on: Mar 18, 2010 | 
|---|
|  | 5 | *      Author: crueger | 
|---|
|  | 6 | */ | 
|---|
|  | 7 |  | 
|---|
|  | 8 | #ifndef ASSERT_HPP_ | 
|---|
|  | 9 | #define ASSERT_HPP_ | 
|---|
|  | 10 |  | 
|---|
| [13d5a9] | 11 | #include<sstream> | 
|---|
| [229e3c] | 12 | #include<string> | 
|---|
| [986ed3] | 13 | #include<iosfwd> | 
|---|
| [5be0eb] | 14 | #include<vector> | 
|---|
| [13d5a9] | 15 | #include<map> | 
|---|
| [5be0eb] | 16 |  | 
|---|
| [ce1d8c] | 17 | /** | 
|---|
|  | 18 | * \file Helpers/Assert.hpp | 
|---|
|  | 19 | * <H1> ASSERT Howto </H1> | 
|---|
|  | 20 | * | 
|---|
|  | 21 | * <H2> Introduction </H2> | 
|---|
|  | 22 | * | 
|---|
|  | 23 | * ASSERT() is a small macro that allows easier debugging, when it is widely used. The custom | 
|---|
|  | 24 | * ASSERT macro defined in this file works mainly the same way as the assert() macro that | 
|---|
|  | 25 | * is defined in the Ansi-C standard, but includes a few nice additions. | 
|---|
|  | 26 | * | 
|---|
|  | 27 | * <H3> What ASSERT() does </H3> | 
|---|
|  | 28 | * | 
|---|
|  | 29 | * ASSERT can be used to make sure that a condition that always needs to be true for the code to | 
|---|
|  | 30 | * work correctly is holding. If you have a function that takes a value greater than 0 and a value | 
|---|
|  | 31 | * smaller than 0 indicates a mistake you should always do it the following way: <br> | 
|---|
|  | 32 | * @code | 
|---|
|  | 33 | * void foo(int a) // a should be greater 0 | 
|---|
|  | 34 | * { | 
|---|
|  | 35 | *  ASSERT(a>0,"Parameter passed to foo was smaller than 0"); | 
|---|
|  | 36 | *  ... | 
|---|
|  | 37 | * } | 
|---|
|  | 38 | * @endcode | 
|---|
|  | 39 | * | 
|---|
|  | 40 | * (Note: some people say, that assertions like these should not be used to check function parameters. | 
|---|
|  | 41 | * This is mainly due to the reason, that a failed assertion will show up inside the function. The buggy | 
|---|
|  | 42 | * code however is at a completely different place, i.e. at the callers side. Always put the | 
|---|
|  | 43 | * Assertions as close to the code that produces the value as possible, when looking at function | 
|---|
|  | 44 | * parameters however this would mean, that any code calling foo would have an ASSERT(...) before | 
|---|
|  | 45 | * it, which makes it easy to forget the Assertion at some places. Also this makes an easy example.) | 
|---|
|  | 46 | * | 
|---|
|  | 47 | * If the condition inside the ASSERT does not evaluate to true the user is shown a message, including | 
|---|
|  | 48 | * the condition that failed, the line in which the failure was observed and the message of the assertion. | 
|---|
|  | 49 | * In the above case that would look something like this:<br> | 
|---|
|  | 50 | * @code | 
|---|
|  | 51 | * Assertion "a>0" failed in foo.cpp in line 3. | 
|---|
|  | 52 | * Assertion Message: Parameter passed to foo was smaller than 0 | 
|---|
|  | 53 | * @endcode | 
|---|
|  | 54 | * | 
|---|
|  | 55 | * In normal conditions, i.e. when no default action is set (see below for default actions) the user | 
|---|
|  | 56 | * is then shown a short choice menu, on how to handle the assertion. The user can choose to abort the | 
|---|
|  | 57 | * program, throw an exception of type AssertionFailure that contains the file, line and message, | 
|---|
|  | 58 | * ignore the assertion or even to always ignore the assertion at that point (i.e. the ASSERT() macro | 
|---|
|  | 59 | * at this file and line is fully disabled). | 
|---|
|  | 60 | * | 
|---|
|  | 61 | * Both ASSERT() and assert() handle debugging in the same way, i.e. they are only used when the | 
|---|
|  | 62 | * NDEBUG macro is not defined. If the NDEBUG macro is defined, for example using a CXXFLAG then | 
|---|
|  | 63 | * all asserts and ASSERTs will be disabled in the compiled program. That way in a end-user version | 
|---|
|  | 64 | * all assertions can be removed with a single switch, thus not hassling the end-user with potential | 
|---|
|  | 65 | * bugs. | 
|---|
|  | 66 | * | 
|---|
|  | 67 | * <H2> Special functions of ASSERT() </H2> | 
|---|
|  | 68 | * | 
|---|
|  | 69 | * Compared to the standard assert() macro the custom ASSERT() contains a few special functions. As | 
|---|
|  | 70 | * first it is possible to set a global default behavior that is used anytime an assertion fails. | 
|---|
|  | 71 | * This default behavior can be either of Assert::Ask, Assert::Abort, Assert::Throw or Assert::ignore. | 
|---|
|  | 72 | * The default behavior is set using the ASSERT_DO() macro. For example if you want to check in a | 
|---|
|  | 73 | * unittest that wrong code at another point actually makes a certain assert fail you could set | 
|---|
|  | 74 | * ASSERT_DO(Assert::Throw) to make sure a exception is thrown and catch that exception using | 
|---|
|  | 75 | * the CPPUNIT_ASSERT_THROW() macro. The current set default behavior can be queried as a string | 
|---|
|  | 76 | * using the ASSERT_DEFAULT macro. | 
|---|
|  | 77 | * | 
|---|
|  | 78 | * As a second enhancement it is possible to install callback functions as hooks that will be executed | 
|---|
|  | 79 | * when an assertion aborts the program. These callback functions could for example be used to flush | 
|---|
|  | 80 | * any open streams, thus making sure files on the disk are not corrupted by a unexpected abortion. | 
|---|
|  | 81 | * It would also be possible to install functions that produce some kind of "coredump" of important | 
|---|
|  | 82 | * internal data-structures, thus giving the person looking for the bug some valuable information. | 
|---|
|  | 83 | * These assertion hooks should however not be used to clean up the reserved memory of the program, | 
|---|
|  | 84 | * because a) this memory is under normal circumstances reclaimed by the OS anyway, once the program | 
|---|
|  | 85 | * has aborted and b) the memory might still contain some hints that could be useful when running | 
|---|
|  | 86 | * the program inside a debugger and which could be destroyed by the clean-up. To use the hooking | 
|---|
|  | 87 | * mechanism you can simply use the ASSERT_HOOK() macro, passing this macro any kind of void function. | 
|---|
|  | 88 | * For example:<br/> | 
|---|
|  | 89 | * @code | 
|---|
|  | 90 | * void foo(){ | 
|---|
|  | 91 | *   // produce a coredump | 
|---|
|  | 92 | *   ... | 
|---|
|  | 93 | *   // close and flush all open handles | 
|---|
|  | 94 | *   ... | 
|---|
|  | 95 | * } | 
|---|
|  | 96 | * | 
|---|
|  | 97 | * int main(int argc, char **argv){ | 
|---|
|  | 98 | *   ASSERT_HOOK(foo); | 
|---|
|  | 99 | *   ... | 
|---|
|  | 100 | *   return 0; | 
|---|
|  | 101 | * } | 
|---|
|  | 102 | * @endcode | 
|---|
|  | 103 | * | 
|---|
|  | 104 | * All hooks will be executed in the reverse order of hooking, i.e. the function hooked last will be | 
|---|
|  | 105 | * executed first when the abortion is handled. It is also possible to remove a hook to any function | 
|---|
|  | 106 | * using the ASSERT_UNHOOK() macro and passing it the pointer to the function one wants to remove. | 
|---|
|  | 107 | * | 
|---|
|  | 108 | * Assertion hooks will only be executed when the program is terminated by an assertion using the | 
|---|
|  | 109 | * abort mechanism. They will not be executed when the program exits in any other way. They also | 
|---|
|  | 110 | * wont be executed when the assertion is ignored or an exception is thrown (even when the exception | 
|---|
|  | 111 | * is not caught and thus terminates the program). | 
|---|
|  | 112 | * | 
|---|
|  | 113 | * <H2> Rules for using ASSERT() </H2> | 
|---|
|  | 114 | * | 
|---|
|  | 115 | * The rules for using ASSERT() are basically the same ones that can be used as guidlines for the | 
|---|
|  | 116 | * standard assert() macro. So if you think you know those guidelines you can skip the following. | 
|---|
|  | 117 | * | 
|---|
|  | 118 | * <ul> | 
|---|
|  | 119 | * <li> ASSERT() should be used only for problems that indicate a bug, i.e. problems that can be | 
|---|
|  | 120 | * improved by rewriting parts of the program. ASSERT() should not be used to query problems that | 
|---|
|  | 121 | * can go wrong during the normal execution of the program. For example ASSERT() should not be | 
|---|
|  | 122 | * used to test whether a file could be opened, or memory could be reserved, as a failure of either | 
|---|
|  | 123 | * of those tasks can not be improved upon by rewriting the code. | 
|---|
|  | 124 | * <li> The condition in the ASSERT() macro should never contain any side-effects. Only call methods, | 
|---|
|  | 125 | * when you are absolutely certain that these methods wont have any side-effects. Calling ASSERT() | 
|---|
|  | 126 | * should in no way change the state of the program, because once the end-user version is produced | 
|---|
|  | 127 | * using the NDEBUG flag all assertions are removed and so are the conditions. If the condition did | 
|---|
|  | 128 | * cause a state transition, this state transition would be removed and the behavior of the end-user | 
|---|
|  | 129 | * and the debug version might differ. Things you should watch out for are for example<br/> | 
|---|
|  | 130 | * @code | 
|---|
|  | 131 | * ASSERT(++i,"i was zero after incrementing"); | 
|---|
|  | 132 | * @endcode | 
|---|
|  | 133 | * instead always do | 
|---|
|  | 134 | * @code | 
|---|
|  | 135 | * ++i; | 
|---|
|  | 136 | * ASSERT(i,"i was zero after incrementing"); | 
|---|
|  | 137 | * @endcode | 
|---|
|  | 138 | * <li> Give descriptive error messages. This one is a bit obvious but easy to do wrong, so I included | 
|---|
|  | 139 | * it here. An | 
|---|
|  | 140 | * @code | 
|---|
|  | 141 | * ASSERT(ptr,"Pointer was zero"); | 
|---|
|  | 142 | * @endcode | 
|---|
|  | 143 | * wont help anyone. If you do <br/> | 
|---|
|  | 144 | * @code | 
|---|
|  | 145 | * ASSERT(ptr,"Second argument of function foo should have pointed to an object of type bar, but was zero."); | 
|---|
|  | 146 | * @endcode | 
|---|
|  | 147 | * instead, people will almost immidiately know what to look for. | 
|---|
|  | 148 | * </ul> | 
|---|
|  | 149 | * | 
|---|
|  | 150 | * <H2> Differences between ASSERT() and assert() </H2> | 
|---|
|  | 151 | * | 
|---|
|  | 152 | * This chapter is to explain why a custom ASSERT() macro was introduced and should be used in place | 
|---|
|  | 153 | * of the standard assert(). Here are the main differences between ASSERT() and assert(). | 
|---|
|  | 154 | * | 
|---|
|  | 155 | * <ul> | 
|---|
|  | 156 | * <li> ASSERT() makes it easy to add a more verbose message about the nature of the failure. For | 
|---|
|  | 157 | * assert() it has become customary to add messages using constructs like | 
|---|
|  | 158 | * @code | 
|---|
|  | 159 | * assert(c>0 && "Counter should be at least 1"); | 
|---|
|  | 160 | * @endcode in order to add descriptions. However both the syntax and the final output for this are | 
|---|
|  | 161 | * a bit awkward. The custom ASSERT() handles messages in a much better way, as well as making them | 
|---|
|  | 162 | * mandatory instead of optional. | 
|---|
|  | 163 | * <li> ASSERT() leaves the user and the programmer a choice how to handle an assertion. While the | 
|---|
|  | 164 | * assert() macro will always abort the program, the ASSERT() macro normally gives the user a choice on | 
|---|
|  | 165 | * what to do. For debugging it might also be interesting how a broken assumption influences the rest | 
|---|
|  | 166 | * of the program, so the assertion can also be ignored. Also the Exception mechanism allows | 
|---|
|  | 167 | * assertions to be part of unittests, whereas they would always fail if the assert() macro was used. | 
|---|
|  | 168 | * <li> ASSERT() does not unwind the stack (at least when compiled using gcc). The normal assert() | 
|---|
|  | 169 | * exits the program, which unwinds the stack and destroys any hope for recovering a stack trace. | 
|---|
|  | 170 | * ASSERT() on the other hand aborts the program using a special trap function, that leaves the | 
|---|
|  | 171 | * stack intact. This way, when the program is run inside a debugger the stack is still available | 
|---|
|  | 172 | * and can be inspected. This is the main reason, why it is safe to use ASSERT() to check function | 
|---|
|  | 173 | * parameters, whereas assert() would give problems in such cases. | 
|---|
|  | 174 | * <li> ASSERT() allows for hooks to be installed when the program exits. As mentioned above this | 
|---|
|  | 175 | * makes it possible to produce coredumps, make sure all files are in a usable state or other tasks | 
|---|
|  | 176 | * that have to be performed before killing the program. | 
|---|
|  | 177 | * </ul> | 
|---|
|  | 178 | * | 
|---|
|  | 179 | * <H2> Tips and tricks and FAQ </H2> | 
|---|
|  | 180 | * | 
|---|
|  | 181 | * <ul> | 
|---|
| [23359f] | 182 | * <li> <H4> How can I add values to the failure message of ASSERT(), e.g. I want to say that above "i" | 
|---|
|  | 183 | *      failed to be zero, with i == ...?</H4> | 
|---|
|  | 184 | * This can be done in the following way: | 
|---|
|  | 185 | * @code | 
|---|
|  | 186 | * ASSERT(!i,"i was not zero but "+std::string(i)+"after incrementing"); | 
|---|
|  | 187 | * @endcode | 
|---|
|  | 188 | * Note that this works because std::string() in the middle requires the const char arrays on both ends | 
|---|
|  | 189 | * to be converted to string and eventually, the whole text is again cast to const char * form. | 
|---|
| [ce1d8c] | 190 | * <li> <H4> ASSERT() is broken. When I abort the program it says something about an | 
|---|
|  | 191 | * "Illegal instruction"</H4> | 
|---|
|  | 192 | * The complaints about the illegal instruction after an abortion are no need to worry. This | 
|---|
|  | 193 | * illegal instruction is part of the trap that is used to exit the program while leaving the stack | 
|---|
|  | 194 | * intact. This illegal instruction can be detected by the debugger, which means it will give you the | 
|---|
|  | 195 | * usual prompt once it is encountered. The illegal instruction is guaranteed not to mess up anything, | 
|---|
|  | 196 | * so there is no need to worry about it. | 
|---|
|  | 197 | * <li> <H4> When compiling the program with $NON_GCC_COMPILER and then debugging it, it will | 
|---|
|  | 198 | * unwind the stack. I need the backtrace however to find the bug </H4> | 
|---|
|  | 199 | * The mechanism to preserve the stack is compiler specific. For now only a mechanism that is supported | 
|---|
|  | 200 | * by gcc is implemented, because this compiler is widely used. For other compilers the program | 
|---|
|  | 201 | * is simply exited, and the stack is destroyed. If you need a backtrace and you cannot use gcc you | 
|---|
|  | 202 | * have to figure out a way to have your compiler produce a trap instruction in the program. You might | 
|---|
|  | 203 | * want to use google to find out how to get your compiler to do that. For many compilers a | 
|---|
|  | 204 | * _asm {int 3} is said to work. Also for VC++ the instruction __debugbreak() might produce a trap. | 
|---|
|  | 205 | * Also dividing by zero is a hack that could be used as a last hope if you don't find a way to produce | 
|---|
|  | 206 | * traps with your compiler even after a longer search. If you found a way to handle the traps you can | 
|---|
|  | 207 | * then add the macro DEBUG_BREAK for your compiler and the stack will be preserved. | 
|---|
|  | 208 | * <li> <H4> I have a portion of the program that should never be executed. How can I assure this | 
|---|
|  | 209 | * using assert.</H4> | 
|---|
|  | 210 | * This is a common task for assertions. For example you might have an exhaustive switch/case where | 
|---|
|  | 211 | * the default value indicates that something went wrong. Simply use the following construct: | 
|---|
|  | 212 | * @code | 
|---|
|  | 213 | * switch(foo){ | 
|---|
|  | 214 | *   case Bar: | 
|---|
|  | 215 | *     ... | 
|---|
|  | 216 | *     break; | 
|---|
|  | 217 | *   case Baz: | 
|---|
|  | 218 | *     ... | 
|---|
|  | 219 | *     break; | 
|---|
|  | 220 | *   ... | 
|---|
|  | 221 | *   default: | 
|---|
|  | 222 | *     ASSERT(0,"This switch should always be exhaustive.\nDid somebody add values to the enum?"); | 
|---|
|  | 223 | * } | 
|---|
|  | 224 | * @endcode | 
|---|
|  | 225 | * </ul> | 
|---|
|  | 226 | */ | 
|---|
|  | 227 |  | 
|---|
| [229e3c] | 228 | #ifndef NDEBUG | 
|---|
|  | 229 | #ifndef STRINGIFY | 
|---|
|  | 230 | #define STRINGIFY(x) #x | 
|---|
|  | 231 | #endif | 
|---|
|  | 232 |  | 
|---|
|  | 233 | #ifdef __GNUC__ | 
|---|
|  | 234 | // on gcc we know how to exit to the Debugger | 
|---|
|  | 235 | #define DEBUG_BREAK __builtin_trap() | 
|---|
|  | 236 | #else | 
|---|
|  | 237 | #define DEBUG_BREAK exit(1) | 
|---|
|  | 238 | #endif | 
|---|
|  | 239 |  | 
|---|
|  | 240 | #define ASSERT(condition,message) \ | 
|---|
|  | 241 | do{\ | 
|---|
|  | 242 | static bool ignore = false;\ | 
|---|
|  | 243 | if(!ignore){\ | 
|---|
| [506d2f] | 244 | if(!(condition) && Assert::_my_assert::check(STRINGIFY(condition),(message),\ | 
|---|
|  | 245 | __FILE__,__LINE__,ignore)){\ | 
|---|
| [13d5a9] | 246 | Assert::_my_assert::doHooks();\ | 
|---|
| [229e3c] | 247 | DEBUG_BREAK;\ | 
|---|
| [5be0eb] | 248 | }\ | 
|---|
| [229e3c] | 249 | } \ | 
|---|
|  | 250 | }while(0) | 
|---|
|  | 251 |  | 
|---|
| [ccacba] | 252 | #define ASSERT_NOCATCH(message) \ | 
|---|
|  | 253 | catch(Assert::AssertionFailure&){throw;}\ | 
|---|
|  | 254 | catch(...){\ | 
|---|
|  | 255 | static bool ignore = false; \ | 
|---|
| [13d5a9] | 256 | if(!ignore){\ | 
|---|
| [506d2f] | 257 | if(Assert::_my_assert::check("Exception caught",(message),__FILE__,__LINE__,ignore)){\ | 
|---|
| [13d5a9] | 258 | Assert::_my_assert::doHooks();\ | 
|---|
| [506d2f] | 259 | DEBUG_BREAK;\ | 
|---|
| [13d5a9] | 260 | }\ | 
|---|
|  | 261 | }\ | 
|---|
| [033a05] | 262 | } do{(void)(0);}while(0) | 
|---|
| [ccacba] | 263 |  | 
|---|
| [13d5a9] | 264 | #define assert_cast Assert::_wrapper(__LINE__,__FILE__)._convert | 
|---|
|  | 265 |  | 
|---|
|  | 266 | #define ASSERT_DO(action)    do{Assert::_my_assert::setDefault(action);}while(0) | 
|---|
|  | 267 | #define ASSERT_HOOK(hook)    do{Assert::_my_assert::addHook(hook);}while(0) | 
|---|
|  | 268 | #define ASSERT_UNHOOK(hook)  do{Assert::_my_assert::removeHook(hook);}while(0) | 
|---|
|  | 269 | #define ASSERT_DEFAULT       (Assert::_myAssert::printDefault()) | 
|---|
| [229e3c] | 270 | #else | 
|---|
|  | 271 | // we need to do something, so this is the usual solution (e.g. assert.h) | 
|---|
|  | 272 | #define ASSERT(condition,message) (void)(0) | 
|---|
| [8bb2fd] | 273 | #define ASSERT_NOCATCH(message)   catch(...) {throw;} do{(void)(0);}while(0) | 
|---|
| [13d5a9] | 274 | #define assert_cast static_cast | 
|---|
| [5be0eb] | 275 | #define ASSERT_DO(action)         (void)(0) | 
|---|
|  | 276 | #define ASSERT_HOOK(hook)         (void)(0) | 
|---|
|  | 277 | #define ASSERT_UNHOOK(hook)       (void)(0) | 
|---|
|  | 278 | #define ASSERT_DEFAULT            std::string("Deactivated") | 
|---|
| [229e3c] | 279 | #endif | 
|---|
|  | 280 |  | 
|---|
| [13d5a9] | 281 | namespace Assert{ | 
|---|
|  | 282 |  | 
|---|
|  | 283 | typedef void (*hook_t)(void); | 
|---|
|  | 284 |  | 
|---|
|  | 285 |  | 
|---|
|  | 286 | enum Action {Ask,Abort,Throw,Ignore,MAX_ACTION}; | 
|---|
|  | 287 | extern const char  ActionKeys[MAX_ACTION]; | 
|---|
|  | 288 | extern const char* ActionNames[MAX_ACTION]; | 
|---|
|  | 289 |  | 
|---|
|  | 290 | class AssertionFailure{ | 
|---|
|  | 291 | public: | 
|---|
|  | 292 | AssertionFailure(std::string _condition, std::string _file, int _line, std::string _message); | 
|---|
|  | 293 | std::string getFile(); | 
|---|
|  | 294 | int getLine(); | 
|---|
|  | 295 | std::string getMessage(); | 
|---|
|  | 296 |  | 
|---|
|  | 297 | std::ostream& operator<<(std::ostream&); | 
|---|
|  | 298 | private: | 
|---|
|  | 299 | std::string condition; | 
|---|
|  | 300 | std::string file; | 
|---|
|  | 301 | int line; | 
|---|
|  | 302 | std::string message; | 
|---|
|  | 303 | }; | 
|---|
|  | 304 |  | 
|---|
|  | 305 | //! @cond | 
|---|
|  | 306 | #ifndef NDEBUG | 
|---|
|  | 307 | class _my_assert{ | 
|---|
|  | 308 | public: | 
|---|
| [506d2f] | 309 | static bool check(const char* condition, | 
|---|
| [23359f] | 310 | std::string message, | 
|---|
| [13d5a9] | 311 | const char* filename, | 
|---|
|  | 312 | const int line, | 
|---|
|  | 313 | bool& ignore); | 
|---|
| [90aeb9] | 314 | #ifdef __GNUC__ | 
|---|
|  | 315 | static void backtrace(const char *file, int line); | 
|---|
|  | 316 | #endif /* __GNUC__ */ | 
|---|
| [13d5a9] | 317 | static void addHook(Assert::hook_t hook); | 
|---|
|  | 318 | static void removeHook(Assert::hook_t hook); | 
|---|
|  | 319 | static void doHooks(); | 
|---|
|  | 320 | static void setDefault(Assert::Action); | 
|---|
|  | 321 | static Assert::Action getDefault(); | 
|---|
|  | 322 | static std::string printDefault(); | 
|---|
|  | 323 | private: | 
|---|
|  | 324 | static Assert::Action defaultAction; | 
|---|
|  | 325 | static std::vector<Assert::hook_t> hooks; | 
|---|
|  | 326 | }; | 
|---|
|  | 327 |  | 
|---|
|  | 328 |  | 
|---|
|  | 329 | class _wrapper{ | 
|---|
|  | 330 | public: | 
|---|
|  | 331 | _wrapper(int _line,const char* _file) : | 
|---|
|  | 332 | line(_line), | 
|---|
|  | 333 | file(_file) | 
|---|
|  | 334 | {} | 
|---|
|  | 335 |  | 
|---|
|  | 336 | // Overloaded template for pointers | 
|---|
|  | 337 | template<typename target,typename source> | 
|---|
|  | 338 | target _convert(source *src){ | 
|---|
|  | 339 | std::stringstream sstr; | 
|---|
|  | 340 | sstr << file << ":" << line; | 
|---|
|  | 341 | bool &ignore = ignores[sstr.str()]; | 
|---|
|  | 342 |  | 
|---|
|  | 343 | if(!ignore){ | 
|---|
| [506d2f] | 344 | bool res = dynamic_cast<target>(src)==static_cast<target>(src); | 
|---|
|  | 345 | if(!res && _my_assert::check("type-safe typecast",message_ptr,file,line,ignore)){ | 
|---|
| [13d5a9] | 346 | _my_assert::doHooks(); | 
|---|
|  | 347 | DEBUG_BREAK; | 
|---|
|  | 348 | } | 
|---|
|  | 349 | } | 
|---|
|  | 350 | return static_cast<target>(src); | 
|---|
|  | 351 | } | 
|---|
|  | 352 |  | 
|---|
|  | 353 | // Overloaded template for references | 
|---|
|  | 354 | template<typename target, typename source> | 
|---|
|  | 355 | target _convert(source &src){ | 
|---|
|  | 356 | std::stringstream sstr; | 
|---|
|  | 357 | sstr << file << ":" << line; | 
|---|
|  | 358 | bool &ignore = ignores[sstr.str()]; | 
|---|
|  | 359 |  | 
|---|
|  | 360 | try{ | 
|---|
|  | 361 | target res =dynamic_cast<target>(src); | 
|---|
|  | 362 | return res; | 
|---|
|  | 363 | } | 
|---|
|  | 364 | catch(...){ | 
|---|
|  | 365 | if(!ignore){ | 
|---|
| [506d2f] | 366 | if(_my_assert::check("type-safe typecast",message_ref,file,line,ignore)){ | 
|---|
| [13d5a9] | 367 | _my_assert::doHooks(); | 
|---|
|  | 368 | DEBUG_BREAK; | 
|---|
|  | 369 | } | 
|---|
|  | 370 | } | 
|---|
|  | 371 | } | 
|---|
|  | 372 | // The error was ignored. Just return whatever a static_cast would do | 
|---|
|  | 373 | return static_cast<target>(src); | 
|---|
|  | 374 | } | 
|---|
|  | 375 | private: | 
|---|
|  | 376 | int line; | 
|---|
|  | 377 | const char *file; | 
|---|
|  | 378 | static std::map<std::string,bool> ignores; | 
|---|
|  | 379 | // this avoids duplication of the strings when templates are instantiated | 
|---|
|  | 380 | static const char* message_ptr; | 
|---|
|  | 381 | static const char* message_ref; | 
|---|
|  | 382 | }; | 
|---|
|  | 383 | #endif | 
|---|
|  | 384 | //! @endcond | 
|---|
|  | 385 | } | 
|---|
|  | 386 |  | 
|---|
|  | 387 |  | 
|---|
| [229e3c] | 388 |  | 
|---|
|  | 389 |  | 
|---|
|  | 390 | #endif /* ASSERT_HPP_ */ | 
|---|