1 #ifndef CHECK_H_
2 #define CHECK_H_
3
4 #include <cmath>
5 #include <cstdlib>
6 #include <ostream>
7
8 #include "benchmark/export.h"
9 #include "internal_macros.h"
10 #include "log.h"
11
12 #if defined(__GNUC__) || defined(__clang__)
13 #define BENCHMARK_NOEXCEPT noexcept
14 #define BENCHMARK_NOEXCEPT_OP(x) noexcept(x)
15 #elif defined(_MSC_VER) && !defined(__clang__)
16 #if _MSC_VER >= 1900
17 #define BENCHMARK_NOEXCEPT noexcept
18 #define BENCHMARK_NOEXCEPT_OP(x) noexcept(x)
19 #else
20 #define BENCHMARK_NOEXCEPT
21 #define BENCHMARK_NOEXCEPT_OP(x)
22 #endif
23 #define __func__ __FUNCTION__
24 #else
25 #define BENCHMARK_NOEXCEPT
26 #define BENCHMARK_NOEXCEPT_OP(x)
27 #endif
28
29 namespace benchmark {
30 namespace internal {
31
32 typedef void(AbortHandlerT)();
33
34 BENCHMARK_EXPORT
35 AbortHandlerT*& GetAbortHandler();
36
CallAbortHandler()37 BENCHMARK_NORETURN inline void CallAbortHandler() {
38 GetAbortHandler()();
39 std::abort(); // fallback to enforce noreturn
40 }
41
42 // CheckHandler is the class constructed by failing BM_CHECK macros.
43 // CheckHandler will log information about the failures and abort when it is
44 // destructed.
45 class CheckHandler {
46 public:
CheckHandler(const char * check,const char * file,const char * func,int line)47 CheckHandler(const char* check, const char* file, const char* func, int line)
48 : log_(GetErrorLogInstance()) {
49 log_ << file << ":" << line << ": " << func << ": Check `" << check
50 << "' failed. ";
51 }
52
GetLog()53 LogType& GetLog() { return log_; }
54
55 #if defined(COMPILER_MSVC)
56 #pragma warning(push)
57 #pragma warning(disable : 4722)
58 #endif
~CheckHandler()59 BENCHMARK_NORETURN ~CheckHandler() BENCHMARK_NOEXCEPT_OP(false) {
60 log_ << std::endl;
61 CallAbortHandler();
62 }
63 #if defined(COMPILER_MSVC)
64 #pragma warning(pop)
65 #endif
66
67 CheckHandler& operator=(const CheckHandler&) = delete;
68 CheckHandler(const CheckHandler&) = delete;
69 CheckHandler() = delete;
70
71 private:
72 LogType& log_;
73 };
74
75 } // end namespace internal
76 } // end namespace benchmark
77
78 // The BM_CHECK macro returns a std::ostream object that can have extra
79 // information written to it.
80 #ifndef NDEBUG
81 #define BM_CHECK(b) \
82 (b ? ::benchmark::internal::GetNullLogInstance() \
83 : ::benchmark::internal::CheckHandler(#b, __FILE__, __func__, __LINE__) \
84 .GetLog())
85 #else
86 #define BM_CHECK(b) ::benchmark::internal::GetNullLogInstance()
87 #endif
88
89 // clang-format off
90 // preserve whitespacing between operators for alignment
91 #define BM_CHECK_EQ(a, b) BM_CHECK((a) == (b))
92 #define BM_CHECK_NE(a, b) BM_CHECK((a) != (b))
93 #define BM_CHECK_GE(a, b) BM_CHECK((a) >= (b))
94 #define BM_CHECK_LE(a, b) BM_CHECK((a) <= (b))
95 #define BM_CHECK_GT(a, b) BM_CHECK((a) > (b))
96 #define BM_CHECK_LT(a, b) BM_CHECK((a) < (b))
97
98 #define BM_CHECK_FLOAT_EQ(a, b, eps) BM_CHECK(std::fabs((a) - (b)) < (eps))
99 #define BM_CHECK_FLOAT_NE(a, b, eps) BM_CHECK(std::fabs((a) - (b)) >= (eps))
100 #define BM_CHECK_FLOAT_GE(a, b, eps) BM_CHECK((a) - (b) > -(eps))
101 #define BM_CHECK_FLOAT_LE(a, b, eps) BM_CHECK((b) - (a) > -(eps))
102 #define BM_CHECK_FLOAT_GT(a, b, eps) BM_CHECK((a) - (b) > (eps))
103 #define BM_CHECK_FLOAT_LT(a, b, eps) BM_CHECK((b) - (a) > (eps))
104 //clang-format on
105
106 #endif // CHECK_H_
107