'Classes/System/Text/StringBuilder.ab Namespace System Namespace Text Class StringBuilder 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 Char) As StringBuilder EnsureCapacity(size + 1) separateBuffer() chars[size] = x size++ Return This End Function #ifdef UNICODE Function Append(x As SByte) As StringBuilder ActiveBasic.Strings.Detail.FormatIntegerD(This, x, DWORD_MAX, 0, 0) Return This End Function #endif Function Append(x As Byte) As StringBuilder ActiveBasic.Strings.Detail.FormatIntegerU(This, x, DWORD_MAX, 0, 0) Return This End Function Function Append(x As Integer) As StringBuilder ActiveBasic.Strings.Detail.FormatIntegerD(This, x, DWORD_MAX, 0, 0) Return This End Function #ifndef UNICODE Function Append(x As Word) As StringBuilder ActiveBasic.Strings.Detail.FormatIntegerU(This, x, DWORD_MAX, 0, 0) Return This End Function #endif Function Append(x As Long) As StringBuilder ActiveBasic.Strings.Detail.FormatIntegerD(This, x, DWORD_MAX, 0, 0) Return This End Function Function Append(x As DWord) As StringBuilder ActiveBasic.Strings.Detail.FormatIntegerU(This, x, DWORD_MAX, 0, 0) Return This End Function Function Append(x As Int64) As StringBuilder ActiveBasic.Strings.Detail.FormatIntegerLD(This, x, DWORD_MAX, 0, 0) Return This End Function Function Append(x As QWord) As StringBuilder ActiveBasic.Strings.Detail.FormatIntegerLU(This, x, DWORD_MAX, 0, 0) Return This End Function Function Append(x As Single) As StringBuilder ActiveBasic.Strings.Detail.FormatFloatG(This, x, DWORD_MAX, 0, 0) Return This End Function Function Append(x As Double) As StringBuilder ActiveBasic.Strings.Detail.FormatFloatG(This, x, DWORD_MAX, 0, 0) Return This End Function Function Append(x As Object) As StringBuilder Append(x.ToString) Return This End Function Function Append(c As Char, 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 Return Append(StrPtr(s), startIndex, count) End Function Function Append(s As *Char, startIndex As Long, count As Long) As StringBuilder If s = 0 Then If startIndex = 0 And count = 0 Then Return This Else Throw New ArgumentNullException("StringBuilder.Append: An argument is null", "s") End If ElseIf startIndex < 0 Or count < 0 Then Throw New ArgumentOutOfRangeException("StringBuilder.Append: One or more arguments are out of range value.", "startIndex or count or both") End If appendCore(s, startIndex, count) Return This End Function Private Sub appendCore(s As *Char, 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 Char, destIndex As Long, count As Long) If dest = 0 Then Throw New ArgumentNullException("StringBuilder.CopyTo: An argument is null", "sourceIndex") ElseIf size < sourceIndex + count Or sourceIndex < 0 Or destIndex < 0 Or count < 0 Then Throw New ArgumentOutOfRangeException("StringBuilder.CopyTo: One or more arguments are out of range value.", "startIndex or count or both") End If memcpy(VarPtr(dest[destIndex]), VarPtr(chars[sourceIndex]), count * SizeOf (Char)) End Sub Function EnsureCapacity(c As Long) As Long If c < 0 Or c > MaxCapacity Then Throw New ArgumentOutOfRangeException("StringBuilder.Append: An argument is out of range value.", "c") ElseIf c > Capacity Then Dim p = GC_malloc_atomic((c + 1) * SizeOf (Char)) As *Char 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 UNICODE Dim n = size #else Dim n = (size + 1) >> 1 #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 Char) As StringBuilder Insert(i, VarPtr(x), 0, 1) Return This End Function #ifdef UNICODE Function Insert(i As Long, x As SByte) As StringBuilder rangeCheck(i) insertCore(i, Str$(x As Long)) Return This End Function #else Function Insert(i As Long, x As Word) As StringBuilder rangeCheck(i) insertCore(i, Str$(x As DWord)) 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("StringBuilder.Insert: An argument is out of range value.", "n") End If Dim len = x.Length Dim lenTotal = len * n Dim newSize = size + lenTotal EnsureCapacity(newSize) separateBuffer() 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 *Char, index As Long, count As Long) As StringBuilder rangeCheck(i) If x = 0 Then Throw New ArgumentNullException("StringBuilder.Insert: An argument is null", "x") ElseIf index < 0 Or count < 0 Then Throw New ArgumentOutOfRangeException("StringBuilder.Append: One or more arguments are out of range value.", "index or count or both") 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 Char, newChar As Char) 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 Char, newChar As Char, 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 Char, newChar As Char, 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 ActiveBasic.IsNothing(oldStr) Then Throw New ArgumentNullException("StringBuilder.Replace: An argument is null", "oldStr") ElseIf oldStr.Length = 0 Then Throw New ArgumentException("StringBuilder.Replace: The argument 'oldStr' is empty string. ", "oldStr") End If Dim s = New StringBuilder(capacity, maxCapacity) Dim curPos = start Dim last = start + count Do Dim nextPos = ActiveBasic.Strings.ChrFind(VarPtr(chars[curPos]) As *Char, size As SIZE_T, StrPtr(oldStr), oldStr.Length As SIZE_T) As Long If nextPos = -1 As SIZE_T Or curPos > last Then s.appendCore(chars, curPos, size - curPos) Exit Do End If s.appendCore(chars, curPos, nextPos As Long) s.Append(newStr) curPos += nextPos As Long + 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 Char Return Chars[i] End Function Sub Operator []=(i As Long, c As Char) 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 New ArgumentOutOfRangeException("StringBuilder.Capacity: An argument is out of range value.", "c") End If EnsureCapacity(c) End Sub Const Function Chars(i As Long) As Char If i >= Length Or i < 0 Then Throw New IndexOutOfRangeException("StringBuilder.Chars: The index argument 'i' is out of range value.") End If Return chars[i] End Function Sub Chars(i As Long, c As Char) If i >= Length Or i < 0 Then Throw New ArgumentOutOfRangeException("StringBuilder.Chars: An argument is out of range value.", "i") 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 Char) End If size = i End Sub Const Function MaxCapacity() As Long Return maxCapacity End Function Function __Chars() As *Char 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 New ArgumentOutOfRangeException("StringBuilder constructor: One or more arguments are out of range value.", "capacity or maxCapacity or both") 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 (Char)) 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 New ArgumentOutOfRangeException("StringBuilder: Index argument is out of range value.") 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 New ArgumentOutOfRangeException("StringBuilder: One or more arguments are out of range value.", "startIndex or count or both") End If End Sub Sub separateBuffer() If stringized Then Dim newChars = GC_malloc_atomic(SizeOf (Char) * capacity) As *Char ActiveBasic.Strings.ChrCopy(newChars, chars, capacity As SIZE_T) chars = newChars stringized = False End If End Sub chars As *Char 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 *Char Return sb.__Chars End Function