diff --git a/src/string.cr b/src/string.cr index 9454f6d1ea03..61237013800f 100644 --- a/src/string.cr +++ b/src/string.cr @@ -143,10 +143,9 @@ require "c/string" # remove the offending byte sequences first. class String # :nodoc: - TYPE_ID = "".crystal_type_id - - # :nodoc: - HEADER_SIZE = sizeof({Int32, Int32, Int32}) + # + # Holds the offset to the first character byte. + HEADER_SIZE = offsetof(String, @c) include Comparable(self) @@ -266,9 +265,18 @@ class String str = GC.realloc(str, bytesize.to_u32 + HEADER_SIZE + 1) end - str_header = str.as({Int32, Int32, Int32}*) - str_header.value = {TYPE_ID, bytesize.to_i, size.to_i} - str.as(String) + set_crystal_type_id(str) + str = str.as(String) + str.initialize_header(bytesize.to_i, size.to_i) + str + end + + # :nodoc: + # + # Initializes the header information of a `String` instance. + # The actual character content at `@c` is expected to be already filled and is + # unaffected by this method. + def initialize_header(@bytesize : Int32, @length : Int32 = 0) end # Builds a `String` by creating a `String::Builder` with the given initial capacity, yielding diff --git a/src/string/builder.cr b/src/string/builder.cr index d1add8dc9be2..0fb77f4ca41b 100644 --- a/src/string/builder.cr +++ b/src/string/builder.cr @@ -14,7 +14,6 @@ class String::Builder < IO # Make sure to also be able to hold # the header size plus the trailing zero byte capacity += String::HEADER_SIZE + 1 - String.check_capacity_in_bounds(capacity) @buffer = GC.malloc_atomic(capacity.to_u32).as(UInt8*) @bytesize = 0 @@ -117,9 +116,10 @@ class String::Builder < IO resize_to_capacity(real_bytesize) end - header = @buffer.as({Int32, Int32, Int32}*) - header.value = {String::TYPE_ID, @bytesize - 1, 0} - @buffer.as(String) + String.set_crystal_type_id(@buffer) + str = @buffer.as(String) + str.initialize_header((bytesize - 1).to_i) + str end private def real_bytesize