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)
6 // A pretty printing library for C++
9 // Include this header, and operator<< will "just work".
11 #ifndef H_PRETTY_PRINT
12 #define H_PRETTY_PRINT
20 #include <type_traits>
21 #include <unordered_set>
25 namespace pretty_print
29 // SFINAE type trait to detect whether T::const_iterator exists.
38 struct has_const_iterator
: private sfinae_base
41 template <typename C
> static yes
& test(typename
C::const_iterator
*);
42 template <typename C
> static no
& test(...);
44 static const bool value
= sizeof(test
<T
>(nullptr)) == sizeof(yes
);
49 struct has_begin_end
: private sfinae_base
53 static yes
& f(typename
std::enable_if
<
54 std::is_same
<decltype(static_cast<typename
C::const_iterator(C::*)() const>(&C::begin
)),
55 typename
C::const_iterator(C::*)() const>::value
>::type
*);
57 template <typename C
> static no
& f(...);
60 static yes
& g(typename
std::enable_if
<
61 std::is_same
<decltype(static_cast<typename
C::const_iterator(C::*)() const>(&C::end
)),
62 typename
C::const_iterator(C::*)() const>::value
, void>::type
*);
64 template <typename C
> static no
& g(...);
67 static bool const beg_value
= sizeof(f
<T
>(nullptr)) == sizeof(yes
);
68 static bool const end_value
= sizeof(g
<T
>(nullptr)) == sizeof(yes
);
74 // Holds the delimiter values for a specific character type
76 template <typename TChar
>
77 struct delimiters_values
79 using char_type
= TChar
;
80 const char_type
* prefix
;
81 const char_type
* delimiter
;
82 const char_type
* postfix
;
86 // Defines the delimiter values for a specific container and character type
88 template <typename T
, typename TChar
>
91 using type
= delimiters_values
<TChar
>;
92 static const type values
;
96 // Functor to print containers. You can use this directly if you want
97 // to specificy a non-default delimiters type. The printing logic can
98 // be customized by specializing the nested template.
100 template <typename T
,
101 typename TChar
= char,
102 typename TCharTraits
= ::std::char_traits
<TChar
>,
103 typename TDelimiters
= delimiters
<T
, TChar
>>
104 struct print_container_helper
106 using delimiters_type
= TDelimiters
;
107 using ostream_type
= std::basic_ostream
<TChar
, TCharTraits
>;
109 template <typename U
>
112 static void print_body(const U
& c
, ostream_type
& stream
)
118 const auto the_end
= end(c
);
126 if (++it
== the_end
) break;
128 if (delimiters_type::values
.delimiter
!= NULL
)
129 stream
<< delimiters_type::values
.delimiter
;
135 print_container_helper(const T
& container
)
136 : container_(container
)
139 inline void operator()(ostream_type
& stream
) const
141 if (delimiters_type::values
.prefix
!= NULL
)
142 stream
<< delimiters_type::values
.prefix
;
144 printer
<T
>::print_body(container_
, stream
);
146 if (delimiters_type::values
.postfix
!= NULL
)
147 stream
<< delimiters_type::values
.postfix
;
151 const T
& container_
;
154 // Specialization for pairs
156 template <typename T
, typename TChar
, typename TCharTraits
, typename TDelimiters
>
157 template <typename T1
, typename T2
>
158 struct print_container_helper
<T
, TChar
, TCharTraits
, TDelimiters
>::printer
<std::pair
<T1
, T2
>>
160 using ostream_type
= print_container_helper
<T
, TChar
, TCharTraits
, TDelimiters
>::ostream_type
;
162 static void print_body(const std::pair
<T1
, T2
> & c
, ostream_type
& stream
)
165 if (print_container_helper
<T
, TChar
, TCharTraits
, TDelimiters
>::delimiters_type::values
.delimiter
!= NULL
)
166 stream
<< print_container_helper
<T
, TChar
, TCharTraits
, TDelimiters
>::delimiters_type::values
.delimiter
;
171 // Specialization for tuples
173 template <typename T
, typename TChar
, typename TCharTraits
, typename TDelimiters
>
174 template <typename
...Args
>
175 struct print_container_helper
<T
, TChar
, TCharTraits
, TDelimiters
>::printer
<std::tuple
<Args
...>>
177 using ostream_type
= print_container_helper
<T
, TChar
, TCharTraits
, TDelimiters
>::ostream_type
;
178 using element_type
= std::tuple
<Args
...>;
180 template <std::size_t I
> struct Int
{ };
182 static void print_body(const element_type
& c
, ostream_type
& stream
)
184 tuple_print(c
, stream
, Int
<0>());
187 static void tuple_print(const element_type
&, ostream_type
&, Int
<sizeof...(Args
)>)
191 static void tuple_print(const element_type
& c
, ostream_type
& stream
,
192 typename
std::conditional
<sizeof...(Args
) != 0, Int
<0>, std::nullptr_t
>::type
)
194 stream
<< std::get
<0>(c
);
195 tuple_print(c
, stream
, Int
<1>());
198 template <std::size_t N
>
199 static void tuple_print(const element_type
& c
, ostream_type
& stream
, Int
<N
>)
201 if (print_container_helper
<T
, TChar
, TCharTraits
, TDelimiters
>::delimiters_type::values
.delimiter
!= NULL
)
202 stream
<< print_container_helper
<T
, TChar
, TCharTraits
, TDelimiters
>::delimiters_type::values
.delimiter
;
204 stream
<< std::get
<N
>(c
);
206 tuple_print(c
, stream
, Int
<N
+ 1>());
210 // Prints a print_container_helper to the specified stream.
212 template<typename T
, typename TChar
, typename TCharTraits
, typename TDelimiters
>
213 inline std::basic_ostream
<TChar
, TCharTraits
> & operator<<(
214 std::basic_ostream
<TChar
, TCharTraits
> & stream
,
215 const print_container_helper
<T
, TChar
, TCharTraits
, TDelimiters
> & helper
)
222 // Basic is_container template; specialize to derive from std::true_type for all desired container types
224 template <typename T
>
225 struct is_container
: public std::integral_constant
<bool,
226 detail::has_const_iterator
<T
>::value
&&
227 detail::has_begin_end
<T
>::beg_value
&&
228 detail::has_begin_end
<T
>::end_value
> { };
230 template <typename T
, std::size_t N
>
231 struct is_container
<T
[N
]> : std::true_type
{ };
233 template <std::size_t N
>
234 struct is_container
<char[N
]> : std::false_type
{ };
236 template <typename T
>
237 struct is_container
<std::valarray
<T
>> : std::true_type
{ };
239 template <typename T1
, typename T2
>
240 struct is_container
<std::pair
<T1
, T2
>> : std::true_type
{ };
242 template <typename
...Args
>
243 struct is_container
<std::tuple
<Args
...>> : std::true_type
{ };
246 // Default delimiters
248 template <typename T
> struct delimiters
<T
, char> { static const delimiters_values
<char> values
; };
249 template <typename T
> const delimiters_values
<char> delimiters
<T
, char>::values
= { "[", ", ", "]" };
250 template <typename T
> struct delimiters
<T
, wchar_t> { static const delimiters_values
<wchar_t> values
; };
251 template <typename T
> const delimiters_values
<wchar_t> delimiters
<T
, wchar_t>::values
= { L
"[", L
", ", L
"]" };
254 // Delimiters for (multi)set and unordered_(multi)set
256 template <typename T
, typename TComp
, typename TAllocator
>
257 struct delimiters
< ::std::set
<T
, TComp
, TAllocator
>, char> { static const delimiters_values
<char> values
; };
259 template <typename T
, typename TComp
, typename TAllocator
>
260 const delimiters_values
<char> delimiters
< ::std::set
<T
, TComp
, TAllocator
>, char>::values
= { "{", ", ", "}" };
262 template <typename T
, typename TComp
, typename TAllocator
>
263 struct delimiters
< ::std::set
<T
, TComp
, TAllocator
>, wchar_t> { static const delimiters_values
<wchar_t> values
; };
265 template <typename T
, typename TComp
, typename TAllocator
>
266 const delimiters_values
<wchar_t> delimiters
< ::std::set
<T
, TComp
, TAllocator
>, wchar_t>::values
= { L
"{", L
", ", L
"}" };
268 template <typename T
, typename TComp
, typename TAllocator
>
269 struct delimiters
< ::std::multiset
<T
, TComp
, TAllocator
>, char> { static const delimiters_values
<char> values
; };
271 template <typename T
, typename TComp
, typename TAllocator
>
272 const delimiters_values
<char> delimiters
< ::std::multiset
<T
, TComp
, TAllocator
>, char>::values
= { "{", ", ", "}" };
274 template <typename T
, typename TComp
, typename TAllocator
>
275 struct delimiters
< ::std::multiset
<T
, TComp
, TAllocator
>, wchar_t> { static const delimiters_values
<wchar_t> values
; };
277 template <typename T
, typename TComp
, typename TAllocator
>
278 const delimiters_values
<wchar_t> delimiters
< ::std::multiset
<T
, TComp
, TAllocator
>, wchar_t>::values
= { L
"{", L
", ", L
"}" };
280 template <typename T
, typename THash
, typename TEqual
, typename TAllocator
>
281 struct delimiters
< ::std::unordered_set
<T
, THash
, TEqual
, TAllocator
>, char> { static const delimiters_values
<char> values
; };
283 template <typename T
, typename THash
, typename TEqual
, typename TAllocator
>
284 const delimiters_values
<char> delimiters
< ::std::unordered_set
<T
, THash
, TEqual
, TAllocator
>, char>::values
= { "{", ", ", "}" };
286 template <typename T
, typename THash
, typename TEqual
, typename TAllocator
>
287 struct delimiters
< ::std::unordered_set
<T
, THash
, TEqual
, TAllocator
>, wchar_t> { static const delimiters_values
<wchar_t> values
; };
289 template <typename T
, typename THash
, typename TEqual
, typename TAllocator
>
290 const delimiters_values
<wchar_t> delimiters
< ::std::unordered_set
<T
, THash
, TEqual
, TAllocator
>, wchar_t>::values
= { L
"{", L
", ", L
"}" };
292 template <typename T
, typename THash
, typename TEqual
, typename TAllocator
>
293 struct delimiters
< ::std::unordered_multiset
<T
, THash
, TEqual
, TAllocator
>, char> { static const delimiters_values
<char> values
; };
295 template <typename T
, typename THash
, typename TEqual
, typename TAllocator
>
296 const delimiters_values
<char> delimiters
< ::std::unordered_multiset
<T
, THash
, TEqual
, TAllocator
>, char>::values
= { "{", ", ", "}" };
298 template <typename T
, typename THash
, typename TEqual
, typename TAllocator
>
299 struct delimiters
< ::std::unordered_multiset
<T
, THash
, TEqual
, TAllocator
>, wchar_t> { static const delimiters_values
<wchar_t> values
; };
301 template <typename T
, typename THash
, typename TEqual
, typename TAllocator
>
302 const delimiters_values
<wchar_t> delimiters
< ::std::unordered_multiset
<T
, THash
, TEqual
, TAllocator
>, wchar_t>::values
= { L
"{", L
", ", L
"}" };
305 // Delimiters for pair and tuple
307 template <typename T1
, typename T2
> struct delimiters
<std::pair
<T1
, T2
>, char> { static const delimiters_values
<char> values
; };
308 template <typename T1
, typename T2
> const delimiters_values
<char> delimiters
<std::pair
<T1
, T2
>, char>::values
= { "(", ", ", ")" };
309 template <typename T1
, typename T2
> struct delimiters
< ::std::pair
<T1
, T2
>, wchar_t> { static const delimiters_values
<wchar_t> values
; };
310 template <typename T1
, typename T2
> const delimiters_values
<wchar_t> delimiters
< ::std::pair
<T1
, T2
>, wchar_t>::values
= { L
"(", L
", ", L
")" };
312 template <typename
...Args
> struct delimiters
<std::tuple
<Args
...>, char> { static const delimiters_values
<char> values
; };
313 template <typename
...Args
> const delimiters_values
<char> delimiters
<std::tuple
<Args
...>, char>::values
= { "(", ", ", ")" };
314 template <typename
...Args
> struct delimiters
< ::std::tuple
<Args
...>, wchar_t> { static const delimiters_values
<wchar_t> values
; };
315 template <typename
...Args
> const delimiters_values
<wchar_t> delimiters
< ::std::tuple
<Args
...>, wchar_t>::values
= { L
"(", L
", ", L
")" };
318 // Type-erasing helper class for easy use of custom delimiters.
319 // Requires TCharTraits = std::char_traits<TChar> and TChar = char or wchar_t, and MyDelims needs to be defined for TChar.
320 // Usage: "cout << pretty_print::custom_delims<MyDelims>(x)".
322 struct custom_delims_base
324 virtual ~custom_delims_base() { }
325 virtual std::ostream
& stream(::std::ostream
&) = 0;
326 virtual std::wostream
& stream(::std::wostream
&) = 0;
329 template <typename T
, typename Delims
>
330 struct custom_delims_wrapper
: custom_delims_base
332 custom_delims_wrapper(const T
& t_
) : t(t_
) { }
334 std::ostream
& stream(std::ostream
& s
)
336 return s
<< print_container_helper
<T
, char, std::char_traits
<char>, Delims
>(t
);
339 std::wostream
& stream(std::wostream
& s
)
341 return s
<< print_container_helper
<T
, wchar_t, std::char_traits
<wchar_t>, Delims
>(t
);
348 template <typename Delims
>
351 template <typename Container
>
352 custom_delims(const Container
& c
) : base(new custom_delims_wrapper
<Container
, Delims
>(c
)) { }
354 std::unique_ptr
<custom_delims_base
> base
;
357 template <typename TChar
, typename TCharTraits
, typename Delims
>
358 inline std::basic_ostream
<TChar
, TCharTraits
> & operator<<(std::basic_ostream
<TChar
, TCharTraits
> & s
, const custom_delims
<Delims
> & p
)
360 return p
.base
->stream(s
);
364 // A wrapper for a C-style array given as pointer-plus-size.
365 // Usage: std::cout << pretty_print_array(arr, n) << std::endl;
368 struct array_wrapper_n
370 typedef const T
* const_iterator
;
371 typedef T value_type
;
373 array_wrapper_n(const T
* const a
, size_t n
) : _array(a
), _n(n
) { }
374 inline const_iterator
begin() const { return _array
; }
375 inline const_iterator
end() const { return _array
+ _n
; }
378 const T
* const _array
;
383 // A wrapper for hash-table based containers that offer local iterators to each bucket.
384 // Usage: std::cout << bucket_print(m, 4) << std::endl; (Prints bucket 5 of container m.)
386 template <typename T
>
387 struct bucket_print_wrapper
389 typedef typename
T::const_local_iterator const_iterator
;
390 typedef typename
T::size_type size_type
;
392 const_iterator
begin() const
394 return m_map
.cbegin(n
);
397 const_iterator
end() const
399 return m_map
.cend(n
);
402 bucket_print_wrapper(const T
& m
, size_type bucket
) : m_map(m
), n(bucket
) { }
409 } // namespace pretty_print
412 // Global accessor functions for the convenience wrappers
415 inline pretty_print::array_wrapper_n
<T
> pretty_print_array(const T
* const a
, size_t n
)
417 return pretty_print::array_wrapper_n
<T
>(a
, n
);
420 template <typename T
> pretty_print::bucket_print_wrapper
<T
>
421 bucket_print(const T
& m
, typename
T::size_type n
)
423 return pretty_print::bucket_print_wrapper
<T
>(m
, n
);
427 // Main magic entry point: An overload snuck into namespace std.
432 // Prints a container to the stream using default delimiters
434 template<typename T
, typename TChar
, typename TCharTraits
>
435 inline typename enable_if
< ::pretty_print::is_container
<T
>::value
,
436 basic_ostream
<TChar
, TCharTraits
> &>::type
437 operator<<(basic_ostream
<TChar
, TCharTraits
> & stream
, const T
& container
)
439 return stream
<< ::pretty_print::print_container_helper
<T
, TChar
, TCharTraits
>(container
);
445 #endif // H_PRETTY_PRINT