algorithm-dev

This documentation is automatically generated by online-judge-tools/verification-helper

View the Project on GitHub today2098/algorithm-dev

:heavy_check_mark: デバッグ用関数形式マクロ
(algorithm/Utils/debug.hpp)

概要

ローカル環境でのみ実行されるデバッグ用の関数形式マクロ.

引数にあるものを,経過時間(マイクロ秒)と行番号,引数名を合わせて,標準エラー出力 (std::clog) に出力する. 可変長引数に対応しており,複数の値を同時に出力することもできる.

引数として使用できるものは次の通り.

使用する際は,コンパイル時に「-D=DEBUG」とオプション指定する.

使用例は次の通り.

int a = 0;
double b = 3.14;
std::string s = "Hello, world!";
std::pair<int, double> p({1, 1.41});
std::vector<int> v({1, 1, 2, 3, 5});

debug('i', -1LL);
debug(a, b);
debug(s);
debug(p);
debug(v);
debug();
$ g++ -std=gnu++23 -D=DEBUG -o debug.out main.cpp
$ ./debug.out
(       0) [L61] ('i', -1LL): (i, -1)
(     119) [L62] (a, b): (0, 3.14)
(     164) [L63] s: Hello, world!
(     198) [L64] p: {1, 1.41}
(     226) [L65] v: [1 1 2 3 5]
(     270) [L66] (empty)

参考文献

  1. “SFINAE”. Wikipedia. https://ja.wikipedia.org/wiki/SFINAE.
  2. “任意の式によるSFINAE [N2634]”. cpprefjp. https://cpprefjp.github.io/index.html.
  3. _EnumHack. “C++メタ関数のまとめ”. Qiita. https://qiita.com/_EnumHack/items/ee2141ad47915c55d9cb.
  4. terukazu. “特定のメンバ関数有無で、呼び出す関数を変えたい”. Qiita. https://qiita.com/terukazu/items/e257c05a7b191d32c577.
  5. “競技プログラミングで print デバッグ”. https://naskya.net/post/0002/.
  6. rsk0315_h4x. X (Twitter). https://twitter.com/rsk0315_h4x/status/1522810205029167105.
  7. raclamusi. X (Twitter). https://twitter.com/raclamusi/status/1522862497463631872.

Verified with

Code

#ifndef ALGORITHM_DEBUG_HPP
#define ALGORITHM_DEBUG_HPP 1

#include <chrono>
#include <iomanip>
#include <iostream>
#include <queue>
#include <ranges>
#include <stack>
#include <string>
#include <string_view>
#include <tuple>
#include <type_traits>
#include <utility>

#ifdef DEBUG

#define debug(...) algorithm::debug::debug_internal(__LINE__ __VA_OPT__(, #__VA_ARGS__, __VA_ARGS__))

namespace algorithm {

namespace debug {

constexpr std::ostream &os = std::clog;

// Forward declaration.

template <typename Type>
void print(const Type &);

template <std::ranges::range R>
void print(const R &);

template <typename... Types>
void print(const std::basic_string<Types...> &);

void print(std::string_view);

template <typename... Types>
void print(const std::stack<Types...> &);

template <typename... Types>
void print(const std::queue<Types...> &);

template <typename... Types>
void print(const std::priority_queue<Types...> &);

template <typename T, typename U>
void print(const std::pair<T, U> &);

template <typename... Types>
void print(const std::tuple<Types...> &);

template <class Tuple, std::size_t... Idxes>
void print_tuple(const Tuple &, std::index_sequence<Idxes...>);

auto elapsed() {
    static const auto start = std::chrono::system_clock::now();
    return std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now() - start).count();
}

template <typename Type, typename... Args>
void debug_internal(int line, std::string_view context, const Type &first, const Args &...args) {
    constexpr const char *open_bracket = (sizeof...(args) == 0 ? "" : "(");
    constexpr const char *close_bracket = (sizeof...(args) == 0 ? "" : ")");
    os << "(" << std::setw(8) << elapsed() << ") [L" << line << "] " << open_bracket << context << close_bracket << ": " << open_bracket;
    print(first);
    ((os << ", ", print(args)), ...);
    os << close_bracket << std::endl;
}

void debug_internal(int line) {
    os << "(" << std::setw(8) << elapsed() << ") [L" << line << "] (empty)" << std::endl;
}

// Implementation.

template <typename Type>
void print(const Type &a) {
    os << a;
}

template <std::ranges::range R>
void print(const R &r) {
    os << "[";
    for(auto iter = std::ranges::cbegin(r); iter != std::ranges::cend(r); ++iter) {
        if(iter != std::ranges::cbegin(r)) os << " ";
        print(*iter);
    }
    os << "]";
}

template <typename... Types>
void print(const std::basic_string<Types...> &s) {
    os << s;
}

void print(std::string_view sv) {
    os << sv;
}

template <typename... Types>
void print(const std::stack<Types...> &st) {
    std::stack<Types...> tmp(st);
    os << "[";
    for(bool first = true; !tmp.empty(); tmp.pop(), first = false) {
        if(!first) os << " ";
        print(tmp.top());
    }
    os << "]";
}

template <typename... Types>
void print(const std::queue<Types...> &que) {
    std::queue<Types...> tmp(que);
    os << "[";
    for(bool first = true; !tmp.empty(); tmp.pop(), first = false) {
        if(!first) os << " ";
        print(tmp.front());
    }
    os << "]";
}

template <typename... Types>
void print(const std::priority_queue<Types...> &pque) {
    std::priority_queue<Types...> tmp(pque);
    os << "[";
    for(bool first = true; !tmp.empty(); tmp.pop(), first = false) {
        if(!first) os << " ";
        print(tmp.top());
    }
    os << "]";
}

template <typename T, typename U>
void print(const std::pair<T, U> &p) {
    os << "{";
    print(p.first);
    os << ", ";
    print(p.second);
    os << "}";
}

template <typename... Types>
void print(const std::tuple<Types...> &t) {
    print_tuple(t, std::make_index_sequence<sizeof...(Types)>());
}

template <class Tuple, std::size_t... Idxes>
void print_tuple(const Tuple &t, std::index_sequence<Idxes...>) {
    os << "{";
    ((os << (Idxes == 0 ? "" : ", "), print(std::get<Idxes>(t))), ...);
    os << "}";
}

}  // namespace debug

}  // namespace algorithm

#else

#define debug(...) static_cast<void>(0)

#endif

#endif
#line 1 "algorithm/Utils/debug.hpp"



#include <chrono>
#include <iomanip>
#include <iostream>
#include <queue>
#include <ranges>
#include <stack>
#include <string>
#include <string_view>
#include <tuple>
#include <type_traits>
#include <utility>

#ifdef DEBUG

#define debug(...) algorithm::debug::debug_internal(__LINE__ __VA_OPT__(, #__VA_ARGS__, __VA_ARGS__))

namespace algorithm {

namespace debug {

constexpr std::ostream &os = std::clog;

// Forward declaration.

template <typename Type>
void print(const Type &);

template <std::ranges::range R>
void print(const R &);

template <typename... Types>
void print(const std::basic_string<Types...> &);

void print(std::string_view);

template <typename... Types>
void print(const std::stack<Types...> &);

template <typename... Types>
void print(const std::queue<Types...> &);

template <typename... Types>
void print(const std::priority_queue<Types...> &);

template <typename T, typename U>
void print(const std::pair<T, U> &);

template <typename... Types>
void print(const std::tuple<Types...> &);

template <class Tuple, std::size_t... Idxes>
void print_tuple(const Tuple &, std::index_sequence<Idxes...>);

auto elapsed() {
    static const auto start = std::chrono::system_clock::now();
    return std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now() - start).count();
}

template <typename Type, typename... Args>
void debug_internal(int line, std::string_view context, const Type &first, const Args &...args) {
    constexpr const char *open_bracket = (sizeof...(args) == 0 ? "" : "(");
    constexpr const char *close_bracket = (sizeof...(args) == 0 ? "" : ")");
    os << "(" << std::setw(8) << elapsed() << ") [L" << line << "] " << open_bracket << context << close_bracket << ": " << open_bracket;
    print(first);
    ((os << ", ", print(args)), ...);
    os << close_bracket << std::endl;
}

void debug_internal(int line) {
    os << "(" << std::setw(8) << elapsed() << ") [L" << line << "] (empty)" << std::endl;
}

// Implementation.

template <typename Type>
void print(const Type &a) {
    os << a;
}

template <std::ranges::range R>
void print(const R &r) {
    os << "[";
    for(auto iter = std::ranges::cbegin(r); iter != std::ranges::cend(r); ++iter) {
        if(iter != std::ranges::cbegin(r)) os << " ";
        print(*iter);
    }
    os << "]";
}

template <typename... Types>
void print(const std::basic_string<Types...> &s) {
    os << s;
}

void print(std::string_view sv) {
    os << sv;
}

template <typename... Types>
void print(const std::stack<Types...> &st) {
    std::stack<Types...> tmp(st);
    os << "[";
    for(bool first = true; !tmp.empty(); tmp.pop(), first = false) {
        if(!first) os << " ";
        print(tmp.top());
    }
    os << "]";
}

template <typename... Types>
void print(const std::queue<Types...> &que) {
    std::queue<Types...> tmp(que);
    os << "[";
    for(bool first = true; !tmp.empty(); tmp.pop(), first = false) {
        if(!first) os << " ";
        print(tmp.front());
    }
    os << "]";
}

template <typename... Types>
void print(const std::priority_queue<Types...> &pque) {
    std::priority_queue<Types...> tmp(pque);
    os << "[";
    for(bool first = true; !tmp.empty(); tmp.pop(), first = false) {
        if(!first) os << " ";
        print(tmp.top());
    }
    os << "]";
}

template <typename T, typename U>
void print(const std::pair<T, U> &p) {
    os << "{";
    print(p.first);
    os << ", ";
    print(p.second);
    os << "}";
}

template <typename... Types>
void print(const std::tuple<Types...> &t) {
    print_tuple(t, std::make_index_sequence<sizeof...(Types)>());
}

template <class Tuple, std::size_t... Idxes>
void print_tuple(const Tuple &t, std::index_sequence<Idxes...>) {
    os << "{";
    ((os << (Idxes == 0 ? "" : ", "), print(std::get<Idxes>(t))), ...);
    os << "}";
}

}  // namespace debug

}  // namespace algorithm

#else

#define debug(...) static_cast<void>(0)

#endif
Back to top page