PageRenderTime 39ms CodeModel.GetById 1ms app.highlight 33ms RepoModel.GetById 1ms app.codeStats 0ms

/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
  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