-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathValueStringBuilder.Insert.cs
129 lines (110 loc) · 5.04 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
125
126
127
128
129
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.");
}
if (value.IsEmpty)
{
return;
}
var newLength = bufferPosition + value.Length;
if (newLength > buffer.Length)
{
EnsureCapacity(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)
{
EnsureCapacity(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?");
}
}
}