2
0
Эх сурвалжийг харах

CreateString and FormatString: No longer needs or uses the `max_size` argument

This improvement handles the size automatically, no need to specify this manually anymore. Public API will be changed in a follow-up.
Michael Ragazzon 1 жил өмнө
parent
commit
0f8c7073ca

+ 30 - 18
Source/Core/StringUtilities.cpp

@@ -37,23 +37,36 @@
 
 namespace Rml {
 
-static int FormatString(String& string, size_t max_size, const char* format, va_list argument_list)
+static int FormatString(String& string, const char* format, va_list argument_list)
 {
-	const int INTERNAL_BUFFER_SIZE = 1024;
-	static char buffer[INTERNAL_BUFFER_SIZE];
+	constexpr size_t InternalBufferSize = 256;
+	char buffer[InternalBufferSize];
 	char* buffer_ptr = buffer;
 
-	if (max_size + 1 > INTERNAL_BUFFER_SIZE)
-		buffer_ptr = new char[max_size + 1];
+	size_t max_size = InternalBufferSize;
+	int length = 0;
 
-	int length = vsnprintf(buffer_ptr, max_size, format, argument_list);
-	buffer_ptr[length >= 0 ? length : max_size] = '\0';
-#ifdef RMLUI_DEBUG
-	if (length == -1)
+	for (int i = 0; i < 2; i++)
 	{
-		Log::Message(Log::LT_WARNING, "FormatString: String truncated to %zu bytes when processing %s", max_size, format);
+		va_list argument_list_copy;
+		va_copy(argument_list_copy, argument_list);
+
+		length = vsnprintf(buffer_ptr, max_size, format, argument_list_copy);
+
+		va_end(argument_list_copy);
+
+		if (length < 0)
+		{
+			RMLUI_ERRORMSG("Error while formatting string");
+			return 0;
+		}
+
+		if ((size_t)length < max_size || i > 0)
+			break;
+
+		max_size = (size_t)length + 1;
+		buffer_ptr = new char[max_size];
 	}
-#endif
 
 	string = buffer_ptr;
 
@@ -63,21 +76,20 @@ static int FormatString(String& string, size_t max_size, const char* format, va_
 	return length;
 }
 
-int FormatString(String& string, size_t max_size, const char* format, ...)
+int FormatString(String& string, size_t /*max_size*/, const char* format, ...)
 {
 	va_list argument_list;
 	va_start(argument_list, format);
-	int result = FormatString(string, (int)max_size, format, argument_list);
+	int result = FormatString(string, format, argument_list);
 	va_end(argument_list);
 	return result;
 }
-String CreateString(size_t max_size, const char* format, ...)
+String CreateString(size_t /*max_size*/, const char* format, ...)
 {
 	String result;
-	result.reserve(max_size);
 	va_list argument_list;
 	va_start(argument_list, format);
-	FormatString(result, max_size, format, argument_list);
+	FormatString(result, format, argument_list);
 	va_end(argument_list);
 	return result;
 }
@@ -164,7 +176,7 @@ String StringUtilities::DecodeRml(const String& s)
 					size_t j = 0;
 					for (; j < 8; j++)
 					{
-						auto const& c = s[start + j];
+						const auto& c = s[start + j];
 						if (!((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')))
 							break;
 					}
@@ -188,7 +200,7 @@ String StringUtilities::DecodeRml(const String& s)
 					size_t j = 0;
 					for (; j < 8; j++)
 					{
-						auto const& c = s[start + j];
+						const auto& c = s[start + j];
 						if (!(c >= '0' && c <= '9'))
 							break;
 					}

+ 33 - 0
Tests/Source/UnitTests/StringUtilities.cpp

@@ -148,3 +148,36 @@ TEST_CASE("StringUtilities::ConvertCharacterOffsetToByteOffset")
 	CHECK(ConvertCharacterOffsetToByteOffset("a\xE2\x82\xAC" "b", 4) == 5);
 	// clang-format on
 }
+
+TEST_CASE("CreateString")
+{
+	CHECK(Rml::CreateString(0, "Hello %s!", "world") == "Hello world!");
+	CHECK(Rml::CreateString(0, "%g, %d, %.2f", 0.5f, 5, 2.f) == "0.5, 5, 2.00");
+
+	constexpr int InternalBufferSize = 256;
+	for (int string_size : {InternalBufferSize - 1, InternalBufferSize, InternalBufferSize + 1})
+	{
+		Rml::String large_string(string_size, 'x');
+		CHECK(Rml::CreateString(0, "%s", large_string.c_str()) == large_string);
+	}
+}
+
+TEST_CASE("FormatString")
+{
+	{
+		Rml::String result;
+		int length = Rml::FormatString(result, 0, "Hello %s!", "world");
+		CHECK(result == "Hello world!");
+		CHECK(length == 12);
+	}
+
+	constexpr int InternalBufferSize = 256;
+	for (int string_size : {InternalBufferSize - 1, InternalBufferSize, InternalBufferSize + 1})
+	{
+		const Rml::String large_string(string_size, 'x');
+		Rml::String result;
+		int length = Rml::FormatString(result, 0, "%s", large_string.c_str());
+		CHECK(result == large_string);
+		CHECK(length == string_size);
+	}
+}