Skip to content

Commit

Permalink
add DString.insert
Browse files Browse the repository at this point in the history
Signed-off-by: Pierre Curto <[email protected]>
  • Loading branch information
pierrec committed Oct 3, 2023
1 parent 2f93b2e commit fcac5dc
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 2 deletions.
36 changes: 34 additions & 2 deletions lib/std/core/dstring.c3
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ fn void DString.chop(self, usz new_size)

fn String DString.str_view(self)
{
StringData* data = (StringData*)self;
StringData* data = self.data();
if (!data) return "";
return (String)data.chars[:data.len];
}
Expand Down Expand Up @@ -267,7 +267,7 @@ fn Char32[] DString.copy_utf32(&self, Allocator* using = mem::heap())

fn void DString.append_string(&self, DString str)
{
StringData* other = (StringData*)str;
StringData* other = str.data();
if (!other) return;
self.append(str.str_view());
}
Expand Down Expand Up @@ -315,6 +315,38 @@ macro void DString.append(&self, value)
$endswitch
}

fn void DString.insert_at(&self, usz index, String s)
{
if (s.len == 0) return;
self.reserve(s.len);
StringData* data = self.data();
usz len = self.len();
if (data.chars[:len].ptr == s.ptr)
{
// Source and destination are the same: nothing to do.
return;
}
index = min(index, len);
data.len += s.len;

char* start = data.chars[index:s.len].ptr; // area to insert into
mem::move(start + s.len, start, len - index); // move existing data
switch
{
case s.ptr <= start && start < s.ptr + s.len:
// Overlapping areas.
foreach_r (i, c : s)
{
data.chars[index + i] = c;
}
case start <= s.ptr && s.ptr < start + s.len:
// Source has moved.
mem::move(start, s.ptr + s.len, s.len);
default:
mem::move(start, s, s.len);
}
}


fn usz! DString.printf(&self, String format, args...) @maydiscard
{
Expand Down
55 changes: 55 additions & 0 deletions test/unit/stdlib/core/dstring.c3
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
module std::core::dstring::tests @test;

fn void test_insert_at()
{
DString str = dstring::tnew(" world");
String s;

str.insert_at(0, "");
s = str.str_view();
assert(s == " world", "got '%s'; want ' world'", s);

str.insert_at(0, "hello");
s = str.str_view();
assert(s == "hello world", "got '%s'; want 'hello world'", s);

str.insert_at(5, " shiny");
s = str.str_view();
assert(s == "hello shiny world", "got '%s'; want 'hello shiny world'", s);
}

fn void test_insert_at_overlaps()
{
DString str = dstring::tnew("abc");
String s;
String v;

str.insert_at(0, "bc");
s = str.str_view();
assert(s == "bcabc", "got '%s'; want 'bcabc'", s);

// Inserted string is unchanged.
str.chop(0);
str.append("abc");
v = str.str_view();
str.insert_at(0, v);
s = str.str_view();
assert(s == "abc", "got '%s'; want 'abc'", s);

// Inserted string is part of the tail.
str.chop(0);
str.append("abc");
v = str.str_view()[1..];
assert(v == "bc");
str.insert_at(0, v);
s = str.str_view();
assert(s == "bcabc", "got '%s'; want 'bcabc'", s);

// Inserted string is part of the head.
str.chop(0);
str.append("abc");
v = str.str_view()[1..];
str.insert_at(2, v);
s = str.str_view();
assert(s == "abbcc", "got '%s'; want 'abbcc'", s);
}

0 comments on commit fcac5dc

Please sign in to comment.