Rivet API documentation

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