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
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
21namespace 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
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>
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>
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>
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 {
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
259template<typename TChar, typename TCharTraits, typename Delims>
260inline 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
274namespace 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
321namespace 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
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
363namespace 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
385namespace 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
403template<typename T>
404inline pretty_print::array_wrapper_n<T> pretty_print_array(const T * const a, size_t n)
405{
407}
408
409
410#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
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
static const type values
delimiters_values< TChar > type
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)