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