// ====================================================================== // == DO NOT MODIFY THIS FILE BY HAND - IT IS AUTO GENERATED BY CMAKE! == // ====================================================================== #pragma once #define ZEROERR_VERSION_MAJOR 0 #define ZEROERR_VERSION_MINOR 3 #define ZEROERR_VERSION_PATCH 0 #define ZEROERR_VERSION \ (ZEROERR_VERSION_MAJOR * 10000 + ZEROERR_VERSION_MINOR * 100 + ZEROERR_VERSION_PATCH) #define ZEROERR_STR(x) #x #define ZEROERR_VERSION_STR_BUILDER(a, b, c) ZEROERR_STR(a) "." ZEROERR_STR(b) "." ZEROERR_STR(c) #define ZEROERR_VERSION_STR \ ZEROERR_VERSION_STR_BUILDER(ZEROERR_VERSION_MAJOR, ZEROERR_VERSION_MINOR, ZEROERR_VERSION_PATCH) // If you just wish to use the color without dynamic // enable or disable it, you can uncomment the following line // #define ZEROERR_ALWAYS_COLORFUL // #define ZEROERR_DISABLE_COLORFUL // If you wish to use the whole library without thread safety, uncomment the following line // #define ZEROERR_NO_THREAD_SAFE // If you wish to disable auto initialization of the system // #define ZEROERR_DISABLE_AUTO_INIT // If you didn't wish override operator<< for ostream, we can disable it // #define ZEROERR_DISABLE_OSTREAM_OVERRIDE // If you wish to disable AND, OR macro // #define ZEROERR_DISABLE_COMPLEX_AND_OR // If you wish ot disable BDD style macros // #define ZEROERR_DISABLE_BDD // Detect C++ standard with a cross-platform way #ifdef _MSC_VER #define ZEROERR_CPLUSPLUS _MSVC_LANG #else #define ZEROERR_CPLUSPLUS __cplusplus #endif #if ZEROERR_CPLUSPLUS >= 202300L #define ZEROERR_CXX_STANDARD 23 #elif ZEROERR_CPLUSPLUS >= 202002L #define ZEROERR_CXX_STANDARD 20 #elif ZEROERR_CPLUSPLUS >= 201703L #define ZEROERR_CXX_STANDARD 17 #elif ZEROERR_CPLUSPLUS >= 201402L #define ZEROERR_CXX_STANDARD 14 #elif ZEROERR_CPLUSPLUS >= 201103L #define ZEROERR_CXX_STANDARD 11 #else #error "Unsupported C++ standard detected. ZeroErr requires C++11 or later." #endif #if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) #define ZEROERR_OS_UNIX #if defined(__linux__) #define ZEROERR_OS_LINUX #endif #elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32) #define ZEROERR_OS_WINDOWS #else #define ZEROERR_OS_UNKNOWN #endif #if defined(NDEBUG) && !defined(ZEROERR_ALWAYS_ASSERT) // FIXME: we should safely remove the assert in IF statement // #define ZEROERR_NO_ASSERT #endif // This is used for generating a unique name based on the file name and line number #define ZEROERR_CAT_IMPL(s1, s2) s1##s2 #define ZEROERR_CAT(x, s) ZEROERR_CAT_IMPL(x, s) // The following macros are used to check the arguments is empty or not // from: https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/ #define ZEROERR_ARG16(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, ...) _15 #define ZEROERR_HAS_COMMA(...) \ ZEROERR_ARG16(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0) #define ZEROERR_TRIGGER_PARENTHESIS_(...) , #define ZEROERR_ISEMPTY(...) \ _ZEROERR_ISEMPTY(/* test if there is just one argument, eventually an empty \ one */ \ ZEROERR_HAS_COMMA(__VA_ARGS__), /* test if ZEROERR_TRIGGER_PARENTHESIS_ \ together with the argument adds a comma */ \ ZEROERR_HAS_COMMA(ZEROERR_TRIGGER_PARENTHESIS_ \ __VA_ARGS__), /* test if the argument together with \ a parenthesis adds a comma */ \ ZEROERR_HAS_COMMA(__VA_ARGS__( \ /*empty*/)), /* test if placing it between ZEROERR_TRIGGER_PARENTHESIS_ \ and the parenthesis adds a comma */ \ ZEROERR_HAS_COMMA(ZEROERR_TRIGGER_PARENTHESIS_ __VA_ARGS__(/*empty*/))) #define ZEROERR_PASTE5(_0, _1, _2, _3, _4) _0##_1##_2##_3##_4 #define _ZEROERR_ISEMPTY(_0, _1, _2, _3) \ ZEROERR_HAS_COMMA(ZEROERR_PASTE5(_IS_EMPTY_CASE_, _0, _1, _2, _3)) #define _IS_EMPTY_CASE_0001 , // The counter is used to generate a unique name #ifdef __COUNTER__ #define ZEROERR_NAMEGEN(x) ZEROERR_CAT(x, __COUNTER__) #else // __COUNTER__ #define ZEROERR_NAMEGEN(x) ZEROERR_CAT(x, __LINE__) #endif // __COUNTER__ #ifdef ZEROERR_OS_LINUX #define ZEROERR_PERF #endif #ifdef ZEROERR_DISABLE_ASSERTS_RETURN_VALUES #define ZEROERR_FUNC_SCOPE_BEGIN do #define ZEROERR_FUNC_SCOPE_END while (0) #define ZEROERR_FUNC_SCOPE_RET(v) (void)0 #else #define ZEROERR_FUNC_SCOPE_BEGIN [&] #define ZEROERR_FUNC_SCOPE_END () #define ZEROERR_FUNC_SCOPE_RET(v) return v #endif #ifndef ZEROERR_NO_SHORT_LOG_MACRO #define ZEROERR_USE_SHORT_LOG_MACRO #endif #define ZEROERR_EXPAND(x) x // ================================================================================================= // == COMPILER Detector ============================================================================ // ================================================================================================= #define ZEROERR_COMPILER(MAJOR, MINOR, PATCH) ((MAJOR) * 10000000 + (MINOR) * 100000 + (PATCH)) // GCC/Clang and GCC/MSVC are mutually exclusive, but Clang/MSVC are not because of clang-cl... #if defined(_MSC_VER) && defined(_MSC_FULL_VER) #if _MSC_VER == _MSC_FULL_VER / 10000 #define ZEROERR_MSVC ZEROERR_COMPILER(_MSC_VER / 100, _MSC_VER % 100, _MSC_FULL_VER % 10000) #else // MSVC #define ZEROERR_MSVC \ ZEROERR_COMPILER(_MSC_VER / 100, (_MSC_FULL_VER / 100000) % 100, _MSC_FULL_VER % 100000) #endif // MSVC #endif // MSVC #if defined(__clang__) && defined(__clang_minor__) && defined(__clang_patchlevel__) #define ZEROERR_CLANG ZEROERR_COMPILER(__clang_major__, __clang_minor__, __clang_patchlevel__) #elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) && \ !defined(__INTEL_COMPILER) #define ZEROERR_GCC ZEROERR_COMPILER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) #endif // GCC #if defined(__INTEL_COMPILER) #define ZEROERR_ICC ZEROERR_COMPILER(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0) #endif // ICC #ifndef ZEROERR_MSVC #define ZEROERR_MSVC 0 #endif // ZEROERR_MSVC #ifndef ZEROERR_CLANG #define ZEROERR_CLANG 0 #endif // ZEROERR_CLANG #ifndef ZEROERR_GCC #define ZEROERR_GCC 0 #endif // ZEROERR_GCC #ifndef ZEROERR_ICC #define ZEROERR_ICC 0 #endif // ZEROERR_ICC // ================================================================================================= // == COMPILER WARNINGS HELPERS ==================================================================== // ================================================================================================= #if ZEROERR_CLANG && !ZEROERR_ICC #define ZEROERR_PRAGMA_TO_STR(x) _Pragma(#x) #define ZEROERR_CLANG_SUPPRESS_WARNING_PUSH _Pragma("clang diagnostic push") #define ZEROERR_CLANG_SUPPRESS_WARNING(w) ZEROERR_PRAGMA_TO_STR(clang diagnostic ignored w) #define ZEROERR_CLANG_SUPPRESS_WARNING_POP _Pragma("clang diagnostic pop") #define ZEROERR_CLANG_SUPPRESS_WARNING_WITH_PUSH(w) \ ZEROERR_CLANG_SUPPRESS_WARNING_PUSH ZEROERR_CLANG_SUPPRESS_WARNING(w) #else // ZEROERR_CLANG #define ZEROERR_CLANG_SUPPRESS_WARNING_PUSH #define ZEROERR_CLANG_SUPPRESS_WARNING(w) #define ZEROERR_CLANG_SUPPRESS_WARNING_POP #define ZEROERR_CLANG_SUPPRESS_WARNING_WITH_PUSH(w) #endif // ZEROERR_CLANG #if ZEROERR_GCC #define ZEROERR_PRAGMA_TO_STR(x) _Pragma(#x) #define ZEROERR_GCC_SUPPRESS_WARNING_PUSH _Pragma("GCC diagnostic push") #define ZEROERR_GCC_SUPPRESS_WARNING(w) ZEROERR_PRAGMA_TO_STR(GCC diagnostic ignored w) #define ZEROERR_GCC_SUPPRESS_WARNING_POP _Pragma("GCC diagnostic pop") #define ZEROERR_GCC_SUPPRESS_WARNING_WITH_PUSH(w) \ ZEROERR_GCC_SUPPRESS_WARNING_PUSH ZEROERR_GCC_SUPPRESS_WARNING(w) #else // ZEROERR_GCC #define ZEROERR_GCC_SUPPRESS_WARNING_PUSH #define ZEROERR_GCC_SUPPRESS_WARNING(w) #define ZEROERR_GCC_SUPPRESS_WARNING_POP #define ZEROERR_GCC_SUPPRESS_WARNING_WITH_PUSH(w) #endif // ZEROERR_GCC #if ZEROERR_MSVC #define ZEROERR_MSVC_SUPPRESS_WARNING_PUSH __pragma(warning(push)) #define ZEROERR_MSVC_SUPPRESS_WARNING(w) __pragma(warning(disable : w)) #define ZEROERR_MSVC_SUPPRESS_WARNING_POP __pragma(warning(pop)) #define ZEROERR_MSVC_SUPPRESS_WARNING_WITH_PUSH(w) \ ZEROERR_MSVC_SUPPRESS_WARNING_PUSH ZEROERR_MSVC_SUPPRESS_WARNING(w) #else // ZEROERR_MSVC #define ZEROERR_MSVC_SUPPRESS_WARNING_PUSH #define ZEROERR_MSVC_SUPPRESS_WARNING(w) #define ZEROERR_MSVC_SUPPRESS_WARNING_POP #define ZEROERR_MSVC_SUPPRESS_WARNING_WITH_PUSH(w) #endif // ZEROERR_MSVC // ================================================================================================= // == COMPILER WARNINGS ============================================================================ // ================================================================================================= // both the header and the implementation suppress all of these, // so it only makes sense to aggregate them like so #define ZEROERR_SUPPRESS_COMMON_WARNINGS_PUSH \ ZEROERR_CLANG_SUPPRESS_WARNING_PUSH \ ZEROERR_CLANG_SUPPRESS_WARNING("-Wunknown-pragmas") \ ZEROERR_CLANG_SUPPRESS_WARNING("-Wweak-vtables") \ ZEROERR_CLANG_SUPPRESS_WARNING("-Wpadded") \ ZEROERR_CLANG_SUPPRESS_WARNING("-Wmissing-prototypes") \ ZEROERR_CLANG_SUPPRESS_WARNING("-Wc++98-compat") \ ZEROERR_CLANG_SUPPRESS_WARNING("-Wc++98-compat-pedantic") \ \ ZEROERR_GCC_SUPPRESS_WARNING_PUSH \ ZEROERR_GCC_SUPPRESS_WARNING("-Wunknown-pragmas") \ ZEROERR_GCC_SUPPRESS_WARNING("-Wpragmas") \ ZEROERR_GCC_SUPPRESS_WARNING("-Weffc++") \ ZEROERR_GCC_SUPPRESS_WARNING("-Wstrict-overflow") \ ZEROERR_GCC_SUPPRESS_WARNING("-Wstrict-aliasing") \ ZEROERR_GCC_SUPPRESS_WARNING("-Wmissing-declarations") \ ZEROERR_GCC_SUPPRESS_WARNING("-Wuseless-cast") \ ZEROERR_GCC_SUPPRESS_WARNING("-Wnoexcept") \ \ ZEROERR_MSVC_SUPPRESS_WARNING_PUSH \ /* these 4 also disabled globally via cmake: */ \ ZEROERR_MSVC_SUPPRESS_WARNING(4514) /* unreferenced inline function has been removed */ \ ZEROERR_MSVC_SUPPRESS_WARNING(4571) /* SEH related */ \ ZEROERR_MSVC_SUPPRESS_WARNING(4710) /* function not inlined */ \ ZEROERR_MSVC_SUPPRESS_WARNING(4711) /* function selected for inline expansion*/ \ /* common ones */ \ ZEROERR_MSVC_SUPPRESS_WARNING(4616) /* invalid compiler warning */ \ ZEROERR_MSVC_SUPPRESS_WARNING(4619) /* invalid compiler warning */ \ ZEROERR_MSVC_SUPPRESS_WARNING(4996) /* The compiler encountered a deprecated declaration */ \ ZEROERR_MSVC_SUPPRESS_WARNING(4706) /* assignment within conditional expression */ \ ZEROERR_MSVC_SUPPRESS_WARNING(4512) /* 'class' : assignment operator could not be generated */ \ ZEROERR_MSVC_SUPPRESS_WARNING(4127) /* conditional expression is constant */ \ ZEROERR_MSVC_SUPPRESS_WARNING(4820) /* padding */ \ ZEROERR_MSVC_SUPPRESS_WARNING(4625) /* copy constructor was implicitly deleted */ \ ZEROERR_MSVC_SUPPRESS_WARNING(4626) /* assignment operator was implicitly deleted */ \ ZEROERR_MSVC_SUPPRESS_WARNING(5027) /* move assignment operator implicitly deleted */ \ ZEROERR_MSVC_SUPPRESS_WARNING(5026) /* move constructor was implicitly deleted */ \ ZEROERR_MSVC_SUPPRESS_WARNING(4640) /* construction of local static object not thread-safe */ \ ZEROERR_MSVC_SUPPRESS_WARNING(5045) /* Spectre mitigation for memory load */ \ ZEROERR_MSVC_SUPPRESS_WARNING(5264) /* 'variable-name': 'const' variable is not used */ \ /* static analysis */ \ ZEROERR_MSVC_SUPPRESS_WARNING(26439) /* Function may not throw. Declare it 'noexcept' */ \ ZEROERR_MSVC_SUPPRESS_WARNING(26495) /* Always initialize a member variable */ \ ZEROERR_MSVC_SUPPRESS_WARNING(26451) /* Arithmetic overflow ... */ \ ZEROERR_MSVC_SUPPRESS_WARNING(26444) /* Avoid unnamed objects with custom ctor and dtor... */ \ ZEROERR_MSVC_SUPPRESS_WARNING(26812) /* Prefer 'enum class' over 'enum' */ #define ZEROERR_SUPPRESS_COMMON_WARNINGS_POP \ ZEROERR_CLANG_SUPPRESS_WARNING_POP \ ZEROERR_GCC_SUPPRESS_WARNING_POP \ ZEROERR_MSVC_SUPPRESS_WARNING_POP #define ZEROERR_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_BEGIN \ ZEROERR_MSVC_SUPPRESS_WARNING_PUSH \ ZEROERR_MSVC_SUPPRESS_WARNING(4548) /* before comma no effect; expected side - effect */ \ ZEROERR_MSVC_SUPPRESS_WARNING(4265) /* virtual functions, but destructor is not virtual */ \ ZEROERR_MSVC_SUPPRESS_WARNING(4986) /* exception specification does not match previous */ \ ZEROERR_MSVC_SUPPRESS_WARNING(4350) /* 'member1' called instead of 'member2' */ \ ZEROERR_MSVC_SUPPRESS_WARNING(4668) /* not defined as a preprocessor macro */ \ ZEROERR_MSVC_SUPPRESS_WARNING(4365) /* signed/unsigned mismatch */ \ ZEROERR_MSVC_SUPPRESS_WARNING(4774) /* format string not a string literal */ \ ZEROERR_MSVC_SUPPRESS_WARNING(4820) /* padding */ \ ZEROERR_MSVC_SUPPRESS_WARNING(4625) /* copy constructor was implicitly deleted */ \ ZEROERR_MSVC_SUPPRESS_WARNING(4626) /* assignment operator was implicitly deleted */ \ ZEROERR_MSVC_SUPPRESS_WARNING(5027) /* move assignment operator implicitly deleted */ \ ZEROERR_MSVC_SUPPRESS_WARNING(5026) /* move constructor was implicitly deleted */ \ ZEROERR_MSVC_SUPPRESS_WARNING(4623) /* default constructor was implicitly deleted */ \ ZEROERR_MSVC_SUPPRESS_WARNING(5039) /* pointer to pot. throwing function passed to extern C */ \ ZEROERR_MSVC_SUPPRESS_WARNING(5045) /* Spectre mitigation for memory load */ \ ZEROERR_MSVC_SUPPRESS_WARNING(5105) /* macro producing 'defined' has undefined behavior */ \ ZEROERR_MSVC_SUPPRESS_WARNING(4738) /* storing float result in memory, loss of performance */ \ ZEROERR_MSVC_SUPPRESS_WARNING(5262) /* implicit fall-through */ #define ZEROERR_MAKE_STD_HEADERS_CLEAN_FROM_WARNINGS_ON_WALL_END ZEROERR_MSVC_SUPPRESS_WARNING_POP #define ZEROERR_SUPPRESS_VARIADIC_MACRO \ ZEROERR_CLANG_SUPPRESS_WARNING_WITH_PUSH("-Wgnu-zero-variadic-macro-arguments") #define ZEROERR_SUPPRESS_VARIADIC_MACRO_POP ZEROERR_CLANG_SUPPRESS_WARNING_POP #define ZEROERR_SUPPRESS_COMPARE \ ZEROERR_CLANG_SUPPRESS_WARNING_PUSH \ ZEROERR_CLANG_SUPPRESS_WARNING("-Wsign-conversion") \ ZEROERR_CLANG_SUPPRESS_WARNING("-Wsign-compare") \ ZEROERR_CLANG_SUPPRESS_WARNING("-Wgnu-zero-variadic-macro-arguments") \ ZEROERR_GCC_SUPPRESS_WARNING_PUSH \ ZEROERR_GCC_SUPPRESS_WARNING("-Wsign-conversion") \ ZEROERR_GCC_SUPPRESS_WARNING("-Wsign-compare") \ ZEROERR_MSVC_SUPPRESS_WARNING_PUSH \ ZEROERR_MSVC_SUPPRESS_WARNING(4388) \ ZEROERR_MSVC_SUPPRESS_WARNING(4389) \ ZEROERR_MSVC_SUPPRESS_WARNING(4018) #define ZEROERR_SUPPRESS_COMPARE_POP \ ZEROERR_CLANG_SUPPRESS_WARNING_POP ZEROERR_GCC_SUPPRESS_WARNING_POP \ ZEROERR_MSVC_SUPPRESS_WARNING_POP /** * Macro to suppress unused variable/parameter warnings * * This macro can be used to mark variables or parameters as intentionally unused * while maintaining cross-compiler compatibility. It handles different compiler-specific * attributes and warning suppressions: * * - For Clang/GCC: Uses __attribute__((unused)) * - For LCLINT: Uses @unused@ comment annotation * - For MSVC: Suppresses warning C4100 (unreferenced formal parameter) * - For other compilers: No special handling * * Usage example: * void foo(ZEROERR_UNUSED(int x)) { * // x is marked as intentionally unused * } */ #if ZEROERR_CLANG || ZEROERR_GCC #define ZEROERR_UNUSED(x) x __attribute__((unused)) #elif defined(__LCLINT__) #define ZEROERR_UNUSED(x) /*@unused@*/ x #elif ZEROERR_MSVC #define ZEROERR_UNUSED(x) \ ZEROERR_MSVC_SUPPRESS_WARNING_WITH_PUSH(4100) x ZEROERR_MSVC_SUPPRESS_WARNING_POP #else #define ZEROERR_UNUSED(x) x #endif #pragma once namespace zeroerr { #ifdef ZEROERR_ALWAYS_COLORFUL constexpr const char* Reset = "\x1b[0m"; constexpr const char* Bright = "\x1b[1m"; constexpr const char* Dim = "\x1b[2m"; constexpr const char* Underscore = "\x1b[4m"; constexpr const char* Blink = "\x1b[5m"; constexpr const char* Reverse = "\x1b[7m"; constexpr const char* Hidden = "\x1b[8m"; constexpr const char* FgBlack = "\x1b[30m"; constexpr const char* FgRed = "\x1b[31m"; constexpr const char* FgGreen = "\x1b[32m"; constexpr const char* FgYellow = "\x1b[33m"; constexpr const char* FgBlue = "\x1b[34m"; constexpr const char* FgMagenta = "\x1b[35m"; constexpr const char* FgCyan = "\x1b[36m"; constexpr const char* FgWhite = "\x1b[37m"; constexpr const char* BgBlack = "\x1b[40m"; constexpr const char* BgRed = "\x1b[41m"; constexpr const char* BgGreen = "\x1b[42m"; constexpr const char* BgYellow = "\x1b[43m"; constexpr const char* BgBlue = "\x1b[44m"; constexpr const char* BgMagenta = "\x1b[45m"; constexpr const char* BgCyan = "\x1b[46m"; constexpr const char* BgWhite = "\x1b[47m"; #elif defined(ZEROERR_DISABLE_COLORFUL) constexpr const char* Reset = ""; constexpr const char* Bright = ""; constexpr const char* Dim = ""; constexpr const char* Underscore = ""; constexpr const char* Blink = ""; constexpr const char* Reverse = ""; constexpr const char* Hidden = ""; constexpr const char* FgBlack = ""; constexpr const char* FgRed = ""; constexpr const char* FgGreen = ""; constexpr const char* FgYellow = ""; constexpr const char* FgBlue = ""; constexpr const char* FgMagenta = ""; constexpr const char* FgCyan = ""; constexpr const char* FgWhite = ""; constexpr const char* BgBlack = ""; constexpr const char* BgRed = ""; constexpr const char* BgGreen = ""; constexpr const char* BgYellow = ""; constexpr const char* BgBlue = ""; constexpr const char* BgMagenta = ""; constexpr const char* BgCyan = ""; constexpr const char* BgWhite = ""; #else extern const char* Reset; extern const char* Bright; extern const char* Dim; extern const char* Underscore; extern const char* Blink; extern const char* Reverse; extern const char* Hidden; extern const char* FgBlack; extern const char* FgRed; extern const char* FgGreen; extern const char* FgYellow; extern const char* FgBlue; extern const char* FgMagenta; extern const char* FgCyan; extern const char* FgWhite; extern const char* BgBlack; extern const char* BgRed; extern const char* BgGreen; extern const char* BgYellow; extern const char* BgBlue; extern const char* BgMagenta; extern const char* BgCyan; extern const char* BgWhite; /** * @brief Global function to disable colorful output. */ extern void disableColorOutput(); /** * @brief Global function to enable colorful output. */ extern void enableColorOutput(); #endif } // namespace zeroerr #pragma once namespace zeroerr { enum OutputStream { STDOUT, STDERR }; extern bool isTerminalOutput(OutputStream stream); struct TerminalSize { int width; int height; }; TerminalSize getTerminalSize(); } // namespace zeroerr /* Copyright (c) 2011-2021, Scott Tsai * * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #ifndef DEBUG_BREAK_H #define DEBUG_BREAK_H #ifdef _MSC_VER #define debug_break __debugbreak #else #ifdef __cplusplus extern "C" { #endif #define DEBUG_BREAK_USE_TRAP_INSTRUCTION 1 #define DEBUG_BREAK_USE_BULTIN_TRAP 2 #define DEBUG_BREAK_USE_SIGTRAP 3 #if defined(__i386__) || defined(__x86_64__) #define DEBUG_BREAK_IMPL DEBUG_BREAK_USE_TRAP_INSTRUCTION __inline__ static void trap_instruction(void) { __asm__ volatile("int $0x03"); } #elif defined(__thumb__) #define DEBUG_BREAK_IMPL DEBUG_BREAK_USE_TRAP_INSTRUCTION /* FIXME: handle __THUMB_INTERWORK__ */ __attribute__((always_inline)) __inline__ static void trap_instruction(void) { /* See 'arm-linux-tdep.c' in GDB source. * Both instruction sequences below work. */ #if 1 /* 'eabi_linux_thumb_le_breakpoint' */ __asm__ volatile(".inst 0xde01"); #else /* 'eabi_linux_thumb2_le_breakpoint' */ __asm__ volatile(".inst.w 0xf7f0a000"); #endif /* Known problem: * After a breakpoint hit, can't 'stepi', 'step', or 'continue' in GDB. * 'step' would keep getting stuck on the same instruction. * * Workaround: use the new GDB commands 'debugbreak-step' and * 'debugbreak-continue' that become available * after you source the script from GDB: * * $ gdb -x debugbreak-gdb.py <... USUAL ARGUMENTS ...> * * 'debugbreak-step' would jump over the breakpoint instruction with * roughly equivalent of: * (gdb) set $instruction_len = 2 * (gdb) tbreak *($pc + $instruction_len) * (gdb) jump *($pc + $instruction_len) */ } #elif defined(__arm__) && !defined(__thumb__) #define DEBUG_BREAK_IMPL DEBUG_BREAK_USE_TRAP_INSTRUCTION __attribute__((always_inline)) __inline__ static void trap_instruction(void) { /* See 'arm-linux-tdep.c' in GDB source, * 'eabi_linux_arm_le_breakpoint' */ __asm__ volatile(".inst 0xe7f001f0"); /* Known problem: * Same problem and workaround as Thumb mode */ } #elif defined(__aarch64__) && defined(__APPLE__) #define DEBUG_BREAK_IMPL DEBUG_BREAK_USE_BULTIN_DEBUGTRAP #elif defined(__aarch64__) #define DEBUG_BREAK_IMPL DEBUG_BREAK_USE_TRAP_INSTRUCTION __attribute__((always_inline)) __inline__ static void trap_instruction(void) { /* See 'aarch64-tdep.c' in GDB source, * 'aarch64_default_breakpoint' */ __asm__ volatile(".inst 0xd4200000"); } #elif defined(__powerpc__) /* PPC 32 or 64-bit, big or little endian */ #define DEBUG_BREAK_IMPL DEBUG_BREAK_USE_TRAP_INSTRUCTION __attribute__((always_inline)) __inline__ static void trap_instruction(void) { /* See 'rs6000-tdep.c' in GDB source, * 'rs6000_breakpoint' */ __asm__ volatile(".4byte 0x7d821008"); /* Known problem: * After a breakpoint hit, can't 'stepi', 'step', or 'continue' in GDB. * 'step' stuck on the same instruction ("twge r2,r2"). * * The workaround is the same as ARM Thumb mode: use debugbreak-gdb.py * or manually jump over the instruction. */ } #elif defined(__riscv) /* RISC-V 32 or 64-bit, whether the "C" extension * for compressed, 16-bit instructions are supported or not */ #define DEBUG_BREAK_IMPL DEBUG_BREAK_USE_TRAP_INSTRUCTION __attribute__((always_inline)) __inline__ static void trap_instruction(void) { /* See 'riscv-tdep.c' in GDB source, * 'riscv_sw_breakpoint_from_kind' */ __asm__ volatile(".4byte 0x00100073"); } #else #define DEBUG_BREAK_IMPL DEBUG_BREAK_USE_SIGTRAP #endif #ifndef DEBUG_BREAK_IMPL #error "debugbreak.h is not supported on this target" #elif DEBUG_BREAK_IMPL == DEBUG_BREAK_USE_TRAP_INSTRUCTION __attribute__((always_inline)) __inline__ static void debug_break(void) { trap_instruction(); } #elif DEBUG_BREAK_IMPL == DEBUG_BREAK_USE_BULTIN_DEBUGTRAP __attribute__((always_inline)) __inline__ static void debug_break(void) { __builtin_debugtrap(); } #elif DEBUG_BREAK_IMPL == DEBUG_BREAK_USE_BULTIN_TRAP __attribute__((always_inline)) __inline__ static void debug_break(void) { __builtin_trap(); } #elif DEBUG_BREAK_IMPL == DEBUG_BREAK_USE_SIGTRAP #include __attribute__((always_inline)) __inline__ static void debug_break(void) { raise(SIGTRAP); } #else #error "invalid DEBUG_BREAK_IMPL value" #endif #ifdef __cplusplus } #endif #endif /* ifdef _MSC_VER */ // Here is for checking the debugger is running #include #ifdef IS_DEBUGGER_ACTIVE __attribute__((always_inline)) __inline__ static bool isDebuggerActive() { return IS_DEBUGGER_ACTIVE(); } #else // IS_DEBUGGER_ACTIVE #ifdef __linux__ class ErrnoGuard { public: ErrnoGuard() : m_oldErrno(errno) {} ~ErrnoGuard() { errno = m_oldErrno; } private: int m_oldErrno; }; // See the comments in Catch2 for the reasoning behind this implementation: // https://github.com/catchorg/Catch2/blob/v2.13.1/include/internal/catch_debugger.cpp#L79-L102 __attribute__((always_inline)) __inline__ static bool isDebuggerActive() { ErrnoGuard guard; std::ifstream in("/proc/self/status"); for (std::string line; std::getline(in, line);) { static const int PREFIX_LEN = 11; if (line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0) { return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0'; } } return false; } #elif defined(__APPLE__) #include #include #include // The following function is taken directly from the following technical note: // https://developer.apple.com/library/archive/qa/qa1361/_index.html // Returns true if the current process is being debugged (either // running under the debugger or has a debugger attached post facto). __attribute__((always_inline)) __inline__ static bool isDebuggerActive() { int mib[4]; kinfo_proc info; size_t size; // Initialize the flags so that, if sysctl fails for some bizarre // reason, we get a predictable result. info.kp_proc.p_flag = 0; // Initialize mib, which tells sysctl the info we want, in this case // we're looking for information about a specific process ID. mib[0] = CTL_KERN; mib[1] = KERN_PROC; mib[2] = KERN_PROC_PID; mib[3] = getpid(); // Call sysctl. size = sizeof(info); if (sysctl(mib, (sizeof(mib) / sizeof(*mib)), &info, &size, 0, 0) != 0) { std::cerr << "\nCall to sysctl failed - unable to determine if debugger is active **\n"; return false; } // We're being debugged if the P_TRACED flag is set. return ((info.kp_proc.p_flag & P_TRACED) != 0); } #elif defined(__MINGW32__) || defined(__MINGW64__) extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); __attribute__((always_inline)) __inline__ static bool isDebuggerActive() { return ::IsDebuggerPresent() != 0; } #elif defined(_MSC_VER) extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); inline __forceinline static bool isDebuggerActive() { return ::IsDebuggerPresent() != 0; } #else __attribute__((always_inline)) __inline__ static bool isDebuggerActive() { return false; } #endif #endif // IS_DEBUGGER_ACTIVE #endif /* ifndef DEBUG_BREAK_H */ #pragma once /** * @brief Thread safety support * This header provides thread-safe support for zeroerr. * * It defines macros for mutexes, locks, and atomic operations. * The macros are conditionally defined based on the ZEROERR_NO_THREAD_SAFE flag. */ #ifdef ZEROERR_NO_THREAD_SAFE #define ZEROERR_MUTEX(x) #define ZEROERR_LOCK(x) #define ZEROERR_ATOMIC(x) x #define ZEROERR_LOAD(x) x #else #define ZEROERR_MUTEX(x) static std::mutex x; #define ZEROERR_LOCK(x) std::lock_guard lock(x); #define ZEROERR_ATOMIC(x) std::atomic #define ZEROERR_LOAD(x) x.load() #include #include #endif #pragma once #include #include #include #include // this should be removed #include #include #include ZEROERR_SUPPRESS_COMMON_WARNINGS_PUSH namespace zeroerr { /** * @brief rank is a helper class for Printer to define the priority of overloaded functions. * @tparam N the priority of the rule. 0 is the lowest priority. The maximum priority is max_rank. * * You can define a rule by adding it as a function parameter with rank where N is the priority. * For example: * template * void Foo(T v, rank<0>); // lowest priority * void Foo(int v, rank<1>); // higher priority * * Even though in the first rule, type T can be an int, the second function will still be called due * to the priority. */ template struct rank : rank {}; template <> struct rank<0> {}; namespace detail { // C++11 void_t template using void_t = void; // Type dependent "true"/"false". // Useful for SFINAE and static_asserts where we need a type dependent // expression that happens to be constant. template struct always_false { static std::false_type value; }; template struct always_true { static std::true_type value; }; // Generate sequence of integers from 0 to N-1 // Usage: detail::gen_seq then use to match it template struct seq {}; template struct gen_seq : gen_seq {}; template struct gen_seq<0, Is...> : seq {}; // Some utility structs to check template specialization template class Ref> struct is_specialization : std::false_type {}; template