Reduce number of formatting template instantiations needed - should reduce compile time and executable size a bit

Small run-time performance penalty shouldn't be a big deal
This commit is contained in:
Vas Crabb 2016-03-03 13:34:23 +11:00
parent 61b531522a
commit 33b77a8722

View File

@ -1040,7 +1040,7 @@ public:
{
return (m_end && (m_end == it)) || (m_check_nul && (format_chars<char_type>::nul == *it));
}
std::size_t size() const
std::size_t argument_count() const
{
return m_argument_count;
}
@ -1131,6 +1131,9 @@ class format_argument_pack_impl
, public format_argument_pack<Stream>
{
public:
using typename format_argument_pack<Stream>::iterator;
using format_argument_pack<Stream>::operator[];
template <typename Format, typename... Params>
format_argument_pack_impl(Format &&fmt, Params &&... args)
: std::array<format_argument<Stream>, Count>({ { format_argument<Stream>(std::forward<Params>(args))... } })
@ -1147,15 +1150,9 @@ public:
//**************************************************************************
// ARGUMENT PACK CREATOR FUNCTIONS
// ARGUMENT PACK CREATOR FUNCTION
//**************************************************************************
template <typename Stream = std::ostream, typename... Params>
inline std::array<format_argument<Stream>, sizeof...(Params)> make_format_arguments(Params &&... args)
{
return std::array<format_argument<Stream>, sizeof...(Params)>({ { format_argument<Stream>(std::forward<Params>(args))... } });
}
template <typename Stream = std::ostream, typename Format, typename... Params>
inline format_argument_pack_impl<Stream, sizeof...(Params)> make_format_argument_pack(Format &&fmt, Params &&... args)
{
@ -1164,54 +1161,16 @@ inline format_argument_pack_impl<Stream, sizeof...(Params)> make_format_argument
//**************************************************************************
// FORMAT STRING PARSING HELPERS
// FORMAT STRING PARSING HELPER
//**************************************************************************
template <typename Format>
class format_helper_base : public format_chars<std::remove_cv_t<std::remove_reference_t<decltype(*std::cbegin(std::declval<Format>()))> > >
{
public:
typedef std::remove_reference_t<decltype(std::cbegin(std::declval<Format>()))> iterator;
static iterator begin(Format const &fmt) { return std::cbegin(fmt); }
static bool at_end(Format const &fmt, iterator const &it) { return std::cend(fmt) == it; }
};
template <typename Character>
class format_helper_base<Character *> : public format_chars<std::remove_cv_t<Character> >
{
public:
typedef Character const *iterator;
static iterator begin(Character const *fmt) { return fmt; }
static bool at_end(Character const *fmt, iterator const &it) { return format_helper_base::nul == *it; }
};
template <typename Character, std::size_t Length>
class format_helper_base<Character [Length]> : public format_chars<std::remove_cv_t<Character> >
{
public:
typedef Character const *iterator;
static iterator begin(std::remove_const_t<Character> (&fmt)[Length]) { return std::cbegin(fmt); }
static iterator begin(std::add_const_t<Character> (&fmt)[Length]) { return std::cbegin(fmt); }
static bool at_end(std::remove_const_t<Character> (&fmt)[Length], iterator const &it) { return (std::cend(fmt) == it) || (format_chars<Character>::nul == *it); }
static bool at_end(std::add_const_t<Character> (&fmt)[Length], iterator const &it) { return (std::cend(fmt) == it) || (format_helper_base::nul == *it); }
};
template <typename Stream>
class format_helper_base<format_argument_pack<Stream> > : public format_chars<typename format_argument_pack<Stream>::char_type>
{
public:
typedef typename format_argument_pack<Stream>::iterator iterator;
static iterator begin(format_argument_pack<Stream> const &fmt) { return fmt.format_begin(); }
static bool at_end(format_argument_pack<Stream> const &fmt, iterator const &it) { return fmt.format_at_end(it); }
};
template <typename Format>
class format_helper : public format_helper_base<Format>
class format_helper : public format_chars<typename Format::char_type>
{
public:
static bool parse_format(
Format const &fmt,
typename format_helper::iterator &it,
typename Format::iterator &it,
format_flags &flags,
int &next_position,
int &argument_position,
@ -1219,7 +1178,7 @@ public:
int &precision_position)
{
static_assert((format_helper::nine - format_helper::zero) == 9, "Digits must be contiguous");
assert(!format_helper::at_end(fmt, it));
assert(!fmt.format_at_end(it));
assert(format_helper::percent == *it);
int num;
@ -1231,8 +1190,8 @@ public:
precision_position = -1;
// Leading zeroes are tricky - they could be a zero-pad flag or part of a position specifier
bool const leading_zero(!format_helper::at_end(fmt, it) && (format_helper::zero == *it));
while (!format_helper::at_end(fmt, it) && (format_helper::zero == *it)) ++it;
bool const leading_zero(!fmt.format_at_end(it) && (format_helper::zero == *it));
while (!fmt.format_at_end(it) && (format_helper::zero == *it)) ++it;
// Digits encountered at this point could be a field width or a position specifier
num = 0;
@ -1258,7 +1217,7 @@ public:
}
// Parse flag characters
while (!format_helper::at_end(fmt, it))
while (!fmt.format_at_end(it))
{
switch (*it)
{
@ -1275,7 +1234,7 @@ public:
}
// Check for literal or parameterised field width
if (!format_helper::at_end(fmt, it))
if (!fmt.format_at_end(it))
{
if (is_digit(*it))
{
@ -1302,14 +1261,14 @@ public:
}
// Check for literal or parameterised precision
if (!format_helper::at_end(fmt, it) && (*it == format_helper::point))
if (!fmt.format_at_end(it) && (*it == format_helper::point))
{
++it;
if (have_digit(fmt, it))
{
flags.set_precision(read_number(fmt, it));
}
else if (!format_helper::at_end(fmt, it) && (format_helper::asterisk == *it))
else if (!fmt.format_at_end(it) && (format_helper::asterisk == *it))
{
++it;
if (have_digit(fmt, it))
@ -1333,11 +1292,11 @@ public:
}
// Check for length modifiers
if (!format_helper::at_end(fmt, it)) switch (*it)
if (!fmt.format_at_end(it)) switch (*it)
{
case format_helper::h:
++it;
if (!format_helper::at_end(fmt, it) && (format_helper::h == *it))
if (!fmt.format_at_end(it) && (format_helper::h == *it))
{
++it;
flags.set_length(format_flags::length::character);
@ -1349,7 +1308,7 @@ public:
break;
case format_helper::l:
++it;
if (!format_helper::at_end(fmt, it) && (format_helper::l == *it))
if (!fmt.format_at_end(it) && (format_helper::l == *it))
{
++it;
flags.set_length(format_flags::length::long_long_integer);
@ -1379,13 +1338,13 @@ public:
{
++it;
format_flags::length length = format_flags::length::size_type;
if (!format_helper::at_end(fmt, it))
if (!fmt.format_at_end(it))
{
if ((typename format_helper::char_type(format_helper::zero) + 3) == *it)
{
typename format_helper::iterator tmp(it);
typename Format::iterator tmp(it);
++tmp;
if (!format_helper::at_end(fmt, tmp) && ((typename format_helper::char_type(format_helper::zero) + 2) == *tmp))
if (!fmt.format_at_end(tmp) && ((typename format_helper::char_type(format_helper::zero) + 2) == *tmp))
{
length = format_flags::length::integer_32;
it = ++tmp;
@ -1393,9 +1352,9 @@ public:
}
else if ((typename format_helper::char_type(format_helper::zero) + 6) == *it)
{
typename format_helper::iterator tmp(it);
typename Format::iterator tmp(it);
++tmp;
if (!format_helper::at_end(fmt, tmp) && ((typename format_helper::char_type(format_helper::zero) + 4) == *tmp))
if (!fmt.format_at_end(tmp) && ((typename format_helper::char_type(format_helper::zero) + 4) == *tmp))
{
length = format_flags::length::integer_64;
it = ++tmp;
@ -1414,8 +1373,8 @@ public:
}
// Now we should find a conversion specifier
assert(!format_helper::at_end(fmt, it)); // missing conversion
if (format_helper::at_end(fmt, it)) return false;
assert(!fmt.format_at_end(it)); // missing conversion
if (fmt.format_at_end(it)) return false;
switch (*it)
{
case format_helper::d:
@ -1498,14 +1457,14 @@ public:
}
private:
static bool have_dollar(Format const &fmt, typename format_helper::iterator const &it)
static bool have_dollar(Format const &fmt, typename Format::iterator const &it)
{
return !format_helper::at_end(fmt, it) && (*it == format_helper::dollar);
return !fmt.format_at_end(it) && (*it == format_helper::dollar);
}
static bool have_digit(Format const &fmt, typename format_helper::iterator const &it)
static bool have_digit(Format const &fmt, typename Format::iterator const &it)
{
return !format_helper::at_end(fmt, it) && is_digit(*it);
return !fmt.format_at_end(it) && is_digit(*it);
}
static bool is_digit(typename format_helper::char_type value)
@ -1524,7 +1483,7 @@ private:
num = (num * 10) + digit_value(digit);
}
static int read_number(Format const &fmt, typename format_helper::iterator &it)
static int read_number(Format const &fmt, typename Format::iterator &it)
{
assert(have_digit(fmt, it));
int value = 0;
@ -1538,11 +1497,11 @@ private:
// CORE FORMATTING FUNCTION
//**************************************************************************
template <typename Stream, typename Format, typename Params>
typename Stream::off_type stream_format(Stream &str, Format &&fmt, Params &&args)
template <typename Stream, typename Format>
typename Stream::off_type stream_format(Stream &str, Format const &args)
{
typedef format_helper<std::remove_cv_t<std::remove_reference_t<Format> > > format_helper;
typedef typename format_helper::iterator iterator;
typedef format_helper<std::remove_cv_t<Format> > format_helper;
typedef typename Format::iterator iterator;
class stream_preserver
{
public:
@ -1572,21 +1531,21 @@ typename Stream::off_type stream_format(Stream &str, Format &&fmt, Params &&args
typename Stream::pos_type const begin(str.tellp());
stream_preserver const preserver(str);
int next_pos(1);
iterator start = format_helper::begin(fmt);
for (iterator it = start; !format_helper::at_end(fmt, start); )
iterator start = args.format_begin();
for (iterator it = start; !args.format_at_end(start); )
{
while (!format_helper::at_end(fmt, it) && (format_helper::percent != *it)) ++it;
while (!args.format_at_end(it) && (format_helper::percent != *it)) ++it;
if (start != it)
{
str.write(&*start, it - start);
start = it;
}
if (!format_helper::at_end(fmt, it))
if (!args.format_at_end(it))
{
// Try to parse a percent format specification
format_flags flags;
int arg_pos, width_pos, prec_pos;
if (!format_helper::parse_format(fmt, it, flags, next_pos, arg_pos, width_pos, prec_pos))
if (!format_helper::parse_format(args, it, flags, next_pos, arg_pos, width_pos, prec_pos))
continue;
// Handle parameterised width
@ -1594,8 +1553,8 @@ typename Stream::off_type stream_format(Stream &str, Format &&fmt, Params &&args
{
assert(flags.get_field_width() == 0U);
assert(0 < width_pos);
assert(args.size() >= unsigned(width_pos));
if ((0 < width_pos) && (args.size() >= unsigned(width_pos)))
assert(args.argument_count() >= unsigned(width_pos));
if ((0 < width_pos) && (args.argument_count() >= unsigned(width_pos)))
{
int width;
if (args[width_pos - 1].make_integer(width))
@ -1622,8 +1581,8 @@ typename Stream::off_type stream_format(Stream &str, Format &&fmt, Params &&args
{
assert(flags.get_precision() < 0);
assert(0 < prec_pos);
assert(args.size() >= unsigned(prec_pos));
if ((0 < prec_pos) && (args.size() >= unsigned(prec_pos)))
assert(args.argument_count() >= unsigned(prec_pos));
if ((0 < prec_pos) && (args.argument_count() >= unsigned(prec_pos)))
{
int precision;
if (args[prec_pos - 1].make_integer(precision))
@ -1648,8 +1607,8 @@ typename Stream::off_type stream_format(Stream &str, Format &&fmt, Params &&args
else
{
assert(0 < arg_pos);
assert(args.size() >= unsigned(arg_pos));
if ((0 >= arg_pos) || (args.size() < unsigned(arg_pos)))
assert(args.argument_count() >= unsigned(arg_pos));
if ((0 >= arg_pos) || (args.argument_count() < unsigned(arg_pos)))
continue;
if (format_flags::conversion::tell == flags.get_conversion())
{
@ -1683,19 +1642,19 @@ typename Stream::off_type stream_format(Stream &str, Format &&fmt, Params &&args
template <typename Stream, typename Format, typename... Params>
inline typename Stream::off_type stream_format(Stream &str, Format const &fmt, Params &&... args)
{
return detail::stream_format(str, fmt, detail::make_format_arguments<Stream>(std::forward<Params>(args)...));
return detail::stream_format(str, detail::make_format_argument_pack<Stream>(fmt, std::forward<Params>(args)...));
}
template <typename Stream, typename Base>
inline typename Stream::off_type stream_format(Stream &str, detail::format_argument_pack<Base> const &args)
{
return detail::stream_format(str, args, args);
return detail::stream_format(str, args);
}
template <typename Stream, typename Base>
inline typename Stream::off_type stream_format(Stream &str, detail::format_argument_pack<Base> &&args)
{
return detail::stream_format(str, args, args);
return detail::stream_format(str, args);
}