1+ namespace LinkDotNet . StringBuilder ;
2+
3+ public ref partial struct ValueStringBuilder
4+ {
5+ /// <summary>
6+ /// Replaces all instances of one character with another in this builder.
7+ /// </summary>
8+ /// <param name="oldValue">The character to replace.</param>
9+ /// <param name="newValue">The character to replace <paramref name="oldValue"/> with.</param>
10+ public void Replace ( char oldValue , char newValue ) => Replace ( oldValue , newValue , 0 , Length ) ;
11+
12+ /// <summary>
13+ /// Replaces all instances of one character with another in this builder.
14+ /// </summary>
15+ /// <param name="oldValue">The character to replace.</param>
16+ /// <param name="newValue">The character to replace <paramref name="oldValue"/> with.</param>
17+ /// <param name="startIndex">The index to start in this builder.</param>
18+ /// <param name="count">The number of characters to read in this builder.</param>
19+ public void Replace ( char oldValue , char newValue , int startIndex , int count )
20+ {
21+ if ( startIndex < 0 )
22+ {
23+ throw new ArgumentException ( "Start index can't be smaller than 0." , nameof ( startIndex ) ) ;
24+ }
25+
26+ if ( count > bufferPosition )
27+ {
28+ throw new ArgumentException ( $ "Count: { count } is bigger than the current size { bufferPosition } .", nameof ( count ) ) ;
29+ }
30+
31+ for ( var i = startIndex ; i < startIndex + count ; i ++ )
32+ {
33+ if ( buffer [ i ] == oldValue )
34+ {
35+ buffer [ i ] = newValue ;
36+ }
37+ }
38+ }
39+
40+ /// <summary>
41+ /// Replaces all instances of one string with another in this builder.
42+ /// </summary>
43+ /// <param name="oldValue">The string to replace.</param>
44+ /// <param name="newValue">The string to replace <paramref name="oldValue"/> with.</param>
45+ /// <remarks>
46+ /// If <paramref name="newValue"/> is <c>empty</c>, instances of <paramref name="oldValue"/>
47+ /// are removed from this builder.
48+ /// </remarks>
49+ public void Replace ( ReadOnlySpan < char > oldValue , ReadOnlySpan < char > newValue )
50+ => Replace ( oldValue , newValue , 0 , Length ) ;
51+
52+ /// <summary>
53+ /// Replaces all instances of one string with another in this builder.
54+ /// </summary>
55+ /// <param name="oldValue">The string to replace.</param>
56+ /// <param name="newValue">The string to replace <paramref name="oldValue"/> with.</param>
57+ /// <param name="startIndex">The index to start in this builder.</param>
58+ /// <param name="count">The number of characters to read in this builder.</param>
59+ /// <remarks>
60+ /// If <paramref name="newValue"/> is <c>empty</c>, instances of <paramref name="oldValue"/>
61+ /// are removed from this builder.
62+ /// </remarks>
63+ public void Replace ( ReadOnlySpan < char > oldValue , ReadOnlySpan < char > newValue , int startIndex , int count )
64+ {
65+ var length = startIndex + count ;
66+ var slice = buffer [ startIndex ..length ] ;
67+
68+ // We might want to check whether or not we want to introduce different
69+ // string search algorithms for longer strings.
70+ // I had checked initially with Boyer-Moore but it didn't make that much sense as we
71+ // don't expect very long strings and then the performance is literally the same. So I went with the easier solution.
72+ var hits = NaiveSearch . FindAll ( slice , oldValue ) ;
73+
74+ if ( hits . IsEmpty )
75+ {
76+ return ;
77+ }
78+
79+ var delta = newValue . Length - oldValue . Length ;
80+
81+ for ( var i = 0 ; i < hits . Length ; i ++ )
82+ {
83+ var index = startIndex + hits [ i ] + ( delta * i ) ;
84+ Remove ( index , oldValue . Length ) ;
85+ Insert ( index , newValue ) ;
86+ }
87+ }
88+ }
0 commit comments