@@ -610,6 +610,7 @@ using wformat_parse_context = basic_format_parse_context<wchar_t>;
610
610
611
611
template <typename Context> class basic_format_arg ;
612
612
template <typename Context> class basic_format_args ;
613
+ template <typename Context> class dynamic_format_arg_store ;
613
614
614
615
// A formatter for objects of type T.
615
616
template <typename T, typename Char = char , typename Enable = void >
@@ -1111,6 +1112,7 @@ template <typename Context> class basic_format_arg {
1111
1112
1112
1113
friend class basic_format_args <Context>;
1113
1114
friend class internal ::arg_map<Context>;
1115
+ friend class dynamic_format_arg_store <Context>;
1114
1116
1115
1117
using char_type = typename Context::char_type;
1116
1118
@@ -1252,10 +1254,14 @@ inline basic_format_arg<Context> make_arg(const T& value) {
1252
1254
}
1253
1255
1254
1256
template <typename T> struct is_reference_wrapper : std::false_type {};
1255
-
1256
1257
template <typename T>
1257
1258
struct is_reference_wrapper <std::reference_wrapper<T>> : std::true_type {};
1258
1259
1260
+ template <typename T> const T& unwrap (const T& v) { return v; }
1261
+ template <typename T> const T& unwrap (const std::reference_wrapper<T>& v) {
1262
+ return static_cast <const T&>(v);
1263
+ }
1264
+
1259
1265
class dynamic_arg_list {
1260
1266
// Workaround for clang's -Wweak-vtables. Unlike for regular classes, for
1261
1267
// templates it doesn't complain about inability to deduce single translation
@@ -1404,6 +1410,50 @@ inline format_arg_store<Context, Args...> make_format_args(
1404
1410
return {args...};
1405
1411
}
1406
1412
1413
+ namespace internal {
1414
+ template <typename Char> struct named_arg_base {
1415
+ const Char* name;
1416
+
1417
+ // Serialized value<context>.
1418
+ mutable char data[sizeof (basic_format_arg<buffer_context<Char>>)];
1419
+
1420
+ named_arg_base (const Char* nm) : name(nm) {}
1421
+
1422
+ template <typename Context> basic_format_arg<Context> deserialize () const {
1423
+ basic_format_arg<Context> arg;
1424
+ std::memcpy (&arg, data, sizeof (basic_format_arg<Context>));
1425
+ return arg;
1426
+ }
1427
+ };
1428
+
1429
+ struct view {};
1430
+
1431
+ template <typename T, typename Char>
1432
+ struct named_arg : view, named_arg_base<Char> {
1433
+ const T& value;
1434
+
1435
+ named_arg (const Char* name, const T& val)
1436
+ : named_arg_base<Char>(name), value(val) {}
1437
+ };
1438
+
1439
+ } // namespace internal
1440
+
1441
+ /* *
1442
+ \rst
1443
+ Returns a named argument to be used in a formatting function. It should only
1444
+ be used in a call to a formatting function.
1445
+
1446
+ **Example**::
1447
+
1448
+ fmt::print("Elapsed time: {s:.2f} seconds", fmt::arg("s", 1.23));
1449
+ \endrst
1450
+ */
1451
+ template <typename Char, typename T>
1452
+ inline internal::named_arg<T, Char> arg (const Char* name, const T& arg) {
1453
+ static_assert (!internal::is_named_arg<T>(), " nested named arguments" );
1454
+ return {name, arg};
1455
+ }
1456
+
1407
1457
/* *
1408
1458
\rst
1409
1459
A dynamic version of `fmt::format_arg_store<>`.
@@ -1434,8 +1484,7 @@ class dynamic_format_arg_store
1434
1484
std::is_same<T, internal::std_string_view<char_type>>::value ||
1435
1485
(mapped_type != internal::type::cstring_type &&
1436
1486
mapped_type != internal::type::string_type &&
1437
- mapped_type != internal::type::custom_type &&
1438
- mapped_type != internal::type::named_arg_type))
1487
+ mapped_type != internal::type::custom_type))
1439
1488
};
1440
1489
};
1441
1490
@@ -1445,6 +1494,7 @@ class dynamic_format_arg_store
1445
1494
1446
1495
// Storage of basic_format_arg must be contiguous.
1447
1496
std::vector<basic_format_arg<Context>> data_;
1497
+ std::vector<internal::named_arg_info<char_type>> named_info_;
1448
1498
1449
1499
// Storage of arguments not fitting into basic_format_arg must grow
1450
1500
// without relocation because items in data_ refer to it.
@@ -1453,13 +1503,38 @@ class dynamic_format_arg_store
1453
1503
friend class basic_format_args <Context>;
1454
1504
1455
1505
unsigned long long get_types () const {
1456
- return internal::is_unpacked_bit | data_.size ();
1506
+ return internal::is_unpacked_bit | data_.size () |
1507
+ (named_info_.empty () ? 0ULL
1508
+ : static_cast <unsigned long long >(
1509
+ internal::has_named_args_bit));
1510
+ }
1511
+
1512
+ const basic_format_arg<Context>* data () const {
1513
+ return named_info_.empty () ? data_.data () : data_.data () + 1 ;
1457
1514
}
1458
1515
1459
1516
template <typename T> void emplace_arg (const T& arg) {
1460
1517
data_.emplace_back (internal::make_arg<Context>(arg));
1461
1518
}
1462
1519
1520
+ template <typename T>
1521
+ void emplace_arg (const internal::named_arg<T, char_type>& arg) {
1522
+ if (named_info_.empty ()) {
1523
+ constexpr const internal::named_arg_info<char_type>* zero_ptr{nullptr };
1524
+ data_.insert (data_.begin (), {zero_ptr, 0 });
1525
+ }
1526
+ data_.emplace_back (
1527
+ internal::make_arg<Context>(internal::unwrap (arg.value )));
1528
+ auto pop_one = [](std::vector<basic_format_arg<Context>>* data) {
1529
+ data->pop_back ();
1530
+ };
1531
+ std::unique_ptr<std::vector<basic_format_arg<Context>>, decltype (pop_one)>
1532
+ guard{&data_, pop_one};
1533
+ named_info_.push_back ({arg.name , static_cast <int >(data_.size () - 2u )});
1534
+ data_[0 ].value_ .named_args = {named_info_.data (), named_info_.size ()};
1535
+ guard.release ();
1536
+ }
1537
+
1463
1538
public:
1464
1539
/* *
1465
1540
\rst
@@ -1485,19 +1560,54 @@ class dynamic_format_arg_store
1485
1560
if (internal::const_check (need_copy<T>::value))
1486
1561
emplace_arg (dynamic_args_.push <stored_type<T>>(arg));
1487
1562
else
1488
- emplace_arg (arg);
1563
+ emplace_arg (internal::unwrap ( arg) );
1489
1564
}
1490
1565
1491
1566
/* *
1567
+ \rst
1492
1568
Adds a reference to the argument into the dynamic store for later passing to
1493
- a formating function.
1569
+ a formating function. Supports named arguments wrapped in
1570
+ std::reference_wrapper (via std::ref()/std::cref()).
1571
+
1572
+ **Example**::
1573
+ fmt::dynamic_format_arg_store<fmt::format_context> store;
1574
+ char str[] = "1234567890";
1575
+ store.push_back(std::cref(str));
1576
+ int a1_val{42};
1577
+ auto a1 = fmt::arg("a1_", a1_val);
1578
+ store.push_back(std::cref(a1));
1579
+
1580
+ // Changing str affects the output but only for string and custom types.
1581
+ str[0] = 'X';
1582
+
1583
+ std::string result = fmt::vformat("{} and {a1_}");
1584
+ assert(result == "X234567890 and 42");
1585
+ \endrst
1494
1586
*/
1495
1587
template <typename T> void push_back (std::reference_wrapper<T> arg) {
1496
1588
static_assert (
1497
- need_copy<T>::value,
1589
+ internal::is_named_arg<typename std::remove_cv<T>::type>::value ||
1590
+ need_copy<T>::value,
1498
1591
" objects of built-in types and string views are always copied" );
1499
1592
emplace_arg (arg.get ());
1500
1593
}
1594
+
1595
+ /* *
1596
+ Adds named argument into the dynamic store for later passing to a formating
1597
+ function. std::reference_wrapper is supported to avoid copying of the
1598
+ argument.
1599
+ */
1600
+ template <typename T>
1601
+ void push_back (const internal::named_arg<T, char_type>& arg) {
1602
+ const char_type* arg_name =
1603
+ dynamic_args_.push <std::basic_string<char_type>>(arg.name ).c_str ();
1604
+ if (internal::const_check (need_copy<T>::value)) {
1605
+ emplace_arg (
1606
+ fmt::arg (arg_name, dynamic_args_.push <stored_type<T>>(arg.value )));
1607
+ } else {
1608
+ emplace_arg (fmt::arg (arg_name, arg.value ));
1609
+ }
1610
+ }
1501
1611
};
1502
1612
1503
1613
/* *
@@ -1582,7 +1692,7 @@ template <typename Context> class basic_format_args {
1582
1692
\endrst
1583
1693
*/
1584
1694
FMT_INLINE basic_format_args (const dynamic_format_arg_store<Context>& store)
1585
- : basic_format_args(store.get_types(), store.data_. data()) {}
1695
+ : basic_format_args(store.get_types(), store.data()) {}
1586
1696
1587
1697
/* *
1588
1698
\rst
@@ -1644,31 +1754,6 @@ template <typename Container>
1644
1754
struct is_contiguous_back_insert_iterator <std::back_insert_iterator<Container>>
1645
1755
: is_contiguous<Container> {};
1646
1756
1647
- template <typename Char> struct named_arg_base {
1648
- const Char* name;
1649
-
1650
- // Serialized value<context>.
1651
- mutable char data[sizeof (basic_format_arg<buffer_context<Char>>)];
1652
-
1653
- named_arg_base (const Char* nm) : name(nm) {}
1654
-
1655
- template <typename Context> basic_format_arg<Context> deserialize () const {
1656
- basic_format_arg<Context> arg;
1657
- std::memcpy (&arg, data, sizeof (basic_format_arg<Context>));
1658
- return arg;
1659
- }
1660
- };
1661
-
1662
- struct view {};
1663
-
1664
- template <typename T, typename Char>
1665
- struct named_arg : view, named_arg_base<Char> {
1666
- const T& value;
1667
-
1668
- named_arg (const Char* name, const T& val)
1669
- : named_arg_base<Char>(name), value(val) {}
1670
- };
1671
-
1672
1757
// Reports a compile-time error if S is not a valid format string.
1673
1758
template <typename ..., typename S, FMT_ENABLE_IF(!is_compile_string<S>::value)>
1674
1759
FMT_INLINE void check_format_string (const S&) {
@@ -1712,22 +1797,6 @@ inline void vprint_mojibake(std::FILE*, string_view, format_args) {}
1712
1797
#endif
1713
1798
} // namespace internal
1714
1799
1715
- /* *
1716
- \rst
1717
- Returns a named argument to be used in a formatting function. It should only
1718
- be used in a call to a formatting function.
1719
-
1720
- **Example**::
1721
-
1722
- fmt::print("Elapsed time: {s:.2f} seconds", fmt::arg("s", 1.23));
1723
- \endrst
1724
- */
1725
- template <typename Char, typename T>
1726
- inline internal::named_arg<T, Char> arg (const Char* name, const T& arg) {
1727
- static_assert (!internal::is_named_arg<T>(), " nested named arguments" );
1728
- return {name, arg};
1729
- }
1730
-
1731
1800
/* * Formats a string and writes the output to ``out``. */
1732
1801
// GCC 8 and earlier cannot handle std::back_insert_iterator<Container> with
1733
1802
// vformat_to<ArgFormatter>(...) overload, so SFINAE on iterator type instead.
0 commit comments