From 2233f24c8fccce7354c963c0f3df5bf8fe894590 Mon Sep 17 00:00:00 2001 From: chri-k Date: Wed, 2 Oct 2024 11:22:59 +0300 Subject: [PATCH] Add variants of DString.insert_at to match .append (#1510) --- lib/std/core/dstring.c3 | 109 ++++++++++++++++++++++++++++++- releasenotes.md | 1 + test/unit/stdlib/core/dstring.c3 | 17 +++++ 3 files changed, 124 insertions(+), 3 deletions(-) diff --git a/lib/std/core/dstring.c3 b/lib/std/core/dstring.c3 index f37cd609d..4bc53855e 100644 --- a/lib/std/core/dstring.c3 +++ b/lib/std/core/dstring.c3 @@ -154,13 +154,15 @@ fn String DString.str_view(self) return (String)data.chars[:data.len]; } -fn void DString.append_utf32(&self, Char32[] chars) +fn usz DString.append_utf32(&self, Char32[] chars) { self.reserve(chars.len); + usz end = self.len(); foreach (Char32 c : chars) { self.append_char32(c); } + return self.data().len - end; } /** @@ -185,7 +187,7 @@ fn void DString.append_repeat(&self, char c, usz times) /** * @require c <= 0x10ffff */ -fn void DString.append_char32(&self, Char32 c) +fn usz DString.append_char32(&self, Char32 c) { char[4] buffer @noinit; char* p = &buffer; @@ -194,6 +196,7 @@ fn void DString.append_char32(&self, Char32 c) StringData* data = self.data(); data.chars[data.len:n] = buffer[:n]; data.len += n; + return n; } fn DString DString.tcopy(&self) => self.copy(allocator::temp()); @@ -387,7 +390,10 @@ macro void DString.append(&self, value) $endswitch } -fn void DString.insert_at(&self, usz index, String s) +/** + * @require index <= self.len() + **/ +fn void DString.insert_chars_at(&self, usz index, String s) { if (s.len == 0) return; self.reserve(s.len); @@ -419,6 +425,103 @@ fn void DString.insert_at(&self, usz index, String s) } } +/** + * @require index <= self.len() + **/ +fn void DString.insert_string_at(&self, usz index, DString str) +{ + StringData* other = str.data(); + if (!other) return; + self.insert_at(index, str.str_view()); +} + +/** + * @require index <= self.len() + **/ +fn void DString.insert_char_at(&self, usz index, char c) +{ + self.reserve(1); + StringData* data = self.data(); + + char* start = &data.chars[index]; + mem::move(start + 1, start, self.len() - index); + data.chars[index] = c; + data.len++; +} + +/** + * @require index <= self.len() + **/ +fn usz DString.insert_char32_at(&self, usz index, Char32 c) +{ + char[4] buffer @noinit; + char* p = &buffer; + usz n = conv::char32_to_utf8_unsafe(c, &p); + + self.reserve(n); + StringData* data = self.data(); + + char* start = &data.chars[index]; + mem::move(start + n, start, self.len() - index); + data.chars[index:n] = buffer[:n]; + data.len += n; + + return n; +} + +/** + * @require index <= self.len() + **/ +fn usz DString.insert_utf32_at(&self, usz index, Char32[] chars) +{ + usz n = conv::utf8len_for_utf32(chars); + + self.reserve(n); + StringData* data = self.data(); + + char* start = &data.chars[index]; + mem::move(start + n, start, self.len() - index); + + char[4] buffer @noinit; + + foreach(c : chars) + { + char* p = &buffer; + usz m = conv::char32_to_utf8_unsafe(c, &p); + data.chars[index:m] = buffer[:m]; + index += m; + } + + data.len += n; + + return n; +} + +macro void DString.insert_at(&self, usz index, value) +{ + var $Type = $typeof(value); + $switch ($Type) + $case char: + $case ichar: + self.insert_char_at(index, value); + $case DString: + self.insert_string_at(index, value); + $case String: + self.insert_chars_at(index, value); + $case Char32: + self.insert_char32_at(index, value); + $default: + $switch + $case $defined((Char32)value): + self.insert_char32_at(index, (Char32)value); + $case $defined((String)value): + self.insert_chars_at(index, (String)value); + $default: + $error "Unsupported type for insert"; + $endswitch + $endswitch +} + fn usz! DString.appendf(&self, String format, args...) @maydiscard { if (!self.data()) self.new_init(format.len + 20); diff --git a/releasenotes.md b/releasenotes.md index 91840d54a..33836fc45 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -83,6 +83,7 @@ - Added generic HMAC. - Added generic PBKDF2 implementation. - DString `reverse`. +- `DString.insert_at` now has variants for other types. ## 0.6.2 Change list diff --git a/test/unit/stdlib/core/dstring.c3 b/test/unit/stdlib/core/dstring.c3 index e9f9cb1eb..e7132bb81 100644 --- a/test/unit/stdlib/core/dstring.c3 +++ b/test/unit/stdlib/core/dstring.c3 @@ -184,6 +184,23 @@ fn void test_insert_at() str.insert_at(5, " shiny"); s = str.str_view(); assert(s == "hello shiny world", "got '%s'; want 'hello shiny world'", s); + + str.insert_at(0, '['); + s = str.str_view(); + assert(s == "[hello shiny world", "got '%s'; want '[hello shiny world'", s); + + str.insert_at(18, ']'); + s = str.str_view(); + assert(s == "[hello shiny world]", "got '%s'; want 'hello shiny world]'", s); + + str.insert_at(0, 'ꫩ'); + s = str.str_view(); + assert(s == "ꫩ[hello shiny world]", "got '%s'; want 'ꫩ[hello shiny world]'", s); + + // ꫩ is 3 bytes long + str.insert_utf32_at(4, {'寃', 't', 'e', 'x', 't', '¥'}); + s = str.str_view(); + assert(s == "ꫩ[寃text¥hello shiny world]", "got '%s'; want 'ꫩ[寃text¥hello shiny world]'", s); } fn void test_insert_at_overlaps()