diff --git a/src/lib/format-string.cpp b/src/lib/format-string.cpp index 30d3a7774..c0e84fad1 100644 --- a/src/lib/format-string.cpp +++ b/src/lib/format-string.cpp @@ -70,6 +70,38 @@ namespace util { } + /** */ + template + void + _Fmt::pushParameter (VAL const& val) + { + UNIMPLEMENTED ("feed the parameter to the embedded formatter"); + } + + template + void + _Fmt::pushParameter (const VAL * const pVal) + { + if (pVal) + pushParameter(*pVal); + else + pushParameter(string("(null)")); + } + + + /* ===== explicitly supported =================== */ + + template void _Fmt::pushParameter(string const&); + template void _Fmt::pushParameter(int const&); + template void _Fmt::pushParameter(uint const&); + + template void _Fmt::pushParameter(const string * const); + template void _Fmt::pushParameter(const int * const); + template void _Fmt::pushParameter(const uint * const); + + + + /** */ _Fmt::operator string() const { diff --git a/src/lib/format-string.hpp b/src/lib/format-string.hpp index 5efbe2f6f..53d3d278e 100644 --- a/src/lib/format-string.hpp +++ b/src/lib/format-string.hpp @@ -48,6 +48,7 @@ //#include "lib/meta/trait.hpp" //#include "lib/symbol.hpp" //#include "lib/util.hpp" +#include "lib/error.hpp" #include //#include @@ -70,6 +71,7 @@ namespace std { // forward declaration to avoid including } + namespace util { using boost::enable_if; @@ -77,11 +79,6 @@ namespace util { using std::string; - namespace { // helpers to pick a suitable specialisation.... - - enum{ FORMATTER_SIZE = 100 }; - - }//(End) guards/helpers @@ -92,13 +89,19 @@ namespace util { class _Fmt : boost::noncopyable { + enum{ FORMATTER_SIZE = 100 }; + + + char formatter_[FORMATTER_SIZE]; template - struct Param; + struct Converter; - template - friend struct Param; + template + void pushParameter (VAL const&); + template + void pushParameter (const VAL * const); public: @@ -130,28 +133,138 @@ namespace util { - /* == forwarding into the implementation == */ + /* ===== forwarding into the implementation ====== */ + /** The percent operator (\c '%' ) is used do feed + * additional parameter values to be included into + * the formatted result, at the positions marked + * within the format string. + * + * \par type specific treatment + * Basic types (numbers, chars, strings) are passed to the implementation + * (= boost::format) literally. For custom types, we try to use an custom + * string conversion, if applicable. Any other type gets just translated + * into a type-ID (using the mangled RTTI info). In case of errors during + * the conversion, a string representation of the error is returned + * @param val arbitrary value or pointer to be included into the result + * @warning you need to provide exactly the right number of parameters, + * i.e. matching the number of fields in the format string. + */ template inline _Fmt& _Fmt::operator% (VAL const& val) { - Param::push (val); + pushParameter (Converter::prepare (val)); return *this; } - template - struct _Fmt::Param + + namespace { // helpers to pick a suitable specialisation.... + + template + struct _can_convertToString + { + enum{ value = false }; + }; + + + /** + * by default we don't allow to + * treat any types directly by boost::format. + * As fallback we rather just produce a type-ID + */ + template + struct _can_forward { enum{ value = false };}; + + /* the following definitions enable some basic types + * to be forwarded to boost::format literally */ + template<> struct _can_forward { enum{ value = true }; }; + template<> struct _can_forward { enum{ value = true }; }; + template<> struct _can_forward { enum{ value = true }; }; + + + + inline string + _log_and_stringify (std::exception const& ex) { - static void - push (VAL const&) + WARN (progress, "Error while invoking custom string conversion: %s", ex.what()); + return ex.what(); + } + + inline string + _log_unknown_exception() + { + const char* errID = lumiera_error(); + if (errID) + { + ERROR (progress, "Unknown error while invoking custom string conversion. Lumiera error flag = %s", errID); + return string("Unknown error in string conversion. FLAG=")+errID; + } + else + { + ERROR (progress, "Unknown error while invoking custom string conversion. No Lumiera error flag set."); + return "Unknown error in string conversion"; + } + } + + }//(End) guards/helpers + + + + /* === explicit specialisations to control the kind of conversion === */ + + template + struct _Fmt::Converter + { + static string + prepare (VAL const&) { UNIMPLEMENTED ("get type string"); } }; + template + struct _Fmt::Converter >::type> + { + static string + prepare (VAL const& val) + try { + return string(val); + } + catch(std::exception const& ex) + { + return _log_and_stringify(ex); + } + catch(...) + { + return _log_unknown_exception(); + } + }; + template + struct _Fmt::Converter >::type> + { + static VAL const& + prepare (VAL const& val) + { + return val; + } + }; + + template + struct _Fmt::Converter >::type> + { + static const VAL * + prepare (const VAL * const pVal) + { + return pVal; + } + }; + + + + /* === comparison of formatter objects === */ inline bool operator== (_Fmt const& left, _Fmt const& right)