Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add float and double support to plFormat #431

Merged
merged 2 commits into from
May 28, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Sources/Plasma/CoreLib/plFileSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -556,9 +556,9 @@ plString plFileSystem::ConvertFileSize(uint64_t size)
float decimal = static_cast<float>(last_div) / 1024.f;
// Kilobytes are so small that we only care about whole numbers
if (i < 1)
return plString::Format("%.0f %s", decimal, labels[i]);
return plFormat("{.0f} {}", decimal, labels[i]);
else
return plString::Format("%.2f %s", decimal, labels[i]);
return plFormat("{.2f} {}", decimal, labels[i]);
}
last_div = my_div;
}
Expand Down
92 changes: 73 additions & 19 deletions Sources/Plasma/CoreLib/plFormat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,15 +147,15 @@ namespace plFormat_Private
case '5': case '6': case '7': case '8': case '9':
{
char *end = nullptr;
spec.fPrecisionLeft = strtol(ptr, &end, 10);
spec.fMinimumLength = strtol(ptr, &end, 10);
ptr = end - 1;
}
break;
case '.':
{
hsAssert(*(ptr + 1), "Unterminated format specifier");
char *end = nullptr;
spec.fPrecisionRight = strtol(ptr + 1, &end, 10);
spec.fPrecision = strtol(ptr + 1, &end, 10);
ptr = end - 1;
}
break;
Expand Down Expand Up @@ -227,16 +227,16 @@ static plStringBuffer<char> _formatNumeric(const plFormat_Private::FormatSpec &f
max = 1;

plStringBuffer<char> buffer;
if (format.fPrecisionLeft > max) {
char *output = buffer.CreateWritableBuffer(format.fPrecisionLeft);
memset(output, pad, format.fPrecisionLeft);
if (format.fMinimumLength > max) {
char *output = buffer.CreateWritableBuffer(format.fMinimumLength);
memset(output, pad, format.fMinimumLength);
if (format.fAlignment == plFormat_Private::kAlignLeft) {
_IFormatNumeric_Impl<_IType>(output + max, value, radix, upperCase);
} else {
_IFormatNumeric_Impl<_IType>(output + format.fPrecisionLeft,
_IFormatNumeric_Impl<_IType>(output + format.fMinimumLength,
value, radix, upperCase);
}
output[format.fPrecisionLeft] = 0;
output[format.fMinimumLength] = 0;
} else {
char *output = buffer.CreateWritableBuffer(max);
_IFormatNumeric_Impl<_IType>(output + max, value, radix, upperCase);
Expand Down Expand Up @@ -268,21 +268,21 @@ static plStringBuffer<char> _formatDecimal(const plFormat_Private::FormatSpec &f

plStringBuffer<char> buffer;
char *output;
if (format.fPrecisionLeft > max) {
output = buffer.CreateWritableBuffer(format.fPrecisionLeft);
memset(output, pad, format.fPrecisionLeft);
if (format.fMinimumLength > max) {
output = buffer.CreateWritableBuffer(format.fMinimumLength);
memset(output, pad, format.fMinimumLength);
if (format.fAlignment == plFormat_Private::kAlignLeft)
_IFormatNumeric_Impl<_IType>(output + max, abs, 10);
else
_IFormatNumeric_Impl<_IType>(output + format.fPrecisionLeft, abs, 10);
output[format.fPrecisionLeft] = 0;
_IFormatNumeric_Impl<_IType>(output + format.fMinimumLength, abs, 10);
output[format.fMinimumLength] = 0;
} else {
output = buffer.CreateWritableBuffer(max);
_IFormatNumeric_Impl<_IType>(output + max, abs, 10);
output[max] = 0;
}

int signPos = format.fPrecisionLeft - static_cast<int>(max);
int signPos = format.fPrecision - static_cast<int>(max);
if (signPos < 0)
signPos = 0;

Expand All @@ -296,7 +296,7 @@ static plStringBuffer<char> _formatDecimal(const plFormat_Private::FormatSpec &f

static plStringBuffer<char> _formatChar(const plFormat_Private::FormatSpec &format, int ch)
{
hsAssert(format.fPrecisionLeft == 0 && format.fPadChar == 0,
hsAssert(format.fMinimumLength == 0 && format.fPadChar == 0,
"Char formatting does not currently support padding");

// Don't need to nul-terminate this, since plStringBuffer's constructor fixes it
Expand Down Expand Up @@ -392,6 +392,60 @@ _PL_FORMAT_IMPL_INT_TYPE(long, unsigned long)
_PL_FORMAT_IMPL_INT_TYPE(int64_t, uint64_t)
#endif

PL_FORMAT_IMPL(float)
{
return PL_FORMAT_FORWARD(format, double(value));
}

PL_FORMAT_IMPL(double)
{
char pad = format.fPadChar ? format.fPadChar : ' ';

// Cheating a bit here -- just pass it along to cstdio
char format_buffer[32];
size_t end = 0;

format_buffer[end++] = '%';
if (format.fPrecision) {
int count = snprintf(format_buffer + end, arrsize(format_buffer) - end,
".%d", format.fPrecision);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be ..."%d.%d", format.fMinimumLength, format.fPrecision)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The libc version of *printf doesn't allow arbitrary padding chars, so no, I handle that separately.


// Ensure one more space (excluding \0) is available for the format specifier
hsAssert(count > 0 && count + end + 2 < arrsize(format_buffer),
"Not enough space for format string");
end += count;
}

format_buffer[end++] =
(format.fFloatClass == plFormat_Private::kFloatExp) ? 'e' :
(format.fFloatClass == plFormat_Private::kFloatExpUpper) ? 'E' :
(format.fFloatClass == plFormat_Private::kFloatFixed) ? 'f' : 'g';
format_buffer[end] = 0;

int format_size = snprintf(nullptr, 0, format_buffer, value);
hsAssert(format_size > 0, "Your libc doesn't support reporting format size");
plStringBuffer<char> out_buffer;
char *output;

if (format.fMinimumLength > format_size) {
output = out_buffer.CreateWritableBuffer(format.fMinimumLength);
memset(output, pad, format.fMinimumLength);
if (format.fAlignment == plFormat_Private::kAlignLeft) {
snprintf(output, format_size + 1, format_buffer, value);
output[format_size] = pad; // snprintf overwrites this
output[format.fMinimumLength] = 0;
} else {
snprintf(output + (format.fMinimumLength - format_size), format_size + 1,
format_buffer, value);
}
} else {
output = out_buffer.CreateWritableBuffer(format_size);
snprintf(output, format_size + 1, format_buffer, value);
}

return out_buffer;
}

PL_FORMAT_IMPL(char)
{
/* Note: The use of unsigned here is not a typo -- we only format decimal
Expand Down Expand Up @@ -445,18 +499,18 @@ static plStringBuffer<char> _formatString(const plFormat_Private::FormatSpec &fo
{
char pad = format.fPadChar ? format.fPadChar : ' ';

if (format.fPrecisionLeft > value.GetSize()) {
if (format.fMinimumLength > value.GetSize()) {
plStringBuffer<char> buf;
char *output = buf.CreateWritableBuffer(format.fPrecisionLeft);
memset(output, pad, format.fPrecisionLeft);
char *output = buf.CreateWritableBuffer(format.fMinimumLength);
memset(output, pad, format.fMinimumLength);
if (format.fAlignment == plFormat_Private::kAlignRight) {
memcpy(output + (format.fPrecisionLeft - value.GetSize()),
memcpy(output + (format.fMinimumLength - value.GetSize()),
value.GetData(), value.GetSize());
} else {
memcpy(output, value.GetData(), value.GetSize());
}

output[format.fPrecisionLeft] = 0;
output[format.fMinimumLength] = 0;
return buf;
}

Expand Down
13 changes: 7 additions & 6 deletions Sources/Plasma/CoreLib/plFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ Mead, WA 99021
* `b` | Binary
* `d` | Decimal (default) -- when used with char types, outputs a number instead of the UTF representation of the char
* `c` | UTF character (default for character types)
* `FFF.EEE` | Use FFF.EEE floating point precision
* `.EEE` | Use EEE digits of floating point precision
* `f` | Fixed floating point format (ddd.ddd)
* `e` | Exponent notation for floating point (d.ddde[+/-]dd)
* `E` | Same as 'e' format, but with upper case E (d.dddE[+/-]dd)
Expand Down Expand Up @@ -114,8 +114,8 @@ namespace plFormat_Private
/** Represents a parsed format tag, for use in formatter implementations. */
struct FormatSpec
{
int fPrecisionLeft = 0; /**< Requested padding and/or precision */
int fPrecisionRight = 0; /**< Requested precision after the . for floating-point */
int fMinimumLength = 0; /**< Requested minimum padding length */
int fPrecision = 0; /**< Requested precision for floating-point */

char fPadChar = 0; /**< Explicit padding char (default is space) */
Alignment fAlignment = kAlignDefault; /**< Requested pad alignment */
Expand Down Expand Up @@ -192,6 +192,10 @@ namespace plFormat_Private
PL_FORMAT_TYPE(int64_t)
PL_FORMAT_TYPE(uint64_t)
#endif

PL_FORMAT_TYPE(float)
PL_FORMAT_TYPE(double)

PL_FORMAT_TYPE(const char *)
PL_FORMAT_TYPE(const wchar_t *)
PL_FORMAT_TYPE(const plString &)
Expand All @@ -203,9 +207,6 @@ namespace plFormat_Private
PL_FORMAT_TYPE(const std::string &)
PL_FORMAT_TYPE(const std::wstring &)

// TODO: Implement floating point types (float, double). They're harder
// than the others, so I'll get around to them later >.>

// Formats as "true" or "false", following normal string formatting rules.
// To use other formats, don't pass us a bool directly...
PL_FORMAT_TYPE(bool)
Expand Down
6 changes: 3 additions & 3 deletions Sources/Plasma/FeatureLib/pfConsole/pfDispatchLog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -257,10 +257,10 @@ static bool DumpSpecificMsgInfo(plMessage* msg, plString& info)
PrintKIType(kGZFlashUpdate); // flash an update without saving (for animation of GZFill in)
PrintKIType(kNoCommand);

info = plString::Format("Type: %s Str: %s User: %s(%d) Delay: %f Int: %d",
info = plFormat("Type: {} Str: {} User: {}({}) Delay: {} Int: {}",
typeName,
kiMsg->GetString().c_str("(nil)"),
kiMsg->GetUser().c_str("(nil)"),
kiMsg->GetString(),
kiMsg->GetUser(),
kiMsg->GetPlayerID(),
kiMsg->GetDelay(),
kiMsg->GetIntValue());
Expand Down
2 changes: 1 addition & 1 deletion Sources/Plasma/FeatureLib/pfPython/cyMisc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1566,7 +1566,7 @@ void cyMisc::FogSetDefExp2(float end, float density)
void cyMisc::SetClearColor(float red, float green, float blue)
{
// do this command via the console to keep the maxplugins from barfing
plString command = plString::Format("Graphics.Renderer.SetClearColor %f %f %f", red, green, blue);
plString command = plFormat("Graphics.Renderer.SetClearColor {f} {f} {f}", red, green, blue);

// create message to send to the console
plControlEventMsg* pMsg = new plControlEventMsg;
Expand Down
12 changes: 6 additions & 6 deletions Sources/Plasma/PubUtilLib/plAvatar/plAvTaskSeek.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -563,17 +563,17 @@ bool plAvTaskSeek::IUpdateObjective(plArmatureMod *avatar)
// ----------
void plAvTaskSeek::DumpDebug(const char *name, int &x, int&y, int lineHeight, plDebugText &debugTxt)
{
debugTxt.DrawString(x, y, plString::Format("duration: %.2f pos: (%.3f, %.3f, %.3f) goalPos: (%.3f, %.3f, %.3f) ",
debugTxt.DrawString(x, y, plFormat("duration: {.2f} pos: ({.3f}, {.3f}, {.3f}) goalPos: ({.3f}, {.3f}, {.3f}) ",
hsTimer::GetSysSeconds() - fStartTime,
fPosition.fX, fPosition.fY, fPosition.fZ, fSeekPos.fX, fSeekPos.fY, fSeekPos.fZ));
y += lineHeight;

debugTxt.DrawString(x, y, plString::Format("positioning: %d rotating %d goalVec: (%.3f, %.3f, %.3f) dist: %.3f angFwd: %.3f angRt: %.3f",
debugTxt.DrawString(x, y, plFormat("positioning: {} rotating {} goalVec: ({.3f}, {.3f}, {.3f}) dist: {.3f} angFwd: {.3f} angRt: {.3f}",
fStillPositioning, fStillRotating, fGoalVec.fX, fGoalVec.fY, fGoalVec.fZ,
fDistance, fAngForward, fAngRight));
y += lineHeight;

debugTxt.DrawString(x, y, plString::Format(" distFwd: %.3f distRt: %.3f shufRange: %.3f sidAngle: %.3f sidRange: %.3f, fMinWalk: %.3f",
debugTxt.DrawString(x, y, plFormat(" distFwd: {.3f} distRt: {.3f} shufRange: {.3f} sidAngle: {.3f} sidRange: {.3f}, fMinWalk: {.3f}",
fDistForward, fDistRight, fShuffleRange, fMaxSidleAngle, fMaxSidleRange, fMinFwdAngle));
y += lineHeight;
}
Expand All @@ -583,17 +583,17 @@ void plAvTaskSeek::DumpToAvatarLog(plArmatureMod *avatar)
plStatusLog *log = plAvatarMgr::GetInstance()->GetLog();
log->AddLine(avatar->GetMoveKeyString().c_str());

log->AddLine(plString::Format(" duration: %.2f pos: (%.3f, %.3f, %.3f) goalPos: (%.3f, %.3f, %.3f) ",
log->AddLine(plFormat(" duration: {.2f} pos: ({.3f}, {.3f}, {.3f}) goalPos: ({.3f}, {.3f}, {.3f}) ",
hsTimer::GetSysSeconds() - fStartTime,
fPosition.fX, fPosition.fY, fPosition.fZ,
fSeekPos.fX, fSeekPos.fY, fSeekPos.fZ).c_str());

log->AddLine(plString::Format(" positioning: %d rotating %d goalVec: (%.3f, %.3f, %.3f) dist: %.3f angFwd: %.3f angRt: %.3f",
log->AddLine(plFormat(" positioning: {} rotating {} goalVec: ({.3f}, {.3f}, {.3f}) dist: {.3f} angFwd: {.3f} angRt: {.3f}",
fStillPositioning, fStillRotating,
fGoalVec.fX, fGoalVec.fY, fGoalVec.fZ,
fDistance, fAngForward, fAngRight).c_str());

log->AddLine(plString::Format(" distFwd: %.3f distRt: %.3f shufRange: %.3f sidAngle: %.3f sidRange: %.3f, fMinWalk: %.3f",
log->AddLine(plFormat(" distFwd: {.3f} distRt: {.3f} shufRange: {.3f} sidAngle: {.3f} sidRange: {.3f}, fMinWalk: {.3f}",
fDistForward, fDistRight, fShuffleRange,
fMaxSidleAngle, fMaxSidleRange, fMinFwdAngle).c_str());
}
Expand Down