2016-01-05 23:34:53 +01:00
|
|
|
|
/*
|
|
|
|
|
|
FORMAT-OBJ.hpp - simple means to display an object
|
|
|
|
|
|
|
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
|
|
|
|
Copyright (C)
|
|
|
|
|
|
2016, Hermann Vosseler <Ichthyostega@web.de>
|
2016-01-05 23:34:53 +01:00
|
|
|
|
|
Copyright: clarify and simplify the file headers
* Lumiera source code always was copyrighted by individual contributors
* there is no entity "Lumiera.org" which holds any copyrights
* Lumiera source code is provided under the GPL Version 2+
== Explanations ==
Lumiera as a whole is distributed under Copyleft, GNU General Public License Version 2 or above.
For this to become legally effective, the ''File COPYING in the root directory is sufficient.''
The licensing header in each file is not strictly necessary, yet considered good practice;
attaching a licence notice increases the likeliness that this information is retained
in case someone extracts individual code files. However, it is not by the presence of some
text, that legally binding licensing terms become effective; rather the fact matters that a
given piece of code was provably copyrighted and published under a license. Even reformatting
the code, renaming some variables or deleting parts of the code will not alter this legal
situation, but rather creates a derivative work, which is likewise covered by the GPL!
The most relevant information in the file header is the notice regarding the
time of the first individual copyright claim. By virtue of this initial copyright,
the first author is entitled to choose the terms of licensing. All further
modifications are permitted and covered by the License. The specific wording
or format of the copyright header is not legally relevant, as long as the
intention to publish under the GPL remains clear. The extended wording was
based on a recommendation by the FSF. It can be shortened, because the full terms
of the license are provided alongside the distribution, in the file COPYING.
2024-11-17 23:42:55 +01:00
|
|
|
|
**Lumiera** is free software; you can redistribute it and/or modify it
|
|
|
|
|
|
under the terms of the GNU General Public License as published by the
|
|
|
|
|
|
Free Software Foundation; either version 2 of the License, or (at your
|
|
|
|
|
|
option) any later version. See the file COPYING for further details.
|
2016-01-05 23:34:53 +01:00
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** @file format-obj.hpp
|
|
|
|
|
|
** Simple functions to represent objects, for debugging and diagnostics.
|
|
|
|
|
|
** The helpers provided here are rather commonplace, but written in a way
|
2025-02-17 18:36:23 +01:00
|
|
|
|
** to incur only modest header inclusion load. It should be OK to use them
|
|
|
|
|
|
** even on interface headers in widespread use.
|
2016-01-05 23:34:53 +01:00
|
|
|
|
** - util::toString() performs a failsafe to-String conversion, thereby preferring a
|
|
|
|
|
|
** built-in conversion operator, falling back to a lexical conversion (boost)
|
2025-02-17 18:36:23 +01:00
|
|
|
|
** or just an unmangled and simplified type string as default.
|
|
|
|
|
|
** - util::typedString() combines this with an always visible type display
|
2016-01-05 23:34:53 +01:00
|
|
|
|
** - lib::meta::demangleCxx() uses the built-in compiler support to translate a mangled
|
|
|
|
|
|
** type-ID (as given by `typeid(TY).name()`) into a readable, fully qualified
|
|
|
|
|
|
** C++ type name. This is only supported for GNU compatible compilers.
|
|
|
|
|
|
**
|
2016-01-09 04:05:14 +01:00
|
|
|
|
** @todo is it possible to stash away the `boost::lexical_cast` behind a custom facade,
|
|
|
|
|
|
** the way we did it for `boost::format`? This would reduce inclusion cost...
|
|
|
|
|
|
**
|
2016-01-05 23:34:53 +01:00
|
|
|
|
** @see FormatHelper_test
|
2018-09-21 13:46:42 +02:00
|
|
|
|
** @see [frontend for boost::format, printf-style](\ref format-string.hpp)
|
2016-01-05 23:34:53 +01:00
|
|
|
|
**
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef LIB_FORMAT_OBJ_H
|
|
|
|
|
|
#define LIB_FORMAT_OBJ_H
|
|
|
|
|
|
|
2016-01-15 21:29:39 +01:00
|
|
|
|
#include "lib/symbol.hpp"
|
2016-01-05 23:34:53 +01:00
|
|
|
|
#include "lib/meta/trait.hpp"
|
|
|
|
|
|
|
|
|
|
|
|
#include <boost/lexical_cast.hpp>
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-01-06 04:51:37 +01:00
|
|
|
|
namespace std { // forward declaration to avoid including <iostream>
|
|
|
|
|
|
|
|
|
|
|
|
template<typename C>
|
|
|
|
|
|
struct char_traits;
|
|
|
|
|
|
|
|
|
|
|
|
template<typename C, class _TRAITS>
|
|
|
|
|
|
class basic_ostream;
|
|
|
|
|
|
|
|
|
|
|
|
using ostream = basic_ostream<char, char_traits<char>>;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-01-05 23:34:53 +01:00
|
|
|
|
namespace lib {
|
|
|
|
|
|
class Literal;
|
|
|
|
|
|
|
|
|
|
|
|
namespace meta {
|
|
|
|
|
|
|
|
|
|
|
|
std::string demangleCxx (lib::Literal rawName);
|
|
|
|
|
|
std::string humanReadableTypeID (lib::Literal);
|
2016-01-08 08:20:59 +01:00
|
|
|
|
std::string primaryTypeComponent (lib::Literal);
|
|
|
|
|
|
std::string sanitisedFullTypeName(lib::Literal);
|
2016-01-05 23:34:53 +01:00
|
|
|
|
|
2016-01-06 04:04:56 +01:00
|
|
|
|
}}// namespace lib::meta
|
2016-01-05 23:34:53 +01:00
|
|
|
|
|
|
|
|
|
|
|
2016-01-08 01:00:05 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-01-05 23:34:53 +01:00
|
|
|
|
namespace util {
|
|
|
|
|
|
|
2024-11-14 22:10:43 +01:00
|
|
|
|
std::string showDouble (double) noexcept;
|
|
|
|
|
|
std::string showFloat (float) noexcept;
|
|
|
|
|
|
std::string showSize (size_t) noexcept;
|
|
|
|
|
|
std::string showAdr (void const* addr) noexcept;
|
2016-01-06 04:04:56 +01:00
|
|
|
|
|
2016-01-06 04:51:37 +01:00
|
|
|
|
/** preconfigured format for pretty-printing of addresses */
|
2024-11-14 22:10:43 +01:00
|
|
|
|
std::ostream& showAdr (std::ostream&, void const* addr);
|
2016-01-06 04:51:37 +01:00
|
|
|
|
|
2023-11-16 18:42:36 +01:00
|
|
|
|
/** renders the size_t in hex, optionally only trailing bytes */
|
2024-11-14 22:10:43 +01:00
|
|
|
|
std::string showHash (size_t hash, uint showBytes=8) noexcept;
|
2023-11-16 18:42:36 +01:00
|
|
|
|
|
|
|
|
|
|
inline std::string
|
|
|
|
|
|
showHashLSB (size_t hash) noexcept
|
|
|
|
|
|
{
|
|
|
|
|
|
return showHash(hash,1);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-03-14 17:32:22 +01:00
|
|
|
|
std::string showDecimal (double) noexcept;
|
|
|
|
|
|
std::string showDecimal (float) noexcept;
|
|
|
|
|
|
std::string showDecimal (f128) noexcept;
|
|
|
|
|
|
std::string showComplete (double)noexcept;
|
|
|
|
|
|
std::string showComplete (float) noexcept;
|
|
|
|
|
|
std::string showComplete (f128) noexcept;
|
|
|
|
|
|
|
2023-11-16 18:42:36 +01:00
|
|
|
|
|
2016-01-05 23:34:53 +01:00
|
|
|
|
|
2016-01-08 01:00:05 +01:00
|
|
|
|
namespace {
|
|
|
|
|
|
/** toggle to prefer specialisation with direct lexical conversion */
|
|
|
|
|
|
template<typename X>
|
|
|
|
|
|
using enable_LexicalConversion = lib::meta::enable_if< lib::meta::use_LexicalConversion<X>>;
|
2016-07-30 23:19:21 +02:00
|
|
|
|
|
|
|
|
|
|
template<typename SP>
|
|
|
|
|
|
using show_SmartPointer = lib::meta::enable_if< lib::meta::is_smart_ptr<typename lib::meta::Strip<SP>::TypeReferred>>;
|
2016-01-08 01:00:05 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* === generalise the failsafe string conversion === */
|
|
|
|
|
|
|
|
|
|
|
|
/** @note base case is defined in meta/util.hpp */
|
|
|
|
|
|
template<typename X>
|
|
|
|
|
|
struct StringConv<X, enable_LexicalConversion<X>>
|
|
|
|
|
|
{
|
|
|
|
|
|
static std::string
|
|
|
|
|
|
invoke (X const& val) noexcept
|
|
|
|
|
|
try { return boost::lexical_cast<std::string> (val); }
|
2016-01-08 08:20:59 +01:00
|
|
|
|
catch(...) { return FAILURE_INDICATOR; }
|
2016-07-30 23:19:21 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
template<typename SP>
|
|
|
|
|
|
struct StringConv<SP, show_SmartPointer<SP>>
|
|
|
|
|
|
{
|
|
|
|
|
|
static std::string
|
|
|
|
|
|
invoke (SP const& smP) noexcept
|
|
|
|
|
|
try { return showSmartPtr (smP, lib::meta::typeSymbol(smP)); }
|
|
|
|
|
|
catch(...) { return FAILURE_INDICATOR; }
|
2016-01-08 01:00:05 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/** explicit specialisation to control precision of double values.
|
|
|
|
|
|
* @note we set an explicit precision, since this is a diagnostic facility
|
|
|
|
|
|
* and we 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)
|
|
|
|
|
|
*/
|
|
|
|
|
|
template<>
|
|
|
|
|
|
struct StringConv<double>
|
|
|
|
|
|
{
|
|
|
|
|
|
static std::string
|
|
|
|
|
|
invoke (double val) noexcept
|
|
|
|
|
|
{
|
|
|
|
|
|
return util::showDouble (val);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
template<>
|
|
|
|
|
|
struct StringConv<float>
|
|
|
|
|
|
{
|
|
|
|
|
|
static std::string
|
|
|
|
|
|
invoke (float val) noexcept
|
|
|
|
|
|
{
|
|
|
|
|
|
return util::showFloat (val);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
2016-01-10 03:59:01 +01:00
|
|
|
|
template<>
|
|
|
|
|
|
struct StringConv<bool>
|
|
|
|
|
|
{
|
|
|
|
|
|
static std::string
|
|
|
|
|
|
invoke (bool val) noexcept
|
|
|
|
|
|
{
|
|
|
|
|
|
return util::showBool (val);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
2016-01-08 01:00:05 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* get some string representation of any object, reliably.
|
|
|
|
|
|
* A custom string conversion operator is invoked, if applicable,
|
|
|
|
|
|
* while all lexically convertible types (numbers etc) are treated
|
|
|
|
|
|
* by boost::lexical_cast. For double or float values, hard wired
|
|
|
|
|
|
* rounding to a fixed number of digits will be performed, to yield
|
|
|
|
|
|
* a predictable display of printed unit-test results.
|
2023-05-21 23:45:45 +02:00
|
|
|
|
* @remark while the actual parameter is passed by const-ref,
|
|
|
|
|
|
* cv-qualifiactions and references are stripped from the type
|
2023-08-19 02:27:06 +02:00
|
|
|
|
* @note Deliberately there is no magic detection/support for pointers.
|
|
|
|
|
|
* This function _must not be overloaded_ (to avoid ambiguities
|
2023-10-23 01:48:46 +02:00
|
|
|
|
* in more elaborate template instantiations).
|
|
|
|
|
|
* @remark Since 10/2023 an attempt was made to solve this problem down
|
|
|
|
|
|
* in `StringConf<TY>`, yet this solution might be brittle. If you
|
|
|
|
|
|
* want pointers to be indicated (with address), consider using
|
|
|
|
|
|
* util::showPtr explicitly.
|
2016-01-08 01:00:05 +01:00
|
|
|
|
*/
|
|
|
|
|
|
template<typename TY>
|
|
|
|
|
|
inline std::string
|
|
|
|
|
|
toString (TY const& val) noexcept
|
|
|
|
|
|
{
|
2023-05-21 23:45:45 +02:00
|
|
|
|
using PlainVal = typename lib::meta::Strip<TY>::TypeReferred;
|
|
|
|
|
|
return StringConv<PlainVal>::invoke (val);
|
2016-01-08 01:00:05 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-01-08 08:20:59 +01:00
|
|
|
|
/**
|
|
|
|
|
|
* indicate type and possibly a (custom) conversion to string
|
|
|
|
|
|
* @return human readable type name '|' string representation.
|
|
|
|
|
|
* or just the type, when no string representation available
|
|
|
|
|
|
*/
|
|
|
|
|
|
template<typename TY>
|
|
|
|
|
|
inline std::string
|
|
|
|
|
|
typedString (TY const& val) noexcept
|
|
|
|
|
|
try {
|
|
|
|
|
|
std::string repr = StringConv<TY>::invoke (val);
|
|
|
|
|
|
return 0 == repr.rfind("«", 0)? repr
|
|
|
|
|
|
: "«"+typeStr(val)+"»|"+repr;
|
|
|
|
|
|
}
|
|
|
|
|
|
catch(...)
|
|
|
|
|
|
{ return FAILURE_INDICATOR; }
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-01-05 23:34:53 +01:00
|
|
|
|
|
|
|
|
|
|
} // namespace util
|
|
|
|
|
|
#endif /*LIB_FORMAT_OBJ_H*/
|