#ifndef PUGS_ASSERT_HPP #define PUGS_ASSERT_HPP #include <PugsMacros.hpp> #include <iostream> #include <rang.hpp> #include <string> class AssertError { private: const std::string m_file; const int m_line; const std::string m_function; const std::string m_test; const std::string m_message; public: friend std::ostream& operator<<(std::ostream& os, const AssertError& assert_error) { os << '\n' << rang::style::bold << "---------- Assertion error -----------\n" << " at " << assert_error.m_file << ':' << assert_error.m_line << '\n' << " in " << assert_error.m_function << '\n' << " assertion (" << rang::fgB::red << assert_error.m_test << rang::fg::reset << ") failed!\n"; if (not assert_error.m_message.empty()) { os << ' ' << rang::fgB::yellow << assert_error.m_message << rang::fg::reset << '\n'; } os << "--------------------------------------" << rang::style::reset << '\n'; return os; } AssertError(const AssertError&) = default; AssertError(std::string file, int line, std::string function, std::string test, std::string message = "") : m_file(file), m_line(line), m_function(function), m_test(test), m_message(message) { ; } ~AssertError() = default; }; PRAGMA_DIAGNOSTIC_IGNORED_WATTRIBUTES inline bool __attribute__((analyzer_noreturn)) _pugs_assert(const bool& assert) { return assert; } PRAGMA_DIAGNOSTIC_POP #ifdef NDEBUG // Useless test is there to check syntax even in optimized mode. Costs nothing. #define Assert(assertion, ...) \ if (not _pugs_assert(assertion)) { \ using vargs_t = decltype(std::make_tuple(__VA_ARGS__)); \ static_assert(std::tuple_size_v<vargs_t> <= 1, "too many arguments"); \ } #else // NDEBUG #define Assert(assertion, ...) \ if (not _pugs_assert(assertion)) { \ using vargs_t = decltype(std::make_tuple(__VA_ARGS__)); \ static_assert(std::tuple_size_v<vargs_t> <= 1, "too many arguments"); \ if constexpr (std::tuple_size_v<vargs_t> == 0) { \ throw AssertError(__FILE__, __LINE__, __PRETTY_FUNCTION__, #assertion); \ } else { \ throw AssertError(__FILE__, __LINE__, __PRETTY_FUNCTION__, #assertion, #__VA_ARGS__); \ } \ } #endif // NDEBUG // store the current state of Assert macro. This is useful for // instance to noexcept management of Assert throws #ifdef NDEBUG #define NO_ASSERT true #else // NDEBUG #define NO_ASSERT false #endif // NDEBUG #endif // PUGS_ASSERT_HPP