CYCLUS
Loading...
Searching...
No Matches
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#ifndef H_PRETTY_PRINT
7#define H_PRETTY_PRINT
8
9#include <ostream>
10#include <utility>
11#include <iterator>
12#include <set>
13
14#ifndef NO_TR1
15#include <tr1/tuple>
16#include <tr1/unordered_set>
17#endif
18
19namespace pretty_print {
20
21template <bool, typename S, typename T> struct conditional {};
22template <typename S, typename T> struct conditional<true, S, T> {
23 typedef S type;
24};
25template <typename S, typename T> struct conditional<false, S, T> {
26 typedef T type;
27};
28
29template <bool, typename T> struct enable_if {};
30template <typename T> struct enable_if<true, T> {
31 typedef T type;
32};
33
34// SFINAE type trait to detect whether T::const_iterator exists.
35
36template <typename T> struct has_const_iterator {
37 private:
38 typedef char yes;
39 typedef struct {
40 char array[2];
41 } no;
42
43 template <typename C> static yes test(typename C::const_iterator *);
44 template <typename C> static no test(...);
45
46 public:
47 static const bool value = sizeof(test<T>(0)) == sizeof(yes);
48 typedef T type;
49};
50
51// SFINAE type trait to detect whether "T::const_iterator T::begin/end() const"
52// exist.
53
54template <typename T> struct has_begin_end {
55 struct Dummy {
56 typedef void const_iterator;
57 };
58 typedef
60 typedef typename TType::const_iterator iter;
61
62 struct Fallback {
63 iter begin() const;
64 iter end() const;
65 };
66 struct Derived : TType, Fallback {};
67
68 template <typename C, C> struct ChT;
69
70 template <typename C>
71 static char (&f(ChT<iter (Fallback::*)() const, &C::begin> *))[1];
72 template <typename C> static char (&f(...))[2];
73 template <typename C>
74 static char (&g(ChT<iter (Fallback::*)() const, &C::end> *))[1];
75 template <typename C> static char (&g(...))[2];
76
77 static bool const beg_value = sizeof(f<Derived>(0)) == 2;
78 static bool const end_value = sizeof(g<Derived>(0)) == 2;
79};
80
81// Basic is_container template; specialize to have value "true" for all desired
82// container types
83
84template <typename T> struct is_container {
85 static const bool value = has_const_iterator<T>::value &&
88};
89
90template <typename T, std::size_t N> struct is_container<T[N]> {
91 static const bool value = true;
92};
93
94template <std::size_t N> struct is_container<char[N]> {
95 static const bool value = false;
96};
97
98// Holds the delimiter values for a specific character type
99
100template <typename TChar> struct delimiters_values {
101 typedef TChar char_type;
102 const TChar *prefix;
103 const TChar *delimiter;
104 const TChar *postfix;
105};
106
107// Defines the delimiter values for a specific container and character type
108
109template <typename T, typename TChar> struct delimiters {
111 static const type values;
112};
113
114// Default delimiters
115
116template <typename T> struct delimiters<T, char> {
118};
119template <typename T>
121template <typename T> struct delimiters<T, wchar_t> {
123};
124template <typename T>
127
128// Delimiters for (multi)set and unordered_(multi)set
129
130template <typename T, typename TComp, typename TAllocator>
131struct delimiters<::std::set<T, TComp, TAllocator>, char> {
133};
134
135template <typename T, typename TComp, typename TAllocator>
139
140template <typename T, typename TComp, typename TAllocator>
141struct delimiters<::std::set<T, TComp, TAllocator>, wchar_t> {
143};
144
145template <typename T, typename TComp, typename TAllocator>
148 L"{", L", ", L"}"};
149
150template <typename T, typename TComp, typename TAllocator>
151struct delimiters<::std::multiset<T, TComp, TAllocator>, char> {
153};
154
155template <typename T, typename TComp, typename TAllocator>
159
160template <typename T, typename TComp, typename TAllocator>
161struct delimiters<::std::multiset<T, TComp, TAllocator>, wchar_t> {
163};
164
165template <typename T, typename TComp, typename TAllocator>
168 L"{", L", ", L"}"};
169
170#ifndef NO_TR1
171template <typename T, typename THash, typename TEqual, typename TAllocator>
172struct delimiters<::std::tr1::unordered_set<T, THash, TEqual, TAllocator>,
173 char> {
175};
176
177template <typename T, typename THash, typename TEqual, typename TAllocator>
180 char>::values = {"{", ", ", "}"};
181
182template <typename T, typename THash, typename TEqual, typename TAllocator>
183struct delimiters<::std::tr1::unordered_set<T, THash, TEqual, TAllocator>,
184 wchar_t> {
186};
187
188template <typename T, typename THash, typename TEqual, typename TAllocator>
191 wchar_t>::values = {L"{", L", ", L"}"};
192
193template <typename T, typename THash, typename TEqual, typename TAllocator>
194struct delimiters<::std::tr1::unordered_multiset<T, THash, TEqual, TAllocator>,
195 char> {
197};
198
199template <typename T, typename THash, typename TEqual, typename TAllocator>
202 char>::values = {"{", ", ", "}"};
203
204template <typename T, typename THash, typename TEqual, typename TAllocator>
205struct delimiters<::std::tr1::unordered_multiset<T, THash, TEqual, TAllocator>,
206 wchar_t> {
208};
209
210template <typename T, typename THash, typename TEqual, typename TAllocator>
213 wchar_t>::values = {L"{", L", ", L"}"};
214#endif
215
216// Delimiters for pair (reused for tuple, see below)
217
218template <typename T1, typename T2>
219struct delimiters<::std::pair<T1, T2>, char> {
221};
222template <typename T1, typename T2>
225template <typename T1, typename T2>
226struct delimiters<::std::pair<T1, T2>, wchar_t> {
228};
229template <typename T1, typename T2>
231 delimiters<::std::pair<T1, T2>, wchar_t>::values = {L"(", L", ", L")"};
232
233// Iterator microtrait class to handle C arrays uniformly
234
235template <typename T> struct get_iterator {
236 typedef typename T::const_iterator iter;
237};
238template <typename T, std::size_t N> struct get_iterator<T[N]> {
239 typedef const T *iter;
240};
241
242template <typename T>
244 typename T::const_iterator>::type
245begin(const T &c) {
246 return c.begin();
247}
248template <typename T>
249typename enable_if<has_const_iterator<T>::value,
250 typename T::const_iterator>::type
251end(const T &c) {
252 return c.end();
253}
254template <typename T, size_t N> const T *begin(const T (&x)[N]) {
255 return &x[0];
256}
257template <typename T, size_t N> const T *end(const T (&x)[N]) {
258 return &x[0] + N;
259}
260
261// Functor to print containers. You can use this directly if you want to
262// specificy a non-default delimiters type.
263
264template <typename T,
265 typename TChar = char,
266 typename TCharTraits = ::std::char_traits<TChar>,
267 typename TDelimiters = delimiters<T, TChar>>
269 typedef TChar char_type;
270 typedef TDelimiters delimiters_type;
271 typedef std::basic_ostream<TChar, TCharTraits> ostream_type;
272 typedef typename get_iterator<T>::iter TIter;
273
274 print_container_helper(const T &container) : _container(container) {}
275
276 inline void operator()(ostream_type &stream) const {
277 if (delimiters_type::values.prefix != NULL)
278 stream << delimiters_type::values.prefix;
279
280 if (begin(_container) != end(_container))
281 for (TIter it = begin(_container), it_end = end(_container);;) {
282 stream << *it;
283
284 if (++it == it_end) break;
285
286 if (delimiters_type::values.delimiter != NULL)
287 stream << delimiters_type::values.delimiter;
288 }
289
290 if (delimiters_type::values.postfix != NULL)
291 stream << delimiters_type::values.postfix;
292 }
293
294 private:
295 const T &_container;
296};
297
298// Type-erasing helper class for easy use of custom delimiters.
299// Requires TCharTraits = std::char_traits<TChar> and TChar = char or wchar_t,
300// and MyDelims needs to be defined for TChar. Usage: "cout <<
301// pretty_print::custom_delims<MyDelims>(x)".
302
305 virtual ::std::ostream &stream(::std::ostream &) = 0;
306 virtual ::std::wostream &stream(::std::wostream &) = 0;
307};
308
309template <typename T, typename Delims>
311 custom_delims_wrapper(const T &t_) : t(t_) {}
312
313 ::std::ostream &stream(::std::ostream &s) {
315 char,
316 ::std::char_traits<char>,
317 Delims>(t);
318 }
319 ::std::wostream &stream(::std::wostream &s) {
321 T,
322 wchar_t,
323 ::std::char_traits<wchar_t>,
324 Delims>(t);
325 }
326
327 private:
328 const T &t;
329};
330
331template <typename Delims> struct custom_delims {
332 template <typename Container>
333 custom_delims(const Container &c)
334 : base(new custom_delims_wrapper<Container, Delims>(c)) {}
335 ~custom_delims() { delete base; }
337};
338
339} // namespace pretty_print
340
341template <typename TChar, typename TCharTraits, typename Delims>
342inline std::basic_ostream<TChar, TCharTraits> &operator<<(
343 std::basic_ostream<TChar, TCharTraits> &s,
345 return p.base->stream(s);
346}
347
348// Template aliases for char and wchar_t delimiters
349// Enable these if you have compiler support
350//
351// Implement as "template<T, C, A> const sdelims::type
352// sdelims<std::set<T,C,A>>::values = { ... }."
353
354// template<typename T> using pp_sdelims = pretty_print::delimiters<T, char>;
355// template<typename T> using pp_wsdelims = pretty_print::delimiters<T,
356// wchar_t>;
357
358namespace std {
359// Prints a print_container_helper to the specified stream.
360
361template <typename T,
362 typename TChar,
363 typename TCharTraits,
364 typename TDelimiters>
365inline basic_ostream<TChar, TCharTraits> &operator<<(
366 basic_ostream<TChar, TCharTraits> &stream,
367 const ::pretty_print::
368 print_container_helper<T, TChar, TCharTraits, TDelimiters> &helper) {
369 helper(stream);
370 return stream;
371}
372
373// Prints a container to the stream using default delimiters
374
375template <typename T, typename TChar, typename TCharTraits>
376inline typename ::pretty_print::enable_if<
378 basic_ostream<TChar, TCharTraits> &>::type
379operator<<(basic_ostream<TChar, TCharTraits> &stream, const T &container) {
380 return stream
382 container);
383}
384
385// Prints a pair to the stream using delimiters from delimiters<std::pair<T1,
386// T2>>.
387template <typename T1, typename T2, typename TChar, typename TCharTraits>
388inline basic_ostream<TChar, TCharTraits> &operator<<(
389 basic_ostream<TChar, TCharTraits> &stream, const pair<T1, T2> &value) {
390 if (::pretty_print::delimiters<pair<T1, T2>, TChar>::values.prefix != NULL)
391 stream << ::pretty_print::delimiters<pair<T1, T2>, TChar>::values.prefix;
392
393 stream << value.first;
394
395 if (::pretty_print::delimiters<pair<T1, T2>, TChar>::values.delimiter != NULL)
396 stream << ::pretty_print::delimiters<pair<T1, T2>, TChar>::values.delimiter;
397
398 stream << value.second;
399
400 if (::pretty_print::delimiters<pair<T1, T2>, TChar>::values.postfix != NULL)
401 stream << ::pretty_print::delimiters<pair<T1, T2>, TChar>::values.postfix;
402
403 return stream;
404}
405} // namespace std
406
407#ifndef NO_TR1
408
409// Prints a tuple to the stream using delimiters from
410// delimiters<std::pair<tuple_dummy_t, tuple_dummy_t>>.
411
412namespace pretty_print {
413struct tuple_dummy_t {}; // Just if you want special delimiters for tuples.
414
415typedef std::pair<tuple_dummy_t, tuple_dummy_t> tuple_dummy_pair;
416
417template <typename Tuple, size_t N, typename TChar, typename TCharTraits>
419 static inline void print(::std::basic_ostream<TChar, TCharTraits> &stream,
420 const Tuple &value) {
422
424 stream << delimiters<tuple_dummy_pair, TChar>::values.delimiter;
425
426 stream << std::tr1::get<N - 1>(value);
427 }
428};
429
430template <typename Tuple, typename TChar, typename TCharTraits>
431struct pretty_tuple_helper<Tuple, 1, TChar, TCharTraits> {
432 static inline void print(::std::basic_ostream<TChar, TCharTraits> &stream,
433 const Tuple &value) {
434 stream << ::std::tr1::get<0>(value);
435 }
436};
437} // namespace pretty_print
438
439/* The following macros allow us to write "template <TUPLE_PARAMAS>
440 * std::tuple<TUPLE_ARGS>" uniformly in C++0x compilers and in MS Visual Studio
441 * 2010. Credits to STL:
442 * http://channel9.msdn.com/Shows/Going+Deep/C9-Lectures-Stephan-T-Lavavej-Advanced-STL-6-of-n
443 */
444
445#define TUPLE_PARAMS \
446 typename T0, typename T1, typename T2, typename T3, typename T4, \
447 typename T5, typename T6, typename T7, typename T8, typename T9
448#define TUPLE_ARGS T0, T1, T2, T3, T4, T5, T6, T7, T8, T9
449
450namespace std {
451template <typename TChar, typename TCharTraits, TUPLE_PARAMS>
452inline basic_ostream<TChar, TCharTraits> &operator<<(
453 basic_ostream<TChar, TCharTraits> &stream,
454 const tr1::tuple<TUPLE_ARGS> &value) {
456 TChar>::values.prefix != NULL)
458 TChar>::values.prefix;
459
461 const tr1::tuple<TUPLE_ARGS> &,
462 tr1::tuple_size<tr1::tuple<TUPLE_ARGS>>::value,
463 TChar,
464 TCharTraits>::print(stream, value);
465
467 TChar>::values.postfix != NULL)
469 TChar>::values.postfix;
470
471 return stream;
472}
473} // namespace std
474
475#endif // NO_TR1
476
477// A wrapper for raw C-style arrays. Usage: int arr[] = { 1, 2, 4, 8, 16 };
478// std::cout << wrap_array(arr) << ...
479
480namespace pretty_print {
481template <typename T> struct array_wrapper_n {
482 typedef const T *const_iterator;
483 typedef T value_type;
484
485 array_wrapper_n(const T *const a, size_t n) : _array(a), _n(n) {}
486 inline const_iterator begin() const { return _array; }
487 inline const_iterator end() const { return _array + _n; }
488
489 private:
490 const T *const _array;
491 size_t _n;
492};
493} // namespace pretty_print
494
495template <typename T>
497 size_t n) {
499}
500
501#endif
enable_if< has_const_iterator< T >::value, typenameT::const_iterator >::type begin(const T &c)
enable_if< has_const_iterator< T >::value, typenameT::const_iterator >::type end(const T &c)
std::pair< tuple_dummy_t, tuple_dummy_t > tuple_dummy_pair
const delimiters_values< char > delimiters< T, char >::values
basic_ostream< TChar, TCharTraits > & operator<<(basic_ostream< TChar, TCharTraits > &stream, const ::pretty_print::print_container_helper< T, TChar, TCharTraits, TDelimiters > &helper)
pretty_print::array_wrapper_n< T > pretty_print_array(const T *const a, size_t n)
std::basic_ostream< TChar, TCharTraits > & operator<<(std::basic_ostream< TChar, TCharTraits > &s, const pretty_print::custom_delims< Delims > &p)
array_wrapper_n(const T *const a, size_t n)
const_iterator end() const
const_iterator begin() const
virtual::std::wostream & stream(::std::wostream &)=0
virtual::std::ostream & stream(::std::ostream &)=0
::std::wostream & stream(::std::wostream &s)
::std::ostream & stream(::std::ostream &s)
custom_delims(const Container &c)
custom_delims_base * base
static const delimiters_values< char > values
static const delimiters_values< wchar_t > values
static const delimiters_values< char > values
static const delimiters_values< wchar_t > values
delimiters_values< TChar > type
static const type values
TType::const_iterator iter
static char(& f(...))[2]
static bool const end_value
static char(& f(ChT< iter(Fallback::*)() const, &C::begin > *))[1]
conditional< has_const_iterator< T >::value, T, Dummy >::type TType
static char(& g(ChT< iter(Fallback::*)() const, &C::end > *))[1]
static char(& g(...))[2]
static bool const beg_value
static const bool value
static void print(::std::basic_ostream< TChar, TCharTraits > &stream, const Tuple &value)
static void print(::std::basic_ostream< TChar, TCharTraits > &stream, const Tuple &value)
std::basic_ostream< TChar, TCharTraits > ostream_type
void operator()(ostream_type &stream) const
print_container_helper(const T &container)