From 69d7d2cd5d6984da763cd10576fa15008784230a Mon Sep 17 00:00:00 2001 From: Mikhail Tavarez Date: Fri, 31 May 2024 10:59:42 -0500 Subject: [PATCH] update slice builder --- gojo/strings/builder.mojo | 20 +++++++++++++++----- goodies/std.mojo | 2 +- tests/test_performance.mojo | 17 ++++++++++++----- tests/test_strings_stringbuilder.mojo | 6 +++--- 4 files changed, 31 insertions(+), 14 deletions(-) diff --git a/gojo/strings/builder.mojo b/gojo/strings/builder.mojo index 1660be1..b1e9143 100644 --- a/gojo/strings/builder.mojo +++ b/gojo/strings/builder.mojo @@ -134,7 +134,7 @@ struct StringBuilder(Stringable, Sized, io.Writer, io.ByteWriter, io.StringWrite @value -struct NewStringBuilder(Stringable, Sized): +struct NewStringBuilder[growth_factor: Float32 = 2](Stringable, Sized): """ A string builder class that allows for efficient string management and concatenation. This class is useful when you need to build a string by appending multiple strings @@ -164,6 +164,7 @@ struct NewStringBuilder(Stringable, Sized): @always_inline fn __init__(inout self, *, capacity: Int = 4096): + constrained[growth_factor >= 1.25]() self.data = DTypePointer[DType.uint8]().alloc(capacity) self.size = 0 self.capacity = capacity @@ -177,10 +178,19 @@ struct NewStringBuilder(Stringable, Sized): The string representation of the string builder. Returns an empty string if the string builder is empty. """ - var copy = DTypePointer[DType.uint8]().alloc(self.size + 1) + var copy = DTypePointer[DType.uint8]().alloc(self.size) memcpy(copy, self.data, self.size) - copy[self.size] = 0 - return StringRef(copy, self.size + 1) + return StringRef(copy, self.size) + + @always_inline + fn render(self: Reference[Self]) -> StringSlice[self.is_mutable, self.lifetime]: + """ + Return a StringSlice view of the data owned by the builder. + + Returns: + The string representation of the string builder. Returns an empty string if the string builder is empty. + """ + return StringSlice[self.is_mutable, self.lifetime](unsafe_from_utf8_strref=StringRef(self[].data, self[].size)) @always_inline fn __del__(owned self): @@ -212,7 +222,7 @@ struct NewStringBuilder(Stringable, Sized): src: The byte array to append. """ if len(src) > self.capacity - self.size: - self._resize(self.capacity * 2) + self._resize(int(self.capacity * growth_factor)) memcpy(self.data.offset(self.size), src._data, len(src)) self.size += len(src) diff --git a/goodies/std.mojo b/goodies/std.mojo index 5e48583..096e14e 100644 --- a/goodies/std.mojo +++ b/goodies/std.mojo @@ -39,7 +39,7 @@ struct STDWriter(Copyable, io.Writer, io.StringWriter): ) if write_count == -1: - return 0, Error("Failed to write to file descriptor " + String(self.fd)) + return 0, Error("Failed to write to file descriptor " + str(self.fd)) return write_count, Error() diff --git a/tests/test_performance.mojo b/tests/test_performance.mojo index 0a5ee29..7d2995f 100644 --- a/tests/test_performance.mojo +++ b/tests/test_performance.mojo @@ -9,7 +9,7 @@ fn test_string_builder() raises: # Create a string from the buffer var builder_write_start_time = now() var builder = StringBuilder() - for _ in range(100): + for _ in range(10000): _ = builder.write_string( "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod" " tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim" @@ -30,7 +30,7 @@ fn test_string_builder() raises: # Create a string from the buffer var new_builder_write_start_time = now() var new_builder = NewStringBuilder() - for _ in range(100): + for _ in range(10000): _ = new_builder.write_string( "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod" " tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim" @@ -47,10 +47,16 @@ fn test_string_builder() raises: var new_builder_execution_time = now() - new_builder_start_time print("NewStringBuilder buffer len", len(new_output), "\n") + var new_builder_render_start_time = now() + var new_output_render = str(new_builder.render()) + var new_builder_render_execution_time = now() - new_builder_render_start_time + print("NewStringBuilder buffer len", len(new_output_render), "\n") + # print(new_output_render) + # Create a string using the + operator print("Testing string concatenation performance") var vec = List[String]() - for i in range(100): + for i in range(10000): vec.append( "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod" " tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim" @@ -72,7 +78,7 @@ fn test_string_builder() raises: var buffer_write_start_time = now() print("Testing bytes buffer performance") var buf = buffer.new_buffer() - for i in range(100): + for i in range(10000): _ = buf.write_string( "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod" " tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim" @@ -92,11 +98,12 @@ fn test_string_builder() raises: print("\nWrite times:") print("StringBuilder:", "(", builder_write_execution_time, "ns)") print("NewStringBuilder:", "(", new_builder_write_execution_time, "ns)") - print("Bytes buffer write time:", "(", buffer_write_execution_time, "ns)", "\n") + print("Bytes buffer write time:", "(", buffer_write_execution_time, "ns)") print("\nExecution times:") print("StringBuilder:", "(", builder_execution_time, "ns)") print("NewStringBuilder:", "(", new_builder_execution_time, "ns)") + print("NewStringBuilder Render:", "(", new_builder_render_execution_time, "ns)") print("String concat:", "(", concat_execution_time, "ns)") print("Bytes Buffer:", "(", buffer_execution_time, "ns)") diff --git a/tests/test_strings_stringbuilder.mojo b/tests/test_strings_stringbuilder.mojo index f4f6304..b4ff00b 100644 --- a/tests/test_strings_stringbuilder.mojo +++ b/tests/test_strings_stringbuilder.mojo @@ -13,7 +13,7 @@ fn test_write_string() raises: _ = builder.write_string("Lorem ipsum dolor sit amet ") test.assert_equal( - String(builder), + str(builder), "Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet Lorem ipsum dolor sit amet ", ) @@ -24,7 +24,7 @@ fn test_write() raises: # Create a string from the builder by writing bytes to it. var builder = StringBuilder() _ = builder.write(String("Hello").as_bytes()) - test.assert_equal(String(builder), "Hello") + test.assert_equal(str(builder), "Hello") fn test_write_byte() raises: @@ -33,7 +33,7 @@ fn test_write_byte() raises: # Create a string from the builder by writing bytes to it. var builder = StringBuilder() _ = builder.write_byte(32) - test.assert_equal(String(builder), " ") + test.assert_equal(str(builder), " ") fn main() raises: