prettyprint.hpp
1 /**********************************************************************
2  * prettyprint.hpp -- Pretty-printing STL containers *
3  * *
4  * Author: louisdx (http://louisdx.github.com/cxx-prettyprint/) *
5  * *
6  * Purpose: Making the communication of STL objects, particularly, *
7  * vectors and tuples possible *
8  * Usage: This file is included automatically *
9  * *
10  * License: *
11  *******************************************************************/
12 
13 #ifndef H_PRETTY_PRINT
14 #define H_PRETTY_PRINT
15 
16 
17 #include <type_traits>
18 #include <ostream>
19 #include <utility>
20 #include <tuple>
21 #include <iterator>
22 #include <functional>
23 
24 
25 namespace std
26 {
27  // Pre-declarations of container types so we don't actually have to include the relevant headers if not needed, speeding up compilation time.
28  template<typename T, typename TComp, typename TAllocator> class set;
29  template<typename T, typename TComp, typename TAllocator> class multiset;
30  template<typename T, typename THash, typename TEqual, typename TAllocator> class unordered_set;
31  template<typename T, typename THash, typename TEqual, typename TAllocator> class unordered_multiset;
32 }
33 
34 namespace pretty_print
35 {
36 
37  // SFINAE type trait to detect whether T::const_iterator exists.
38 
39  template<typename T>
41  {
42  private:
43  typedef char yes;
44  typedef struct { char array[2]; } no;
45 
46  template<typename C> static yes test(typename C::const_iterator*);
47  template<typename C> static no test(...);
48  public:
49  static const bool value = sizeof(test<T>(0)) == sizeof(yes);
50  typedef T type;
51  };
52 
53  // SFINAE type trait to detect whether "T::const_iterator T::begin/end() const" exist.
54 
55  template <typename T>
57  {
58  struct Dummy { typedef void const_iterator; };
59  typedef typename std::conditional<has_const_iterator<T>::value, T, Dummy>::type TType;
60  typedef typename TType::const_iterator iter;
61 
62  struct Fallback { iter begin() const; iter end() const; };
63  struct Derived : TType, Fallback { };
64 
65  template<typename C, C> struct ChT;
66 
67  template<typename C> static char (&f(ChT<iter (Fallback::*)() const, &C::begin>*))[1];
68  template<typename C> static char (&f(...))[2];
69  template<typename C> static char (&g(ChT<iter (Fallback::*)() const, &C::end>*))[1];
70  template<typename C> static char (&g(...))[2];
71 
72  static bool const beg_value = sizeof(f<Derived>(0)) == 2;
73  static bool const end_value = sizeof(g<Derived>(0)) == 2;
74  };
75 
76  template <typename T>
78  {
79  template<typename C> static char (&f(typename std::enable_if<
80  std::is_same<decltype(static_cast<typename C::const_iterator (C::*)() const>(&C::begin)),
81  typename C::const_iterator(C::*)() const>::value, void>::type*))[1];
82 
83  template<typename C> static char (&f(...))[2];
84 
85  template<typename C> static char (&g(typename std::enable_if<
86  std::is_same<decltype(static_cast<typename C::const_iterator (C::*)() const>(&C::end)),
87  typename C::const_iterator(C::*)() const>::value, void>::type*))[1];
88 
89  template<typename C> static char (&g(...))[2];
90 
91  static bool const beg_value = sizeof(f<T>(0)) == 1;
92  static bool const end_value = sizeof(g<T>(0)) == 1;
93  };
94 
95  // Basic is_container template; specialize to derive from std::true_type for all desired container types
96 
97  template<typename T> struct is_container : public ::std::integral_constant<bool,
98  has_const_iterator<T>::value && has_begin_end<T>::beg_value && has_begin_end<T>::end_value> { };
99 
100  template<typename T, std::size_t N> struct is_container<T[N]> : public ::std::true_type { };
101 
102  template<std::size_t N> struct is_container<char[N]> : public ::std::false_type { };
103 
104 
105  // Holds the delimiter values for a specific character type
106 
107  template<typename TChar>
109  {
110  typedef TChar char_type;
111  const TChar * prefix;
112  const TChar * delimiter;
113  const TChar * postfix;
114  };
115 
116 
117  // Defines the delimiter values for a specific container and character type
118 
119  template<typename T, typename TChar>
120  struct delimiters
121  {
123  static const type values;
124  };
125 
126 
127  // Default delimiters
128 
129  template<typename T> struct delimiters<T, char> { static const delimiters_values<char> values; };
130  template<typename T> const delimiters_values<char> delimiters<T, char>::values = { "[", ", ", "]" };
131  template<typename T> struct delimiters<T, wchar_t> { static const delimiters_values<wchar_t> values; };
132  template<typename T> const delimiters_values<wchar_t> delimiters<T, wchar_t>::values = { L"[", L", ", L"]" };
133 
134 
135  // Delimiters for (multi)set and unordered_(multi)set
136 
137  template<typename T, typename TTraits, typename TAllocator>
138  struct delimiters< ::std::set<T, TTraits, TAllocator>, char> { static const delimiters_values<char> values; };
139 
140  template<typename T, typename TTraits, typename TAllocator>
141  const delimiters_values<char> delimiters< ::std::set<T, TTraits, TAllocator>, char>::values = { "{", ", ", "}" };
142 
143  template<typename T, typename TTraits, typename TAllocator>
144  struct delimiters< ::std::set<T, TTraits, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; };
145 
146  template<typename T, typename TTraits, typename TAllocator>
147  const delimiters_values<wchar_t> delimiters< ::std::set<T, TTraits, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
148 
149  template<typename T, typename TTraits, typename TAllocator>
150  struct delimiters< ::std::multiset<T, TTraits, TAllocator>, char> { static const delimiters_values<char> values; };
151 
152  template<typename T, typename TTraits, typename TAllocator>
153  const delimiters_values<char> delimiters< ::std::multiset<T, TTraits, TAllocator>, char>::values = { "{", ", ", "}" };
154 
155  template<typename T, typename TTraits, typename TAllocator>
156  struct delimiters< ::std::multiset<T, TTraits, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; };
157 
158  template<typename T, typename TTraits, typename TAllocator>
159  const delimiters_values<wchar_t> delimiters< ::std::multiset<T, TTraits, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
160 
161  template<typename T, typename THash, typename TEqual, typename TAllocator>
162  struct delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, char> { static const delimiters_values<char> values; };
163 
164  template<typename T, typename THash, typename TEqual, typename TAllocator>
166 
167  template<typename T, typename THash, typename TEqual, typename TAllocator>
168  struct delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; };
169 
170  template<typename T, typename THash, typename TEqual, typename TAllocator>
171  const delimiters_values<wchar_t> delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
172 
173  template<typename T, typename THash, typename TEqual, typename TAllocator>
174  struct delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, char> { static const delimiters_values<char> values; };
175 
176  template<typename T, typename THash, typename TEqual, typename TAllocator>
178 
179  template<typename T, typename THash, typename TEqual, typename TAllocator>
180  struct delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; };
181 
182  template<typename T, typename THash, typename TEqual, typename TAllocator>
183  const delimiters_values<wchar_t> delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
184 
185 
186  // Delimiters for pair (reused for tuple, see below)
187 
188  template<typename T1, typename T2> struct delimiters< ::std::pair<T1, T2>, char> { static const delimiters_values<char> values; };
189  template<typename T1, typename T2> const delimiters_values<char> delimiters< ::std::pair<T1, T2>, char>::values = { "(", ", ", ")" };
190  template<typename T1, typename T2> struct delimiters< ::std::pair<T1, T2>, wchar_t> { static const delimiters_values<wchar_t> values; };
191  template<typename T1, typename T2> const delimiters_values<wchar_t> delimiters< ::std::pair<T1, T2>, wchar_t>::values = { L"(", L", ", L")" };
192 
193 
194  // Iterator microtrait class to handle C arrays uniformly
195 
196  template <typename T> struct get_iterator { typedef typename T::const_iterator iter; };
197  template <typename T, std::size_t N> struct get_iterator<T[N]> { typedef const T * iter; };
198 
199 
200  // Functor to print containers. You can use this directly if you want to specificy a non-default delimiters type.
201 
202  template<typename T, typename TChar = char, typename TCharTraits = ::std::char_traits<TChar>, typename TDelimiters = delimiters<T, TChar>>
204  {
205  typedef TChar char_type;
206  typedef TDelimiters delimiters_type;
207  typedef std::basic_ostream<TChar, TCharTraits> ostream_type;
208  typedef typename get_iterator<T>::iter TIter;
209 
210  print_container_helper(const T & container)
211  : _container(container)
212  {
213  }
214 
215  inline void operator()(ostream_type & stream) const
216  {
217  if (delimiters_type::values.prefix != NULL)
218  stream << delimiters_type::values.prefix;
219 
220  if (std::begin(_container) != std::end(_container))
221  for (TIter it = std::begin(_container), end = std::end(_container); ; )
222  {
223  stream << *it;
224 
225  if (++it == end) break;
226 
227  if (delimiters_type::values.delimiter != NULL)
228  stream << delimiters_type::values.delimiter;
229  }
230 
231  if (delimiters_type::values.postfix != NULL)
232  stream << delimiters_type::values.postfix;
233  }
234 
235  private:
236  const T & _container;
237  };
238 
239 
240  // Type-erasing helper class for easy use of custom delimiters.
241  // Requires TCharTraits = std::char_traits<TChar> and TChar = char or wchar_t, and MyDelims needs to be defined for TChar.
242  // Usage: "cout << pretty_print::custom_delims<MyDelims>(x)".
243 
245  {
246  virtual ~custom_delims_base() { }
247  virtual ::std::ostream & stream(::std::ostream &) = 0;
248  virtual ::std::wostream & stream(::std::wostream &) = 0;
249  };
250 
251  template<typename T, typename Delims>
253  {
254  custom_delims_wrapper(const T & t) : t(t) { }
255 
256  ::std::ostream & stream(::std::ostream & stream)
257  {
258  return stream << ::pretty_print::print_container_helper<T, char, ::std::char_traits<char>, Delims>(t);
259  }
260  ::std::wostream & stream(::std::wostream & stream)
261  {
262  return stream << ::pretty_print::print_container_helper<T, wchar_t, ::std::char_traits<wchar_t>, Delims>(t);
263  }
264 
265  private:
266  const T & t;
267  };
268 
269  template<typename Delims>
271  {
272  template<typename Container> custom_delims(const Container & c) : base(new custom_delims_wrapper<Container, Delims>(c)) { }
273  ~custom_delims() { delete base; }
274  custom_delims_base * base;
275  };
276 
277 } // namespace pretty_print
278 
279 
280 template<typename TChar, typename TCharTraits, typename Delims>
281 inline std::basic_ostream<TChar, TCharTraits> & operator<<(std::basic_ostream<TChar, TCharTraits> & stream, const pretty_print::custom_delims<Delims> & p)
282 {
283  return p.base->stream(stream);
284 }
285 
286 
287 // Template aliases for char and wchar_t delimiters
288 // Enable these if you have compiler support
289 //
290 // Implement as "template<T, C, A> const sdelims::type sdelims<std::set<T,C,A>>::values = { ... }."
291 
292 //template<typename T> using pp_sdelims = pretty_print::delimiters<T, char>;
293 //template<typename T> using pp_wsdelims = pretty_print::delimiters<T, wchar_t>;
294 
295 
296 namespace std
297 {
298  // Prints a print_container_helper to the specified stream.
299 
300  template<typename T, typename TChar, typename TCharTraits, typename TDelimiters>
301  inline basic_ostream<TChar, TCharTraits> & operator<<(basic_ostream<TChar, TCharTraits> & stream,
302  const ::pretty_print::print_container_helper<T, TChar, TCharTraits, TDelimiters> & helper)
303  {
304  helper(stream);
305  return stream;
306  }
307 
308  // Prints a container to the stream using default delimiters
309 
310  template<typename T, typename TChar, typename TCharTraits>
311  inline typename enable_if< ::pretty_print::is_container<T>::value, basic_ostream<TChar, TCharTraits>&>::type
312  operator<<(basic_ostream<TChar, TCharTraits> & stream, const T & container)
313  {
314  return stream << ::pretty_print::print_container_helper<T, TChar, TCharTraits>(container);
315  }
316 
317  // Prints a pair to the stream using delimiters from delimiters<std::pair<T1, T2>>.
318  template<typename T1, typename T2, typename TChar, typename TCharTraits>
319  inline basic_ostream<TChar, TCharTraits> & operator<<(basic_ostream<TChar, TCharTraits> & stream, const pair<T1, T2> & value)
320  {
321  if (::pretty_print::delimiters<pair<T1, T2>, TChar>::values.prefix != NULL)
322  stream << ::pretty_print::delimiters<pair<T1, T2>, TChar>::values.prefix;
323 
324  stream << value.first;
325 
326  if (::pretty_print::delimiters<pair<T1, T2>, TChar>::values.delimiter != NULL)
327  stream << ::pretty_print::delimiters<pair<T1, T2>, TChar>::values.delimiter;
328 
329  stream << value.second;
330 
331  if (::pretty_print::delimiters<pair<T1, T2>, TChar>::values.postfix != NULL)
332  stream << ::pretty_print::delimiters<pair<T1, T2>, TChar>::values.postfix;
333 
334  return stream;
335  }
336 } // namespace std
337 
338 // Prints a tuple to the stream using delimiters from delimiters<std::pair<tuple_dummy_t, tuple_dummy_t>>.
339 
340 namespace pretty_print
341 {
342  struct tuple_dummy_t { }; // Just if you want special delimiters for tuples.
343 
344  typedef std::pair<tuple_dummy_t, tuple_dummy_t> tuple_dummy_pair;
345 
346  template<typename Tuple, size_t N, typename TChar, typename TCharTraits>
348  {
349  static inline void print(::std::basic_ostream<TChar, TCharTraits> & stream, const Tuple & value)
350  {
352 
353  if (delimiters<tuple_dummy_pair, TChar>::values.delimiter != NULL)
354  stream << delimiters<tuple_dummy_pair, TChar>::values.delimiter;
355 
356  stream << std::get<N - 1>(value);
357  }
358  };
359 
360  template<typename Tuple, typename TChar, typename TCharTraits>
361  struct pretty_tuple_helper<Tuple, 1, TChar, TCharTraits>
362  {
363  static inline void print(::std::basic_ostream<TChar, TCharTraits> & stream, const Tuple & value)
364  {
365  stream << ::std::get<0>(value);
366  }
367  };
368 } // namespace pretty_print
369 
370 
371 /* The following macros allow us to write "template <TUPLE_PARAMAS> std::tuple<TUPLE_ARGS>"
372  * uniformly in C++0x compilers and in MS Visual Studio 2010.
373  * Credits to STL: http://channel9.msdn.com/Shows/Going+Deep/C9-Lectures-Stephan-T-Lavavej-Advanced-STL-6-of-n
374  */
375 
376 #if defined(_MSC_VER) && _MSC_VER == 1600
377  #define TUPLE_PARAMS \
378  typename T0, typename T1, typename T2, typename T3, typename T4, \
379  typename T5, typename T6, typename T7, typename T8, typename T9
380  #define TUPLE_ARGS T0, T1, T2, T3, T4, T5, T6, T7, T8, T9
381 #else
382  #define TUPLE_PARAMS typename ...Args
383  #define TUPLE_ARGS Args...
384 #endif
385 
386 
387 namespace std
388 {
389  template<typename TChar, typename TCharTraits, TUPLE_PARAMS>
390  inline basic_ostream<TChar, TCharTraits> & operator<<(basic_ostream<TChar, TCharTraits> & stream, const tuple<TUPLE_ARGS> & value)
391  {
393  stream << ::pretty_print::delimiters< ::pretty_print::tuple_dummy_pair, TChar>::values.prefix;
394 
395  ::pretty_print::pretty_tuple_helper<const tuple<TUPLE_ARGS> &, tuple_size<tuple<TUPLE_ARGS>>::value, TChar, TCharTraits>::print(stream, value);
396 
398  stream << ::pretty_print::delimiters< ::pretty_print::tuple_dummy_pair, TChar>::values.postfix;
399 
400  return stream;
401  }
402 } // namespace std
403 
404 namespace std
405 {
406  template<typename TChar, typename TCharTraits, typename _Res, typename... _ArgTypes>
407  inline basic_ostream<TChar, TCharTraits> & operator<<(basic_ostream<TChar, TCharTraits> & stream, class function<_Res(_ArgTypes...)> func)
408  {
409  return stream;
410  }
411 } // namespace std
412 
413 // A wrapper for raw C-style arrays. Usage: int arr[] = { 1, 2, 4, 8, 16 }; std::cout << wrap_array(arr) << ...
414 
415 namespace pretty_print
416 {
417  template<typename T>
419  {
420  typedef const T * const_iterator;
421  typedef T value_type;
422 
423  array_wrapper_n(const T * const a, size_t n) : _array(a), _n(n) { }
424  inline const_iterator begin() const { return _array; }
425  inline const_iterator end() const { return _array + _n; }
426 
427  private:
428  const T * const _array;
429  size_t _n;
430  };
431 } // namespace pretty_print
432 
433 template<typename T>
434 inline pretty_print::array_wrapper_n<T> pretty_print_array(const T * const a, size_t n)
435 {
437 }
438 
439 
440 #endif
Definition: prettyprint.hpp:34
Definition: prettyprint.hpp:244
Definition: prettyprint.hpp:342
Definition: prettyprint.hpp:196
Definition: prettyprint.hpp:62
Definition: prettyprint.hpp:77
Definition: prettyprint.hpp:30
Definition: prettyprint.hpp:120
Definition: prettyprint.hpp:108
Definition: prettyprint.hpp:25
Definition: prettyprint.hpp:270
Definition: prettyprint.hpp:97
Definition: prettyprint.hpp:29
Definition: prettyprint.hpp:347
Definition: prettyprint.hpp:56
Definition: prettyprint.hpp:203
Definition: prettyprint.hpp:65
Definition: prettyprint.hpp:40
Definition: prettyprint.hpp:31
Definition: prettyprint.hpp:63
Definition: prettyprint.hpp:418
Definition: prettyprint.hpp:252
Definition: prettyprint.hpp:58
Definition: prettyprint.hpp:28