#pragma once #if !defined(NDEBUG) && defined(JVALIDATE_TRACE) #include #include #include #include #include #include namespace jvalidate::detail { template std::ostream & operator<<(std::ostream & os, std::map const & value) { os << '{'; std::string_view div; for (auto const & [k, v] : value) { os << std::exchange(div, ", ") << k << ':' << ' ' << v; } return os << '}'; } template std::ostream & operator<<(std::ostream & os, std::vector const & value) { os << '['; std::string_view div; for (auto const & v : value) { os << std::exchange(div, ", ") << v; } return os << ']'; } template std::ostream & operator<<(std::ostream & os, std::set const & value) { os << '['; std::string_view div; for (auto const & v : value) { os << std::exchange(div, ", ") << v; } return os << ']'; } } namespace jvalidate::detail { inline size_t g_debug_trace_depth = 0; } #define JVALIDATE_NAME(x) JVALIDATE_CONCAT(__, JVALIDATE_CONCAT(x, __LINE__)) #define JVALIDATE_DEBUG(expression) \ do { \ using ::jvalidate::detail::operator<<; \ auto JVALIDATE_NAME(here) = std::source_location::current(); \ std::string_view JVALIDATE_NAME(fname) = JVALIDATE_NAME(here).file_name(); \ JVALIDATE_NAME(fname).remove_prefix(JVALIDATE_NAME(fname).find_last_of('/') + 1); \ std::cerr << std::string(2 * ::jvalidate::detail::g_depth, ' ') << JVALIDATE_NAME(fname) \ << ':' << JVALIDATE_NAME(here).line() << ' ' << expression << std::endl; \ } while (false) #define JVALIDATE_DEBUG_INDENTED_SCOPE() \ ::jvalidate::detail::OnBlockExit JVALIDATE_NAME(indent_scope) = \ (++::jvalidate::detail::g_debug_trace_depth, \ []() { --::jvalidate::detail::g_debug_trace_depth; }) #else #define JVALIDATE_DEBUG(...) #define JVALIDATE_DEBUG_INDENTED_SCOPE() #endif