diff --git a/include/dmlc/base.h b/include/dmlc/base.h index 8b5c7f8816..05278287e7 100644 --- a/include/dmlc/base.h +++ b/include/dmlc/base.h @@ -242,6 +242,14 @@ typedef unsigned __int64 uint64_t; #define DMLC_NO_INLINE __attribute__((noinline)) #endif +#if defined(__GNUC__) || defined(__clang__) +#define DMLC_ALWAYS_INLINE inline __attribute__((__always_inline__)) +#elif defined(_MSC_VER) +#define DMLC_ALWAYS_INLINE __forceinline +#else +#define DMLC_ALWAYS_INLINE inline +#endif + #if DMLC_USE_CXX11 #define DMLC_THROW_EXCEPTION noexcept(false) #define DMLC_NO_EXCEPTION noexcept(true) diff --git a/include/dmlc/logging.h b/include/dmlc/logging.h index fbdf7f14fe..86a13d4b7b 100644 --- a/include/dmlc/logging.h +++ b/include/dmlc/logging.h @@ -162,51 +162,19 @@ inline bool DebugLoggingEnabled() { return state == 1; } -class LogCheckError { - public: - LogCheckError() : str(nullptr) {} - explicit LogCheckError(const std::string& str_) : str(new std::string(str_)) {} - LogCheckError(const LogCheckError& other) = delete; - LogCheckError(LogCheckError&& other) : str(other.str) { - other.str = nullptr; - } - ~LogCheckError() { if (str != nullptr) delete str; } - operator bool() const { return str != nullptr; } - LogCheckError& operator=(const LogCheckError& other) = delete; - LogCheckError& operator=(LogCheckError&& other) = delete; - std::string* str; -}; - #ifndef DMLC_GLOG_DEFINED -#ifndef _LIBCPP_SGX_NO_IOSTREAMS -#define DEFINE_CHECK_FUNC(name, op) \ - template \ - inline LogCheckError LogCheck##name(const X& x, const Y& y) { \ - if (x op y) return LogCheckError(); \ - std::ostringstream os; \ - os << " (" << x << " vs. " << y << ") "; /* CHECK_XX(x, y) requires x and y can be serialized to string. Use CHECK(x OP y) otherwise. NOLINT(*) */ \ - return LogCheckError(os.str()); \ - } \ - inline LogCheckError LogCheck##name(int x, int y) { \ - return LogCheck##name(x, y); \ +// This function allows us to ignore sign comparison in the right scope. +// Once dmlc requires c++11, #pragma can be changed to _Pramga, and directives +// can be moved to CHECK_BINARY_OP definition itself +#define DEFINE_CHECK_FUNC(name, op) \ + template \ + DMLC_ALWAYS_INLINE bool LogCheck##name(const X& x, const Y& y) { \ + return (x op y); \ + } \ + DMLC_ALWAYS_INLINE bool LogCheck##name(int x, int y) { \ + return LogCheck##name(x, y); \ } -#else -#define DEFINE_CHECK_FUNC(name, op) \ - template \ - inline LogCheckError LogCheck##name(const X& x, const Y& y) { \ - if (x op y) return LogCheckError(); \ - return LogCheckError("Error."); \ - } \ - inline LogCheckError LogCheck##name(int x, int y) { \ - return LogCheck##name(x, y); \ - } -#endif - -#define CHECK_BINARY_OP(name, op, x, y) \ - if (dmlc::LogCheckError _check_err = dmlc::LogCheck##name(x, y)) \ - dmlc::LogMessageFatal(__FILE__, __LINE__).stream() \ - << "Check failed: " << #x " " #op " " #y << *(_check_err.str) << ": " #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wsign-compare" @@ -218,6 +186,11 @@ DEFINE_CHECK_FUNC(_EQ, ==) DEFINE_CHECK_FUNC(_NE, !=) #pragma GCC diagnostic pop +#define CHECK_BINARY_OP(name, op, x, y) \ + if (!(dmlc::LogCheck##name(x, y))) \ + dmlc::LogMessageFatal(__FILE__, __LINE__).stream() \ + << "Check failed: " << #x " " #op " " #y << " (" << x << " vs. " << y << ") " << ": " /* CHECK_XX(x, y) requires x and y can be serialized to string. Use CHECK(x OP y) otherwise. NOLINT(*) */ + // Always-on checking #define CHECK(x) \ if (!(x)) \ diff --git a/test/unittest/unittest_logging.cc b/test/unittest/unittest_logging.cc index 2f600cafd9..a39ea9c130 100644 --- a/test/unittest/unittest_logging.cc +++ b/test/unittest/unittest_logging.cc @@ -18,6 +18,14 @@ TEST(Logging, basics) { EXPECT_THROW(CHECK_NE(x, y), dmlc::Error); } +TEST(Logging, signed_compare) { + int32_t x = 1; + uint32_t y = 2; + CHECK_GT(y, x); + + EXPECT_THROW(CHECK_EQ(x, y), dmlc::Error); +} + TEST(Logging, throw_fatal) { EXPECT_THROW({ LOG(FATAL) << "message";