Core: Optimize StringStream

This commit is contained in:
Lynix 2017-10-15 12:25:08 +02:00
parent a9307d5e7b
commit 9911c6e07c
2 changed files with 87 additions and 67 deletions

View File

@ -17,8 +17,8 @@ namespace Nz
class NAZARA_CORE_API StringStream
{
public:
StringStream();
StringStream(const String& str);
StringStream() = default;
StringStream(String str);
StringStream(const StringStream&) = default;
StringStream(StringStream&&) noexcept = default;
@ -53,8 +53,7 @@ namespace Nz
operator String() const;
private:
std::vector<String> m_strings;
std::size_t m_bufferSize;
String m_result;
};
}

View File

@ -3,6 +3,9 @@
// For conditions of distribution and use, see copyright notice in Config.hpp
#include <Nazara/Core/StringStream.hpp>
#include <Nazara/Math/Algorithm.hpp>
#include <array>
#include <limits>
#include <Nazara/Core/Debug.hpp>
namespace Nz
@ -13,23 +16,14 @@ namespace Nz
* \brief Core class that represents a stream of strings
*/
/*!
* \brief Constructs a StringStream object by default
*/
StringStream::StringStream() :
m_bufferSize(0)
{
}
/*!
* \brief Constructs a StringStream object with a string
*
* \param str First value of the stream
*/
StringStream::StringStream(const String& str) :
m_bufferSize(str.GetSize())
StringStream::StringStream(String str) :
m_result(std::move(str))
{
m_strings.push_back(str);
}
/*!
@ -37,8 +31,7 @@ namespace Nz
*/
void StringStream::Clear()
{
m_bufferSize = 0;
m_strings.clear();
m_result.Clear();
}
/*!
@ -47,7 +40,7 @@ namespace Nz
*/
std::size_t StringStream::GetBufferSize() const
{
return m_bufferSize;
return m_result.GetSize();
}
/*!
@ -56,13 +49,7 @@ namespace Nz
*/
String StringStream::ToString() const
{
String string;
string.Reserve(m_bufferSize);
for (const String& str : m_strings)
string += str;
return string;
return m_result;
}
/*!
@ -73,8 +60,10 @@ namespace Nz
*/
StringStream& StringStream::operator<<(bool boolean)
{
m_strings.push_back(String::Boolean(boolean));
m_bufferSize += m_strings.back().GetSize();
std::size_t size = (boolean) ? 4 : 5;
std::size_t start = m_result.GetSize();
m_result.Resize(start + size);
std::memcpy(&m_result[start], (boolean) ? "true" : "false", size);
return *this;
}
@ -87,8 +76,11 @@ namespace Nz
*/
StringStream& StringStream::operator<<(short number)
{
m_strings.push_back(String::Number(number));
m_bufferSize += m_strings.back().GetSize();
constexpr std::size_t maxSize = std::numeric_limits<short>::digits10 + 2;
std::size_t start = m_result.GetSize();
m_result.Resize(start + maxSize);
std::size_t written = std::snprintf(&m_result[start], maxSize + 1, "%hd", number);
m_result.Resize(start + written);
return *this;
}
@ -101,8 +93,11 @@ namespace Nz
*/
StringStream& StringStream::operator<<(unsigned short number)
{
m_strings.push_back(String::Number(number));
m_bufferSize += m_strings.back().GetSize();
constexpr std::size_t maxSize = std::numeric_limits<unsigned short>::digits10 + 1;
std::size_t start = m_result.GetSize();
m_result.Resize(start + maxSize);
std::size_t written = std::snprintf(&m_result[start], maxSize + 1, "%hu", number);
m_result.Resize(start + written);
return *this;
}
@ -115,8 +110,11 @@ namespace Nz
*/
StringStream& StringStream::operator<<(int number)
{
m_strings.push_back(String::Number(number));
m_bufferSize += m_strings.back().GetSize();
constexpr std::size_t maxSize = std::numeric_limits<int>::digits10 + 2;
std::size_t start = m_result.GetSize();
m_result.Resize(start + maxSize);
std::size_t written = std::snprintf(&m_result[start], maxSize + 1, "%d", number);
m_result.Resize(start + written);
return *this;
}
@ -129,8 +127,11 @@ namespace Nz
*/
StringStream& StringStream::operator<<(unsigned int number)
{
m_strings.push_back(String::Number(number));
m_bufferSize += m_strings.back().GetSize();
constexpr std::size_t maxSize = std::numeric_limits<unsigned int>::digits10 + 1;
std::size_t start = m_result.GetSize();
m_result.Resize(start + maxSize);
std::size_t written = std::snprintf(&m_result[start], maxSize + 1, "%u", number);
m_result.Resize(start + written);
return *this;
}
@ -143,8 +144,11 @@ namespace Nz
*/
StringStream& StringStream::operator<<(long number)
{
m_strings.push_back(String::Number(number));
m_bufferSize += m_strings.back().GetSize();
constexpr std::size_t maxSize = std::numeric_limits<long>::digits10 + 2;
std::size_t start = m_result.GetSize();
m_result.Resize(start + maxSize);
std::size_t written = std::snprintf(&m_result[start], maxSize + 1, "%ld", number);
m_result.Resize(start + written);
return *this;
}
@ -157,8 +161,12 @@ namespace Nz
*/
StringStream& StringStream::operator<<(unsigned long number)
{
m_strings.push_back(String::Number(number));
m_bufferSize += m_strings.back().GetSize();
constexpr std::size_t maxSize = std::numeric_limits<unsigned long>::digits10 + 1;
std::size_t start = m_result.GetSize();
m_result.Resize(start + maxSize);
std::size_t written = std::snprintf(&m_result[start], maxSize + 1, "%lu", number);
m_result.Resize(start + written);
return *this;
}
@ -171,8 +179,11 @@ namespace Nz
*/
StringStream& StringStream::operator<<(long long number)
{
m_strings.push_back(String::Number(number));
m_bufferSize += m_strings.back().GetSize();
constexpr std::size_t maxSize = std::numeric_limits<long long>::digits10 + 2;
std::size_t start = m_result.GetSize();
m_result.Resize(start + maxSize);
std::size_t written = std::snprintf(&m_result[start], maxSize + 1, "%lld", number);
m_result.Resize(start + written);
return *this;
}
@ -185,8 +196,11 @@ namespace Nz
*/
StringStream& StringStream::operator<<(unsigned long long number)
{
m_strings.push_back(String::Number(number));
m_bufferSize += m_strings.back().GetSize();
constexpr std::size_t maxSize = std::numeric_limits<unsigned long long>::digits10 + 1;
std::size_t start = m_result.GetSize();
m_result.Resize(start + maxSize);
std::size_t written = std::snprintf(&m_result[start], maxSize + 1, "%llu", number);
m_result.Resize(start + written);
return *this;
}
@ -199,10 +213,7 @@ namespace Nz
*/
StringStream& StringStream::operator<<(float number)
{
m_strings.push_back(String::Number(number));
m_bufferSize += m_strings.back().GetSize();
return *this;
return operator<<(double(number)); //< snprintf doesn't support float anyway
}
/*!
@ -213,8 +224,16 @@ namespace Nz
*/
StringStream& StringStream::operator<<(double number)
{
m_strings.push_back(String::Number(number));
m_bufferSize += m_strings.back().GetSize();
// https://stackoverflow.com/questions/1701055/what-is-the-maximum-length-in-chars-needed-to-represent-any-double-value
const std::size_t maxSize = 3 + std::numeric_limits<double>::digits - std::numeric_limits<double>::min_exponent;
// Use a temporary buffer to prevent 1kb string capacity growth
std::array<char, maxSize + 1> buffer;
std::size_t written = std::snprintf(buffer.data(), buffer.size(), "%f", number);
std::size_t start = m_result.GetSize();
m_result.Resize(start + written);
std::memcpy(&m_result[start], buffer.data(), written);
return *this;
}
@ -227,8 +246,16 @@ namespace Nz
*/
StringStream& StringStream::operator<<(long double number)
{
m_strings.push_back(String::Number(number));
m_bufferSize += m_strings.back().GetSize();
// https://stackoverflow.com/questions/1701055/what-is-the-maximum-length-in-chars-needed-to-represent-any-double-value
const std::size_t maxSize = 3 + std::numeric_limits<long double>::digits - std::numeric_limits<long double>::min_exponent;
// Use a temporary buffer to prevent 1kb string capacity growth
std::array<char, maxSize + 1> buffer;
std::size_t written = std::snprintf(buffer.data(), buffer.size(), "%f", number);
std::size_t start = m_result.GetSize();
m_result.Resize(start + written);
std::memcpy(&m_result[start], buffer.data(), written);
return *this;
}
@ -241,9 +268,7 @@ namespace Nz
*/
StringStream& StringStream::operator<<(char character)
{
m_strings.push_back(String(character));
m_bufferSize++;
m_result.Append(character);
return *this;
}
@ -255,9 +280,7 @@ namespace Nz
*/
StringStream& StringStream::operator<<(unsigned char character)
{
m_strings.push_back(String(static_cast<char>(character)));
m_bufferSize++;
m_result.Append(static_cast<unsigned char>(character));
return *this;
}
@ -269,9 +292,7 @@ namespace Nz
*/
StringStream& StringStream::operator<<(const char* string)
{
m_strings.push_back(string);
m_bufferSize += m_strings.back().GetSize();
m_result.Append(string);
return *this;
}
@ -283,9 +304,7 @@ namespace Nz
*/
StringStream& StringStream::operator<<(const std::string& string)
{
m_strings.push_back(string);
m_bufferSize += string.size();
m_result.Append(string.data(), string.size());
return *this;
}
@ -297,8 +316,7 @@ namespace Nz
*/
StringStream& StringStream::operator<<(const String& string)
{
m_strings.push_back(string);
m_bufferSize += string.GetSize();
m_result.Append(string);
return *this;
}
@ -311,8 +329,11 @@ namespace Nz
*/
StringStream& StringStream::operator<<(const void* ptr)
{
m_strings.push_back(String::Pointer(ptr));
m_bufferSize += m_strings.back().GetSize();
constexpr std::size_t maxSize = sizeof(void*) * 2 + 2;
std::size_t start = m_result.GetSize();
m_result.Resize(start + maxSize);
std::size_t written = std::snprintf(&m_result[start], maxSize + 1, "0x%p", ptr);
m_result.Resize(start + written);
return *this;
}