reorganisation(#985): move basic typeString implementation into lib::meta

- simple function to pick up the mangled type
- pretty-printing is implemented in format-obj.cpp
- also move the demangleCxx()-Function to that location,
  it starts to be used for real, outside the test framework
This commit is contained in:
Fischlurch 2016-01-05 23:34:53 +01:00
parent f077c14d47
commit 0c4495a451
13 changed files with 301 additions and 113 deletions

View file

@ -81,6 +81,7 @@ typedef unsigned int uint;
using lib::diff::GenNode;
using lib::P;
using lib::meta::enable_if;
using lib::meta::typeStr;
using lib::meta::can_convertToString;
using std::string;
@ -93,28 +94,11 @@ using std::endl;
///////////////////////////////copied from format-util.hpp
template<typename TY>
inline string
typeStr (const TY* obj=0)
{
auto mangledType = obj? typeid(obj).name()
: typeid(TY).name();
return string("«")+ mangledType +"»";
}
template<typename TY>
inline string
typeStr (TY const& ref)
{ return typeStr(&ref); }
///////////////////////////////copied from format-util.hpp
///////////////////////////////planned minimal conversion, maybe in meta/util.hpp ?
template<typename X, typename COND =void>
struct CustomStringConv
{
static string invoke (X const& x) { return typeStr(x); }
static string invoke (X const& x) { return "«"+typeStr(x)+"»"; }
};
template<typename X>
@ -134,7 +118,7 @@ inline string
stringz (P<X> ptr)
{
if (not ptr)
return "⟂ P"+typeStr(ptr.get());
return "⟂ P<"+typeStr(ptr.get())+">";
else
return CustomStringConv<X>::invoke (*ptr);
}
@ -202,7 +186,7 @@ namespace meta {
if (ptr)
return os << (void*)ptr << "" << *ptr;
else
return os << "" << typeStr<X>();
return os << "«" << typeStr<X>() << "»";
}
template<typename X>

152
src/lib/format-obj.cpp Normal file
View file

@ -0,0 +1,152 @@
/*
FormatObj - simple means to display an object
Copyright (C) Lumiera.org
2016, Hermann Vosseler <Ichthyostega@web.de>
This program 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.
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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* *****************************************************/
/** @file format-obj.cpp
** Some implementation helpers for simple object display.
** This file provides some basic implementation functions, which
** can be called from a generic front-end (header). The reason we
** stash away some functions into an implementation unit is to keep
** the include overhead low, which helps to reduce both code size
** and compilation time. The functions here perform some formatting
** tasks commonly used from debugging and diagnostics code, both to
** investigate object contents and show types and addresses. They
** are referred from our [lightweight string converter](\ref
** lib::meta::CustomStringConv), but also from the util::toString()
** function and more common [formatting utils](format-util.hpp).
**
** @see FormatHelper_test
** @see FormatString_test
**
*/
#include "lib/error.hpp"
#include "lib/format-obj.hpp"
#include "lib/unique-malloc-owner.hpp"
#include "lib/symbol.hpp"
#ifdef __GNUG__
#include <cxxabi.h>
#endif
#include <string>
using std::string;
namespace lib {
namespace meta {
#ifdef __GNUG__
/**
* \par Implementation notes
* GCC / G++ subscribes to a cross-vendor ABI for C++, sometimes called the IA64 ABI
* because it happens to be the native ABI for that platform. It is summarised at
* \link http://www.codesourcery.com/cxx-abi/ mentor-embedded \endlink
* along with the current specification. For users of GCC greater than or equal to 3.x,
* entry points are exposed through the standard library in `<cxxabi.h>`
*
* This implementation relies on a vendor neutral ABI for C++ compiled programs
*
* char* abi::__cxa_demangle(const char* mangled_name,
* char* output_buffer, size_t* length,
* int* status)
*
* Parameters:
* - \c mangled_name
* NUL-terminated character string containing the name to be demangled.
* - \c output_buffer
* region of memory, allocated with \c malloc, of `*length` bytes,
* into which the demangled name is stored. If \c output_buffer is not long enough,
* it is expanded using \c realloc. output_buffer may instead be NULL; in that case,
* the demangled name is placed in a region of memory allocated with \c malloc.
* - \c length
* If length is non-NULL, the length of the buffer containing the demangled name is placed in `*length`.
* - \c status
* error flag: `*status` is set to one of the following values:
*
* 0: The demangling operation succeeded.
* -1: A memory allocation failure occurred.
* -2: mangled_name is not a valid name under the C++ ABI mangling rules.
* -3: One of the arguments is invalid.
*
* The function returns a pointer to the start of the NUL-terminated demangled name,
* or NULL if the demangling fails. The caller is responsible for deallocating
* this memory using \c free.
*/
string
demangleCxx (Literal rawName)
{
int error = -4;
UniqueMallocOwner<char> demangled (abi::__cxa_demangle (rawName,
NULL,
NULL,
&error));
return 0==error? demangled.get()
: string(rawName);
}
#else
#warning "Lumiera was _not_ built with a GCC compatible compiler."
#warning "There are good chances this works without problems, but up to now, \
the Lumiera developers lacked the resources to investigate that option; \
apologies for that."
/** Fallback type-ID:
* @return unaltered internal type-ID
*/
string
demangleCxx (Literal rawName)
{
return string (rawName);
}
#endif
string
humanReadableTypeID (Literal rawType)
{
string typeName = demangleCxx (rawType);
return typeName;
}
}}
namespace util {
namespace { // implementation details...
}//(End) implementation details
/**
*/
} // namespace util

79
src/lib/format-obj.hpp Normal file
View file

@ -0,0 +1,79 @@
/*
FORMAT-OBJ.hpp - simple means to display an object
Copyright (C) Lumiera.org
2016, Hermann Vosseler <Ichthyostega@web.de>
This program 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.
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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/** @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
** as to incur a rather modest header inclusion load. It should be OK to
** use these even on widely used interface headers.
** - util::toString() performs a failsafe to-String conversion, thereby preferring a
** built-in conversion operator, falling back to a lexical conversion (boost)
** or just a unmangled and simplified type string as default.
** - 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.
**
** @see FormatHelper_test
** @see [frontend for boost::format, printf-style](format-string.hpp)
**
*/
#ifndef LIB_FORMAT_OBJ_H
#define LIB_FORMAT_OBJ_H
#include "lib/meta/trait.hpp"
//#include "lib/util.hpp"
#include <string>
#include <boost/lexical_cast.hpp>
namespace lib {
class Literal;
namespace meta {
/** reverse the effect of C++ name mangling.
* @return string in language-level form of a C++ type or object name,
* or a string with the original input if demangling fails.
* @warning implementation relies on the cross vendor C++ ABI in use
* by GCC and compatible compilers, so portability is limited.
* The implementation is accessed through libStdC++
* Name representation in emitted object code and type IDs is
* essentially an implementation detail and subject to change.
*/
std::string demangleCxx (lib::Literal rawName);
std::string humanReadableTypeID (lib::Literal);
}} // namespace lib::meta
namespace util {
} // namespace util
#endif /*LIB_FORMAT_OBJ_H*/

View file

@ -91,13 +91,13 @@
** \endcode
**
** @remarks See the unit-test for extensive usage examples and corner cases.
** The header format-conv.hpp provides an alternative string conversion,
** using a bit of boost type traits and lexical_cast, but no boost::format.
** The header format-obj.hpp provides an alternative string conversion,
** using a bit of type traits and boost lexical_cast, but no boost::format.
** @warning not suited for performance critical code. About 10 times slower than printf.
**
** @see FormatString_test
** @see format-util.hpp
** @see format-conv.hpp
** @see format-obj.hpp
**
*/

View file

@ -39,6 +39,7 @@
#include "lib/hash-standard.hpp"
#include "lib/meta/trait.hpp"
#include "lib/format-obj.hpp"
#include "lib/itertools.hpp"
#include "lib/symbol.hpp"
#include "lib/util.hpp"
@ -52,11 +53,6 @@
#include <boost/utility/enable_if.hpp>
namespace lib {
namespace test{ // see test-helper.cpp
std::string demangleCxx (lib::Literal rawName);
}}
namespace util {
@ -159,7 +155,7 @@ namespace util {
{
auto mangledType = obj? typeid(obj).name()
: typeid(TY).name();
string typeName = lib::test::demangleCxx (mangledType);
string typeName = lib::meta::demangleCxx (mangledType);
removePrefix (typeName, "const ");
removeSuffix (typeName, " const*");
return "«"+ typeName +"»";

View file

@ -23,6 +23,7 @@
#include "lib/idi/genfunc.hpp"
#include "lib/format-string.hpp"
#include "lib/format-obj.hpp"
#include "lib/util.hpp"
#include <string>
@ -34,15 +35,12 @@ using std::string;
namespace lib {
namespace test{ // see test-helper.cpp
std::string demangleCxx (lib::Literal rawName);
}
namespace idi {
namespace format { // generic entry points / integration helpers...
using lib::test::demangleCxx;
using lib::meta::demangleCxx;
string
demangled_innermost_component (const char* rawName)
@ -59,7 +57,7 @@ namespace idi {
string
demangled_sanitised_name (const char* rawName)
{
return util::sanitise (test::demangleCxx (rawName));
return util::sanitise (demangleCxx (rawName));
}
@ -82,4 +80,4 @@ namespace idi {
}} // namespace lib::test
}} // namespace lib::idi

View file

@ -57,6 +57,9 @@ namespace std { // forward declaration for std::string...
namespace lib {
class Literal;
class Symbol;
namespace meta {
/* === conditional definition selector === */
@ -154,7 +157,6 @@ namespace meta {
/** Trait template for detecting a typelist type.
* For example, this allows to write specialisations with the help of
* boost::enable_if
@ -173,5 +175,50 @@ namespace meta {
/* ==== generic string representation ==== */
/** pretty-print an internal C++ type representation
* @see \ref format-obj.cpp implementation
*/
std::string humanReadableTypeID (lib::Literal);
std::string demangleCxx (lib::Literal rawName);
/** failsafe human readable type display
* @return string representing the C++ type.
* @remarks the purpose of this function is diagnostics
* and unit-testing. When possible, RTTI is exposed, otherwise
* the implementation falls back on the static type as seen by
* the compiler on usage site. An attempt is made to de-mangle
* and further simplify the type string, leaving out some common
* (hard wired) namespace prefixes, and stripping typical adornments
* like `const`, `*` and `&`
* @warning this function does string transformations behind the scenes,
* and thus should not be used in performance critical context. Moreover,
* the returned type string is not necessarily exact and re-parsable.
*/
template<typename TY>
inline std::string
typeStr (const TY* obj=nullptr)
{
auto mangledType = obj? typeid(obj).name()
: typeid(TY).name();
return humanReadableTypeID (mangledType);
}
template<typename TY>
inline std::string
typeStr (TY const& ref)
{
return typeStr (&ref);
}
}} // namespace lib::meta
#endif

View file

@ -54,7 +54,7 @@ namespace test {
using util::isnil;
using util::contains;
using lib::test::showType;
using lib::test::demangleCxx;
using lib::meta::demangleCxx;
typedef map<string, Launcher*> TestMap;
typedef shared_ptr<TestMap> PTestMap;

View file

@ -35,10 +35,6 @@
#include "lib/format-string.hpp"
#include "lib/unique-malloc-owner.hpp"
#ifdef __GNUG__
#include <cxxabi.h>
#endif
#include <string>
using std::string;
@ -55,62 +51,6 @@ namespace test{
}
#ifdef __GNUG__
/**
* \par Implementation notes
* GCC / G++ subscribes to a cross-vendor ABI for C++, sometimes called the IA64 ABI
* because it happens to be the native ABI for that platform. It is summarised at
* \link http://www.codesourcery.com/cxx-abi/ mentor-embedded \endlink
* along with the current specification. For users of GCC greater than or equal to 3.x,
* entry points are exposed through the standard library in `<cxxabi.h>`
*
* This implementation relies on a vendor neutral ABI for C++ compiled programs
*
* char* abi::__cxa_demangle(const char* mangled_name,
* char* output_buffer, size_t* length,
* int* status)
*
* Parameters:
* - \c mangled_name
* NUL-terminated character string containing the name to be demangled.
* - \c output_buffer
* region of memory, allocated with \c malloc, of `*length` bytes,
* into which the demangled name is stored. If \c output_buffer is not long enough,
* it is expanded using \c realloc. output_buffer may instead be NULL; in that case,
* the demangled name is placed in a region of memory allocated with \c malloc.
* - \c length
* If length is non-NULL, the length of the buffer containing the demangled name is placed in `*length`.
* - \c status
* error flag: `*status` is set to one of the following values:
*
* 0: The demangling operation succeeded.
* -1: A memory allocation failure occurred.
* -2: mangled_name is not a valid name under the C++ ABI mangling rules.
* -3: One of the arguments is invalid.
*
* The function returns a pointer to the start of the NUL-terminated demangled name,
* or NULL if the demangling fails. The caller is responsible for deallocating
* this memory using \c free.
*/
string
demangleCxx (Literal rawName)
{
int error = -4;
UniqueMallocOwner<char> demangled (abi::__cxa_demangle (rawName,
NULL,
NULL,
&error));
return 0==error? demangled.get()
: string(rawName);
}
#else
string
demangleCxx (Literal rawName)
{
return string (rawName);
}
#endif

View file

@ -26,7 +26,7 @@
** Mostly, these are diagnostics helpers to produce readable output, especially
** for types. Some of these support meta programming to figure out the \em actual
** reference kind (value, lvalue, rvalue) of a template parameter instantiation.
** For GNU compatible compilers, we define here also an interface to the internal
** For GNU compatible compilers, we provide here also an interface to the internal
** ABI for [demangling type names](\ref demangleCxx).
**
** @note this header is included into a large number of tests.
@ -42,6 +42,7 @@
#include "lib/symbol.hpp"
#include "lib/time/timevalue.hpp"
#include "lib/format-obj.hpp"
#include <boost/lexical_cast.hpp>
#include <typeinfo>
@ -56,6 +57,7 @@ namespace test{
using lib::Literal;
using std::string;
using std::rand;
using lib::meta::demangleCxx;
@ -65,6 +67,7 @@ namespace test{
* @return either the literal name without any further magic,
* or the result of compile-time or run time
* type identification as implemented by the compiler.
* @deprecated 1/2016 to be replaced by lib::typeString (from \ref format-obj.hpp=
*/
template<typename T>
inline Literal
@ -78,6 +81,7 @@ namespace test{
* @return either the literal name without any further magic,
* or the result of compile-time or run time
* type identification as implemented by the compiler.
* @deprecated 1/2016 to be replaced by lib::typeString (from \ref format-obj.hpp=
*/
template<typename T>
inline Literal
@ -87,18 +91,6 @@ namespace test{
}
/** reverse the effect of C++ name mangling.
* @return string in language-level form of a C++ type or object name,
* or a string with the original input if demangling fails.
* @warning implementation relies on the cross vendor C++ ABI in use
* by GCC and compatible compilers, so portability is limited.
* The implementation is accessed through libStdC++
* Name representation in emitted object code and type IDs is
* essentially an implementation detail and subject to change.
*/
string
demangleCxx (Literal rawName);
/** short yet distinct name identifying the given type.
* @return demangled type-id without any scopes. */

View file

@ -27,7 +27,7 @@
** mostly for the purpose of documenting the issue at the
** usage site.
**
** @see lib::test::demangleCxx
** @see lib::meta::demangleCxx
** @see UniqueMallocOwner_test
**
*/

View file

@ -40,7 +40,7 @@ using std::cout;
using std::endl;
using lib::test::showType;
using lib::test::demangleCxx;
using lib::meta::demangleCxx;
namespace lib {

View file

@ -68,7 +68,7 @@ namespace test{
* and the ownership token should be empty.
*
* @see lib::UniqueMallocOwner
* @see lib::test::demangleCxx
* @see lib::meta::demangleCxx
*/
class UniqueMallocOwner_test : public Test
{