mirror of https://github.com/alibaba/MNN.git
				
				
				
			
		
			
				
	
	
		
			201 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			201 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C++
		
	
	
	
//
 | 
						|
//  logkit.h
 | 
						|
//  MNN
 | 
						|
//
 | 
						|
//  Created by MNN on 2019/01/31.
 | 
						|
//  Copyright © 2018, Alibaba Group Holding Limited
 | 
						|
//
 | 
						|
 | 
						|
#ifndef LOGKIT_H
 | 
						|
#define LOGKIT_H
 | 
						|
 | 
						|
#include <assert.h>
 | 
						|
#include <cstdio>
 | 
						|
#include <cstdlib>
 | 
						|
#include <ctime>
 | 
						|
#include <iostream>
 | 
						|
#include <sstream>
 | 
						|
#include <stdexcept>
 | 
						|
#include <string>
 | 
						|
 | 
						|
#if defined(_MSC_VER)
 | 
						|
#pragma warning(disable : 4722)
 | 
						|
#endif
 | 
						|
 | 
						|
class LogCheckError {
 | 
						|
public:
 | 
						|
    LogCheckError() : str(nullptr) {
 | 
						|
    }
 | 
						|
    explicit LogCheckError(const std::string& str_) : str(new std::string(str_)) {
 | 
						|
    }
 | 
						|
    ~LogCheckError() {
 | 
						|
        if (str != nullptr)
 | 
						|
            delete str;
 | 
						|
    }
 | 
						|
    operator bool() {
 | 
						|
        return str != nullptr;
 | 
						|
    }
 | 
						|
    std::string* str;
 | 
						|
};
 | 
						|
 | 
						|
#define DEFINE_CHECK_FUNC(name, op)                                                                                  \
 | 
						|
    template <typename X, typename Y>                                                                                \
 | 
						|
    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<int, int>(x, y);                                                                       \
 | 
						|
    }
 | 
						|
 | 
						|
#define CHECK_BINARY_OP(name, op, x, y)                  \
 | 
						|
    if (LogCheckError _check_err = LogCheck##name(x, y)) \
 | 
						|
    LogMessageFatal(__FILE__, __LINE__).stream() << "Check failed: " << #x " " #op " " #y << *(_check_err.str)
 | 
						|
 | 
						|
DEFINE_CHECK_FUNC(_LT, <)
 | 
						|
DEFINE_CHECK_FUNC(_GT, >)
 | 
						|
DEFINE_CHECK_FUNC(_LE, <=)
 | 
						|
DEFINE_CHECK_FUNC(_GE, >=)
 | 
						|
DEFINE_CHECK_FUNC(_EQ, ==)
 | 
						|
DEFINE_CHECK_FUNC(_NE, !=)
 | 
						|
 | 
						|
// Always-on checking
 | 
						|
#define CHECK(x) \
 | 
						|
    if (!(x))    \
 | 
						|
    LogMessageFatal(__FILE__, __LINE__).stream() << "Check failed: " #x << " ==> "
 | 
						|
#define CHECK_LT(x, y) CHECK_BINARY_OP(_LT, <, x, y)
 | 
						|
#define CHECK_GT(x, y) CHECK_BINARY_OP(_GT, >, x, y)
 | 
						|
#define CHECK_LE(x, y) CHECK_BINARY_OP(_LE, <=, x, y)
 | 
						|
#define CHECK_GE(x, y) CHECK_BINARY_OP(_GE, >=, x, y)
 | 
						|
#define CHECK_EQ(x, y) CHECK_BINARY_OP(_EQ, ==, x, y)
 | 
						|
#define CHECK_NE(x, y) CHECK_BINARY_OP(_NE, !=, x, y)
 | 
						|
#define CHECK_NOTNULL(x) \
 | 
						|
    ((x) == NULL ? LogMessageFatal(__FILE__, __LINE__).stream() << "Check  notnull: " #x << ' ', (x) : (x)) // NOLINT(*)
 | 
						|
 | 
						|
#define DCHECK(x) CHECK(x)
 | 
						|
#define DCHECK_LT(x, y) CHECK((x) < (y))
 | 
						|
#define DCHECK_GT(x, y) CHECK((x) > (y))
 | 
						|
#define DCHECK_LE(x, y) CHECK((x) <= (y))
 | 
						|
#define DCHECK_GE(x, y) CHECK((x) >= (y))
 | 
						|
#define DCHECK_EQ(x, y) CHECK((x) == (y))
 | 
						|
#define DCHECK_NE(x, y) CHECK((x) != (y))
 | 
						|
 | 
						|
#define LOG_INFO LogMessage(__FILE__, __LINE__)
 | 
						|
 | 
						|
#define LOG_ERROR LOG_FATAL
 | 
						|
#define LOG_WARNING LOG_INFO
 | 
						|
#define LOG_FATAL LogMessageFatal(__FILE__, __LINE__)
 | 
						|
#define LOG_QFATAL LOG_FATAL
 | 
						|
 | 
						|
// Poor man version of VLOG
 | 
						|
#define VLOG(x) LOG_INFO.stream()
 | 
						|
 | 
						|
#define LOG(severity) LOG_##severity.stream()
 | 
						|
#define LG LOG_INFO.stream()
 | 
						|
#define LOG_IF(severity, condition) !(condition) ? (void)0 : LogMessageVoidify() & LOG(severity)
 | 
						|
 | 
						|
#define LOG_DFATAL LOG_FATAL
 | 
						|
#define DFATAL FATAL
 | 
						|
#define DLOG(severity) LOG(severity)
 | 
						|
#define DLOG_IF(severity, condition) LOG_IF(severity, condition)
 | 
						|
 | 
						|
// Poor man version of LOG_EVERY_N
 | 
						|
#define LOG_EVERY_N(severity, n) LOG(severity)
 | 
						|
 | 
						|
class DateLogger {
 | 
						|
public:
 | 
						|
    DateLogger() {
 | 
						|
#if defined(_MSC_VER)
 | 
						|
        _tzset();
 | 
						|
#endif
 | 
						|
    }
 | 
						|
    const char* HumanDate() {
 | 
						|
#if defined(_MSC_VER)
 | 
						|
        _strtime_s(buffer_, sizeof(buffer_));
 | 
						|
#else
 | 
						|
        time_t time_value = time(NULL);
 | 
						|
        struct tm* pnow;
 | 
						|
#if !defined(_WIN32)
 | 
						|
        struct tm now;
 | 
						|
        pnow = localtime_r(&time_value, &now);
 | 
						|
#else
 | 
						|
        pnow = localtime(&time_value); // NOLINT(*)
 | 
						|
#endif
 | 
						|
        snprintf(buffer_, sizeof(buffer_), "%02d:%02d:%02d", pnow->tm_hour, pnow->tm_min, pnow->tm_sec);
 | 
						|
#endif
 | 
						|
        return buffer_;
 | 
						|
    }
 | 
						|
 | 
						|
private:
 | 
						|
    char buffer_[9];
 | 
						|
};
 | 
						|
 | 
						|
class LogMessage {
 | 
						|
public:
 | 
						|
    LogMessage(const char* file, int line) : log_stream_(std::cout) {
 | 
						|
#ifdef NDEBUG
 | 
						|
        log_stream_ << "[" << pretty_date_.HumanDate() << "] "
 | 
						|
                    << "@ " << line << ": ";
 | 
						|
#else
 | 
						|
        log_stream_ << "[" << pretty_date_.HumanDate() << "] " << file << ":" << line << ": ";
 | 
						|
#endif
 | 
						|
    }
 | 
						|
    ~LogMessage() {
 | 
						|
        log_stream_ << '\n';
 | 
						|
    }
 | 
						|
    std::ostream& stream() {
 | 
						|
        return log_stream_;
 | 
						|
    }
 | 
						|
 | 
						|
protected:
 | 
						|
    std::ostream& log_stream_;
 | 
						|
 | 
						|
private:
 | 
						|
    DateLogger pretty_date_;
 | 
						|
    LogMessage(const LogMessage&);
 | 
						|
    void operator=(const LogMessage&);
 | 
						|
};
 | 
						|
 | 
						|
class LogMessageFatal {
 | 
						|
public:
 | 
						|
    LogMessageFatal(const char* file, int line) {
 | 
						|
        log_stream_ << "[" << pretty_date_.HumanDate() << "] " << file << ":" << line << ": ";
 | 
						|
    }
 | 
						|
#if defined(_MSC_VER) && _MSC_VER < 1900
 | 
						|
    ~LogMessageFatal() {
 | 
						|
#else
 | 
						|
    ~LogMessageFatal() noexcept(false) {
 | 
						|
#endif
 | 
						|
        std::cout << log_stream_.str();
 | 
						|
        std::cout.flush();
 | 
						|
    }
 | 
						|
    std::ostringstream& stream() {
 | 
						|
        return log_stream_;
 | 
						|
    }
 | 
						|
 | 
						|
private:
 | 
						|
    std::ostringstream log_stream_;
 | 
						|
    DateLogger pretty_date_;
 | 
						|
    LogMessageFatal(const LogMessageFatal&);
 | 
						|
    void operator=(const LogMessageFatal&);
 | 
						|
};
 | 
						|
 | 
						|
// This class is used to explicitly ignore values in the conditional
 | 
						|
// logging macros.  This avoids compiler warnings like "value computed
 | 
						|
// is not used" and "statement has no effect".
 | 
						|
class LogMessageVoidify {
 | 
						|
public:
 | 
						|
    LogMessageVoidify() {
 | 
						|
    }
 | 
						|
    // This has to be an operator with a precedence lower than << but
 | 
						|
    // higher than "?:". See its usage.
 | 
						|
    void operator&(std::ostream&) {
 | 
						|
    }
 | 
						|
};
 | 
						|
 | 
						|
#endif // LOGKIT_H
 |