Browse Source

Merge pull request #438 from zrax/plFormat_stream

Switch plFormat's accumulator to a plStringStream for better performance
Adam Johnson 11 years ago
parent
commit
a82c110a9a
  1. 2
      Sources/Plasma/CoreLib/plFileSystem.cpp
  2. 289
      Sources/Plasma/CoreLib/plFormat.cpp
  3. 22
      Sources/Plasma/CoreLib/plFormat.h
  4. 43
      Sources/Plasma/CoreLib/plString.cpp
  5. 5
      Sources/Plasma/CoreLib/plString.h
  6. 4
      Sources/Plasma/NucleusLib/pnKeyedObject/plUoid.cpp
  7. 2
      Sources/Plasma/NucleusLib/pnUUID/pnUUID.cpp

2
Sources/Plasma/CoreLib/plFileSystem.cpp

@ -199,7 +199,7 @@ plFileName plFileName::Join(const plFileName &base, const plFileName &path)
PL_FORMAT_IMPL(const plFileName &) PL_FORMAT_IMPL(const plFileName &)
{ {
return PL_FORMAT_FORWARD(format, value.AsString()); PL_FORMAT_FORWARD(value.AsString());
} }

289
Sources/Plasma/CoreLib/plFormat.cpp

@ -70,13 +70,13 @@ namespace plFormat_Private
const char *next = _scanNextFormat(data); const char *next = _scanNextFormat(data);
if (*next && *(next + 1) == '{') { if (*next && *(next + 1) == '{') {
// Escaped '{' // Escaped '{'
data.fOutput.push_back(plStringBuffer<char>(data.fFormatStr, 1 + next - data.fFormatStr)); data.fOutput.append(data.fFormatStr, 1 + next - data.fFormatStr);
data.fFormatStr = next + 2; data.fFormatStr = next + 2;
continue; continue;
} }
if (next != data.fFormatStr) if (next != data.fFormatStr)
data.fOutput.push_back(plStringBuffer<char>(data.fFormatStr, next - data.fFormatStr)); data.fOutput.append(data.fFormatStr, next - data.fFormatStr);
data.fFormatStr = next; data.fFormatStr = next;
} while (0); } while (0);
} }
@ -170,20 +170,30 @@ namespace plFormat_Private
{ {
_fetchPrefixChunk(data); _fetchPrefixChunk(data);
hsAssert(*data.fFormatStr == 0, "Not enough actual parameters for format string"); hsAssert(*data.fFormatStr == 0, "Not enough actual parameters for format string");
return data.fOutput.GetString();
}
}
size_t outsize = 0; static void _formatString(const plFormat_Private::FormatSpec &format,
for (const plStringBuffer<char> &buf : data.fOutput) plStringStream &output, const char *text, size_t size,
outsize += buf.GetSize(); plFormat_Private::Alignment defaultAlignment)
{
char pad = format.fPadChar ? format.fPadChar : ' ';
plStringBuffer<char> outbuf; if (format.fMinimumLength > size) {
char *out_ptr = outbuf.CreateWritableBuffer(outsize); plFormat_Private::Alignment align =
for (const plStringBuffer<char> &buf : data.fOutput) { (format.fAlignment == plFormat_Private::kAlignDefault)
memcpy(out_ptr, buf.GetData(), buf.GetSize()); ? defaultAlignment : format.fAlignment;
out_ptr += buf.GetSize();
}
*out_ptr = 0;
return outbuf; if (align == plFormat_Private::kAlignRight) {
output.appendChar(pad, format.fMinimumLength - size);
output.append(text, size);
} else {
output.append(text, size);
output.appendChar(pad, format.fMinimumLength - size);
}
} else {
output.append(text, size);
} }
} }
@ -211,128 +221,106 @@ void _IFormatNumeric_Impl(char *output_end, _IType value, int radix, bool upperC
} }
template <typename _IType> template <typename _IType>
static plStringBuffer<char> _formatNumeric(const plFormat_Private::FormatSpec &format, static void _formatNumeric(const plFormat_Private::FormatSpec &format,
_IType value, int radix, bool upperCase = false) plStringStream &output, _IType value,
int radix, bool upperCase = false)
{ {
char pad = format.fPadChar ? format.fPadChar : ' '; char pad = format.fPadChar ? format.fPadChar : ' ';
size_t max = 0; size_t format_size = 0;
_IType temp = value; _IType temp = value;
while (temp) { while (temp) {
++max; ++format_size;
temp /= radix; temp /= radix;
} }
if (max == 0) if (format_size == 0)
max = 1; format_size = 1;
plStringBuffer<char> buffer; hsAssert(format_size < 64, "Format length too long");
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.fMinimumLength,
value, radix, upperCase);
}
output[format.fMinimumLength] = 0;
} else {
char *output = buffer.CreateWritableBuffer(max);
_IFormatNumeric_Impl<_IType>(output + max, value, radix, upperCase);
output[max] = 0;
}
return buffer; char buffer[64];
_IFormatNumeric_Impl<_IType>(buffer + format_size, value, radix, upperCase);
_formatString(format, output, buffer, format_size, plFormat_Private::kAlignRight);
} }
// Currently, only decimal formatting supports rendering negative numbers // Currently, only decimal formatting supports rendering negative numbers
template <typename _IType> template <typename _IType>
static plStringBuffer<char> _formatDecimal(const plFormat_Private::FormatSpec &format, _IType value) static void _formatDecimal(const plFormat_Private::FormatSpec &format,
plStringStream &output, _IType value)
{ {
char pad = format.fPadChar ? format.fPadChar : ' '; char pad = format.fPadChar ? format.fPadChar : ' ';
_IType abs = (value < 0) ? -value : value; _IType abs = (value < 0) ? -value : value;
size_t max = 0; size_t format_size = 0;
_IType temp = abs; _IType temp = abs;
while (temp) { while (temp) {
++max; ++format_size;
temp /= 10; temp /= 10;
} }
if (max == 0) if (format_size == 0)
max = 1; format_size = 1;
if (value < 0 || format.fDigitClass == plFormat_Private::kDigitDecAlwaysSigned) if (value < 0 || format.fDigitClass == plFormat_Private::kDigitDecAlwaysSigned)
++max; ++format_size;
plStringBuffer<char> buffer; hsAssert(format_size < 21, "Format length too long");
char *output;
if (format.fMinimumLength > max) { char buffer[21];
output = buffer.CreateWritableBuffer(format.fMinimumLength); _IFormatNumeric_Impl<_IType>(buffer + format_size, abs, 10);
memset(output, pad, format.fMinimumLength);
if (format.fAlignment == plFormat_Private::kAlignLeft)
_IFormatNumeric_Impl<_IType>(output + max, abs, 10);
else
_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.fPrecision - static_cast<int>(max); int signPos = arrsize(buffer) - static_cast<int>(format_size);
if (signPos < 0) hsAssert(signPos >= 0, "Format buffer not large enough for sign");
signPos = 0;
if (value < 0) if (value < 0)
output[signPos] = '-'; buffer[signPos] = '-';
else if (format.fDigitClass == plFormat_Private::kDigitDecAlwaysSigned) else if (format.fDigitClass == plFormat_Private::kDigitDecAlwaysSigned)
output[signPos] = '+'; buffer[signPos] = '+';
return buffer; _formatString(format, output, buffer, format_size, plFormat_Private::kAlignRight);
} }
static plStringBuffer<char> _formatChar(const plFormat_Private::FormatSpec &format, int ch) static void _formatChar(const plFormat_Private::FormatSpec &format,
plStringStream &output, int ch)
{ {
hsAssert(format.fMinimumLength == 0 && format.fPadChar == 0, hsAssert(format.fMinimumLength == 0 && format.fPadChar == 0,
"Char formatting does not currently support padding"); "Char formatting does not currently support padding");
// Don't need to nul-terminate this, since plStringBuffer's constructor fixes it // Don't need to nul-terminate this, since plStringBuffer's constructor fixes it
char utf8[4]; char utf8[4];
size_t max; size_t format_size;
// Yanked from plString // Yanked from plString
if (ch > 0x10FFFF) { if (ch > 0x10FFFF) {
hsAssert(0, "Unicode character out of range"); hsAssert(0, "Unicode character out of range");
// Character out of range; Use U+FFFD instead for release builds // Character out of range; Use U+FFFD instead for release builds
max = 3; format_size = 3;
utf8[0] = 0xE0 | ((BADCHAR_REPLACEMENT >> 12) & 0x0F); utf8[0] = 0xE0 | ((BADCHAR_REPLACEMENT >> 12) & 0x0F);
utf8[1] = 0x80 | ((BADCHAR_REPLACEMENT >> 6) & 0x3F); utf8[1] = 0x80 | ((BADCHAR_REPLACEMENT >> 6) & 0x3F);
utf8[2] = 0x80 | ((BADCHAR_REPLACEMENT ) & 0x3F); utf8[2] = 0x80 | ((BADCHAR_REPLACEMENT ) & 0x3F);
} else if (ch > 0xFFFF) { } else if (ch > 0xFFFF) {
max = 4; format_size = 4;
utf8[0] = 0xF0 | ((ch >> 18) & 0x07); utf8[0] = 0xF0 | ((ch >> 18) & 0x07);
utf8[1] = 0x80 | ((ch >> 12) & 0x3F); utf8[1] = 0x80 | ((ch >> 12) & 0x3F);
utf8[2] = 0x80 | ((ch >> 6) & 0x3F); utf8[2] = 0x80 | ((ch >> 6) & 0x3F);
utf8[3] = 0x80 | ((ch ) & 0x3F); utf8[3] = 0x80 | ((ch ) & 0x3F);
} else if (ch > 0x7FF) { } else if (ch > 0x7FF) {
max = 3; format_size = 3;
utf8[0] = 0xE0 | ((ch >> 12) & 0x0F); utf8[0] = 0xE0 | ((ch >> 12) & 0x0F);
utf8[1] = 0x80 | ((ch >> 6) & 0x3F); utf8[1] = 0x80 | ((ch >> 6) & 0x3F);
utf8[2] = 0x80 | ((ch ) & 0x3F); utf8[2] = 0x80 | ((ch ) & 0x3F);
} else if (ch > 0x7F) { } else if (ch > 0x7F) {
max = 2; format_size = 2;
utf8[0] = 0xC0 | ((ch >> 6) & 0x1F); utf8[0] = 0xC0 | ((ch >> 6) & 0x1F);
utf8[1] = 0x80 | ((ch ) & 0x3F); utf8[1] = 0x80 | ((ch ) & 0x3F);
} else { } else {
max = 1; format_size = 1;
utf8[0] = (char)ch; utf8[0] = (char)ch;
} }
return plStringBuffer<char>(utf8, max); output.append(utf8, format_size);
} }
#define _PL_FORMAT_IMPL_INT_TYPE(_stype, _utype) \ #define _PL_FORMAT_IMPL_INT_TYPE(_stype, _utype) \
@ -342,46 +330,58 @@ static plStringBuffer<char> _formatChar(const plFormat_Private::FormatSpec &form
values with a sign, so we can convert everything else to unsigned. */ \ values with a sign, so we can convert everything else to unsigned. */ \
switch (format.fDigitClass) { \ switch (format.fDigitClass) { \
case plFormat_Private::kDigitBin: \ case plFormat_Private::kDigitBin: \
return _formatNumeric<_utype>(format, value, 2); \ _formatNumeric<_utype>(format, output, value, 2); \
break; \
case plFormat_Private::kDigitOct: \ case plFormat_Private::kDigitOct: \
return _formatNumeric<_utype>(format, value, 8); \ _formatNumeric<_utype>(format, output, value, 8); \
break; \
case plFormat_Private::kDigitHex: \ case plFormat_Private::kDigitHex: \
return _formatNumeric<_utype>(format, value, 16, false); \ _formatNumeric<_utype>(format, output, value, 16, false); \
break; \
case plFormat_Private::kDigitHexUpper: \ case plFormat_Private::kDigitHexUpper: \
return _formatNumeric<_utype>(format, value, 16, true); \ _formatNumeric<_utype>(format, output, value, 16, true); \
break; \
case plFormat_Private::kDigitDec: \ case plFormat_Private::kDigitDec: \
case plFormat_Private::kDigitDecAlwaysSigned: \ case plFormat_Private::kDigitDecAlwaysSigned: \
case plFormat_Private::kDigitDefault: \ case plFormat_Private::kDigitDefault: \
return _formatDecimal<_stype>(format, value); \ _formatDecimal<_stype>(format, output, value); \
break; \
case plFormat_Private::kDigitChar: \ case plFormat_Private::kDigitChar: \
return _formatChar(format, value); \ _formatChar(format, output, value); \
} \ break; \
\ default: \
hsAssert(0, "Unexpected digit class"); \ hsAssert(0, "Unexpected digit class"); \
return plStringBuffer<char>(); \ break; \
} \
} \ } \
\ \
PL_FORMAT_IMPL(_utype) \ PL_FORMAT_IMPL(_utype) \
{ \ { \
switch (format.fDigitClass) { \ switch (format.fDigitClass) { \
case plFormat_Private::kDigitBin: \ case plFormat_Private::kDigitBin: \
return _formatNumeric<_utype>(format, value, 2); \ _formatNumeric<_utype>(format, output, value, 2); \
break; \
case plFormat_Private::kDigitOct: \ case plFormat_Private::kDigitOct: \
return _formatNumeric<_utype>(format, value, 8); \ _formatNumeric<_utype>(format, output, value, 8); \
break; \
case plFormat_Private::kDigitHex: \ case plFormat_Private::kDigitHex: \
return _formatNumeric<_utype>(format, value, 16, false); \ _formatNumeric<_utype>(format, output, value, 16, false); \
break; \
case plFormat_Private::kDigitHexUpper: \ case plFormat_Private::kDigitHexUpper: \
return _formatNumeric<_utype>(format, value, 16, true); \ _formatNumeric<_utype>(format, output, value, 16, true); \
break; \
case plFormat_Private::kDigitDec: \ case plFormat_Private::kDigitDec: \
case plFormat_Private::kDigitDecAlwaysSigned: \ case plFormat_Private::kDigitDecAlwaysSigned: \
case plFormat_Private::kDigitDefault: \ case plFormat_Private::kDigitDefault: \
return _formatDecimal<_utype>(format, value); \ _formatDecimal<_utype>(format, output, value); \
break; \
case plFormat_Private::kDigitChar: \ case plFormat_Private::kDigitChar: \
return _formatChar(format, value); \ _formatChar(format, output, value); \
} \ break; \
\ default: \
hsAssert(0, "Unexpected digit class"); \ hsAssert(0, "Unexpected digit class"); \
return plStringBuffer<char>(); \ break; \
} \
} }
_PL_FORMAT_IMPL_INT_TYPE(signed char, unsigned char) _PL_FORMAT_IMPL_INT_TYPE(signed char, unsigned char)
@ -394,7 +394,7 @@ _PL_FORMAT_IMPL_INT_TYPE(int64_t, uint64_t)
PL_FORMAT_IMPL(float) PL_FORMAT_IMPL(float)
{ {
return PL_FORMAT_FORWARD(format, double(value)); PL_FORMAT_FORWARD(double(value));
} }
PL_FORMAT_IMPL(double) PL_FORMAT_IMPL(double)
@ -425,25 +425,24 @@ PL_FORMAT_IMPL(double)
int format_size = snprintf(nullptr, 0, format_buffer, value); int format_size = snprintf(nullptr, 0, format_buffer, value);
hsAssert(format_size > 0, "Your libc doesn't support reporting format size"); hsAssert(format_size > 0, "Your libc doesn't support reporting format size");
plStringBuffer<char> out_buffer; plStringBuffer<char> out_buffer;
char *output; char *fmt_out;
if (format.fMinimumLength > format_size) { if (format.fMinimumLength > format_size) {
output = out_buffer.CreateWritableBuffer(format.fMinimumLength); fmt_out = out_buffer.CreateWritableBuffer(format.fMinimumLength);
memset(output, pad, format.fMinimumLength); memset(fmt_out, pad, format.fMinimumLength);
if (format.fAlignment == plFormat_Private::kAlignLeft) { if (format.fAlignment == plFormat_Private::kAlignLeft) {
snprintf(output, format_size + 1, format_buffer, value); snprintf(fmt_out, format_size + 1, format_buffer, value);
output[format_size] = pad; // snprintf overwrites this fmt_out[format_size] = pad; // snprintf overwrites this
output[format.fMinimumLength] = 0;
} else { } else {
snprintf(output + (format.fMinimumLength - format_size), format_size + 1, snprintf(fmt_out + (format.fMinimumLength - format_size), format_size + 1,
format_buffer, value); format_buffer, value);
} }
} else { } else {
output = out_buffer.CreateWritableBuffer(format_size); fmt_out = out_buffer.CreateWritableBuffer(format_size);
snprintf(output, format_size + 1, format_buffer, value); snprintf(fmt_out, format_size + 1, format_buffer, value);
} }
return out_buffer; output.append(out_buffer.GetData(), out_buffer.GetSize());
} }
PL_FORMAT_IMPL(char) PL_FORMAT_IMPL(char)
@ -452,97 +451,93 @@ PL_FORMAT_IMPL(char)
values with a sign, so we can convert everything else to unsigned. */ values with a sign, so we can convert everything else to unsigned. */
switch (format.fDigitClass) { switch (format.fDigitClass) {
case plFormat_Private::kDigitBin: case plFormat_Private::kDigitBin:
return _formatNumeric<unsigned char>(format, value, 2); _formatNumeric<unsigned char>(format, output, value, 2);
break;
case plFormat_Private::kDigitOct: case plFormat_Private::kDigitOct:
return _formatNumeric<unsigned char>(format, value, 8); _formatNumeric<unsigned char>(format, output, value, 8);
break;
case plFormat_Private::kDigitHex: case plFormat_Private::kDigitHex:
return _formatNumeric<unsigned char>(format, value, 16, false); _formatNumeric<unsigned char>(format, output, value, 16, false);
break;
case plFormat_Private::kDigitHexUpper: case plFormat_Private::kDigitHexUpper:
return _formatNumeric<unsigned char>(format, value, 16, true); _formatNumeric<unsigned char>(format, output, value, 16, true);
break;
case plFormat_Private::kDigitDec: case plFormat_Private::kDigitDec:
case plFormat_Private::kDigitDecAlwaysSigned: case plFormat_Private::kDigitDecAlwaysSigned:
return _formatDecimal<signed char>(format, value); _formatDecimal<signed char>(format, output, value);
break;
case plFormat_Private::kDigitChar: case plFormat_Private::kDigitChar:
case plFormat_Private::kDigitDefault: case plFormat_Private::kDigitDefault:
return _formatChar(format, value); _formatChar(format, output, value);
} break;
default:
hsAssert(0, "Unexpected digit class"); hsAssert(0, "Unexpected digit class");
return plStringBuffer<char>(); break;
}
} }
PL_FORMAT_IMPL(wchar_t) PL_FORMAT_IMPL(wchar_t)
{ {
switch (format.fDigitClass) { switch (format.fDigitClass) {
case plFormat_Private::kDigitBin: case plFormat_Private::kDigitBin:
return _formatNumeric<wchar_t>(format, value, 2); _formatNumeric<wchar_t>(format, output, value, 2);
break;
case plFormat_Private::kDigitOct: case plFormat_Private::kDigitOct:
return _formatNumeric<wchar_t>(format, value, 8); _formatNumeric<wchar_t>(format, output, value, 8);
break;
case plFormat_Private::kDigitHex: case plFormat_Private::kDigitHex:
return _formatNumeric<wchar_t>(format, value, 16, false); _formatNumeric<wchar_t>(format, output, value, 16, false);
break;
case plFormat_Private::kDigitHexUpper: case plFormat_Private::kDigitHexUpper:
return _formatNumeric<wchar_t>(format, value, 16, true); _formatNumeric<wchar_t>(format, output,value, 16, true);
break;
case plFormat_Private::kDigitDec: case plFormat_Private::kDigitDec:
case plFormat_Private::kDigitDecAlwaysSigned: case plFormat_Private::kDigitDecAlwaysSigned:
return _formatDecimal<wchar_t>(format, value); _formatDecimal<wchar_t>(format, output, value);
break;
case plFormat_Private::kDigitChar: case plFormat_Private::kDigitChar:
case plFormat_Private::kDigitDefault: case plFormat_Private::kDigitDefault:
return _formatChar(format, value); _formatChar(format, output, value);
} break;
default:
hsAssert(0, "Unexpected digit class"); hsAssert(0, "Unexpected digit class");
return plStringBuffer<char>(); break;
}
static plStringBuffer<char> _formatString(const plFormat_Private::FormatSpec &format,
const plStringBuffer<char> &value)
{
char pad = format.fPadChar ? format.fPadChar : ' ';
if (format.fMinimumLength > value.GetSize()) {
plStringBuffer<char> buf;
char *output = buf.CreateWritableBuffer(format.fMinimumLength);
memset(output, pad, format.fMinimumLength);
if (format.fAlignment == plFormat_Private::kAlignRight) {
memcpy(output + (format.fMinimumLength - value.GetSize()),
value.GetData(), value.GetSize());
} else {
memcpy(output, value.GetData(), value.GetSize());
}
output[format.fMinimumLength] = 0;
return buf;
} }
return value;
} }
PL_FORMAT_IMPL(const char *) PL_FORMAT_IMPL(const char *)
{ {
return _formatString(format, plString(value).ToUtf8()); _formatString(format, output, value, strlen(value),
plFormat_Private::kAlignLeft);
} }
PL_FORMAT_IMPL(const wchar_t *) PL_FORMAT_IMPL(const wchar_t *)
{ {
return _formatString(format, plString::FromWchar(value).ToUtf8()); plStringBuffer<char> utf8 = plString::FromWchar(value).ToUtf8();
_formatString(format, output, utf8.GetData(), utf8.GetSize(),
plFormat_Private::kAlignLeft);
} }
PL_FORMAT_IMPL(const plString &) PL_FORMAT_IMPL(const plString &)
{ {
return _formatString(format, value.ToUtf8()); _formatString(format, output, value.c_str(), value.GetSize(),
plFormat_Private::kAlignLeft);
} }
PL_FORMAT_IMPL(const std::string &) PL_FORMAT_IMPL(const std::string &)
{ {
return _formatString(format, plStringBuffer<char>(value.c_str(), value.size())); _formatString(format, output, value.c_str(), value.size(),
plFormat_Private::kAlignLeft);
} }
PL_FORMAT_IMPL(const std::wstring &) PL_FORMAT_IMPL(const std::wstring &)
{ {
return _formatString(format, plString::FromWchar(value.c_str(), value.size()).ToUtf8()); plStringBuffer<char> utf8 = plString::FromWchar(value.c_str()).ToUtf8();
_formatString(format, output, utf8.GetData(), utf8.GetSize(),
plFormat_Private::kAlignLeft);
} }
PL_FORMAT_IMPL(bool) PL_FORMAT_IMPL(bool)
{ {
return PL_FORMAT_FORWARD(format, value ? "true" : "false"); PL_FORMAT_FORWARD(value ? "true" : "false");
} }

22
Sources/Plasma/CoreLib/plFormat.h

@ -128,7 +128,7 @@ namespace plFormat_Private
struct _IFormatDataObject struct _IFormatDataObject
{ {
const char *fFormatStr; const char *fFormatStr;
std::list<plStringBuffer<char>> fOutput; plStringStream fOutput;
}; };
extern FormatSpec _FetchNextFormat(_IFormatDataObject &data); extern FormatSpec _FetchNextFormat(_IFormatDataObject &data);
@ -140,8 +140,8 @@ namespace plFormat_Private
* \sa PL_FORMAT_IMPL() * \sa PL_FORMAT_IMPL()
*/ */
#define PL_FORMAT_TYPE(_type) \ #define PL_FORMAT_TYPE(_type) \
extern plStringBuffer<char> _impl_plFormat_DataHandler( \ extern void _impl_plFormat_DataHandler(const plFormat_Private::FormatSpec &, \
const plFormat_Private::FormatSpec &format, _type value); plStringStream &, _type);
/** Provide the implementation for a formattable type for `plFormat`. /** Provide the implementation for a formattable type for `plFormat`.
* \sa PL_FORMAT_TYPE(), PL_FORMAT_FORWARD() * \sa PL_FORMAT_TYPE(), PL_FORMAT_FORWARD()
@ -151,13 +151,13 @@ namespace plFormat_Private
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* PL_FORMAT_IMPL(const MyType &) * PL_FORMAT_IMPL(const MyType &)
* { * {
* return plFormat("MyType[data={},count={}]", value.data, value.count); * output << plFormat("MyType[data={},count={}]", value.data, value.count);
* } * }
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/ */
#define PL_FORMAT_IMPL(_type) \ #define PL_FORMAT_IMPL(_type) \
plStringBuffer<char> _impl_plFormat_DataHandler( \ void _impl_plFormat_DataHandler(const plFormat_Private::FormatSpec &format, \
const plFormat_Private::FormatSpec &format, _type value) plStringStream &output, _type value)
/** Shortcut to call another `PL_FORMAT_IMPL` formatter. /** Shortcut to call another `PL_FORMAT_IMPL` formatter.
* \sa PL_FORMAT_IMPL() * \sa PL_FORMAT_IMPL()
@ -167,12 +167,12 @@ namespace plFormat_Private
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* PL_FORMAT_IMPL(const MyType &) * PL_FORMAT_IMPL(const MyType &)
* { * {
* return PL_FORMAT_FORWARD(format, value.ToString()); * PL_FORMAT_FORWARD(value.ToString());
* } * }
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/ */
#define PL_FORMAT_FORWARD(format, fwd_value) \ #define PL_FORMAT_FORWARD(fwd_value) \
_impl_plFormat_DataHandler((format), (fwd_value)) _impl_plFormat_DataHandler(format, output, (fwd_value))
// ==================================== // ====================================
// BEGIN: Formattable type declarations // BEGIN: Formattable type declarations
@ -236,7 +236,7 @@ namespace plFormat_Private
plString _IFormat(_IFormatDataObject &data, _Type value, _Args... args) plString _IFormat(_IFormatDataObject &data, _Type value, _Args... args)
{ {
plFormat_Private::FormatSpec format = plFormat_Private::_FetchNextFormat(data); plFormat_Private::FormatSpec format = plFormat_Private::_FetchNextFormat(data);
data.fOutput.push_back(_impl_plFormat_DataHandler(format, value)); _impl_plFormat_DataHandler(format, data.fOutput, value);
return _IFormat(data, args...); return _IFormat(data, args...);
} }
} }
@ -247,7 +247,7 @@ plString plFormat(const char *fmt_str, _Type value, _Args... args)
plFormat_Private::_IFormatDataObject data; plFormat_Private::_IFormatDataObject data;
data.fFormatStr = fmt_str; data.fFormatStr = fmt_str;
plFormat_Private::FormatSpec format = plFormat_Private::_FetchNextFormat(data); plFormat_Private::FormatSpec format = plFormat_Private::_FetchNextFormat(data);
data.fOutput.push_back(_impl_plFormat_DataHandler(format, value)); _impl_plFormat_DataHandler(format, data.fOutput, value);
return plFormat_Private::_IFormat(data, args...); return plFormat_Private::_IFormat(data, args...);
} }

43
Sources/Plasma/CoreLib/plString.cpp

@ -867,29 +867,42 @@ plString operator+(const char *left, const plString &right)
return cat; return cat;
} }
#define EXPAND_BUFFER(addedLength) \
char *bufp = ICanHasHeap() ? fBuffer : fShort; \
\
if (fLength + addedLength > fBufSize) { \
size_t bigSize = fBufSize; \
do { \
bigSize *= 2; \
} while (fLength + addedLength > bigSize); \
\
char *bigger = new char[bigSize]; \
memcpy(bigger, GetRawBuffer(), fBufSize); \
if (ICanHasHeap()) \
delete [] fBuffer; \
fBuffer = bufp = bigger; \
fBufSize = bigSize; \
}
plStringStream &plStringStream::append(const char *data, size_t length) plStringStream &plStringStream::append(const char *data, size_t length)
{ {
char *bufp = ICanHasHeap() ? fBuffer : fShort; EXPAND_BUFFER(length)
if (fLength + length > fBufSize) {
size_t bigSize = fBufSize;
do {
bigSize *= 2;
} while (fLength + length > bigSize);
char *bigger = new char[bigSize];
memcpy(bigger, GetRawBuffer(), fBufSize);
if (ICanHasHeap())
delete [] fBuffer;
fBuffer = bufp = bigger;
fBufSize = bigSize;
}
memcpy(bufp + fLength, data, length); memcpy(bufp + fLength, data, length);
fLength += length; fLength += length;
return *this; return *this;
} }
plStringStream &plStringStream::appendChar(char ch, size_t count)
{
EXPAND_BUFFER(count)
memset(bufp + fLength, ch, count);
fLength += count;
return *this;
}
plStringStream &plStringStream::operator<<(const char *text) plStringStream &plStringStream::operator<<(const char *text)
{ {
size_t length = strlen(text); size_t length = strlen(text);

5
Sources/Plasma/CoreLib/plString.h

@ -677,6 +677,9 @@ public:
/** Append string data to the end of the stream. */ /** Append string data to the end of the stream. */
plStringStream &append(const char *data, size_t length); plStringStream &append(const char *data, size_t length);
/** Append a sequence of characters to the stream. */
plStringStream &appendChar(char ch, size_t count = 1);
/** Append UTF-8 C-style string data to the stream. */ /** Append UTF-8 C-style string data to the stream. */
plStringStream &operator<<(const char *text); plStringStream &operator<<(const char *text);
@ -693,7 +696,7 @@ public:
plStringStream &operator<<(double num); plStringStream &operator<<(double num);
/** Append a single Latin-1 character to the stream. */ /** Append a single Latin-1 character to the stream. */
plStringStream &operator<<(char ch) { return append(&ch, 1); } plStringStream &operator<<(char ch) { return appendChar(ch); }
/** Append the contents of \a text to the stream. */ /** Append the contents of \a text to the stream. */
plStringStream &operator<<(const plString &text) plStringStream &operator<<(const plString &text)

4
Sources/Plasma/NucleusLib/pnKeyedObject/plUoid.cpp

@ -119,7 +119,7 @@ plString plLocation::StringIze() const // Format to displayable string
PL_FORMAT_IMPL(const plLocation &) PL_FORMAT_IMPL(const plLocation &)
{ {
return PL_FORMAT_FORWARD(format, value.StringIze()); PL_FORMAT_FORWARD(value.StringIze());
} }
plLocation plLocation::MakeReserved(uint32_t number) plLocation plLocation::MakeReserved(uint32_t number)
@ -276,5 +276,5 @@ plString plUoid::StringIze() const // Format to displayable string
PL_FORMAT_IMPL(const plUoid &) PL_FORMAT_IMPL(const plUoid &)
{ {
return PL_FORMAT_FORWARD(format, value.StringIze()); PL_FORMAT_FORWARD(value.StringIze());
} }

2
Sources/Plasma/NucleusLib/pnUUID/pnUUID.cpp

@ -86,5 +86,5 @@ plString plUUID::AsString() const
PL_FORMAT_IMPL(const plUUID &) PL_FORMAT_IMPL(const plUUID &)
{ {
return PL_FORMAT_FORWARD(format, value.AsString()); PL_FORMAT_FORWARD(value.AsString());
} }

Loading…
Cancel
Save