'Classes/System/Text/StringBuilder.ab #require Namespace System Namespace Text Class StringBuilder 'Inherits ISerializable Public Sub StringBuilder() initialize(1024) End Sub Sub StringBuilder(capacity As Long) initialize(capacity) End Sub Sub StringBuilder(s As String) initialize(s, 0, s.Length, s.Length * 2) End Sub Sub StringBuilder(capacity As Long, maxCapacity As Long) initialize(capacity, maxCapacity) End Sub Sub StringBuilder(s As String, capacity As Long) initialize(s, 0, s.Length, capacity) End Sub Sub StringBuilder(s As String, startIndex As Long, length As Long, capacity As Long) initialize(s, startIndex, length, capacity) End Sub 'Methods Function Append(x As Boolean) As StringBuilder Append(Str$(x)) Return This End Function Function Append(x As StrChar) As StringBuilder EnsureCapacity(size + 1) separateBuffer() chars[size] = x size++ Return This End Function #ifdef __STRING_IS_NOT_UNICODE Function Append(x As Word) As StringBuilder Append(Str$(x As DWord)) Return This End Function #else Function Append(x As SByte) As StringBuilder Append(Str$(x As Long)) Return This End Function #endif Function Append(x As Byte) As StringBuilder Append(Str$(x As DWord)) Return This End Function Function Append(x As Integer) As StringBuilder Append(Str$(x As Long)) Return This End Function Function Append(x As Long) As StringBuilder Append(Str$(x)) Return This End Function Function Append(x As DWord) As StringBuilder Append(Str$(x)) Return This End Function Function Append(x As Int64) As StringBuilder Append(Str$(x)) Return This End Function Function Append(x As QWord) As StringBuilder Append(Str$(x)) Return This End Function Function Append(x As Single) As StringBuilder Append(Str$(x)) Return This End Function Function Append(x As Double) As StringBuilder Append(Str$(x)) Return This End Function Function Append(x As Object) As StringBuilder Append(x.ToString) Return This End Function Function Append(c As StrChar, n As Long) As StringBuilder EnsureCapacity(size + n) ActiveBasic.Strings.ChrFill(VarPtr(chars[size]), n As SIZE_T, c) size += n Return This End Function Function Append(s As String) As StringBuilder If Not String.IsNullOrEmpty(s) Then appendCore(s, 0, s.Length) End If Return This End Function Function Append(s As String, startIndex As Long, count As Long) As StringBuilder If s = 0 Then If startIndex = 0 And count = 0 Then Return This Else 'Throw ArgumentNullException End If End If StringBuilder.rangeCheck2(s.Length, startIndex, count) appendCore(s, startIndex, count) Return This End Function Function Append(s As *StrChar, startIndex As Long, count As Long) As StringBuilder If s = 0 Then If startIndex = 0 And count = 0 Then Return This Else 'Throw ArgumentNullException End If ElseIf startIndex < 0 Or count < 0 Then 'Throw ArgumentOutOfRangeException End If appendCore(s, startIndex, count) Return This End Function Private Sub appendCore(s As *StrChar, start As Long, count As Long) EnsureCapacity(size + count) separateBuffer() ActiveBasic.Strings.ChrCopy(VarPtr(chars[size]), VarPtr(s[start]), count As SIZE_T) size += count End Sub Sub appendCore(s As String, start As Long, count As Long) EnsureCapacity(size + count) separateBuffer() s.CopyTo(start, chars, size, count) size += count End Sub Public 'AppendFormat Function AppendLine() As StringBuilder separateBuffer() Append(Environment.NewLine) Return This End Function Function AppendLine(s As String) As StringBuilder EnsureCapacity(Capacity + s.Length + Environment.NewLine.Length) separateBuffer() Append(s) Append(Environment.NewLine) Return This End Function Const Sub CopyTo(sourceIndex As Long, ByRef dest[] As StrChar, destIndex As Long, count As Long) If dest = 0 Then 'Throw ArgumentNullException ElseIf size < sourceIndex + count Or sourceIndex < 0 Or destIndex < 0 Or count < 0 Then 'Throw ArgumentOutOfRangeException End If memcpy(VarPtr(dest[destIndex]), VarPtr(chars[sourceIndex]), count * SizeOf (StrChar)) End Sub Function EnsureCapacity(c As Long) As Long If c < 0 Or c > MaxCapacity Then 'Throw ArgumentOutOfRangeException ElseIf c > Capacity Then Dim p = GC_malloc_atomic((c + 1) * SizeOf (StrChar)) As *StrChar If p = 0 Then 'Throw OutOfMemoryException Debug End If ActiveBasic.Strings.ChrCopy(p, chars, size As SIZE_T) chars = p capacity = c stringized = False End If End Function 'Override Function Equals(o As Object) As Boolean Const Function Equals(s As StringBuilder) As Boolean Return ActiveBasic.Strings.StrCmp(chars, s.chars) = 0 _ And capacity = s.capacity _ And maxCapacity = s.maxCapacity End Function Override Function GetHashCode() As Long #ifdef __STRING_IS_NOT_UNICODE Dim n = (size + 1) >> 1 #else Dim n = size #endif Return _System_GetHashFromWordArray(chars As *Word, n As SIZE_T) Xor capacity Xor maxCapacity End Function Function Insert(i As Long, x As Boolean) As StringBuilder rangeCheck(i) insertCore(i, Str$(x)) Return This End Function Function Insert(i As Long, x As StrChar) As StringBuilder Insert(i, VarPtr(x), 0, 1) Return This End Function #ifdef __STRING_IS_NOT_UNICODE Function Insert(i As Long, x As Word) As StringBuilder rangeCheck(i) insertCore(i, Str$(x As DWord)) Return This End Function #else Function Insert(i As Long, x As SByte) As StringBuilder rangeCheck(i) insertCore(i, Str$(x As Long)) Return This End Function #endif Function Insert(i As Long, x As Byte) As StringBuilder rangeCheck(i) insertCore(i, Str$(x)) Return This End Function Function Insert(i As Long, x As Integer) As StringBuilder rangeCheck(i) insertCore(i, Str$(x)) Return This End Function Function Insert(i As Long, x As Long) As StringBuilder rangeCheck(i) insertCore(i, Str$(x)) Return This End Function Function Insert(i As Long, x As DWord) As StringBuilder rangeCheck(i) insertCore(i, Str$(x)) Return This End Function Function Insert(i As Long, x As Int64) As StringBuilder rangeCheck(i) insertCore(i, Str$(x)) Return This End Function Function Insert(i As Long, x As Single) As StringBuilder rangeCheck(i) insertCore(i, Str$(x)) Return This End Function Function Insert(i As Long, x As Double) As StringBuilder rangeCheck(i) insertCore(i, Str$(x)) Return This End Function Function Insert(i As Long, s As String) As StringBuilder rangeCheck(i) insertCore(i, s) Return This End Function Function Insert(i As Long, o As Object) As StringBuilder rangeCheck(i) insertCore(i, o.ToString) Return This End Function Function Insert(index As Long, x As String, n As Long) As StringBuilder rangeCheck(index) If n < 0 Then 'Throw New ArgumentOutOfRangeException Debug End If Dim len = x.Length Dim lenTotal = len * n Dim newSize = size + lenTotal EnsureCapacity(newSize) separateBuffer() ' TODO: fix me!(定義されていない変数iが使われています) 'ActiveBasic.Strings.ChrMove(VarPtr(chars[i + lenTotal]), VarPtr(chars[i]), (size - index) As SIZE_T) Dim i As Long For i = 0 To ELM(n) x.CopyTo(0, chars, size + i * len, len) Next size = newSize Return This End Function Function Insert(i As Long, x As *StrChar, index As Long, count As Long) As StringBuilder rangeCheck(i) If x = 0 Then 'Throw New ArgumentNullException Debug ElseIf index < 0 Or count < 0 Then 'Throw New ArgumentNullException Debug End If Dim newSize = size + count EnsureCapacity(newSize) separateBuffer() ActiveBasic.Strings.ChrMove(VarPtr(chars[i + count]), VarPtr(chars[i]), (size - i) As SIZE_T) ActiveBasic.Strings.ChrCopy(VarPtr(chars[i]), VarPtr(x[index]), count As SIZE_T) size = newSize Return This End Function Private Sub insertCore(i As Long, s As String) Dim newSize = size + s.Length EnsureCapacity(newSize) separateBuffer() ActiveBasic.Strings.ChrMove(VarPtr(chars[i + s.Length]), VarPtr(chars[i]), (size - i) As SIZE_T) s.CopyTo(0, chars, i, s.Length) size = newSize End Sub Public Function Remove(startIndex As Long, length As Long) As StringBuilder rangeCheck(startIndex, length) separateBuffer() Dim moveStart = startIndex + length ActiveBasic.Strings.ChrMove( VarPtr(chars[startIndex]), VarPtr(chars[moveStart]), (size - moveStart) As SIZE_T) size -= length Return This End Function Function Replace(oldChar As StrChar, newChar As StrChar) As StringBuilder replaceCore(oldChar, newChar, 0, size) Return This End Function Function Replace(oldStr As String, newStr As String) As StringBuilder replaceCore(oldStr, newStr, 0, size) Return This End Function Function Replace(oldChar As StrChar, newChar As StrChar, startIndex As Long, count As Long) As StringBuilder rangeCheck(startIndex, count) replaceCore(oldChar, newChar, startIndex, count) Return This End Function Function Replace(oldStr As String, newStr As String, startIndex As Long, count As Long) As StringBuilder rangeCheck(startIndex, count) replaceCore(oldStr, newStr, startIndex, count) Return This End Function Private Sub replaceCore(oldChar As StrChar, newChar As StrChar, start As Long, count As Long) separateBuffer() Dim i As Long Dim last = ELM(start + count) For i = start To last If chars[i] = oldChar Then chars[i] = newChar End If Next End Sub Sub replaceCore(oldStr As String, newStr As String, start As Long, count As Long) If Object.ReferenceEquals(oldStr, Nothing) Then 'Throw ArgumentNullException Debug ElseIf oldStr.Length = 0 Then 'Throw ArgumentException Debug End If Dim s = New StringBuilder(capacity, maxCapacity) Dim curPos = 0 As Long Do Dim nextPos = ActiveBasic.Strings.ChrFind(VarPtr(chars[curPos]) As *StrChar, size As SIZE_T, StrPtr(oldStr), oldStr.Length As SIZE_T) As Long If nextPos = -1 As SIZE_T Then Exit Sub End If s.appendCore(chars, curPos, nextPos) s.Append(newStr) curPos += nextPos + oldStr.Length Loop chars = s.chars size = s.size End Sub Public Override Function ToString() As String chars[size] = 0 Return New String(This) End Function Const Function ToString(startIndex As Long, length As Long) As String rangeCheck(startIndex, length) Return New String(chars, startIndex, length) End Function Const Function Operator [](i As Long) As StrChar Return Chars[i] End Function Sub Operator []=(i As Long, c As StrChar) Chars[i] = c End Sub 'Properties Const Function Capacity() As Long Return capacity End Function Sub Capacity(c As Long) If c < size Or c > MaxCapacity Then 'sizeとの比較でcが負の場合も対応 'Throw ArgumentOutOfRangeException End If EnsureCapacity(c) End Sub Const Function Chars(i As Long) As StrChar If i >= Length Or i < 0 Then 'Throw IndexOutOfRangeException Debug End If Return chars[i] End Function Sub Chars(i As Long, c As StrChar) If i >= Length Or i < 0 Then 'Throw ArgumentOutOfRangeException Debug End If chars[i] = c End Sub Const Function Length() As Long Return size End Function Sub Length(i As Long) EnsureCapacity(i) 'iが適切な値かどうかの確認はこの中で行う If size < i Then ActiveBasic.Strings.ChrFill(VarPtr(chars[size]), (i - size + 1) As SIZE_T, 0 As StrChar) End If size = i End Sub Const Function MaxCapacity() As Long Return maxCapacity End Function Function __Chars() As *StrChar Return chars End Function Sub __Stringized() stringized = True End Sub Private Sub initialize(capacity As Long, maxCapacity = LONG_MAX As Long) If capacity < 0 Or maxCapacity < 1 Or maxCapacity < capacity Then 'Throw ArgumentOutOfRangeException End If If capacity = 0 Then This.capacity = 1024 Else This.capacity = capacity End If This.maxCapacity = maxCapacity This.size = 0 This.chars = GC_malloc_atomic((This.capacity + 1) * SizeOf (StrChar)) If chars = 0 Then 'Throw OutOfMemoryException Debug End If End Sub Sub initialize(s As String, startIndex As Long, length As Long, capacity As Long, maxCapacity = LONG_MAX As Long) StringBuilder.rangeCheck2(s.Length, startIndex, length) initialize(Math.Max(capacity, length), maxCapacity) If Not String.IsNullOrEmpty(s) Then s.CopyTo(startIndex, chars, 0, length) size = length End If End Sub Sub rangeCheck(index As Long) If index < 0 Or index > size Then 'Throw ArgumentOutOfRangeException Debug End If End Sub Sub rangeCheck(startIndex As Long, count As Long) StringBuilder.rangeCheck2(size, startIndex, count) End Sub Static Sub rangeCheck2(length As Long, startIndex As Long, count As Long) 'length < 0は判定に入っていないことに注意 If startIndex < 0 Or count < 0 Or startIndex + count > length Then 'Throw ArgumentOutOfRangeException Debug End If End Sub Sub separateBuffer() If stringized Then Dim newChars = GC_malloc_atomic(SizeOf (StrChar) * capacity) As *StrChar ActiveBasic.Strings.ChrCopy(newChars, chars, capacity As SIZE_T) chars = newChars stringized = False End If End Sub chars As *StrChar maxCapacity As Long capacity As Long size As Long stringized As Boolean End Class End Namespace 'Text End Namespace 'System '暫定 Function StrPtr(sb As System.Text.StringBuilder) As *StrChar Return sb.__Chars End Function