Better debug helpers [#CLICKHOUSE-2]

This commit is contained in:
Alexey Milovidov 2018-04-06 07:46:18 +03:00
parent 65ad97452b
commit e655cb0bff
8 changed files with 214 additions and 283 deletions

View File

@ -0,0 +1,158 @@
#pragma once
#include <Common/demangle.h>
#include <type_traits>
#include <tuple>
#include <iomanip>
/** Usage:
*
* DUMP(variable...)
*/
template <typename Out, typename T>
Out & dumpValue(Out &, T &&);
/// Catch-all case.
template <int priority, typename Out, typename T>
std::enable_if_t<priority == -1, Out> & dumpImpl(Out & out, T &&)
{
return out << "{...}";
}
/// An object, that could be output with operator <<.
template <int priority, typename Out, typename T>
std::enable_if_t<priority == 0, Out> & dumpImpl(Out & out, T && x, std::decay_t<decltype(std::declval<Out &>() << std::declval<T>())> * = nullptr)
{
return out << x;
}
/// A pointer-like object.
template <int priority, typename Out, typename T>
std::enable_if_t<priority == 1
/// Protect from the case when operator * do effectively nothing (function pointer).
&& !std::is_same_v<std::decay_t<T>, std::decay_t<decltype(*std::declval<T>())>>
, Out> & dumpImpl(Out & out, T && x, std::decay_t<decltype(*std::declval<T>())> * = nullptr)
{
if (!x)
return out << "nullptr";
return dumpValue(out, *x);
}
/// Container.
template <int priority, typename Out, typename T>
std::enable_if_t<priority == 2, Out> & dumpImpl(Out & out, T && x, std::decay_t<decltype(std::begin(std::declval<T>()))> * = nullptr)
{
bool first = true;
out << "{";
for (const auto & elem : x)
{
if (first)
first = false;
else
out << ", ";
dumpValue(out, elem);
}
return out << "}";
}
/// string and const char * - output not as container or pointer.
template <int priority, typename Out, typename T>
std::enable_if_t<priority == 3 && (std::is_same_v<std::decay_t<T>, std::string> || std::is_same_v<std::decay_t<T>, const char *>), Out> &
dumpImpl(Out & out, T && x)
{
return out << std::quoted(x);
}
/// UInt8 - output as number, not char.
template <int priority, typename Out, typename T>
std::enable_if_t<priority == 3 && std::is_same_v<std::decay_t<T>, unsigned char>, Out> &
dumpImpl(Out & out, T && x)
{
return out << int(x);
}
/// Tuple, pair
template <size_t N, typename Out, typename T>
Out & dumpTupleImpl(Out & out, T && x)
{
if constexpr (N == 0)
out << "{";
else
out << ", ";
dumpValue(out, std::get<N>(x));
if constexpr (N + 1 == std::tuple_size_v<std::decay_t<T>>)
out << "}";
else
dumpTupleImpl<N + 1>(out, x);
return out;
}
template <int priority, typename Out, typename T>
std::enable_if_t<priority == 4, Out> & dumpImpl(Out & out, T && x, std::decay_t<decltype(std::get<0>(std::declval<T>()))> * = nullptr)
{
return dumpTupleImpl<0>(out, x);
}
template <int priority, typename Out, typename T>
Out & dumpDispatchPriorities(Out & out, T && x, std::decay_t<decltype(dumpImpl<priority>(std::declval<Out &>(), std::declval<T>()))> *)
{
return dumpImpl<priority>(out, x);
}
struct LowPriority { LowPriority(void *) {} };
template <int priority, typename Out, typename T>
Out & dumpDispatchPriorities(Out & out, T && x, LowPriority)
{
return dumpDispatchPriorities<priority - 1>(out, x, nullptr);
}
template <typename Out, typename T>
Out & dumpValue(Out & out, T && x)
{
return dumpDispatchPriorities<5>(out, x, nullptr);
}
template <typename Out, typename T>
Out & dump(Out & out, const char * name, T && x)
{
out << demangle(typeid(x).name()) << " " << name << " = ";
return dumpValue(out, x);
}
#define DUMPVAR(VAR) dump(std::cerr, #VAR, (VAR)); std::cerr << "; ";
#define DUMPHEAD std::cerr << __FILE__ << ':' << __LINE__ << " ";
#define DUMPTAIL std::cerr << '\n';
#define DUMP1(V1) do { DUMPHEAD DUMPVAR(V1) DUMPTAIL } while(0);
#define DUMP2(V1, V2) do { DUMPHEAD DUMPVAR(V1) DUMPVAR(V2) DUMPTAIL } while(0);
#define DUMP3(V1, V2, V3) do { DUMPHEAD DUMPVAR(V1) DUMPVAR(V2) DUMPVAR(V3) DUMPTAIL } while(0);
#define DUMP4(V1, V2, V3, V4) do { DUMPHEAD DUMPVAR(V1) DUMPVAR(V2) DUMPVAR(V3) DUMPVAR(V4) DUMPTAIL } while(0);
#define DUMP5(V1, V2, V3, V4, V5) do { DUMPHEAD DUMPVAR(V1) DUMPVAR(V2) DUMPVAR(V3) DUMPVAR(V4) DUMPVAR(V5) DUMPTAIL } while(0);
/// https://groups.google.com/forum/#!searchin/kona-dev/variadic$20macro%7Csort:date/kona-dev/XMA-lDOqtlI/GCzdfZsD41sJ
#define VA_NUM_ARGS_IMPL(x1, x2, x3, x4, x5, N, ...) N
#define VA_NUM_ARGS(...) VA_NUM_ARGS_IMPL(__VA_ARGS__, 5, 4, 3, 2, 1)
#define MAKE_VAR_MACRO_IMPL_CONCAT(PREFIX, NUM_ARGS) PREFIX ## NUM_ARGS
#define MAKE_VAR_MACRO_IMPL(PREFIX, NUM_ARGS) MAKE_VAR_MACRO_IMPL_CONCAT(PREFIX, NUM_ARGS)
#define MAKE_VAR_MACRO(PREFIX, ...) MAKE_VAR_MACRO_IMPL(PREFIX, VA_NUM_ARGS(__VA_ARGS__))
#define DUMP(...) MAKE_VAR_MACRO(DUMP, __VA_ARGS__)(__VA_ARGS__)

View File

@ -71,3 +71,6 @@ target_link_libraries (cow_columns clickhouse_common_io)
add_executable (stopwatch stopwatch.cpp)
target_link_libraries (stopwatch clickhouse_common_io)
add_executable (dump_variable dump_variable.cpp)
target_link_libraries (dump_variable clickhouse_common_io)

View File

@ -0,0 +1,51 @@
#include <Common/iostream_debug_helpers.h>
#include <iostream>
#include <memory>
#include <vector>
#include <map>
#include <tuple>
#include <array>
#include <utility>
struct S1;
struct S2 {};
int main(int, char **)
{
int x = 1;
DUMP(x);
DUMP(x, 1, &x);
DUMP(std::make_unique<int>(1));
DUMP(std::make_shared<int>(1));
std::vector<int> vec{1, 2, 3};
DUMP(vec);
auto pair = std::make_pair(1, 2);
DUMP(pair);
auto tuple = std::make_tuple(1, 2, 3);
DUMP(tuple);
std::map<int, std::string> map{{1, "hello"}, {2, "world"}};
DUMP(map);
std::initializer_list<const char *> list{"hello", "world"};
DUMP(list);
std::array<const char *, 2> arr{"hello", "world"};
DUMP(arr);
DUMP([]{});
S1 * s = nullptr;
DUMP(s);
DUMP(S2());
return 0;
}

View File

@ -71,27 +71,10 @@ std::ostream & operator<<(std::ostream & stream, const Block & what)
return stream;
}
template <typename T>
std::ostream & printCOWPtr(std::ostream & stream, const typename COWPtr<T>::Ptr & what)
{
stream << "COWPtr::Ptr(" << what.get();
if (what)
stream << ", use_count = " << what->use_count();
stream << ") {";
if (what)
stream << *what;
else
stream << "nullptr";
stream << "}";
return stream;
}
std::ostream & operator<<(std::ostream & stream, const ColumnWithTypeAndName & what)
{
stream << "ColumnWithTypeAndName(name = " << what.name << ", type = " << what.type << ", column = ";
return printCOWPtr<IColumn>(stream, what.column) << ")";
return dumpValue(stream, what.column) << ")";
}
std::ostream & operator<<(std::ostream & stream, const IColumn & what)
@ -112,15 +95,6 @@ std::ostream & operator<<(std::ostream & stream, const Connection::Packet & what
return stream;
}
std::ostream & operator<<(std::ostream & stream, const SubqueryForSet & what)
{
stream << "SubqueryForSet(source = " << what.source
// TODO: << ", set = " << what.set << ", join = " << what.join
<< ", table = " << what.table
<< ")";
return stream;
}
std::ostream & operator<<(std::ostream & stream, const IAST & what)
{
stream << "IAST{";
@ -129,14 +103,4 @@ std::ostream & operator<<(std::ostream & stream, const IAST & what)
return stream;
}
std::ostream & operator<<(std::ostream & stream, const ExpressionAnalyzer & what)
{
stream << "ExpressionAnalyzer{"
<< "hasAggregation=" << what.hasAggregation()
<< ", SubqueriesForSet=" << what.getSubqueriesForSets()
<< ", ExternalTables=" << what.getExternalTables()
<< "}";
return stream;
}
}

View File

@ -2,8 +2,6 @@
#include <iostream>
#include <Client/Connection.h>
#include <Common/PODArray.h>
#include <Common/AutoArray.h>
namespace DB
@ -39,35 +37,12 @@ std::ostream & operator<<(std::ostream & stream, const ColumnWithTypeAndName & w
class IColumn;
std::ostream & operator<<(std::ostream & stream, const IColumn & what);
struct SubqueryForSet;
std::ostream & operator<<(std::ostream & stream, const SubqueryForSet & what);
class IAST;
std::ostream & operator<<(std::ostream & stream, const IAST & what);
class ExpressionAnalyzer;
std::ostream & operator<<(std::ostream & stream, const ExpressionAnalyzer & what);
std::ostream & operator<<(std::ostream & stream, const Connection::Packet & what);
template <typename T, size_t INITIAL_SIZE, typename TAllocator, size_t pad_right_>
std::ostream & operator<<(std::ostream & stream, const PODArray<T, INITIAL_SIZE, TAllocator, pad_right_> & what)
{
stream << "PODArray(size = " << what.size() << ", capacity = " << what.capacity() << ")";
dumpContainer(stream, what);
return stream;
};
template <typename T>
std::ostream & operator<<(std::ostream & stream, const AutoArray<T> & what)
{
stream << "AutoArray(size = " << what.size() << ")";
dumpContainer(stream, what);
return stream;
};
}
/// some operator<< should be declared before operator<<(... std::shared_ptr<>)
#include <common/iostream_debug_helpers.h>
#include <Common/iostream_debug_helpers.h>

View File

@ -26,7 +26,6 @@ add_library (common ${SPLIT_SHARED}
src/JSON.cpp
src/getMemoryAmount.cpp
src/ThreadPool.cpp
src/iostream_debug_helpers.cpp
include/common/Types.h
include/common/DateLUT.h
@ -45,7 +44,6 @@ add_library (common ${SPLIT_SHARED}
include/common/JSON.h
include/common/getMemoryAmount.h
include/common/ThreadPool.h
include/common/iostream_debug_helpers.h
include/ext/bit_cast.h
include/ext/collection_cast.h

View File

@ -1,203 +0,0 @@
#pragma once
#include <iostream>
#include <array>
#include <chrono>
#include <list>
#include <map>
#include <memory>
#include <optional>
#include <ratio>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
// TODO: https://stackoverflow.com/questions/16464032/how-to-enhance-this-variable-dumping-debug-macro-to-be-variadic
#define DUMPS(VAR) #VAR " = " << (VAR)
#define DUMPHEAD std::cerr << __FILE__ << ":" << __LINE__ << " "
#define DUMP(V1) DUMPHEAD << DUMPS(V1) << "\n";
#define DUMP2(V1, V2) DUMPHEAD << DUMPS(V1) << ", " << DUMPS(V2) << "\n";
#define DUMP3(V1, V2, V3) DUMPHEAD << DUMPS(V1) << ", " << DUMPS(V2) << ", " << DUMPS(V3) << "\n";
#define DUMP4(V1, V2, V3, V4) DUMPHEAD << DUMPS(V1) << ", " << DUMPS(V2) << ", " << DUMPS(V3)<< ", " << DUMPS(V4) << "\n";
#define DUMP5(V1, V2, V3, V4, V5) DUMPHEAD << DUMPS(V1) << ", " << DUMPS(V2) << ", " << DUMPS(V3)<< ", " << DUMPS(V4) << ", " << DUMPS(V5) << "\n";
#define DUMP6(V1, V2, V3, V4, V5, V6) DUMPHEAD << DUMPS(V1) << ", " << DUMPS(V2) << ", " << DUMPS(V3)<< ", " << DUMPS(V4) << ", " << DUMPS(V5) << ", " << DUMPS(V6) << "\n";
namespace std
{
template <typename K, typename V>
ostream & operator<<(ostream & stream, const pair<K, V> & what)
{
stream << "pair{" << what.first << ", " << what.second << "}";
return stream;
}
template <typename T>
void dumpContainer(ostream & stream, const T & container)
{
stream << "{";
bool first = true;
for (const auto & elem : container)
{
if (!first)
stream << ", ";
first = false;
stream << elem;
}
stream << "}";
}
template <typename T>
ostream & operator<<(ostream & stream, const vector<T> & what)
{
stream << "vector(size = " << what.size() << ", capacity = " << what.capacity() << ")";
dumpContainer(stream, what);
return stream;
}
template <typename T, size_t N>
ostream & operator<<(ostream & stream, const array<T, N> & what)
{
stream << "array<" << what.size() << ">";
dumpContainer(stream, what);
return stream;
}
template <typename K, typename V>
ostream & operator<<(ostream & stream, const map<K, V> & what)
{
stream << "map(size = " << what.size() << ")";
dumpContainer(stream, what);
return stream;
}
template <typename K, typename V>
ostream & operator<<(ostream & stream, const multimap<K, V> & what)
{
stream << "multimap(size = " << what.size() << ")";
dumpContainer(stream, what);
return stream;
}
template <typename K, typename V>
ostream & operator<<(ostream & stream, const unordered_map<K, V> & what)
{
stream << "unordered_map(size = " << what.size() << ")";
dumpContainer(stream, what);
return stream;
}
template <typename K, typename V>
ostream & operator<<(ostream & stream, const unordered_multimap<K, V> & what)
{
stream << "unordered_multimap(size = " << what.size() << ")";
dumpContainer(stream, what);
return stream;
}
template <typename K>
ostream & operator<<(ostream & stream, const set<K> & what)
{
stream << "set(size = " << what.size() << ")";
dumpContainer(stream, what);
return stream;
}
template <typename K>
ostream & operator<<(ostream & stream, const multiset<K> & what)
{
stream << "multiset(size = " << what.size() << ")";
dumpContainer(stream, what);
return stream;
}
template <typename K>
ostream & operator<<(ostream & stream, const unordered_set<K> & what)
{
stream << "unordered_set(size = " << what.size() << ")";
dumpContainer(stream, what);
return stream;
}
template <typename K>
ostream & operator<<(ostream & stream, const unordered_multiset<K> & what)
{
stream << "unordered_multiset(size = " << what.size() << ")";
dumpContainer(stream, what);
return stream;
}
template <typename K>
ostream & operator<<(ostream & stream, const list<K> & what)
{
stream << "list(size = " << what.size() << ")";
dumpContainer(stream, what);
return stream;
}
template <intmax_t Num, intmax_t Denom>
ostream & operator<<(ostream & stream, [[maybe_unused]] const ratio<Num, Denom> & what)
{
stream << "ratio<Num=" << Num << ", Denom=" << Denom << ">";
return stream;
}
template <typename clock, typename duration>
ostream & operator<<(ostream & stream, const chrono::duration<clock, duration> & what)
{
stream << "chrono::duration<clock=" << clock() << ", duration=" << duration() << ">{" << what.count() << "}";
return stream;
}
template <typename clock, typename duration>
ostream & operator<<(ostream & stream, const chrono::time_point<clock, duration> & what)
{
stream << "chrono::time_point{" << what.time_since_epoch() << "}";
return stream;
}
template <typename T>
ostream & operator<<(ostream & stream, const shared_ptr<T> & what)
{
stream << "shared_ptr(" << what.get() << ", use_count = " << what.use_count() << ") {";
if (what)
stream << *what;
else
stream << "nullptr";
stream << "}";
return stream;
}
template <typename T>
ostream & operator<<(ostream & stream, const unique_ptr<T> & what)
{
stream << "unique_ptr(" << what.get() << ") {";
if (what)
stream << *what;
else
stream << "nullptr";
stream << "}";
return stream;
}
template <typename T>
ostream & operator<<(ostream & stream, const optional<T> & what)
{
stream << "optional{";
if (what)
stream << *what;
else
stream << "empty";
stream << "}";
return stream;
}
class exception;
ostream & operator<<(ostream & stream, const exception & what);
// TODO: add more types
}

View File

@ -1,15 +0,0 @@
#include "common/iostream_debug_helpers.h"
#include <exception>
namespace std
{
std::ostream & operator<<(std::ostream & stream, const std::exception & what)
{
stream << "exception{" << what.what() << "}";
return stream;
}
}