Lumiera  0.pre.03
»edit your freedom«
format-string.hpp File Reference

Go to the source code of this file.

Description

Front-end for printf-style string template interpolation.

While the actual implementation just delegates to boost::format, this front-end hides the direct dependency, additionally invokes a custom toSting conversion whenever possible, provides a direct automatic conversion to the formatted result to string and catches any exceptions.

This front-end is used pervasively for diagnostics and logging, so keeping down the compilation and object size cost and reliably handling any error is more important than the (small) performance gain of directly invoking boost::format (which is known to be 10 times slower than printf anyway).

Implementation notes

To perform the formatting, usually a _Fmt object is created as an anonymous temporary, but it may as well be stored into a variable. Copying is not permitted. Individual parameters are then fed for formatting through the '' operator. Each instance of _Fmt uses its own embedded boost::format object for implementation, but this formatter resides within an opaque buffer embedded into the frontend object. The rationale for this admittedly tricky approach is to confine any usage of boost::format to the implementation translation unit (format-string.cpp).

The implementation is invoked by the frontend through a set of explicit specialisations for all the relevant primitive data types. For custom types, we prefer to invoke operator string() if possible, which is determined by a simple metaprogramming test, which is defined in lib/meta/util.pp, without relying on boost. As a fallback, for all other types without built-in or custom string conversion, we use the mangled type string produced by RTTI.

The compile time and object size overhead incurred by using this header was verified to be negligible, in comparison to using boost::format. When compiling a demo example on x86_64, the following executable sizes could be observed:

                                     |debug | stripped

-------------------------------------—:|-—: | —: just string concatenation ... | 42k | 8.8k including and using format-string.hpp ...| 50k | 9.4k including and using boost::format ... | 420k | 140k

In addition, we need to take the implementation translation unit (format-string.cpp) into account, which is required once per application and contains the specialisations for all primitive types. In the test showed above, the corresponding object file had a size of 1300k (with debug information) resp. 290k (stripped).

Usage

The syntax of the format string is defined by boost::format and closely mimics the printf formatting directives. The notable difference is that boost::format uses the C++ stream output framework, and thus avoids the perils of printf. The individual formatting placeholders just set the corresponding flags on an embedded string stream, thus the actual parameter types cause the selection of a suitable format, not the definitions within the format string.

An illegal format string will raise an error::Fatal. Any other error during usage of the formatter is caught, logged and suppressed, inserting an error indicator into the formatted result instead

A formatter is usually created as an anonymous object, at places where a string is expected. An arbitrary number of parameters is then supplied using the '' operator. The result can be obtained

  • by string conversion
  • by feeding into an output stream.

Code example:

double total = 22.9499;
const char * currency = "€";
cout << _Fmt("price %+5.2f %s") % total % currency << endl;
Remarks
See the unit-test for extensive usage examples and corner cases. The header format-obj.hpp provides an alternative string conversion, using a bit of type traits and boost lexical_cast, but no boost::format.
Warning
not suited for performance critical code. About 10 times slower than printf.

TICKET #1204 : proper alignment verified 10/2019

See also
FormatString_test
format-util.hpp
format-obj.hpp

Definition in file format-string.hpp.

#include "lib/error.hpp"
#include "lib/symbol.hpp"
#include "lib/nocopy.hpp"
#include "lib/meta/util.hpp"
#include "lib/meta/size-trait.hpp"
#include <string>

Classes

struct  _allow_call< X >
 by default we don't allow to treat any types directly by boost::format. More...
 
struct  _allow_call< char >
 
struct  _allow_call< double >
 
struct  _allow_call< float >
 
struct  _allow_call< int16_t >
 
struct  _allow_call< int32_t >
 
struct  _allow_call< int64_t >
 
struct  _allow_call< long >
 
struct  _allow_call< string >
 
struct  _allow_call< uchar >
 
struct  _allow_call< uint16_t >
 
struct  _allow_call< uint32_t >
 
struct  _allow_call< uint64_t >
 
struct  _allow_call< ulong >
 
class  _Fmt
 A front-end for using printf-style formatting. More...
 
struct  _is_smart_wrapper< SP >
 
struct  _is_smart_wrapper< std::shared_ptr< T > >
 
struct  _is_smart_wrapper< std::unique_ptr< T, D > >
 
struct  _shall_convert_toString< X >
 
struct  _shall_format_directly< X >
 
struct  _shall_show_smartWrapper< SP >
 
class  basic_ostream< Char >
 STL class.
 
class  char_traits< C >
 
struct  _Fmt::Converter< VAL, SEL >
 helper to prepare parameters for inclusion More...
 
struct  _Fmt::Converter< VAL, SEL >
 helper to prepare parameters for inclusion More...
 
struct  _Fmt::Converter< bool >
 
struct  _Fmt::Converter< const char * >
 
struct  _Fmt::Converter< lib::Literal >
 
struct  _Fmt::Converter< lib::Symbol >
 
struct  _Fmt::Converter< SP, lib::meta::enable_if< _shall_show_smartWrapper< SP > > >
 
struct  _Fmt::Converter< VAL * >
 
struct  _Fmt::Converter< VAL, lib::meta::enable_if< _shall_convert_toString< VAL > > >
 some custom types explicitly provide a string representation More...
 
struct  _Fmt::Converter< VAL, lib::meta::enable_if< _shall_format_directly< VAL > > >
 some basic types are directly forwarded down to the implementation; More...
 
struct  _Fmt::Converter< void * >
 

Typedefs

typedef unsigned char uchar
 

Functions

void _clear_errorflag ()
 
string _log_and_stringify (std::exception const &ex)
 
string _log_unknown_exception ()
 
 LUMIERA_ERROR_DECLARE (FORMAT_SYNTAX)
 "Syntax error in format string for boost::format"
 
bool operator== (_Fmt const &left, _Fmt const &right)
 
bool operator== (_Fmt const &fmt, string const &str)
 
bool operator== (_Fmt const &fmt, const char *const cString)
 
bool operator== (string const &str, _Fmt const &fmt)
 
bool operator== (const char *const cString, _Fmt const &fmt)
 

Namespaces

 lib
 Implementation namespace for support and library code.