This documentation is automatically generated by online-judge-tools/verification-helper
View the Project on GitHub
#include "C++/core/io/debug_print.hpp"
/* last update: 2022-08-03 */ #ifndef DEBUG_PRINT_HPP #define DEBUG_PRINT_HPP #define INCLUDED(n) ((defined _GLIBCXX_##n) || (defined _LIBCPP_##n)) #pragma GCC diagnostic ignored "-Wexpansion-to-defined" #if __cplusplus < 201703L # warning Please use C++17 (or later version). #endif #include <algorithm> #include <cctype> #include <iostream> #include <iterator> #include <string_view> #include <type_traits> namespace debug_print { std::ostream& os = std::cerr; template <class Tp> auto has_cbegin(int) -> decltype(std::cbegin(std::declval<Tp>()), std::true_type {}); template <class Tp> auto has_cbegin(...) -> std::false_type; template <class Tp> auto has_value_type(int) -> decltype(std::declval<typename Tp::value_type>(), std::true_type {}); template <class Tp> auto has_value_type(...) -> std::false_type; template <class Tp>[[maybe_unused]] constexpr bool is_iterable_container_v = decltype(has_cbegin<Tp>(int {}))::value; template <class Tp>[[maybe_unused]] constexpr bool is_container_v = decltype(has_value_type<Tp>(int {}))::value || is_iterable_container_v<Tp>; template <> [[maybe_unused]] constexpr bool is_iterable_container_v<std::string_view> = false; template <> [[maybe_unused]] constexpr bool is_container_v<std::string_view> = false; #if INCLUDED(STRING) template <> [[maybe_unused]] constexpr bool is_iterable_container_v<std::string> = false; template <> [[maybe_unused]] constexpr bool is_container_v<std::string> = false; #endif template <class Tp, class... Ts> struct first_element { using type = Tp; }; template <class... Ts> using first_t = typename first_element<Ts...>::type; template <class Tp, std::enable_if_t<!decltype(has_value_type<Tp>(int {}))::value, std::nullptr_t> = nullptr> auto check_elem(int) -> decltype(*std::cbegin(std::declval<Tp>())); template <class Tp, std::enable_if_t<decltype(has_value_type<Tp>(int {}))::value, std::nullptr_t> = nullptr> auto check_elem(int) -> typename Tp::value_type; template <class Tp> auto check_elem(...) -> void; template <class Tp> using elem_t = decltype(check_elem<Tp>(int {})); template <class Tp> [[maybe_unused]] constexpr bool is_multidim_container_v = is_container_v<Tp> && is_container_v<elem_t<Tp>>; template <class Tp> std::enable_if_t<!is_container_v<Tp>> out(const Tp&); void out(const char&); void out(const char*); void out(const std::string_view&); #if INCLUDED(STRING) void out(const std::string&); #endif #ifdef __SIZEOF_INT128__ void out(const __int128&); void out(const unsigned __int128&); #endif template <class Tp1, class Tp2> void out(const std::pair<Tp1, Tp2>&); #if INCLUDED(TUPLE) template <class... Ts> void out(const std::tuple<Ts...>&); #endif #if INCLUDED(STACK) template <class... Ts> void out(std::stack<Ts...>); #endif #if INCLUDED(QUEUE) template <class... Ts> void out(std::queue<Ts...>); template <class... Ts> void out(std::priority_queue<Ts...>); #endif template <class C> std::enable_if_t<is_iterable_container_v<C>> out(const C&); template <class Tp> std::enable_if_t<!is_container_v<Tp>> out(const Tp& arg) { os << arg; } void out(const char& arg) { os << '\'' << arg << '\''; } void out(const char* arg) { os << '\"' << arg << '\"'; } void out(const std::string_view& arg) { os << '\"' << arg << '\"'; } #if INCLUDED(STRING) void out(const std::string& arg) { os << '\"' << arg << '\"'; } #endif #ifdef __SIZEOF_INT128__ void out(const __int128& arg) { int sign = (arg < 0) ? (-1) : 1; if (sign == -1) os << '-'; __int128 base = sign; while (sign * arg >= sign * base * 10) base *= 10; while (base) { os << static_cast<char>('0' + (arg / base % 10)); base /= 10; } } void out(const unsigned __int128& arg) { unsigned __int128 base = 1; while (arg >= base * 10) base *= 10; while (base) { os << static_cast<char>('0' + (arg / base % 10)); base /= 10; } } #endif template <class Tp1, class Tp2> void out(const std::pair<Tp1, Tp2>& arg) { os << '('; out(arg.first); os << ", "; out(arg.second); os << ')'; } #if INCLUDED(TUPLE) template <class T, std::size_t... Is> void print_tuple(const T& arg, std::index_sequence<Is...>) { static_cast<void>(((os << (Is == 0 ? "" : ", "), out(std::get<Is>(arg))), ...)); } template <class... Ts> void out(const std::tuple<Ts...>& arg) { os << '('; print_tuple(arg, std::make_index_sequence<sizeof...(Ts)>()); os << ')'; } #endif #if INCLUDED(STACK) template <class... Ts> void out(std::stack<Ts...> arg) { if (arg.empty()) { os << "<empty stack>"; return; } os << "[ "; while (!arg.empty()) { out(arg.top()); os << ' '; arg.pop(); } os << ']'; } #endif #if INCLUDED(QUEUE) template <class... Ts> void out(std::queue<Ts...> arg) { if (arg.empty()) { os << "<empty queue>"; return; } os << "[ "; while (!arg.empty()) { out(arg.front()); os << ' '; arg.pop(); } os << ']'; } template <class... Ts> void out(std::priority_queue<Ts...> arg) { if (arg.empty()) { os << "<empty priority_queue>"; return; } os << "[ "; while (!arg.empty()) { out(arg.top()); os << ' '; arg.pop(); } os << ']'; } #endif template <class Container> std::enable_if_t<is_iterable_container_v<Container>> out(const Container& arg) { if (std::distance(std::cbegin(arg), std::cend(arg)) == 0) { os << "<empty container>"; return; } os << "[ "; std::for_each(std::cbegin(arg), std::cend(arg), [](const elem_t<Container>& elem) { out(elem); os << ' '; }); os << ']'; } template <class Tp> std::enable_if_t<!is_multidim_container_v<Tp>> print(std::string_view name, const Tp& arg) { os << name << ": "; out(arg); if constexpr (is_container_v<Tp>) os << '\n'; } template <class Tp> std::enable_if_t<is_multidim_container_v<Tp>> print(std::string_view name, const Tp& arg) { os << name << ": "; if (std::distance(std::cbegin(arg), std::cend(arg)) == 0) { os << "<empty multidimensional container>\n"; return; } std::for_each(std::cbegin(arg), std::cend(arg), [&name, is_first_elem = true](const elem_t<Tp>& elem) mutable { if (is_first_elem) is_first_elem = false; else for (std::size_t i = 0; i < name.length() + 2; i++) os << ' '; out(elem); os << '\n'; }); } template <class Tp, class... Ts> void multi_print(std::string_view names, const Tp& arg, const Ts&... args) { if constexpr (sizeof...(Ts) == 0) { names.remove_suffix( std::distance( names.crbegin(), std::find_if_not(names.crbegin(), names.crend(), [](const char c) { return std::isspace(c); }) ) ); print(names, arg); if constexpr (!is_container_v<Tp>) os << '\n'; } else { std::size_t comma_pos = 0; for (std::size_t i = 0, paren_depth = 0, inside_quote = false; i < names.length(); i++) { if (!inside_quote && paren_depth == 0 && i > 0 && names[i - 1] != '\'' && names[i] == ',') { comma_pos = i; break; } if (names[i] == '\"' || names[i] == '\'') { if (i > 0 && names[i - 1] == '\\') continue; inside_quote ^= true; } if (!inside_quote && names[i] == '(' && (i == 0 || names[i - 1] != '\'')) paren_depth++; if (!inside_quote && names[i] == ')' && (i == 0 || names[i - 1] != '\'')) paren_depth--; } const std::size_t first_varname_length = comma_pos - std::distance( names.crend() - comma_pos, std::find_if_not( names.crend() - comma_pos, names.crend(), [](const char c) { return std::isspace(c); } ) ); print(names.substr(0, first_varname_length), arg); if constexpr (!is_container_v<Tp>) { if constexpr (is_container_v<first_t<Ts...>>) os << '\n'; else os << " | "; } const std::size_t next_varname_begins_at = std::distance( names.cbegin(), std::find_if_not( names.cbegin() + comma_pos + 1, names.cend(), [](const char c) { return std::isspace(c); } ) ); names.remove_prefix(next_varname_begins_at); multi_print(names, args...); } } } // namespace debug_print #undef INCLUDED #define dump(...) debug_print::multi_print(#__VA_ARGS__, __VA_ARGS__) #endif // DEBUG_PRINT_HPP /** * @brief デバッガー */
#line 1 "C++/core/io/debug_print.hpp" /* last update: 2022-08-03 */ #ifndef DEBUG_PRINT_HPP #define DEBUG_PRINT_HPP #define INCLUDED(n) ((defined _GLIBCXX_##n) || (defined _LIBCPP_##n)) #pragma GCC diagnostic ignored "-Wexpansion-to-defined" #if __cplusplus < 201703L # warning Please use C++17 (or later version). #endif #include <algorithm> #include <cctype> #include <iostream> #include <iterator> #include <string_view> #include <type_traits> namespace debug_print { std::ostream& os = std::cerr; template <class Tp> auto has_cbegin(int) -> decltype(std::cbegin(std::declval<Tp>()), std::true_type {}); template <class Tp> auto has_cbegin(...) -> std::false_type; template <class Tp> auto has_value_type(int) -> decltype(std::declval<typename Tp::value_type>(), std::true_type {}); template <class Tp> auto has_value_type(...) -> std::false_type; template <class Tp>[[maybe_unused]] constexpr bool is_iterable_container_v = decltype(has_cbegin<Tp>(int {}))::value; template <class Tp>[[maybe_unused]] constexpr bool is_container_v = decltype(has_value_type<Tp>(int {}))::value || is_iterable_container_v<Tp>; template <> [[maybe_unused]] constexpr bool is_iterable_container_v<std::string_view> = false; template <> [[maybe_unused]] constexpr bool is_container_v<std::string_view> = false; #if INCLUDED(STRING) template <> [[maybe_unused]] constexpr bool is_iterable_container_v<std::string> = false; template <> [[maybe_unused]] constexpr bool is_container_v<std::string> = false; #endif template <class Tp, class... Ts> struct first_element { using type = Tp; }; template <class... Ts> using first_t = typename first_element<Ts...>::type; template <class Tp, std::enable_if_t<!decltype(has_value_type<Tp>(int {}))::value, std::nullptr_t> = nullptr> auto check_elem(int) -> decltype(*std::cbegin(std::declval<Tp>())); template <class Tp, std::enable_if_t<decltype(has_value_type<Tp>(int {}))::value, std::nullptr_t> = nullptr> auto check_elem(int) -> typename Tp::value_type; template <class Tp> auto check_elem(...) -> void; template <class Tp> using elem_t = decltype(check_elem<Tp>(int {})); template <class Tp> [[maybe_unused]] constexpr bool is_multidim_container_v = is_container_v<Tp> && is_container_v<elem_t<Tp>>; template <class Tp> std::enable_if_t<!is_container_v<Tp>> out(const Tp&); void out(const char&); void out(const char*); void out(const std::string_view&); #if INCLUDED(STRING) void out(const std::string&); #endif #ifdef __SIZEOF_INT128__ void out(const __int128&); void out(const unsigned __int128&); #endif template <class Tp1, class Tp2> void out(const std::pair<Tp1, Tp2>&); #if INCLUDED(TUPLE) template <class... Ts> void out(const std::tuple<Ts...>&); #endif #if INCLUDED(STACK) template <class... Ts> void out(std::stack<Ts...>); #endif #if INCLUDED(QUEUE) template <class... Ts> void out(std::queue<Ts...>); template <class... Ts> void out(std::priority_queue<Ts...>); #endif template <class C> std::enable_if_t<is_iterable_container_v<C>> out(const C&); template <class Tp> std::enable_if_t<!is_container_v<Tp>> out(const Tp& arg) { os << arg; } void out(const char& arg) { os << '\'' << arg << '\''; } void out(const char* arg) { os << '\"' << arg << '\"'; } void out(const std::string_view& arg) { os << '\"' << arg << '\"'; } #if INCLUDED(STRING) void out(const std::string& arg) { os << '\"' << arg << '\"'; } #endif #ifdef __SIZEOF_INT128__ void out(const __int128& arg) { int sign = (arg < 0) ? (-1) : 1; if (sign == -1) os << '-'; __int128 base = sign; while (sign * arg >= sign * base * 10) base *= 10; while (base) { os << static_cast<char>('0' + (arg / base % 10)); base /= 10; } } void out(const unsigned __int128& arg) { unsigned __int128 base = 1; while (arg >= base * 10) base *= 10; while (base) { os << static_cast<char>('0' + (arg / base % 10)); base /= 10; } } #endif template <class Tp1, class Tp2> void out(const std::pair<Tp1, Tp2>& arg) { os << '('; out(arg.first); os << ", "; out(arg.second); os << ')'; } #if INCLUDED(TUPLE) template <class T, std::size_t... Is> void print_tuple(const T& arg, std::index_sequence<Is...>) { static_cast<void>(((os << (Is == 0 ? "" : ", "), out(std::get<Is>(arg))), ...)); } template <class... Ts> void out(const std::tuple<Ts...>& arg) { os << '('; print_tuple(arg, std::make_index_sequence<sizeof...(Ts)>()); os << ')'; } #endif #if INCLUDED(STACK) template <class... Ts> void out(std::stack<Ts...> arg) { if (arg.empty()) { os << "<empty stack>"; return; } os << "[ "; while (!arg.empty()) { out(arg.top()); os << ' '; arg.pop(); } os << ']'; } #endif #if INCLUDED(QUEUE) template <class... Ts> void out(std::queue<Ts...> arg) { if (arg.empty()) { os << "<empty queue>"; return; } os << "[ "; while (!arg.empty()) { out(arg.front()); os << ' '; arg.pop(); } os << ']'; } template <class... Ts> void out(std::priority_queue<Ts...> arg) { if (arg.empty()) { os << "<empty priority_queue>"; return; } os << "[ "; while (!arg.empty()) { out(arg.top()); os << ' '; arg.pop(); } os << ']'; } #endif template <class Container> std::enable_if_t<is_iterable_container_v<Container>> out(const Container& arg) { if (std::distance(std::cbegin(arg), std::cend(arg)) == 0) { os << "<empty container>"; return; } os << "[ "; std::for_each(std::cbegin(arg), std::cend(arg), [](const elem_t<Container>& elem) { out(elem); os << ' '; }); os << ']'; } template <class Tp> std::enable_if_t<!is_multidim_container_v<Tp>> print(std::string_view name, const Tp& arg) { os << name << ": "; out(arg); if constexpr (is_container_v<Tp>) os << '\n'; } template <class Tp> std::enable_if_t<is_multidim_container_v<Tp>> print(std::string_view name, const Tp& arg) { os << name << ": "; if (std::distance(std::cbegin(arg), std::cend(arg)) == 0) { os << "<empty multidimensional container>\n"; return; } std::for_each(std::cbegin(arg), std::cend(arg), [&name, is_first_elem = true](const elem_t<Tp>& elem) mutable { if (is_first_elem) is_first_elem = false; else for (std::size_t i = 0; i < name.length() + 2; i++) os << ' '; out(elem); os << '\n'; }); } template <class Tp, class... Ts> void multi_print(std::string_view names, const Tp& arg, const Ts&... args) { if constexpr (sizeof...(Ts) == 0) { names.remove_suffix( std::distance( names.crbegin(), std::find_if_not(names.crbegin(), names.crend(), [](const char c) { return std::isspace(c); }) ) ); print(names, arg); if constexpr (!is_container_v<Tp>) os << '\n'; } else { std::size_t comma_pos = 0; for (std::size_t i = 0, paren_depth = 0, inside_quote = false; i < names.length(); i++) { if (!inside_quote && paren_depth == 0 && i > 0 && names[i - 1] != '\'' && names[i] == ',') { comma_pos = i; break; } if (names[i] == '\"' || names[i] == '\'') { if (i > 0 && names[i - 1] == '\\') continue; inside_quote ^= true; } if (!inside_quote && names[i] == '(' && (i == 0 || names[i - 1] != '\'')) paren_depth++; if (!inside_quote && names[i] == ')' && (i == 0 || names[i - 1] != '\'')) paren_depth--; } const std::size_t first_varname_length = comma_pos - std::distance( names.crend() - comma_pos, std::find_if_not( names.crend() - comma_pos, names.crend(), [](const char c) { return std::isspace(c); } ) ); print(names.substr(0, first_varname_length), arg); if constexpr (!is_container_v<Tp>) { if constexpr (is_container_v<first_t<Ts...>>) os << '\n'; else os << " | "; } const std::size_t next_varname_begins_at = std::distance( names.cbegin(), std::find_if_not( names.cbegin() + comma_pos + 1, names.cend(), [](const char c) { return std::isspace(c); } ) ); names.remove_prefix(next_varname_begins_at); multi_print(names, args...); } } } // namespace debug_print #undef INCLUDED #define dump(...) debug_print::multi_print(#__VA_ARGS__, __VA_ARGS__) #endif // DEBUG_PRINT_HPP /** * @brief デバッガー */