/prelude/more_ostreaming.hpp
C++ Header | 393 lines | 304 code | 86 blank | 3 comment | 27 complexity | d2ecc4a53443869b4684f9f2153740b8 MD5 | raw file
1#ifndef MORE_OSTREAMING_HPP 2#define MORE_OSTREAMING_HPP 3 4#include <ostream> 5#include <valarray> 6#include <utility> 7#include <stack> 8#include <queue> 9#include <cstdlib> 10#include <ctime> 11#include <algorithm> 12#include "geordi.hpp" 13#include "literal_escape.hpp" 14 15#if !defined(__clang__) && __cplusplus >= 201500 // TODO 16#include <experimental/filesystem> 17#endif 18 19template <typename C, typename Tr> 20std::basic_ostream<C, Tr> & operator<<(std::basic_ostream<C, Tr> & o, utsname const & u) 21{ return o << u.sysname << ' ' << u.release << ' ' << u.version, u.machine; } 22 23 24#if __cplusplus >= 201103 25 26template <typename C, typename Tr, typename T> 27std::basic_ostream<C, Tr> & operator<<(std::basic_ostream<C, Tr> & o, std::reference_wrapper<T> const & rw) 28{ T & r(rw); return o << r; } 29 30#endif 31 32template <typename C, typename Tr, typename A, typename B> 33std::basic_ostream<C, Tr> & operator<< (std::basic_ostream<C, Tr> & o, std::pair<A, B> const & p) 34{ return o << '{' << escape(p.first) << ", " << escape(p.second) << '}'; } 35 36template <typename C, typename Tr, typename D> 37void print_div_t(std::basic_ostream<C, Tr> & o, D const d) { o << '{' << d.quot << ", " << d.rem << "}"; } 38 39template <typename C, typename Tr> 40std::basic_ostream<C, Tr> & operator<<(std::basic_ostream<C, Tr> & o, std::div_t const d) 41{ print_div_t(o, d); return o; } 42 43template <typename C, typename Tr> 44std::basic_ostream<C, Tr> & operator<<(std::basic_ostream<C, Tr> & o, std::ldiv_t const d) 45{ print_div_t(o, d); return o; } 46 47#if __cplusplus >= 201103 48 49template <typename C, typename Tr> 50std::basic_ostream<C, Tr> & operator<<(std::basic_ostream<C, Tr> & o, std::lldiv_t const d) 51{ print_div_t(o, d); return o; } 52 53template <typename C, typename T, typename R, typename... A> 54std::basic_ostream<C, T> & operator<<(std::basic_ostream<C, T> & o, R (* const p) (A...)) 55{ 56 void * q; 57 static_assert(sizeof(p) == sizeof(q), "void- and function-pointer differ in size"); 58 std::copy(reinterpret_cast<char const *>(&p), 59 reinterpret_cast<char const *>(&p) + sizeof(p), reinterpret_cast<char *>(&q)); 60 return o << q; 61} 62 63#include <tuple> 64 65namespace more_ostreaming { namespace detail { 66 67 template <int O> 68 struct tuple_printer 69 { 70 template <typename C, typename Tr, typename... P> 71 static void print (std::basic_ostream<C, Tr> & o, std::tuple<P...> const & t) 72 { 73 if (O != 1) { tuple_printer<O-1>::print(o, t); o << ", "; } 74 o << escape(std::get<O-1>(t)); 75 } 76 }; 77 78 template <> 79 struct tuple_printer<0> 80 { 81 template <typename C, typename Tr, typename T> 82 static void print (std::basic_ostream<C, Tr> &, T const &) {} 83 }; 84}} 85 86template <typename C, typename Tr, typename... P> 87std::basic_ostream<C, Tr> & operator<< (std::basic_ostream<C, Tr> & o, std::tuple<P...> const & t) 88{ o << '{'; more_ostreaming::detail::tuple_printer<sizeof...(P)>::print(o, t); return o << '}'; } 89 90#endif 91 92#if __cplusplus >= 201103 93 94namespace more_ostreaming 95{ 96 template <typename C, typename Tr, typename Range> 97 void delimit(std::basic_ostream<C, Tr> & o, Range const & r) 98 { 99 bool first = true; 100 for (auto && x : r) { if (first) first = false; else o << ", "; o << escape(x); } 101 } 102 103 #if !defined(__clang__) 104 extern template void delimit<char, std::char_traits<char>, std::vector<int> >(std::ostream &, std::vector<int> const &); 105 // vector<int> is the most used container for demonstrations, so it's worth making it print fast. 106 #endif 107} 108 109#endif 110 111namespace more_ostreaming { namespace detail { 112 struct bytes_t { unsigned char const * p; std::size_t n; }; 113 template <typename C, typename Tr> 114 std::basic_ostream<C, Tr> & operator<<(std::basic_ostream<C, Tr> & o, bytes_t const b) { 115 typedef unsigned int uint; 116 o << '{'; 117 if(b.n != 0) o << uint(*b.p); 118 for(std::size_t i = 1; i != b.n; ++i) o << ", " << uint(b.p[i]); 119 return o << '}'; 120 } 121}} 122 123template <typename T> 124more_ostreaming::detail::bytes_t bytes(T const & x) { 125 more_ostreaming::detail::bytes_t const r = 126 { reinterpret_cast<unsigned char const *>(&x), sizeof(T) }; 127 return r; 128} 129 130inline more_ostreaming::detail::bytes_t bytes(void const * const p, std::size_t const n) { 131 more_ostreaming::detail::bytes_t const r = 132 { reinterpret_cast<unsigned char const *>(p), n }; 133 return r; 134} 135 136namespace more_ostreaming { namespace detail { 137 template <typename, typename T> struct snd { typedef T type; }; 138}} 139 140#if __cplusplus >= 201103 141 142template <typename C, typename Tr, typename R> 143typename more_ostreaming::detail::snd<typename R::iterator, std::basic_ostream<C, Tr> &>::type 144 operator<<(std::basic_ostream<C, Tr> & o, R const & r) 145{ o << '{'; more_ostreaming::delimit(o, r); return o << '}'; } 146 147// Since we defined our generic operator<< for ranges in the global namespace, boost::lexical_cast won't find it when used on range types defined in namespaces other than the global namespace. For now, our quick fix for standard library containers is the following: 148 149namespace std { using ::operator<<; } 150 151template <typename C, typename Tr, typename T, size_t N> 152typename std::enable_if<!geordi::is_character<T>::value, std::basic_ostream<C, Tr> &>::type 153 operator<<(std::basic_ostream<C, Tr> & o, T const (& a) [N]) 154{ o << '{'; more_ostreaming::delimit(o, a); return o << '}'; } 155 156#endif 157 158template <typename C, typename Tr> 159std::basic_ostream<C, Tr> & operator<<(std::basic_ostream<C, Tr> & o, std::tm const * const t) 160{ 161 o.write(std::asctime(t), 24); // Omit the final \n. 162 return o; 163} 164 165template <typename T, typename C> 166C const & underlying(std::stack<T, C> const & s) { 167 struct S: std::stack<T, C> { 168 static C const & peek(std::stack<T, C> const & ss) { return ss.*(&S::c); } 169 }; 170 return S::peek(s); 171} 172 173template <typename T, typename C> 174C const & underlying(std::queue<T, C> const & q) { 175 struct S: std::queue<T, C> { 176 static C const & peek(std::queue<T, C> const & qq) { return qq.*(&S::c); } 177 }; 178 return S::peek(q); 179} 180 181template <typename T, typename C, typename P> 182C const & underlying(std::priority_queue<T, C, P> const & pq) { 183 struct S: std::priority_queue<T, C> { 184 static C const & peek(std::priority_queue<T, C> const & pqpq) { return pqpq.*(&S::c); } 185 }; 186 return S::peek(pq); 187} 188 189namespace std 190{ 191 template <typename Ch, typename Tr, typename T> 192 std::basic_ostream<Ch, Tr> & operator<< (std::basic_ostream<Ch, Tr> & o, std::valarray<T> const & v) 193 { 194 o << '{'; 195 for (std::size_t i = 0; i != v.size(); ++i) { if (i != 0) o << ", "; o << v[i]; } 196 return o << '}'; 197 } 198 199 template <typename Ch, typename Tr, typename T, typename C> 200 std::basic_ostream<Ch, Tr> & 201 operator<<(std::basic_ostream<Ch, Tr> & o, std::stack<T, C> const & s) 202 { return o << underlying(s); } 203 204 template <typename Ch, typename Tr, typename T, typename C> 205 std::basic_ostream<Ch, Tr> & 206 operator<<(std::basic_ostream<Ch, Tr> & o, std::queue<T, C> const & q) 207 { return o << underlying(q); } 208 209 template <typename Ch, typename Tr, typename T, typename C, typename P> 210 std::basic_ostream<Ch, Tr> & 211 operator<<(std::basic_ostream<Ch, Tr> & o, std::priority_queue<T, C, P> const & q) 212 { return o << underlying(q); } 213 214 template <typename Ch, typename Tr> 215 std::basic_ostream<Ch, Tr> & operator<<(std::basic_ostream<Ch, Tr> & o, std::type_info const & t) 216 { return o << t.name(); } 217} 218 219#if !defined(__clang__) && __cplusplus >= 201500 220 221template <typename Ch, typename Tr> 222std::basic_ostream<Ch, Tr> & operator<<( 223 std::basic_ostream<Ch, Tr> & o, std::experimental::filesystem::perms const p) 224{ 225 std::ios::fmtflags f(o.flags()); 226 std::oct(o); 227 o << std::underlying_type_t<std::experimental::filesystem::perms>(p); 228 o.flags(f); 229 return o; 230} 231 232template <typename Ch, typename Tr> 233std::basic_ostream<Ch, Tr> & operator<<( 234 std::basic_ostream<Ch, Tr> & o, std::experimental::filesystem::file_type const t) 235{ 236 switch (t) 237 { 238 #define CASE(c) \ 239 case std::experimental::filesystem::file_type::c: return o << "file_type::" #c; 240 241 CASE(none) 242 CASE(not_found) 243 CASE(regular) 244 CASE(directory) 245 CASE(symlink) 246 CASE(block) 247 CASE(character) 248 CASE(fifo) 249 CASE(socket) 250 CASE(unknown) 251 252 #undef CASE 253 254 default: return o << "?"; 255 } 256} 257 258template <typename Ch, typename Tr> 259std::basic_ostream<Ch, Tr> & operator<<( 260 std::basic_ostream<Ch, Tr> & o, std::experimental::filesystem::file_status const & s) 261{ return o << '{' << s.type() << ", " << s.permissions() << '}'; } 262 263#endif 264 265 266#if __cplusplus >= 201103 267 268#include <chrono> 269 270template <typename Ch, typename Tr, typename K, typename D> 271std::basic_ostream<Ch, Tr> & 272 operator<<(std::basic_ostream<Ch, Tr> & o, std::chrono::time_point<K, D> const & t) 273{ return o << "epoch + " << t.time_since_epoch(); } 274 275template<typename Ch, typename Tr, typename R, typename F> 276std::basic_ostream<Ch, Tr> & operator<<(std::basic_ostream<Ch, Tr> & o, std::chrono::duration<R, F> const & d) 277{ return o << d.count(); } 278 279#define T(r, s) \ 280 template <typename Ch, typename Tr, typename R> std::basic_ostream<Ch, Tr> & \ 281 operator<<(std::basic_ostream<Ch, Tr> & o, std::chrono::duration<R, std::r> const & d) \ 282 { return o << d.count() << s; } 283 284T(ratio<86400>, " d") 285T(ratio<3600>, " h") 286T(ratio<60>, " min") 287T(ratio<1>, " s") 288T(milli, " ms") 289T(micro, " µs") 290T(nano, " ns") 291 292#undef T 293 294#endif 295 296#if __cplusplus >= 201103 297 298#include <system_error> 299 300template<typename Ch, typename Tr> 301inline std::basic_ostream<Ch, Tr> & 302 operator<<(std::basic_ostream<Ch, Tr> & o, std::error_category const & c) 303{ 304 return o << c.name(); 305} 306 307#endif 308 309#if __cplusplus >= 201500 && __has_include(<variant>) 310 311#include <variant> 312 313template<typename Ch, typename Tr, typename T, typename... Ts> 314inline std::basic_ostream<Ch, Tr> & 315 operator<<(std::basic_ostream<Ch, Tr> & o, std::variant<T, Ts...> const & v) 316{ 317 // See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78966 318 319 if (v.valueless_by_exception()) return o << "<valueless>"; 320 321 std::visit([&](auto const & x){ o << x; }, v); 322 return o; 323} 324 325#endif 326 327#if __cplusplus > 201402 && __has_include(<optional>) 328 329#include <optional> 330 331template<typename Ch, typename Tr, typename T> 332inline std::basic_ostream<Ch, Tr> & 333 operator<<(std::basic_ostream<Ch, Tr> & o, std::optional<T> const & x) 334{ 335 if (x) o << *x; 336 else o << "<none>"; 337 return o; 338} 339 340#endif 341 342#if __cplusplus >= 201103 343 344#include <memory> 345 346template<typename Ch, typename Tr, typename T> 347inline std::basic_ostream<Ch, Tr> & 348 operator<<(std::basic_ostream<Ch, Tr> & o, std::unique_ptr<T> const & p) 349{ 350 if (p) o << p.get(); 351 else o << "nullptr"; 352 return o; 353} 354 355template<typename Ch, typename Tr, typename T> 356inline std::basic_ostream<Ch, Tr> & 357 operator<<(std::basic_ostream<Ch, Tr> & o, std::shared_ptr<T> const & p) 358{ 359 if (p) o << p.get(); 360 else o << "nullptr"; 361 return o; 362} 363 364#endif 365 366 367#endif // header guard 368 369#ifdef MORE_OSTREAMING_TEST 370 371#include <vector> 372#include <set> 373#include <map> 374#include <list> 375#include <utility> 376#include <deque> 377#include <array> 378#include <iostream> 379 380int main() 381{ 382 std::map<int, int> m; 383 m[1]= 1; m[2]= 2; 384 std::set<int> s; 385 s.insert(10); 386 s.insert(20); 387 std::vector<int> v(2, 2); 388 int a [] = { 3, 9, 5 }; 389 390 std::wcout << m << '\n' << s << '\n' << v << '\n' << a << '\n'; 391} 392 393#endif // testing