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:
parent
c8f46f47c9
commit
e1b9b5b135
3 changed files with 104 additions and 119 deletions
|
|
@ -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&);
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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 === */
|
||||
|
|
|
|||
|
|
@ -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__");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue