Skip to content

Commit 1d229ae

Browse files
authored
Merge pull request #5221 from rocallahan/typed-stringf
Introduce variadic template implementation of `stringf` that supports `std::string` parameters
2 parents 4d51e62 + 6ee3cd8 commit 1d229ae

File tree

4 files changed

+550
-18
lines changed

4 files changed

+550
-18
lines changed

backends/verilog/verilog_backend.cc

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1163,9 +1163,9 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
11631163
dump_sigspec(f, cell->getPort(ID::Y));
11641164
f << stringf(" = ~((");
11651165
dump_cell_expr_port(f, cell, "A", false);
1166-
f << stringf(cell->type == ID($_AOI3_) ? " & " : " | ");
1166+
f << (cell->type == ID($_AOI3_) ? " & " : " | ");
11671167
dump_cell_expr_port(f, cell, "B", false);
1168-
f << stringf(cell->type == ID($_AOI3_) ? ") |" : ") &");
1168+
f << (cell->type == ID($_AOI3_) ? ") |" : ") &");
11691169
dump_attributes(f, "", cell->attributes, " ");
11701170
f << stringf(" ");
11711171
dump_cell_expr_port(f, cell, "C", false);
@@ -1178,13 +1178,13 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
11781178
dump_sigspec(f, cell->getPort(ID::Y));
11791179
f << stringf(" = ~((");
11801180
dump_cell_expr_port(f, cell, "A", false);
1181-
f << stringf(cell->type == ID($_AOI4_) ? " & " : " | ");
1181+
f << (cell->type == ID($_AOI4_) ? " & " : " | ");
11821182
dump_cell_expr_port(f, cell, "B", false);
1183-
f << stringf(cell->type == ID($_AOI4_) ? ") |" : ") &");
1183+
f << (cell->type == ID($_AOI4_) ? ") |" : ") &");
11841184
dump_attributes(f, "", cell->attributes, " ");
11851185
f << stringf(" (");
11861186
dump_cell_expr_port(f, cell, "C", false);
1187-
f << stringf(cell->type == ID($_AOI4_) ? " & " : " | ");
1187+
f << (cell->type == ID($_AOI4_) ? " & " : " | ");
11881188
dump_cell_expr_port(f, cell, "D", false);
11891189
f << stringf("));\n");
11901190
return true;
@@ -1395,10 +1395,10 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
13951395
int s_width = cell->getPort(ID::S).size();
13961396
std::string func_name = cellname(cell);
13971397

1398-
f << stringf("%s" "function [%d:0] %s;\n", indent.c_str(), width-1, func_name.c_str());
1399-
f << stringf("%s" " input [%d:0] a;\n", indent.c_str(), width-1);
1400-
f << stringf("%s" " input [%d:0] b;\n", indent.c_str(), s_width*width-1);
1401-
f << stringf("%s" " input [%d:0] s;\n", indent.c_str(), s_width-1);
1398+
f << stringf("%s" "function [%d:0] %s;\n", indent, width-1, func_name);
1399+
f << stringf("%s" " input [%d:0] a;\n", indent, width-1);
1400+
f << stringf("%s" " input [%d:0] b;\n", indent, s_width*width-1);
1401+
f << stringf("%s" " input [%d:0] s;\n", indent, s_width-1);
14021402

14031403
dump_attributes(f, indent + " ", cell->attributes);
14041404
if (noparallelcase)
@@ -1407,7 +1407,7 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell)
14071407
if (!noattr)
14081408
f << stringf("%s" " (* parallel_case *)\n", indent.c_str());
14091409
f << stringf("%s" " casez (s)", indent.c_str());
1410-
f << stringf(noattr ? " // synopsys parallel_case\n" : "\n");
1410+
f << (noattr ? " // synopsys parallel_case\n" : "\n");
14111411
}
14121412

14131413
for (int i = 0; i < s_width; i++)

kernel/io.cc

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,4 +384,153 @@ std::string escape_filename_spaces(const std::string& filename)
384384
return out;
385385
}
386386

387+
void format_emit_unescaped(std::string &result, std::string_view fmt)
388+
{
389+
result.reserve(result.size() + fmt.size());
390+
for (size_t i = 0; i < fmt.size(); ++i) {
391+
char ch = fmt[i];
392+
result.push_back(ch);
393+
if (ch == '%' && i + 1 < fmt.size() && fmt[i + 1] == '%') {
394+
++i;
395+
}
396+
}
397+
}
398+
399+
std::string unescape_format_string(std::string_view fmt)
400+
{
401+
std::string result;
402+
format_emit_unescaped(result, fmt);
403+
return result;
404+
}
405+
406+
static std::string string_view_stringf(std::string_view spec, ...)
407+
{
408+
std::string fmt(spec);
409+
char format_specifier = fmt[fmt.size() - 1];
410+
switch (format_specifier) {
411+
case 'd':
412+
case 'i':
413+
case 'o':
414+
case 'u':
415+
case 'x':
416+
case 'X': {
417+
// Strip any length modifier off `fmt`
418+
std::string long_fmt;
419+
for (size_t i = 0; i + 1 < fmt.size(); ++i) {
420+
char ch = fmt[i];
421+
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) {
422+
break;
423+
}
424+
long_fmt.push_back(ch);
425+
}
426+
// Add `lld` or whatever
427+
long_fmt += "ll";
428+
long_fmt.push_back(format_specifier);
429+
fmt = long_fmt;
430+
break;
431+
}
432+
default:
433+
break;
434+
}
435+
436+
va_list ap;
437+
va_start(ap, spec);
438+
std::string result = vstringf(fmt.c_str(), ap);
439+
va_end(ap);
440+
return result;
441+
}
442+
443+
template <typename Arg>
444+
static void format_emit_stringf(std::string &result, std::string_view spec, int *dynamic_ints,
445+
DynamicIntCount num_dynamic_ints, Arg arg)
446+
{
447+
// Delegate nontrivial formats to the C library.
448+
switch (num_dynamic_ints) {
449+
case DynamicIntCount::NONE:
450+
result += string_view_stringf(spec, arg);
451+
return;
452+
case DynamicIntCount::ONE:
453+
result += string_view_stringf(spec, dynamic_ints[0], arg);
454+
return;
455+
case DynamicIntCount::TWO:
456+
result += string_view_stringf(spec, dynamic_ints[0], dynamic_ints[1], arg);
457+
return;
458+
}
459+
YOSYS_ABORT("Internal error");
460+
}
461+
462+
void format_emit_long_long(std::string &result, std::string_view spec, int *dynamic_ints,
463+
DynamicIntCount num_dynamic_ints, long long arg)
464+
{
465+
if (spec == "%d") {
466+
// Format checking will have guaranteed num_dynamic_ints == 0.
467+
result += std::to_string(arg);
468+
return;
469+
}
470+
format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, arg);
471+
}
472+
473+
void format_emit_unsigned_long_long(std::string &result, std::string_view spec, int *dynamic_ints,
474+
DynamicIntCount num_dynamic_ints, unsigned long long arg)
475+
{
476+
if (spec == "%u") {
477+
// Format checking will have guaranteed num_dynamic_ints == 0.
478+
result += std::to_string(arg);
479+
return;
480+
}
481+
if (spec == "%c") {
482+
result += static_cast<char>(arg);
483+
return;
484+
}
485+
format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, arg);
486+
}
487+
488+
void format_emit_double(std::string &result, std::string_view spec, int *dynamic_ints,
489+
DynamicIntCount num_dynamic_ints, double arg)
490+
{
491+
format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, arg);
492+
}
493+
494+
void format_emit_char_ptr(std::string &result, std::string_view spec, int *dynamic_ints,
495+
DynamicIntCount num_dynamic_ints, const char *arg)
496+
{
497+
if (spec == "%s") {
498+
// Format checking will have guaranteed num_dynamic_ints == 0.
499+
result += arg;
500+
return;
501+
}
502+
format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, arg);
503+
}
504+
505+
void format_emit_string(std::string &result, std::string_view spec, int *dynamic_ints,
506+
DynamicIntCount num_dynamic_ints, const std::string &arg)
507+
{
508+
if (spec == "%s") {
509+
// Format checking will have guaranteed num_dynamic_ints == 0.
510+
result += arg;
511+
return;
512+
}
513+
format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, arg.c_str());
514+
}
515+
516+
void format_emit_string_view(std::string &result, std::string_view spec, int *dynamic_ints,
517+
DynamicIntCount num_dynamic_ints, std::string_view arg)
518+
{
519+
if (spec == "%s") {
520+
// Format checking will have guaranteed num_dynamic_ints == 0.
521+
// We can output the string without creating a temporary copy.
522+
result += arg;
523+
return;
524+
}
525+
// Delegate nontrivial formats to the C library. We need to construct
526+
// a temporary string to ensure null termination.
527+
format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, std::string(arg).c_str());
528+
}
529+
530+
void format_emit_void_ptr(std::string &result, std::string_view spec, int *dynamic_ints,
531+
DynamicIntCount num_dynamic_ints, const void *arg)
532+
{
533+
format_emit_stringf(result, spec, dynamic_ints, num_dynamic_ints, arg);
534+
}
535+
387536
YOSYS_NAMESPACE_END

0 commit comments

Comments
 (0)