forked from linkdotnet/StringBuilder
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathValueStringBuilder.Insert.cs
124 lines (106 loc) · 4.96 KB
/
ValueStringBuilder.Insert.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
using System.Runtime.CompilerServices;
using System.Text;
namespace LinkDotNet.StringBuilder;
public ref partial struct ValueStringBuilder
{
/// <summary>
/// Insert the string representation of the boolean to the builder at the given index.
/// </summary>
/// <param name="index">Index where <paramref name="value"/> should be inserted.</param>
/// <param name="value">Boolean to insert into this builder.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Insert(int index, bool value) => Insert(index, value.ToString());
/// <summary>
/// Insert the string representation of the character to the builder at the given index.
/// </summary>
/// <param name="index">Index where <paramref name="value"/> should be inserted.</param>
/// <param name="value">Character to insert into this builder.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Insert(int index, char value) => Insert(index, [value]);
/// <summary>
/// Insert the string representation of the rune to the builder at the given index.
/// </summary>
/// <param name="index">Index where <paramref name="value"/> should be inserted.</param>
/// <param name="value">Rune to insert into this builder.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Insert(int index, Rune value)
{
Span<char> valueChars = stackalloc char[2];
var valueCharsWritten = value.EncodeToUtf16(valueChars);
ReadOnlySpan<char> valueCharsSlice = valueChars[..valueCharsWritten];
Insert(index, valueCharsSlice);
}
/// <summary>
/// Insert the string representation of the char to the builder at the given index.
/// </summary>
/// <param name="index">Index where <paramref name="value"/> should be inserted.</param>
/// <param name="value">Formattable span to insert into this builder.</param>
/// <param name="format">Optional formatter. If not provided the default of the given instance is taken.</param>
/// <param name="bufferSize">Size of the buffer allocated on the stack.</param>
/// <typeparam name="T">Any <see cref="ISpanFormattable"/>.</typeparam>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Insert<T>(int index, T value, scoped ReadOnlySpan<char> format = default, int bufferSize = 36)
where T : ISpanFormattable => InsertSpanFormattable(index, value, format, bufferSize);
/// <summary>
/// Appends the string representation of the boolean to the builder.
/// </summary>
/// <param name="index">Index where <paramref name="value"/> should be inserted.</param>
/// <param name="value">String to insert into this builder.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Insert(int index, scoped ReadOnlySpan<char> value)
{
if (index < 0)
{
throw new ArgumentOutOfRangeException(nameof(index), "The given index can't be negative.");
}
if (index > bufferPosition)
{
throw new ArgumentOutOfRangeException(nameof(index), "The given index can't be bigger than the string itself.");
}
var newLength = bufferPosition + value.Length;
if (newLength > buffer.Length)
{
Grow(newLength);
}
bufferPosition = newLength;
// Move Slice at beginning index
var oldPosition = bufferPosition - value.Length;
var shift = index + value.Length;
buffer[index..oldPosition].CopyTo(buffer[shift..bufferPosition]);
// Add new word
value.CopyTo(buffer[index..shift]);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void InsertSpanFormattable<T>(int index, T value, scoped ReadOnlySpan<char> format, int bufferSize)
where T : ISpanFormattable
{
if (index < 0)
{
throw new ArgumentOutOfRangeException(nameof(index), "The given index can't be negative.");
}
if (index > bufferPosition)
{
throw new ArgumentOutOfRangeException(nameof(index), "The given index can't be bigger than the string itself.");
}
Span<char> tempBuffer = stackalloc char[bufferSize];
if (value.TryFormat(tempBuffer, out var written, format, null))
{
var newLength = bufferPosition + written;
if (newLength > buffer.Length)
{
Grow(newLength);
}
bufferPosition = newLength;
// Move Slice at beginning index
var oldPosition = bufferPosition - written;
var shift = index + written;
buffer[index..oldPosition].CopyTo(buffer[shift..bufferPosition]);
// Add new word
tempBuffer[..written].CopyTo(buffer[index..shift]);
}
else
{
throw new InvalidOperationException($"Could not insert {value} into given buffer. Is the buffer (size: {bufferSize}) large enough?");
}
}
}