mirror of
https://github.com/OpenRCT2/OpenRCT2.git
synced 2025-01-22 18:31:59 -05:00
Replace std::stringstream with custom string buffer
This commit is contained in:
parent
5ae54eb9f9
commit
2ef4dd23aa
3 changed files with 217 additions and 101 deletions
|
@ -19,7 +19,7 @@
|
|||
|
||||
namespace OpenRCT2
|
||||
{
|
||||
static void FormatMonthYear(std::stringstream& ss, int32_t month, int32_t year);
|
||||
static void FormatMonthYear(FormatBuffer& ss, int32_t month, int32_t year);
|
||||
|
||||
static std::optional<int32_t> ParseNumericToken(std::string_view s)
|
||||
{
|
||||
|
@ -278,7 +278,7 @@ namespace OpenRCT2
|
|||
return sz != nullptr ? sz : std::string_view();
|
||||
}
|
||||
|
||||
void FormatRealName(std::stringstream& ss, rct_string_id id)
|
||||
void FormatRealName(FormatBuffer& ss, rct_string_id id)
|
||||
{
|
||||
if (IsRealNameStringId(id))
|
||||
{
|
||||
|
@ -301,7 +301,7 @@ namespace OpenRCT2
|
|||
}
|
||||
}
|
||||
|
||||
template<size_t TDecimalPlace, bool TDigitSep, typename T> void FormatNumber(std::stringstream& ss, T value)
|
||||
template<size_t TDecimalPlace, bool TDigitSep, typename T> void FormatNumber(FormatBuffer& ss, T value)
|
||||
{
|
||||
char buffer[32];
|
||||
size_t i = 0;
|
||||
|
@ -379,7 +379,7 @@ namespace OpenRCT2
|
|||
}
|
||||
}
|
||||
|
||||
template<size_t TDecimalPlace, bool TDigitSep, typename T> void FormatCurrency(std::stringstream& ss, T rawValue)
|
||||
template<size_t TDecimalPlace, bool TDigitSep, typename T> void FormatCurrency(FormatBuffer& ss, T rawValue)
|
||||
{
|
||||
auto currencyDesc = &CurrencyDescriptors[EnumValue(gConfigGeneral.currency_format)];
|
||||
auto value = static_cast<int64_t>(rawValue) * currencyDesc->rate;
|
||||
|
@ -434,7 +434,7 @@ namespace OpenRCT2
|
|||
}
|
||||
}
|
||||
|
||||
template<typename T> static void FormatMinutesSeconds(std::stringstream& ss, T value)
|
||||
template<typename T> static void FormatMinutesSeconds(FormatBuffer& ss, T value)
|
||||
{
|
||||
static constexpr const rct_string_id Formats[][2] = {
|
||||
{ STR_DURATION_SEC, STR_DURATION_SECS },
|
||||
|
@ -456,7 +456,7 @@ namespace OpenRCT2
|
|||
}
|
||||
}
|
||||
|
||||
template<typename T> static void FormatHoursMinutes(std::stringstream& ss, T value)
|
||||
template<typename T> static void FormatHoursMinutes(FormatBuffer& ss, T value)
|
||||
{
|
||||
static constexpr const rct_string_id Formats[][2] = {
|
||||
{ STR_REALTIME_MIN, STR_REALTIME_MINS },
|
||||
|
@ -478,7 +478,7 @@ namespace OpenRCT2
|
|||
}
|
||||
}
|
||||
|
||||
template<typename T> void FormatArgument(std::stringstream& ss, FormatToken token, T arg)
|
||||
template<typename T> void FormatArgument(FormatBuffer& ss, FormatToken token, T arg)
|
||||
{
|
||||
switch (token)
|
||||
{
|
||||
|
@ -625,12 +625,12 @@ namespace OpenRCT2
|
|||
}
|
||||
}
|
||||
|
||||
template void FormatArgument(std::stringstream&, FormatToken, uint16_t);
|
||||
template void FormatArgument(std::stringstream&, FormatToken, int16_t);
|
||||
template void FormatArgument(std::stringstream&, FormatToken, int32_t);
|
||||
template void FormatArgument(std::stringstream&, FormatToken, int64_t);
|
||||
template void FormatArgument(std::stringstream&, FormatToken, uint64_t);
|
||||
template void FormatArgument(std::stringstream&, FormatToken, const char*);
|
||||
template void FormatArgument(FormatBuffer&, FormatToken, uint16_t);
|
||||
template void FormatArgument(FormatBuffer&, FormatToken, int16_t);
|
||||
template void FormatArgument(FormatBuffer&, FormatToken, int32_t);
|
||||
template void FormatArgument(FormatBuffer&, FormatToken, int64_t);
|
||||
template void FormatArgument(FormatBuffer&, FormatToken, uint64_t);
|
||||
template void FormatArgument(FormatBuffer&, FormatToken, const char*);
|
||||
|
||||
bool IsRealNameStringId(rct_string_id id)
|
||||
{
|
||||
|
@ -643,27 +643,24 @@ namespace OpenRCT2
|
|||
return FmtString(fmtc);
|
||||
}
|
||||
|
||||
std::stringstream& GetThreadFormatStream()
|
||||
FormatBuffer& GetThreadFormatStream()
|
||||
{
|
||||
thread_local std::stringstream ss;
|
||||
// Reset the buffer (reported as most efficient way)
|
||||
std::stringstream().swap(ss);
|
||||
thread_local FormatBuffer ss;
|
||||
ss.clear();
|
||||
return ss;
|
||||
}
|
||||
|
||||
size_t CopyStringStreamToBuffer(char* buffer, size_t bufferLen, std::stringstream& ss)
|
||||
size_t CopyStringStreamToBuffer(char* buffer, size_t bufferLen, FormatBuffer& ss)
|
||||
{
|
||||
auto stringLen = ss.tellp();
|
||||
auto copyLen = std::min<size_t>(bufferLen - 1, stringLen);
|
||||
auto copyLen = std::min<size_t>(bufferLen - 1, ss.size());
|
||||
|
||||
ss.seekg(0, std::ios::beg);
|
||||
ss.read(buffer, copyLen);
|
||||
std::copy(ss.data(), ss.data() + copyLen, buffer);
|
||||
buffer[copyLen] = '\0';
|
||||
|
||||
return stringLen;
|
||||
return ss.size();
|
||||
}
|
||||
|
||||
static void FormatArgumentAny(std::stringstream& ss, FormatToken token, const FormatArg_t& value)
|
||||
static void FormatArgumentAny(FormatBuffer& ss, FormatToken token, const FormatArg_t& value)
|
||||
{
|
||||
if (std::holds_alternative<uint16_t>(value))
|
||||
{
|
||||
|
@ -687,8 +684,7 @@ namespace OpenRCT2
|
|||
}
|
||||
}
|
||||
|
||||
static void FormatStringAny(
|
||||
std::stringstream& ss, const FmtString& fmt, const std::vector<FormatArg_t>& args, size_t& argIndex)
|
||||
static void FormatStringAny(FormatBuffer& ss, const FmtString& fmt, const std::vector<FormatArg_t>& args, size_t& argIndex)
|
||||
{
|
||||
for (const auto& token : fmt)
|
||||
{
|
||||
|
@ -735,7 +731,7 @@ namespace OpenRCT2
|
|||
auto& ss = GetThreadFormatStream();
|
||||
size_t argIndex = 0;
|
||||
FormatStringAny(ss, fmt, args, argIndex);
|
||||
return ss.str();
|
||||
return ss.data();
|
||||
}
|
||||
|
||||
size_t FormatStringAny(char* buffer, size_t bufferLen, const FmtString& fmt, const std::vector<FormatArg_t>& args)
|
||||
|
@ -815,7 +811,7 @@ namespace OpenRCT2
|
|||
return FormatStringAny(buffer, bufferLen, fmt, anyArgs);
|
||||
}
|
||||
|
||||
static void FormatMonthYear(std::stringstream& ss, int32_t month, int32_t year)
|
||||
static void FormatMonthYear(FormatBuffer& ss, int32_t month, int32_t year)
|
||||
{
|
||||
thread_local std::vector<FormatArg_t> tempArgs;
|
||||
tempArgs.clear();
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "FormatCodes.h"
|
||||
#include "Language.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <stack>
|
||||
#include <string>
|
||||
|
@ -23,6 +24,114 @@
|
|||
|
||||
namespace OpenRCT2
|
||||
{
|
||||
template<typename T, size_t (*LenFn)(const T*), size_t StackSize = 256> class FormatBufferBase
|
||||
{
|
||||
T _storage[StackSize];
|
||||
T* _buffer;
|
||||
size_t _size;
|
||||
// NOTE: Capacity is on purpose uint32_t to have a fixed position for the flag on each architecture.
|
||||
uint32_t _capacity;
|
||||
|
||||
static constexpr uint32_t FlagLocalStorage = (1u << 31);
|
||||
|
||||
public:
|
||||
explicit FormatBufferBase()
|
||||
: _storage{}
|
||||
, _buffer(_storage)
|
||||
, _size{}
|
||||
, _capacity(FlagLocalStorage | static_cast<uint32_t>(std::size(_storage)))
|
||||
{
|
||||
}
|
||||
|
||||
~FormatBufferBase()
|
||||
{
|
||||
if (_capacity & FlagLocalStorage)
|
||||
return;
|
||||
delete[] _buffer;
|
||||
}
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
return _size;
|
||||
}
|
||||
|
||||
size_t capacity() const
|
||||
{
|
||||
return _capacity & ~FlagLocalStorage;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
_size = 0;
|
||||
_buffer[0] = T{};
|
||||
}
|
||||
|
||||
const T* data() const
|
||||
{
|
||||
return _buffer;
|
||||
}
|
||||
|
||||
T* data()
|
||||
{
|
||||
return _buffer;
|
||||
}
|
||||
|
||||
auto& operator<<(const T* v)
|
||||
{
|
||||
if (!v)
|
||||
return *this;
|
||||
|
||||
append(v, LenFn(v));
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto& operator<<(const T v)
|
||||
{
|
||||
append(&v, 1);
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto& operator<<(const std::basic_string_view<T> v)
|
||||
{
|
||||
append(v.data(), v.size());
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
void append(const T* buf, size_t len)
|
||||
{
|
||||
ensure_capacity(len);
|
||||
|
||||
std::copy(buf, buf + len, _buffer + _size);
|
||||
|
||||
_size += len;
|
||||
_buffer[_size] = T{};
|
||||
}
|
||||
|
||||
void ensure_capacity(size_t additionalSize)
|
||||
{
|
||||
const size_t curSize = size();
|
||||
const size_t curCapacity = capacity();
|
||||
const bool isLocalStorage = _capacity & FlagLocalStorage;
|
||||
|
||||
if (curSize + additionalSize < curCapacity)
|
||||
return;
|
||||
|
||||
const size_t newCapacity = (curCapacity + additionalSize + 1) << 1;
|
||||
|
||||
T* newBuf = new T[newCapacity];
|
||||
std::copy(_buffer, _buffer + curSize, newBuf);
|
||||
|
||||
if (!isLocalStorage)
|
||||
delete[] _buffer;
|
||||
|
||||
_capacity = static_cast<uint32_t>(newCapacity);
|
||||
_buffer = newBuf;
|
||||
}
|
||||
};
|
||||
|
||||
using FormatBuffer = FormatBufferBase<char, strlen>;
|
||||
|
||||
using FormatArg_t = std::variant<uint16_t, int32_t, const char*, std::string>;
|
||||
|
||||
class FmtString
|
||||
|
@ -76,15 +185,15 @@ namespace OpenRCT2
|
|||
std::string WithoutFormatTokens() const;
|
||||
};
|
||||
|
||||
template<typename T> void FormatArgument(std::stringstream& ss, FormatToken token, T arg);
|
||||
template<typename T> void FormatArgument(FormatBuffer& ss, FormatToken token, T arg);
|
||||
|
||||
bool IsRealNameStringId(rct_string_id id);
|
||||
void FormatRealName(std::stringstream& ss, rct_string_id id);
|
||||
void FormatRealName(FormatBuffer& ss, rct_string_id id);
|
||||
FmtString GetFmtStringById(rct_string_id id);
|
||||
std::stringstream& GetThreadFormatStream();
|
||||
size_t CopyStringStreamToBuffer(char* buffer, size_t bufferLen, std::stringstream& ss);
|
||||
FormatBuffer& GetThreadFormatStream();
|
||||
size_t CopyStringStreamToBuffer(char* buffer, size_t bufferLen, FormatBuffer& ss);
|
||||
|
||||
inline void FormatString(std::stringstream& ss, std::stack<FmtString::iterator>& stack)
|
||||
inline void FormatString(FormatBuffer& ss, std::stack<FmtString::iterator>& stack)
|
||||
{
|
||||
while (!stack.empty())
|
||||
{
|
||||
|
@ -103,7 +212,7 @@ namespace OpenRCT2
|
|||
}
|
||||
|
||||
template<typename TArg0, typename... TArgs>
|
||||
static void FormatString(std::stringstream& ss, std::stack<FmtString::iterator>& stack, TArg0 arg0, TArgs&&... argN)
|
||||
static void FormatString(FormatBuffer& ss, std::stack<FmtString::iterator>& stack, TArg0 arg0, TArgs&&... argN)
|
||||
{
|
||||
while (!stack.empty())
|
||||
{
|
||||
|
@ -144,7 +253,7 @@ namespace OpenRCT2
|
|||
}
|
||||
}
|
||||
|
||||
template<typename... TArgs> static void FormatString(std::stringstream& ss, const FmtString& fmt, TArgs&&... argN)
|
||||
template<typename... TArgs> static void FormatString(FormatBuffer& ss, const FmtString& fmt, TArgs&&... argN)
|
||||
{
|
||||
std::stack<FmtString::iterator> stack;
|
||||
stack.push(fmt.begin());
|
||||
|
@ -155,7 +264,7 @@ namespace OpenRCT2
|
|||
{
|
||||
auto& ss = GetThreadFormatStream();
|
||||
FormatString(ss, fmt, argN...);
|
||||
return ss.str();
|
||||
return ss.data();
|
||||
}
|
||||
|
||||
template<typename... TArgs>
|
||||
|
@ -166,7 +275,7 @@ namespace OpenRCT2
|
|||
return CopyStringStreamToBuffer(buffer, bufferLen, ss);
|
||||
}
|
||||
|
||||
template<typename... TArgs> static void FormatStringId(std::stringstream& ss, rct_string_id id, TArgs&&... argN)
|
||||
template<typename... TArgs> static void FormatStringId(FormatBuffer& ss, rct_string_id id, TArgs&&... argN)
|
||||
{
|
||||
auto fmt = GetFmtStringById(id);
|
||||
FormatString(ss, fmt, argN...);
|
||||
|
|
|
@ -341,260 +341,260 @@ TEST_F(FormattingTests, using_legacy_buffer_args)
|
|||
|
||||
TEST_F(FormattingTests, format_number_basic)
|
||||
{
|
||||
std::stringstream ss;
|
||||
FormatBuffer ss;
|
||||
// test basic integral conversion
|
||||
FormatArgument<int32_t>(ss, FormatToken::UInt16, 123);
|
||||
ASSERT_STREQ("123", ss.str().c_str());
|
||||
ASSERT_STREQ("123", ss.data());
|
||||
}
|
||||
|
||||
TEST_F(FormattingTests, format_number_basic_int32)
|
||||
{
|
||||
std::stringstream ss;
|
||||
FormatBuffer ss;
|
||||
// test that case fallthrough works
|
||||
FormatArgument<int32_t>(ss, FormatToken::Int32, 123);
|
||||
ASSERT_STREQ("123", ss.str().c_str());
|
||||
ASSERT_STREQ("123", ss.data());
|
||||
}
|
||||
|
||||
TEST_F(FormattingTests, format_number_negative)
|
||||
{
|
||||
std::stringstream ss;
|
||||
FormatBuffer ss;
|
||||
// test negative conversion
|
||||
FormatArgument<int32_t>(ss, FormatToken::Int32, -123);
|
||||
ASSERT_STREQ("-123", ss.str().c_str());
|
||||
ASSERT_STREQ("-123", ss.data());
|
||||
}
|
||||
|
||||
TEST_F(FormattingTests, format_number_comma16_basic)
|
||||
{
|
||||
std::stringstream ss;
|
||||
FormatBuffer ss;
|
||||
// test separator formatter
|
||||
// test base case separator formatter
|
||||
FormatArgument<int32_t>(ss, FormatToken::Comma16, 123);
|
||||
ASSERT_STREQ("123", ss.str().c_str());
|
||||
ASSERT_STREQ("123", ss.data());
|
||||
}
|
||||
|
||||
TEST_F(FormattingTests, format_number_comma16_negative)
|
||||
{
|
||||
std::stringstream ss;
|
||||
FormatBuffer ss;
|
||||
// test separator formatter
|
||||
// test base case separator formatter
|
||||
FormatArgument<int32_t>(ss, FormatToken::Comma16, -123);
|
||||
ASSERT_STREQ("-123", ss.str().c_str());
|
||||
ASSERT_STREQ("-123", ss.data());
|
||||
}
|
||||
|
||||
TEST_F(FormattingTests, format_number_comma16_large)
|
||||
{
|
||||
std::stringstream ss;
|
||||
FormatBuffer ss;
|
||||
// test larger value for separator formatter
|
||||
FormatArgument<int32_t>(ss, FormatToken::Comma16, 123456789);
|
||||
ASSERT_STREQ("123,456,789", ss.str().c_str());
|
||||
ASSERT_STREQ("123,456,789", ss.data());
|
||||
}
|
||||
|
||||
TEST_F(FormattingTests, format_number_comma16_large_negative)
|
||||
{
|
||||
std::stringstream ss;
|
||||
FormatBuffer ss;
|
||||
// test larger value for separator formatter with negative
|
||||
FormatArgument<int32_t>(ss, FormatToken::Comma16, -123456789);
|
||||
ASSERT_STREQ("-123,456,789", ss.str().c_str());
|
||||
ASSERT_STREQ("-123,456,789", ss.data());
|
||||
}
|
||||
|
||||
TEST_F(FormattingTests, format_number_comma16_uneven)
|
||||
{
|
||||
std::stringstream ss;
|
||||
FormatBuffer ss;
|
||||
// test non-multiple of 3
|
||||
FormatArgument<int32_t>(ss, FormatToken::Comma16, 12345678);
|
||||
ASSERT_STREQ("12,345,678", ss.str().c_str());
|
||||
ASSERT_STREQ("12,345,678", ss.data());
|
||||
}
|
||||
|
||||
TEST_F(FormattingTests, format_number_comma16_uneven_negative)
|
||||
{
|
||||
std::stringstream ss;
|
||||
FormatBuffer ss;
|
||||
// test non-multiple of 3 with negative
|
||||
FormatArgument<int32_t>(ss, FormatToken::Comma16, -12345678);
|
||||
ASSERT_STREQ("-12,345,678", ss.str().c_str());
|
||||
ASSERT_STREQ("-12,345,678", ss.data());
|
||||
}
|
||||
|
||||
TEST_F(FormattingTests, format_number_comma16_zero)
|
||||
{
|
||||
std::stringstream ss;
|
||||
FormatBuffer ss;
|
||||
// test zero
|
||||
FormatArgument<int32_t>(ss, FormatToken::Comma16, 0);
|
||||
ASSERT_STREQ("0", ss.str().c_str());
|
||||
ASSERT_STREQ("0", ss.data());
|
||||
}
|
||||
|
||||
TEST_F(FormattingTests, format_number_comma1dp16_zero)
|
||||
{
|
||||
std::stringstream ss;
|
||||
FormatBuffer ss;
|
||||
// zero case
|
||||
FormatArgument<int32_t>(ss, FormatToken::Comma1dp16, 0);
|
||||
ASSERT_STREQ("0.0", ss.str().c_str());
|
||||
ASSERT_STREQ("0.0", ss.data());
|
||||
}
|
||||
|
||||
TEST_F(FormattingTests, format_number_comma1dp16_leading_zero)
|
||||
{
|
||||
std::stringstream ss;
|
||||
FormatBuffer ss;
|
||||
// test leading zero
|
||||
FormatArgument<int32_t>(ss, FormatToken::Comma1dp16, 5);
|
||||
ASSERT_STREQ("0.5", ss.str().c_str());
|
||||
ASSERT_STREQ("0.5", ss.data());
|
||||
}
|
||||
|
||||
TEST_F(FormattingTests, format_number_comma1dp16_leading_zero_negative)
|
||||
{
|
||||
std::stringstream ss;
|
||||
FormatBuffer ss;
|
||||
// test leading zero with negative value
|
||||
FormatArgument<int32_t>(ss, FormatToken::Comma1dp16, -5);
|
||||
ASSERT_STREQ("-0.5", ss.str().c_str());
|
||||
ASSERT_STREQ("-0.5", ss.data());
|
||||
}
|
||||
|
||||
TEST_F(FormattingTests, format_number_comma1dp16_small_value)
|
||||
{
|
||||
std::stringstream ss;
|
||||
FormatBuffer ss;
|
||||
// test small value
|
||||
FormatArgument<int32_t>(ss, FormatToken::Comma1dp16, 75);
|
||||
ASSERT_STREQ("7.5", ss.str().c_str());
|
||||
ASSERT_STREQ("7.5", ss.data());
|
||||
}
|
||||
|
||||
TEST_F(FormattingTests, format_number_comma1dp16_small_value_negative)
|
||||
{
|
||||
std::stringstream ss;
|
||||
FormatBuffer ss;
|
||||
// test small value with negative
|
||||
FormatArgument<int32_t>(ss, FormatToken::Comma1dp16, -75);
|
||||
ASSERT_STREQ("-7.5", ss.str().c_str());
|
||||
ASSERT_STREQ("-7.5", ss.data());
|
||||
}
|
||||
|
||||
TEST_F(FormattingTests, format_number_comma1dp16_trailing_zeros)
|
||||
{
|
||||
std::stringstream ss;
|
||||
FormatBuffer ss;
|
||||
// test value with trailing zero, no commas
|
||||
FormatArgument<int32_t>(ss, FormatToken::Comma1dp16, 1000);
|
||||
ASSERT_STREQ("100.0", ss.str().c_str());
|
||||
ASSERT_STREQ("100.0", ss.data());
|
||||
}
|
||||
|
||||
TEST_F(FormattingTests, format_number_comma1dp16_trailing_zeros_negative)
|
||||
{
|
||||
std::stringstream ss;
|
||||
FormatBuffer ss;
|
||||
// test value with trailing zero, no commas
|
||||
FormatArgument<int32_t>(ss, FormatToken::Comma1dp16, -1000);
|
||||
ASSERT_STREQ("-100.0", ss.str().c_str());
|
||||
ASSERT_STREQ("-100.0", ss.data());
|
||||
}
|
||||
|
||||
TEST_F(FormattingTests, format_number_comma1dp16_large_trailing_zeros)
|
||||
{
|
||||
std::stringstream ss;
|
||||
FormatBuffer ss;
|
||||
// test value with commas and trailing zeros
|
||||
FormatArgument<int32_t>(ss, FormatToken::Comma1dp16, 10000000);
|
||||
ASSERT_STREQ("1,000,000.0", ss.str().c_str());
|
||||
ASSERT_STREQ("1,000,000.0", ss.data());
|
||||
}
|
||||
|
||||
TEST_F(FormattingTests, format_number_comma1dp16_large_trailing_zeros_negative)
|
||||
{
|
||||
std::stringstream ss;
|
||||
FormatBuffer ss;
|
||||
// test value with commas and trailing zeros
|
||||
FormatArgument<int32_t>(ss, FormatToken::Comma1dp16, -10000000);
|
||||
ASSERT_STREQ("-1,000,000.0", ss.str().c_str());
|
||||
ASSERT_STREQ("-1,000,000.0", ss.data());
|
||||
}
|
||||
|
||||
TEST_F(FormattingTests, format_number_comma1dp16_large_value)
|
||||
{
|
||||
std::stringstream ss;
|
||||
FormatBuffer ss;
|
||||
// test large value
|
||||
FormatArgument<int32_t>(ss, FormatToken::Comma1dp16, 123456789);
|
||||
ASSERT_STREQ("12,345,678.9", ss.str().c_str());
|
||||
ASSERT_STREQ("12,345,678.9", ss.data());
|
||||
}
|
||||
|
||||
TEST_F(FormattingTests, format_number_comma1dp16_large_value_negative)
|
||||
{
|
||||
std::stringstream ss;
|
||||
FormatBuffer ss;
|
||||
// test large value
|
||||
FormatArgument<int32_t>(ss, FormatToken::Comma1dp16, -123456789);
|
||||
ASSERT_STREQ("-12,345,678.9", ss.str().c_str());
|
||||
ASSERT_STREQ("-12,345,678.9", ss.data());
|
||||
}
|
||||
|
||||
TEST_F(FormattingTests, format_number_comma2dp32_zero)
|
||||
{
|
||||
std::stringstream ss;
|
||||
FormatBuffer ss;
|
||||
// zero case
|
||||
FormatArgument<int32_t>(ss, FormatToken::Comma2dp32, 0);
|
||||
ASSERT_STREQ("0.00", ss.str().c_str());
|
||||
ASSERT_STREQ("0.00", ss.data());
|
||||
}
|
||||
|
||||
TEST_F(FormattingTests, format_number_comma2dp32_less_sig_figs)
|
||||
{
|
||||
std::stringstream ss;
|
||||
FormatBuffer ss;
|
||||
// test leading zero
|
||||
FormatArgument<int32_t>(ss, FormatToken::Comma2dp32, 5);
|
||||
ASSERT_STREQ("0.05", ss.str().c_str());
|
||||
ASSERT_STREQ("0.05", ss.data());
|
||||
}
|
||||
|
||||
TEST_F(FormattingTests, format_number_comma2dp32_less_sig_figs_negative)
|
||||
{
|
||||
std::stringstream ss;
|
||||
FormatBuffer ss;
|
||||
// test leading zero
|
||||
FormatArgument<int32_t>(ss, FormatToken::Comma2dp32, -5);
|
||||
ASSERT_STREQ("-0.05", ss.str().c_str());
|
||||
ASSERT_STREQ("-0.05", ss.data());
|
||||
}
|
||||
|
||||
TEST_F(FormattingTests, format_number_comma2dp32_leading_zero)
|
||||
{
|
||||
std::stringstream ss;
|
||||
FormatBuffer ss;
|
||||
// test small value
|
||||
FormatArgument<int32_t>(ss, FormatToken::Comma2dp32, 75);
|
||||
ASSERT_STREQ("0.75", ss.str().c_str());
|
||||
ASSERT_STREQ("0.75", ss.data());
|
||||
}
|
||||
|
||||
TEST_F(FormattingTests, format_number_comma2dp32_leading_zero_negative)
|
||||
{
|
||||
std::stringstream ss;
|
||||
FormatBuffer ss;
|
||||
// test small value
|
||||
FormatArgument<int32_t>(ss, FormatToken::Comma2dp32, -75);
|
||||
ASSERT_STREQ("-0.75", ss.str().c_str());
|
||||
ASSERT_STREQ("-0.75", ss.data());
|
||||
}
|
||||
|
||||
TEST_F(FormattingTests, format_number_comma2dp32_trailing_zeros)
|
||||
{
|
||||
std::stringstream ss;
|
||||
FormatBuffer ss;
|
||||
// test value with trailing zero, no commas
|
||||
FormatArgument<int32_t>(ss, FormatToken::Comma2dp32, 1000);
|
||||
ASSERT_STREQ("10.00", ss.str().c_str());
|
||||
ASSERT_STREQ("10.00", ss.data());
|
||||
}
|
||||
|
||||
TEST_F(FormattingTests, format_number_comma2dp32_trailing_zeros_negative)
|
||||
{
|
||||
std::stringstream ss;
|
||||
FormatBuffer ss;
|
||||
// test value with trailing zero, no commas
|
||||
FormatArgument<int32_t>(ss, FormatToken::Comma2dp32, -1000);
|
||||
ASSERT_STREQ("-10.00", ss.str().c_str());
|
||||
ASSERT_STREQ("-10.00", ss.data());
|
||||
}
|
||||
|
||||
TEST_F(FormattingTests, format_number_comma2dp32_large_trailing_zeros)
|
||||
{
|
||||
std::stringstream ss;
|
||||
FormatBuffer ss;
|
||||
// test value with commas and trailing zeros
|
||||
FormatArgument<int32_t>(ss, FormatToken::Comma2dp32, 10000000);
|
||||
ASSERT_STREQ("100,000.00", ss.str().c_str());
|
||||
ASSERT_STREQ("100,000.00", ss.data());
|
||||
}
|
||||
|
||||
TEST_F(FormattingTests, format_number_comma2dp32_large_trailing_zeros_negative)
|
||||
{
|
||||
std::stringstream ss;
|
||||
FormatBuffer ss;
|
||||
// test value with commas and trailing zeros
|
||||
FormatArgument<int32_t>(ss, FormatToken::Comma2dp32, -10000000);
|
||||
ASSERT_STREQ("-100,000.00", ss.str().c_str());
|
||||
ASSERT_STREQ("-100,000.00", ss.data());
|
||||
}
|
||||
|
||||
TEST_F(FormattingTests, format_number_comma2dp32_large_value)
|
||||
{
|
||||
std::stringstream ss;
|
||||
FormatBuffer ss;
|
||||
// test large value
|
||||
FormatArgument<int32_t>(ss, FormatToken::Comma2dp32, 123456789);
|
||||
ASSERT_STREQ("1,234,567.89", ss.str().c_str());
|
||||
ASSERT_STREQ("1,234,567.89", ss.data());
|
||||
}
|
||||
|
||||
TEST_F(FormattingTests, format_number_comma2dp32_large_value_negative)
|
||||
{
|
||||
std::stringstream ss;
|
||||
FormatBuffer ss;
|
||||
// test large value
|
||||
FormatArgument<int32_t>(ss, FormatToken::Comma2dp32, -123456789);
|
||||
ASSERT_STREQ("-1,234,567.89", ss.str().c_str());
|
||||
ASSERT_STREQ("-1,234,567.89", ss.data());
|
||||
|
||||
// extra note:
|
||||
// for some reason the FormatArgument function contains constexpr
|
||||
|
@ -604,3 +604,14 @@ TEST_F(FormattingTests, format_number_comma2dp32_large_value_negative)
|
|||
// the necessary symbol to link with.
|
||||
// FormatArgument<double>(ss, FormatToken::Comma1dp16, 12.372);
|
||||
}
|
||||
|
||||
TEST_F(FormattingTests, buffer_storage_swap)
|
||||
{
|
||||
FormatBufferBase<char, strlen, 16> ss;
|
||||
ss << "Hello World";
|
||||
ASSERT_STREQ(ss.data(), "Hello World");
|
||||
ss << ", Exceeding local storage";
|
||||
ASSERT_STREQ(ss.data(), "Hello World, Exceeding local storage");
|
||||
ss << ", extended";
|
||||
ASSERT_STREQ(ss.data(), "Hello World, Exceeding local storage, extended");
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue