Last active
November 27, 2019 09:29
-
-
Save pnck/b82c529f1d0f674b7aa1d4b3240217b7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <map> | |
template <typename CT=char, typename=std::enable_if_t<std::is_same_v<CT,char>>> | |
class Printer { | |
private: | |
template<typename T> | |
class _has_to_string { | |
template<typename U> | |
static constexpr bool _help(decltype(&U::to_string)) noexcept { return true; } | |
template<typename U> | |
static constexpr bool _help(...) noexcept { return false; } | |
public: | |
static constexpr bool value = _help<T>(0); | |
}; | |
template <typename Tp, std::size_t ... Is> | |
inline Printer& _helper_tuple(const Tp &tp, std::index_sequence<Is...>){ | |
return (((Is==0?(*this):this->putchar(',').putchar(' '))<<std::get<Is>(tp)),...); | |
} | |
inline Printer& _helper_put_escaped(char c){ | |
char eseq[5]; | |
if(c<=0x20 || c>0x7e) { | |
snprintf(eseq,5,"\\x%02hhx",c); | |
return this->putchar(eseq[0]).putchar(eseq[1]).putchar(eseq[2]).putchar(eseq[3]); | |
} else { | |
return this->putchar(c); | |
} | |
} | |
private: | |
std::basic_ostream<CT> &os_; | |
public: | |
Printer():os_(std::cout){} | |
Printer(std::basic_ostream<CT> &os):os_(os){} | |
public: | |
Printer& putchar(CT v){ | |
os_.put(v); | |
return *this; | |
} | |
public: | |
template <typename F,typename S> | |
Printer& operator<<(const std::pair<F,S> &v){ | |
return this->putchar('(').operator<<(v.first).putchar(',').putchar(' ').operator<<(v.second).putchar(')'); | |
} | |
template <typename F,typename S> | |
Printer& operator<<(const std::map<F,S> &v){ | |
this->putchar('{'); | |
for (auto beg=std::begin(v),it=beg,end=std::end(v);it!=end;++it) { | |
if(it!=beg){ | |
this->putchar(',').putchar(' '); | |
} | |
this->operator<<(it->first).putchar(':').putchar(' ').operator<<(it->second); | |
} | |
return this->putchar('}'); | |
} | |
template <typename ... Ts> | |
Printer& operator<<(const std::tuple<Ts...> &v){ | |
return this->putchar('(')._helper_tuple(v,std::index_sequence_for<Ts...>{}).putchar(')'); | |
} | |
template <typename T> | |
Printer& operator<<(const std::vector<T> &v) { | |
this->putchar('['); | |
for(auto beg=std::begin(v),it=beg,end=std::end(v);it!=end;++it){ | |
if(it!=beg) { | |
this->putchar(',').putchar(' '); | |
} | |
this->operator<<(*it); | |
} | |
return this->putchar(']'); | |
} | |
Printer& operator<<(const std::basic_string<CT> &v) { | |
this->putchar('"'); | |
for(auto &c:v){ | |
this->_helper_put_escaped(c); | |
} | |
return this->putchar('"'); | |
} | |
Printer& operator<<(const char* s) { | |
return this->operator<<(std::string{s}); | |
} | |
Printer& operator<<(char v){ | |
return this->putchar('\'')._helper_put_escaped(v).putchar('\''); | |
} | |
Printer& operator<<(decltype(os_)& (*pf)(decltype(os_)&)) { | |
pf(os_); | |
return *this; | |
} | |
template <typename T> | |
Printer& operator<<(const T &v) { | |
if constexpr(_has_to_string<T>::value) { | |
os_ << v.to_string(); | |
return *this; | |
} else { | |
os_ << v; | |
return *this; | |
} | |
} | |
template <typename T> | |
Printer& operator()(const T &v){ | |
return this->operator<<(v); | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment