1  'Classes/System/Text/StringBuilder.ab


2 


3  #require <Classes/ActiveBasic/Strings/Strings.ab>


4 


5  Namespace System


6  Namespace Text


7 


8  Class StringBuilder


9  'Inherits ISerializable


10  Public


11  Sub StringBuilder()


12  initialize(1024)


13  End Sub


14 


15  Sub StringBuilder(capacity As Long)


16  initialize(capacity)


17  End Sub


18 


19  Sub StringBuilder(s As String)


20  initialize(s, 0, s.Length, s.Length * 2)


21  End Sub


22 


23  Sub StringBuilder(capacity As Long, maxCapacity As Long)


24  initialize(capacity, maxCapacity)


25  End Sub


26 


27  Sub StringBuilder(s As String, capacity As Long)


28  initialize(s, 0, s.Length, capacity)


29  End Sub


30 


31  Sub StringBuilder(s As String, startIndex As Long, length As Long, capacity As Long)


32  initialize(s, startIndex, length, capacity)


33  End Sub


34 


35  'Methods


36 


37  Function Append(x As Boolean) As StringBuilder


38  Append(Str$(x))


39  Return This


40  End Function


41 


42  Function Append(x As StrChar) As StringBuilder


43  EnsureCapacity(size + 1)


44  separateBuffer()


45  chars[size] = x


46  size++


47  Return This


48  End Function


49 


50  #ifdef __STRING_IS_NOT_UNICODE


51  Function Append(x As Word) As StringBuilder


52  Append(Str$(x As DWord))


53  Return This


54  End Function


55  #else


56  Function Append(x As SByte) As StringBuilder


57  Append(Str$(x As Long))


58  Return This


59  End Function


60  #endif


61 


62  Function Append(x As Byte) As StringBuilder


63  Append(Str$(x As DWord))


64  Return This


65  End Function


66 


67  Function Append(x As Integer) As StringBuilder


68  Append(Str$(x As Long))


69  Return This


70  End Function


71 


72  Function Append(x As Long) As StringBuilder


73  Append(Str$(x))


74  Return This


75  End Function


76 


77  Function Append(x As DWord) As StringBuilder


78  Append(Str$(x))


79  Return This


80  End Function


81 


82  Function Append(x As Int64) As StringBuilder


83  Append(Str$(x))


84  Return This


85  End Function


86 


87  Function Append(x As QWord) As StringBuilder


88  Append(Str$(x))


89  Return This


90  End Function


91 


92  Function Append(x As Single) As StringBuilder


93  Append(Str$(x))


94  Return This


95  End Function


96 


97  Function Append(x As Double) As StringBuilder


98  Append(Str$(x))


99  Return This


100  End Function


101 


102  Function Append(x As Object) As StringBuilder


103  Append(x.ToString)


104  Return This


105  End Function


106 


107  Function Append(c As StrChar, n As Long) As StringBuilder


108  EnsureCapacity(size + n)


109  ActiveBasic.Strings.ChrFill(VarPtr(chars[size]), n As SIZE_T, c)


110  size += n


111  Return This


112  End Function


113 


114  Function Append(s As String) As StringBuilder


115  If Not String.IsNullOrEmpty(s) Then


116  appendCore(s, 0, s.Length)


117  End If


118  Return This


119  End Function


120 


121  Function Append(s As String, startIndex As Long, count As Long) As StringBuilder


122  If s = 0 Then


123  If startIndex = 0 And count = 0 Then


124  Return This


125  Else


126  'Throw ArgumentNullException


127  End If


128  End If


129  StringBuilder.rangeCheck2(s.Length, startIndex, count)


130  appendCore(s, startIndex, count)


131  Return This


132  End Function


133 


134  Function Append(s As *StrChar, startIndex As Long, count As Long) As StringBuilder


135  If s = 0 Then


136  If startIndex = 0 And count = 0 Then


137  Return This


138  Else


139  'Throw ArgumentNullException


140  End If


141  ElseIf startIndex < 0 Or count < 0 Then


142  'Throw ArgumentOutOfRangeException


143  End If


144  appendCore(s, startIndex, count)


145  Return This


146  End Function


147  Private


148  Sub appendCore(s As *StrChar, start As Long, count As Long)


149  EnsureCapacity(size + count)


150  separateBuffer()


151  ActiveBasic.Strings.ChrCopy(VarPtr(chars[size]), VarPtr(s[start]), count As SIZE_T)


152  size += count


153  End Sub


154 


155  Sub appendCore(s As String, start As Long, count As Long)


156  EnsureCapacity(size + count)


157  separateBuffer()


158  s.CopyTo(start, chars, size, count)


159  size += count


160  End Sub


161  Public


162  'AppendFormat


163 


164  Function AppendLine() As StringBuilder


165  separateBuffer()


166  Append(Environment.NewLine)


167  Return This


168  End Function


169 


170  Function AppendLine(s As String) As StringBuilder


171  EnsureCapacity(Capacity + s.Length + Environment.NewLine.Length)


172  separateBuffer()


173  Append(s)


174  Append(Environment.NewLine)


175  Return This


176  End Function


177 


178  Const Sub CopyTo(sourceIndex As Long, ByRef dest[] As StrChar, destIndex As Long, count As Long)


179  If dest = 0 Then


180  'Throw ArgumentNullException


181  ElseIf size < sourceIndex + count Or sourceIndex < 0 Or destIndex < 0 Or count < 0 Then


182  'Throw ArgumentOutOfRangeException


183  End If


184 


185  memcpy(VarPtr(dest[destIndex]), VarPtr(chars[sourceIndex]), count * SizeOf (StrChar))


186  End Sub


187 


188  Function EnsureCapacity(c As Long) As Long


189  If c < 0 Or c > MaxCapacity Then


190  'Throw ArgumentOutOfRangeException


191  ElseIf c > Capacity Then


192  Dim p = GC_malloc_atomic((c + 1) * SizeOf (StrChar)) As *StrChar


193  If p = 0 Then


194  'Throw OutOfMemoryException


195  Debug


196  End If


197  ActiveBasic.Strings.ChrCopy(p, chars, size As SIZE_T)


198  chars = p


199  capacity = c


200  stringized = False


201  End If


202  End Function


203 


204  'Override Function Equals(o As Object) As Boolean


205 


206  Const Function Equals(s As StringBuilder) As Boolean


207  Return ActiveBasic.Strings.StrCmp(chars, s.chars) = 0 _


208  And capacity = s.capacity _


209  And maxCapacity = s.maxCapacity


210  End Function


211 


212  Override Function GetHashCode() As Long


213  #ifdef __STRING_IS_NOT_UNICODE


214  Dim n = (size + 1) >> 1


215  #else


216  Dim n = size


217  #endif


218  Return _System_GetHashFromWordArray(chars As *Word, n As SIZE_T) Xor capacity Xor maxCapacity


219  End Function


220 


221  Function Insert(i As Long, x As Boolean) As StringBuilder


222  rangeCheck(i)


223  insertCore(i, Str$(x))


224  Return This


225  End Function


226 


227  Function Insert(i As Long, x As StrChar) As StringBuilder


228  Insert(i, VarPtr(x), 0, 1)


229  Return This


230  End Function


231  #ifdef __STRING_IS_NOT_UNICODE


232  Function Insert(i As Long, x As Word) As StringBuilder


233  rangeCheck(i)


234  insertCore(i, Str$(x As DWord))


235  Return This


236  End Function


237  #else


238  Function Insert(i As Long, x As SByte) As StringBuilder


239  rangeCheck(i)


240  insertCore(i, Str$(x As Long))


241  Return This


242  End Function


243  #endif


244 


245  Function Insert(i As Long, x As Byte) As StringBuilder


246  rangeCheck(i)


247  insertCore(i, Str$(x))


248  Return This


249  End Function


250 


251  Function Insert(i As Long, x As Integer) As StringBuilder


252  rangeCheck(i)


253  insertCore(i, Str$(x))


254  Return This


255  End Function


256 


257  Function Insert(i As Long, x As Long) As StringBuilder


258  rangeCheck(i)


259  insertCore(i, Str$(x))


260  Return This


261  End Function


262 


263  Function Insert(i As Long, x As DWord) As StringBuilder


264  rangeCheck(i)


265  insertCore(i, Str$(x))


266  Return This


267  End Function


268 


269  Function Insert(i As Long, x As Int64) As StringBuilder


270  rangeCheck(i)


271  insertCore(i, Str$(x))


272  Return This


273  End Function


274 


275  Function Insert(i As Long, x As Single) As StringBuilder


276  rangeCheck(i)


277  insertCore(i, Str$(x))


278  Return This


279  End Function


280 


281  Function Insert(i As Long, x As Double) As StringBuilder


282  rangeCheck(i)


283  insertCore(i, Str$(x))


284  Return This


285  End Function


286 


287  Function Insert(i As Long, s As String) As StringBuilder


288  rangeCheck(i)


289  insertCore(i, s)


290  Return This


291  End Function


292 


293  Function Insert(i As Long, o As Object) As StringBuilder


294  rangeCheck(i)


295  insertCore(i, o.ToString)


296  Return This


297  End Function


298 


299  Function Insert(index As Long, x As String, n As Long) As StringBuilder


300  rangeCheck(index)


301  If n < 0 Then


302  'Throw New ArgumentOutOfRangeException


303  Debug


304  End If


305  Dim len = x.Length


306  Dim lenTotal = len * n


307  Dim newSize = size + lenTotal


308  EnsureCapacity(newSize)


309  separateBuffer()


310 


311  ' TODO: fix me!（定義されていない変数iが使われています）


312  'ActiveBasic.Strings.ChrMove(VarPtr(chars[i + lenTotal]), VarPtr(chars[i]), (size  index) As SIZE_T)


313 


314  Dim i As Long


315  For i = 0 To ELM(n)


316  x.CopyTo(0, chars, size + i * len, len)


317  Next


318  size = newSize


319  Return This


320  End Function


321 


322 


323  Function Insert(i As Long, x As *StrChar, index As Long, count As Long) As StringBuilder


324  rangeCheck(i)


325  If x = 0 Then


326  'Throw New ArgumentNullException


327  Debug


328  ElseIf index < 0 Or count < 0 Then


329  'Throw New ArgumentNullException


330  Debug


331  End If


332 


333  Dim newSize = size + count


334  EnsureCapacity(newSize)


335  separateBuffer()


336  ActiveBasic.Strings.ChrMove(VarPtr(chars[i + count]), VarPtr(chars[i]), (size  i) As SIZE_T)


337  ActiveBasic.Strings.ChrCopy(VarPtr(chars[i]), VarPtr(x[index]), count As SIZE_T)


338  size = newSize


339  Return This


340  End Function


341 


342  Private


343  Sub insertCore(i As Long, s As String)


344  Dim newSize = size + s.Length


345  EnsureCapacity(newSize)


346  separateBuffer()


347  ActiveBasic.Strings.ChrMove(VarPtr(chars[i + s.Length]), VarPtr(chars[i]), (size  i) As SIZE_T)


348  s.CopyTo(0, chars, i, s.Length)


349  size = newSize


350  End Sub


351  Public


352 


353  Function Remove(startIndex As Long, length As Long) As StringBuilder


354  rangeCheck(startIndex, length)


355  separateBuffer()


356 


357  Dim moveStart = startIndex + length


358  ActiveBasic.Strings.ChrMove(


359  VarPtr(chars[startIndex]), VarPtr(chars[moveStart]), (size  moveStart) As SIZE_T)


360  size = length


361  Return This


362  End Function


363 


364  Function Replace(oldChar As StrChar, newChar As StrChar) As StringBuilder


365  replaceCore(oldChar, newChar, 0, size)


366  Return This


367  End Function


368 


369  Function Replace(oldStr As String, newStr As String) As StringBuilder


370  replaceCore(oldStr, newStr, 0, size)


371  Return This


372  End Function


373 


374  Function Replace(oldChar As StrChar, newChar As StrChar, startIndex As Long, count As Long) As StringBuilder


375  rangeCheck(startIndex, count)


376  replaceCore(oldChar, newChar, startIndex, count)


377  Return This


378  End Function


379 


380  Function Replace(oldStr As String, newStr As String, startIndex As Long, count As Long) As StringBuilder


381  rangeCheck(startIndex, count)


382  replaceCore(oldStr, newStr, startIndex, count)


383  Return This


384  End Function


385  Private


386  Sub replaceCore(oldChar As StrChar, newChar As StrChar, start As Long, count As Long)


387  separateBuffer()


388  Dim i As Long


389  Dim last = ELM(start + count)


390  For i = start To last


391  If chars[i] = oldChar Then


392  chars[i] = newChar


393  End If


394  Next


395  End Sub


396 


397  Sub replaceCore(oldStr As String, newStr As String, start As Long, count As Long)


398  If Object.ReferenceEquals(oldStr, Nothing) Then


399  'Throw ArgumentNullException


400  Debug


401  ElseIf oldStr.Length = 0 Then


402  'Throw ArgumentException


403  Debug


404  End If


405 


406  Dim s = New StringBuilder(capacity, maxCapacity)


407  Dim curPos = 0 As Long


408  Do


409  Dim nextPos = ActiveBasic.Strings.ChrFind(VarPtr(chars[curPos]) As *StrChar, size As SIZE_T, StrPtr(oldStr), oldStr.Length As SIZE_T)


410  If nextPos = 1 As SIZE_T Then


411  Exit Sub


412  End If


413 


414  s.appendCore(chars, curPos, nextPos)


415  s.Append(newStr)


416  curPos += nextPos + oldStr.Length


417  Loop


418  chars = s.chars


419  size = s.size


420  End Sub


421 


422  Public


423  Override Function ToString() As String


424  chars[size] = 0


425  Return New String(This)


426  End Function


427 


428  Const Function ToString(startIndex As Long, length As Long) As String


429  rangeCheck(startIndex, length)


430  Return New String(chars, startIndex, length)


431  End Function


432 


433  Const Function Operator [](i As Long) As StrChar


434  Return Chars[i]


435  End Function


436 


437  Sub Operator []=(i As Long, c As StrChar)


438  Chars[i] = c


439  End Sub


440 


441  'Properties


442  Const Function Capacity() As Long


443  Return capacity


444  End Function


445 


446  Sub Capacity(c As Long)


447  If c < size Or c > MaxCapacity Then 'sizeとの比較でcが負の場合も対応


448  'Throw ArgumentOutOfRangeException


449  End If


450  EnsureCapacity(c)


451  End Sub


452 


453  Const Function Chars(i As Long) As StrChar


454  If i >= Length Or i < 0 Then


455  'Throw IndexOutOfRangeException


456  Debug


457  End If


458  Return chars[i]


459  End Function


460 


461  Sub Chars(i As Long, c As StrChar)


462  If i >= Length Or i < 0 Then


463  'Throw ArgumentOutOfRangeException


464  Debug


465  End If


466  chars[i] = c


467  End Sub


468 


469  Const Function Length() As Long


470  Return size


471  End Function


472 


473  Sub Length(i As Long)


474  EnsureCapacity(i) 'iが適切な値かどうかの確認はこの中で行う


475  If size < i Then


476  ActiveBasic.Strings.ChrFill(VarPtr(chars[size]), (i  size + 1) As SIZE_T, 0 As StrChar)


477  End If


478  size = i


479  End Sub


480 


481  Const Function MaxCapacity() As Long


482  Return maxCapacity


483  End Function


484 


485  Function __Chars() As *StrChar


486  Return chars


487  End Function


488 


489  Sub __Stringized()


490  stringized = True


491  End Sub


492 


493  Private


494  Sub initialize(capacity As Long, maxCapacity = LONG_MAX As Long)


495  If capacity < 0 Or maxCapacity < 1 Or maxCapacity < capacity Then


496  'Throw ArgumentOutOfRangeException


497  End If


498 


499  If capacity = 0 Then


500  This.capacity = 1024


501  Else


502  This.capacity = capacity


503  End If


504 


505  This.maxCapacity = maxCapacity


506  This.size = 0


507  This.chars = GC_malloc_atomic((This.capacity + 1) * SizeOf (StrChar))


508  If chars = 0 Then


509  'Throw OutOfMemoryException


510  Debug


511  End If


512 


513  End Sub


514 


515  Sub initialize(s As String, startIndex As Long, length As Long, capacity As Long, maxCapacity = LONG_MAX As Long)


516  StringBuilder.rangeCheck2(s.Length, startIndex, length)


517 


518  initialize(Math.Max(capacity, length), maxCapacity)


519 


520  If Not String.IsNullOrEmpty(s) Then


521  s.CopyTo(startIndex, chars, 0, length)


522  size = s.Length


523  End If


524  End Sub


525 


526  Sub rangeCheck(index As Long)


527  If index < 0 Or index > size Then


528  'Throw ArgumentOutOfRangeException


529  Debug


530  End If


531  End Sub


532 


533  Sub rangeCheck(startIndex As Long, count As Long)


534  StringBuilder.rangeCheck2(size, startIndex, count)


535  End Sub


536 


537  Static Sub rangeCheck2(length As Long, startIndex As Long, count As Long)


538  'length < 0は判定に入っていないことに注意


539  If startIndex < 0 Or count < 0 Or startIndex + count > length Then


540  'Throw ArgumentOutOfRangeException


541  Debug


542  End If


543  End Sub


544 


545  Sub separateBuffer()


546  If stringized Then


547  Dim newChars = GC_malloc_atomic(SizeOf (StrChar) * capacity) As *StrChar


548  ActiveBasic.Strings.ChrCopy(newChars, chars, capacity As SIZE_T)


549  chars = newChars


550  stringized = False


551  End If


552  End Sub


553 


554  chars As *StrChar


555  maxCapacity As Long


556  capacity As Long


557  size As Long


558  stringized As Boolean


559  End Class


560 


561  End Namespace 'Text


562  End Namespace 'System


563 


564  '暫定


565  Function StrPtr(sb As System.Text.StringBuilder) As *StrChar


566  Return sb.__Chars


567  End Function

