rivet is hosted by Hepforge, IPPP Durham
PrettyPrint.hh
Go to the documentation of this file.
00001 //          Copyright Louis Delacroix 2010 - 2014.
00002 // Distributed under the Boost Software License, Version 1.0.
00003 //    (See accompanying file LICENSE_1_0.txt or copy at
00004 //          http://www.boost.org/LICENSE_1_0.txt)
00005 //
00006 // A pretty printing library for C++
00007 //
00008 // Usage:
00009 // Include this header, and operator<< will "just work".
00010 //
00011 // See: https://louisdx.github.io/cxx-prettyprint/
00012 
00013 #ifndef H_PRETTY_PRINT
00014 #define H_PRETTY_PRINT
00015 
00016 #include <cstddef>
00017 #include <iterator>
00018 #include <memory>
00019 #include <ostream>
00020 #include <set>
00021 #include <tuple>
00022 #include <type_traits>
00023 #include <unordered_set>
00024 #include <utility>
00025 #include <valarray>
00026 
00027 namespace Rivet
00028 {
00029 namespace pretty_print
00030 {
00031     namespace detail
00032     {
00033         // SFINAE type trait to detect whether T::const_iterator exists.
00034 
00035         struct sfinae_base
00036         {
00037             using yes = char;
00038             using no  = yes[2];
00039         };
00040 
00041         template <typename T>
00042         struct has_const_iterator : private sfinae_base
00043         {
00044         private:
00045             template <typename C> static yes & test(typename C::const_iterator*);
00046             template <typename C> static no  & test(...);
00047         public:
00048             static const bool value = sizeof(test<T>(nullptr)) == sizeof(yes);
00049             using type =  T;
00050         };
00051 
00052         template <typename T>
00053         struct has_begin_end : private sfinae_base
00054         {
00055         private:
00056             template <typename C>
00057             static yes & f(typename std::enable_if<
00058                 std::is_same<decltype(static_cast<typename C::const_iterator(C::*)() const>(&C::begin)),
00059                              typename C::const_iterator(C::*)() const>::value>::type *);
00060 
00061             template <typename C> static no & f(...);
00062 
00063             template <typename C>
00064             static yes & g(typename std::enable_if<
00065                 std::is_same<decltype(static_cast<typename C::const_iterator(C::*)() const>(&C::end)),
00066                              typename C::const_iterator(C::*)() const>::value, void>::type*);
00067 
00068             template <typename C> static no & g(...);
00069 
00070         public:
00071             static bool const beg_value = sizeof(f<T>(nullptr)) == sizeof(yes);
00072             static bool const end_value = sizeof(g<T>(nullptr)) == sizeof(yes);
00073         };
00074 
00075     }  // namespace detail
00076 
00077 
00078     // Holds the delimiter values for a specific character type
00079 
00080     template <typename TChar>
00081     struct delimiters_values
00082     {
00083         using char_type = TChar;
00084         const char_type * prefix;
00085         const char_type * delimiter;
00086         const char_type * postfix;
00087     };
00088 
00089 
00090     // Defines the delimiter values for a specific container and character type
00091 
00092     template <typename T, typename TChar>
00093     struct delimiters
00094     {
00095         using type = delimiters_values<TChar>;
00096         static const type values;
00097     };
00098 
00099 
00100     // Functor to print containers. You can use this directly if you want
00101     // to specificy a non-default delimiters type. The printing logic can
00102     // be customized by specializing the nested template.
00103 
00104     template <typename T,
00105               typename TChar = char,
00106               typename TCharTraits = ::std::char_traits<TChar>,
00107               typename TDelimiters = delimiters<T, TChar>>
00108     struct print_container_helper
00109     {
00110         using delimiters_type = TDelimiters;
00111         using ostream_type = std::basic_ostream<TChar, TCharTraits>;
00112 
00113         template <typename U>
00114         struct printer
00115         {
00116             static void print_body(const U & c, ostream_type & stream)
00117             {
00118                 using std::begin;
00119                 using std::end;
00120 
00121                 auto it = begin(c);
00122                 const auto the_end = end(c);
00123 
00124                 if (it != the_end)
00125                 {
00126                     for ( ; ; )
00127                     {
00128                         stream << *it;
00129 
00130                     if (++it == the_end) break;
00131 
00132                     if (delimiters_type::values.delimiter != NULL)
00133                         stream << delimiters_type::values.delimiter;
00134                     }
00135                 }
00136             }
00137         };
00138 
00139         print_container_helper(const T & container)
00140         : container_(container)
00141         { }
00142 
00143         inline void operator()(ostream_type & stream) const
00144         {
00145             if (delimiters_type::values.prefix != NULL)
00146                 stream << delimiters_type::values.prefix;
00147 
00148             printer<T>::print_body(container_, stream);
00149 
00150             if (delimiters_type::values.postfix != NULL)
00151                 stream << delimiters_type::values.postfix;
00152         }
00153 
00154     private:
00155         const T & container_;
00156     };
00157 
00158     // Specialization for pairs
00159 
00160     template <typename T, typename TChar, typename TCharTraits, typename TDelimiters>
00161     template <typename T1, typename T2>
00162     struct print_container_helper<T, TChar, TCharTraits, TDelimiters>::printer<std::pair<T1, T2>>
00163     {
00164         using ostream_type = typename print_container_helper<T, TChar, TCharTraits, TDelimiters>::ostream_type;
00165 
00166         static void print_body(const std::pair<T1, T2> & c, ostream_type & stream)
00167         {
00168             stream << c.first;
00169             if (print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter != NULL)
00170                 stream << print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter;
00171             stream << c.second;
00172         }
00173     };
00174 
00175     // Specialization for tuples
00176 
00177     template <typename T, typename TChar, typename TCharTraits, typename TDelimiters>
00178     template <typename ...Args>
00179     struct print_container_helper<T, TChar, TCharTraits, TDelimiters>::printer<std::tuple<Args...>>
00180     {
00181         using ostream_type = typename print_container_helper<T, TChar, TCharTraits, TDelimiters>::ostream_type;
00182         using element_type = std::tuple<Args...>;
00183 
00184         template <std::size_t I> struct Int { };
00185 
00186         static void print_body(const element_type & c, ostream_type & stream)
00187         {
00188             tuple_print(c, stream, Int<0>());
00189         }
00190 
00191         static void tuple_print(const element_type &, ostream_type &, Int<sizeof...(Args)>)
00192         {
00193         }
00194 
00195         static void tuple_print(const element_type & c, ostream_type & stream,
00196                                 typename std::conditional<sizeof...(Args) != 0, Int<0>, std::nullptr_t>::type)
00197         {
00198             stream << std::get<0>(c);
00199             tuple_print(c, stream, Int<1>());
00200         }
00201 
00202         template <std::size_t N>
00203         static void tuple_print(const element_type & c, ostream_type & stream, Int<N>)
00204         {
00205             if (print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter != NULL)
00206                 stream << print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter;
00207 
00208             stream << std::get<N>(c);
00209 
00210             tuple_print(c, stream, Int<N + 1>());
00211         }
00212     };
00213 
00214     // Prints a print_container_helper to the specified stream.
00215 
00216     template<typename T, typename TChar, typename TCharTraits, typename TDelimiters>
00217     inline std::basic_ostream<TChar, TCharTraits> & operator<<(
00218         std::basic_ostream<TChar, TCharTraits> & stream,
00219         const print_container_helper<T, TChar, TCharTraits, TDelimiters> & helper)
00220     {
00221         helper(stream);
00222         return stream;
00223     }
00224 
00225 
00226     // Basic is_container template; specialize to derive from std::true_type for all desired container types
00227 
00228     template <typename T>
00229     struct is_container : public std::integral_constant<bool,
00230                                                         detail::has_const_iterator<T>::value &&
00231                                                         detail::has_begin_end<T>::beg_value  &&
00232                                                         detail::has_begin_end<T>::end_value> { };
00233 
00234     template <typename T, std::size_t N>
00235     struct is_container<T[N]> : std::true_type { };
00236 
00237     template <std::size_t N>
00238     struct is_container<char[N]> : std::false_type { };
00239 
00240     template <typename T>
00241     struct is_container<std::valarray<T>> : std::true_type { };
00242 
00243     template <typename T1, typename T2>
00244     struct is_container<std::pair<T1, T2>> : std::true_type { };
00245 
00246     template <typename ...Args>
00247     struct is_container<std::tuple<Args...>> : std::true_type { };
00248 
00249 
00250     // Default delimiters
00251 
00252     template <typename T> struct delimiters<T, char> { static const delimiters_values<char> values; };
00253     template <typename T> const delimiters_values<char> delimiters<T, char>::values = { "[", ", ", "]" };
00254     template <typename T> struct delimiters<T, wchar_t> { static const delimiters_values<wchar_t> values; };
00255     template <typename T> const delimiters_values<wchar_t> delimiters<T, wchar_t>::values = { L"[", L", ", L"]" };
00256 
00257 
00258     // Delimiters for (multi)set and unordered_(multi)set
00259 
00260     template <typename T, typename TComp, typename TAllocator>
00261     struct delimiters< ::std::set<T, TComp, TAllocator>, char> { static const delimiters_values<char> values; };
00262 
00263     template <typename T, typename TComp, typename TAllocator>
00264     const delimiters_values<char> delimiters< ::std::set<T, TComp, TAllocator>, char>::values = { "{", ", ", "}" };
00265 
00266     template <typename T, typename TComp, typename TAllocator>
00267     struct delimiters< ::std::set<T, TComp, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; };
00268 
00269     template <typename T, typename TComp, typename TAllocator>
00270     const delimiters_values<wchar_t> delimiters< ::std::set<T, TComp, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
00271 
00272     template <typename T, typename TComp, typename TAllocator>
00273     struct delimiters< ::std::multiset<T, TComp, TAllocator>, char> { static const delimiters_values<char> values; };
00274 
00275     template <typename T, typename TComp, typename TAllocator>
00276     const delimiters_values<char> delimiters< ::std::multiset<T, TComp, TAllocator>, char>::values = { "{", ", ", "}" };
00277 
00278     template <typename T, typename TComp, typename TAllocator>
00279     struct delimiters< ::std::multiset<T, TComp, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; };
00280 
00281     template <typename T, typename TComp, typename TAllocator>
00282     const delimiters_values<wchar_t> delimiters< ::std::multiset<T, TComp, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
00283 
00284     template <typename T, typename THash, typename TEqual, typename TAllocator>
00285     struct delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, char> { static const delimiters_values<char> values; };
00286 
00287     template <typename T, typename THash, typename TEqual, typename TAllocator>
00288     const delimiters_values<char> delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, char>::values = { "{", ", ", "}" };
00289 
00290     template <typename T, typename THash, typename TEqual, typename TAllocator>
00291     struct delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; };
00292 
00293     template <typename T, typename THash, typename TEqual, typename TAllocator>
00294     const delimiters_values<wchar_t> delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
00295 
00296     template <typename T, typename THash, typename TEqual, typename TAllocator>
00297     struct delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, char> { static const delimiters_values<char> values; };
00298 
00299     template <typename T, typename THash, typename TEqual, typename TAllocator>
00300     const delimiters_values<char> delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, char>::values = { "{", ", ", "}" };
00301 
00302     template <typename T, typename THash, typename TEqual, typename TAllocator>
00303     struct delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; };
00304 
00305     template <typename T, typename THash, typename TEqual, typename TAllocator>
00306     const delimiters_values<wchar_t> delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
00307 
00308 
00309     // Delimiters for pair and tuple
00310 
00311     template <typename T1, typename T2> struct delimiters<std::pair<T1, T2>, char> { static const delimiters_values<char> values; };
00312     template <typename T1, typename T2> const delimiters_values<char> delimiters<std::pair<T1, T2>, char>::values = { "(", ", ", ")" };
00313     template <typename T1, typename T2> struct delimiters< ::std::pair<T1, T2>, wchar_t> { static const delimiters_values<wchar_t> values; };
00314     template <typename T1, typename T2> const delimiters_values<wchar_t> delimiters< ::std::pair<T1, T2>, wchar_t>::values = { L"(", L", ", L")" };
00315 
00316     template <typename ...Args> struct delimiters<std::tuple<Args...>, char> { static const delimiters_values<char> values; };
00317     template <typename ...Args> const delimiters_values<char> delimiters<std::tuple<Args...>, char>::values = { "(", ", ", ")" };
00318     template <typename ...Args> struct delimiters< ::std::tuple<Args...>, wchar_t> { static const delimiters_values<wchar_t> values; };
00319     template <typename ...Args> const delimiters_values<wchar_t> delimiters< ::std::tuple<Args...>, wchar_t>::values = { L"(", L", ", L")" };
00320 
00321 
00322     // Type-erasing helper class for easy use of custom delimiters.
00323     // Requires TCharTraits = std::char_traits<TChar> and TChar = char or wchar_t, and MyDelims needs to be defined for TChar.
00324     // Usage: "cout << pretty_print::custom_delims<MyDelims>(x)".
00325 
00326     struct custom_delims_base
00327     {
00328         virtual ~custom_delims_base() { }
00329         virtual std::ostream & stream(::std::ostream &) = 0;
00330         virtual std::wostream & stream(::std::wostream &) = 0;
00331     };
00332 
00333     template <typename T, typename Delims>
00334     struct custom_delims_wrapper : custom_delims_base
00335     {
00336         custom_delims_wrapper(const T & t_) : t(t_) { }
00337 
00338         std::ostream & stream(std::ostream & s)
00339         {
00340             return s << print_container_helper<T, char, std::char_traits<char>, Delims>(t);
00341         }
00342 
00343         std::wostream & stream(std::wostream & s)
00344         {
00345             return s << print_container_helper<T, wchar_t, std::char_traits<wchar_t>, Delims>(t);
00346         }
00347 
00348     private:
00349         const T & t;
00350     };
00351 
00352     template <typename Delims>
00353     struct custom_delims
00354     {
00355         template <typename Container>
00356         custom_delims(const Container & c) : base(new custom_delims_wrapper<Container, Delims>(c)) { }
00357 
00358         std::unique_ptr<custom_delims_base> base;
00359     };
00360 
00361     template <typename TChar, typename TCharTraits, typename Delims>
00362     inline std::basic_ostream<TChar, TCharTraits> & operator<<(std::basic_ostream<TChar, TCharTraits> & s, const custom_delims<Delims> & p)
00363     {
00364         return p.base->stream(s);
00365     }
00366 
00367 
00368     // A wrapper for a C-style array given as pointer-plus-size.
00369     // Usage: std::cout << pretty_print_array(arr, n) << std::endl;
00370 
00371     template<typename T>
00372     struct array_wrapper_n
00373     {
00374         typedef const T * const_iterator;
00375         typedef T value_type;
00376 
00377         array_wrapper_n(const T * const a, size_t n) : _array(a), _n(n) { }
00378         inline const_iterator begin() const { return _array; }
00379         inline const_iterator end() const { return _array + _n; }
00380 
00381     private:
00382         const T * const _array;
00383         size_t _n;
00384     };
00385 
00386 
00387     // A wrapper for hash-table based containers that offer local iterators to each bucket.
00388     // Usage: std::cout << bucket_print(m, 4) << std::endl;  (Prints bucket 5 of container m.)
00389 
00390     template <typename T>
00391     struct bucket_print_wrapper
00392     {
00393         typedef typename T::const_local_iterator const_iterator;
00394         typedef typename T::size_type size_type;
00395 
00396         const_iterator begin() const
00397         {
00398             return m_map.cbegin(n);
00399         }
00400 
00401         const_iterator end() const
00402         {
00403             return m_map.cend(n);
00404         }
00405 
00406         bucket_print_wrapper(const T & m, size_type bucket) : m_map(m), n(bucket) { }
00407 
00408     private:
00409         const T & m_map;
00410         const size_type n;
00411     };
00412 
00413 }   // namespace pretty_print
00414 
00415 
00416 // Global accessor functions for the convenience wrappers
00417 
00418 template<typename T>
00419 inline pretty_print::array_wrapper_n<T> pretty_print_array(const T * const a, size_t n)
00420 {
00421     return pretty_print::array_wrapper_n<T>(a, n);
00422 }
00423 
00424 template <typename T> pretty_print::bucket_print_wrapper<T>
00425 bucket_print(const T & m, typename T::size_type n)
00426 {
00427     return pretty_print::bucket_print_wrapper<T>(m, n);
00428 }
00429 
00430 
00431 } // namespace Rivet
00432 
00433 
00434 
00435 // Main magic entry point: An overload snuck into namespace std.
00436 // Can we do better?
00437 
00438 namespace std
00439 {
00440 
00441 // Prints a container to the stream using default delimiters
00442 template<typename T, typename TChar, typename TCharTraits>
00443 inline typename enable_if< ::Rivet::pretty_print::is_container<T>::value,
00444                           basic_ostream<TChar, TCharTraits> &>::type
00445 operator<<(std::basic_ostream<TChar, TCharTraits> & stream, const T & container)
00446 {
00447   return stream << ::Rivet::pretty_print::print_container_helper<T, TChar, TCharTraits>(container);
00448 }
00449 
00450 }
00451 
00452 
00453 
00454 #endif  // H_PRETTY_PRINT