1  'Classes/System/Text/StringBuilder.ab


2 


3  Namespace System


4  Namespace Text


5 


6  Class StringBuilder


7  Public


8  Sub StringBuilder()


9  initialize(1024)


10  End Sub


11 


12  Sub StringBuilder(capacity As Long)


13  initialize(capacity)


14  End Sub


15 


16  Sub StringBuilder(s As String)


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


18  End Sub


19 


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


21  initialize(capacity, maxCapacity)


22  End Sub


23 


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


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


26  End Sub


27 


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


29  initialize(s, startIndex, length, capacity)


30  End Sub


31 


32  'Methods


33 


34  Function Append(x As Boolean) As StringBuilder


35  Append(Str$(x))


36  Return This


37  End Function


38 


39  Function Append(x As Char) As StringBuilder


40  EnsureCapacity(size + 1)


41  separateBuffer()


42  chars[size] = x


43  size++


44  Return This


45  End Function


46  #ifdef UNICODE


47  Function Append(x As SByte) As StringBuilder


48  ActiveBasic.Strings.Detail.FormatIntegerD(This, x, DWORD_MAX, 0, 0)


49  Return This


50  End Function


51  #endif


52  Function Append(x As Byte) As StringBuilder


53  ActiveBasic.Strings.Detail.FormatIntegerU(This, x, DWORD_MAX, 0, 0)


54  Return This


55  End Function


56 


57  Function Append(x As Integer) As StringBuilder


58  ActiveBasic.Strings.Detail.FormatIntegerD(This, x, DWORD_MAX, 0, 0)


59  Return This


60  End Function


61  #ifndef UNICODE


62  Function Append(x As Word) As StringBuilder


63  ActiveBasic.Strings.Detail.FormatIntegerU(This, x, DWORD_MAX, 0, 0)


64  Return This


65  End Function


66  #endif


67  Function Append(x As Long) As StringBuilder


68  ActiveBasic.Strings.Detail.FormatIntegerD(This, x, DWORD_MAX, 0, 0)


69  Return This


70  End Function


71 


72  Function Append(x As DWord) As StringBuilder


73  ActiveBasic.Strings.Detail.FormatIntegerU(This, x, DWORD_MAX, 0, 0)


74  Return This


75  End Function


76 


77  Function Append(x As Int64) As StringBuilder


78  ActiveBasic.Strings.Detail.FormatIntegerLD(This, x, DWORD_MAX, 0, 0)


79  Return This


80  End Function


81 


82  Function Append(x As QWord) As StringBuilder


83  ActiveBasic.Strings.Detail.FormatIntegerLU(This, x, DWORD_MAX, 0, 0)


84  Return This


85  End Function


86 


87  Function Append(x As Single) As StringBuilder


88  ActiveBasic.Strings.Detail.FormatFloatG(This, x, DWORD_MAX, 0, 0)


89  Return This


90  End Function


91 


92  Function Append(x As Double) As StringBuilder


93  ActiveBasic.Strings.Detail.FormatFloatG(This, x, DWORD_MAX, 0, 0)


94  Return This


95  End Function


96 


97  Function Append(x As Object) As StringBuilder


98  Append(x.ToString)


99  Return This


100  End Function


101 


102  Function Append(c As Char, n As Long) As StringBuilder


103  EnsureCapacity(size + n)


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


105  size += n


106  Return This


107  End Function


108 


109  Function Append(s As String) As StringBuilder


110  If Not String.IsNullOrEmpty(s) Then


111  appendCore(s, 0, s.Length)


112  End If


113  Return This


114  End Function


115 


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


117  Return Append(StrPtr(s), startIndex, count)


118  End Function


119 


120  Function Append(s As *Char, startIndex As Long, count As Long) As StringBuilder


121  If s = 0 Then


122  If startIndex = 0 And count = 0 Then


123  Return This


124  Else


125  Throw New ArgumentNullException("s")


126  End If


127  ElseIf startIndex < 0 Or count < 0 Then


128  Throw New ArgumentOutOfRangeException("startIndex or count or both")


129  End If


130  appendCore(s, startIndex, count)


131  Return This


132  End Function


133  Private


134  Sub appendCore(s As *Char, start As Long, count As Long)


135  EnsureCapacity(size + count)


136  separateBuffer()


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


138  size += count


139  End Sub


140 


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


142  EnsureCapacity(size + count)


143  separateBuffer()


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


145  size += count


146  End Sub


147  Public


148  'AppendFormat


149 


150  Function AppendLine() As StringBuilder


151  separateBuffer()


152  Append(Environment.NewLine)


153  Return This


154  End Function


155 


156  Function AppendLine(s As String) As StringBuilder


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


158  separateBuffer()


159  Append(s)


160  Append(Environment.NewLine)


161  Return This


162  End Function


163 


164  Const Sub CopyTo(sourceIndex As Long, ByRef dest[] As Char, destIndex As Long, count As Long)


165  If dest = 0 Then


166  Throw New ArgumentNullException("sourceIndex")


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


168  Throw New ArgumentOutOfRangeException("startIndex or count or both")


169  End If


170 


171  memcpy(VarPtr(dest[destIndex]), VarPtr(chars[sourceIndex]), count * SizeOf (Char))


172  End Sub


173 


174  Function EnsureCapacity(c As Long) As Long


175  If c < 0 Or c > MaxCapacity Then


176  Throw New ArgumentOutOfRangeException("c")


177  ElseIf c > Capacity Then


178  Dim p = GC_malloc_atomic((c + 1) * SizeOf (Char)) As *Char


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


180  chars = p


181  capacity = c


182  stringized = False


183  End If


184  End Function


185 


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


187 


188  Const Function Equals(s As StringBuilder) As Boolean


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


190  And capacity = s.capacity _


191  And maxCapacity = s.maxCapacity


192  End Function


193 


194  Override Function GetHashCode() As Long


195  #ifdef UNICODE


196  Dim n = size


197  #else


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


199  #endif


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


201  End Function


202 


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


204  rangeCheck(i)


205  insertCore(i, Str$(x))


206  Return This


207  End Function


208 


209  Function Insert(i As Long, x As Char) As StringBuilder


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


211  Return This


212  End Function


213  #ifdef UNICODE


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


215  rangeCheck(i)


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


217  Return This


218  End Function


219  #else


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


221  rangeCheck(i)


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


223  Return This


224  End Function


225  #endif


226 


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


228  rangeCheck(i)


229  insertCore(i, Str$(x))


230  Return This


231  End Function


232 


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


234  rangeCheck(i)


235  insertCore(i, Str$(x))


236  Return This


237  End Function


238 


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


240  rangeCheck(i)


241  insertCore(i, Str$(x))


242  Return This


243  End Function


244 


245  Function Insert(i As Long, x As DWord) 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 Int64) 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 Single) 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 Double) As StringBuilder


264  rangeCheck(i)


265  insertCore(i, Str$(x))


266  Return This


267  End Function


268 


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


270  rangeCheck(i)


271  insertCore(i, s)


272  Return This


273  End Function


274 


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


276  rangeCheck(i)


277  insertCore(i, o.ToString)


278  Return This


279  End Function


280 


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


282  rangeCheck(index)


283  If n < 0 Then


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


285  End If


286  Dim len = x.Length


287  Dim lenTotal = len * n


288  Dim newSize = size + lenTotal


289  EnsureCapacity(newSize)


290  separateBuffer()


291 


292  Dim i As Long


293  For i = 0 To ELM(n)


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


295  Next


296  size = newSize


297  Return This


298  End Function


299 


300  Function Insert(i As Long, x As *Char, index As Long, count As Long) As StringBuilder


301  rangeCheck(i)


302  If x = 0 Then


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


304  ElseIf index < 0 Or count < 0 Then


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


306  End If


307 


308  Dim newSize = size + count


309  EnsureCapacity(newSize)


310  separateBuffer()


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


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


313  size = newSize


314  Return This


315  End Function


316 


317  Private


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


319  Dim newSize = size + s.Length


320  EnsureCapacity(newSize)


321  separateBuffer()


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


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


324  size = newSize


325  End Sub


326  Public


327 


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


329  rangeCheck(startIndex, length)


330  separateBuffer()


331 


332  Dim moveStart = startIndex + length


333  ActiveBasic.Strings.ChrMove(


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


335  size = length


336  Return This


337  End Function


338 


339  Function Replace(oldChar As Char, newChar As Char) As StringBuilder


340  replaceCore(oldChar, newChar, 0, size)


341  Return This


342  End Function


343 


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


345  replaceCore(oldStr, newStr, 0, size)


346  Return This


347  End Function


348 


349  Function Replace(oldChar As Char, newChar As Char, startIndex As Long, count As Long) As StringBuilder


350  rangeCheck(startIndex, count)


351  replaceCore(oldChar, newChar, startIndex, count)


352  Return This


353  End Function


354 


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


356  rangeCheck(startIndex, count)


357  replaceCore(oldStr, newStr, startIndex, count)


358  Return This


359  End Function


360  Private


361  Sub replaceCore(oldChar As Char, newChar As Char, start As Long, count As Long)


362  separateBuffer()


363  Dim i As Long


364  Dim last = start + count  1'ELM(start + count)


365  For i = start To last


366  If chars[i] = oldChar Then


367  chars[i] = newChar


368  End If


369  Next


370  End Sub


371 


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


373  If ActiveBasic.IsNothing(oldStr) Then


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


375  ElseIf oldStr.Length = 0 Then


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


377  End If


378 


379  Dim s = New StringBuilder(capacity, maxCapacity)


380  Dim curPos = start


381  Dim last = start + count


382  Do


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


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


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


386  Exit Do


387  End If


388 


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


390  s.Append(newStr)


391  curPos += nextPos As Long + oldStr.Length


392  Loop


393  chars = s.chars


394  size = s.size


395  End Sub


396 


397  Public


398  Override Function ToString() As String


399  separateBuffer()


400  chars[size] = 0


401  Return New String(This)


402  End Function


403 


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


405  rangeCheck(startIndex, length)


406  Return New String(chars, startIndex, length)


407  End Function


408 


409  Const Function Operator [](i As Long) As Char


410  Return Chars[i]


411  End Function


412 


413  Sub Operator []=(i As Long, c As Char)


414  Chars[i] = c


415  End Sub


416 


417  'Properties


418  Const Function Capacity() As Long


419  Return capacity


420  End Function


421 


422  Sub Capacity(c As Long)


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


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


425  End If


426  EnsureCapacity(c)


427  End Sub


428 


429  Const Function Chars(i As Long) As Char


430  If i >= Length Or i < 0 Then


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


432  End If


433  Return chars[i]


434  End Function


435 


436  Sub Chars(i As Long, c As Char)


437  If i >= Length Or i < 0 Then


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


439  End If


440  separateBuffer()


441  chars[i] = c


442  End Sub


443 


444  Const Function Length() As Long


445  Return size


446  End Function


447 


448  Sub Length(i As Long)


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


450  If size < i Then


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


452  End If


453  size = i


454  End Sub


455 


456  Const Function MaxCapacity() As Long


457  Return maxCapacity


458  End Function


459 


460  /*!


461  @brief 内部用


462  代わりにStrPtr使ってください。


463  */


464  Function __Chars() As *Char


465  Return chars


466  End Function


467 


468  /*!


469  @brief 内部用


470  使わないでください。


471  */


472  Sub __Stringized()


473  stringized = True


474  End Sub


475 


476  Private


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


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


479  Throw New ArgumentOutOfRangeException("StringBuilder constructor", "capacity or maxCapacity or both")


480  End If


481 


482  If capacity = 0 Then


483  This.capacity = 1024


484  Else


485  This.capacity = capacity


486  End If


487 


488  This.maxCapacity = maxCapacity


489  This.size = 0


490  This.chars = GC_malloc_atomic((This.capacity + 1) * SizeOf (Char))


491  End Sub


492 


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


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


495 


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


497 


498  If Not String.IsNullOrEmpty(s) Then


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


500  size = length


501  End If


502  End Sub


503 


504  Sub rangeCheck(index As Long)


505  If index < 0 Or index > size Then


506  Throw New ArgumentOutOfRangeException("StringBuilder")


507  End If


508  End Sub


509 


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


511  StringBuilder.rangeCheck2(size, startIndex, count)


512  End Sub


513 


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


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


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


517  Throw New ArgumentOutOfRangeException("StringBuilder", "startIndex or count or both")


518  End If


519  End Sub


520 


521  Sub separateBuffer()


522  If stringized Then


523  Dim newChars = GC_malloc_atomic(SizeOf (Char) * capacity) As *Char


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


525  chars = newChars


526  stringized = False


527  End If


528  End Sub


529 


530  chars As *Char


531  maxCapacity As Long


532  capacity As Long


533  size As Long


534  stringized As Boolean


535  End Class


536 


537  End Namespace 'Text


538  End Namespace 'System


539 


540  '暫定


541  Function StrPtr(sb As System.Text.StringBuilder) As *Char


542  Return sb.__Chars


543  End Function

