PrettyPrint.hh
Go to the documentation of this file.
00001 // Copyright Louis Delacroix 2010 - 2014. 00002 // Distributed under the Boost Software License, Version 1.0. 00003 // (See accompanying file LICENSE_1_0.txt or copy at 00004 // http://www.boost.org/LICENSE_1_0.txt) 00005 // 00006 // A pretty printing library for C++ 00007 // 00008 // Usage: 00009 // Include this header, and operator<< will "just work". 00010 // 00011 // See: https://louisdx.github.io/cxx-prettyprint/ 00012 00013 #ifndef H_PRETTY_PRINT 00014 #define H_PRETTY_PRINT 00015 00016 #include <cstddef> 00017 #include <iterator> 00018 #include <memory> 00019 #include <ostream> 00020 #include <set> 00021 #include <tuple> 00022 #include <type_traits> 00023 #include <unordered_set> 00024 #include <utility> 00025 #include <valarray> 00026 00027 namespace Rivet 00028 { 00029 namespace pretty_print 00030 { 00031 namespace detail 00032 { 00033 // SFINAE type trait to detect whether T::const_iterator exists. 00034 00035 struct sfinae_base 00036 { 00037 using yes = char; 00038 using no = yes[2]; 00039 }; 00040 00041 template <typename T> 00042 struct has_const_iterator : private sfinae_base 00043 { 00044 private: 00045 template <typename C> static yes & test(typename C::const_iterator*); 00046 template <typename C> static no & test(...); 00047 public: 00048 static const bool value = sizeof(test<T>(nullptr)) == sizeof(yes); 00049 using type = T; 00050 }; 00051 00052 template <typename T> 00053 struct has_begin_end : private sfinae_base 00054 { 00055 private: 00056 template <typename C> 00057 static yes & f(typename std::enable_if< 00058 std::is_same<decltype(static_cast<typename C::const_iterator(C::*)() const>(&C::begin)), 00059 typename C::const_iterator(C::*)() const>::value>::type *); 00060 00061 template <typename C> static no & f(...); 00062 00063 template <typename C> 00064 static yes & g(typename std::enable_if< 00065 std::is_same<decltype(static_cast<typename C::const_iterator(C::*)() const>(&C::end)), 00066 typename C::const_iterator(C::*)() const>::value, void>::type*); 00067 00068 template <typename C> static no & g(...); 00069 00070 public: 00071 static bool const beg_value = sizeof(f<T>(nullptr)) == sizeof(yes); 00072 static bool const end_value = sizeof(g<T>(nullptr)) == sizeof(yes); 00073 }; 00074 00075 } // namespace detail 00076 00077 00078 // Holds the delimiter values for a specific character type 00079 00080 template <typename TChar> 00081 struct delimiters_values 00082 { 00083 using char_type = TChar; 00084 const char_type * prefix; 00085 const char_type * delimiter; 00086 const char_type * postfix; 00087 }; 00088 00089 00090 // Defines the delimiter values for a specific container and character type 00091 00092 template <typename T, typename TChar> 00093 struct delimiters 00094 { 00095 using type = delimiters_values<TChar>; 00096 static const type values; 00097 }; 00098 00099 00100 // Functor to print containers. You can use this directly if you want 00101 // to specificy a non-default delimiters type. The printing logic can 00102 // be customized by specializing the nested template. 00103 00104 template <typename T, 00105 typename TChar = char, 00106 typename TCharTraits = ::std::char_traits<TChar>, 00107 typename TDelimiters = delimiters<T, TChar>> 00108 struct print_container_helper 00109 { 00110 using delimiters_type = TDelimiters; 00111 using ostream_type = std::basic_ostream<TChar, TCharTraits>; 00112 00113 template <typename U> 00114 struct printer 00115 { 00116 static void print_body(const U & c, ostream_type & stream) 00117 { 00118 using std::begin; 00119 using std::end; 00120 00121 auto it = begin(c); 00122 const auto the_end = end(c); 00123 00124 if (it != the_end) 00125 { 00126 for ( ; ; ) 00127 { 00128 stream << *it; 00129 00130 if (++it == the_end) break; 00131 00132 if (delimiters_type::values.delimiter != NULL) 00133 stream << delimiters_type::values.delimiter; 00134 } 00135 } 00136 } 00137 }; 00138 00139 print_container_helper(const T & container) 00140 : container_(container) 00141 { } 00142 00143 inline void operator()(ostream_type & stream) const 00144 { 00145 if (delimiters_type::values.prefix != NULL) 00146 stream << delimiters_type::values.prefix; 00147 00148 printer<T>::print_body(container_, stream); 00149 00150 if (delimiters_type::values.postfix != NULL) 00151 stream << delimiters_type::values.postfix; 00152 } 00153 00154 private: 00155 const T & container_; 00156 }; 00157 00158 // Specialization for pairs 00159 00160 template <typename T, typename TChar, typename TCharTraits, typename TDelimiters> 00161 template <typename T1, typename T2> 00162 struct print_container_helper<T, TChar, TCharTraits, TDelimiters>::printer<std::pair<T1, T2>> 00163 { 00164 using ostream_type = typename print_container_helper<T, TChar, TCharTraits, TDelimiters>::ostream_type; 00165 00166 static void print_body(const std::pair<T1, T2> & c, ostream_type & stream) 00167 { 00168 stream << c.first; 00169 if (print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter != NULL) 00170 stream << print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter; 00171 stream << c.second; 00172 } 00173 }; 00174 00175 // Specialization for tuples 00176 00177 template <typename T, typename TChar, typename TCharTraits, typename TDelimiters> 00178 template <typename ...Args> 00179 struct print_container_helper<T, TChar, TCharTraits, TDelimiters>::printer<std::tuple<Args...>> 00180 { 00181 using ostream_type = typename print_container_helper<T, TChar, TCharTraits, TDelimiters>::ostream_type; 00182 using element_type = std::tuple<Args...>; 00183 00184 template <std::size_t I> struct Int { }; 00185 00186 static void print_body(const element_type & c, ostream_type & stream) 00187 { 00188 tuple_print(c, stream, Int<0>()); 00189 } 00190 00191 static void tuple_print(const element_type &, ostream_type &, Int<sizeof...(Args)>) 00192 { 00193 } 00194 00195 static void tuple_print(const element_type & c, ostream_type & stream, 00196 typename std::conditional<sizeof...(Args) != 0, Int<0>, std::nullptr_t>::type) 00197 { 00198 stream << std::get<0>(c); 00199 tuple_print(c, stream, Int<1>()); 00200 } 00201 00202 template <std::size_t N> 00203 static void tuple_print(const element_type & c, ostream_type & stream, Int<N>) 00204 { 00205 if (print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter != NULL) 00206 stream << print_container_helper<T, TChar, TCharTraits, TDelimiters>::delimiters_type::values.delimiter; 00207 00208 stream << std::get<N>(c); 00209 00210 tuple_print(c, stream, Int<N + 1>()); 00211 } 00212 }; 00213 00214 // Prints a print_container_helper to the specified stream. 00215 00216 template<typename T, typename TChar, typename TCharTraits, typename TDelimiters> 00217 inline std::basic_ostream<TChar, TCharTraits> & operator<<( 00218 std::basic_ostream<TChar, TCharTraits> & stream, 00219 const print_container_helper<T, TChar, TCharTraits, TDelimiters> & helper) 00220 { 00221 helper(stream); 00222 return stream; 00223 } 00224 00225 00226 // Basic is_container template; specialize to derive from std::true_type for all desired container types 00227 00228 template <typename T> 00229 struct is_container : public std::integral_constant<bool, 00230 detail::has_const_iterator<T>::value && 00231 detail::has_begin_end<T>::beg_value && 00232 detail::has_begin_end<T>::end_value> { }; 00233 00234 template <typename T, std::size_t N> 00235 struct is_container<T[N]> : std::true_type { }; 00236 00237 template <std::size_t N> 00238 struct is_container<char[N]> : std::false_type { }; 00239 00240 template <typename T> 00241 struct is_container<std::valarray<T>> : std::true_type { }; 00242 00243 template <typename T1, typename T2> 00244 struct is_container<std::pair<T1, T2>> : std::true_type { }; 00245 00246 template <typename ...Args> 00247 struct is_container<std::tuple<Args...>> : std::true_type { }; 00248 00249 00250 // Default delimiters 00251 00252 template <typename T> struct delimiters<T, char> { static const delimiters_values<char> values; }; 00253 template <typename T> const delimiters_values<char> delimiters<T, char>::values = { "[", ", ", "]" }; 00254 template <typename T> struct delimiters<T, wchar_t> { static const delimiters_values<wchar_t> values; }; 00255 template <typename T> const delimiters_values<wchar_t> delimiters<T, wchar_t>::values = { L"[", L", ", L"]" }; 00256 00257 00258 // Delimiters for (multi)set and unordered_(multi)set 00259 00260 template <typename T, typename TComp, typename TAllocator> 00261 struct delimiters< ::std::set<T, TComp, TAllocator>, char> { static const delimiters_values<char> values; }; 00262 00263 template <typename T, typename TComp, typename TAllocator> 00264 const delimiters_values<char> delimiters< ::std::set<T, TComp, TAllocator>, char>::values = { "{", ", ", "}" }; 00265 00266 template <typename T, typename TComp, typename TAllocator> 00267 struct delimiters< ::std::set<T, TComp, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; }; 00268 00269 template <typename T, typename TComp, typename TAllocator> 00270 const delimiters_values<wchar_t> delimiters< ::std::set<T, TComp, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" }; 00271 00272 template <typename T, typename TComp, typename TAllocator> 00273 struct delimiters< ::std::multiset<T, TComp, TAllocator>, char> { static const delimiters_values<char> values; }; 00274 00275 template <typename T, typename TComp, typename TAllocator> 00276 const delimiters_values<char> delimiters< ::std::multiset<T, TComp, TAllocator>, char>::values = { "{", ", ", "}" }; 00277 00278 template <typename T, typename TComp, typename TAllocator> 00279 struct delimiters< ::std::multiset<T, TComp, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; }; 00280 00281 template <typename T, typename TComp, typename TAllocator> 00282 const delimiters_values<wchar_t> delimiters< ::std::multiset<T, TComp, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" }; 00283 00284 template <typename T, typename THash, typename TEqual, typename TAllocator> 00285 struct delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, char> { static const delimiters_values<char> values; }; 00286 00287 template <typename T, typename THash, typename TEqual, typename TAllocator> 00288 const delimiters_values<char> delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, char>::values = { "{", ", ", "}" }; 00289 00290 template <typename T, typename THash, typename TEqual, typename TAllocator> 00291 struct delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; }; 00292 00293 template <typename T, typename THash, typename TEqual, typename TAllocator> 00294 const delimiters_values<wchar_t> delimiters< ::std::unordered_set<T, THash, TEqual, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" }; 00295 00296 template <typename T, typename THash, typename TEqual, typename TAllocator> 00297 struct delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, char> { static const delimiters_values<char> values; }; 00298 00299 template <typename T, typename THash, typename TEqual, typename TAllocator> 00300 const delimiters_values<char> delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, char>::values = { "{", ", ", "}" }; 00301 00302 template <typename T, typename THash, typename TEqual, typename TAllocator> 00303 struct delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, wchar_t> { static const delimiters_values<wchar_t> values; }; 00304 00305 template <typename T, typename THash, typename TEqual, typename TAllocator> 00306 const delimiters_values<wchar_t> delimiters< ::std::unordered_multiset<T, THash, TEqual, TAllocator>, wchar_t>::values = { L"{", L", ", L"}" }; 00307 00308 00309 // Delimiters for pair and tuple 00310 00311 template <typename T1, typename T2> struct delimiters<std::pair<T1, T2>, char> { static const delimiters_values<char> values; }; 00312 template <typename T1, typename T2> const delimiters_values<char> delimiters<std::pair<T1, T2>, char>::values = { "(", ", ", ")" }; 00313 template <typename T1, typename T2> struct delimiters< ::std::pair<T1, T2>, wchar_t> { static const delimiters_values<wchar_t> values; }; 00314 template <typename T1, typename T2> const delimiters_values<wchar_t> delimiters< ::std::pair<T1, T2>, wchar_t>::values = { L"(", L", ", L")" }; 00315 00316 template <typename ...Args> struct delimiters<std::tuple<Args...>, char> { static const delimiters_values<char> values; }; 00317 template <typename ...Args> const delimiters_values<char> delimiters<std::tuple<Args...>, char>::values = { "(", ", ", ")" }; 00318 template <typename ...Args> struct delimiters< ::std::tuple<Args...>, wchar_t> { static const delimiters_values<wchar_t> values; }; 00319 template <typename ...Args> const delimiters_values<wchar_t> delimiters< ::std::tuple<Args...>, wchar_t>::values = { L"(", L", ", L")" }; 00320 00321 00322 // Type-erasing helper class for easy use of custom delimiters. 00323 // Requires TCharTraits = std::char_traits<TChar> and TChar = char or wchar_t, and MyDelims needs to be defined for TChar. 00324 // Usage: "cout << pretty_print::custom_delims<MyDelims>(x)". 00325 00326 struct custom_delims_base 00327 { 00328 virtual ~custom_delims_base() { } 00329 virtual std::ostream & stream(::std::ostream &) = 0; 00330 virtual std::wostream & stream(::std::wostream &) = 0; 00331 }; 00332 00333 template <typename T, typename Delims> 00334 struct custom_delims_wrapper : custom_delims_base 00335 { 00336 custom_delims_wrapper(const T & t_) : t(t_) { } 00337 00338 std::ostream & stream(std::ostream & s) 00339 { 00340 return s << print_container_helper<T, char, std::char_traits<char>, Delims>(t); 00341 } 00342 00343 std::wostream & stream(std::wostream & s) 00344 { 00345 return s << print_container_helper<T, wchar_t, std::char_traits<wchar_t>, Delims>(t); 00346 } 00347 00348 private: 00349 const T & t; 00350 }; 00351 00352 template <typename Delims> 00353 struct custom_delims 00354 { 00355 template <typename Container> 00356 custom_delims(const Container & c) : base(new custom_delims_wrapper<Container, Delims>(c)) { } 00357 00358 std::unique_ptr<custom_delims_base> base; 00359 }; 00360 00361 template <typename TChar, typename TCharTraits, typename Delims> 00362 inline std::basic_ostream<TChar, TCharTraits> & operator<<(std::basic_ostream<TChar, TCharTraits> & s, const custom_delims<Delims> & p) 00363 { 00364 return p.base->stream(s); 00365 } 00366 00367 00368 // A wrapper for a C-style array given as pointer-plus-size. 00369 // Usage: std::cout << pretty_print_array(arr, n) << std::endl; 00370 00371 template<typename T> 00372 struct array_wrapper_n 00373 { 00374 typedef const T * const_iterator; 00375 typedef T value_type; 00376 00377 array_wrapper_n(const T * const a, size_t n) : _array(a), _n(n) { } 00378 inline const_iterator begin() const { return _array; } 00379 inline const_iterator end() const { return _array + _n; } 00380 00381 private: 00382 const T * const _array; 00383 size_t _n; 00384 }; 00385 00386 00387 // A wrapper for hash-table based containers that offer local iterators to each bucket. 00388 // Usage: std::cout << bucket_print(m, 4) << std::endl; (Prints bucket 5 of container m.) 00389 00390 template <typename T> 00391 struct bucket_print_wrapper 00392 { 00393 typedef typename T::const_local_iterator const_iterator; 00394 typedef typename T::size_type size_type; 00395 00396 const_iterator begin() const 00397 { 00398 return m_map.cbegin(n); 00399 } 00400 00401 const_iterator end() const 00402 { 00403 return m_map.cend(n); 00404 } 00405 00406 bucket_print_wrapper(const T & m, size_type bucket) : m_map(m), n(bucket) { } 00407 00408 private: 00409 const T & m_map; 00410 const size_type n; 00411 }; 00412 00413 } // namespace pretty_print 00414 00415 00416 // Global accessor functions for the convenience wrappers 00417 00418 template<typename T> 00419 inline pretty_print::array_wrapper_n<T> pretty_print_array(const T * const a, size_t n) 00420 { 00421 return pretty_print::array_wrapper_n<T>(a, n); 00422 } 00423 00424 template <typename T> pretty_print::bucket_print_wrapper<T> 00425 bucket_print(const T & m, typename T::size_type n) 00426 { 00427 return pretty_print::bucket_print_wrapper<T>(m, n); 00428 } 00429 00430 00431 } // namespace Rivet 00432 00433 00434 00435 // Main magic entry point: An overload snuck into namespace std. 00436 // Can we do better? 00437 00438 namespace std 00439 { 00440 00441 // Prints a container to the stream using default delimiters 00442 template<typename T, typename TChar, typename TCharTraits> 00443 inline typename enable_if< ::Rivet::pretty_print::is_container<T>::value, 00444 basic_ostream<TChar, TCharTraits> &>::type 00445 operator<<(std::basic_ostream<TChar, TCharTraits> & stream, const T & container) 00446 { 00447 return stream << ::Rivet::pretty_print::print_container_helper<T, TChar, TCharTraits>(container); 00448 } 00449 00450 } 00451 00452 00453 00454 #endif // H_PRETTY_PRINT Generated on Tue Dec 13 2016 16:32:40 for The Rivet MC analysis system by ![]() |