mirror of
https://github.com/holub/mame
synced 2025-04-23 17:00:53 +03:00
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:
parent
61b531522a
commit
33b77a8722
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user