fix pretty printer for recursive types

This commit is contained in:
Johannes Kapfhammer 2019-10-06 18:37:37 +02:00
parent 310d119ffb
commit 4d25fc25c4
5 changed files with 396 additions and 388 deletions

View File

@ -11,6 +11,9 @@ signed main() {
vector<int> pi{3,1,4,1,5,9,2,6}; vector<int> pi{3,1,4,1,5,9,2,6};
dbg(pi); dbg(pi);
dbg(vector<int>{3,1,4,1,5,9,2,6}); dbg(vector<int>{3,1,4,1,5,9,2,6});
dbg(pi); dbg(vector<pair<int, int>>{{3,1},{4,1}});
dbg(vector<pair<int, vector<string>>>{{3,{"hi"}},{4,{"hello", "world"}}});
dbg(set<int>{3,1,4});
dbg(map<int, string>{{3,"three"},{1,"one"}});
cout << "hi\n"; cout << "hi\n";
} }

View File

@ -21,424 +21,430 @@
#include <utility> #include <utility>
#include <valarray> #include <valarray>
namespace pretty_print namespace soi {
template<typename T, typename TChar, typename TCharTraits>
std::basic_ostream<TChar, TCharTraits> &
print(std::basic_ostream<TChar, TCharTraits> & stream, const T& x);
namespace detail
{ {
namespace detail // SFINAE type trait to detect whether T::const_iterator exists.
struct sfinae_base
{
using yes = char;
using no = yes[2];
};
template <typename T>
struct has_const_iterator : private sfinae_base
{
private:
template <typename C> static yes & test(typename C::const_iterator*);
template <typename C> static no & test(...);
public:
static const bool value = sizeof(test<T>(nullptr)) == sizeof(yes);
using type = T;
};
template <typename T>
struct has_begin_end : private sfinae_base
{
private:
template <typename C>
static yes & f(typename std::enable_if<
std::is_same<decltype(static_cast<typename C::const_iterator(C::*)() const>(&C::begin)),
typename C::const_iterator(C::*)() const>::value>::type *);
template <typename C> static no & f(...);
template <typename C>
static yes & g(typename std::enable_if<
std::is_same<decltype(static_cast<typename C::const_iterator(C::*)() const>(&C::end)),
typename C::const_iterator(C::*)() const>::value, void>::type*);
template <typename C> static no & g(...);
public:
static bool const beg_value = sizeof(f<T>(nullptr)) == sizeof(yes);
static bool const end_value = sizeof(g<T>(nullptr)) == sizeof(yes);
};
} // namespace detail
// Holds the delimiter values for a specific character type
template <typename TChar>
struct delimiters_values
{
using char_type = TChar;
const char_type * prefix;
const char_type * delimiter;
const char_type * postfix;
};
// Defines the delimiter values for a specific container and character type
template <typename T, typename TChar>
struct delimiters
{
using type = delimiters_values<TChar>;
static const type values;
};
// Functor to pretty_print containers. You can use this directly if you want
// to specificy a non-default delimiters type. The pretty_printing logic can
// be customized by specializing the nested template.
template <typename T,
typename TChar = char,
typename TCharTraits = ::std::char_traits<TChar>,
typename TDelimiters = delimiters<T, TChar>>
struct pretty_print_container_helper
{
using delimiters_type = TDelimiters;
using ostream_type = std::basic_ostream<TChar, TCharTraits>;
template <typename U>
struct pretty_printer
{ {
// SFINAE type trait to detect whether T::const_iterator exists. static void pretty_print_body(const U & c, ostream_type & stream)
struct sfinae_base
{ {
using yes = char; using std::begin;
using no = yes[2]; using std::end;
};
template <typename T> auto it = begin(c);
struct has_const_iterator : private sfinae_base const auto the_end = end(c);
{
private:
template <typename C> static yes & test(typename C::const_iterator*);
template <typename C> static no & test(...);
public:
static const bool value = sizeof(test<T>(nullptr)) == sizeof(yes);
using type = T;
};
template <typename T> if (it != the_end)
struct has_begin_end : private sfinae_base
{
private:
template <typename C>
static yes & f(typename std::enable_if<
std::is_same<decltype(static_cast<typename C::const_iterator(C::*)() const>(&C::begin)),
typename C::const_iterator(C::*)() const>::value>::type *);
template <typename C> static no & f(...);
template <typename C>
static yes & g(typename std::enable_if<
std::is_same<decltype(static_cast<typename C::const_iterator(C::*)() const>(&C::end)),
typename C::const_iterator(C::*)() const>::value, void>::type*);
template <typename C> static no & g(...);
public:
static bool const beg_value = sizeof(f<T>(nullptr)) == sizeof(yes);
static bool const end_value = sizeof(g<T>(nullptr)) == sizeof(yes);
};
} // namespace detail
// Holds the delimiter values for a specific character type
template <typename TChar>
struct delimiters_values
{
using char_type = TChar;
const char_type * prefix;
const char_type * delimiter;
const char_type * postfix;
};
// Defines the delimiter values for a specific container and character type
template <typename T, typename TChar>
struct delimiters
{
using type = delimiters_values<TChar>;
static const type values;
};
// Functor to print containers. You can use this directly if you want
// to specificy a non-default delimiters type. The printing logic can
// be customized by specializing the nested template.
template <typename T,
typename TChar = char,
typename TCharTraits = ::std::char_traits<TChar>,
typename TDelimiters = delimiters<T, TChar>>
struct print_container_helper
{
using delimiters_type = TDelimiters;
using ostream_type = std::basic_ostream<TChar, TCharTraits>;
template <typename U>
struct printer
{
static void print_body(const U & c, ostream_type & stream)
{
using std::begin;
using std::end;
auto it = begin(c);
const auto the_end = end(c);
if (it != the_end)
{ {
for ( ; ; ) for ( ; ; )
{ {
stream << *it; ::soi::print(stream, *it);
if (++it == the_end) break; if (++it == the_end) break;
if (delimiters_type::values.delimiter != NULL) if (delimiters_type::values.delimiter != NULL)
stream << delimiters_type::values.delimiter; ::soi::print(stream, delimiters_type::values.delimiter);
} }
} }
} }
}; };
print_container_helper(const T & container) pretty_print_container_helper(const T & container)
: container_(container) : container_(container)
{ } { }
inline void operator()(ostream_type & stream) const inline void operator()(ostream_type & stream) const
{
if (delimiters_type::values.prefix != NULL)
stream << delimiters_type::values.prefix;
printer<T>::print_body(container_, stream);
if (delimiters_type::values.postfix != NULL)
stream << delimiters_type::values.postfix;
}
private:
const T & container_;
};
// Specialization for pairs
template <typename T, typename TChar, typename TCharTraits, typename TDelimiters>
template <typename T1, typename T2>
struct print_container_helper<T, TChar, TCharTraits, TDelimiters>::printer<std::pair<T1, T2>>
{ {
using ostream_type = typename print_container_helper<T, TChar, TCharTraits, TDelimiters>::ostream_type; if (delimiters_type::values.prefix != NULL)
::soi::print(stream, delimiters_type::values.prefix);
static void print_body(const std::pair<T1, T2> & c, ostream_type & stream) pretty_printer<T>::pretty_print_body(container_, stream);
{
stream << c.first;
if (print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter != NULL)
stream << print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter;
stream << c.second;
}
};
// Specialization for tuples if (delimiters_type::values.postfix != NULL)
::soi::print(stream, delimiters_type::values.postfix);
template <typename T, typename TChar, typename TCharTraits, typename TDelimiters>
template <typename ...Args>
struct print_container_helper<T, TChar, TCharTraits, TDelimiters>::printer<std::tuple<Args...>>
{
using ostream_type = typename print_container_helper<T, TChar, TCharTraits, TDelimiters>::ostream_type;
using element_type = std::tuple<Args...>;
template <std::size_t I> struct Int { };
static void print_body(const element_type & c, ostream_type & stream)
{
tuple_print(c, stream, Int<0>());
}
static void tuple_print(const element_type &, ostream_type &, Int<sizeof...(Args)>)
{
}
static void tuple_print(const element_type & c, ostream_type & stream,
typename std::conditional<sizeof...(Args) != 0, Int<0>, std::nullptr_t>::type)
{
stream << std::get<0>(c);
tuple_print(c, stream, Int<1>());
}
template <std::size_t N>
static void tuple_print(const element_type & c, ostream_type & stream, Int<N>)
{
if (print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter != NULL)
stream << print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter;
stream << std::get<N>(c);
tuple_print(c, stream, Int<N + 1>());
}
};
// Prints a print_container_helper to the specified stream.
template<typename T, typename TChar, typename TCharTraits, typename TDelimiters>
inline std::basic_ostream<TChar, TCharTraits> & operator<<(
std::basic_ostream<TChar, TCharTraits> & stream,
const print_container_helper<T, TChar, TCharTraits, TDelimiters> & helper)
{
helper(stream);
return stream;
} }
private:
const T & container_;
};
// Basic is_container template; specialize to derive from std::true_type for all desired container types // Specialization for pairs
template <typename T> template <typename T, typename TChar, typename TCharTraits, typename TDelimiters>
struct is_container : public std::integral_constant<bool, template <typename T1, typename T2>
detail::has_const_iterator<T>::value && struct pretty_print_container_helper<T, TChar, TCharTraits, TDelimiters>::pretty_printer<std::pair<T1, T2>>
detail::has_begin_end<T>::beg_value && {
detail::has_begin_end<T>::end_value> { }; using ostream_type = typename pretty_print_container_helper<T, TChar, TCharTraits, TDelimiters>::ostream_type;
template <typename T, std::size_t N> static void pretty_print_body(const std::pair<T1, T2> & c, ostream_type & stream)
struct is_container<T[N]> : std::true_type { }; {
::soi::print(stream, c.first);
if (pretty_print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter != NULL)
::soi::print(stream, pretty_print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter);
::soi::print(stream, c.second);
}
};
// Specialization for tuples
template <typename T, typename TChar, typename TCharTraits, typename TDelimiters>
template <typename ...Args>
struct pretty_print_container_helper<T, TChar, TCharTraits, TDelimiters>::pretty_printer<std::tuple<Args...>>
{
using ostream_type = typename pretty_print_container_helper<T, TChar, TCharTraits, TDelimiters>::ostream_type;
using element_type = std::tuple<Args...>;
template <std::size_t I> struct Int { };
static void pretty_print_body(const element_type & c, ostream_type & stream)
{
tuple_pretty_print(c, stream, Int<0>());
}
static void tuple_pretty_print(const element_type &, ostream_type &, Int<sizeof...(Args)>)
{
}
static void tuple_pretty_print(const element_type & c, ostream_type & stream,
typename std::conditional<sizeof...(Args) != 0, Int<0>, std::nullptr_t>::type)
{
::soi::print(stream, std::get<0>(c));
tuple_pretty_print(c, stream, Int<1>());
}
template <std::size_t N> template <std::size_t N>
struct is_container<char[N]> : std::false_type { }; static void tuple_pretty_print(const element_type & c, ostream_type & stream, Int<N>)
template <typename T>
struct is_container<std::valarray<T>> : std::true_type { };
template <typename T1, typename T2>
struct is_container<std::pair<T1, T2>> : std::true_type { };
template <typename ...Args>
struct is_container<std::tuple<Args...>> : std::true_type { };
// Default delimiters
template <typename T> struct delimiters<T, char> { static const delimiters_values<char> values; };
template <typename T> const delimiters_values<char> delimiters<T, char>::values = { "[", ", ", "]" };
template <typename T> struct delimiters<T, wchar_t> { static const delimiters_values<wchar_t> values; };
template <typename T> const delimiters_values<wchar_t> delimiters<T, wchar_t>::values = { L"[", L", ", L"]" };
// Delimiters for (multi)set and unordered_(multi)set
template <typename T, typename TComp, typename TAllocator>
struct delimiters< ::std::set<T, TComp, TAllocator>, char> { static const delimiters_values<char> values; };
template <typename T, typename TComp, typename TAllocator>
const delimiters_values<char> delimiters< ::std::set<T, TComp, TAllocator>, char>::values = { "{", ", ", "}" };
template <typename T, typename TComp, typename TAllocator>
struct delimiters< ::std::set<T, TComp, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; };
template <typename T, typename TComp, typename TAllocator>
const delimiters_values<wchar_t> delimiters< ::std::set<T, TComp, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
template <typename T, typename TComp, typename TAllocator>
struct delimiters< ::std::multiset<T, TComp, TAllocator>, char> { static const delimiters_values<char> values; };
template <typename T, typename TComp, typename TAllocator>
const delimiters_values<char> delimiters< ::std::multiset<T, TComp, TAllocator>, char>::values = { "{", ", ", "}" };
template <typename T, typename TComp, typename TAllocator>
struct delimiters< ::std::multiset<T, TComp, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; };
template <typename T, typename TComp, typename TAllocator>
const delimiters_values<wchar_t> delimiters< ::std::multiset<T, TComp, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
template <typename T, typename THash, typename TEqual, typename TAllocator>
struct delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, char> { static const delimiters_values<char> values; };
template <typename T, typename THash, typename TEqual, typename TAllocator>
const delimiters_values<char> delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, char>::values = { "{", ", ", "}" };
template <typename T, typename THash, typename TEqual, typename TAllocator>
struct delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; };
template <typename T, typename THash, typename TEqual, typename TAllocator>
const delimiters_values<wchar_t> delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
template <typename T, typename THash, typename TEqual, typename TAllocator>
struct delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, char> { static const delimiters_values<char> values; };
template <typename T, typename THash, typename TEqual, typename TAllocator>
const delimiters_values<char> delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, char>::values = { "{", ", ", "}" };
template <typename T, typename THash, typename TEqual, typename TAllocator>
struct delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; };
template <typename T, typename THash, typename TEqual, typename TAllocator>
const delimiters_values<wchar_t> delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
// Delimiters for pair and tuple
template <typename T1, typename T2> struct delimiters<std::pair<T1, T2>, char> { static const delimiters_values<char> values; };
template <typename T1, typename T2> const delimiters_values<char> delimiters<std::pair<T1, T2>, char>::values = { "(", ", ", ")" };
template <typename T1, typename T2> struct delimiters< ::std::pair<T1, T2>, wchar_t> { static const delimiters_values<wchar_t> values; };
template <typename T1, typename T2> const delimiters_values<wchar_t> delimiters< ::std::pair<T1, T2>, wchar_t>::values = { L"(", L", ", L")" };
template <typename ...Args> struct delimiters<std::tuple<Args...>, char> { static const delimiters_values<char> values; };
template <typename ...Args> const delimiters_values<char> delimiters<std::tuple<Args...>, char>::values = { "(", ", ", ")" };
template <typename ...Args> struct delimiters< ::std::tuple<Args...>, wchar_t> { static const delimiters_values<wchar_t> values; };
template <typename ...Args> const delimiters_values<wchar_t> delimiters< ::std::tuple<Args...>, wchar_t>::values = { L"(", L", ", L")" };
// Type-erasing helper class for easy use of custom delimiters.
// Requires TCharTraits = std::char_traits<TChar> and TChar = char or wchar_t, and MyDelims needs to be defined for TChar.
// Usage: "cout << pretty_print::custom_delims<MyDelims>(x)".
struct custom_delims_base
{ {
virtual ~custom_delims_base() { } if (pretty_print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter != NULL)
virtual std::ostream & stream(::std::ostream &) = 0; ::soi::print(stream, pretty_print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter);
virtual std::wostream & stream(::std::wostream &) = 0;
};
template <typename T, typename Delims> ::soi::print(stream, std::get<N>(c));
struct custom_delims_wrapper : custom_delims_base
tuple_pretty_print(c, stream, Int<N + 1>());
}
};
// Pretty_Prints a pretty_print_container_helper to the specified stream.
template<typename T, typename TChar, typename TCharTraits, typename TDelimiters>
inline std::basic_ostream<TChar, TCharTraits> & pretty_print(
std::basic_ostream<TChar, TCharTraits> & stream,
const pretty_print_container_helper<T, TChar, TCharTraits, TDelimiters> & helper)
{
helper(stream);
return stream;
}
// Basic is_container template; specialize to derive from std::true_type for all desired container types
template <typename T>
struct is_container : public std::integral_constant<bool,
detail::has_const_iterator<T>::value &&
detail::has_begin_end<T>::beg_value &&
detail::has_begin_end<T>::end_value> { };
template <typename T, std::size_t N>
struct is_container<T[N]> : std::true_type { };
template <std::size_t N>
struct is_container<char[N]> : std::false_type { };
template <typename T>
struct is_container<std::valarray<T>> : std::true_type { };
template <typename T1, typename T2>
struct is_container<std::pair<T1, T2>> : std::true_type { };
template <typename ...Args>
struct is_container<std::tuple<Args...>> : std::true_type { };
// Default delimiters
template <typename T> struct delimiters<T, char> { static const delimiters_values<char> values; };
template <typename T> const delimiters_values<char> delimiters<T, char>::values = { "[", ", ", "]" };
template <typename T> struct delimiters<T, wchar_t> { static const delimiters_values<wchar_t> values; };
template <typename T> const delimiters_values<wchar_t> delimiters<T, wchar_t>::values = { L"[", L", ", L"]" };
// Delimiters for (multi)set and unordered_(multi)set
template <typename T, typename TComp, typename TAllocator>
struct delimiters< ::std::set<T, TComp, TAllocator>, char> { static const delimiters_values<char> values; };
template <typename T, typename TComp, typename TAllocator>
const delimiters_values<char> delimiters< ::std::set<T, TComp, TAllocator>, char>::values = { "{", ", ", "}" };
template <typename T, typename TComp, typename TAllocator>
struct delimiters< ::std::set<T, TComp, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; };
template <typename T, typename TComp, typename TAllocator>
const delimiters_values<wchar_t> delimiters< ::std::set<T, TComp, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
template <typename T, typename TComp, typename TAllocator>
struct delimiters< ::std::multiset<T, TComp, TAllocator>, char> { static const delimiters_values<char> values; };
template <typename T, typename TComp, typename TAllocator>
const delimiters_values<char> delimiters< ::std::multiset<T, TComp, TAllocator>, char>::values = { "{", ", ", "}" };
template <typename T, typename TComp, typename TAllocator>
struct delimiters< ::std::multiset<T, TComp, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; };
template <typename T, typename TComp, typename TAllocator>
const delimiters_values<wchar_t> delimiters< ::std::multiset<T, TComp, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
template <typename T, typename THash, typename TEqual, typename TAllocator>
struct delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, char> { static const delimiters_values<char> values; };
template <typename T, typename THash, typename TEqual, typename TAllocator>
const delimiters_values<char> delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, char>::values = { "{", ", ", "}" };
template <typename T, typename THash, typename TEqual, typename TAllocator>
struct delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; };
template <typename T, typename THash, typename TEqual, typename TAllocator>
const delimiters_values<wchar_t> delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
template <typename T, typename THash, typename TEqual, typename TAllocator>
struct delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, char> { static const delimiters_values<char> values; };
template <typename T, typename THash, typename TEqual, typename TAllocator>
const delimiters_values<char> delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, char>::values = { "{", ", ", "}" };
template <typename T, typename THash, typename TEqual, typename TAllocator>
struct delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; };
template <typename T, typename THash, typename TEqual, typename TAllocator>
const delimiters_values<wchar_t> delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
// Delimiters for pair and tuple
template <typename T1, typename T2> struct delimiters<std::pair<T1, T2>, char> { static const delimiters_values<char> values; };
template <typename T1, typename T2> const delimiters_values<char> delimiters<std::pair<T1, T2>, char>::values = { "(", ", ", ")" };
template <typename T1, typename T2> struct delimiters< ::std::pair<T1, T2>, wchar_t> { static const delimiters_values<wchar_t> values; };
template <typename T1, typename T2> const delimiters_values<wchar_t> delimiters< ::std::pair<T1, T2>, wchar_t>::values = { L"(", L", ", L")" };
template <typename ...Args> struct delimiters<std::tuple<Args...>, char> { static const delimiters_values<char> values; };
template <typename ...Args> const delimiters_values<char> delimiters<std::tuple<Args...>, char>::values = { "(", ", ", ")" };
template <typename ...Args> struct delimiters< ::std::tuple<Args...>, wchar_t> { static const delimiters_values<wchar_t> values; };
template <typename ...Args> const delimiters_values<wchar_t> delimiters< ::std::tuple<Args...>, wchar_t>::values = { L"(", L", ", L")" };
// Type-erasing helper class for easy use of custom delimiters.
// Requires TCharTraits = std::char_traits<TChar> and TChar = char or wchar_t, and MyDelims needs to be defined for TChar.
// Usage: "cout << pretty_pretty_print::custom_delims<MyDelims>(x)".
struct custom_delims_base
{
virtual ~custom_delims_base() { }
virtual std::ostream & stream(::std::ostream &) = 0;
virtual std::wostream & stream(::std::wostream &) = 0;
};
template <typename T, typename Delims>
struct custom_delims_wrapper : custom_delims_base
{
custom_delims_wrapper(const T & t_) : t(t_) { }
std::ostream & stream(std::ostream & s)
{ {
custom_delims_wrapper(const T & t_) : t(t_) { } return pretty_print(s, pretty_print_container_helper<T, char, std::char_traits<char>, Delims>(t));
std::ostream & stream(std::ostream & s)
{
return s << print_container_helper<T, char, std::char_traits<char>, Delims>(t);
}
std::wostream & stream(std::wostream & s)
{
return s << print_container_helper<T, wchar_t, std::char_traits<wchar_t>, Delims>(t);
}
private:
const T & t;
};
template <typename Delims>
struct custom_delims
{
template <typename Container>
custom_delims(const Container & c) : base(new custom_delims_wrapper<Container, Delims>(c)) { }
std::unique_ptr<custom_delims_base> base;
};
template <typename TChar, typename TCharTraits, typename Delims>
inline std::basic_ostream<TChar, TCharTraits> & operator<<(std::basic_ostream<TChar, TCharTraits> & s, const custom_delims<Delims> & p)
{
return p.base->stream(s);
} }
std::wostream & stream(std::wostream & s)
// A wrapper for a C-style array given as pointer-plus-size.
// Usage: std::cout << pretty_print_array(arr, n) << std::endl;
template<typename T>
struct array_wrapper_n
{ {
typedef const T * const_iterator; return pretty_print(s, pretty_print_container_helper<T, wchar_t, std::char_traits<wchar_t>, Delims>(t));
typedef T value_type; }
array_wrapper_n(const T * const a, size_t n) : _array(a), _n(n) { } private:
inline const_iterator begin() const { return _array; } const T & t;
inline const_iterator end() const { return _array + _n; } };
private: template <typename Delims>
const T * const _array; struct custom_delims
size_t _n; {
}; template <typename Container>
custom_delims(const Container & c) : base(new custom_delims_wrapper<Container, Delims>(c)) { }
std::unique_ptr<custom_delims_base> base;
};
template <typename TChar, typename TCharTraits, typename Delims>
inline std::basic_ostream<TChar, TCharTraits> & pretty_print(std::basic_ostream<TChar, TCharTraits> & s, const custom_delims<Delims> & p)
{
return p.base->stream(s);
}
// A wrapper for hash-table based containers that offer local iterators to each bucket. // A wrapper for a C-style array given as pointer-plus-size.
// Usage: std::cout << bucket_print(m, 4) << std::endl; (Prints bucket 5 of container m.) // Usage: std::cout << pretty_pretty_print_array(arr, n) << std::endl;
template <typename T> template<typename T>
struct bucket_print_wrapper struct array_wrapper_n
{
typedef const T * const_iterator;
typedef T value_type;
array_wrapper_n(const T * const a, size_t n) : _array(a), _n(n) { }
inline const_iterator begin() const { return _array; }
inline const_iterator end() const { return _array + _n; }
private:
const T * const _array;
size_t _n;
};
// A wrapper for hash-table based containers that offer local iterators to each bucket.
// Usage: std::cout << bucket_pretty_print(m, 4) << std::endl; (Pretty_Prints bucket 5 of container m.)
template <typename T>
struct bucket_pretty_print_wrapper
{
typedef typename T::const_local_iterator const_iterator;
typedef typename T::size_type size_type;
const_iterator begin() const
{ {
typedef typename T::const_local_iterator const_iterator; return m_map.cbegin(n);
typedef typename T::size_type size_type; }
const_iterator begin() const const_iterator end() const
{ {
return m_map.cbegin(n); return m_map.cend(n);
} }
const_iterator end() const bucket_pretty_print_wrapper(const T & m, size_type bucket) : m_map(m), n(bucket) { }
{
return m_map.cend(n);
}
bucket_print_wrapper(const T & m, size_type bucket) : m_map(m), n(bucket) { } private:
const T & m_map;
const size_type n;
};
private: } // namespace soi
const T & m_map;
const size_type n;
};
} // namespace pretty_print
/* /*
// Global accessor functions for the convenience wrappers // Global accessor functions for the convenience wrappers
template<typename T> template<typename T>
inline pretty_print::array_wrapper_n<T> pretty_print_array(const T * const a, size_t n) inline pretty_pretty_print::array_wrapper_n<T> pretty_pretty_print_array(const T * const a, size_t n)
{ {
return pretty_print::array_wrapper_n<T>(a, n); return pretty_pretty_print::array_wrapper_n<T>(a, n);
} }
template <typename T> pretty_print::bucket_print_wrapper<T> template <typename T> pretty_pretty_print::bucket_pretty_print_wrapper<T>
bucket_print(const T & m, typename T::size_type n) bucket_pretty_print(const T & m, typename T::size_type n)
{ {
return pretty_print::bucket_print_wrapper<T>(m, n); return pretty_pretty_print::bucket_pretty_print_wrapper<T>(m, n);
} }
// Main magic entry point: An overload snuck into namespace std. // Main magic entry point: An overload snuck into namespace std.
// Can we do better? // Can we do better?
namespace std
{
// Prints a container to the stream using default delimiters
template<typename T, typename TChar, typename TCharTraits>
inline typename enable_if< ::pretty_print::is_container<T>::value,
basic_ostream<TChar, TCharTraits> &>::type
operator<<(basic_ostream<TChar, TCharTraits> & stream, const T & container)
{
return stream << ::pretty_print::print_container_helper<T, TChar, TCharTraits>(container);
}
}
*/ */
#endif // SOI_PRETTY_PRINT namespace soi
{
// Pretty_Prints a container to the stream using default delimiters
template<typename T, typename TChar, typename TCharTraits>
inline typename std::enable_if< ::soi::is_container<T>::value,
std::basic_ostream<TChar, TCharTraits> &>::type
pretty_print(std::basic_ostream<TChar, TCharTraits> & stream, const T & container)
{
return ::soi::print(stream, ::soi::pretty_print_container_helper<T, TChar, TCharTraits>(container));
}
}
#endif // SOI_PRETTY_PRETTY_PRINT

View File

@ -23,7 +23,7 @@
#include "soi-pretty.hpp" #include "soi-pretty.hpp"
namespace soi_h { namespace soi {
namespace detail { namespace detail {
@ -102,7 +102,7 @@ CONSTEXPR14_TN
static_string static_string
type_name() type_name()
{ {
const int k = sizeof("constexpr soi_h::detail:: T =")/sizeof(char); const int k = sizeof("constexpr soi::detail:: T")/sizeof(char);
#ifdef __clang__ #ifdef __clang__
static_string p = __PRETTY_FUNCTION__; static_string p = __PRETTY_FUNCTION__;
return static_string(p.data() + 31 + k, p.size() - 31 - k - 1); return static_string(p.data() + 31 + k, p.size() - 31 - k - 1);
@ -215,7 +215,7 @@ T&& dbg_print(T&& value,
char const* expression) { char const* expression) {
const T& ref = value; const T& ref = value;
std::stringstream value_buffer; // avoid nesting of dbg macros within print functinos std::stringstream value_buffer; // avoid nesting of dbg macros within print functinos
soi_h::pretty_print(value_buffer, ref); soi::print(value_buffer, ref);
std::cerr << ANSI_DEBUG std::cerr << ANSI_DEBUG
<< "[" << file << ":" << line << "[" << file << ":" << line
@ -257,8 +257,8 @@ T&& identity(T&& t) {
#define dbg(...) dbg_macro::identity(__VA_ARGS__) #define dbg(...) dbg_macro::identity(__VA_ARGS__)
#else #else
#define dbg(...) \ #define dbg(...) \
soi_h::detail::dbg_print((__VA_ARGS__), \ soi::detail::dbg_print((__VA_ARGS__), \
soi_h::detail::sanitized_type_name<decltype(__VA_ARGS__)>(), \ soi::detail::sanitized_type_name<decltype(__VA_ARGS__)>(), \
__FILE__, \ __FILE__, \
__LINE__, \ __LINE__, \
__func__, \ __func__, \

View File

@ -3,7 +3,7 @@
// (See accompanying file LICENSE_1_0.txt or copy at // (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt) // http://www.boost.org/LICENSE_1_0.txt)
// //
// pretty printing with c++ // pretty pretty_printing with c++
// //
#ifndef SOI_PRETTY #ifndef SOI_PRETTY
@ -11,14 +11,7 @@
#include "prettyprint.hpp" #include "prettyprint.hpp"
namespace soi_h { namespace soi {
template<typename T, typename TChar, typename TCharTraits>
inline typename std::enable_if< ::pretty_print::is_container<T>::value,
std::basic_ostream<TChar, TCharTraits> &>::type
pretty_print(std::basic_ostream<TChar, TCharTraits> & stream, const T & container) {
return stream << ::pretty_print::print_container_helper<T, TChar, TCharTraits>(container);
}
template<typename TChar, typename TCharTraits> template<typename TChar, typename TCharTraits>
std::basic_ostream<TChar, TCharTraits> & std::basic_ostream<TChar, TCharTraits> &
@ -65,12 +58,18 @@ pretty_print(std::basic_ostream<TChar, TCharTraits> & stream, char c) {
} }
template<typename T, typename TChar, typename TCharTraits> template<typename T, typename TChar, typename TCharTraits>
inline typename std::enable_if< !::pretty_print::is_container<T>::value, inline typename std::enable_if< !::soi::is_container<T>::value,
std::basic_ostream<TChar, TCharTraits> &>::type std::basic_ostream<TChar, TCharTraits> &>::type
pretty_print(std::basic_ostream<TChar, TCharTraits> & stream, const T& x) { pretty_print(std::basic_ostream<TChar, TCharTraits> & stream, const T& x) {
return stream << x; return stream << x;
} }
template<typename T, typename TChar, typename TCharTraits>
std::basic_ostream<TChar, TCharTraits> &
print(std::basic_ostream<TChar, TCharTraits> & stream, const T& x) {
return pretty_print(stream, x);
}
} }
#endif // SOI_PRETTY #endif // SOI_PRETTY

View File

@ -8,7 +8,7 @@
#include <fstream> #include <fstream>
#include "bits/soi-dbg.hpp" #include "bits/soi-dbg.hpp"
namespace soi_h { namespace soi {
void check_for_eof() { void check_for_eof() {
if (!(std::cin >> std::ws).eof()) if (!(std::cin >> std::ws).eof())
@ -52,11 +52,11 @@ void initialize_debug() {
std::atexit(noninteractive_check_eof) != 0) { std::atexit(noninteractive_check_eof) != 0) {
std::cerr << "WARNING: soi.h -- registration of sanity check at exit failed\n"; std::cerr << "WARNING: soi.h -- registration of sanity check at exit failed\n";
} }
soi_h::detail::dbg_init(); soi::detail::dbg_init();
} }
struct soi_h_initializer { struct soi_initializer {
soi_h_initializer(bool release) { soi_initializer(bool release) {
if (release) { if (release) {
std::ios::sync_with_stdio(false); std::ios::sync_with_stdio(false);
std::cin.tie(0); std::cin.tie(0);
@ -67,12 +67,12 @@ struct soi_h_initializer {
}; };
#ifdef SOI_RELEASE #ifdef SOI_RELEASE
soi_h_initializer soi_h_initializer_{true}; soi_initializer soi_initializer_{true};
#else #else
soi_h_initializer soi_h_initializer_{false}; soi_initializer soi_initializer_{false};
#endif #endif
} // end namespace soi_h } // end namespace soi
#include "bits/soi-deprecate.hpp" #include "bits/soi-deprecate.hpp"