formatting-utils(#985): provide some basics
No more fiddling with printf just to show a number reliably! simple functions to pretty-print addresses, doubles and floats (fixed-point, with rounding). Also make all these basic formatting helpers noexcept
This commit is contained in:
parent
1814b1fc69
commit
60a7e7acb2
3 changed files with 125 additions and 15 deletions
|
|
@ -42,6 +42,7 @@
|
|||
|
||||
#include "lib/error.hpp"
|
||||
#include "lib/format-obj.hpp"
|
||||
//#include "lib/format-string.hpp"
|
||||
#include "lib/unique-malloc-owner.hpp"
|
||||
#include "lib/symbol.hpp"
|
||||
|
||||
|
|
@ -49,11 +50,26 @@
|
|||
#include <cxxabi.h>
|
||||
#endif
|
||||
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
|
||||
//using util::_Fmt;
|
||||
using std::string;
|
||||
|
||||
|
||||
namespace { // hard-wired configuration for debugging output....
|
||||
|
||||
// precision for rendering of double values
|
||||
const auto DIAGNOSTICS_DOUBLE_PRECISION = 8;
|
||||
const auto DIAGNOSTICS_FLOAT_PRECISION = 5;
|
||||
|
||||
/** amount of hex digits required to represent an address on this plattform */
|
||||
const auto PLATFORM_ADDRESS_HEX_DIGITS = sizeof(size_t) * 2;
|
||||
}
|
||||
|
||||
|
||||
|
||||
namespace lib {
|
||||
namespace meta {
|
||||
|
||||
|
|
@ -132,7 +148,12 @@ apologies for that."
|
|||
return typeName;
|
||||
}
|
||||
|
||||
}}
|
||||
}}// namespace lib::meta
|
||||
|
||||
|
||||
|
||||
|
||||
/* === formatting and pretty printing support uitls === */
|
||||
|
||||
namespace util {
|
||||
|
||||
|
|
@ -141,11 +162,59 @@ namespace util {
|
|||
|
||||
}//(End) implementation details
|
||||
|
||||
|
||||
using std::ostringstream;
|
||||
using std::hex;
|
||||
using std::setw;
|
||||
using std::right;
|
||||
using std::setfill;
|
||||
using std::noshowbase;
|
||||
|
||||
|
||||
/**
|
||||
* @return fixed point string representation, never empty
|
||||
* @note we set an explicit precision, since this is a diagnostic facility
|
||||
* @remarks typically do not want to see all digits, but, for test code,
|
||||
* we do want a predictable string representation of simple fractional
|
||||
* values like `0.1` (which can not be represented as binary floats)
|
||||
*/
|
||||
string
|
||||
showDouble (double val) noexcept
|
||||
try {
|
||||
ostringstream buffer;
|
||||
buffer.precision (DIAGNOSTICS_DOUBLE_PRECISION);
|
||||
buffer << val;
|
||||
return buffer.str();
|
||||
}
|
||||
catch(...)
|
||||
{ return "↯"; }
|
||||
|
||||
|
||||
string
|
||||
showFloat (float val) noexcept
|
||||
try {
|
||||
std::ostringstream buffer;
|
||||
buffer.precision (DIAGNOSTICS_FLOAT_PRECISION);
|
||||
buffer << val;
|
||||
return buffer.str();
|
||||
}
|
||||
catch(...)
|
||||
{ return "↯"; }
|
||||
|
||||
|
||||
string
|
||||
showAddr (void *addr) noexcept
|
||||
try {
|
||||
std::ostringstream buffer;
|
||||
buffer << hex
|
||||
<< noshowbase
|
||||
<< setw (PLATFORM_ADDRESS_HEX_DIGITS)
|
||||
<< setfill('_')
|
||||
<< right
|
||||
<< addr;
|
||||
return buffer.str();
|
||||
}
|
||||
catch(...)
|
||||
{ return "↯"; }
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -68,11 +68,15 @@ namespace meta {
|
|||
|
||||
std::string humanReadableTypeID (lib::Literal);
|
||||
|
||||
}} // namespace lib::meta
|
||||
}}// namespace lib::meta
|
||||
|
||||
|
||||
namespace util {
|
||||
|
||||
std::string showDouble (double) noexcept;
|
||||
std::string showFloat (float) noexcept;
|
||||
std::string showAddr (void *addr) noexcept;
|
||||
|
||||
|
||||
|
||||
} // namespace util
|
||||
|
|
|
|||
|
|
@ -204,16 +204,18 @@ namespace meta {
|
|||
*/
|
||||
template<typename TY>
|
||||
inline std::string
|
||||
typeStr (const TY* obj=nullptr)
|
||||
{
|
||||
auto mangledType = obj? typeid(obj).name()
|
||||
: typeid(TY).name();
|
||||
return humanReadableTypeID (mangledType);
|
||||
}
|
||||
typeStr (const TY* obj =nullptr) noexcept
|
||||
try {
|
||||
auto mangledType = obj? typeid(obj).name()
|
||||
: typeid(TY).name();
|
||||
return humanReadableTypeID (mangledType);
|
||||
}
|
||||
catch(...)
|
||||
{ return "↯"; }
|
||||
|
||||
template<typename TY>
|
||||
inline std::string
|
||||
typeStr (TY const& ref)
|
||||
typeStr (TY const& ref) noexcept
|
||||
{
|
||||
return typeStr (&ref);
|
||||
}
|
||||
|
|
@ -234,20 +236,55 @@ namespace meta {
|
|||
template<typename X, typename COND =void>
|
||||
struct CustomStringConv
|
||||
{
|
||||
static std::string invoke (X const& x) { return "«"+typeStr(x)+"»"; }
|
||||
static std::string
|
||||
invoke (X const& x) noexcept
|
||||
try { return "«"+typeStr(x)+"»"; }
|
||||
catch(...) { return "↯"; }
|
||||
};
|
||||
|
||||
template<typename X>
|
||||
struct CustomStringConv<X, enable_if<can_convertToString<X>> >
|
||||
{
|
||||
static std::string
|
||||
invoke (X const& val)
|
||||
invoke (X const& val) noexcept
|
||||
try { return std::string(val); }
|
||||
catch(...) { return "↯"; }
|
||||
};
|
||||
|
||||
// NOTE: this is meant to be extensible;
|
||||
// more specialisations are e.g. in format-obj.hpp
|
||||
|
||||
}}// namespace lib::meta
|
||||
|
||||
|
||||
|
||||
namespace util {
|
||||
|
||||
/** pretty-print a double in fixed-point format */
|
||||
std::string showDouble (double) noexcept;
|
||||
std::string showFloat (float) noexcept;
|
||||
|
||||
/** pretty-print an address as hex-string */
|
||||
std::string showAddr (void *addr) noexcept;
|
||||
|
||||
template<typename X>
|
||||
inline std::string
|
||||
showAddr (const X& elm) noexcept
|
||||
{
|
||||
return showAddr(&elm);
|
||||
}
|
||||
|
||||
|
||||
/** diagnostics helper for explicitly indicating pointers */
|
||||
template<typename X>
|
||||
inline std::string
|
||||
showPtr (X* ptr =nullptr)
|
||||
{
|
||||
return ptr? showAddr(ptr) + " ↗" + lib::meta::CustomStringConv<X>::invoke(*ptr)
|
||||
: "⟂ «" + typeStr(ptr) + "»";
|
||||
}
|
||||
|
||||
|
||||
|
||||
}} // namespace lib::meta
|
||||
#endif
|
||||
}// namespace util
|
||||
#endif /*LIB_META_UTIL_H*/
|
||||
|
|
|
|||
Loading…
Reference in a new issue