Permalink
Find file
Fetching contributors…
Cannot retrieve contributors at this time
394 lines (307 sloc) 10.9 KB
#ifndef MORE_OSTREAMING_HPP
#define MORE_OSTREAMING_HPP
#include <ostream>
#include <valarray>
#include <utility>
#include <stack>
#include <queue>
#include <cstdlib>
#include <ctime>
#include <algorithm>
#include "geordi.hpp"
#include "literal_escape.hpp"
#if !defined(__clang__) && __cplusplus >= 201500 // TODO
#include <experimental/filesystem>
#endif
template <typename C, typename Tr>
std::basic_ostream<C, Tr> & operator<<(std::basic_ostream<C, Tr> & o, utsname const & u)
{ return o << u.sysname << ' ' << u.release << ' ' << u.version, u.machine; }
#if __cplusplus >= 201103
template <typename C, typename Tr, typename T>
std::basic_ostream<C, Tr> & operator<<(std::basic_ostream<C, Tr> & o, std::reference_wrapper<T> const & rw)
{ T & r(rw); return o << r; }
#endif
template <typename C, typename Tr, typename A, typename B>
std::basic_ostream<C, Tr> & operator<< (std::basic_ostream<C, Tr> & o, std::pair<A, B> const & p)
{ return o << '{' << escape(p.first) << ", " << escape(p.second) << '}'; }
template <typename C, typename Tr, typename D>
void print_div_t(std::basic_ostream<C, Tr> & o, D const d) { o << '{' << d.quot << ", " << d.rem << "}"; }
template <typename C, typename Tr>
std::basic_ostream<C, Tr> & operator<<(std::basic_ostream<C, Tr> & o, std::div_t const d)
{ print_div_t(o, d); return o; }
template <typename C, typename Tr>
std::basic_ostream<C, Tr> & operator<<(std::basic_ostream<C, Tr> & o, std::ldiv_t const d)
{ print_div_t(o, d); return o; }
#if __cplusplus >= 201103
template <typename C, typename Tr>
std::basic_ostream<C, Tr> & operator<<(std::basic_ostream<C, Tr> & o, std::lldiv_t const d)
{ print_div_t(o, d); return o; }
template <typename C, typename T, typename R, typename... A>
std::basic_ostream<C, T> & operator<<(std::basic_ostream<C, T> & o, R (* const p) (A...))
{
void * q;
static_assert(sizeof(p) == sizeof(q), "void- and function-pointer differ in size");
std::copy(reinterpret_cast<char const *>(&p),
reinterpret_cast<char const *>(&p) + sizeof(p), reinterpret_cast<char *>(&q));
return o << q;
}
#include <tuple>
namespace more_ostreaming { namespace detail {
template <int O>
struct tuple_printer
{
template <typename C, typename Tr, typename... P>
static void print (std::basic_ostream<C, Tr> & o, std::tuple<P...> const & t)
{
if (O != 1) { tuple_printer<O-1>::print(o, t); o << ", "; }
o << escape(std::get<O-1>(t));
}
};
template <>
struct tuple_printer<0>
{
template <typename C, typename Tr, typename T>
static void print (std::basic_ostream<C, Tr> &, T const &) {}
};
}}
template <typename C, typename Tr, typename... P>
std::basic_ostream<C, Tr> & operator<< (std::basic_ostream<C, Tr> & o, std::tuple<P...> const & t)
{ o << '{'; more_ostreaming::detail::tuple_printer<sizeof...(P)>::print(o, t); return o << '}'; }
#endif
#if __cplusplus >= 201103
namespace more_ostreaming
{
template <typename C, typename Tr, typename Range>
void delimit(std::basic_ostream<C, Tr> & o, Range const & r)
{
bool first = true;
for (auto && x : r) { if (first) first = false; else o << ", "; o << escape(x); }
}
#if !defined(__clang__)
extern template void delimit<char, std::char_traits<char>, std::vector<int> >(std::ostream &, std::vector<int> const &);
// vector<int> is the most used container for demonstrations, so it's worth making it print fast.
#endif
}
#endif
namespace more_ostreaming { namespace detail {
struct bytes_t { unsigned char const * p; std::size_t n; };
template <typename C, typename Tr>
std::basic_ostream<C, Tr> & operator<<(std::basic_ostream<C, Tr> & o, bytes_t const b) {
typedef unsigned int uint;
o << '{';
if(b.n != 0) o << uint(*b.p);
for(std::size_t i = 1; i != b.n; ++i) o << ", " << uint(b.p[i]);
return o << '}';
}
}}
template <typename T>
more_ostreaming::detail::bytes_t bytes(T const & x) {
more_ostreaming::detail::bytes_t const r =
{ reinterpret_cast<unsigned char const *>(&x), sizeof(T) };
return r;
}
inline more_ostreaming::detail::bytes_t bytes(void const * const p, std::size_t const n) {
more_ostreaming::detail::bytes_t const r =
{ reinterpret_cast<unsigned char const *>(p), n };
return r;
}
namespace more_ostreaming { namespace detail {
template <typename, typename T> struct snd { typedef T type; };
}}
#if __cplusplus >= 201103
template <typename C, typename Tr, typename R>
typename more_ostreaming::detail::snd<typename R::iterator, std::basic_ostream<C, Tr> &>::type
operator<<(std::basic_ostream<C, Tr> & o, R const & r)
{ o << '{'; more_ostreaming::delimit(o, r); return o << '}'; }
// 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:
namespace std { using ::operator<<; }
template <typename C, typename Tr, typename T, size_t N>
typename std::enable_if<!geordi::is_character<T>::value, std::basic_ostream<C, Tr> &>::type
operator<<(std::basic_ostream<C, Tr> & o, T const (& a) [N])
{ o << '{'; more_ostreaming::delimit(o, a); return o << '}'; }
#endif
template <typename C, typename Tr>
std::basic_ostream<C, Tr> & operator<<(std::basic_ostream<C, Tr> & o, std::tm const * const t)
{
o.write(std::asctime(t), 24); // Omit the final \n.
return o;
}
template <typename T, typename C>
C const & underlying(std::stack<T, C> const & s) {
struct S: std::stack<T, C> {
static C const & peek(std::stack<T, C> const & ss) { return ss.*(&S::c); }
};
return S::peek(s);
}
template <typename T, typename C>
C const & underlying(std::queue<T, C> const & q) {
struct S: std::queue<T, C> {
static C const & peek(std::queue<T, C> const & qq) { return qq.*(&S::c); }
};
return S::peek(q);
}
template <typename T, typename C, typename P>
C const & underlying(std::priority_queue<T, C, P> const & pq) {
struct S: std::priority_queue<T, C> {
static C const & peek(std::priority_queue<T, C> const & pqpq) { return pqpq.*(&S::c); }
};
return S::peek(pq);
}
namespace std
{
template <typename Ch, typename Tr, typename T>
std::basic_ostream<Ch, Tr> & operator<< (std::basic_ostream<Ch, Tr> & o, std::valarray<T> const & v)
{
o << '{';
for (std::size_t i = 0; i != v.size(); ++i) { if (i != 0) o << ", "; o << v[i]; }
return o << '}';
}
template <typename Ch, typename Tr, typename T, typename C>
std::basic_ostream<Ch, Tr> &
operator<<(std::basic_ostream<Ch, Tr> & o, std::stack<T, C> const & s)
{ return o << underlying(s); }
template <typename Ch, typename Tr, typename T, typename C>
std::basic_ostream<Ch, Tr> &
operator<<(std::basic_ostream<Ch, Tr> & o, std::queue<T, C> const & q)
{ return o << underlying(q); }
template <typename Ch, typename Tr, typename T, typename C, typename P>
std::basic_ostream<Ch, Tr> &
operator<<(std::basic_ostream<Ch, Tr> & o, std::priority_queue<T, C, P> const & q)
{ return o << underlying(q); }
template <typename Ch, typename Tr>
std::basic_ostream<Ch, Tr> & operator<<(std::basic_ostream<Ch, Tr> & o, std::type_info const & t)
{ return o << t.name(); }
}
#if !defined(__clang__) && __cplusplus >= 201500
template <typename Ch, typename Tr>
std::basic_ostream<Ch, Tr> & operator<<(
std::basic_ostream<Ch, Tr> & o, std::experimental::filesystem::perms const p)
{
std::ios::fmtflags f(o.flags());
std::oct(o);
o << std::underlying_type_t<std::experimental::filesystem::perms>(p);
o.flags(f);
return o;
}
template <typename Ch, typename Tr>
std::basic_ostream<Ch, Tr> & operator<<(
std::basic_ostream<Ch, Tr> & o, std::experimental::filesystem::file_type const t)
{
switch (t)
{
#define CASE(c) \
case std::experimental::filesystem::file_type::c: return o << "file_type::" #c;
CASE(none)
CASE(not_found)
CASE(regular)
CASE(directory)
CASE(symlink)
CASE(block)
CASE(character)
CASE(fifo)
CASE(socket)
CASE(unknown)
#undef CASE
default: return o << "?";
}
}
template <typename Ch, typename Tr>
std::basic_ostream<Ch, Tr> & operator<<(
std::basic_ostream<Ch, Tr> & o, std::experimental::filesystem::file_status const & s)
{ return o << '{' << s.type() << ", " << s.permissions() << '}'; }
#endif
#if __cplusplus >= 201103
#include <chrono>
template <typename Ch, typename Tr, typename K, typename D>
std::basic_ostream<Ch, Tr> &
operator<<(std::basic_ostream<Ch, Tr> & o, std::chrono::time_point<K, D> const & t)
{ return o << "epoch + " << t.time_since_epoch(); }
template<typename Ch, typename Tr, typename R, typename F>
std::basic_ostream<Ch, Tr> & operator<<(std::basic_ostream<Ch, Tr> & o, std::chrono::duration<R, F> const & d)
{ return o << d.count(); }
#define T(r, s) \
template <typename Ch, typename Tr, typename R> std::basic_ostream<Ch, Tr> & \
operator<<(std::basic_ostream<Ch, Tr> & o, std::chrono::duration<R, std::r> const & d) \
{ return o << d.count() << s; }
T(ratio<86400>, " d")
T(ratio<3600>, " h")
T(ratio<60>, " min")
T(ratio<1>, " s")
T(milli, " ms")
T(micro, " µs")
T(nano, " ns")
#undef T
#endif
#if __cplusplus >= 201103
#include <system_error>
template<typename Ch, typename Tr>
inline std::basic_ostream<Ch, Tr> &
operator<<(std::basic_ostream<Ch, Tr> & o, std::error_category const & c)
{
return o << c.name();
}
#endif
#if __cplusplus >= 201500 && __has_include(<variant>)
#include <variant>
template<typename Ch, typename Tr, typename T, typename... Ts>
inline std::basic_ostream<Ch, Tr> &
operator<<(std::basic_ostream<Ch, Tr> & o, std::variant<T, Ts...> const & v)
{
// See https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78966
if (v.valueless_by_exception()) return o << "<valueless>";
std::visit([&](auto const & x){ o << x; }, v);
return o;
}
#endif
#if __cplusplus > 201402 && __has_include(<optional>)
#include <optional>
template<typename Ch, typename Tr, typename T>
inline std::basic_ostream<Ch, Tr> &
operator<<(std::basic_ostream<Ch, Tr> & o, std::optional<T> const & x)
{
if (x) o << *x;
else o << "<none>";
return o;
}
#endif
#if __cplusplus >= 201103
#include <memory>
template<typename Ch, typename Tr, typename T>
inline std::basic_ostream<Ch, Tr> &
operator<<(std::basic_ostream<Ch, Tr> & o, std::unique_ptr<T> const & p)
{
if (p) o << p.get();
else o << "nullptr";
return o;
}
template<typename Ch, typename Tr, typename T>
inline std::basic_ostream<Ch, Tr> &
operator<<(std::basic_ostream<Ch, Tr> & o, std::shared_ptr<T> const & p)
{
if (p) o << p.get();
else o << "nullptr";
return o;
}
#endif
#endif // header guard
#ifdef MORE_OSTREAMING_TEST
#include <vector>
#include <set>
#include <map>
#include <list>
#include <utility>
#include <deque>
#include <array>
#include <iostream>
int main()
{
std::map<int, int> m;
m[1]= 1; m[2]= 2;
std::set<int> s;
s.insert(10);
s.insert(20);
std::vector<int> v(2, 2);
int a [] = { 3, 9, 5 };
std::wcout << m << '\n' << s << '\n' << v << '\n' << a << '\n';
}
#endif // testing