122 changes: 81 additions & 41 deletions include/boost/log/utility/type_dispatch/standard_types.hpp
Expand Up @@ -17,8 +17,10 @@

#include <string>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/copy.hpp>
#include <boost/mpl/back_inserter.hpp>
#include <boost/mpl/vector/vector30.hpp> // needed to use mpl::vector sizes greater than 20 even when the default BOOST_MPL_LIMIT_VECTOR_SIZE is not set
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/seq/enum.hpp>
#include <boost/preprocessor/seq/size.hpp>
#include <boost/log/detail/config.hpp>
#include <boost/log/utility/string_literal_fwd.hpp>
#include <boost/log/detail/header.hpp>
Expand All @@ -31,70 +33,108 @@ namespace boost {

BOOST_LOG_OPEN_NAMESPACE

#if !defined(BOOST_NO_INTRINSIC_WCHAR_T)
#define BOOST_LOG_AUX_STANDARD_TYPE_WCHAR_T() (wchar_t)
#else
#define BOOST_LOG_AUX_STANDARD_TYPE_WCHAR_T()
#endif

#if !defined(BOOST_NO_CXX11_CHAR16_T)
#define BOOST_LOG_AUX_STANDARD_TYPE_CHAR16_T() (char16_t)
#else
#define BOOST_LOG_AUX_STANDARD_TYPE_CHAR16_T()
#endif

#if !defined(BOOST_NO_CXX11_CHAR32_T)
#define BOOST_LOG_AUX_STANDARD_TYPE_CHAR32_T() (char32_t)
#else
#define BOOST_LOG_AUX_STANDARD_TYPE_CHAR32_T()
#endif

//! Boost.Preprocessor sequence of character types
#define BOOST_LOG_STANDARD_CHAR_TYPES()\
(char)BOOST_LOG_AUX_STANDARD_TYPE_WCHAR_T()BOOST_LOG_AUX_STANDARD_TYPE_CHAR16_T()BOOST_LOG_AUX_STANDARD_TYPE_CHAR32_T()

#if defined(BOOST_HAS_LONG_LONG)
#define BOOST_LOG_AUX_STANDARD_LONG_LONG_TYPES() (long long)(unsigned long long)
#else
#define BOOST_LOG_AUX_STANDARD_LONG_LONG_TYPES()
#endif

//! Boost.Preprocessor sequence of integral types
#define BOOST_LOG_STANDARD_INTEGRAL_TYPES()\
(bool)(signed char)(unsigned char)(short)(unsigned short)(int)(unsigned int)(long)(unsigned long)BOOST_LOG_AUX_STANDARD_LONG_LONG_TYPES()\
BOOST_LOG_STANDARD_CHAR_TYPES()

//! Boost.Preprocessor sequence of floating point types
#define BOOST_LOG_STANDARD_FLOATING_POINT_TYPES()\
(float)(double)(long double)

//! Boost.Preprocessor sequence of arithmetic types
#define BOOST_LOG_STANDARD_ARITHMETIC_TYPES()\
BOOST_LOG_STANDARD_INTEGRAL_TYPES()BOOST_LOG_STANDARD_FLOATING_POINT_TYPES()

#if defined(BOOST_LOG_USE_CHAR)
#define BOOST_LOG_AUX_STANDARD_STRING_TYPES() (std::string)(boost::log::string_literal)
#else
#define BOOST_LOG_AUX_STANDARD_STRING_TYPES()
#endif

#if defined(BOOST_LOG_USE_WCHAR_T)
#define BOOST_LOG_AUX_STANDARD_WSTRING_TYPES() (std::wstring)(boost::log::wstring_literal)
#else
#define BOOST_LOG_AUX_STANDARD_WSTRING_TYPES()
#endif

//! Boost.Preprocessor sequence of string types
#define BOOST_LOG_STANDARD_STRING_TYPES()\
BOOST_LOG_AUX_STANDARD_STRING_TYPES()BOOST_LOG_AUX_STANDARD_WSTRING_TYPES()

//! Boost.Preprocessor sequence of the default attribute value types supported by the library
#define BOOST_LOG_DEFAULT_ATTRIBUTE_VALUE_TYPES()\
BOOST_LOG_STANDARD_ARITHMETIC_TYPES()BOOST_LOG_STANDARD_STRING_TYPES()


/*!
* An MPL-sequence of integral types of attributes, supported by default
*/
typedef mpl::vector<
bool,
char,
#if !defined(BOOST_NO_INTRINSIC_WCHAR_T)
wchar_t,
#endif
signed char,
unsigned char,
short,
unsigned short,
int,
unsigned int,
long,
unsigned long
#if defined(BOOST_HAS_LONG_LONG)
, long long
, unsigned long long
#endif // defined(BOOST_HAS_LONG_LONG)
BOOST_PP_SEQ_ENUM(BOOST_LOG_STANDARD_INTEGRAL_TYPES())
> integral_types;

/*!
* An MPL-sequence of FP types of attributes, supported by default
*/
typedef mpl::vector<
float,
double,
long double
BOOST_PP_SEQ_ENUM(BOOST_LOG_STANDARD_FLOATING_POINT_TYPES())
> floating_point_types;

/*!
* An MPL-sequence of all numeric types of attributes, supported by default
*/
typedef mpl::copy<
floating_point_types,
mpl::back_inserter< integral_types >
>::type numeric_types;
typedef mpl::vector<
BOOST_PP_SEQ_ENUM(BOOST_LOG_STANDARD_ARITHMETIC_TYPES())
> arithmetic_types;

//! Deprecated alias
typedef arithmetic_types numeric_types;

/*!
* An MPL-sequence of string types of attributes, supported by default
*/
typedef mpl::vector<
#ifdef BOOST_LOG_USE_CHAR
std::string,
string_literal
#ifdef BOOST_LOG_USE_WCHAR_T
,
#endif
#endif
#ifdef BOOST_LOG_USE_WCHAR_T
std::wstring,
wstring_literal
#endif
BOOST_PP_SEQ_ENUM(BOOST_LOG_STANDARD_STRING_TYPES())
> string_types;

/*!
* An MPL-sequence of all attribute value types that are supported by the library by default.
*/
typedef mpl::copy<
string_types,
mpl::back_inserter< numeric_types >
>::type default_attribute_types;
typedef BOOST_PP_CAT(mpl::vector, BOOST_PP_SEQ_SIZE(BOOST_LOG_DEFAULT_ATTRIBUTE_VALUE_TYPES()))<
BOOST_PP_SEQ_ENUM(BOOST_LOG_DEFAULT_ATTRIBUTE_VALUE_TYPES())
> default_attribute_value_types;

//! Deprecated alias
typedef default_attribute_value_types default_attribute_types;

BOOST_LOG_CLOSE_NAMESPACE // namespace log

Expand Down
49 changes: 43 additions & 6 deletions src/code_conversion.cpp
Expand Up @@ -13,6 +13,7 @@
* at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html.
*/

#include <cstddef>
#include <locale>
#include <string>
#include <stdexcept>
Expand Down Expand Up @@ -114,13 +115,13 @@ inline void code_convert(const SourceCharT* begin, const SourceCharT* end, std::
}

//! The function converts one string to the character type of another
BOOST_LOG_API void code_convert(const wchar_t* str1, std::size_t len, std::string& str2, std::locale const& loc)
BOOST_LOG_API void code_convert_impl(const wchar_t* str1, std::size_t len, std::string& str2, std::locale const& loc)
{
code_convert(str1, str1 + len, str2, std::use_facet< std::codecvt< wchar_t, char, std::mbstate_t > >(loc));
}

//! The function converts one string to the character type of another
BOOST_LOG_API void code_convert(const char* str1, std::size_t len, std::wstring& str2, std::locale const& loc)
BOOST_LOG_API void code_convert_impl(const char* str1, std::size_t len, std::wstring& str2, std::locale const& loc)
{
code_convert(str1, str1 + len, str2, std::use_facet< std::codecvt< wchar_t, char, std::mbstate_t > >(loc));
}
Expand All @@ -131,33 +132,69 @@ BOOST_LOG_API void code_convert(const char* str1, std::size_t len, std::wstring&
#if !defined(BOOST_NO_CXX11_CHAR16_T)

//! The function converts one string to the character type of another
BOOST_LOG_API void code_convert(const char16_t* str1, std::size_t len, std::string& str2, std::locale const& loc)
BOOST_LOG_API void code_convert_impl(const char16_t* str1, std::size_t len, std::string& str2, std::locale const& loc)
{
code_convert(str1, str1 + len, str2, std::use_facet< std::codecvt< char16_t, char, std::mbstate_t > >(loc));
}

//! The function converts one string to the character type of another
BOOST_LOG_API void code_convert(const char* str1, std::size_t len, std::u16string& str2, std::locale const& loc)
BOOST_LOG_API void code_convert_impl(const char* str1, std::size_t len, std::u16string& str2, std::locale const& loc)
{
code_convert(str1, str1 + len, str2, std::use_facet< std::codecvt< char16_t, char, std::mbstate_t > >(loc));
}

//! The function converts one string to the character type of another
BOOST_LOG_API void code_convert_impl(const char16_t* str1, std::size_t len, std::wstring& str2, std::locale const& loc)
{
std::string temp_str;
code_convert(str1, str1 + len, temp_str, std::use_facet< std::codecvt< char16_t, char, std::mbstate_t > >(loc));
code_convert(temp_str.c_str(), temp_str.c_str() + temp_str.size(), str2, std::use_facet< std::codecvt< wchar_t, char, std::mbstate_t > >(loc));
}

#endif

#if !defined(BOOST_NO_CXX11_CHAR32_T)

//! The function converts one string to the character type of another
BOOST_LOG_API void code_convert(const char32_t* str1, std::size_t len, std::string& str2, std::locale const& loc)
BOOST_LOG_API void code_convert_impl(const char32_t* str1, std::size_t len, std::string& str2, std::locale const& loc)
{
code_convert(str1, str1 + len, str2, std::use_facet< std::codecvt< char32_t, char, std::mbstate_t > >(loc));
}

//! The function converts one string to the character type of another
BOOST_LOG_API void code_convert(const char* str1, std::size_t len, std::u32string& str2, std::locale const& loc)
BOOST_LOG_API void code_convert_impl(const char* str1, std::size_t len, std::u32string& str2, std::locale const& loc)
{
code_convert(str1, str1 + len, str2, std::use_facet< std::codecvt< char32_t, char, std::mbstate_t > >(loc));
}

//! The function converts one string to the character type of another
BOOST_LOG_API void code_convert_impl(const char32_t* str1, std::size_t len, std::wstring& str2, std::locale const& loc)
{
std::string temp_str;
code_convert(str1, str1 + len, temp_str, std::use_facet< std::codecvt< char32_t, char, std::mbstate_t > >(loc));
code_convert(temp_str.c_str(), temp_str.c_str() + temp_str.size(), str2, std::use_facet< std::codecvt< wchar_t, char, std::mbstate_t > >(loc));
}

#endif

#if !defined(BOOST_NO_CXX11_CHAR16_T) && !defined(BOOST_NO_CXX11_CHAR32_T)

//! The function converts one string to the character type of another
BOOST_LOG_API void code_convert_impl(const char16_t* str1, std::size_t len, std::u32string& str2, std::locale const& loc)
{
std::string temp_str;
code_convert(str1, str1 + len, temp_str, std::use_facet< std::codecvt< char16_t, char, std::mbstate_t > >(loc));
code_convert(temp_str.c_str(), temp_str.c_str() + temp_str.size(), str2, std::use_facet< std::codecvt< char32_t, char, std::mbstate_t > >(loc));
}

//! The function converts one string to the character type of another
BOOST_LOG_API void code_convert_impl(const char32_t* str1, std::size_t len, std::u16string& str2, std::locale const& loc)
{
std::string temp_str;
code_convert(str1, str1 + len, temp_str, std::use_facet< std::codecvt< char32_t, char, std::mbstate_t > >(loc));
code_convert(temp_str.c_str(), temp_str.c_str() + temp_str.size(), str2, std::use_facet< std::codecvt< char16_t, char, std::mbstate_t > >(loc));
}

#endif

#endif // !defined(BOOST_MSVC)
Expand Down
11 changes: 5 additions & 6 deletions src/default_filter_factory.cpp
Expand Up @@ -16,8 +16,8 @@
#if !defined(BOOST_LOG_WITHOUT_SETTINGS_PARSERS) && !defined(BOOST_LOG_WITHOUT_DEFAULT_FACTORIES)

#include <string>
#include <boost/mpl/copy.hpp>
#include <boost/mpl/back_inserter.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/preprocessor/seq/enum.hpp>
#include <boost/spirit/include/qi_core.hpp>
#include <boost/log/exceptions.hpp>
#include <boost/log/expressions/predicates/has_attr.hpp>
Expand Down Expand Up @@ -181,10 +181,9 @@ class numeric_predicate :
const numeric_type m_numeric_operand;
};

typedef mpl::copy<
log::string_types,
mpl::back_inserter< log::floating_point_types >
>::type floating_point_and_string_types;
typedef mpl::vector<
BOOST_PP_SEQ_ENUM(BOOST_LOG_STANDARD_FLOATING_POINT_TYPES()BOOST_LOG_STANDARD_STRING_TYPES())
> floating_point_and_string_types;

} // namespace

Expand Down
255 changes: 214 additions & 41 deletions src/default_formatter_factory.cpp
Expand Up @@ -5,7 +5,7 @@
* http://www.boost.org/LICENSE_1_0.txt)
*/
/*!
* \file default_formatter_factory.hpp
* \file default_formatter_factory.cpp
* \author Andrey Semashev
* \date 14.07.2013
*
Expand All @@ -15,25 +15,24 @@

#if !defined(BOOST_LOG_WITHOUT_SETTINGS_PARSERS) && !defined(BOOST_LOG_WITHOUT_DEFAULT_FACTORIES)

#undef BOOST_MPL_LIMIT_VECTOR_SIZE
#define BOOST_MPL_LIMIT_VECTOR_SIZE 50

#include <cstddef>
#include <ctime>
#include <boost/mpl/vector.hpp>
#include <boost/mpl/copy.hpp>
#include <boost/mpl/push_back.hpp>
#include <boost/mpl/back_inserter.hpp>
#include <boost/date_time/gregorian/gregorian.hpp>
#include <boost/date_time/local_time/local_time.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/phoenix/core.hpp>
#include <boost/phoenix/operator.hpp>
#include <boost/log/exceptions.hpp>
#include <boost/log/expressions/attr.hpp>
#include <boost/log/expressions/formatters/stream.hpp>
#include <boost/mpl/vector/vector40.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/seq/enum.hpp>
#include <boost/preprocessor/seq/size.hpp>
#include <boost/date_time/gregorian/gregorian_types.hpp>
#include <boost/date_time/local_time/local_time_types.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/log/attributes/attribute_name.hpp>
#include <boost/log/attributes/value_visitation.hpp>
#include <boost/log/utility/type_dispatch/standard_types.hpp>
#include <boost/log/utility/type_dispatch/date_time_types.hpp>
#include <boost/log/utility/string_literal.hpp>
#include <boost/log/utility/formatting_ostream.hpp>
#include <boost/log/detail/code_conversion.hpp>
#include <boost/log/detail/snprintf.hpp>
#include <boost/log/detail/process_id.hpp>
#if !defined(BOOST_LOG_NO_THREADS)
#include <boost/log/detail/thread_id.hpp>
Expand All @@ -48,38 +47,212 @@ BOOST_LOG_OPEN_NAMESPACE

namespace aux {

#if !defined(BOOST_LOG_NO_THREADS)
#define BOOST_LOG_AUX_THREAD_ID_TYPE() (boost::log::aux::thread::id)
#else
#define BOOST_LOG_AUX_THREAD_ID_TYPE()
#endif

#define BOOST_LOG_AUX_LOG_ATTRIBUTE_VALUE_TYPES()\
(boost::log::attributes::named_scope_list)(boost::log::aux::process::id)BOOST_LOG_AUX_THREAD_ID_TYPE()

// The list of the attribute value types supported by the default formatter. Note that we have to exclude std::time_t
// as it is an integral type, as well as double from the native time duration types - these are part of arithmetic types already.
#define BOOST_LOG_AUX_LOG_DEFAULT_VALUE_TYPES()\
BOOST_LOG_DEFAULT_ATTRIBUTE_VALUE_TYPES()\
(std::tm)\
BOOST_LOG_BOOST_DATE_TYPES()\
BOOST_LOG_BOOST_TIME_DURATION_TYPES()\
BOOST_LOG_BOOST_TIME_PERIOD_TYPES()\
BOOST_LOG_AUX_LOG_ATTRIBUTE_VALUE_TYPES()

BOOST_LOG_ANONYMOUS_NAMESPACE {

//! The default formatter generated by the default formatter factory
template< typename CharT >
class default_formatter
{
public:
typedef void result_type;

private:
//! Attribute value visitor
struct visitor
{
typedef void result_type;

explicit visitor(basic_formatting_ostream< CharT >& strm) : m_strm(strm)
{
}

template< typename T >
void operator() (T const& value) const
{
m_strm << value;
}

void operator() (std::tm const& value) const
{
char buf[32];
std::size_t len = std::strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &value);
m_strm.write(buf, len);
}

void operator() (boost::posix_time::ptime const& value) const
{
if (!value.is_special())
{
std::tm t = boost::posix_time::to_tm(value);
char buf[32];
std::size_t len = std::strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &t);
int res = boost::log::aux::snprintf(buf + len, sizeof(buf) - len, ".%06u", static_cast< unsigned int >(value.time_of_day().total_microseconds() % 1000000));
if (res > 0)
len += res;
m_strm.write(buf, len);
}
else
{
format_special_date_time(value);
}
}

void operator() (boost::local_time::local_date_time const& value) const
{
if (!value.is_special())
{
this->operator()(value.local_time());
m_strm << ' ' << value.zone_as_posix_string();
}
else
{
format_special_date_time(value);
}
}

void operator() (boost::gregorian::date const& value) const
{
if (!value.is_special())
{
std::tm t = boost::gregorian::to_tm(value);
char buf[32];
std::size_t len = std::strftime(buf, sizeof(buf), "%Y-%m-%d", &t);
m_strm.write(buf, len);
}
else
{
format_special_date_time(value.as_special());
}
}

void operator() (boost::posix_time::time_duration const& value) const
{
if (!value.is_special())
{
boost::posix_time::time_duration val = value;
if (val.is_negative())
{
m_strm << '-';
val = -val;
}
unsigned long long total_useconds = value.total_microseconds();
unsigned long long hours = total_useconds / (3600ull * 1000000ull);
unsigned int minutes = total_useconds / (60ull * 1000000ull) % 60ull;
unsigned int seconds = total_useconds / 1000000ull % 60ull;
unsigned int useconds = total_useconds % 1000000ull;
char buf[64];
int len = boost::log::aux::snprintf(buf, sizeof(buf), "%02llu:%02u:%02u.%06u", hours, minutes, seconds, useconds);
if (len > 0)
m_strm.write(buf, len);
}
else
{
format_special_date_time(value);
}
}

void operator() (boost::gregorian::date_duration const& value) const
{
if (!value.is_special())
{
m_strm << value.get_rep().as_number();
}
else
{
format_special_date_time(value.get_rep().as_special());
}
}

template< typename PointRepT, typename DurationRepT >
void operator() (boost::date_time::period< PointRepT, DurationRepT > const& value) const
{
m_strm << '[';
this->operator()(value.begin());
m_strm << '/';
this->operator()(value.last());
m_strm << ']';
}

private:
template< typename T >
void format_special_date_time(T const& value) const
{
if (value.is_not_a_date_time())
m_strm << "not-a-date-time";
else if (value.is_pos_infinity())
m_strm << "+infinity";
else if (value.is_neg_infinity())
m_strm << "-infinity";
}

void format_special_date_time(boost::date_time::special_values value) const
{
switch (value)
{
case boost::date_time::special_values::not_a_date_time:
m_strm << "not-a-date-time";
break;
case boost::date_time::special_values::pos_infin:
m_strm << "+infinity";
break;
case boost::date_time::special_values::neg_infin:
m_strm << "-infinity";
break;
default:
break;
}
}

private:
basic_formatting_ostream< CharT >& m_strm;
};

public:
explicit default_formatter(attribute_name name) : m_attribute_name(name)
{
}

result_type operator() (record_view const& rec, basic_formatting_ostream< CharT >& strm) const
{
typedef BOOST_PP_CAT(mpl::vector, BOOST_PP_SEQ_SIZE(BOOST_LOG_AUX_LOG_DEFAULT_VALUE_TYPES()))<
BOOST_PP_SEQ_ENUM(BOOST_LOG_AUX_LOG_DEFAULT_VALUE_TYPES())
> value_types;

boost::log::visit< value_types >(m_attribute_name, rec, visitor(strm));
}

private:
const attribute_name m_attribute_name;
};

} // namespace

//! The callback for equality relation filter
template< typename CharT >
typename default_formatter_factory< CharT >::formatter_type
default_formatter_factory< CharT >::create_formatter(attribute_name const& name, args_map const& args)
{
// No user-defined factory, shall use the most generic formatter we can ever imagine at this point
typedef mpl::copy<
// We have to exclude std::time_t since it's an integral type and will conflict with one of the standard types
boost_time_period_types,
mpl::back_inserter<
mpl::copy<
boost_time_duration_types,
mpl::back_inserter< boost_date_time_types >
>::type
>
>::type time_related_types;

typedef mpl::copy<
mpl::copy<
mpl::vector<
attributes::named_scope_list,
#if !defined(BOOST_LOG_NO_THREADS)
log::aux::thread::id,
#endif
log::aux::process::id
>,
mpl::back_inserter< time_related_types >
>::type,
mpl::back_inserter< default_attribute_types >
>::type supported_types;

return formatter_type(expressions::stream << expressions::attr< supported_types::type >(name));
return formatter_type(default_formatter< CharT >(name));
}

// Explicitly instantiate factory implementation
Expand Down