// Copyright Louis Delacroix 2010 - 2014. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef H_PRETTY_PRINT #define H_PRETTY_PRINT #include #include #include #include #ifndef NO_TR1 # include # include #endif namespace pretty_print { template struct conditional { }; template struct conditional { typedef S type; }; template struct conditional { typedef T type; }; template struct enable_if { }; template struct enable_if { typedef T type; }; // SFINAE type trait to detect whether T::const_iterator exists. template struct has_const_iterator { private: typedef char yes; typedef struct { char array[2]; } no; template static yes test(typename C::const_iterator*); template static no test(...); public: static const bool value = sizeof(test(0)) == sizeof(yes); typedef T type; }; // SFINAE type trait to detect whether "T::const_iterator T::begin/end() const" exist. template struct has_begin_end { struct Dummy { typedef void const_iterator; }; typedef typename conditional::value, T, Dummy>::type TType; typedef typename TType::const_iterator iter; struct Fallback { iter begin() const; iter end() const; }; struct Derived : TType, Fallback { }; template struct ChT; template static char (&f(ChT*))[1]; template static char (&f(...))[2]; template static char (&g(ChT*))[1]; template static char (&g(...))[2]; static bool const beg_value = sizeof(f(0)) == 2; static bool const end_value = sizeof(g(0)) == 2; }; // Basic is_container template; specialize to have value "true" for all desired container types template struct is_container { static const bool value = has_const_iterator::value && has_begin_end::beg_value && has_begin_end::end_value; }; template struct is_container { static const bool value = true; }; template struct is_container { static const bool value = false; }; // Holds the delimiter values for a specific character type template struct delimiters_values { typedef TChar char_type; const TChar * prefix; const TChar * delimiter; const TChar * postfix; }; // Defines the delimiter values for a specific container and character type template struct delimiters { typedef delimiters_values type; static const type values; }; // Default delimiters template struct delimiters { static const delimiters_values values; }; template const delimiters_values delimiters::values = { "[", ", ", "]" }; template struct delimiters { static const delimiters_values values; }; template const delimiters_values delimiters::values = { L"[", L", ", L"]" }; // Delimiters for (multi)set and unordered_(multi)set template struct delimiters< ::std::set, char> { static const delimiters_values values; }; template const delimiters_values delimiters< ::std::set, char>::values = { "{", ", ", "}" }; template struct delimiters< ::std::set, wchar_t> { static const delimiters_values values; }; template const delimiters_values delimiters< ::std::set, wchar_t>::values = { L"{", L", ", L"}" }; template struct delimiters< ::std::multiset, char> { static const delimiters_values values; }; template const delimiters_values delimiters< ::std::multiset, char>::values = { "{", ", ", "}" }; template struct delimiters< ::std::multiset, wchar_t> { static const delimiters_values values; }; template const delimiters_values delimiters< ::std::multiset, wchar_t>::values = { L"{", L", ", L"}" }; #ifndef NO_TR1 template struct delimiters< ::std::tr1::unordered_set, char> { static const delimiters_values values; }; template const delimiters_values delimiters< ::std::tr1::unordered_set, char>::values = { "{", ", ", "}" }; template struct delimiters< ::std::tr1::unordered_set, wchar_t> { static const delimiters_values values; }; template const delimiters_values delimiters< ::std::tr1::unordered_set, wchar_t>::values = { L"{", L", ", L"}" }; template struct delimiters< ::std::tr1::unordered_multiset, char> { static const delimiters_values values; }; template const delimiters_values delimiters< ::std::tr1::unordered_multiset, char>::values = { "{", ", ", "}" }; template struct delimiters< ::std::tr1::unordered_multiset, wchar_t> { static const delimiters_values values; }; template const delimiters_values delimiters< ::std::tr1::unordered_multiset, wchar_t>::values = { L"{", L", ", L"}" }; #endif // Delimiters for pair (reused for tuple, see below) template struct delimiters< ::std::pair, char> { static const delimiters_values values; }; template const delimiters_values delimiters< ::std::pair, char>::values = { "(", ", ", ")" }; template struct delimiters< ::std::pair, wchar_t> { static const delimiters_values values; }; template const delimiters_values delimiters< ::std::pair, wchar_t>::values = { L"(", L", ", L")" }; // Iterator microtrait class to handle C arrays uniformly template struct get_iterator { typedef typename T::const_iterator iter; }; template struct get_iterator { typedef const T * iter; }; template typename enable_if::value, typename T::const_iterator>::type begin(const T & c) { return c.begin(); } template typename enable_if::value, typename T::const_iterator>::type end(const T & c) { return c.end(); } template const T * begin(const T(&x)[N]) { return &x[0]; } template const T * end (const T(&x)[N]) { return &x[0] + N; } // Functor to print containers. You can use this directly if you want to specificy a non-default delimiters type. template, typename TDelimiters = delimiters > struct print_container_helper { typedef TChar char_type; typedef TDelimiters delimiters_type; typedef std::basic_ostream ostream_type; typedef typename get_iterator::iter TIter; print_container_helper(const T & container) : _container(container) { } inline void operator()(ostream_type & stream) const { if (delimiters_type::values.prefix != NULL) stream << delimiters_type::values.prefix; if (begin(_container) != end(_container)) for (TIter it = begin(_container), it_end = end(_container); ; ) { stream << *it; if (++it == it_end) break; if (delimiters_type::values.delimiter != NULL) stream << delimiters_type::values.delimiter; } if (delimiters_type::values.postfix != NULL) stream << delimiters_type::values.postfix; } private: const T & _container; }; // Type-erasing helper class for easy use of custom delimiters. // Requires TCharTraits = std::char_traits and TChar = char or wchar_t, and MyDelims needs to be defined for TChar. // Usage: "cout << pretty_print::custom_delims(x)". struct custom_delims_base { virtual ~custom_delims_base() { } virtual ::std::ostream & stream(::std::ostream &) = 0; virtual ::std::wostream & stream(::std::wostream &) = 0; }; template struct custom_delims_wrapper : public custom_delims_base { custom_delims_wrapper(const T & t_) : t(t_) { } ::std::ostream & stream(::std::ostream & s) { return s << ::pretty_print::print_container_helper, Delims>(t); } ::std::wostream & stream(::std::wostream & s) { return s << ::pretty_print::print_container_helper, Delims>(t); } private: const T & t; }; template struct custom_delims { template custom_delims(const Container & c) : base(new custom_delims_wrapper(c)) { } ~custom_delims() { delete base; } custom_delims_base * base; }; } // namespace pretty_print template inline std::basic_ostream & operator<<(std::basic_ostream & s, const pretty_print::custom_delims & p) { return p.base->stream(s); } // Template aliases for char and wchar_t delimiters // Enable these if you have compiler support // // Implement as "template const sdelims::type sdelims>::values = { ... }." //template using pp_sdelims = pretty_print::delimiters; //template using pp_wsdelims = pretty_print::delimiters; namespace std { // Prints a print_container_helper to the specified stream. template inline basic_ostream & operator<<(basic_ostream & stream, const ::pretty_print::print_container_helper & helper) { helper(stream); return stream; } // Prints a container to the stream using default delimiters template inline typename ::pretty_print::enable_if< ::pretty_print::is_container::value, basic_ostream&>::type operator<<(basic_ostream & stream, const T & container) { return stream << ::pretty_print::print_container_helper(container); } // Prints a pair to the stream using delimiters from delimiters>. template inline basic_ostream & operator<<(basic_ostream & stream, const pair & value) { if (::pretty_print::delimiters, TChar>::values.prefix != NULL) stream << ::pretty_print::delimiters, TChar>::values.prefix; stream << value.first; if (::pretty_print::delimiters, TChar>::values.delimiter != NULL) stream << ::pretty_print::delimiters, TChar>::values.delimiter; stream << value.second; if (::pretty_print::delimiters, TChar>::values.postfix != NULL) stream << ::pretty_print::delimiters, TChar>::values.postfix; return stream; } } // namespace std #ifndef NO_TR1 // Prints a tuple to the stream using delimiters from delimiters>. namespace pretty_print { struct tuple_dummy_t { }; // Just if you want special delimiters for tuples. typedef std::pair tuple_dummy_pair; template struct pretty_tuple_helper { static inline void print(::std::basic_ostream & stream, const Tuple & value) { pretty_tuple_helper::print(stream, value); if (delimiters::values.delimiter != NULL) stream << delimiters::values.delimiter; stream << std::tr1::get(value); } }; template struct pretty_tuple_helper { static inline void print(::std::basic_ostream & stream, const Tuple & value) { stream << ::std::tr1::get<0>(value); } }; } // namespace pretty_print /* The following macros allow us to write "template std::tuple" * uniformly in C++0x compilers and in MS Visual Studio 2010. * Credits to STL: http://channel9.msdn.com/Shows/Going+Deep/C9-Lectures-Stephan-T-Lavavej-Advanced-STL-6-of-n */ #define TUPLE_PARAMS \ typename T0, typename T1, typename T2, typename T3, typename T4, \ typename T5, typename T6, typename T7, typename T8, typename T9 #define TUPLE_ARGS T0, T1, T2, T3, T4, T5, T6, T7, T8, T9 namespace std { template inline basic_ostream & operator<<(basic_ostream & stream, const tr1::tuple & value) { if (::pretty_print::delimiters< ::pretty_print::tuple_dummy_pair, TChar>::values.prefix != NULL) stream << ::pretty_print::delimiters< ::pretty_print::tuple_dummy_pair, TChar>::values.prefix; ::pretty_print::pretty_tuple_helper &, tr1::tuple_size >::value, TChar, TCharTraits>::print(stream, value); if (::pretty_print::delimiters< ::pretty_print::tuple_dummy_pair, TChar>::values.postfix != NULL) stream << ::pretty_print::delimiters< ::pretty_print::tuple_dummy_pair, TChar>::values.postfix; return stream; } } // namespace std #endif // NO_TR1 // A wrapper for raw C-style arrays. Usage: int arr[] = { 1, 2, 4, 8, 16 }; std::cout << wrap_array(arr) << ... namespace pretty_print { template 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; }; } // namespace pretty_print template inline pretty_print::array_wrapper_n pretty_print_array(const T * const a, size_t n) { return pretty_print::array_wrapper_n(a, n); } #endif