Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions ZString.sln
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ZString.Tests", "tests\ZStr
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PerfBenchmark", "sandbox\PerfBenchmark\PerfBenchmark.csproj", "{D766AEB3-3609-4F1D-8D81-5549F748F372}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ZString.NetTests", "tests\ZString.NetTests\ZString.NetTests.csproj", "{ED2423B1-0069-427B-B378-75BD8654F99E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -47,6 +49,10 @@ Global
{D766AEB3-3609-4F1D-8D81-5549F748F372}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D766AEB3-3609-4F1D-8D81-5549F748F372}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D766AEB3-3609-4F1D-8D81-5549F748F372}.Release|Any CPU.Build.0 = Release|Any CPU
{ED2423B1-0069-427B-B378-75BD8654F99E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ED2423B1-0069-427B-B378-75BD8654F99E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ED2423B1-0069-427B-B378-75BD8654F99E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ED2423B1-0069-427B-B378-75BD8654F99E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -56,6 +62,7 @@ Global
{9ADF67E1-1872-43D3-882E-607071726FE7} = {A7D7AA7D-9A79-48A8-978D-0C98EBD81ED0}
{62090C00-9727-4375-BE40-ABE2F4D41571} = {0803618F-C4E8-4D37-831E-5D26C5574F49}
{D766AEB3-3609-4F1D-8D81-5549F748F372} = {A7D7AA7D-9A79-48A8-978D-0C98EBD81ED0}
{ED2423B1-0069-427B-B378-75BD8654F99E} = {0803618F-C4E8-4D37-831E-5D26C5574F49}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {DF39BF43-3E0E-4F7D-9943-7E50D301234D}
Expand Down
163 changes: 161 additions & 2 deletions src/ZString.Unity/Assets/Scripts/ZString/Utf16ValueStringBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,30 @@ public void AppendLine(ReadOnlySpan<char> value)
AppendLine();
}

#if NET6_0_OR_GREATER
/// <summary>Appends a contiguous region of arbitrary memory to this instance.</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Append(ZStringInterpolatedStringHandler value)
{
AppendCore(value);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AppendLine(ZStringInterpolatedStringHandler value)
{
AppendCore(value);
AppendLine();
}

/// <summary>Appends a contiguous region of arbitrary memory to this instance.</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void AppendCore(ZStringInterpolatedStringHandler value)
{
value.GetString(ref this);
value.Dispose();
}
#endif

/// <summary>Appends the string representation of a specified value to this instance.</summary>
public void Append<T>(T value)
{
Expand Down Expand Up @@ -350,6 +374,53 @@ public void Insert(int index, ReadOnlySpan<char> value, int count)
this.index = newBufferIndex + remainLnegth;
}

#if NET6_0_OR_GREATER
public void Insert(int index, ZStringInterpolatedStringHandler value, int count)
{
if (count < 0)
{
ExceptionUtil.ThrowArgumentOutOfRangeException(nameof(count));
}

int currentLength = Length;
if ((uint)index > (uint)currentLength)
{
ExceptionUtil.ThrowArgumentOutOfRangeException(nameof(index));
}

if (value.Length == 0 || count == 0)
{
return;
}

var newSize = index + value.Length * count;
var newBuffer = ArrayPool<char>.Shared.Rent(Math.Max(DefaultBufferSize, newSize));

buffer.AsSpan(0, index).CopyTo(newBuffer);
int newBufferIndex = index;

for (int i = 0; i < count; i++)
{
value.CopyTo(newBuffer.AsSpan(newBufferIndex));
newBufferIndex += value.Length;
}

int remainLnegth = this.index - index;
buffer.AsSpan(index, remainLnegth).CopyTo(newBuffer.AsSpan(newBufferIndex));

if (buffer!.Length != ThreadStaticBufferSize)
{
if (buffer != null)
{
ArrayPool<char>.Shared.Return(buffer);
}
}

buffer = newBuffer;
this.index = newBufferIndex + remainLnegth;
}
#endif

/// <summary>
/// Replaces all instances of one character with another in this builder.
/// </summary>
Expand Down Expand Up @@ -401,6 +472,12 @@ public void Replace(char oldChar, char newChar, int startIndex, int count)

public void Replace(ReadOnlySpan<char> oldValue, ReadOnlySpan<char> newValue) => Replace(oldValue, newValue, 0, Length);

#if NET6_0_OR_GREATER
public void Replace(string oldValue, ZStringInterpolatedStringHandler newValue) => Replace(oldValue, newValue, 0, Length);

public void Replace(ReadOnlySpan<char> oldValue, ZStringInterpolatedStringHandler newValue) => Replace(oldValue, newValue, 0, Length);
#endif

/// <summary>
/// Replaces all instances of one string with another in part of this builder.
/// </summary>
Expand All @@ -422,6 +499,18 @@ public void Replace(string oldValue, string newValue, int startIndex, int count)
Replace(oldValue.AsSpan(), newValue.AsSpan(), startIndex, count);
}

#if NET6_0_OR_GREATER
public void Replace(string oldValue, ZStringInterpolatedStringHandler newValue, int startIndex, int count)
{
if (oldValue == null)
{
throw new ArgumentNullException(nameof(oldValue));
}

Replace(oldValue.AsSpan(), newValue, startIndex, count);
}
#endif

public void Replace(ReadOnlySpan<char> oldValue, ReadOnlySpan<char> newValue, int startIndex, int count)
{
int currentLength = Length;
Expand Down Expand Up @@ -489,7 +578,77 @@ public void Replace(ReadOnlySpan<char> oldValue, ReadOnlySpan<char> newValue, in
buffer = newBuffer;
index = newBufferIndex;
}


#if NET6_0_OR_GREATER
public void Replace(ReadOnlySpan<char> oldValue, ZStringInterpolatedStringHandler newValue, int startIndex, int count)
{
int currentLength = Length;

if ((uint)startIndex > (uint)currentLength)
{
ExceptionUtil.ThrowArgumentOutOfRangeException(nameof(startIndex));
}

if (count < 0 || startIndex > currentLength - count)
{
ExceptionUtil.ThrowArgumentOutOfRangeException(nameof(count));
}

if (oldValue.Length == 0)
{
throw new ArgumentException("oldValue.Length is 0", nameof(oldValue));
}

var readOnlySpan = AsSpan();
int endIndex = startIndex + count;
int matchCount = 0;

for (int i = startIndex; i < endIndex; i += oldValue.Length)
{
var span = readOnlySpan.Slice(i, endIndex - i);
var pos = span.IndexOf(oldValue, StringComparison.Ordinal);
if (pos == -1)
{
break;
}
i += pos;
matchCount++;
}

if (matchCount == 0)
return;

var newBuffer = ArrayPool<char>.Shared.Rent(Math.Max(DefaultBufferSize, Length + (newValue.Length - oldValue.Length) * matchCount));

buffer.AsSpan(0, startIndex).CopyTo(newBuffer);
int newBufferIndex = startIndex;

for (int i = startIndex; i < endIndex; i += oldValue.Length)
{
var span = readOnlySpan.Slice(i, endIndex - i);
var pos = span.IndexOf(oldValue, StringComparison.Ordinal);
if (pos == -1)
{
var remain = readOnlySpan.Slice(i);
remain.CopyTo(newBuffer.AsSpan(newBufferIndex));
newBufferIndex += remain.Length;
break;
}
readOnlySpan.Slice(i, pos).CopyTo(newBuffer.AsSpan(newBufferIndex));
newValue.CopyTo(newBuffer.AsSpan(newBufferIndex + pos));
newBufferIndex += pos + newValue.Length;
i += pos;
}

if (buffer!.Length != ThreadStaticBufferSize)
{
ArrayPool<char>.Shared.Return(buffer);
}
buffer = newBuffer;
index = newBufferIndex;
}
#endif

/// <summary>
/// Replaces the contents of a single position within the builder.
/// </summary>
Expand All @@ -502,7 +661,7 @@ public void ReplaceAt(char newChar, int replaceIndex)
{
ExceptionUtil.ThrowArgumentOutOfRangeException(nameof(replaceIndex));
}

buffer![replaceIndex] = newChar;
}

Expand Down
24 changes: 24 additions & 0 deletions src/ZString.Unity/Assets/Scripts/ZString/Utf8ValueStringBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,30 @@ public void AppendLine(ReadOnlySpan<char> value)
AppendLine();
}

#if NET6_0_OR_GREATER
/// <summary>Appends a contiguous region of arbitrary memory to this instance.</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Append(ZStringInterpolatedStringHandler value)
{
AppendCore(value);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AppendLine(ZStringInterpolatedStringHandler value)
{
AppendCore(value);
AppendLine();
}

/// <summary>Appends a contiguous region of arbitrary memory to this instance.</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void AppendCore(ZStringInterpolatedStringHandler value)
{
value.GetString(ref this);
value.Dispose();
}
#endif

public void AppendLiteral(ReadOnlySpan<byte> value)
{
if ((buffer!.Length - index) < value.Length)
Expand Down
Loading