diff --git a/src/lib/format-cout.hpp b/src/lib/format-cout.hpp index e044c9ed6..a874f3c32 100644 --- a/src/lib/format-cout.hpp +++ b/src/lib/format-cout.hpp @@ -28,8 +28,23 @@ ** by the representation of the pointee. When the displayed entity defines an ** `operator string()`, this custom string conversion will be used (suppressing ** any exceptions, of course). As fallback, a simplified type string is printed. + ** + ** \par policy + ** What shall be expected from a generic toString conversion? + ** It should be _minimal_, it should be _transparent_ and it should + ** always work and deliver a string, irrespective of the circumstances. + ** By extension, this means that we do not want to differentiate much + ** between values, references and pointers, which also means, we do + ** not want to indicate pointers explicitly (just signal NULL, when + ** encountered). The situation is slightly different for the `ostream` + ** inserter; in a modern GUI application, there isn't much use for + ** STDOUT and STDERR, beyond error messages and unit testing. + ** Thus, we can strive at building a more convenient flavour + ** here, which does indeed even show the address of pointers. ** + ** @see FormatCOUT_test ** @see FormatHelper_test + ** @see [generic string conversion helper](\ref util::toString) ** @see [frontend for boost::format, printf-style](format-string.hpp) ** */ diff --git a/src/lib/format-obj.hpp b/src/lib/format-obj.hpp index 07c30ab2c..35addbbd4 100644 --- a/src/lib/format-obj.hpp +++ b/src/lib/format-obj.hpp @@ -24,15 +24,19 @@ /** @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. + ** as to incur only 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. + ** - util::typedString() combines this with a always visible type display ** - 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. ** + ** @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... + ** ** @see FormatHelper_test ** @see [frontend for boost::format, printf-style](format-string.hpp) ** diff --git a/src/lib/meta/trait.hpp b/src/lib/meta/trait.hpp index b92de002a..189207a67 100644 --- a/src/lib/meta/trait.hpp +++ b/src/lib/meta/trait.hpp @@ -254,8 +254,8 @@ namespace meta { /** compare unadorned types, disregarding const and references */ template struct is_basically - : is_same ::TypeReferred - ,typename Strip::TypeReferred> + : is_same ::TypePlain + ,typename Strip::TypePlain> { }; /** detect various flavours of string / text data */ diff --git a/tests/00support.tests b/tests/00support.tests index d8ae934a4..3e817e729 100644 --- a/tests/00support.tests +++ b/tests/00support.tests @@ -47,12 +47,6 @@ return: 0 END -TEST "Helper to show demangled C++ names" TestHelperDemangling_test <::Inner const&&) -END - - TEST "Testsuite option handling" TestOption_test < Testgroup=ALL diff --git a/tests/12metaprogramming.tests b/tests/12metaprogramming.tests index 295ba9de0..2c0db5531 100644 --- a/tests/12metaprogramming.tests +++ b/tests/12metaprogramming.tests @@ -320,6 +320,16 @@ out-lit: :. END +TEST "Helper to show demangled C++ names" TypeDemangling_test <::Inner const&&) +END + + +TEST "Helper for human readable type display" TypeDisplay_test <` in this category, which allows us - ** at least to show a type name as fallback - ** - distill an essential version of `enable_if`, which can be inlined. - ** This allows us to get rid of `boost::enable_if` finally. - ** - build a sensible `operator string()` for our `lib::P` based on this - ** - and _finally_, to come up with a templated version of the `ostream` - ** inserter `operator<<`, which does not cause too much havoc when - ** used by default. The greatest challenge here is to avoid ambiguous - ** overloads, yet also to deal with references, `void` and arrays. - ** - ** \par policy - ** What shall be expected from such a generic toString conversion? - ** It should be _minimal_, it should be _transparent_ and it should - ** always work and deliver a string, irrespective of the circumstances. - ** By extension, this means that we do not want to differentiate much - ** between values, references and pointers, which also means, we do - ** not want to indicate pointers explicitly (just signal NULL, when - ** encountered). The situation is slightly different for the `ostream` - ** inserter; in a modern GUI application, there isn't much use for - ** STDOUT and STDERR, beyond error messages and unit testing. - ** Thus, we can strive at building a more convenient flavour - ** here, which does indeed even shows the address of pointers. - ** - */ - -typedef unsigned int uint; #include "lib/p.hpp" #include "lib/diff/gen-node.hpp" @@ -69,105 +35,115 @@ typedef unsigned int uint; using lib::P; using lib::newP; using lib::diff::GenNode; -using lib::meta::is_basically; -using lib::meta::is_StringLike; -using lib::meta::can_lexical2string; -using lib::meta::can_convertToString; -using lib::meta::use_StringConversion4Stream; using std::string; - - - - - namespace util { namespace test { - - class Reticent - { - uint neigh_ = 42; - }; - - -template -using BasicallyString = is_basically; -template -using BasicallyChar = std::is_convertible; - - -void -showTypes() - { + namespace { // test fixture + + /** opaque class without string conversion */ + class Reticent + { + uint neigh_ = 42; + }; + + + using lib::meta::is_basically; + using lib::meta::is_StringLike; + using lib::meta::can_lexical2string; + using lib::meta::can_convertToString; + using lib::meta::use_StringConversion4Stream; + + template + using BasicallyString = is_basically; + template + using BasicallyCString = std::is_convertible; + #define SHOW_CHECK(_EXPR_) cout << STRINGIFY(_EXPR_) << "\t : " << (_EXPR_::value? "Yes":"No") << endl; -#define ANALYSE(_TYPE_) \ - cout << "Type: " STRINGIFY(_TYPE_) " ......"<); \ - SHOW_CHECK (BasicallyChar<_TYPE_>); \ - SHOW_CHECK (BasicallyString<_TYPE_>); \ - SHOW_CHECK (std::is_arithmetic<_TYPE_>); \ - SHOW_CHECK (can_lexical2string<_TYPE_>); \ - SHOW_CHECK (can_convertToString<_TYPE_>); \ - SHOW_CHECK (use_StringConversion4Stream<_TYPE_>); +#define ANALYSE(_TYPE_) \ + cout << "Type: " STRINGIFY(_TYPE_) " ......"<); \ + SHOW_CHECK (BasicallyString<_TYPE_>); \ + SHOW_CHECK (BasicallyCString<_TYPE_>); \ + SHOW_CHECK (std::is_arithmetic<_TYPE_>); \ + SHOW_CHECK (can_lexical2string<_TYPE_>); \ + SHOW_CHECK (can_convertToString<_TYPE_>); \ + SHOW_CHECK (use_StringConversion4Stream<_TYPE_>); - using CharLit = typeof("bla"); - using CharPtr = typeof(const char*); - using GenNodePtr = typeof(GenNode*); - using GenNodeRef = typeof(GenNode&); - - ANALYSE (string); - ANALYSE (CharLit); - ANALYSE (CharPtr) - ANALYSE (Reticent) - ANALYSE (P) - ANALYSE (GenNode) - ANALYSE (GenNodePtr) - ANALYSE (GenNodeRef) - ANALYSE (P) - cout << endl; - } - - - + void + showTraits() + { + using CharLit = typeof("literal"); + using CharPtr = typeof(const char*); + using StrCRef = typeof(string const&); + using GenNodePtr = typeof(GenNode*); + using GenNodeRef = typeof(GenNode&); + + ANALYSE (double); + ANALYSE (string); + ANALYSE (StrCRef); + ANALYSE (CharLit); + ANALYSE (CharPtr) + ANALYSE (Reticent) + ANALYSE (P) + ANALYSE (GenNode) + ANALYSE (GenNodePtr) + ANALYSE (GenNodeRef) + ANALYSE (P) + cout << endl; + } + }//(end)fixture + + + + /***************************************************************************//** - * @test verifies the proper working of some string-formatting helper functions. - * - util::toString() provides a failsafe to-String conversion, preferring - * an built-in conversion, falling back to just a type string. - * - util::join() combines elements from arbitrary containers or iterators - * into a string, relyint on aforementioned generic string conversion - * @see format-util.hpp + * @test How to build generic string conversion into `ostream::operator<< `. + * This task (#985) was actually a conglomerate of several chores: + * - sanitise and segregate the type-traits usage + * - disentangle the existing util::str conversion helper + * - extract a basic form from this helper, which can be placed + * into a header with minimal dependencies. After some consideration, + * I decided to allow `` in this category, which allows us + * at least to show a type name as fallback + * - distill an essential version of `enable_if`, which can be inlined. + * This allows us to get rid of `boost::enable_if` finally. + * - build a sensible `operator string()` for our `lib::P` based on this + * - and _finally_, to come up with a templated version of the `ostream` + * inserter `operator<<`, which does not cause too much havoc when + * used by default. The greatest challenge here is to avoid ambiguous + * overloads, yet also to deal with references, `void` and arrays. + * + * @see format-cout.hpp + * @see FormatHelper_test */ class FormatCOUT_test : public Test { void run (Arg) - { - showTypes(); - - auto psss = newP(); - auto gnng = newP("Hui", "Buh"); - - cout << "mauu..." << psss <(); + auto chatty = newP("Hui", "Buh"); + + cout << "smart-ptr, no string conv..." << silent < @@ -22,7 +22,7 @@ #include "lib/test/run.hpp" -#include "lib/test/test-helper.hpp" +#include "lib/meta/util.hpp" #include #include @@ -33,7 +33,7 @@ using std::endl; namespace lib { -namespace test{ +namespace meta{ namespace test{ template @@ -42,7 +42,7 @@ namespace test{ struct Inner { }; static const T* - phantom (Inner const&&) + cloak (Inner const&&) { return nullptr; } @@ -62,13 +62,13 @@ namespace test{ * * @see test-helper.hpp */ - class TestHelperDemangling_test : public Test + class TypeDemangling_test : public Test { void run (Arg) { Outer ship; - auto magic = &ship.phantom; + auto magic = &ship.cloak; auto rawType = typeid(magic).name(); cout << rawType << endl; @@ -76,7 +76,7 @@ namespace test{ } }; - LAUNCHER (TestHelperDemangling_test, "unit common"); + LAUNCHER (TypeDemangling_test, "unit common"); -}}} // namespace lib::test::test +}}} // namespace lib::meta::test diff --git a/tests/library/meta/type-display-test.cpp b/tests/library/meta/type-display-test.cpp new file mode 100644 index 000000000..e2560ad5d --- /dev/null +++ b/tests/library/meta/type-display-test.cpp @@ -0,0 +1,109 @@ +/* + TypeDisplay(Test) - human readable simplified display of C++ types + + 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. + +* *****************************************************/ + + +#include "lib/test/run.hpp" + +//#include "lib/p.hpp" +//#include "lib/diff/gen-node.hpp" + +#include "lib/meta/util.hpp" + +#include //////////TODO +#include + +//using lib::P; +//using lib::newP; +//using lib::diff::GenNode; + +using std::string; +using std::cout; /////////////TODO +using std::endl; /////////////TODO + + +namespace lib { +namespace meta{ +namespace test{ + + namespace { // test fixture + + template + struct Outer + { + struct Inner { }; + + static const T* + cloak (Inner const&&) + { + return nullptr; + } + }; + + struct Space { }; + + auto CHALLENGE_1 = "some::arbitrary::BullShit"; + auto CHALLENGE_2 = "lib::BullShit)>"; + auto CHALLENGE_3 = "std::function>)>"; + + }//(end)fixture + + + + + /***************************************************************************//** + * @test verify post processing of demangled C++ type names. + * The purpose of those pretty printing functions is to support diagnostics + * and unit testing by making type names easier to digest. But of course + * we do not want to pick the right primary type for shortened display + * and we do not want mess up the semantic structure. + * + * @see format-cout.hpp + * @see FormatHelper_test + */ + class TypeDisplay_test + : public Test + { + void + run (Arg) + { + cout << "-----human-readable-------------"<