trunk/src/lib/util/strformat.h
| r253952 | r253953 | |
| 1040 | 1040 | { |
| 1041 | 1041 | return (m_end && (m_end == it)) || (m_check_nul && (format_chars<char_type>::nul == *it)); |
| 1042 | 1042 | } |
| 1043 | | std::size_t size() const |
| 1043 | std::size_t argument_count() const |
| 1044 | 1044 | { |
| 1045 | 1045 | return m_argument_count; |
| 1046 | 1046 | } |
| r253952 | r253953 | |
| 1131 | 1131 | , public format_argument_pack<Stream> |
| 1132 | 1132 | { |
| 1133 | 1133 | public: |
| 1134 | using typename format_argument_pack<Stream>::iterator; |
| 1135 | using format_argument_pack<Stream>::operator[]; |
| 1136 | |
| 1134 | 1137 | template <typename Format, typename... Params> |
| 1135 | 1138 | format_argument_pack_impl(Format &&fmt, Params &&... args) |
| 1136 | 1139 | : std::array<format_argument<Stream>, Count>({ { format_argument<Stream>(std::forward<Params>(args))... } }) |
| r253952 | r253953 | |
| 1147 | 1150 | |
| 1148 | 1151 | |
| 1149 | 1152 | //************************************************************************** |
| 1150 | | // ARGUMENT PACK CREATOR FUNCTIONS |
| 1153 | // ARGUMENT PACK CREATOR FUNCTION |
| 1151 | 1154 | //************************************************************************** |
| 1152 | 1155 | |
| 1153 | | template <typename Stream = std::ostream, typename... Params> |
| 1154 | | inline 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 | | |
| 1159 | 1156 | template <typename Stream = std::ostream, typename Format, typename... Params> |
| 1160 | 1157 | inline format_argument_pack_impl<Stream, sizeof...(Params)> make_format_argument_pack(Format &&fmt, Params &&... args) |
| 1161 | 1158 | { |
| r253952 | r253953 | |
| 1164 | 1161 | |
| 1165 | 1162 | |
| 1166 | 1163 | //************************************************************************** |
| 1167 | | // FORMAT STRING PARSING HELPERS |
| 1164 | // FORMAT STRING PARSING HELPER |
| 1168 | 1165 | //************************************************************************** |
| 1169 | 1166 | |
| 1170 | 1167 | template <typename Format> |
| 1171 | | class format_helper_base : public format_chars<std::remove_cv_t<std::remove_reference_t<decltype(*std::cbegin(std::declval<Format>()))> > > |
| 1168 | class format_helper : public format_chars<typename Format::char_type> |
| 1172 | 1169 | { |
| 1173 | 1170 | public: |
| 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 | | |
| 1179 | | template <typename Character> |
| 1180 | | class format_helper_base<Character *> : public format_chars<std::remove_cv_t<Character> > |
| 1181 | | { |
| 1182 | | public: |
| 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 | | |
| 1188 | | template <typename Character, std::size_t Length> |
| 1189 | | class format_helper_base<Character [Length]> : public format_chars<std::remove_cv_t<Character> > |
| 1190 | | { |
| 1191 | | public: |
| 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 | | |
| 1199 | | template <typename Stream> |
| 1200 | | class format_helper_base<format_argument_pack<Stream> > : public format_chars<typename format_argument_pack<Stream>::char_type> |
| 1201 | | { |
| 1202 | | public: |
| 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 | | |
| 1208 | | template <typename Format> |
| 1209 | | class format_helper : public format_helper_base<Format> |
| 1210 | | { |
| 1211 | | public: |
| 1212 | 1171 | static bool parse_format( |
| 1213 | 1172 | Format const &fmt, |
| 1214 | | typename format_helper::iterator &it, |
| 1173 | typename Format::iterator &it, |
| 1215 | 1174 | format_flags &flags, |
| 1216 | 1175 | int &next_position, |
| 1217 | 1176 | int &argument_position, |
| r253952 | r253953 | |
| 1219 | 1178 | int &precision_position) |
| 1220 | 1179 | { |
| 1221 | 1180 | 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)); |
| 1223 | 1182 | assert(format_helper::percent == *it); |
| 1224 | 1183 | |
| 1225 | 1184 | int num; |
| r253952 | r253953 | |
| 1231 | 1190 | precision_position = -1; |
| 1232 | 1191 | |
| 1233 | 1192 | // 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; |
| 1236 | 1195 | |
| 1237 | 1196 | // Digits encountered at this point could be a field width or a position specifier |
| 1238 | 1197 | num = 0; |
| r253952 | r253953 | |
| 1258 | 1217 | } |
| 1259 | 1218 | |
| 1260 | 1219 | // Parse flag characters |
| 1261 | | while (!format_helper::at_end(fmt, it)) |
| 1220 | while (!fmt.format_at_end(it)) |
| 1262 | 1221 | { |
| 1263 | 1222 | switch (*it) |
| 1264 | 1223 | { |
| r253952 | r253953 | |
| 1275 | 1234 | } |
| 1276 | 1235 | |
| 1277 | 1236 | // Check for literal or parameterised field width |
| 1278 | | if (!format_helper::at_end(fmt, it)) |
| 1237 | if (!fmt.format_at_end(it)) |
| 1279 | 1238 | { |
| 1280 | 1239 | if (is_digit(*it)) |
| 1281 | 1240 | { |
| r253952 | r253953 | |
| 1302 | 1261 | } |
| 1303 | 1262 | |
| 1304 | 1263 | // 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)) |
| 1306 | 1265 | { |
| 1307 | 1266 | ++it; |
| 1308 | 1267 | if (have_digit(fmt, it)) |
| 1309 | 1268 | { |
| 1310 | 1269 | flags.set_precision(read_number(fmt, it)); |
| 1311 | 1270 | } |
| 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)) |
| 1313 | 1272 | { |
| 1314 | 1273 | ++it; |
| 1315 | 1274 | if (have_digit(fmt, it)) |
| r253952 | r253953 | |
| 1333 | 1292 | } |
| 1334 | 1293 | |
| 1335 | 1294 | // Check for length modifiers |
| 1336 | | if (!format_helper::at_end(fmt, it)) switch (*it) |
| 1295 | if (!fmt.format_at_end(it)) switch (*it) |
| 1337 | 1296 | { |
| 1338 | 1297 | case format_helper::h: |
| 1339 | 1298 | ++it; |
| 1340 | | if (!format_helper::at_end(fmt, it) && (format_helper::h == *it)) |
| 1299 | if (!fmt.format_at_end(it) && (format_helper::h == *it)) |
| 1341 | 1300 | { |
| 1342 | 1301 | ++it; |
| 1343 | 1302 | flags.set_length(format_flags::length::character); |
| r253952 | r253953 | |
| 1349 | 1308 | break; |
| 1350 | 1309 | case format_helper::l: |
| 1351 | 1310 | ++it; |
| 1352 | | if (!format_helper::at_end(fmt, it) && (format_helper::l == *it)) |
| 1311 | if (!fmt.format_at_end(it) && (format_helper::l == *it)) |
| 1353 | 1312 | { |
| 1354 | 1313 | ++it; |
| 1355 | 1314 | flags.set_length(format_flags::length::long_long_integer); |
| r253952 | r253953 | |
| 1379 | 1338 | { |
| 1380 | 1339 | ++it; |
| 1381 | 1340 | format_flags::length length = format_flags::length::size_type; |
| 1382 | | if (!format_helper::at_end(fmt, it)) |
| 1341 | if (!fmt.format_at_end(it)) |
| 1383 | 1342 | { |
| 1384 | 1343 | if ((typename format_helper::char_type(format_helper::zero) + 3) == *it) |
| 1385 | 1344 | { |
| 1386 | | typename format_helper::iterator tmp(it); |
| 1345 | typename Format::iterator tmp(it); |
| 1387 | 1346 | ++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)) |
| 1389 | 1348 | { |
| 1390 | 1349 | length = format_flags::length::integer_32; |
| 1391 | 1350 | it = ++tmp; |
| r253952 | r253953 | |
| 1393 | 1352 | } |
| 1394 | 1353 | else if ((typename format_helper::char_type(format_helper::zero) + 6) == *it) |
| 1395 | 1354 | { |
| 1396 | | typename format_helper::iterator tmp(it); |
| 1355 | typename Format::iterator tmp(it); |
| 1397 | 1356 | ++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)) |
| 1399 | 1358 | { |
| 1400 | 1359 | length = format_flags::length::integer_64; |
| 1401 | 1360 | it = ++tmp; |
| r253952 | r253953 | |
| 1414 | 1373 | } |
| 1415 | 1374 | |
| 1416 | 1375 | // 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; |
| 1419 | 1378 | switch (*it) |
| 1420 | 1379 | { |
| 1421 | 1380 | case format_helper::d: |
| r253952 | r253953 | |
| 1498 | 1457 | } |
| 1499 | 1458 | |
| 1500 | 1459 | private: |
| 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) |
| 1502 | 1461 | { |
| 1503 | | return !format_helper::at_end(fmt, it) && (*it == format_helper::dollar); |
| 1462 | return !fmt.format_at_end(it) && (*it == format_helper::dollar); |
| 1504 | 1463 | } |
| 1505 | 1464 | |
| 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) |
| 1507 | 1466 | { |
| 1508 | | return !format_helper::at_end(fmt, it) && is_digit(*it); |
| 1467 | return !fmt.format_at_end(it) && is_digit(*it); |
| 1509 | 1468 | } |
| 1510 | 1469 | |
| 1511 | 1470 | static bool is_digit(typename format_helper::char_type value) |
| r253952 | r253953 | |
| 1524 | 1483 | num = (num * 10) + digit_value(digit); |
| 1525 | 1484 | } |
| 1526 | 1485 | |
| 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) |
| 1528 | 1487 | { |
| 1529 | 1488 | assert(have_digit(fmt, it)); |
| 1530 | 1489 | int value = 0; |
| r253952 | r253953 | |
| 1538 | 1497 | // CORE FORMATTING FUNCTION |
| 1539 | 1498 | //************************************************************************** |
| 1540 | 1499 | |
| 1541 | | template <typename Stream, typename Format, typename Params> |
| 1542 | | typename Stream::off_type stream_format(Stream &str, Format &&fmt, Params &&args) |
| 1500 | template <typename Stream, typename Format> |
| 1501 | typename Stream::off_type stream_format(Stream &str, Format const &args) |
| 1543 | 1502 | { |
| 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; |
| 1546 | 1505 | class stream_preserver |
| 1547 | 1506 | { |
| 1548 | 1507 | public: |
| r253952 | r253953 | |
| 1572 | 1531 | typename Stream::pos_type const begin(str.tellp()); |
| 1573 | 1532 | stream_preserver const preserver(str); |
| 1574 | 1533 | 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); ) |
| 1577 | 1536 | { |
| 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; |
| 1579 | 1538 | if (start != it) |
| 1580 | 1539 | { |
| 1581 | 1540 | str.write(&*start, it - start); |
| 1582 | 1541 | start = it; |
| 1583 | 1542 | } |
| 1584 | | if (!format_helper::at_end(fmt, it)) |
| 1543 | if (!args.format_at_end(it)) |
| 1585 | 1544 | { |
| 1586 | 1545 | // Try to parse a percent format specification |
| 1587 | 1546 | format_flags flags; |
| 1588 | 1547 | 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)) |
| 1590 | 1549 | continue; |
| 1591 | 1550 | |
| 1592 | 1551 | // Handle parameterised width |
| r253952 | r253953 | |
| 1594 | 1553 | { |
| 1595 | 1554 | assert(flags.get_field_width() == 0U); |
| 1596 | 1555 | 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))) |
| 1599 | 1558 | { |
| 1600 | 1559 | int width; |
| 1601 | 1560 | if (args[width_pos - 1].make_integer(width)) |
| r253952 | r253953 | |
| 1622 | 1581 | { |
| 1623 | 1582 | assert(flags.get_precision() < 0); |
| 1624 | 1583 | 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))) |
| 1627 | 1586 | { |
| 1628 | 1587 | int precision; |
| 1629 | 1588 | if (args[prec_pos - 1].make_integer(precision)) |
| r253952 | r253953 | |
| 1648 | 1607 | else |
| 1649 | 1608 | { |
| 1650 | 1609 | 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))) |
| 1653 | 1612 | continue; |
| 1654 | 1613 | if (format_flags::conversion::tell == flags.get_conversion()) |
| 1655 | 1614 | { |
| r253952 | r253953 | |
| 1683 | 1642 | template <typename Stream, typename Format, typename... Params> |
| 1684 | 1643 | inline typename Stream::off_type stream_format(Stream &str, Format const &fmt, Params &&... args) |
| 1685 | 1644 | { |
| 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)...)); |
| 1687 | 1646 | } |
| 1688 | 1647 | |
| 1689 | 1648 | template <typename Stream, typename Base> |
| 1690 | 1649 | inline typename Stream::off_type stream_format(Stream &str, detail::format_argument_pack<Base> const &args) |
| 1691 | 1650 | { |
| 1692 | | return detail::stream_format(str, args, args); |
| 1651 | return detail::stream_format(str, args); |
| 1693 | 1652 | } |
| 1694 | 1653 | |
| 1695 | 1654 | template <typename Stream, typename Base> |
| 1696 | 1655 | inline typename Stream::off_type stream_format(Stream &str, detail::format_argument_pack<Base> &&args) |
| 1697 | 1656 | { |
| 1698 | | return detail::stream_format(str, args, args); |
| 1657 | return detail::stream_format(str, args); |
| 1699 | 1658 | } |
| 1700 | 1659 | |
| 1701 | 1660 | |