Skip to content

Instantly share code, notes, and snippets.

@pnck
Last active November 27, 2019 09:29
Show Gist options
  • Save pnck/b82c529f1d0f674b7aa1d4b3240217b7 to your computer and use it in GitHub Desktop.
Save pnck/b82c529f1d0f674b7aa1d4b3240217b7 to your computer and use it in GitHub Desktop.
#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