remove the ARC epsilon define
[clinton/Smoothieware.git] / src / testframework / prettyprint.hpp
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 #ifndef H_PRETTY_PRINT
12 #define H_PRETTY_PRINT
13
14 #include <cstddef>
15 #include <iterator>
16 #include <memory>
17 #include <ostream>
18 #include <set>
19 #include <tuple>
20 #include <type_traits>
21 #include <unordered_set>
22 #include <utility>
23 #include <valarray>
24
25 namespace pretty_print
26 {
27 namespace detail
28 {
29 // SFINAE type trait to detect whether T::const_iterator exists.
30
31 struct sfinae_base
32 {
33 using yes = char;
34 using no = yes[2];
35 };
36
37 template <typename T>
38 struct has_const_iterator : private sfinae_base
39 {
40 private:
41 template <typename C> static yes & test(typename C::const_iterator*);
42 template <typename C> static no & test(...);
43 public:
44 static const bool value = sizeof(test<T>(nullptr)) == sizeof(yes);
45 using type = T;
46 };
47
48 template <typename T>
49 struct has_begin_end : private sfinae_base
50 {
51 private:
52 template <typename C>
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 *);
56
57 template <typename C> static no & f(...);
58
59 template <typename C>
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*);
63
64 template <typename C> static no & g(...);
65
66 public:
67 static bool const beg_value = sizeof(f<T>(nullptr)) == sizeof(yes);
68 static bool const end_value = sizeof(g<T>(nullptr)) == sizeof(yes);
69 };
70
71 } // namespace detail
72
73
74 // Holds the delimiter values for a specific character type
75
76 template <typename TChar>
77 struct delimiters_values
78 {
79 using char_type = TChar;
80 const char_type * prefix;
81 const char_type * delimiter;
82 const char_type * postfix;
83 };
84
85
86 // Defines the delimiter values for a specific container and character type
87
88 template <typename T, typename TChar>
89 struct delimiters
90 {
91 using type = delimiters_values<TChar>;
92 static const type values;
93 };
94
95
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.
99
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
105 {
106 using delimiters_type = TDelimiters;
107 using ostream_type = std::basic_ostream<TChar, TCharTraits>;
108
109 template <typename U>
110 struct printer
111 {
112 static void print_body(const U & c, ostream_type & stream)
113 {
114 using std::begin;
115 using std::end;
116
117 auto it = begin(c);
118 const auto the_end = end(c);
119
120 if (it != the_end)
121 {
122 for ( ; ; )
123 {
124 stream << *it;
125
126 if (++it == the_end) break;
127
128 if (delimiters_type::values.delimiter != NULL)
129 stream << delimiters_type::values.delimiter;
130 }
131 }
132 }
133 };
134
135 print_container_helper(const T & container)
136 : container_(container)
137 { }
138
139 inline void operator()(ostream_type & stream) const
140 {
141 if (delimiters_type::values.prefix != NULL)
142 stream << delimiters_type::values.prefix;
143
144 printer<T>::print_body(container_, stream);
145
146 if (delimiters_type::values.postfix != NULL)
147 stream << delimiters_type::values.postfix;
148 }
149
150 private:
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 {
160 using ostream_type = print_container_helper<T, TChar, TCharTraits, TDelimiters>::ostream_type;
161
162 static void print_body(const std::pair<T1, T2> & c, ostream_type & stream)
163 {
164 stream << c.first;
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;
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 {
177 using ostream_type = print_container_helper<T, TChar, TCharTraits, TDelimiters>::ostream_type;
178 using element_type = std::tuple<Args...>;
179
180 template <std::size_t I> struct Int { };
181
182 static void print_body(const element_type & c, ostream_type & stream)
183 {
184 tuple_print(c, stream, Int<0>());
185 }
186
187 static void tuple_print(const element_type &, ostream_type &, Int<sizeof...(Args)>)
188 {
189 }
190
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)
193 {
194 stream << std::get<0>(c);
195 tuple_print(c, stream, Int<1>());
196 }
197
198 template <std::size_t N>
199 static void tuple_print(const element_type & c, ostream_type & stream, Int<N>)
200 {
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;
203
204 stream << std::get<N>(c);
205
206 tuple_print(c, stream, Int<N + 1>());
207 }
208 };
209
210 // Prints a print_container_helper to the specified stream.
211
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)
216 {
217 helper(stream);
218 return stream;
219 }
220
221
222 // Basic is_container template; specialize to derive from std::true_type for all desired container types
223
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> { };
229
230 template <typename T, std::size_t N>
231 struct is_container<T[N]> : std::true_type { };
232
233 template <std::size_t N>
234 struct is_container<char[N]> : std::false_type { };
235
236 template <typename T>
237 struct is_container<std::valarray<T>> : std::true_type { };
238
239 template <typename T1, typename T2>
240 struct is_container<std::pair<T1, T2>> : std::true_type { };
241
242 template <typename ...Args>
243 struct is_container<std::tuple<Args...>> : std::true_type { };
244
245
246 // Default delimiters
247
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"]" };
252
253
254 // Delimiters for (multi)set and unordered_(multi)set
255
256 template <typename T, typename TComp, typename TAllocator>
257 struct delimiters< ::std::set<T, TComp, TAllocator>, char> { static const delimiters_values<char> values; };
258
259 template <typename T, typename TComp, typename TAllocator>
260 const delimiters_values<char> delimiters< ::std::set<T, TComp, TAllocator>, char>::values = { "{", ", ", "}" };
261
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; };
264
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"}" };
267
268 template <typename T, typename TComp, typename TAllocator>
269 struct delimiters< ::std::multiset<T, TComp, TAllocator>, char> { static const delimiters_values<char> values; };
270
271 template <typename T, typename TComp, typename TAllocator>
272 const delimiters_values<char> delimiters< ::std::multiset<T, TComp, TAllocator>, char>::values = { "{", ", ", "}" };
273
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; };
276
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"}" };
279
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; };
282
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 = { "{", ", ", "}" };
285
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; };
288
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"}" };
291
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; };
294
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 = { "{", ", ", "}" };
297
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; };
300
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"}" };
303
304
305 // Delimiters for pair and tuple
306
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")" };
311
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")" };
316
317
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)".
321
322 struct custom_delims_base
323 {
324 virtual ~custom_delims_base() { }
325 virtual std::ostream & stream(::std::ostream &) = 0;
326 virtual std::wostream & stream(::std::wostream &) = 0;
327 };
328
329 template <typename T, typename Delims>
330 struct custom_delims_wrapper : custom_delims_base
331 {
332 custom_delims_wrapper(const T & t_) : t(t_) { }
333
334 std::ostream & stream(std::ostream & s)
335 {
336 return s << print_container_helper<T, char, std::char_traits<char>, Delims>(t);
337 }
338
339 std::wostream & stream(std::wostream & s)
340 {
341 return s << print_container_helper<T, wchar_t, std::char_traits<wchar_t>, Delims>(t);
342 }
343
344 private:
345 const T & t;
346 };
347
348 template <typename Delims>
349 struct custom_delims
350 {
351 template <typename Container>
352 custom_delims(const Container & c) : base(new custom_delims_wrapper<Container, Delims>(c)) { }
353
354 std::unique_ptr<custom_delims_base> base;
355 };
356
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)
359 {
360 return p.base->stream(s);
361 }
362
363
364 // A wrapper for a C-style array given as pointer-plus-size.
365 // Usage: std::cout << pretty_print_array(arr, n) << std::endl;
366
367 template<typename T>
368 struct array_wrapper_n
369 {
370 typedef const T * const_iterator;
371 typedef T value_type;
372
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; }
376
377 private:
378 const T * const _array;
379 size_t _n;
380 };
381
382
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.)
385
386 template <typename T>
387 struct bucket_print_wrapper
388 {
389 typedef typename T::const_local_iterator const_iterator;
390 typedef typename T::size_type size_type;
391
392 const_iterator begin() const
393 {
394 return m_map.cbegin(n);
395 }
396
397 const_iterator end() const
398 {
399 return m_map.cend(n);
400 }
401
402 bucket_print_wrapper(const T & m, size_type bucket) : m_map(m), n(bucket) { }
403
404 private:
405 const T & m_map;
406 const size_type n;
407 };
408
409 } // namespace pretty_print
410
411
412 // Global accessor functions for the convenience wrappers
413
414 template<typename T>
415 inline pretty_print::array_wrapper_n<T> pretty_print_array(const T * const a, size_t n)
416 {
417 return pretty_print::array_wrapper_n<T>(a, n);
418 }
419
420 template <typename T> pretty_print::bucket_print_wrapper<T>
421 bucket_print(const T & m, typename T::size_type n)
422 {
423 return pretty_print::bucket_print_wrapper<T>(m, n);
424 }
425
426
427 // Main magic entry point: An overload snuck into namespace std.
428 // Can we do better?
429
430 namespace std
431 {
432 // Prints a container to the stream using default delimiters
433
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)
438 {
439 return stream << ::pretty_print::print_container_helper<T, TChar, TCharTraits>(container);
440 }
441 }
442
443
444
445 #endif // H_PRETTY_PRINT