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