rivet is hosted by Hepforge, IPPP Durham
Rivet 4.0.0
PrettyPrint.hh
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// A pretty printing library for C++
7//
8// Usage:
9// Include this header, and operator<< will "just work".
10//
11// See: https://louisdx.github.io/cxx-prettyprint/
12
13#ifndef H_PRETTY_PRINT
14#define H_PRETTY_PRINT
15
17
18#include <cstddef>
19#include <iterator>
20#include <memory>
21#include <ostream>
22#include <set>
23#include <tuple>
24#include <type_traits>
25#include <unordered_set>
26#include <utility>
27#include <valarray>
28
29namespace Rivet
30{
31namespace pretty_print
32{
33 namespace detail
34 {
35 // SFINAE type trait to detect whether T::const_iterator exists.
36
37 struct sfinae_base
38 {
39 using yes = char;
40 using no = yes[2];
41 };
42
43 template <typename T>
44 struct has_const_iterator : private sfinae_base
45 {
46 private:
47 template <typename C> static yes & test(typename C::const_iterator*);
48 template <typename C> static no & test(...);
49 public:
50 static const bool value = sizeof(test<T>(nullptr)) == sizeof(yes);
51 using type = T;
52 };
53
54 template <typename T>
55 struct has_begin_end : private sfinae_base
56 {
57 private:
58 template <typename C>
59 static yes & f(typename std::enable_if<
60 std::is_same<decltype(static_cast<typename C::const_iterator(C::*)() const>(&C::begin)),
61 typename C::const_iterator(C::*)() const>::value>::type *);
62
63 template <typename C> static no & f(...);
64
65 template <typename C>
66 static yes & g(typename std::enable_if<
67 std::is_same<decltype(static_cast<typename C::const_iterator(C::*)() const>(&C::end)),
68 typename C::const_iterator(C::*)() const>::value, void>::type*);
69
70 template <typename C> static no & g(...);
71
72 public:
73 static bool const beg_value = sizeof(f<T>(nullptr)) == sizeof(yes);
74 static bool const end_value = sizeof(g<T>(nullptr)) == sizeof(yes);
75 };
76
77 } // namespace detail
78
79
80 // Holds the delimiter values for a specific character type
81
82 template <typename TChar>
83 struct delimiters_values
84 {
85 using char_type = TChar;
86 const char_type * prefix;
87 const char_type * delimiter;
88 const char_type * postfix;
89 };
90
91
92 // Defines the delimiter values for a specific container and character type
93
94 template <typename T, typename TChar>
95 struct delimiters
96 {
97 using type = delimiters_values<TChar>;
98 static const type values;
99 };
100
101
102 // Functor to print containers. You can use this directly if you want
103 // to specificy a non-default delimiters type. The printing logic can
104 // be customized by specializing the nested template.
105
106 template <typename T,
107 typename TChar = char,
108 typename TCharTraits = ::std::char_traits<TChar>,
109 typename TDelimiters = delimiters<T, TChar>>
110 struct print_container_helper
111 {
112 using delimiters_type = TDelimiters;
113 using ostream_type = std::basic_ostream<TChar, TCharTraits>;
114
115 template <typename U>
116 struct printer
117 {
118 static void print_body(const U & c, ostream_type & stream)
119 {
120 using std::begin;
121 using std::end;
122
123 auto it = begin(c);
124 const auto the_end = end(c);
125
126 if (it != the_end)
127 {
128 for ( ; ; )
129 {
130 stream << *it;
131
132 if (++it == the_end) break;
133
134 if (delimiters_type::values.delimiter != NULL)
135 stream << delimiters_type::values.delimiter;
136 }
137 }
138 }
139 };
140
141 print_container_helper(const T & container)
142 : container_(container)
143 { }
144
145 inline void operator()(ostream_type & stream) const
146 {
147 if (delimiters_type::values.prefix != NULL)
148 stream << delimiters_type::values.prefix;
149
150 printer<T>::print_body(container_, stream);
151
152 if (delimiters_type::values.postfix != NULL)
153 stream << delimiters_type::values.postfix;
154 }
155
156 private:
157 const T & container_;
158 };
159
160 // Specialization for pairs
161
162 template <typename T, typename TChar, typename TCharTraits, typename TDelimiters>
163 template <typename T1, typename T2>
164 struct print_container_helper<T, TChar, TCharTraits, TDelimiters>::printer<std::pair<T1, T2>>
165 {
166 using ostream_type = typename print_container_helper<T, TChar, TCharTraits, TDelimiters>::ostream_type;
167
168 static void print_body(const std::pair<T1, T2> & c, ostream_type & stream)
169 {
170 stream << c.first;
171 if (print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter != NULL)
172 stream << print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter;
173 stream << c.second;
174 }
175 };
176
177 // Specialization for tuples
178
179 template <typename T, typename TChar, typename TCharTraits, typename TDelimiters>
180 template <typename ...Args>
181 struct print_container_helper<T, TChar, TCharTraits, TDelimiters>::printer<std::tuple<Args...>>
182 {
183 using ostream_type = typename print_container_helper<T, TChar, TCharTraits, TDelimiters>::ostream_type;
184 using element_type = std::tuple<Args...>;
185
186 template <std::size_t I> struct Int { };
187
188 static void print_body(const element_type & c, ostream_type & stream)
189 {
190 tuple_print(c, stream, Int<0>());
191 }
192
193 static void tuple_print(const element_type &, ostream_type &, Int<sizeof...(Args)>)
194 {
195 }
196
197 static void tuple_print(const element_type & c, ostream_type & stream,
198 typename std::conditional<sizeof...(Args) != 0, Int<0>, std::nullptr_t>::type)
199 {
200 stream << std::get<0>(c);
201 tuple_print(c, stream, Int<1>());
202 }
203
204 template <std::size_t N>
205 static void tuple_print(const element_type & c, ostream_type & stream, Int<N>)
206 {
207 if (print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter != NULL)
208 stream << print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter;
209
210 stream << std::get<N>(c);
211
212 tuple_print(c, stream, Int<N + 1>());
213 }
214 };
215
216 // Prints a print_container_helper to the specified stream.
217
218 template<typename T, typename TChar, typename TCharTraits, typename TDelimiters>
219 inline std::basic_ostream<TChar, TCharTraits> & operator<<(
220 std::basic_ostream<TChar, TCharTraits> & stream,
221 const print_container_helper<T, TChar, TCharTraits, TDelimiters> & helper)
222 {
223 helper(stream);
224 return stream;
225 }
226
227
228 // Basic is_container template; specialize to derive from std::true_type for all desired container types
229
230 template <typename T>
231 struct is_container : public std::integral_constant<bool,
232 detail::has_const_iterator<T>::value &&
233 detail::has_begin_end<T>::beg_value &&
234 detail::has_begin_end<T>::end_value> { };
235
236 template <typename T, std::size_t N>
237 struct is_container<T[N]> : std::true_type { };
238
239 template <std::size_t N>
240 struct is_container<char[N]> : std::false_type { };
241
242 template <typename T>
243 struct is_container<std::valarray<T>> : std::true_type { };
244
245 template <typename T1, typename T2>
246 struct is_container<std::pair<T1, T2>> : std::true_type { };
247
248 template <typename ...Args>
249 struct is_container<std::tuple<Args...>> : std::true_type { };
250
251
252 // Default delimiters
253
254 template <typename T> struct delimiters<T, char> { static const delimiters_values<char> values; };
255 template <typename T> const delimiters_values<char> delimiters<T, char>::values = { "[", ", ", "]" };
256 template <typename T> struct delimiters<T, wchar_t> { static const delimiters_values<wchar_t> values; };
257 template <typename T> const delimiters_values<wchar_t> delimiters<T, wchar_t>::values = { L"[", L", ", L"]" };
258
259
260 // Delimiters for (multi)set and unordered_(multi)set
261
262 template <typename T, typename TComp, typename TAllocator>
263 struct delimiters< ::std::set<T, TComp, TAllocator>, char> { static const delimiters_values<char> values; };
264
265 template <typename T, typename TComp, typename TAllocator>
266 const delimiters_values<char> delimiters< ::std::set<T, TComp, TAllocator>, char>::values = { "{", ", ", "}" };
267
268 template <typename T, typename TComp, typename TAllocator>
269 struct delimiters< ::std::set<T, TComp, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; };
270
271 template <typename T, typename TComp, typename TAllocator>
272 const delimiters_values<wchar_t> delimiters< ::std::set<T, TComp, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
273
274 template <typename T, typename TComp, typename TAllocator>
275 struct delimiters< ::std::multiset<T, TComp, TAllocator>, char> { static const delimiters_values<char> values; };
276
277 template <typename T, typename TComp, typename TAllocator>
278 const delimiters_values<char> delimiters< ::std::multiset<T, TComp, TAllocator>, char>::values = { "{", ", ", "}" };
279
280 template <typename T, typename TComp, typename TAllocator>
281 struct delimiters< ::std::multiset<T, TComp, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; };
282
283 template <typename T, typename TComp, typename TAllocator>
284 const delimiters_values<wchar_t> delimiters< ::std::multiset<T, TComp, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
285
286 template <typename T, typename THash, typename TEqual, typename TAllocator>
287 struct delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, char> { static const delimiters_values<char> values; };
288
289 template <typename T, typename THash, typename TEqual, typename TAllocator>
290 const delimiters_values<char> delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, char>::values = { "{", ", ", "}" };
291
292 template <typename T, typename THash, typename TEqual, typename TAllocator>
293 struct delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; };
294
295 template <typename T, typename THash, typename TEqual, typename TAllocator>
296 const delimiters_values<wchar_t> delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
297
298 template <typename T, typename THash, typename TEqual, typename TAllocator>
299 struct delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, char> { static const delimiters_values<char> values; };
300
301 template <typename T, typename THash, typename TEqual, typename TAllocator>
302 const delimiters_values<char> delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, char>::values = { "{", ", ", "}" };
303
304 template <typename T, typename THash, typename TEqual, typename TAllocator>
305 struct delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; };
306
307 template <typename T, typename THash, typename TEqual, typename TAllocator>
308 const delimiters_values<wchar_t> delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" };
309
310
311 // Delimiters for pair and tuple
312
313 template <typename T1, typename T2> struct delimiters<std::pair<T1, T2>, char> { static const delimiters_values<char> values; };
314 template <typename T1, typename T2> const delimiters_values<char> delimiters<std::pair<T1, T2>, char>::values = { "(", ", ", ")" };
315 template <typename T1, typename T2> struct delimiters< ::std::pair<T1, T2>, wchar_t> { static const delimiters_values<wchar_t> values; };
316 template <typename T1, typename T2> const delimiters_values<wchar_t> delimiters< ::std::pair<T1, T2>, wchar_t>::values = { L"(", L", ", L")" };
317
318 template <typename ...Args> struct delimiters<std::tuple<Args...>, char> { static const delimiters_values<char> values; };
319 template <typename ...Args> const delimiters_values<char> delimiters<std::tuple<Args...>, char>::values = { "(", ", ", ")" };
320 template <typename ...Args> struct delimiters< ::std::tuple<Args...>, wchar_t> { static const delimiters_values<wchar_t> values; };
321 template <typename ...Args> const delimiters_values<wchar_t> delimiters< ::std::tuple<Args...>, wchar_t>::values = { L"(", L", ", L")" };
322
323
324 // Type-erasing helper class for easy use of custom delimiters.
325 // Requires TCharTraits = std::char_traits<TChar> and TChar = char or wchar_t, and MyDelims needs to be defined for TChar.
326 // Usage: "cout << pretty_print::custom_delims<MyDelims>(x)".
327
328 struct custom_delims_base
329 {
330 virtual ~custom_delims_base() { }
331 virtual std::ostream & stream(::std::ostream &) = 0;
332 virtual std::wostream & stream(::std::wostream &) = 0;
333 };
334
335 template <typename T, typename Delims>
336 struct custom_delims_wrapper : custom_delims_base
337 {
338 custom_delims_wrapper(const T & t_) : t(t_) { }
339
340 std::ostream & stream(std::ostream & s)
341 {
342 return s << print_container_helper<T, char, std::char_traits<char>, Delims>(t);
343 }
344
345 std::wostream & stream(std::wostream & s)
346 {
347 return s << print_container_helper<T, wchar_t, std::char_traits<wchar_t>, Delims>(t);
348 }
349
350 private:
351 const T & t;
352 };
353
354 template <typename Delims>
355 struct custom_delims
356 {
357 template <typename Container>
358 custom_delims(const Container & c) : base(new custom_delims_wrapper<Container, Delims>(c)) { }
359
360 std::unique_ptr<custom_delims_base> base;
361 };
362
363 template <typename TChar, typename TCharTraits, typename Delims>
364 inline std::basic_ostream<TChar, TCharTraits> & operator<<(std::basic_ostream<TChar, TCharTraits> & s, const custom_delims<Delims> & p)
365 {
366 return p.base->stream(s);
367 }
368
369
370 // A wrapper for a C-style array given as pointer-plus-size.
371 // Usage: std::cout << pretty_print_array(arr, n) << std::'\n';
372
373 template<typename T>
374 struct array_wrapper_n
375 {
376 typedef const T * const_iterator;
377 typedef T value_type;
378
379 array_wrapper_n(const T * const a, size_t n) : _array(a), _n(n) { }
380 inline const_iterator begin() const { return _array; }
381 inline const_iterator end() const { return _array + _n; }
382
383 private:
384 const T * const _array;
385 size_t _n;
386 };
387
388
389 // A wrapper for hash-table based containers that offer local iterators to each bucket.
390 // Usage: std::cout << bucket_print(m, 4) << std::'\n'; (Prints bucket 5 of container m.)
391
392 template <typename T>
393 struct bucket_print_wrapper
394 {
395 typedef typename T::const_local_iterator const_iterator;
396 typedef typename T::size_type size_type;
397
398 const_iterator begin() const
399 {
400 return m_map.cbegin(n);
401 }
402
403 const_iterator end() const
404 {
405 return m_map.cend(n);
406 }
407
408 bucket_print_wrapper(const T & m, size_type bucket) : m_map(m), n(bucket) { }
409
410 private:
411 const T & m_map;
412 const size_type n;
413 };
414
415} // namespace pretty_print
416
417
418// Global accessor functions for the convenience wrappers
419
420template<typename T>
421inline pretty_print::array_wrapper_n<T> pretty_print_array(const T * const a, size_t n)
422{
423 return pretty_print::array_wrapper_n<T>(a, n);
424}
425
426template <typename T> pretty_print::bucket_print_wrapper<T>
427bucket_print(const T & m, typename T::size_type n)
428{
429 return pretty_print::bucket_print_wrapper<T>(m, n);
430}
431
432
433} // namespace Rivet
434
435
436
437// Main magic entry point: An overload snuck into namespace std.
438// Can we do better?
439
440namespace std
441{
442
443// Prints a container to the stream using default delimiters
444template<typename T, typename TChar, typename TCharTraits>
445inline typename enable_if< ::Rivet::pretty_print::is_container<T>::value,
446 basic_ostream<TChar, TCharTraits> &>::type
447operator<<(std::basic_ostream<TChar, TCharTraits> & stream, const T & container)
448{
449 return stream << ::Rivet::pretty_print::print_container_helper<T, TChar, TCharTraits>(container);
450}
451
452}
453
455
456#endif // H_PRETTY_PRINT
Definition MC_CENT_PPB_Projections.hh:10
std::ostream & operator<<(std::ostream &os, const AnalysisInfo &ai)
Stream an AnalysisInfo as a text description.
Definition AnalysisInfo.hh:362
STL namespace.