source: trunk/ab5.0/ablib/src/Classes/System/Text/StringBuilder.ab@ 689

Last change on this file since 689 was 689, checked in by イグトランス (egtra), 15 years ago

書換禁止のバッファを書き換えるバグを修正

File size: 14.5 KB
RevLine 
[272]1'Classes/System/Text/StringBuilder.ab
2
3Namespace System
4Namespace Text
5
6Class StringBuilder
7Public
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
[468]39 Function Append(x As Char) As StringBuilder
[272]40 EnsureCapacity(size + 1)
41 separateBuffer()
42 chars[size] = x
43 size++
44 Return This
45 End Function
[468]46#ifdef UNICODE
[272]47 Function Append(x As SByte) As StringBuilder
[468]48 ActiveBasic.Strings.Detail.FormatIntegerD(This, x, DWORD_MAX, 0, 0)
[272]49 Return This
50 End Function
51#endif
52 Function Append(x As Byte) As StringBuilder
[468]53 ActiveBasic.Strings.Detail.FormatIntegerU(This, x, DWORD_MAX, 0, 0)
[272]54 Return This
55 End Function
56
57 Function Append(x As Integer) As StringBuilder
[468]58 ActiveBasic.Strings.Detail.FormatIntegerD(This, x, DWORD_MAX, 0, 0)
[272]59 Return This
60 End Function
[468]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
[272]67 Function Append(x As Long) As StringBuilder
[468]68 ActiveBasic.Strings.Detail.FormatIntegerD(This, x, DWORD_MAX, 0, 0)
[272]69 Return This
70 End Function
71
72 Function Append(x As DWord) As StringBuilder
[468]73 ActiveBasic.Strings.Detail.FormatIntegerU(This, x, DWORD_MAX, 0, 0)
[272]74 Return This
75 End Function
76
77 Function Append(x As Int64) As StringBuilder
[468]78 ActiveBasic.Strings.Detail.FormatIntegerLD(This, x, DWORD_MAX, 0, 0)
[272]79 Return This
80 End Function
81
82 Function Append(x As QWord) As StringBuilder
[468]83 ActiveBasic.Strings.Detail.FormatIntegerLU(This, x, DWORD_MAX, 0, 0)
[272]84 Return This
85 End Function
86
87 Function Append(x As Single) As StringBuilder
[468]88 ActiveBasic.Strings.Detail.FormatFloatG(This, x, DWORD_MAX, 0, 0)
[272]89 Return This
90 End Function
91
92 Function Append(x As Double) As StringBuilder
[468]93 ActiveBasic.Strings.Detail.FormatFloatG(This, x, DWORD_MAX, 0, 0)
[272]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
[468]102 Function Append(c As Char, n As Long) As StringBuilder
[272]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
[385]117 Return Append(StrPtr(s), startIndex, count)
[272]118 End Function
119
[468]120 Function Append(s As *Char, startIndex As Long, count As Long) As StringBuilder
[272]121 If s = 0 Then
122 If startIndex = 0 And count = 0 Then
123 Return This
124 Else
[689]125 Throw New ArgumentNullException("s")
[272]126 End If
127 ElseIf startIndex < 0 Or count < 0 Then
[689]128 Throw New ArgumentOutOfRangeException("startIndex or count or both")
[272]129 End If
130 appendCore(s, startIndex, count)
131 Return This
132 End Function
133Private
[468]134 Sub appendCore(s As *Char, start As Long, count As Long)
[272]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
147Public
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
[468]164 Const Sub CopyTo(sourceIndex As Long, ByRef dest[] As Char, destIndex As Long, count As Long)
[272]165 If dest = 0 Then
[689]166 Throw New ArgumentNullException("sourceIndex")
[272]167 ElseIf size < sourceIndex + count Or sourceIndex < 0 Or destIndex < 0 Or count < 0 Then
[689]168 Throw New ArgumentOutOfRangeException("startIndex or count or both")
[272]169 End If
170
[468]171 memcpy(VarPtr(dest[destIndex]), VarPtr(chars[sourceIndex]), count * SizeOf (Char))
[272]172 End Sub
173
174 Function EnsureCapacity(c As Long) As Long
175 If c < 0 Or c > MaxCapacity Then
[689]176 Throw New ArgumentOutOfRangeException("c")
[272]177 ElseIf c > Capacity Then
[468]178 Dim p = GC_malloc_atomic((c + 1) * SizeOf (Char)) As *Char
[272]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
[497]195#ifdef UNICODE
196 Dim n = size
197#else
[272]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
[468]209 Function Insert(i As Long, x As Char) As StringBuilder
[272]210 Insert(i, VarPtr(x), 0, 1)
211 Return This
212 End Function
[497]213#ifdef UNICODE
214 Function Insert(i As Long, x As SByte) As StringBuilder
[272]215 rangeCheck(i)
[497]216 insertCore(i, Str$(x As Long))
[272]217 Return This
218 End Function
219#else
[497]220 Function Insert(i As Long, x As Word) As StringBuilder
[272]221 rangeCheck(i)
[497]222 insertCore(i, Str$(x As DWord))
[272]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
[388]284 Throw New ArgumentOutOfRangeException("StringBuilder.Insert: An argument is out of range value.", "n")
[272]285 End If
286 Dim len = x.Length
287 Dim lenTotal = len * n
288 Dim newSize = size + lenTotal
289 EnsureCapacity(newSize)
290 separateBuffer()
[288]291
[272]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
[468]300 Function Insert(i As Long, x As *Char, index As Long, count As Long) As StringBuilder
[272]301 rangeCheck(i)
302 If x = 0 Then
[388]303 Throw New ArgumentNullException("StringBuilder.Insert: An argument is null", "x")
[272]304 ElseIf index < 0 Or count < 0 Then
[388]305 Throw New ArgumentOutOfRangeException("StringBuilder.Append: One or more arguments are out of range value.", "index or count or both")
[272]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
317Private
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
326Public
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
[468]339 Function Replace(oldChar As Char, newChar As Char) As StringBuilder
[272]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
[468]349 Function Replace(oldChar As Char, newChar As Char, startIndex As Long, count As Long) As StringBuilder
[272]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
360Private
[468]361 Sub replaceCore(oldChar As Char, newChar As Char, start As Long, count As Long)
[272]362 separateBuffer()
363 Dim i As Long
[521]364 Dim last = start + count - 1'ELM(start + count)
[272]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)
[385]373 If ActiveBasic.IsNothing(oldStr) Then
[388]374 Throw New ArgumentNullException("StringBuilder.Replace: An argument is null", "oldStr")
[272]375 ElseIf oldStr.Length = 0 Then
[385]376 Throw New ArgumentException("StringBuilder.Replace: The argument 'oldStr' is empty string. ", "oldStr")
[272]377 End If
378
379 Dim s = New StringBuilder(capacity, maxCapacity)
[435]380 Dim curPos = start
381 Dim last = start + count
[272]382 Do
[468]383 Dim nextPos = ActiveBasic.Strings.ChrFind(VarPtr(chars[curPos]) As *Char, size As SIZE_T, StrPtr(oldStr), oldStr.Length As SIZE_T) As Long
[435]384 If nextPos = -1 As SIZE_T Or curPos > last Then
385 s.appendCore(chars, curPos, size - curPos)
386 Exit Do
[272]387 End If
388
[385]389 s.appendCore(chars, curPos, nextPos As Long)
[272]390 s.Append(newStr)
[385]391 curPos += nextPos As Long + oldStr.Length
[272]392 Loop
393 chars = s.chars
394 size = s.size
395 End Sub
396
397Public
398 Override Function ToString() As String
[689]399 separateBuffer()
[272]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
[468]409 Const Function Operator [](i As Long) As Char
[272]410 Return Chars[i]
411 End Function
412
[468]413 Sub Operator []=(i As Long, c As Char)
[272]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が負の場合も対応
[388]424 Throw New ArgumentOutOfRangeException("StringBuilder.Capacity: An argument is out of range value.", "c")
[272]425 End If
426 EnsureCapacity(c)
427 End Sub
428
[468]429 Const Function Chars(i As Long) As Char
[272]430 If i >= Length Or i < 0 Then
[388]431 Throw New IndexOutOfRangeException("StringBuilder.Chars: The index argument 'i' is out of range value.")
[272]432 End If
433 Return chars[i]
434 End Function
435
[468]436 Sub Chars(i As Long, c As Char)
[272]437 If i >= Length Or i < 0 Then
[388]438 Throw New ArgumentOutOfRangeException("StringBuilder.Chars: An argument is out of range value.", "i")
[272]439 End If
[689]440 separateBuffer()
[272]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
[468]451 ActiveBasic.Strings.ChrFill(VarPtr(chars[size]), (i - size + 1) As SIZE_T, 0 As Char)
[272]452 End If
453 size = i
454 End Sub
455
456 Const Function MaxCapacity() As Long
457 Return maxCapacity
458 End Function
459
[629]460 /*!
461 @brief 内部用
462 代わりにStrPtr使ってください。
463 */
[468]464 Function __Chars() As *Char
[272]465 Return chars
466 End Function
467
[629]468 /*!
469 @brief 内部用
470 使わないでください。
471 */
[272]472 Sub __Stringized()
473 stringized = True
474 End Sub
475
476Private
477 Sub initialize(capacity As Long, maxCapacity = LONG_MAX As Long)
478 If capacity < 0 Or maxCapacity < 1 Or maxCapacity < capacity Then
[629]479 Throw New ArgumentOutOfRangeException("StringBuilder constructor", "capacity or maxCapacity or both")
[272]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
[468]490 This.chars = GC_malloc_atomic((This.capacity + 1) * SizeOf (Char))
[272]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)
[383]500 size = length
[272]501 End If
502 End Sub
503
504 Sub rangeCheck(index As Long)
505 If index < 0 Or index > size Then
[629]506 Throw New ArgumentOutOfRangeException("StringBuilder")
[272]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
[629]517 Throw New ArgumentOutOfRangeException("StringBuilder", "startIndex or count or both")
[272]518 End If
519 End Sub
520
521 Sub separateBuffer()
522 If stringized Then
[468]523 Dim newChars = GC_malloc_atomic(SizeOf (Char) * capacity) As *Char
[272]524 ActiveBasic.Strings.ChrCopy(newChars, chars, capacity As SIZE_T)
525 chars = newChars
526 stringized = False
527 End If
528 End Sub
529
[468]530 chars As *Char
[272]531 maxCapacity As Long
532 capacity As Long
533 size As Long
534 stringized As Boolean
535End Class
536
537End Namespace 'Text
538End Namespace 'System
539
540'暫定
[468]541Function StrPtr(sb As System.Text.StringBuilder) As *Char
[272]542 Return sb.__Chars
543End Function
Note: See TracBrowser for help on using the repository browser.