// 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) // // A pretty printing library for C++ // // The global operator<< overload hs been removed #ifndef SOI_HEADER_PRETTY_PRINT #define SOI_HEADER_PRETTY_PRINT #include #include #include #include #include #include #include #include #include #include namespace soi { namespace prettyprint { template std::basic_ostream & print(std::basic_ostream &stream, const T &x); namespace detail { // SFINAE type trait to detect whether T::const_iterator exists. struct sfinae_base { using yes = char; using no = yes[2]; }; template struct has_const_iterator : private sfinae_base { private: template static yes &test(typename C::const_iterator *); template static no &test(...); public: static const bool value = sizeof(test(nullptr)) == sizeof(yes); using type = T; }; template struct has_begin_end : private sfinae_base { private: template static yes & f(typename std::enable_if< std::is_same(&C::begin)), typename C::const_iterator (C::*)() const>::value>::type *); template static no &f(...); template static yes & g(typename std::enable_if< std::is_same(&C::end)), typename C::const_iterator (C::*)() const>::value, void>::type *); template static no &g(...); public: static bool const beg_value = sizeof(f(nullptr)) == sizeof(yes); static bool const end_value = sizeof(g(nullptr)) == sizeof(yes); }; } // namespace detail // Holds the delimiter values for a specific character type template 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 struct delimiters { using type = delimiters_values; 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 TDelimiters = delimiters> struct pretty_print_container_helper { using delimiters_type = TDelimiters; using ostream_type = std::basic_ostream; template struct pretty_printer { static void pretty_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 (;;) { ::soi::prettyprint::print(stream, *it); if (++it == the_end) break; if (delimiters_type::values.delimiter != NULL) ::soi::prettyprint::print(stream, delimiters_type::values.delimiter); } } } }; pretty_print_container_helper(const T &container) : container_(container) {} inline void operator()(ostream_type &stream) const { if (delimiters_type::values.prefix != NULL) ::soi::prettyprint::print(stream, delimiters_type::values.prefix); pretty_printer::pretty_print_body(container_, stream); if (delimiters_type::values.postfix != NULL) ::soi::prettyprint::print(stream, delimiters_type::values.postfix); } private: const T &container_; }; // Specialization for pairs template template struct pretty_print_container_helper< T, TChar, TCharTraits, TDelimiters>::pretty_printer> { using ostream_type = typename pretty_print_container_helper::ostream_type; static void pretty_print_body(const std::pair &c, ostream_type &stream) { ::soi::prettyprint::print(stream, c.first); if (pretty_print_container_helper::delimiters_type::values .delimiter != NULL) ::soi::prettyprint::print( stream, pretty_print_container_helper::delimiters_type::values .delimiter); ::soi::prettyprint::print(stream, c.second); } }; // Specialization for tuples template template struct pretty_print_container_helper< T, TChar, TCharTraits, TDelimiters>::pretty_printer> { using ostream_type = typename pretty_print_container_helper::ostream_type; using element_type = std::tuple; template 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) {} static void tuple_pretty_print(const element_type &c, ostream_type &stream, typename std::conditional, std::nullptr_t>::type) { ::soi::prettyprint::print(stream, std::get<0>(c)); tuple_pretty_print(c, stream, Int<1>()); } template static void tuple_pretty_print(const element_type &c, ostream_type &stream, Int) { if (pretty_print_container_helper::delimiters_type::values .delimiter != NULL) ::soi::prettyprint::print( stream, pretty_print_container_helper::delimiters_type::values .delimiter); ::soi::prettyprint::print(stream, std::get(c)); tuple_pretty_print(c, stream, Int()); } }; // Pretty_Prints a pretty_print_container_helper to the specified stream. template inline std::basic_ostream & pretty_print(std::basic_ostream &stream, const pretty_print_container_helper &helper) { helper(stream); return stream; } // Basic is_container template; specialize to derive from std::true_type for all // desired container types template struct is_container : public std::integral_constant::value && detail::has_begin_end::beg_value && detail::has_begin_end::end_value> {}; template struct is_container : std::true_type {}; template struct is_container : std::false_type {}; template struct is_container> : std::true_type {}; template struct is_container> : std::true_type {}; template struct is_container> : std::true_type {}; // 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"}"}; template struct delimiters<::std::unordered_set, char> { static const delimiters_values values; }; template const delimiters_values delimiters< ::std::unordered_set, char>::values = { "{", ", ", "}"}; template struct delimiters<::std::unordered_set, wchar_t> { static const delimiters_values values; }; template const delimiters_values delimiters< ::std::unordered_set, wchar_t>::values = { L"{", L", ", L"}"}; template struct delimiters<::std::unordered_multiset, char> { static const delimiters_values values; }; template const delimiters_values delimiters< ::std::unordered_multiset, char>::values = { "{", ", ", "}"}; template struct delimiters<::std::unordered_multiset, wchar_t> { static const delimiters_values values; }; template const delimiters_values delimiters<::std::unordered_multiset, wchar_t>::values = {L"{", L", ", L"}"}; // Delimiters for pair and tuple template struct delimiters, char> { static const delimiters_values values; }; template const delimiters_values delimiters, 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")"}; template struct delimiters, char> { static const delimiters_values values; }; template const delimiters_values delimiters, char>::values = { "(", ", ", ")"}; template struct delimiters<::std::tuple, wchar_t> { static const delimiters_values values; }; template const delimiters_values delimiters<::std::tuple, wchar_t>::values = {L"(", L", ", L")"}; // 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_prettyprint::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 : custom_delims_base { custom_delims_wrapper(const T &t_) : t(t_) {} std::ostream &stream(std::ostream &s) { return pretty_print( s, pretty_print_container_helper, Delims>( t)); } std::wostream &stream(std::wostream &s) { return pretty_print( s, pretty_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)) {} std::unique_ptr base; }; template inline std::basic_ostream & pretty_print(std::basic_ostream &s, const custom_delims &p) { return p.base->stream(s); } // A wrapper for a C-style array given as pointer-plus-size. // Usage: std::cout << pretty_pretty_print_array(arr, n) << std::endl; 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; }; // 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 struct bucket_pretty_print_wrapper { typedef typename T::const_local_iterator const_iterator; typedef typename T::size_type size_type; const_iterator begin() const { return m_map.cbegin(n); } const_iterator end() const { return m_map.cend(n); } bucket_pretty_print_wrapper(const T &m, size_type bucket) : m_map(m), n(bucket) {} private: const T &m_map; const size_type n; }; /* // Global accessor functions for the convenience wrappers template inline pretty_prettyprint::array_wrapper_n pretty_pretty_print_array(const T * const a, size_t n) { return pretty_prettyprint::array_wrapper_n(a, n); } template pretty_prettyprint::bucket_pretty_print_wrapper bucket_pretty_print(const T & m, typename T::size_type n) { return pretty_prettyprint::bucket_pretty_print_wrapper(m, n); } // Main magic entry point: An overload snuck into namespace std. // Can we do better? */ template inline typename std::enable_if<::soi::prettyprint::is_container::value, std::basic_ostream &>::type pretty_print(std::basic_ostream &stream, const T &container) { return ::soi::prettyprint::print( stream, ::soi::prettyprint::pretty_print_container_helper(container)); } }// namespace prettyprint } // namespace soi #endif // SOI_HEADER_PRETTY_PRETTY_PRINT