Use std::string for string-formatted values (#1360)

* Use `std::string` for string-formatted values

* Make `formatString` and `formatNumber` be `const`
This commit is contained in:
Sylvie
2024-03-19 02:43:18 -04:00
committed by GitHub
parent 33dd97b6a0
commit fec2266dd8
5 changed files with 90 additions and 96 deletions

View File

@@ -5,6 +5,7 @@
#include <stddef.h>
#include <stdint.h>
#include <string>
enum FormatState {
FORMAT_SIGN, // expects '+' or ' ' (optional)
@@ -35,8 +36,9 @@ public:
void useCharacter(int c);
void finishCharacters();
void printString(char *buf, size_t bufLen, char const *value);
void printNumber(char *buf, size_t bufLen, uint32_t value);
std::string formatString(std::string const &value) const;
std::string formatNumber(uint32_t value) const;
};
#endif // RGBDS_FORMAT_SPEC_H

View File

@@ -11,6 +11,7 @@
#include <string.h>
#include "asm/fixpoint.hpp"
#include "asm/lexer.hpp" // MAXSTRLEN
#include "asm/warning.hpp"
void FormatSpec::useCharacter(int c) {
@@ -104,10 +105,11 @@ void FormatSpec::finishCharacters() {
state = FORMAT_INVALID;
}
void FormatSpec::printString(char *buf, size_t bufLen, char const *value) {
std::string FormatSpec::formatString(std::string const &value) const {
int useType = type;
if (isEmpty()) {
// No format was specified
type = 's';
useType = 's';
}
if (sign)
@@ -118,52 +120,50 @@ void FormatSpec::printString(char *buf, size_t bufLen, char const *value) {
error("Formatting string with padding flag '0'\n");
if (hasFrac)
error("Formatting string with fractional width\n");
if (type != 's')
error("Formatting string as type '%c'\n", type);
if (useType != 's')
error("Formatting string as type '%c'\n", useType);
size_t len = strlen(value);
size_t totalLen = width > len ? width : len;
if (totalLen > bufLen - 1) { // bufLen includes terminator
error("Formatted string value too long\n");
totalLen = bufLen - 1;
if (len > totalLen)
len = totalLen;
}
assert(len < bufLen && totalLen < bufLen && len <= totalLen);
size_t padLen = totalLen - len;
size_t valueLen = value.length();
size_t totalLen = width > valueLen ? width : valueLen;
size_t padLen = totalLen - valueLen;
std::string str;
str.reserve(totalLen);
if (alignLeft) {
memcpy(buf, value, len);
for (size_t i = len; i < totalLen; i++)
buf[i] = ' ';
str.append(value);
str.append(padLen, ' ');
} else {
for (size_t i = 0; i < padLen; i++)
buf[i] = ' ';
memcpy(buf + padLen, value, len);
str.append(padLen, ' ');
str.append(value);
}
buf[totalLen] = '\0';
if (str.length() > MAXSTRLEN) {
error("Formatted string value too long\n");
str.resize(MAXSTRLEN);
}
return str;
}
void FormatSpec::printNumber(char *buf, size_t bufLen, uint32_t value) {
std::string FormatSpec::formatNumber(uint32_t value) const {
int useType = type;
bool usePrefix = prefix;
if (isEmpty()) {
// No format was specified; default to uppercase $hex
type = 'X';
prefix = true;
useType = 'X';
usePrefix = true;
}
if (type != 'X' && type != 'x' && type != 'b' && type != 'o' && prefix)
error("Formatting type '%c' with prefix flag '#'\n", type);
if (type != 'f' && hasFrac)
error("Formatting type '%c' with fractional width\n", type);
if (type == 's')
if (useType != 'X' && useType != 'x' && useType != 'b' && useType != 'o' && usePrefix)
error("Formatting type '%c' with prefix flag '#'\n", useType);
if (useType != 'f' && hasFrac)
error("Formatting type '%c' with fractional width\n", useType);
if (useType == 's')
error("Formatting number as type 's'\n");
char signChar = sign; // 0 or ' ' or '+'
if (type == 'd' || type == 'f') {
if (useType == 'd' || useType == 'f') {
int32_t v = value;
if (v < 0 && v != INT32_MIN) {
@@ -172,16 +172,16 @@ void FormatSpec::printNumber(char *buf, size_t bufLen, uint32_t value) {
}
}
char prefixChar = !prefix ? 0
: type == 'X' ? '$'
: type == 'x' ? '$'
: type == 'b' ? '%'
: type == 'o' ? '&'
: 0;
char prefixChar = !usePrefix ? 0
: useType == 'X' ? '$'
: useType == 'x' ? '$'
: useType == 'b' ? '%'
: useType == 'o' ? '&'
: 0;
char valueBuf[262]; // Max 5 digits + decimal + 255 fraction digits + terminator
if (type == 'b') {
if (useType == 'b') {
// Special case for binary
char *ptr = valueBuf;
@@ -194,76 +194,68 @@ void FormatSpec::printNumber(char *buf, size_t bufLen, uint32_t value) {
std::reverse(valueBuf, ptr);
*ptr = '\0';
} else if (type == 'f') {
} else if (useType == 'f') {
// Special case for fixed-point
// Default fractional width (C++'s is 6 for "%f"; here 5 is enough for Q16.16)
size_t cappedFracWidth = hasFrac ? fracWidth : 5;
size_t useFracWidth = hasFrac ? fracWidth : 5;
if (cappedFracWidth > 255) {
error("Fractional width %zu too long, limiting to 255\n", cappedFracWidth);
cappedFracWidth = 255;
if (useFracWidth > 255) {
error("Fractional width %zu too long, limiting to 255\n", useFracWidth);
useFracWidth = 255;
}
snprintf(
valueBuf, sizeof(valueBuf), "%.*f", (int)cappedFracWidth, value / fix_PrecisionFactor()
valueBuf, sizeof(valueBuf), "%.*f", (int)useFracWidth, value / fix_PrecisionFactor()
);
} else {
char const *spec = type == 'd' ? "%" PRId32
: type == 'u' ? "%" PRIu32
: type == 'X' ? "%" PRIX32
: type == 'x' ? "%" PRIx32
: type == 'o' ? "%" PRIo32
: "%" PRId32;
char const *spec = useType == 'd' ? "%" PRId32
: useType == 'u' ? "%" PRIu32
: useType == 'X' ? "%" PRIX32
: useType == 'x' ? "%" PRIx32
: useType == 'o' ? "%" PRIo32
: "%" PRId32;
snprintf(valueBuf, sizeof(valueBuf), spec, value);
}
size_t len = strlen(valueBuf);
size_t numLen = (signChar != 0) + (prefixChar != 0) + len;
size_t valueLen = strlen(valueBuf);
size_t numLen = (signChar != 0) + (prefixChar != 0) + valueLen;
size_t totalLen = width > numLen ? width : numLen;
if (totalLen > bufLen - 1) { // bufLen includes terminator
error("Formatted numeric value too long\n");
totalLen = bufLen - 1;
if (numLen > totalLen) {
len -= numLen - totalLen;
numLen = totalLen;
}
}
assert(numLen < bufLen && totalLen < bufLen && numLen <= totalLen && len <= numLen);
size_t padLen = totalLen - numLen;
size_t pos = 0;
std::string str;
str.reserve(totalLen);
if (alignLeft) {
if (signChar)
buf[pos++] = signChar;
str += signChar;
if (prefixChar)
buf[pos++] = prefixChar;
memcpy(buf + pos, valueBuf, len);
for (size_t i = pos + len; i < totalLen; i++)
buf[i] = ' ';
str += prefixChar;
str.append(valueBuf);
str.append(padLen, ' ');
} else {
if (padZero) {
// sign, then prefix, then zero padding
if (signChar)
buf[pos++] = signChar;
str += signChar;
if (prefixChar)
buf[pos++] = prefixChar;
for (size_t i = 0; i < padLen; i++)
buf[pos++] = '0';
str += prefixChar;
str.append(padLen, '0');
} else {
// space padding, then sign, then prefix
for (size_t i = 0; i < padLen; i++)
buf[pos++] = ' ';
str.append(padLen, ' ');
if (signChar)
buf[pos++] = signChar;
str += signChar;
if (prefixChar)
buf[pos++] = prefixChar;
str += prefixChar;
}
memcpy(buf + pos, valueBuf, len);
str.append(valueBuf);
}
buf[totalLen] = '\0';
if (str.length() > MAXSTRLEN) {
error("Formatted numeric value too long\n");
str.resize(MAXSTRLEN);
}
return str;
}

View File

@@ -1191,10 +1191,12 @@ static char const *readInterpolation(size_t depth) {
if (!sym) {
error("Interpolated symbol \"%s\" does not exist\n", fmtBuf.c_str());
} else if (sym->type == SYM_EQUS) {
fmt.printString(buf, sizeof(buf), sym->getEqus()->c_str());
std::string str = fmt.formatString(*sym->getEqus());
memcpy(buf, str.c_str(), str.length() + 1);
return buf;
} else if (sym->isNumeric()) {
fmt.printNumber(buf, sizeof(buf), sym->getConstantValue());
std::string str = fmt.formatNumber(sym->getConstantValue());
memcpy(buf, str.c_str(), str.length() + 1);
return buf;
} else {
error("Only numerical and string symbols can be interpolated\n");

View File

@@ -2690,15 +2690,13 @@ static std::string strfmt(
// Will warn after formatting is done.
str += '%';
} else {
static char buf[MAXSTRLEN + 1];
std::visit(
str.append(std::visit(
Visitor{
[&](uint32_t n) { fmt.printNumber(buf, sizeof(buf), n); },
[&](std::string const &s) { fmt.printString(buf, sizeof(buf), s.c_str()); },
[&fmt](uint32_t n) { return fmt.formatNumber(n); },
[&fmt](std::string const &s) { return fmt.formatString(s); },
},
args[argIndex]
);
str.append(buf);
));
}
argIndex++;

View File

@@ -1,10 +1,10 @@
$0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002a
$00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
$2a
123.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
hello
000000000000000000000123.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
hello
<$0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002
<$0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
<$2a
<123.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
< hell
<000000000000000000000123.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
<
<hello