pretty_print.hpp
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 // Original source code found here: https://github.com/louisdx/cxx-prettyprint
00006 
00007 #ifndef H_PRETTY_PRINT
00008 #define H_PRETTY_PRINT
00009 
00010 #include <ostream>
00011 #include <utility>
00012 #include <iterator>
00013 #include <set>
00014 
00015 #ifndef NO_TR1
00016 #include <tr1/tuple>
00017 #include <tr1/unordered_set>
00018 #endif
00019 
00020 namespace pretty_print
00021 {
00022 template <bool, typename S, typename T>
00023 struct conditional
00024 {
00025 };
00026 template <typename S, typename T>
00027 struct conditional<true, S, T>
00028 {
00029   typedef S type;
00030 };
00031 template <typename S, typename T>
00032 struct conditional<false, S, T>
00033 {
00034   typedef T type;
00035 };
00036 
00037 template <bool, typename T>
00038 struct enable_if
00039 {
00040 };
00041 template <typename T>
00042 struct enable_if<true, T>
00043 {
00044   typedef T type;
00045 };
00046 
00047 // SFINAE type trait to detect whether T::const_iterator exists.
00048 
00049 template <typename T>
00050 struct has_const_iterator
00051 {
00052 private:
00053   typedef char yes;
00054   typedef struct
00055   {
00056     char array[2];
00057   } no;
00058 
00059   template <typename C>
00060   static yes test(typename C::const_iterator *);
00061   template <typename C>
00062   static no test(...);
00063 
00064 public:
00065   static const bool value = sizeof(test<T>(0)) == sizeof(yes);
00066   typedef T type;
00067 };
00068 
00069 // SFINAE type trait to detect whether "T::const_iterator T::begin/end() const" exist.
00070 
00071 template <typename T>
00072 struct has_begin_end
00073 {
00074   struct Dummy
00075   {
00076     typedef void const_iterator;
00077   };
00078   typedef typename conditional<has_const_iterator<T>::value, T, Dummy>::type TType;
00079   typedef typename TType::const_iterator iter;
00080 
00081   struct Fallback
00082   {
00083     iter begin() const;
00084     iter end() const;
00085   };
00086   struct Derived : TType, Fallback
00087   {
00088   };
00089 
00090   template <typename C, C>
00091   struct ChT;
00092 
00093   template <typename C>
00094   static char(&f(ChT<iter (Fallback::*)() const, &C::begin> *))[1];
00095   template <typename C>
00096   static char(&f(...))[2];
00097   template <typename C>
00098   static char(&g(ChT<iter (Fallback::*)() const, &C::end> *))[1];
00099   template <typename C>
00100   static char(&g(...))[2];
00101 
00102   static bool const beg_value = sizeof(f<Derived>(0)) == 2;
00103   static bool const end_value = sizeof(g<Derived>(0)) == 2;
00104 };
00105 
00106 // Basic is_container template; specialize to have value "true" for all desired container types
00107 
00108 template <typename T>
00109 struct is_container
00110 {
00111   static const bool value = has_const_iterator<T>::value && has_begin_end<T>::beg_value && has_begin_end<T>::end_value;
00112 };
00113 
00114 template <typename T, std::size_t N>
00115 struct is_container<T[N]>
00116 {
00117   static const bool value = true;
00118 };
00119 
00120 template <std::size_t N>
00121 struct is_container<char[N]>
00122 {
00123   static const bool value = false;
00124 };
00125 
00126 // Holds the delimiter values for a specific character type
00127 
00128 template <typename TChar>
00129 struct delimiters_values
00130 {
00131   typedef TChar char_type;
00132   const TChar *prefix;
00133   const TChar *delimiter;
00134   const TChar *postfix;
00135 };
00136 
00137 // Defines the delimiter values for a specific container and character type
00138 
00139 template <typename T, typename TChar>
00140 struct delimiters
00141 {
00142   typedef delimiters_values<TChar> type;
00143   static const type values;
00144 };
00145 
00146 // Default delimiters
00147 
00148 template <typename T>
00149 struct delimiters<T, char>
00150 {
00151   static const delimiters_values<char> values;
00152 };
00153 template <typename T>
00154 const delimiters_values<char> delimiters<T, char>::values = { "[", ", ", "]" };
00155 template <typename T>
00156 struct delimiters<T, wchar_t>
00157 {
00158   static const delimiters_values<wchar_t> values;
00159 };
00160 template <typename T>
00161 const delimiters_values<wchar_t> delimiters<T, wchar_t>::values = { L"[", L", ", L"]" };
00162 
00163 // Delimiters for (multi)set and unordered_(multi)set
00164 
00165 template <typename T, typename TComp, typename TAllocator>
00166 struct delimiters< ::std::set<T, TComp, TAllocator>, char>
00167 {
00168   static const delimiters_values<char> values;
00169 };
00170 
00171 template <typename T, typename TComp, typename TAllocator>
00172 const delimiters_values<char> delimiters< ::std::set<T, TComp, TAllocator>, char>::values = { "{", ", ", "}" };
00173 
00174 template <typename T, typename TComp, typename TAllocator>
00175 struct delimiters< ::std::set<T, TComp, TAllocator>, wchar_t>
00176 {
00177   static const delimiters_values<wchar_t> values;
00178 };
00179 
00180 template <typename T, typename TComp, typename TAllocator>
00181 const delimiters_values<wchar_t> delimiters< ::std::set<T, TComp, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
00182 
00183 template <typename T, typename TComp, typename TAllocator>
00184 struct delimiters< ::std::multiset<T, TComp, TAllocator>, char>
00185 {
00186   static const delimiters_values<char> values;
00187 };
00188 
00189 template <typename T, typename TComp, typename TAllocator>
00190 const delimiters_values<char> delimiters< ::std::multiset<T, TComp, TAllocator>, char>::values = { "{", ", ", "}" };
00191 
00192 template <typename T, typename TComp, typename TAllocator>
00193 struct delimiters< ::std::multiset<T, TComp, TAllocator>, wchar_t>
00194 {
00195   static const delimiters_values<wchar_t> values;
00196 };
00197 
00198 template <typename T, typename TComp, typename TAllocator>
00199 const delimiters_values<wchar_t> delimiters< ::std::multiset<T, TComp, TAllocator>, wchar_t>::values = { L"{", L", ",
00200                                                                                                          L"}" };
00201 
00202 #ifndef NO_TR1
00203 template <typename T, typename THash, typename TEqual, typename TAllocator>
00204 struct delimiters< ::std::tr1::unordered_set<T, THash, TEqual, TAllocator>, char>
00205 {
00206   static const delimiters_values<char> values;
00207 };
00208 
00209 template <typename T, typename THash, typename TEqual, typename TAllocator>
00210 const delimiters_values<char> delimiters< ::std::tr1::unordered_set<T, THash, TEqual, TAllocator>, char>::values = {
00211   "{", ", ", "}"
00212 };
00213 
00214 template <typename T, typename THash, typename TEqual, typename TAllocator>
00215 struct delimiters< ::std::tr1::unordered_set<T, THash, TEqual, TAllocator>, wchar_t>
00216 {
00217   static const delimiters_values<wchar_t> values;
00218 };
00219 
00220 template <typename T, typename THash, typename TEqual, typename TAllocator>
00221 const delimiters_values<wchar_t> delimiters< ::std::tr1::unordered_set<T, THash, TEqual, TAllocator>, wchar_t>::values =
00222     { L"{", L", ", L"}" };
00223 
00224 template <typename T, typename THash, typename TEqual, typename TAllocator>
00225 struct delimiters< ::std::tr1::unordered_multiset<T, THash, TEqual, TAllocator>, char>
00226 {
00227   static const delimiters_values<char> values;
00228 };
00229 
00230 template <typename T, typename THash, typename TEqual, typename TAllocator>
00231 const delimiters_values<char> delimiters< ::std::tr1::unordered_multiset<T, THash, TEqual, TAllocator>, char>::values =
00232     { "{", ", ", "}" };
00233 
00234 template <typename T, typename THash, typename TEqual, typename TAllocator>
00235 struct delimiters< ::std::tr1::unordered_multiset<T, THash, TEqual, TAllocator>, wchar_t>
00236 {
00237   static const delimiters_values<wchar_t> values;
00238 };
00239 
00240 template <typename T, typename THash, typename TEqual, typename TAllocator>
00241 const delimiters_values<wchar_t>
00242     delimiters< ::std::tr1::unordered_multiset<T, THash, TEqual, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
00243 #endif
00244 
00245 // Delimiters for pair (reused for tuple, see below)
00246 
00247 template <typename T1, typename T2>
00248 struct delimiters< ::std::pair<T1, T2>, char>
00249 {
00250   static const delimiters_values<char> values;
00251 };
00252 template <typename T1, typename T2>
00253 const delimiters_values<char> delimiters< ::std::pair<T1, T2>, char>::values = { "(", ", ", ")" };
00254 template <typename T1, typename T2>
00255 struct delimiters< ::std::pair<T1, T2>, wchar_t>
00256 {
00257   static const delimiters_values<wchar_t> values;
00258 };
00259 template <typename T1, typename T2>
00260 const delimiters_values<wchar_t> delimiters< ::std::pair<T1, T2>, wchar_t>::values = { L"(", L", ", L")" };
00261 
00262 // Iterator microtrait class to handle C arrays uniformly
00263 
00264 template <typename T>
00265 struct get_iterator
00266 {
00267   typedef typename T::const_iterator iter;
00268 };
00269 template <typename T, std::size_t N>
00270 struct get_iterator<T[N]>
00271 {
00272   typedef const T *iter;
00273 };
00274 
00275 template <typename T>
00276 typename enable_if<has_const_iterator<T>::value, typename T::const_iterator>::type begin(const T &c)
00277 {
00278   return c.begin();
00279 }
00280 template <typename T>
00281 typename enable_if<has_const_iterator<T>::value, typename T::const_iterator>::type end(const T &c)
00282 {
00283   return c.end();
00284 }
00285 template <typename T, size_t N>
00286 const T *begin(const T(&x)[N])
00287 {
00288   return &x[0];
00289 }
00290 template <typename T, size_t N>
00291 const T *end(const T(&x)[N])
00292 {
00293   return &x[0] + N;
00294 }
00295 
00296 // Functor to print containers. You can use this directly if you want to specificy a non-default delimiters type.
00297 
00298 template <typename T, typename TChar = char, typename TCharTraits = ::std::char_traits<TChar>,
00299           typename TDelimiters = delimiters<T, TChar> >
00300 struct print_container_helper
00301 {
00302   typedef TChar char_type;
00303   typedef TDelimiters delimiters_type;
00304   typedef std::basic_ostream<TChar, TCharTraits> ostream_type;
00305   typedef typename get_iterator<T>::iter TIter;
00306 
00307   print_container_helper(const T &container) : _container(container)
00308   {
00309   }
00310 
00311   inline void operator()(ostream_type &stream) const
00312   {
00313     if (delimiters_type::values.prefix != NULL)
00314       stream << delimiters_type::values.prefix;
00315 
00316     if (pretty_print::begin(_container) != pretty_print::end(_container))
00317       for (TIter it = pretty_print::begin(_container), it_end = pretty_print::end(_container);;)
00318       {
00319         stream << *it;
00320 
00321         if (++it == it_end)
00322           break;
00323 
00324         if (delimiters_type::values.delimiter != NULL)
00325           stream << delimiters_type::values.delimiter;
00326       }
00327 
00328     if (delimiters_type::values.postfix != NULL)
00329       stream << delimiters_type::values.postfix;
00330   }
00331 
00332 private:
00333   const T &_container;
00334 };
00335 
00336 // Type-erasing helper class for easy use of custom delimiters.
00337 // Requires TCharTraits = std::char_traits<TChar> and TChar = char or wchar_t, and MyDelims needs to be defined for
00338 // TChar.
00339 // Usage: "cout << pretty_print::custom_delims<MyDelims>(x)".
00340 
00341 struct custom_delims_base
00342 {
00343   virtual ~custom_delims_base()
00344   {
00345   }
00346   virtual ::std::ostream &stream(::std::ostream &) = 0;
00347   virtual ::std::wostream &stream(::std::wostream &) = 0;
00348 };
00349 
00350 template <typename T, typename Delims>
00351 struct custom_delims_wrapper : public custom_delims_base
00352 {
00353   custom_delims_wrapper(const T &t_) : t(t_)
00354   {
00355   }
00356 
00357   ::std::ostream &stream(::std::ostream &s)
00358   {
00359     return s << ::pretty_print::print_container_helper<T, char, ::std::char_traits<char>, Delims>(t);
00360   }
00361   ::std::wostream &stream(::std::wostream &s)
00362   {
00363     return s << ::pretty_print::print_container_helper<T, wchar_t, ::std::char_traits<wchar_t>, Delims>(t);
00364   }
00365 
00366 private:
00367   const T &t;
00368 };
00369 
00370 template <typename Delims>
00371 struct custom_delims
00372 {
00373   template <typename Container>
00374   custom_delims(const Container &c)
00375     : base(new custom_delims_wrapper<Container, Delims>(c))
00376   {
00377   }
00378   ~custom_delims()
00379   {
00380     delete base;
00381   }
00382   custom_delims_base *base;
00383 };
00384 
00385 }  // namespace pretty_print
00386 
00387 template <typename TChar, typename TCharTraits, typename Delims>
00388 inline std::basic_ostream<TChar, TCharTraits> &operator<<(std::basic_ostream<TChar, TCharTraits> &s,
00389                                                           const pretty_print::custom_delims<Delims> &p)
00390 {
00391   return p.base->stream(s);
00392 }
00393 
00394 // Template aliases for char and wchar_t delimiters
00395 // Enable these if you have compiler support
00396 //
00397 // Implement as "template<T, C, A> const sdelims::type sdelims<std::set<T,C,A>>::values = { ... }."
00398 
00399 // template<typename T> using pp_sdelims = pretty_print::delimiters<T, char>;
00400 // template<typename T> using pp_wsdelims = pretty_print::delimiters<T, wchar_t>;
00401 
00402 namespace std
00403 {
00404 // Prints a print_container_helper to the specified stream.
00405 
00406 template <typename T, typename TChar, typename TCharTraits, typename TDelimiters>
00407 inline basic_ostream<TChar, TCharTraits> &
00408 operator<<(basic_ostream<TChar, TCharTraits> &stream,
00409            const ::pretty_print::print_container_helper<T, TChar, TCharTraits, TDelimiters> &helper)
00410 {
00411   helper(stream);
00412   return stream;
00413 }
00414 
00415 // Prints a container to the stream using default delimiters
00416 
00417 template <typename T, typename TChar, typename TCharTraits>
00418 inline typename ::pretty_print::enable_if< ::pretty_print::is_container<T>::value,
00419                                            basic_ostream<TChar, TCharTraits> &>::type
00420 operator<<(basic_ostream<TChar, TCharTraits> &stream, const T &container)
00421 {
00422   return stream << ::pretty_print::print_container_helper<T, TChar, TCharTraits>(container);
00423 }
00424 
00425 // Prints a pair to the stream using delimiters from delimiters<std::pair<T1, T2>>.
00426 template <typename T1, typename T2, typename TChar, typename TCharTraits>
00427 inline basic_ostream<TChar, TCharTraits> &operator<<(basic_ostream<TChar, TCharTraits> &stream,
00428                                                      const pair<T1, T2> &value)
00429 {
00430   if (::pretty_print::delimiters<pair<T1, T2>, TChar>::values.prefix != NULL)
00431     stream << ::pretty_print::delimiters<pair<T1, T2>, TChar>::values.prefix;
00432 
00433   stream << value.first;
00434 
00435   if (::pretty_print::delimiters<pair<T1, T2>, TChar>::values.delimiter != NULL)
00436     stream << ::pretty_print::delimiters<pair<T1, T2>, TChar>::values.delimiter;
00437 
00438   stream << value.second;
00439 
00440   if (::pretty_print::delimiters<pair<T1, T2>, TChar>::values.postfix != NULL)
00441     stream << ::pretty_print::delimiters<pair<T1, T2>, TChar>::values.postfix;
00442 
00443   return stream;
00444 }
00445 }  // namespace std
00446 
00447 #ifndef NO_TR1
00448 
00449 // Prints a tuple to the stream using delimiters from delimiters<std::pair<tuple_dummy_t, tuple_dummy_t>>.
00450 
00451 namespace pretty_print
00452 {
00453 struct tuple_dummy_t
00454 {
00455 };  // Just if you want special delimiters for tuples.
00456 
00457 typedef std::pair<tuple_dummy_t, tuple_dummy_t> tuple_dummy_pair;
00458 
00459 template <typename Tuple, size_t N, typename TChar, typename TCharTraits>
00460 struct pretty_tuple_helper
00461 {
00462   static inline void print(::std::basic_ostream<TChar, TCharTraits> &stream, const Tuple &value)
00463   {
00464     pretty_tuple_helper<Tuple, N - 1, TChar, TCharTraits>::print(stream, value);
00465 
00466     if (delimiters<tuple_dummy_pair, TChar>::values.delimiter != NULL)
00467       stream << delimiters<tuple_dummy_pair, TChar>::values.delimiter;
00468 
00469     stream << std::tr1::get<N - 1>(value);
00470   }
00471 };
00472 
00473 template <typename Tuple, typename TChar, typename TCharTraits>
00474 struct pretty_tuple_helper<Tuple, 1, TChar, TCharTraits>
00475 {
00476   static inline void print(::std::basic_ostream<TChar, TCharTraits> &stream, const Tuple &value)
00477   {
00478     stream << ::std::tr1::get<0>(value);
00479   }
00480 };
00481 }  // namespace pretty_print
00482 
00483 /* The following macros allow us to write "template <TUPLE_PARAMAS> std::tuple<TUPLE_ARGS>"
00484  * uniformly in C++0x compilers and in MS Visual Studio 2010.
00485  * Credits to STL: http://channel9.msdn.com/Shows/Going+Deep/C9-Lectures-Stephan-T-Lavavej-Advanced-STL-6-of-n
00486  */
00487 
00488 #define TUPLE_PARAMS                                                                                                   \
00489   typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, \
00490       typename T9
00491 #define TUPLE_ARGS T0, T1, T2, T3, T4, T5, T6, T7, T8, T9
00492 
00493 namespace std
00494 {
00495 template <typename TChar, typename TCharTraits, TUPLE_PARAMS>
00496 inline basic_ostream<TChar, TCharTraits> &operator<<(basic_ostream<TChar, TCharTraits> &stream,
00497                                                      const tr1::tuple<TUPLE_ARGS> &value)
00498 {
00499   if (::pretty_print::delimiters< ::pretty_print::tuple_dummy_pair, TChar>::values.prefix != NULL)
00500     stream << ::pretty_print::delimiters< ::pretty_print::tuple_dummy_pair, TChar>::values.prefix;
00501 
00502   ::pretty_print::pretty_tuple_helper<const tr1::tuple<TUPLE_ARGS> &, tr1::tuple_size<tr1::tuple<TUPLE_ARGS> >::value,
00503                                       TChar, TCharTraits>::print(stream, value);
00504 
00505   if (::pretty_print::delimiters< ::pretty_print::tuple_dummy_pair, TChar>::values.postfix != NULL)
00506     stream << ::pretty_print::delimiters< ::pretty_print::tuple_dummy_pair, TChar>::values.postfix;
00507 
00508   return stream;
00509 }
00510 }  // namespace std
00511 
00512 #endif  // NO_TR1
00513 
00514 // A wrapper for raw C-style arrays. Usage: int arr[] = { 1, 2, 4, 8, 16 };  std::cout << wrap_array(arr) << ...
00515 
00516 namespace pretty_print
00517 {
00518 template <typename T>
00519 struct array_wrapper_n
00520 {
00521   typedef const T *const_iterator;
00522   typedef T value_type;
00523 
00524   array_wrapper_n(const T *const a, size_t n) : _array(a), _n(n)
00525   {
00526   }
00527   inline const_iterator begin() const
00528   {
00529     return _array;
00530   }
00531   inline const_iterator end() const
00532   {
00533     return _array + _n;
00534   }
00535 
00536 private:
00537   const T *const _array;
00538   size_t _n;
00539 };
00540 }  // namespace pretty_print
00541 
00542 template <typename T>
00543 inline pretty_print::array_wrapper_n<T> pretty_print_array(const T *const a, size_t n)
00544 {
00545   return pretty_print::array_wrapper_n<T>(a, n);
00546 }
00547 
00548 #endif


descartes_core
Author(s): Dan Solomon
autogenerated on Thu Jun 6 2019 21:35:59