mirror of https://github.com/ByConity/ByConity
Better debug helpers [#CLICKHOUSE-2]
This commit is contained in:
parent
65ad97452b
commit
e655cb0bff
|
@ -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__)
|
|
@ -71,3 +71,6 @@ target_link_libraries (cow_columns clickhouse_common_io)
|
||||||
|
|
||||||
add_executable (stopwatch stopwatch.cpp)
|
add_executable (stopwatch stopwatch.cpp)
|
||||||
target_link_libraries (stopwatch clickhouse_common_io)
|
target_link_libraries (stopwatch clickhouse_common_io)
|
||||||
|
|
||||||
|
add_executable (dump_variable dump_variable.cpp)
|
||||||
|
target_link_libraries (dump_variable clickhouse_common_io)
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -71,27 +71,10 @@ std::ostream & operator<<(std::ostream & stream, const Block & what)
|
||||||
return stream;
|
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)
|
std::ostream & operator<<(std::ostream & stream, const ColumnWithTypeAndName & what)
|
||||||
{
|
{
|
||||||
stream << "ColumnWithTypeAndName(name = " << what.name << ", type = " << what.type << ", column = ";
|
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)
|
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;
|
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)
|
std::ostream & operator<<(std::ostream & stream, const IAST & what)
|
||||||
{
|
{
|
||||||
stream << "IAST{";
|
stream << "IAST{";
|
||||||
|
@ -129,14 +103,4 @@ std::ostream & operator<<(std::ostream & stream, const IAST & what)
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ostream & operator<<(std::ostream & stream, const ExpressionAnalyzer & what)
|
|
||||||
{
|
|
||||||
stream << "ExpressionAnalyzer{"
|
|
||||||
<< "hasAggregation=" << what.hasAggregation()
|
|
||||||
<< ", SubqueriesForSet=" << what.getSubqueriesForSets()
|
|
||||||
<< ", ExternalTables=" << what.getExternalTables()
|
|
||||||
<< "}";
|
|
||||||
return stream;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include <Client/Connection.h>
|
#include <Client/Connection.h>
|
||||||
#include <Common/PODArray.h>
|
|
||||||
#include <Common/AutoArray.h>
|
|
||||||
|
|
||||||
|
|
||||||
namespace DB
|
namespace DB
|
||||||
|
@ -39,35 +37,12 @@ std::ostream & operator<<(std::ostream & stream, const ColumnWithTypeAndName & w
|
||||||
class IColumn;
|
class IColumn;
|
||||||
std::ostream & operator<<(std::ostream & stream, const IColumn & what);
|
std::ostream & operator<<(std::ostream & stream, const IColumn & what);
|
||||||
|
|
||||||
|
|
||||||
struct SubqueryForSet;
|
|
||||||
std::ostream & operator<<(std::ostream & stream, const SubqueryForSet & what);
|
|
||||||
|
|
||||||
class IAST;
|
class IAST;
|
||||||
std::ostream & operator<<(std::ostream & stream, const IAST & what);
|
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);
|
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<>)
|
/// some operator<< should be declared before operator<<(... std::shared_ptr<>)
|
||||||
#include <common/iostream_debug_helpers.h>
|
#include <Common/iostream_debug_helpers.h>
|
||||||
|
|
|
@ -26,7 +26,6 @@ add_library (common ${SPLIT_SHARED}
|
||||||
src/JSON.cpp
|
src/JSON.cpp
|
||||||
src/getMemoryAmount.cpp
|
src/getMemoryAmount.cpp
|
||||||
src/ThreadPool.cpp
|
src/ThreadPool.cpp
|
||||||
src/iostream_debug_helpers.cpp
|
|
||||||
|
|
||||||
include/common/Types.h
|
include/common/Types.h
|
||||||
include/common/DateLUT.h
|
include/common/DateLUT.h
|
||||||
|
@ -45,7 +44,6 @@ add_library (common ${SPLIT_SHARED}
|
||||||
include/common/JSON.h
|
include/common/JSON.h
|
||||||
include/common/getMemoryAmount.h
|
include/common/getMemoryAmount.h
|
||||||
include/common/ThreadPool.h
|
include/common/ThreadPool.h
|
||||||
include/common/iostream_debug_helpers.h
|
|
||||||
|
|
||||||
include/ext/bit_cast.h
|
include/ext/bit_cast.h
|
||||||
include/ext/collection_cast.h
|
include/ext/collection_cast.h
|
||||||
|
|
|
@ -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
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
Loading…
Reference in New Issue