Previous 199869 Revisions Next

r45441 Thursday 3rd March, 2016 at 14:04:10 UTC by Vasantha Crabb
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
[src/lib/util]strformat.h

trunk/src/lib/util/strformat.h
r253952r253953
10401040   {
10411041      return (m_end && (m_end == it)) || (m_check_nul && (format_chars<char_type>::nul == *it));
10421042   }
1043   std::size_t size() const
1043   std::size_t argument_count() const
10441044   {
10451045      return m_argument_count;
10461046   }
r253952r253953
11311131   , public format_argument_pack<Stream>
11321132{
11331133public:
1134   using typename format_argument_pack<Stream>::iterator;
1135   using format_argument_pack<Stream>::operator[];
1136
11341137   template <typename Format, typename... Params>
11351138   format_argument_pack_impl(Format &&fmt, Params &&... args)
11361139      : std::array<format_argument<Stream>, Count>({ { format_argument<Stream>(std::forward<Params>(args))... } })
r253952r253953
11471150
11481151
11491152//**************************************************************************
1150//  ARGUMENT PACK CREATOR FUNCTIONS
1153//  ARGUMENT PACK CREATOR FUNCTION
11511154//**************************************************************************
11521155
1153template <typename Stream = std::ostream, typename... Params>
1154inline std::array<format_argument<Stream>, sizeof...(Params)> make_format_arguments(Params &&... args)
1155{
1156   return std::array<format_argument<Stream>, sizeof...(Params)>({ { format_argument<Stream>(std::forward<Params>(args))... } });
1157}
1158
11591156template <typename Stream = std::ostream, typename Format, typename... Params>
11601157inline format_argument_pack_impl<Stream, sizeof...(Params)> make_format_argument_pack(Format &&fmt, Params &&... args)
11611158{
r253952r253953
11641161
11651162
11661163//**************************************************************************
1167//  FORMAT STRING PARSING HELPERS
1164//  FORMAT STRING PARSING HELPER
11681165//**************************************************************************
11691166
11701167template <typename Format>
1171class format_helper_base : public format_chars<std::remove_cv_t<std::remove_reference_t<decltype(*std::cbegin(std::declval<Format>()))> > >
1168class format_helper : public format_chars<typename Format::char_type>
11721169{
11731170public:
1174   typedef std::remove_reference_t<decltype(std::cbegin(std::declval<Format>()))> iterator;
1175   static iterator begin(Format const &fmt) { return std::cbegin(fmt); }
1176   static bool at_end(Format const &fmt, iterator const &it) { return std::cend(fmt) == it; }
1177};
1178
1179template <typename Character>
1180class format_helper_base<Character *> : public format_chars<std::remove_cv_t<Character> >
1181{
1182public:
1183   typedef Character const *iterator;
1184   static iterator begin(Character const *fmt) { return fmt; }
1185   static bool at_end(Character const *fmt, iterator const &it) { return format_helper_base::nul == *it; }
1186};
1187
1188template <typename Character, std::size_t Length>
1189class format_helper_base<Character [Length]> : public format_chars<std::remove_cv_t<Character> >
1190{
1191public:
1192   typedef Character const *iterator;
1193   static iterator begin(std::remove_const_t<Character> (&fmt)[Length]) { return std::cbegin(fmt); }
1194   static iterator begin(std::add_const_t<Character> (&fmt)[Length]) { return std::cbegin(fmt); }
1195   static bool at_end(std::remove_const_t<Character> (&fmt)[Length], iterator const &it) { return (std::cend(fmt) == it) || (format_chars<Character>::nul == *it); }
1196   static bool at_end(std::add_const_t<Character> (&fmt)[Length], iterator const &it) { return (std::cend(fmt) == it) || (format_helper_base::nul == *it); }
1197};
1198
1199template <typename Stream>
1200class format_helper_base<format_argument_pack<Stream> > : public format_chars<typename format_argument_pack<Stream>::char_type>
1201{
1202public:
1203   typedef typename format_argument_pack<Stream>::iterator iterator;
1204   static iterator begin(format_argument_pack<Stream> const &fmt) { return fmt.format_begin(); }
1205   static bool at_end(format_argument_pack<Stream> const &fmt, iterator const &it) { return fmt.format_at_end(it); }
1206};
1207
1208template <typename Format>
1209class format_helper : public format_helper_base<Format>
1210{
1211public:
12121171   static bool parse_format(
12131172         Format const &fmt,
1214         typename format_helper::iterator &it,
1173         typename Format::iterator &it,
12151174         format_flags &flags,
12161175         int &next_position,
12171176         int &argument_position,
r253952r253953
12191178         int &precision_position)
12201179   {
12211180      static_assert((format_helper::nine - format_helper::zero) == 9, "Digits must be contiguous");
1222      assert(!format_helper::at_end(fmt, it));
1181      assert(!fmt.format_at_end(it));
12231182      assert(format_helper::percent == *it);
12241183
12251184      int num;
r253952r253953
12311190      precision_position = -1;
12321191
12331192      // Leading zeroes are tricky - they could be a zero-pad flag or part of a position specifier
1234      bool const leading_zero(!format_helper::at_end(fmt, it) && (format_helper::zero == *it));
1235      while (!format_helper::at_end(fmt, it) && (format_helper::zero == *it)) ++it;
1193      bool const leading_zero(!fmt.format_at_end(it) && (format_helper::zero == *it));
1194      while (!fmt.format_at_end(it) && (format_helper::zero == *it)) ++it;
12361195
12371196      // Digits encountered at this point could be a field width or a position specifier
12381197      num = 0;
r253952r253953
12581217         }
12591218
12601219         // Parse flag characters
1261         while (!format_helper::at_end(fmt, it))
1220         while (!fmt.format_at_end(it))
12621221         {
12631222            switch (*it)
12641223            {
r253952r253953
12751234         }
12761235
12771236         // Check for literal or parameterised field width
1278         if (!format_helper::at_end(fmt, it))
1237         if (!fmt.format_at_end(it))
12791238         {
12801239            if (is_digit(*it))
12811240            {
r253952r253953
13021261      }
13031262
13041263      // Check for literal or parameterised precision
1305      if (!format_helper::at_end(fmt, it) && (*it == format_helper::point))
1264      if (!fmt.format_at_end(it) && (*it == format_helper::point))
13061265      {
13071266         ++it;
13081267         if (have_digit(fmt, it))
13091268         {
13101269            flags.set_precision(read_number(fmt, it));
13111270         }
1312         else if (!format_helper::at_end(fmt, it) && (format_helper::asterisk == *it))
1271         else if (!fmt.format_at_end(it) && (format_helper::asterisk == *it))
13131272         {
13141273            ++it;
13151274            if (have_digit(fmt, it))
r253952r253953
13331292      }
13341293
13351294      // Check for length modifiers
1336      if (!format_helper::at_end(fmt, it)) switch (*it)
1295      if (!fmt.format_at_end(it)) switch (*it)
13371296      {
13381297      case format_helper::h:
13391298         ++it;
1340         if (!format_helper::at_end(fmt, it) && (format_helper::h == *it))
1299         if (!fmt.format_at_end(it) && (format_helper::h == *it))
13411300         {
13421301            ++it;
13431302            flags.set_length(format_flags::length::character);
r253952r253953
13491308         break;
13501309      case format_helper::l:
13511310         ++it;
1352         if (!format_helper::at_end(fmt, it) && (format_helper::l == *it))
1311         if (!fmt.format_at_end(it) && (format_helper::l == *it))
13531312         {
13541313            ++it;
13551314            flags.set_length(format_flags::length::long_long_integer);
r253952r253953
13791338         {
13801339            ++it;
13811340            format_flags::length length = format_flags::length::size_type;
1382            if (!format_helper::at_end(fmt, it))
1341            if (!fmt.format_at_end(it))
13831342            {
13841343               if ((typename format_helper::char_type(format_helper::zero) + 3) == *it)
13851344               {
1386                  typename format_helper::iterator tmp(it);
1345                  typename Format::iterator tmp(it);
13871346                  ++tmp;
1388                  if (!format_helper::at_end(fmt, tmp) && ((typename format_helper::char_type(format_helper::zero) + 2) == *tmp))
1347                  if (!fmt.format_at_end(tmp) && ((typename format_helper::char_type(format_helper::zero) + 2) == *tmp))
13891348                  {
13901349                     length = format_flags::length::integer_32;
13911350                     it = ++tmp;
r253952r253953
13931352               }
13941353               else if ((typename format_helper::char_type(format_helper::zero) + 6) == *it)
13951354               {
1396                  typename format_helper::iterator tmp(it);
1355                  typename Format::iterator tmp(it);
13971356                  ++tmp;
1398                  if (!format_helper::at_end(fmt, tmp) && ((typename format_helper::char_type(format_helper::zero) + 4) == *tmp))
1357                  if (!fmt.format_at_end(tmp) && ((typename format_helper::char_type(format_helper::zero) + 4) == *tmp))
13991358                  {
14001359                     length = format_flags::length::integer_64;
14011360                     it = ++tmp;
r253952r253953
14141373      }
14151374
14161375      // Now we should find a conversion specifier
1417      assert(!format_helper::at_end(fmt, it)); // missing conversion
1418      if (format_helper::at_end(fmt, it)) return false;
1376      assert(!fmt.format_at_end(it)); // missing conversion
1377      if (fmt.format_at_end(it)) return false;
14191378      switch (*it)
14201379      {
14211380      case format_helper::d:
r253952r253953
14981457   }
14991458
15001459private:
1501   static bool have_dollar(Format const &fmt, typename format_helper::iterator const &it)
1460   static bool have_dollar(Format const &fmt, typename Format::iterator const &it)
15021461   {
1503      return !format_helper::at_end(fmt, it) && (*it == format_helper::dollar);
1462      return !fmt.format_at_end(it) && (*it == format_helper::dollar);
15041463   }
15051464
1506   static bool have_digit(Format const &fmt, typename format_helper::iterator const &it)
1465   static bool have_digit(Format const &fmt, typename Format::iterator const &it)
15071466   {
1508      return !format_helper::at_end(fmt, it) && is_digit(*it);
1467      return !fmt.format_at_end(it) && is_digit(*it);
15091468   }
15101469
15111470   static bool is_digit(typename format_helper::char_type value)
r253952r253953
15241483      num = (num * 10) + digit_value(digit);
15251484   }
15261485
1527   static int read_number(Format const &fmt, typename format_helper::iterator &it)
1486   static int read_number(Format const &fmt, typename Format::iterator &it)
15281487   {
15291488      assert(have_digit(fmt, it));
15301489      int value = 0;
r253952r253953
15381497//  CORE FORMATTING FUNCTION
15391498//**************************************************************************
15401499
1541template <typename Stream, typename Format, typename Params>
1542typename Stream::off_type stream_format(Stream &str, Format &&fmt, Params &&args)
1500template <typename Stream, typename Format>
1501typename Stream::off_type stream_format(Stream &str, Format const &args)
15431502{
1544   typedef format_helper<std::remove_cv_t<std::remove_reference_t<Format> > > format_helper;
1545   typedef typename format_helper::iterator iterator;
1503   typedef format_helper<std::remove_cv_t<Format> > format_helper;
1504   typedef typename Format::iterator iterator;
15461505   class stream_preserver
15471506   {
15481507   public:
r253952r253953
15721531   typename Stream::pos_type const begin(str.tellp());
15731532   stream_preserver const preserver(str);
15741533   int next_pos(1);
1575   iterator start = format_helper::begin(fmt);
1576   for (iterator it = start; !format_helper::at_end(fmt, start); )
1534   iterator start = args.format_begin();
1535   for (iterator it = start; !args.format_at_end(start); )
15771536   {
1578      while (!format_helper::at_end(fmt, it) && (format_helper::percent != *it)) ++it;
1537      while (!args.format_at_end(it) && (format_helper::percent != *it)) ++it;
15791538      if (start != it)
15801539      {
15811540         str.write(&*start, it - start);
15821541         start = it;
15831542      }
1584      if (!format_helper::at_end(fmt, it))
1543      if (!args.format_at_end(it))
15851544      {
15861545         // Try to parse a percent format specification
15871546         format_flags flags;
15881547         int arg_pos, width_pos, prec_pos;
1589         if (!format_helper::parse_format(fmt, it, flags, next_pos, arg_pos, width_pos, prec_pos))
1548         if (!format_helper::parse_format(args, it, flags, next_pos, arg_pos, width_pos, prec_pos))
15901549            continue;
15911550
15921551         // Handle parameterised width
r253952r253953
15941553         {
15951554            assert(flags.get_field_width() == 0U);
15961555            assert(0 < width_pos);
1597            assert(args.size() >= unsigned(width_pos));
1598            if ((0 < width_pos) && (args.size() >= unsigned(width_pos)))
1556            assert(args.argument_count() >= unsigned(width_pos));
1557            if ((0 < width_pos) && (args.argument_count() >= unsigned(width_pos)))
15991558            {
16001559               int width;
16011560               if (args[width_pos - 1].make_integer(width))
r253952r253953
16221581         {
16231582            assert(flags.get_precision() < 0);
16241583            assert(0 < prec_pos);
1625            assert(args.size() >= unsigned(prec_pos));
1626            if ((0 < prec_pos) && (args.size() >= unsigned(prec_pos)))
1584            assert(args.argument_count() >= unsigned(prec_pos));
1585            if ((0 < prec_pos) && (args.argument_count() >= unsigned(prec_pos)))
16271586            {
16281587               int precision;
16291588               if (args[prec_pos - 1].make_integer(precision))
r253952r253953
16481607         else
16491608         {
16501609            assert(0 < arg_pos);
1651            assert(args.size() >= unsigned(arg_pos));
1652            if ((0 >= arg_pos) || (args.size() < unsigned(arg_pos)))
1610            assert(args.argument_count() >= unsigned(arg_pos));
1611            if ((0 >= arg_pos) || (args.argument_count() < unsigned(arg_pos)))
16531612               continue;
16541613            if (format_flags::conversion::tell == flags.get_conversion())
16551614            {
r253952r253953
16831642template <typename Stream, typename Format, typename... Params>
16841643inline typename Stream::off_type stream_format(Stream &str, Format const &fmt, Params &&... args)
16851644{
1686   return detail::stream_format(str, fmt, detail::make_format_arguments<Stream>(std::forward<Params>(args)...));
1645   return detail::stream_format(str, detail::make_format_argument_pack<Stream>(fmt, std::forward<Params>(args)...));
16871646}
16881647
16891648template <typename Stream, typename Base>
16901649inline typename Stream::off_type stream_format(Stream &str, detail::format_argument_pack<Base> const &args)
16911650{
1692   return detail::stream_format(str, args, args);
1651   return detail::stream_format(str, args);
16931652}
16941653
16951654template <typename Stream, typename Base>
16961655inline typename Stream::off_type stream_format(Stream &str, detail::format_argument_pack<Base> &&args)
16971656{
1698   return detail::stream_format(str, args, args);
1657   return detail::stream_format(str, args);
16991658}
17001659
17011660


Previous 199869 Revisions Next


© 1997-2024 The MAME Team