#ifndef CS_ASSERT_HELPERS_H_ #define CS_ASSERT_HELPERS_H_ #include namespace cs { extern "C" void CS_Fatal(const char* file, int line, const char* format, ...); // The FATAL, UNREACHABLE and UNIMPLEMENTED macros are useful during // development, but they should not be relied on in the final product. #ifndef NDEBUG #define FATAL(msg) \ CS_Fatal(__FILE__, __LINE__, "%s", (msg)) #define UNIMPLEMENTED() \ CS_Fatal(__FILE__, __LINE__, "unimplemented code") #define UNREACHABLE() \ CS_Fatal(__FILE__, __LINE__, "unreachable code") #else #define FATAL(msg) \ CS_Fatal("", 0, "%s", (msg)) #define UNIMPLEMENTED() \ CS_Fatal("", 0, "unimplemented code") #define UNREACHABLE() ((void) 0) #endif // Used by the ASSERT macro -- should not be called directly. static inline void AssertHelper(const char* file, int line, const char* source, bool condition) { if (!condition) CS_Fatal(file, line, "assert(%s) failed", source); } // Helper function used by the ASSERT_EQ function when given int // arguments. Should not be called directly. static inline void AssertEqualsHelper(const char* file, int line, const char* expected_source, int expected, const char* value_source, int value) { if (expected != value) { CS_Fatal(file, line, "ASSERT_EQ(%s, %s) failed\n# Expected: %i\n# Found: %i", expected_source, value_source, expected, value); } } // Helper function used by the ASSERT_EQ function when given int // arguments. Should not be called directly. static inline void AssertEqualsHelper(const char* file, int line, const char* expected_source, size_t expected, const char* value_source, size_t value) { if (expected != value) { CS_Fatal(file, line, "ASSERT_EQ(%s, %s) failed\n# Expected: %i\n# Found: %i", expected_source, value_source, expected, value); } } // Helper function used by the ASSERT_NE function when given int // arguments. Should not be called directly. static inline void AssertNonEqualsHelper(const char* file, int line, const char* unexpected_source, int unexpected, const char* value_source, int value) { if (unexpected == value) { CS_Fatal(file, line, "ASSERT_NE(%s, %s) failed\n# Value: %i", unexpected_source, value_source, value); } } // Helper function used by the ASSERT function when given string // arguments. Should not be called directly. static inline void AssertEqualsHelper(const char* file, int line, const char* expected_source, const char* expected, const char* value_source, const char* value) { if (strcmp(expected, value) != 0) { CS_Fatal(file, line, "ASSERT_EQ(%s, %s) failed\n# Expected: %s\n# Found: %s", expected_source, value_source, expected, value); } } static inline void AssertNonEqualsHelper(const char* file, int line, const char* expected_source, const char* expected, const char* value_source, const char* value) { if (expected == value || (expected != NULL && value != NULL && strcmp(expected, value) == 0)) { CS_Fatal(file, line, "ASSERT_NE(%s, %s) failed\n# Value: %s", expected_source, value_source, value); } } // Helper function used by the ASSERT function when given pointer // arguments. Should not be called directly. static inline void AssertEqualsHelper(const char* file, int line, const char* expected_source, void* expected, const char* value_source, void* value) { if (expected != value) { CS_Fatal(file, line, "ASSERT_EQ(%s, %s) failed\n# Expected: %p\n# Found: %p", expected_source, value_source, expected, value); } } static inline void AssertNonEqualsHelper(const char* file, int line, const char* expected_source, void* expected, const char* value_source, void* value) { if (expected == value) { CS_Fatal(file, line, "ASSERT_NE(%s, %s) failed\n# Value: %p", expected_source, value_source, value); } } // Helper function used by the ASSERT function when given floating // point arguments. Should not be called directly. static inline void AssertEqualsHelper(const char* file, int line, const char* expected_source, double expected, const char* value_source, double value) { // Force values to 64 bit memory to truncate 80 bit precision on IA32. volatile double* exp = new double[1]; *exp = expected; volatile double* val = new double[1]; *val = value; if (*exp != *val) { CS_Fatal(file, line, "ASSERT_EQ(%s, %s) failed\n# Expected: %f\n# Found: %f", expected_source, value_source, *exp, *val); } delete[] exp; delete[] val; } // Helper function used by the ASSERT function when given floating // point arguments. Should not be called directly. static inline void AssertNonEqualsHelper(const char* file, int line, const char* unexpected_source, double unexpected, const char* value_source, double value) { // Force values to 64 bit memory to truncate 80 bit precision on IA32. volatile double* exp = new double[1]; *exp = unexpected; volatile double* val = new double[1]; *val = value; if (*exp == *val) { CS_Fatal(file, line, "ASSERT_NE(%s, %s) failed\n# Value: %i", unexpected_source, value_source, value); } delete[] exp; delete[] val; } // The ASSERT macro only generates code in debug builds. #undef assert #ifndef NDEBUG #define assert_result(expr) AssertHelper(__FILE__, __LINE__, #expr, expr) #define assert(condition) AssertHelper(__FILE__, __LINE__, \ #condition, condition) #define assert_eq(v1, v2) AssertEqualsHelper(__FILE__, __LINE__, \ #v1, v1, #v2, v2) #define assert_ne(v1, v2) AssertNonEqualsHelper(__FILE__, __LINE__, \ #v1, v1, #v2, v2) #else #define assert_result(expr) (expr) #define assert(condition) ((void) 0) #define assert_eq(v1, v2) ((void) 0) #define assert_ne(v1, v2) ((void) 0) #endif } #endif // CS_ASSERT_HELPERS_H_