rewrite type selection logic to handle ptrs in the front-end

whew, quite a heavy rewrite, but greatly
simplifies the code and removes the necessity
to declare explicit specialisations of pointers
This commit is contained in:
Fischlurch 2011-12-31 03:52:10 +01:00
parent c8f46f47c9
commit e1b9b5b135
3 changed files with 104 additions and 119 deletions

View file

@ -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<typename VAL>
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<typename VAL>
void
_Fmt::pushParameter (const VAL val)
{
doFormatParameter (formatter_, val);
}
_Fmt::format (const VAL val, Implementation& formatter)
try {
accessImpl(formatter) % val;
}
template<typename VAL>
void
_Fmt::pushParameter (const VAL * pVal)
{
if (pVal)
doFormatParameter (formatter_, *pVal);
else
doFormatParameter (formatter_, "<null>");
}
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&);

View file

@ -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<typename VAL>
static void format (const VAL, Implementation&);
/** helper to prepare parameters for inclusion */
template<typename VAL, class SEL =void>
struct Converter;
template<typename VAL>
void pushParameter (const VAL);
template<typename VAL>
void pushParameter (const VAL *);
template<typename VAL>
void pushParameter (VAL *);
public:
@ -158,7 +154,7 @@ namespace util {
inline _Fmt&
_Fmt::operator% (VAL const& val)
{
pushParameter (Converter<VAL>::prepare (val));
Converter<VAL>::dump (val, formatter_);
return *this;
}
@ -187,7 +183,6 @@ namespace util {
template<> struct _allow_call<uint64_t>{ enum{ value = true }; };
template<> struct _allow_call<float> { enum{ value = true }; };
template<> struct _allow_call<double> { enum{ value = true }; };
template<> struct _allow_call<void*> { enum{ value = true }; };
template<typename X>
struct _shall_format_directly
@ -197,11 +192,6 @@ namespace util {
enum{ value = _allow_call<BaseType>::value };
};
template<typename X>
struct _shall_format_directly<X*>
: _shall_format_directly<X>
{ };
template<typename X>
@ -246,10 +236,43 @@ namespace util {
template<typename VAL, class SEL>
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<typename VAL>
struct _Fmt::Converter<VAL*>
{
static void
dump (const VAL *pVal, Implementation& impl)
{
if (pVal)
Converter<VAL>::dump(*pVal, impl);
else
format ("<null>", impl);
}
};
template<>
struct _Fmt::Converter<void *>
{
static void
dump (const void* address, Implementation& impl)
{
format (address, impl);
}
};
template<>
struct _Fmt::Converter<const char *>
{
static void
dump (const char* cString, Implementation& impl)
{
format (cString? cString : "", impl);
}
};
@ -257,18 +280,18 @@ namespace util {
template<typename VAL>
struct _Fmt::Converter<VAL, typename enable_if< _shall_convert_toString<VAL> >::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<typename VAL>
struct _Fmt::Converter<VAL, typename enable_if< _shall_format_directly<VAL> >::type>
{
static VAL const&
prepare (VAL const& val)
static void
dump (const VAL val, Implementation& impl)
{
return val;
format (val, impl);
}
};
template<typename VAL>
void
_Fmt::pushParameter (VAL * pV) ///< treat as const
{
pushParameter ((const VAL*) pV);
}
/* === comparison of formatter objects === */

View file

@ -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 == "__<null>__");
CHECK (_Fmt("__%s__") % pv == "__0__");
CHECK (_Fmt("__%s__") % vv == "__0__");
}
};