/** * \file src/core/include/megbrain/common.h * MegEngine is Licensed under the Apache License, Version 2.0 (the "License") * * Copyright (c) 2014-2020 Megvii Inc. All rights reserved. * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ #pragma once #include "megbrain_build_config.h" #include #include #include #include #include #include #include #include namespace mgb { /* ================ compiler related ================ */ //! comma to be used in macros for template arguments #define MGB_COMMA , //! branch prediction hint: likely to take #define mgb_likely(v) __builtin_expect(static_cast(v), 1) //! branch prediction hint: unlikely to take #define mgb_unlikely(v) __builtin_expect(static_cast(v), 0) //! mark a var to be used #define MGB_MARK_USED_VAR(var) static_cast(var) //! remove padding in a struct #define MGB_PACKED __attribute__((packed)) //! ask the compiler to not inline a function #define MGB_NOINLINE __attribute__((noinline)) //! warn if result of a function is not used #define MGB_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) #if __cplusplus >= 201703L || __clang_major__ >= 4 #define MGB_FALLTHRU [[fallthrough]]; #elif __GNUC__ >= 7 #define MGB_FALLTHRU __attribute__((fallthrough)); #else #define MGB_FALLTHRU #endif /* ================ exception and assertion ================ */ #ifndef mgb_trap #define mgb_trap() __builtin_trap() #endif #if MGB_ENABLE_EXCEPTION //! throw raw exception object #define mgb_throw_raw(_exc...) throw _exc //! try block #define MGB_TRY try //! catch block #define MGB_CATCH(_decl, _stmt) \ catch(_decl) _stmt #else #if MGB_ENABLE_LOGGING #define mgb_throw_raw(_exc...) ::mgb::__on_exception_throw__(_exc) void __on_exception_throw__(const std::exception &exc) __attribute__((noreturn)); #else #define mgb_throw_raw(_exc...) mgb_trap() #endif #define MGB_TRY #define MGB_CATCH(_decl, _stmt) #endif // MGB_ENABLE_EXCEPTION //! used after try-catch block, like try-finally construct in python #define MGB_FINALLY(_stmt) \ MGB_CATCH(..., {_stmt; throw; }) \ _stmt #if MGB_ENABLE_LOGGING //! throw exception with given message #define mgb_throw(_exc, _msg...) mgb_throw_raw(_exc(::mgb::ssprintf(_msg))) #else //! throw exception with given message #define mgb_throw(_exc, _msg...) mgb_throw_raw(_exc("")) #endif //! throw exception with given message if condition is true #define mgb_throw_if(_cond, _exc, _msg...) \ do { \ if (mgb_unlikely((_cond))) \ mgb_throw(_exc, _msg); \ } while(0) // assert #if MGB_ASSERT_LOC /*! * \brief extended assert * extra diagnostics message (in printf format) could be printed when assertion * fails; the asserted expression is guaranteed to be evaluated */ #define mgb_assert(expr, msg...) \ do { \ if (mgb_unlikely(!(expr))) \ ::mgb::__assert_fail__(__FILE__, __LINE__, \ __PRETTY_FUNCTION__, # expr, ##msg); \ } while(0) void __assert_fail__( const char *file, int line, const char *func, const char *expr, const char *msg_fmt = 0, ...) __attribute__((format(printf, 5, 6), noreturn)); #else #define mgb_assert(expr, msg...) \ do { \ if (mgb_unlikely(!(expr))) \ ::mgb::__assert_fail__(); \ } while(0) void __assert_fail__() __attribute__((noreturn)); #endif // MGB_ASSERT_LOC /* ================ logging ================ */ //! caused by need remve sensitive words at opt release #if MGB_ENABLE_LOGGING #define mgb_log_debug(fmt...) \ _mgb_do_log(::mgb::LogLevel::DEBUG, __FILE__, __func__, __LINE__, fmt) #define mgb_log(fmt...) \ _mgb_do_log(::mgb::LogLevel::INFO, __FILE__, __func__, __LINE__, fmt) #define mgb_log_warn(fmt...) \ _mgb_do_log(::mgb::LogLevel::WARN, __FILE__, __func__, __LINE__, fmt) #define mgb_log_error(fmt...) \ _mgb_do_log(::mgb::LogLevel::ERROR, __FILE__, __func__, __LINE__, fmt) #else #define mgb_log_debug(fmt...) \ _mgb_do_log(::mgb::LogLevel::DEBUG, "", "", 1, fmt) #define mgb_log(fmt...) \ _mgb_do_log(::mgb::LogLevel::INFO, "", "", 1, fmt) #define mgb_log_warn(fmt...) \ _mgb_do_log(::mgb::LogLevel::WARN, "", "", 1, fmt) #define mgb_log_error(fmt...) \ _mgb_do_log(::mgb::LogLevel::ERROR, "", "", 1, fmt) #endif enum class LogLevel { DEBUG, INFO, WARN, ERROR }; typedef void(*LogHandler)(LogLevel level, const char *file, const char *func, int line, const char *fmt, va_list ap); /*! * \brief set logging level * messages lower than given level would not be sent to log handler * * \return previous log level */ LogLevel set_log_level(LogLevel level); /*! * \brief set callback for receiving log requests * \return previous log handler */ LogHandler set_log_handler(LogHandler handler); #if MGB_ENABLE_LOGGING void __log__(LogLevel level, const char *file, const char *func, int line, const char *fmt, ...) __attribute__((format(printf, 5, 6))); #define _mgb_do_log ::mgb::__log__ //! make a string used for log #define mgb_ssprintf_log ::mgb::ssprintf //! v if log is enabled, and "" if not #define mgb_cstr_log(v) v #else #define _mgb_do_log(...) do{} while(0) #define mgb_ssprintf_log(...) ::std::string{} #define mgb_cstr_log(v) "" #endif // MGB_ENABLE_LOGGING /* ================ misc ================ */ #if MGB_ENABLE_GETENV #define MGB_GETENV ::std::getenv #else #define MGB_GETENV(_name) static_cast(nullptr) #endif #ifdef WIN32 #define unsetenv(_name) _putenv_s(_name, ""); #define setenv(name,value,overwrite) _putenv_s(name,value) #endif // use some macro tricks to get lock guard with unique variable name #define MGB_TOKENPASTE(x, y) x ## y #define MGB_TOKENPASTE2(x, y) MGB_TOKENPASTE(x, y) #define MGB_LOCK_GUARD_CTOR(mtx) MGB_TOKENPASTE2(__lock_guard_, __LINE__)(mtx) #define MGB_LOCK_GUARD(mtx) \ std::lock_guard MGB_LOCK_GUARD_CTOR(mtx) #define MGB_LOCK_GUARD_UNIQUE(mtx) \ std::unique_lock MGB_LOCK_GUARD_CTOR(mtx) #define MGB_LOCK_GUARD_SHARED(mtx) \ std::shared_lock MGB_LOCK_GUARD_CTOR(mtx) /*! * \brief printf-like std::string constructor */ std::string ssprintf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); std::string svsprintf(const char *fmt, va_list ap); #if 0 // used for win32 with vs prior to 2015 const char* convert_fmt_str(const char *fmt); static inline const char* operator "" _fmt(const char *fmt, std::size_t) { return convert_fmt_str(fmt); } #else static inline constexpr const char* convert_fmt_str(const char *fmt) { return fmt; } static inline constexpr const char* operator "" _fmt( const char *fmt, std::size_t) { return convert_fmt_str(fmt); } inline constexpr std::size_t operator"" _z(unsigned long long n) { return n; } #endif } // namespace mgb // vim: syntax=cpp.doxygen foldmethod=marker foldmarker=f{{{,f}}}