/* This file is part of Usertool.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see . */
#ifndef __PX_STRM_HPP__
#define __PX_STRM_HPP__
#include "px_std.hpp"
#include "px_enum.hpp"
namespace px {
template
<
typename E
>
typename std::enable_if
<
std::is_enum< E >::value
>::type
__enum__set_()
{
return;
}
template
<
typename E
>
typename std::enable_if
<
std::is_enum< E >::value
, std::string &
>::type
__enum__str_()
{
static std::string
str;
static bool
set = false;
if (!
set)
{
set = true;
__enum__set_< E >();
}
return str;
}
template
<
typename E
>
typename std::enable_if
<
std::is_enum< E >::value
, std::map
<
E, const char *
> &
>::type
__enum__map_()
{
static std::map< E, const char * >
map;
static bool
set = false;
if (!
set)
{
set = true;
__enum__set_< E >();
}
return map;
}
template
<
typename E
>
typename std::enable_if
<
std::is_enum< E >::value,
std::ostream &
>::type
operator<<(std::ostream &o, E e)
{
auto
id = __enum__str_< E >(),
mp = __enum__map_< E >();
if (!
id.empty())
o << id << ':';
auto
it = mp.find(e);
if (it != mp. end())
o << it->second;
else
o << (int) e;
return o;
}
/** FORWARD
*/
namespace detail
{
struct
io_fmt
{
enum class fmt_type: uint8_t
{
none = 0x00,
fill = 0x01,
width = 0x02,
precision = 0x04,
flags = 0x08
};
// Never initialized by default.
char
fill_;
std::ios_base::fmtflags
flags_;
std::streamsize
width_,
precision_;
io_fmt();
void
copyfmt(std::ios & ios) const;
void
readfmt(const std::ios & ios);
#define __IO_FMT__DECL_(_name) \
decltype(_name ## _) _name () const; \
decltype(_name ## _) _name (decltype(_name ## _) _ ## _name);
__IO_FMT__DECL_(fill)
__IO_FMT__DECL_(flags)
__IO_FMT__DECL_(width)
__IO_FMT__DECL_(precision)
#undef __PX_STRM_FWD__IO_FMT_
private:
mutable fmt_type
type_;
};
} /* detail */
template
<
typename T
>
struct
__strm__forward_
{
typedef void (*io_fnp)(std::ostream &, const T &);
__strm__forward_(const T & t, io_fnp F)
: t_(t)
, F_(F)
{ // Nothing
}
#define __PX_STRM_FWD__MANIP_(_name) \
__strm__forward_ & \
_name(auto _ ## _name) \
{ \
f_._name(_ ## _name); \
return \
* this; \
}
__PX_STRM_FWD__MANIP_(fill)
__PX_STRM_FWD__MANIP_(width)
__PX_STRM_FWD__MANIP_(flags)
__PX_STRM_FWD__MANIP_(precision)
#undef __PX_STRM_FWD__MANIP_
std::ostream &
operator<<(std::ostream & o) const
{
if (F_)
{
struct
__io_saver
{
__io_saver(std::ostream & o)
: o_(o)
{
f_.readfmt(o_);
}
~__io_saver()
{
f_.copyfmt(o_);
}
private:
std::ostream & o_;
detail::
io_fmt f_;
} io_saver(o);
f_.copyfmt(o);
F_(o, t_);
}
return o;
}
private:
typename std::conditional
<
std::is_base_of< T, std::type_info >::value
, const T &
, const T
>::type
t_;
io_fnp F_;
detail::
io_fmt f_;
};
template
<
typename T
>
std::ostream &
operator<<(std::ostream & o, const __strm__forward_< T > & ff)
{
return ff << o;
}
template
<
unsigned N
>
struct uint_type;
template <> struct uint_type< 1 > { typedef std::uint8_t type; };
template <> struct uint_type< 2 > { typedef std::uint16_t type; };
template <> struct uint_type< 4 > { typedef std::uint32_t type; };
template <> struct uint_type< 8 > { typedef std::uint64_t type; };
template
<
typename T
>
typename uint_type< sizeof(T*) >::type
__get_ptr(T * t)
{
return (typename uint_type< sizeof(T *) >::type) ((void *) t);
}
/** AS_DEC
*/
template
<
typename I
>
typename std::enable_if
<
std::is_integral< I >::value,
__strm__forward_< I >
>::type
as_dec(I i)
{
return { i,
// Output
[](std::ostream & o, const I & i) {
o << std::setw(sizeof(I)) << std::dec << i;
return;
} };
}
std::size_t constexpr
__prntsiz(std::size_t siz)
{
return siz <= 1 ? 2 : siz;
}
/** AS_HEX
*/
template
<
typename I
>
typename std::enable_if
<
std::is_integral< I >::value,
__strm__forward_< I >
>::type
as_hex(I i)
{
return { i,
// Output
[](std::ostream & o, const I & i) {
o
<< std::setfill('0');
typedef typename uint_type< __prntsiz(sizeof(I)) >::type T;
if (i)
o
<< std::setw(sizeof(I) * 2)
<< std::hex
// Must not be signed or unsigned char
<< ((T) i & ((T) -1 >> (sizeof(T)
- sizeof(I)) * 8));
else
for (auto n = 0; n < sizeof(I) * 2; ++n)
o
<< o.fill();
return;
} };
}
/** AS_PCH (PRINTCHAR)
*/
template
<
typename C
>
typename std::enable_if
<
std::is_convertible< C, char >::value,
__strm__forward_< C >
>::type
as_pch(C c)
{
return { c,
// Output
[](std::ostream & o, const C & c) {
o << (char) (isprint(c) ? c : '.');
return;
} };
}
/** AS_TEXT
*/
template
<
typename P
>
typename std::enable_if
<
std::is_convertible< P, char >::value,
__strm__forward_< P * >
>::type
as_text(P * p, std::size_t siz = 40)
{
auto
strm__fwd =
__strm__forward_< P * >(p,
// Output
[](std::ostream & o, P * const &p) {
o << std::setfill('.') << (p ? p : "");
return;
});
return
strm__fwd
.width(siz);
}
/** AS_TIME
*/ // as std::put_time isn't available until GCC 5.
template
<
typename T
>
typename std::enable_if
<
std::is_convertible< T, std::tm >::value,
__strm__forward_< std::pair< T *, const char * > >
>::type
as_time(T * time, const char *format = "%c %z")
{
return { std::make_pair(time, format),
// Output
[](std::ostream & o, const std::pair< T *, const char * > & p) {
char b[80] = { 0 };
auto f = p.second;
auto t = p. first;
if (std::strftime(b, arrsiz(b), f, t))
o << b;
return;
} };
}
template
<
typename T
>
typename std::enable_if
<
std::is_convertible< T, std::time_t >::value,
__strm__forward_< std::pair< T, const char * > >
>::type
as_time(T time, const char *format = "%c %z")
{
return { std::make_pair(time, format),
// Output
[](std::ostream & o, const std::pair< T, const char * > & p) {
std::tm *tm = std::localtime(&p.first);
o << as_time(tm, p.second);
return;
} };
}
/** AS_RATE
*/ // Use std::put_time when it becomes available.
template
<
typename T
>
typename std::enable_if
<
std::is_arithmetic< T >::value,
__strm__forward_< std::pair< T, T> >
>::type
as_ratio(T n, T d)
{
return { std::make_pair(n, d),
// Output
[](std::ostream & o, const std::pair< T, T > & p) {
char b[6];
double r = 0 != p.second
&& p.second >= p.first
? ( (double) p. first
/ (double) p.second ) * 100.0
: 000.0;
if (
r < 000.0)
r = 000.0;
else if (
r > 999.9)
r = 999.9;
snprintf(b, arrsiz(b), "%#03.1f", r);
o << std::setfill('0') << std::setw(5) << b << " %";
return;
} };
}
/** AS_HEX_DUMP
*/
template
<
typename P
>
typename std::enable_if
<
std::is_convertible< P *, const void * >::value,
__strm__forward_< std::pair< P *, std::size_t > >
>::type
as_hex_dump(P * p, std::size_t siz = sizeof(P))
{
return { std::make_pair(p, siz),
// Output
[](std::ostream & o, const std::pair< P *, std::size_t > & p) {
static const unsigned
rsiz = 24,
grps = 4;
auto bptr = p. first,
size = p.second;
o << '@' << as_hex(__get_ptr(bptr))
<< "(size=" << size << ')';
if (!
bptr)
return;
auto read = [&](unsigned offs) -> char {
return
*((char *) ((std::ptrdiff_t) bptr + offs));
};
auto ashex = [&](unsigned offs) -> void {
if (offs % rsiz
&&!(offs % grps))
o << ' ';
if (offs < size)
o << as_hex(read(offs));
else
o << ' ' << ' ';
return;
};
auto aspch = [&](unsigned offs) -> void {
if (offs < size)
o << as_pch(read(offs));
else
o << ' '; // lines up multiple single line hex dumps
};
if (size <=rsiz)
o << ' ';
for (auto offs = 0; offs < size; offs += rsiz)
{
if (offs
|| size > rsiz)
o << '\n';
for (auto ridx = 0; ridx < rsiz; ++ridx)
ashex(ridx + offs);
o << ' ' << ' ';
for (auto ridx = 0; ridx < rsiz; ++ridx)
aspch(ridx + offs);
}
} };
}
/** AS_TYPE
*/
template
<
typename T
>
typename std::enable_if
<
std::is_base_of< std::type_info, T >::value,
__strm__forward_< T >
>::type
__as_type(const T & t)
{
return { t,
// Output
[](std::ostream & o, const T & t_id) {
#ifdef __GLIBCXX__
int retc; char * bufp = 0;
struct __free {
__free(char * p): p_(p) { }
~__free() {
if (p_) ::free(p_); }
char * p_;
} free_(bufp);
bufp = abi::__cxa_demangle(t_id.name(), 0, 0, &retc);
// 0: The demangling operation succeeded.
// -1: A memory allocation failiure occurred.
// -2: mangled_name is not a valid name under the C++ ABI mangling
// rules.
// -3: One of the arguments is invalid.
if (!
retc
&& bufp)
o << bufp;
else
#endif
// __GLIBCXX__
o << t_id
.name();
return;
} };
}
template
<
typename T
>
auto
as_type_()
{
return __as_type(typeid(T));
}
template
<
typename T
>
auto
as_type(T&& t)
{
return __as_type(typeid(t));
}
/** AS_ERR
*/
extern
const char *
__dbi_get_error_str(uint16_t err);
template
<
typename E
>
typename std::enable_if
<
std::is_integral< E >::value,
__strm__forward_< E >
>::type
as_err(E e)
{
return { e,
[](std::ostream & o, const E & e) {
const char *err = __dbi_get_error_str((uint16_t) e);
if (err)
{
o << "(`" << as_hex(e) << "'): ``" << err << "''";
}
else
{
o << as_hex(e);
}
return;
} };
}
} /* px */
#endif
/* !__PX_STRM_HPP__ */