diff --git a/src/lib/format-string.cpp b/src/lib/format-string.cpp index 562fe10d1..c0c6926f2 100644 --- a/src/lib/format-string.cpp +++ b/src/lib/format-string.cpp @@ -70,6 +70,13 @@ namespace util { } + inline void + destroyImpl (char* buffer) + { + accessImpl(buffer).~format(); + } + + /** in case the formatting of a (primitive) value fails, * we try to use a error indicator instead */ @@ -88,34 +95,6 @@ namespace util { ERROR_LOG_AND_IGNORE (progress, "Supplying placeholder for problematic format parameter") - /** Core function: let boost::format handle a value */ - template - void - doFormatParameter (char* formatter, VAL const& val) - try { - accessImpl(formatter) % val; - } - - catch (boost::io::too_many_args& argErr) - { - WARN (progress, "Format: excess argument '%s' of type %s ignored." - , cStr(str(val)) - , cStr(tyStr(val))); - } - catch (std::exception& failure) - { - WARN (progress, "Format: Parameter '%s' causes problems: %s" - , cStr(str(val)) - , failure.what()); - pushFailsafeReplacement (formatter, failure.what()); - } - catch (...) - { - WARN (progress, "Format: Unexpected problems accepting format parameter '%s'", cStr(str(val))); - pushFailsafeReplacement (formatter); - } - - inline void suppressInsufficientArgumentErrors (char* formatter) { @@ -141,13 +120,16 @@ namespace util { _Fmt::~_Fmt () { - accessImpl(formatter_).~format(); + destroyImpl (formatter_); } - /** @internal access points for the frontend, - * allowing to push a parameter value down into the implementation - * for the actual formatting. + /** @internal access point for the frontend, + * allowing to push a single parameter value down + * into the implementation for the actual formatting. + * Only selected primitive types are handled directly this way, + * while all custom conversions, the handling of pointers and the + * fallback (showing a type string) is done in the frontend. * @note we need to generate instantiations of this template function * explicitly for all basic types to be supported for direct handling, * otherwise we'll get linker errors. Lumiera uses the ``inclusion model'' @@ -157,60 +139,48 @@ namespace util { */ template void - _Fmt::pushParameter (const VAL val) - { - doFormatParameter (formatter_, val); - } + _Fmt::format (const VAL val, Implementation& formatter) + try { + accessImpl(formatter) % val; + } - template - void - _Fmt::pushParameter (const VAL * pVal) - { - if (pVal) - doFormatParameter (formatter_, *pVal); - else - doFormatParameter (formatter_, ""); - } + catch (boost::io::too_many_args& argErr) + { + WARN (progress, "Format: excess argument '%s' of type %s ignored." + , cStr(str(val)) + , cStr(tyStr(val))); + } + catch (std::exception& failure) + { + WARN (progress, "Format: Parameter '%s' causes problems: %s" + , cStr(str(val)) + , failure.what()); + pushFailsafeReplacement (formatter, failure.what()); + } + catch (...) + { + WARN (progress, "Format: Unexpected problems accepting format parameter '%s'", cStr(str(val))); + pushFailsafeReplacement (formatter); + } - template<> - void - _Fmt::pushParameter (const char * cString) - { - doFormatParameter (formatter_, cString? cString : "↯" ); - } - template<> - void - _Fmt::pushParameter (const void * address) - { - doFormatParameter (formatter_, address); - } /* ===== explicitly supported =================== */ - template void _Fmt::pushParameter(const string); - template void _Fmt::pushParameter(const char); - template void _Fmt::pushParameter(const uchar); - template void _Fmt::pushParameter(const int); - template void _Fmt::pushParameter(const uint); - template void _Fmt::pushParameter(const short); - template void _Fmt::pushParameter(const ushort); - template void _Fmt::pushParameter(const int64_t); - template void _Fmt::pushParameter(const uint64_t); - template void _Fmt::pushParameter(const float); - template void _Fmt::pushParameter(const double); - - template void _Fmt::pushParameter(const string * ); - template void _Fmt::pushParameter(const uchar * ); - template void _Fmt::pushParameter(const int * ); - template void _Fmt::pushParameter(const uint * ); - template void _Fmt::pushParameter(const short * ); - template void _Fmt::pushParameter(const ushort * ); - template void _Fmt::pushParameter(const int64_t *); - template void _Fmt::pushParameter(const uint64_t*); - template void _Fmt::pushParameter(const float * ); - template void _Fmt::pushParameter(const double * ); + template void _Fmt::format (const char, Implementation&); + template void _Fmt::format (const uchar, Implementation&); + template void _Fmt::format (const int, Implementation&); + template void _Fmt::format (const uint, Implementation&); + template void _Fmt::format (const short, Implementation&); + template void _Fmt::format (const ushort, Implementation&); + template void _Fmt::format (const int64_t, Implementation&); + template void _Fmt::format (const uint64_t,Implementation&); + template void _Fmt::format (const float, Implementation&); + template void _Fmt::format (const double, Implementation&); + template void _Fmt::format (const string, Implementation&); + template void _Fmt::format (const void *, Implementation&); + template void _Fmt::format (const char *, Implementation&); diff --git a/src/lib/format-string.hpp b/src/lib/format-string.hpp index 2e7f63060..0c49bbe0a 100644 --- a/src/lib/format-string.hpp +++ b/src/lib/format-string.hpp @@ -89,23 +89,19 @@ namespace util { /** size of an internal implementation Buffer */ enum{ FORMATTER_SIZE = lib::meta::SizeTrait::BOOST_FORMAT }; + typedef char Implementation[FORMATTER_SIZE]; /** @internal buffer to hold a boost::format */ - mutable char formatter_[FORMATTER_SIZE]; + mutable Implementation formatter_; + template + static void format (const VAL, Implementation&); + /** helper to prepare parameters for inclusion */ template struct Converter; - template - void pushParameter (const VAL); - - template - void pushParameter (const VAL *); - - template - void pushParameter (VAL *); public: @@ -158,7 +154,7 @@ namespace util { inline _Fmt& _Fmt::operator% (VAL const& val) { - pushParameter (Converter::prepare (val)); + Converter::dump (val, formatter_); return *this; } @@ -187,7 +183,6 @@ namespace util { template<> struct _allow_call{ enum{ value = true }; }; template<> struct _allow_call { enum{ value = true }; }; template<> struct _allow_call { enum{ value = true }; }; - template<> struct _allow_call { enum{ value = true }; }; template struct _shall_format_directly @@ -197,11 +192,6 @@ namespace util { enum{ value = _allow_call::value }; }; - template - struct _shall_format_directly - : _shall_format_directly - { }; - template @@ -246,10 +236,43 @@ namespace util { template struct _Fmt::Converter { - static const string - prepare (VAL const&) + static void + dump (VAL const&, Implementation& impl) { - return string("«")+typeid(VAL).name()+"»"; + format (string("«")+typeid(VAL).name()+"»", impl); + } + }; + + template + struct _Fmt::Converter + { + static void + dump (const VAL *pVal, Implementation& impl) + { + if (pVal) + Converter::dump(*pVal, impl); + else + format ("", impl); + } + }; + + template<> + struct _Fmt::Converter + { + static void + dump (const void* address, Implementation& impl) + { + format (address, impl); + } + }; + + template<> + struct _Fmt::Converter + { + static void + dump (const char* cString, Implementation& impl) + { + format (cString? cString : "↯", impl); } }; @@ -257,18 +280,18 @@ namespace util { template struct _Fmt::Converter >::type> { - static const string - prepare (VAL const& val) + static void + dump (VAL const& val, Implementation& impl) try { - return string(val); + format (string(val), impl); } catch(std::exception const& ex) { - return _log_and_stringify(ex); + format (_log_and_stringify(ex), impl); } catch(...) { - return _log_unknown_exception(); + format (_log_unknown_exception(), impl); } }; @@ -277,20 +300,13 @@ namespace util { template struct _Fmt::Converter >::type> { - static VAL const& - prepare (VAL const& val) + static void + dump (const VAL val, Implementation& impl) { - return val; + format (val, impl); } }; - template - void - _Fmt::pushParameter (VAL * pV) ///< treat as const - { - pushParameter ((const VAL*) pV); - } - /* === comparison of formatter objects === */ diff --git a/tests/lib/format-string-test.cpp b/tests/lib/format-string-test.cpp index 6ba3b4c32..48c5b5df3 100644 --- a/tests/lib/format-string-test.cpp +++ b/tests/lib/format-string-test.cpp @@ -46,11 +46,11 @@ namespace test { * @test verifies our front-end for printf-style format string based formatting. * - the implementation is based on boost::format * - we create a wrapper-object on-the fly, which is able to hold - * the result of a partial invocation - * - explicit specialisations feed all primitive types directly - * down into the implementation level. If possible, a custom operator string() + * the result of a partial invocation, until all parameters are given. + * - explicit specialisations feed all primitive types directly down + * into the implementation level. If possible, a custom operator string() * will be used for formatting. - * - any kind of exception will be logged, but handled gracefully + * - exceptions will be logged, but handled gracefully * * @see format-string.hpp * @see boost::format @@ -303,7 +303,6 @@ namespace test { Verbose *pv = &v; void *vv = pv; CHECK (_Fmt("__%s__") % v == "__Number-042__"); - cout << "yyy=" << string(_Fmt("__%s__") % pv) << endl; CHECK (_Fmt("__%s__") % pv == "__Number-042__"); CHECK (_Fmt("__%s__") % vv != "__Number-042__"); @@ -313,7 +312,7 @@ namespace test { pv = NULL; vv = NULL; CHECK (_Fmt("__%s__") % pv == "____"); - CHECK (_Fmt("__%s__") % pv == "__0__"); + CHECK (_Fmt("__%s__") % vv == "__0__"); } };