diff --git a/research/try.cpp b/research/try.cpp index 13878cc46..78be072e2 100644 --- a/research/try.cpp +++ b/research/try.cpp @@ -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 - inline string - typeStr (const TY* obj=0) - { - auto mangledType = obj? typeid(obj).name() - : typeid(TY).name(); - return string("«")+ mangledType +"»"; - } - - template - inline string - typeStr (TY const& ref) - { return typeStr(&ref); } -///////////////////////////////copied from format-util.hpp - - ///////////////////////////////planned minimal conversion, maybe in meta/util.hpp ? template struct CustomStringConv { - static string invoke (X const& x) { return typeStr(x); } + static string invoke (X const& x) { return "«"+typeStr(x)+"»"; } }; template @@ -134,7 +118,7 @@ inline string stringz (P ptr) { if (not ptr) - return "⟂ P"+typeStr(ptr.get()); + return "⟂ P<"+typeStr(ptr.get())+">"; else return CustomStringConv::invoke (*ptr); } @@ -202,7 +186,7 @@ namespace meta { if (ptr) return os << (void*)ptr << " ↗" << *ptr; else - return os << "⟂ " << typeStr(); + return os << "⟂ «" << typeStr() << "»"; } template diff --git a/src/lib/format-obj.cpp b/src/lib/format-obj.cpp new file mode 100644 index 000000000..8fd4ca1f2 --- /dev/null +++ b/src/lib/format-obj.cpp @@ -0,0 +1,152 @@ +/* + FormatObj - simple means to display an object + + Copyright (C) Lumiera.org + 2016, Hermann Vosseler + + 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 +#endif + +#include + + +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 `` + * + * 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 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 diff --git a/src/lib/format-obj.hpp b/src/lib/format-obj.hpp new file mode 100644 index 000000000..6bb0d5edc --- /dev/null +++ b/src/lib/format-obj.hpp @@ -0,0 +1,79 @@ +/* + FORMAT-OBJ.hpp - simple means to display an object + + Copyright (C) Lumiera.org + 2016, Hermann Vosseler + + 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 +#include + + +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*/ diff --git a/src/lib/format-string.hpp b/src/lib/format-string.hpp index c28a5796e..a6455be02 100644 --- a/src/lib/format-string.hpp +++ b/src/lib/format-string.hpp @@ -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 ** */ diff --git a/src/lib/format-util.hpp b/src/lib/format-util.hpp index 4272f11b8..985d04265 100644 --- a/src/lib/format-util.hpp +++ b/src/lib/format-util.hpp @@ -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 -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 +"»"; diff --git a/src/lib/idi/genfunc.cpp b/src/lib/idi/genfunc.cpp index 46aa49b5f..d94626064 100644 --- a/src/lib/idi/genfunc.cpp +++ b/src/lib/idi/genfunc.cpp @@ -23,6 +23,7 @@ #include "lib/idi/genfunc.hpp" #include "lib/format-string.hpp" +#include "lib/format-obj.hpp" #include "lib/util.hpp" #include @@ -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 diff --git a/src/lib/meta/util.hpp b/src/lib/meta/util.hpp index 073a9f5fb..2ac910290 100644 --- a/src/lib/meta/util.hpp +++ b/src/lib/meta/util.hpp @@ -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 + inline std::string + typeStr (const TY* obj=nullptr) + { + auto mangledType = obj? typeid(obj).name() + : typeid(TY).name(); + return humanReadableTypeID (mangledType); + } + + template + inline std::string + typeStr (TY const& ref) + { + return typeStr (&ref); + } + + + }} // namespace lib::meta #endif diff --git a/src/lib/test/suite.cpp b/src/lib/test/suite.cpp index 0faf7ccf9..9e3947427 100644 --- a/src/lib/test/suite.cpp +++ b/src/lib/test/suite.cpp @@ -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 TestMap; typedef shared_ptr PTestMap; diff --git a/src/lib/test/test-helper.cpp b/src/lib/test/test-helper.cpp index 20a6a34c3..fc1eaaaa5 100644 --- a/src/lib/test/test-helper.cpp +++ b/src/lib/test/test-helper.cpp @@ -35,10 +35,6 @@ #include "lib/format-string.hpp" #include "lib/unique-malloc-owner.hpp" -#ifdef __GNUG__ -#include -#endif - #include 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 `` - * - * 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 demangled (abi::__cxa_demangle (rawName, - NULL, - NULL, - &error)); - return 0==error? demangled.get() - : string(rawName); - } - -#else - string - demangleCxx (Literal rawName) - { - return string (rawName); - } -#endif diff --git a/src/lib/test/test-helper.hpp b/src/lib/test/test-helper.hpp index babe35c1e..91e95def8 100644 --- a/src/lib/test/test-helper.hpp +++ b/src/lib/test/test-helper.hpp @@ -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 #include @@ -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 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 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. */ diff --git a/src/lib/unique-malloc-owner.hpp b/src/lib/unique-malloc-owner.hpp index a04cf5610..fda6d677c 100644 --- a/src/lib/unique-malloc-owner.hpp +++ b/src/lib/unique-malloc-owner.hpp @@ -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 ** */ diff --git a/tests/library/diff/generic-tree-mutator-test.cpp b/tests/library/diff/generic-tree-mutator-test.cpp index 149783211..5d2a54069 100644 --- a/tests/library/diff/generic-tree-mutator-test.cpp +++ b/tests/library/diff/generic-tree-mutator-test.cpp @@ -40,7 +40,7 @@ using std::cout; using std::endl; using lib::test::showType; -using lib::test::demangleCxx; +using lib::meta::demangleCxx; namespace lib { diff --git a/tests/library/unique-malloc-owner-test.cpp b/tests/library/unique-malloc-owner-test.cpp index adabb2e1b..199ae20cf 100644 --- a/tests/library/unique-malloc-owner-test.cpp +++ b/tests/library/unique-malloc-owner-test.cpp @@ -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 {