source: trunk/Include/Classes/System/Text/StringBuilder.ab@ 468

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

TextWriter, StreamWriterの追加。
SPrintfの浮動小数点数変換で、NaN, Infiniteの出力に対応。
PathとDirectoryInfoのCreateDirectoryで、対象が既に存在するときには例外を投げないように修正。
SimpleTestCase内で使用する一時フォルダの場所にGetTempPathで取得する版を追加(コメントアウト)。

File size: 14.9 KB
Line 
1'Classes/System/Text/StringBuilder.ab
2
3#require <Classes/ActiveBasic/Strings/Strings.ab>
4
5Namespace System
6Namespace Text
7
8Class StringBuilder
9 'Inherits ISerializable
10Public
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 Char) As StringBuilder
43 EnsureCapacity(size + 1)
44 separateBuffer()
45 chars[size] = x
46 size++
47 Return This
48 End Function
49#ifdef UNICODE
50 Function Append(x As SByte) As StringBuilder
51 ActiveBasic.Strings.Detail.FormatIntegerD(This, x, DWORD_MAX, 0, 0)
52 Return This
53 End Function
54#endif
55 Function Append(x As Byte) As StringBuilder
56 ActiveBasic.Strings.Detail.FormatIntegerU(This, x, DWORD_MAX, 0, 0)
57 Return This
58 End Function
59
60 Function Append(x As Integer) As StringBuilder
61 ActiveBasic.Strings.Detail.FormatIntegerD(This, x, DWORD_MAX, 0, 0)
62 Return This
63 End Function
64#ifndef UNICODE
65 Function Append(x As Word) As StringBuilder
66 ActiveBasic.Strings.Detail.FormatIntegerU(This, x, DWORD_MAX, 0, 0)
67 Return This
68 End Function
69#endif
70 Function Append(x As Long) As StringBuilder
71 ActiveBasic.Strings.Detail.FormatIntegerD(This, x, DWORD_MAX, 0, 0)
72 Return This
73 End Function
74
75 Function Append(x As DWord) As StringBuilder
76 ActiveBasic.Strings.Detail.FormatIntegerU(This, x, DWORD_MAX, 0, 0)
77 Return This
78 End Function
79
80 Function Append(x As Int64) As StringBuilder
81 ActiveBasic.Strings.Detail.FormatIntegerLD(This, x, DWORD_MAX, 0, 0)
82 Return This
83 End Function
84
85 Function Append(x As QWord) As StringBuilder
86 ActiveBasic.Strings.Detail.FormatIntegerLU(This, x, DWORD_MAX, 0, 0)
87 Return This
88 End Function
89
90 Function Append(x As Single) As StringBuilder
91 ActiveBasic.Strings.Detail.FormatFloatG(This, x, DWORD_MAX, 0, 0)
92 Return This
93 End Function
94
95 Function Append(x As Double) As StringBuilder
96 ActiveBasic.Strings.Detail.FormatFloatG(This, x, DWORD_MAX, 0, 0)
97 Return This
98 End Function
99
100 Function Append(x As Object) As StringBuilder
101 Append(x.ToString)
102 Return This
103 End Function
104
105 Function Append(c As Char, n As Long) As StringBuilder
106 EnsureCapacity(size + n)
107 ActiveBasic.Strings.ChrFill(VarPtr(chars[size]), n As SIZE_T, c)
108 size += n
109 Return This
110 End Function
111
112 Function Append(s As String) As StringBuilder
113 If Not String.IsNullOrEmpty(s) Then
114 appendCore(s, 0, s.Length)
115 End If
116 Return This
117 End Function
118
119 Function Append(s As String, startIndex As Long, count As Long) As StringBuilder
120 Return Append(StrPtr(s), startIndex, count)
121 End Function
122
123 Function Append(s As *Char, startIndex As Long, count As Long) As StringBuilder
124 If s = 0 Then
125 If startIndex = 0 And count = 0 Then
126 Return This
127 Else
128 Throw New ArgumentNullException("StringBuilder.Append: An argument is null", "s")
129 End If
130 ElseIf startIndex < 0 Or count < 0 Then
131 Throw New ArgumentOutOfRangeException("StringBuilder.Append: One or more arguments are out of range value.", "startIndex or count or both")
132 End If
133 appendCore(s, startIndex, count)
134 Return This
135 End Function
136Private
137 Sub appendCore(s As *Char, start As Long, count As Long)
138 EnsureCapacity(size + count)
139 separateBuffer()
140 ActiveBasic.Strings.ChrCopy(VarPtr(chars[size]), VarPtr(s[start]), count As SIZE_T)
141 size += count
142 End Sub
143
144 Sub appendCore(s As String, start As Long, count As Long)
145 EnsureCapacity(size + count)
146 separateBuffer()
147 s.CopyTo(start, chars, size, count)
148 size += count
149 End Sub
150Public
151 'AppendFormat
152
153 Function AppendLine() As StringBuilder
154 separateBuffer()
155 Append(Environment.NewLine)
156 Return This
157 End Function
158
159 Function AppendLine(s As String) As StringBuilder
160 EnsureCapacity(Capacity + s.Length + Environment.NewLine.Length)
161 separateBuffer()
162 Append(s)
163 Append(Environment.NewLine)
164 Return This
165 End Function
166
167 Const Sub CopyTo(sourceIndex As Long, ByRef dest[] As Char, destIndex As Long, count As Long)
168 If dest = 0 Then
169 Throw New ArgumentNullException("StringBuilder.CopyTo: An argument is null", "sourceIndex")
170 ElseIf size < sourceIndex + count Or sourceIndex < 0 Or destIndex < 0 Or count < 0 Then
171 Throw New ArgumentOutOfRangeException("StringBuilder.CopyTo: One or more arguments are out of range value.", "startIndex or count or both")
172 End If
173
174 memcpy(VarPtr(dest[destIndex]), VarPtr(chars[sourceIndex]), count * SizeOf (Char))
175 End Sub
176
177 Function EnsureCapacity(c As Long) As Long
178 If c < 0 Or c > MaxCapacity Then
179 Throw New ArgumentOutOfRangeException("StringBuilder.Append: An argument is out of range value.", "c")
180 ElseIf c > Capacity Then
181 Dim p = GC_malloc_atomic((c + 1) * SizeOf (Char)) As *Char
182 ActiveBasic.Strings.ChrCopy(p, chars, size As SIZE_T)
183 chars = p
184 capacity = c
185 stringized = False
186 End If
187 End Function
188
189 'Override Function Equals(o As Object) As Boolean
190
191 Const Function Equals(s As StringBuilder) As Boolean
192 Return ActiveBasic.Strings.StrCmp(chars, s.chars) = 0 _
193 And capacity = s.capacity _
194 And maxCapacity = s.maxCapacity
195 End Function
196
197 Override Function GetHashCode() As Long
198#ifdef __STRING_IS_NOT_UNICODE
199 Dim n = (size + 1) >> 1
200#else
201 Dim n = size
202#endif
203 Return _System_GetHashFromWordArray(chars As *Word, n As SIZE_T) Xor capacity Xor maxCapacity
204 End Function
205
206 Function Insert(i As Long, x As Boolean) As StringBuilder
207 rangeCheck(i)
208 insertCore(i, Str$(x))
209 Return This
210 End Function
211
212 Function Insert(i As Long, x As Char) As StringBuilder
213 Insert(i, VarPtr(x), 0, 1)
214 Return This
215 End Function
216#ifdef __STRING_IS_NOT_UNICODE
217 Function Insert(i As Long, x As Word) As StringBuilder
218 rangeCheck(i)
219 insertCore(i, Str$(x As DWord))
220 Return This
221 End Function
222#else
223 Function Insert(i As Long, x As SByte) As StringBuilder
224 rangeCheck(i)
225 insertCore(i, Str$(x As Long))
226 Return This
227 End Function
228#endif
229
230 Function Insert(i As Long, x As Byte) As StringBuilder
231 rangeCheck(i)
232 insertCore(i, Str$(x))
233 Return This
234 End Function
235
236 Function Insert(i As Long, x As Integer) As StringBuilder
237 rangeCheck(i)
238 insertCore(i, Str$(x))
239 Return This
240 End Function
241
242 Function Insert(i As Long, x As Long) As StringBuilder
243 rangeCheck(i)
244 insertCore(i, Str$(x))
245 Return This
246 End Function
247
248 Function Insert(i As Long, x As DWord) As StringBuilder
249 rangeCheck(i)
250 insertCore(i, Str$(x))
251 Return This
252 End Function
253
254 Function Insert(i As Long, x As Int64) As StringBuilder
255 rangeCheck(i)
256 insertCore(i, Str$(x))
257 Return This
258 End Function
259
260 Function Insert(i As Long, x As Single) As StringBuilder
261 rangeCheck(i)
262 insertCore(i, Str$(x))
263 Return This
264 End Function
265
266 Function Insert(i As Long, x As Double) As StringBuilder
267 rangeCheck(i)
268 insertCore(i, Str$(x))
269 Return This
270 End Function
271
272 Function Insert(i As Long, s As String) As StringBuilder
273 rangeCheck(i)
274 insertCore(i, s)
275 Return This
276 End Function
277
278 Function Insert(i As Long, o As Object) As StringBuilder
279 rangeCheck(i)
280 insertCore(i, o.ToString)
281 Return This
282 End Function
283
284 Function Insert(index As Long, x As String, n As Long) As StringBuilder
285 rangeCheck(index)
286 If n < 0 Then
287 Throw New ArgumentOutOfRangeException("StringBuilder.Insert: An argument is out of range value.", "n")
288 End If
289 Dim len = x.Length
290 Dim lenTotal = len * n
291 Dim newSize = size + lenTotal
292 EnsureCapacity(newSize)
293 separateBuffer()
294
295 Dim i As Long
296 For i = 0 To ELM(n)
297 x.CopyTo(0, chars, size + i * len, len)
298 Next
299 size = newSize
300 Return This
301 End Function
302
303 Function Insert(i As Long, x As *Char, index As Long, count As Long) As StringBuilder
304 rangeCheck(i)
305 If x = 0 Then
306 Throw New ArgumentNullException("StringBuilder.Insert: An argument is null", "x")
307 ElseIf index < 0 Or count < 0 Then
308 Throw New ArgumentOutOfRangeException("StringBuilder.Append: One or more arguments are out of range value.", "index or count or both")
309 End If
310
311 Dim newSize = size + count
312 EnsureCapacity(newSize)
313 separateBuffer()
314 ActiveBasic.Strings.ChrMove(VarPtr(chars[i + count]), VarPtr(chars[i]), (size - i) As SIZE_T)
315 ActiveBasic.Strings.ChrCopy(VarPtr(chars[i]), VarPtr(x[index]), count As SIZE_T)
316 size = newSize
317 Return This
318 End Function
319
320Private
321 Sub insertCore(i As Long, s As String)
322 Dim newSize = size + s.Length
323 EnsureCapacity(newSize)
324 separateBuffer()
325 ActiveBasic.Strings.ChrMove(VarPtr(chars[i + s.Length]), VarPtr(chars[i]), (size - i) As SIZE_T)
326 s.CopyTo(0, chars, i, s.Length)
327 size = newSize
328 End Sub
329Public
330
331 Function Remove(startIndex As Long, length As Long) As StringBuilder
332 rangeCheck(startIndex, length)
333 separateBuffer()
334
335 Dim moveStart = startIndex + length
336 ActiveBasic.Strings.ChrMove(
337 VarPtr(chars[startIndex]), VarPtr(chars[moveStart]), (size - moveStart) As SIZE_T)
338 size -= length
339 Return This
340 End Function
341
342 Function Replace(oldChar As Char, newChar As Char) As StringBuilder
343 replaceCore(oldChar, newChar, 0, size)
344 Return This
345 End Function
346
347 Function Replace(oldStr As String, newStr As String) As StringBuilder
348 replaceCore(oldStr, newStr, 0, size)
349 Return This
350 End Function
351
352 Function Replace(oldChar As Char, newChar As Char, startIndex As Long, count As Long) As StringBuilder
353 rangeCheck(startIndex, count)
354 replaceCore(oldChar, newChar, startIndex, count)
355 Return This
356 End Function
357
358 Function Replace(oldStr As String, newStr As String, startIndex As Long, count As Long) As StringBuilder
359 rangeCheck(startIndex, count)
360 replaceCore(oldStr, newStr, startIndex, count)
361 Return This
362 End Function
363Private
364 Sub replaceCore(oldChar As Char, newChar As Char, start As Long, count As Long)
365 separateBuffer()
366 Dim i As Long
367 Dim last = ELM(start + count)
368 For i = start To last
369 If chars[i] = oldChar Then
370 chars[i] = newChar
371 End If
372 Next
373 End Sub
374
375 Sub replaceCore(oldStr As String, newStr As String, start As Long, count As Long)
376 If ActiveBasic.IsNothing(oldStr) Then
377 Throw New ArgumentNullException("StringBuilder.Replace: An argument is null", "oldStr")
378 ElseIf oldStr.Length = 0 Then
379 Throw New ArgumentException("StringBuilder.Replace: The argument 'oldStr' is empty string. ", "oldStr")
380 End If
381
382 Dim s = New StringBuilder(capacity, maxCapacity)
383 Dim curPos = start
384 Dim last = start + count
385 Do
386 Dim nextPos = ActiveBasic.Strings.ChrFind(VarPtr(chars[curPos]) As *Char, size As SIZE_T, StrPtr(oldStr), oldStr.Length As SIZE_T) As Long
387 If nextPos = -1 As SIZE_T Or curPos > last Then
388 s.appendCore(chars, curPos, size - curPos)
389 Exit Do
390 End If
391
392 s.appendCore(chars, curPos, nextPos As Long)
393 s.Append(newStr)
394 curPos += nextPos As Long + oldStr.Length
395 Loop
396 chars = s.chars
397 size = s.size
398 End Sub
399
400Public
401 Override Function ToString() As String
402 chars[size] = 0
403 Return New String(This)
404 End Function
405
406 Const Function ToString(startIndex As Long, length As Long) As String
407 rangeCheck(startIndex, length)
408 Return New String(chars, startIndex, length)
409 End Function
410
411 Const Function Operator [](i As Long) As Char
412 Return Chars[i]
413 End Function
414
415 Sub Operator []=(i As Long, c As Char)
416 Chars[i] = c
417 End Sub
418
419 'Properties
420 Const Function Capacity() As Long
421 Return capacity
422 End Function
423
424 Sub Capacity(c As Long)
425 If c < size Or c > MaxCapacity Then 'sizeとの比較でcが負の場合も対応
426 Throw New ArgumentOutOfRangeException("StringBuilder.Capacity: An argument is out of range value.", "c")
427 End If
428 EnsureCapacity(c)
429 End Sub
430
431 Const Function Chars(i As Long) As Char
432 If i >= Length Or i < 0 Then
433 Throw New IndexOutOfRangeException("StringBuilder.Chars: The index argument 'i' is out of range value.")
434 End If
435 Return chars[i]
436 End Function
437
438 Sub Chars(i As Long, c As Char)
439 If i >= Length Or i < 0 Then
440 Throw New ArgumentOutOfRangeException("StringBuilder.Chars: An argument is out of range value.", "i")
441 End If
442 chars[i] = c
443 End Sub
444
445 Const Function Length() As Long
446 Return size
447 End Function
448
449 Sub Length(i As Long)
450 EnsureCapacity(i) 'iが適切な値かどうかの確認はこの中で行う
451 If size < i Then
452 ActiveBasic.Strings.ChrFill(VarPtr(chars[size]), (i - size + 1) As SIZE_T, 0 As Char)
453 End If
454 size = i
455 End Sub
456
457 Const Function MaxCapacity() As Long
458 Return maxCapacity
459 End Function
460
461 Function __Chars() As *Char
462 Return chars
463 End Function
464
465 Sub __Stringized()
466 stringized = True
467 End Sub
468
469Private
470 Sub initialize(capacity As Long, maxCapacity = LONG_MAX As Long)
471 If capacity < 0 Or maxCapacity < 1 Or maxCapacity < capacity Then
472 Throw New ArgumentOutOfRangeException("StringBuilder constructor: One or more arguments are out of range value.", "capacity or maxCapacity or both")
473 End If
474
475 If capacity = 0 Then
476 This.capacity = 1024
477 Else
478 This.capacity = capacity
479 End If
480
481 This.maxCapacity = maxCapacity
482 This.size = 0
483 This.chars = GC_malloc_atomic((This.capacity + 1) * SizeOf (Char))
484 End Sub
485
486 Sub initialize(s As String, startIndex As Long, length As Long, capacity As Long, maxCapacity = LONG_MAX As Long)
487 StringBuilder.rangeCheck2(s.Length, startIndex, length)
488
489 initialize(Math.Max(capacity, length), maxCapacity)
490
491 If Not String.IsNullOrEmpty(s) Then
492 s.CopyTo(startIndex, chars, 0, length)
493 size = length
494 End If
495 End Sub
496
497 Sub rangeCheck(index As Long)
498 If index < 0 Or index > size Then
499 Throw New ArgumentOutOfRangeException("StringBuilder: Index argument is out of range value.")
500 End If
501 End Sub
502
503 Sub rangeCheck(startIndex As Long, count As Long)
504 StringBuilder.rangeCheck2(size, startIndex, count)
505 End Sub
506
507 Static Sub rangeCheck2(length As Long, startIndex As Long, count As Long)
508 'length < 0は判定に入っていないことに注意
509 If startIndex < 0 Or count < 0 Or startIndex + count > length Then
510 Throw New ArgumentOutOfRangeException("StringBuilder: One or more arguments are out of range value.", "startIndex or count or both")
511 End If
512 End Sub
513
514 Sub separateBuffer()
515 If stringized Then
516 Dim newChars = GC_malloc_atomic(SizeOf (Char) * capacity) As *Char
517 ActiveBasic.Strings.ChrCopy(newChars, chars, capacity As SIZE_T)
518 chars = newChars
519 stringized = False
520 End If
521 End Sub
522
523 chars As *Char
524 maxCapacity As Long
525 capacity As Long
526 size As Long
527 stringized As Boolean
528End Class
529
530End Namespace 'Text
531End Namespace 'System
532
533'暫定
534Function StrPtr(sb As System.Text.StringBuilder) As *Char
535 Return sb.__Chars
536End Function
Note: See TracBrowser for help on using the repository browser.