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  Return Append(StrPtr(s), startIndex, count)


123  End Function


124 


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


126  If s = 0 Then


127  If startIndex = 0 And count = 0 Then


128  Return This


129  Else


130  Throw New ArgumentNullException("StringBuilder.Append: An argument is null", "s")


131  End If


132  ElseIf startIndex < 0 Or count < 0 Then


133  Throw New ArgumentOutOfRangeException("StringBuilder.Append: One or more arguments are out of range value.", "startIndex or count or both")


134  End If


135  appendCore(s, startIndex, count)


136  Return This


137  End Function


138  Private


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


140  EnsureCapacity(size + count)


141  separateBuffer()


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


143  size += count


144  End Sub


145 


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


147  EnsureCapacity(size + count)


148  separateBuffer()


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


150  size += count


151  End Sub


152  Public


153  'AppendFormat


154 


155  Function AppendLine() As StringBuilder


156  separateBuffer()


157  Append(Environment.NewLine)


158  Return This


159  End Function


160 


161  Function AppendLine(s As String) As StringBuilder


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


163  separateBuffer()


164  Append(s)


165  Append(Environment.NewLine)


166  Return This


167  End Function


168 


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


170  If dest = 0 Then


171  Throw New ArgumentNullException("StringBuilder.CopyTo: An argument is null", "sourceIndex")


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


173  Throw New ArgumentOutOfRangeException("StringBuilder.CopyTo: One or more arguments are out of range value.", "startIndex or count or both")


174  End If


175 


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


177  End Sub


178 


179  Function EnsureCapacity(c As Long) As Long


180  If c < 0 Or c > MaxCapacity Then


181  Throw New ArgumentOutOfRangeException("StringBuilder.Append: An argument is out of range value.", "c")


182  ElseIf c > Capacity Then


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


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


185  chars = p


186  capacity = c


187  stringized = False


188  End If


189  End Function


190 


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


192 


193  Const Function Equals(s As StringBuilder) As Boolean


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


195  And capacity = s.capacity _


196  And maxCapacity = s.maxCapacity


197  End Function


198 


199  Override Function GetHashCode() As Long


200  #ifdef __STRING_IS_NOT_UNICODE


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


202  #else


203  Dim n = size


204  #endif


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


206  End Function


207 


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


209  rangeCheck(i)


210  insertCore(i, Str$(x))


211  Return This


212  End Function


213 


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


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


216  Return This


217  End Function


218  #ifdef __STRING_IS_NOT_UNICODE


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


220  rangeCheck(i)


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


222  Return This


223  End Function


224  #else


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


226  rangeCheck(i)


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


228  Return This


229  End Function


230  #endif


231 


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


233  rangeCheck(i)


234  insertCore(i, Str$(x))


235  Return This


236  End Function


237 


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


239  rangeCheck(i)


240  insertCore(i, Str$(x))


241  Return This


242  End Function


243 


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


245  rangeCheck(i)


246  insertCore(i, Str$(x))


247  Return This


248  End Function


249 


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


251  rangeCheck(i)


252  insertCore(i, Str$(x))


253  Return This


254  End Function


255 


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


257  rangeCheck(i)


258  insertCore(i, Str$(x))


259  Return This


260  End Function


261 


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


263  rangeCheck(i)


264  insertCore(i, Str$(x))


265  Return This


266  End Function


267 


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


269  rangeCheck(i)


270  insertCore(i, Str$(x))


271  Return This


272  End Function


273 


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


275  rangeCheck(i)


276  insertCore(i, s)


277  Return This


278  End Function


279 


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


281  rangeCheck(i)


282  insertCore(i, o.ToString)


283  Return This


284  End Function


285 


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


287  rangeCheck(index)


288  If n < 0 Then


289  Throw New ArgumentOutOfRangeException("StringBuilder.Insert: An argument is out of range value.", "n")


290  End If


291  Dim len = x.Length


292  Dim lenTotal = len * n


293  Dim newSize = size + lenTotal


294  EnsureCapacity(newSize)


295  separateBuffer()


296 


297  Dim i As Long


298  For i = 0 To ELM(n)


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


300  Next


301  size = newSize


302  Return This


303  End Function


304 


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


306  rangeCheck(i)


307  If x = 0 Then


308  Throw New ArgumentNullException("StringBuilder.Insert: An argument is null", "x")


309  ElseIf index < 0 Or count < 0 Then


310  Throw New ArgumentOutOfRangeException("StringBuilder.Append: One or more arguments are out of range value.", "index or count or both")


311  End If


312 


313  Dim newSize = size + count


314  EnsureCapacity(newSize)


315  separateBuffer()


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


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


318  size = newSize


319  Return This


320  End Function


321 


322  Private


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


324  Dim newSize = size + s.Length


325  EnsureCapacity(newSize)


326  separateBuffer()


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


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


329  size = newSize


330  End Sub


331  Public


332 


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


334  rangeCheck(startIndex, length)


335  separateBuffer()


336 


337  Dim moveStart = startIndex + length


338  ActiveBasic.Strings.ChrMove(


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


340  size = length


341  Return This


342  End Function


343 


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


345  replaceCore(oldChar, newChar, 0, size)


346  Return This


347  End Function


348 


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


350  replaceCore(oldStr, newStr, 0, size)


351  Return This


352  End Function


353 


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


355  rangeCheck(startIndex, count)


356  replaceCore(oldChar, newChar, startIndex, count)


357  Return This


358  End Function


359 


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


361  rangeCheck(startIndex, count)


362  replaceCore(oldStr, newStr, startIndex, count)


363  Return This


364  End Function


365  Private


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


367  separateBuffer()


368  Dim i As Long


369  Dim last = ELM(start + count)


370  For i = start To last


371  If chars[i] = oldChar Then


372  chars[i] = newChar


373  End If


374  Next


375  End Sub


376 


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


378  If ActiveBasic.IsNothing(oldStr) Then


379  Throw New ArgumentNullException("StringBuilder.Replace: An argument is null", "oldStr")


380  ElseIf oldStr.Length = 0 Then


381  Throw New ArgumentException("StringBuilder.Replace: The argument 'oldStr' is empty string. ", "oldStr")


382  End If


383 


384  Dim s = New StringBuilder(capacity, maxCapacity)


385  Dim curPos = start


386  Dim last = start + count


387  Do


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


389  If nextPos = 1 As SIZE_T Or curPos > last Then


390  s.appendCore(chars, curPos, size  curPos)


391  Exit Do


392  End If


393 


394  s.appendCore(chars, curPos, nextPos As Long)


395  s.Append(newStr)


396  curPos += nextPos As Long + oldStr.Length


397  Loop


398  chars = s.chars


399  size = s.size


400  End Sub


401 


402  Public


403  Override Function ToString() As String


404  chars[size] = 0


405  Return New String(This)


406  End Function


407 


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


409  rangeCheck(startIndex, length)


410  Return New String(chars, startIndex, length)


411  End Function


412 


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


414  Return Chars[i]


415  End Function


416 


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


418  Chars[i] = c


419  End Sub


420 


421  'Properties


422  Const Function Capacity() As Long


423  Return capacity


424  End Function


425 


426  Sub Capacity(c As Long)


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


428  Throw New ArgumentOutOfRangeException("StringBuilder.Capacity: An argument is out of range value.", "c")


429  End If


430  EnsureCapacity(c)


431  End Sub


432 


433  Const Function Chars(i As Long) As StrChar


434  If i >= Length Or i < 0 Then


435  Throw New IndexOutOfRangeException("StringBuilder.Chars: The index argument 'i' is out of range value.")


436  End If


437  Return chars[i]


438  End Function


439 


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


441  If i >= Length Or i < 0 Then


442  Throw New ArgumentOutOfRangeException("StringBuilder.Chars: An argument is out of range value.", "i")


443  End If


444  chars[i] = c


445  End Sub


446 


447  Const Function Length() As Long


448  Return size


449  End Function


450 


451  Sub Length(i As Long)


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


453  If size < i Then


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


455  End If


456  size = i


457  End Sub


458 


459  Const Function MaxCapacity() As Long


460  Return maxCapacity


461  End Function


462 


463  Function __Chars() As *StrChar


464  Return chars


465  End Function


466 


467  Sub __Stringized()


468  stringized = True


469  End Sub


470 


471  Private


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


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


474  Throw New ArgumentOutOfRangeException("StringBuilder constructor: One or more arguments are out of range value.", "capacity or maxCapacity or both")


475  End If


476 


477  If capacity = 0 Then


478  This.capacity = 1024


479  Else


480  This.capacity = capacity


481  End If


482 


483  This.maxCapacity = maxCapacity


484  This.size = 0


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


486  End Sub


487 


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


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


490 


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


492 


493  If Not String.IsNullOrEmpty(s) Then


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


495  size = length


496  End If


497  End Sub


498 


499  Sub rangeCheck(index As Long)


500  If index < 0 Or index > size Then


501  Throw New ArgumentOutOfRangeException("StringBuilder: Index argument is out of range value.")


502  End If


503  End Sub


504 


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


506  StringBuilder.rangeCheck2(size, startIndex, count)


507  End Sub


508 


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


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


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


512  Throw New ArgumentOutOfRangeException("StringBuilder: One or more arguments are out of range value.", "startIndex or count or both")


513  End If


514  End Sub


515 


516  Sub separateBuffer()


517  If stringized Then


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


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


520  chars = newChars


521  stringized = False


522  End If


523  End Sub


524 


525  chars As *StrChar


526  maxCapacity As Long


527  capacity As Long


528  size As Long


529  stringized As Boolean


530  End Class


531 


532  End Namespace 'Text


533  End Namespace 'System


534 


535  '暫定


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


537  Return sb.__Chars


538  End Function

