/prelude/more_ostreaming.hpp

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