Skip to content

Commit 9f0bb26

Browse files
committed
Update formatter() with improved recursive converter
1 parent 576461c commit 9f0bb26

2 files changed

Lines changed: 27 additions & 81 deletions

File tree

ChangeLog

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
2026-04-29 Dirk Eddelbuettel <edd@debian.org>
2+
3+
* src/formatter.cpp: Rewritten using recursive 'vector to args...'
4+
15
2026-03-25 Dirk Eddelbuettel <edd@debian.org>
26

37
* .github/workflows/ci.yaml (jobs): r-ci default version can use rapt

src/formatter.cpp

Lines changed: 23 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,29 @@
33

44
#include <RcppSpdlog>
55

6-
// we accommodate C++20 where fmt::format is available as std::format
7-
// this defines a helper function used below
8-
#if defined(SPDLOG_USE_STD_FORMAT) && __cplusplus >= 202002L
6+
constexpr int max_args = 15; // Arbitrary but 'smallish'
97

10-
template<std::size_t... S>
11-
std::format_args unpack_vector(const std::vector<std::string>& vec, std::index_sequence<S...>) {
12-
return std::make_format_args(vec[S]...);
8+
template<class... Args>
9+
std::string forward_to_format(const std::string s,
10+
const std::vector<std::string>& v,
11+
const Args... args) {
12+
if (v.size() == sizeof...(args)) {
13+
#if defined(SPDLOG_USE_STD_FORMAT) && __cplusplus >= 202002L
14+
// As of 2026-02 we do _not_ set SPDLOG_USE_STD_FORMAT so this section is unused
15+
return std::vformat(std::string_view(s), args...);
16+
#elif __cplusplus >= 202002L
17+
// This section is now the default under C++20 or later
18+
return fmt::format(fmt::runtime(s), args...);
19+
#else
20+
// Fallback
21+
return fmt::format(s, args...);
22+
#endif
1323
}
14-
15-
template<std::size_t size>
16-
std::format_args unpack_vector(const std::vector<std::string>& vec) {
17-
return unpack_vector(vec, std::make_index_sequence<size>());
24+
if constexpr(sizeof...(args) < max_args) {
25+
return forward_to_format(s, v, args..., v[sizeof...(args)]);
1826
}
19-
20-
#endif
27+
return std::string(""); // not reached
28+
}
2129

2230
//' Simple Pass-Through Formatter to \code{fmt::format()}
2331
//'
@@ -37,73 +45,7 @@
3745
//' @seealso https://github.com/fmtlib/fmt
3846
// [[Rcpp::export]]
3947
std::string formatter(const std::string s, std::vector<std::string> v) {
40-
size_t n = v.size();
41-
switch (n) {
42-
#if defined(SPDLOG_USE_STD_FORMAT) && __cplusplus >= 202002L
43-
// As of 2026-02 we do _not_ set SPDLOG_USE_STD_FORMAT so this section is unused
44-
case 0: return std::vformat(std::string_view(s), std::make_format_args());
45-
case 1: return std::vformat(std::string_view(s), unpack_vector<1>(v));
46-
case 2: return std::vformat(std::string_view(s), unpack_vector<2>(v));
47-
case 3: return std::vformat(std::string_view(s), unpack_vector<3>(v));
48-
case 4: return std::vformat(std::string_view(s), unpack_vector<4>(v));
49-
case 5: return std::vformat(std::string_view(s), unpack_vector<5>(v));
50-
case 6: return std::vformat(std::string_view(s), unpack_vector<6>(v));
51-
case 7: return std::vformat(std::string_view(s), unpack_vector<7>(v));
52-
case 8: return std::vformat(std::string_view(s), unpack_vector<8>(v));
53-
case 9: return std::vformat(std::string_view(s), unpack_vector<9>(v));
54-
case 10: return std::vformat(std::string_view(s), unpack_vector<10>(v));
55-
case 11: return std::vformat(std::string_view(s), unpack_vector<11>(v));
56-
case 12: return std::vformat(std::string_view(s), unpack_vector<12>(v));
57-
case 13: return std::vformat(std::string_view(s), unpack_vector<13>(v));
58-
case 14: return std::vformat(std::string_view(s), unpack_vector<14>(v));
59-
case 15: return std::vformat(std::string_view(s), unpack_vector<15>(v));
60-
default: {
61-
Rcpp::warning("Only up to fifteen arguments support for now.");
62-
return std::vformat(std::string_view(s), unpack_vector<12>(v));
63-
}
64-
#elif __cplusplus >= 202002L
65-
// This section is now the default under C++20 or later
66-
case 0: return fmt::format(fmt::runtime(s));
67-
case 1: return fmt::format(fmt::runtime(s), std::string(v[0]));
68-
case 2: return fmt::format(fmt::runtime(s), std::string(v[0]), std::string(v[1]));
69-
case 3: return fmt::format(fmt::runtime(s), std::string(v[0]), std::string(v[1]), std::string(v[2]));
70-
case 4: return fmt::format(fmt::runtime(s), std::string(v[0]), std::string(v[1]), std::string(v[2]), std::string(v[3]));
71-
case 5: return fmt::format(fmt::runtime(s), std::string(v[0]), std::string(v[1]), std::string(v[2]), std::string(v[3]), std::string(v[4]));
72-
case 6: return fmt::format(fmt::runtime(s), std::string(v[0]), std::string(v[1]), std::string(v[2]), std::string(v[3]), std::string(v[4]), std::string(v[5]));
73-
case 7: return fmt::format(fmt::runtime(s), std::string(v[0]), std::string(v[1]), std::string(v[2]), std::string(v[3]), std::string(v[4]), std::string(v[5]), std::string(v[6]));
74-
case 8: return fmt::format(fmt::runtime(s), std::string(v[0]), std::string(v[1]), std::string(v[2]), std::string(v[3]), std::string(v[4]), std::string(v[5]), std::string(v[6]), std::string(v[7]));
75-
case 9: return fmt::format(fmt::runtime(s), std::string(v[0]), std::string(v[1]), std::string(v[2]), std::string(v[3]), std::string(v[4]), std::string(v[5]), std::string(v[6]), std::string(v[7]), std::string(v[8]));
76-
case 10: return fmt::format(fmt::runtime(s), std::string(v[0]), std::string(v[1]), std::string(v[2]), std::string(v[3]), std::string(v[4]), std::string(v[5]), std::string(v[6]), std::string(v[7]), std::string(v[8]), std::string(v[9]));
77-
case 11: return fmt::format(fmt::runtime(s), std::string(v[0]), std::string(v[1]), std::string(v[2]), std::string(v[3]), std::string(v[4]), std::string(v[5]), std::string(v[6]), std::string(v[7]), std::string(v[8]), std::string(v[9]), std::string(v[10]));
78-
case 12: return fmt::format(fmt::runtime(s), std::string(v[0]), std::string(v[1]), std::string(v[2]), std::string(v[3]), std::string(v[4]), std::string(v[5]), std::string(v[6]), std::string(v[7]), std::string(v[8]), std::string(v[9]), std::string(v[10]), std::string(v[11]));
79-
case 13: return fmt::format(fmt::runtime(s), std::string(v[0]), std::string(v[1]), std::string(v[2]), std::string(v[3]), std::string(v[4]), std::string(v[5]), std::string(v[6]), std::string(v[7]), std::string(v[8]), std::string(v[9]), std::string(v[10]), std::string(v[11]), std::string(v[12]));
80-
case 14: return fmt::format(fmt::runtime(s), std::string(v[0]), std::string(v[1]), std::string(v[2]), std::string(v[3]), std::string(v[4]), std::string(v[5]), std::string(v[6]), std::string(v[7]), std::string(v[8]), std::string(v[9]), std::string(v[10]), std::string(v[11]), std::string(v[12]), std::string(v[13]));
81-
case 15: return fmt::format(fmt::runtime(s), std::string(v[0]), std::string(v[1]), std::string(v[2]), std::string(v[3]), std::string(v[4]), std::string(v[5]), std::string(v[6]), std::string(v[7]), std::string(v[8]), std::string(v[9]), std::string(v[10]), std::string(v[11]), std::string(v[12]), std::string(v[13]), std::string(v[14]));
82-
default: {
83-
Rcpp::warning("Only up to fifteen arguments support for now.");
84-
return fmt::format(fmt::runtime(s), std::string(v[0]), std::string(v[1]), std::string(v[2]), std::string(v[3]), std::string(v[4]), std::string(v[5]), std::string(v[6]), std::string(v[7]), std::string(v[8]), std::string(v[9]), std::string(v[10]), std::string(v[11]));
85-
}
86-
#else
87-
case 0: return fmt::format(s);
88-
case 1: return fmt::format(s, std::string(v[0]));
89-
case 2: return fmt::format(s, std::string(v[0]), std::string(v[1]));
90-
case 3: return fmt::format(s, std::string(v[0]), std::string(v[1]), std::string(v[2]));
91-
case 4: return fmt::format(s, std::string(v[0]), std::string(v[1]), std::string(v[2]), std::string(v[3]));
92-
case 5: return fmt::format(s, std::string(v[0]), std::string(v[1]), std::string(v[2]), std::string(v[3]), std::string(v[4]));
93-
case 6: return fmt::format(s, std::string(v[0]), std::string(v[1]), std::string(v[2]), std::string(v[3]), std::string(v[4]), std::string(v[5]));
94-
case 7: return fmt::format(s, std::string(v[0]), std::string(v[1]), std::string(v[2]), std::string(v[3]), std::string(v[4]), std::string(v[5]), std::string(v[6]));
95-
case 8: return fmt::format(s, std::string(v[0]), std::string(v[1]), std::string(v[2]), std::string(v[3]), std::string(v[4]), std::string(v[5]), std::string(v[6]), std::string(v[7]));
96-
case 9: return fmt::format(s, std::string(v[0]), std::string(v[1]), std::string(v[2]), std::string(v[3]), std::string(v[4]), std::string(v[5]), std::string(v[6]), std::string(v[7]), std::string(v[8]));
97-
case 10: return fmt::format(s, std::string(v[0]), std::string(v[1]), std::string(v[2]), std::string(v[3]), std::string(v[4]), std::string(v[5]), std::string(v[6]), std::string(v[7]), std::string(v[8]), std::string(v[9]));
98-
case 11: return fmt::format(s, std::string(v[0]), std::string(v[1]), std::string(v[2]), std::string(v[3]), std::string(v[4]), std::string(v[5]), std::string(v[6]), std::string(v[7]), std::string(v[8]), std::string(v[9]), std::string(v[10]));
99-
case 12: return fmt::format(s, std::string(v[0]), std::string(v[1]), std::string(v[2]), std::string(v[3]), std::string(v[4]), std::string(v[5]), std::string(v[6]), std::string(v[7]), std::string(v[8]), std::string(v[9]), std::string(v[10]), std::string(v[11]));
100-
case 13: return fmt::format(s, std::string(v[0]), std::string(v[1]), std::string(v[2]), std::string(v[3]), std::string(v[4]), std::string(v[5]), std::string(v[6]), std::string(v[7]), std::string(v[8]), std::string(v[9]), std::string(v[10]), std::string(v[11]), std::string(v[12]));
101-
case 14: return fmt::format(s, std::string(v[0]), std::string(v[1]), std::string(v[2]), std::string(v[3]), std::string(v[4]), std::string(v[5]), std::string(v[6]), std::string(v[7]), std::string(v[8]), std::string(v[9]), std::string(v[10]), std::string(v[11]), std::string(v[12]), std::string(v[13]));
102-
case 15: return fmt::format(s, std::string(v[0]), std::string(v[1]), std::string(v[2]), std::string(v[3]), std::string(v[4]), std::string(v[5]), std::string(v[6]), std::string(v[7]), std::string(v[8]), std::string(v[9]), std::string(v[10]), std::string(v[11]), std::string(v[12]), std::string(v[13]), std::string(v[14]));
103-
default: {
104-
Rcpp::warning("Only up to fifteen arguments support for now.");
105-
return fmt::format(s, std::string(v[0]), std::string(v[1]), std::string(v[2]), std::string(v[3]), std::string(v[4]), std::string(v[5]), std::string(v[6]), std::string(v[7]), std::string(v[8]), std::string(v[9]), std::string(v[10]), std::string(v[11]));
106-
}
107-
#endif
108-
}
48+
if (v.size() > max_args)
49+
Rcpp::warning("Only up to " + std::to_string(max_args) + " arguments support for now.");
50+
return forward_to_format(s, v);
10951
}

0 commit comments

Comments
 (0)