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

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

Consoleをスレッド安全化(クリティカルセクション使用)。
Exception.HResultをPublicにした。
StringBuilder.Replaceが正しく機能しない問題を解消。

File size: 14.7 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 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
138Private
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
152Public
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 If p = 0 Then
185 'Throw OutOfMemoryException
186 Debug
187 End If
188 ActiveBasic.Strings.ChrCopy(p, chars, size As SIZE_T)
189 chars = p
190 capacity = c
191 stringized = False
192 End If
193 End Function
194
195 'Override Function Equals(o As Object) As Boolean
196
197 Const Function Equals(s As StringBuilder) As Boolean
198 Return ActiveBasic.Strings.StrCmp(chars, s.chars) = 0 _
199 And capacity = s.capacity _
200 And maxCapacity = s.maxCapacity
201 End Function
202
203 Override Function GetHashCode() As Long
204#ifdef __STRING_IS_NOT_UNICODE
205 Dim n = (size + 1) >> 1
206#else
207 Dim n = size
208#endif
209 Return _System_GetHashFromWordArray(chars As *Word, n As SIZE_T) Xor capacity Xor maxCapacity
210 End Function
211
212 Function Insert(i As Long, x As Boolean) As StringBuilder
213 rangeCheck(i)
214 insertCore(i, Str$(x))
215 Return This
216 End Function
217
218 Function Insert(i As Long, x As StrChar) As StringBuilder
219 Insert(i, VarPtr(x), 0, 1)
220 Return This
221 End Function
222#ifdef __STRING_IS_NOT_UNICODE
223 Function Insert(i As Long, x As Word) As StringBuilder
224 rangeCheck(i)
225 insertCore(i, Str$(x As DWord))
226 Return This
227 End Function
228#else
229 Function Insert(i As Long, x As SByte) As StringBuilder
230 rangeCheck(i)
231 insertCore(i, Str$(x As Long))
232 Return This
233 End Function
234#endif
235
236 Function Insert(i As Long, x As Byte) 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 Integer) 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 Long) 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 DWord) 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 Int64) 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 Single) As StringBuilder
267 rangeCheck(i)
268 insertCore(i, Str$(x))
269 Return This
270 End Function
271
272 Function Insert(i As Long, x As Double) As StringBuilder
273 rangeCheck(i)
274 insertCore(i, Str$(x))
275 Return This
276 End Function
277
278 Function Insert(i As Long, s As String) As StringBuilder
279 rangeCheck(i)
280 insertCore(i, s)
281 Return This
282 End Function
283
284 Function Insert(i As Long, o As Object) As StringBuilder
285 rangeCheck(i)
286 insertCore(i, o.ToString)
287 Return This
288 End Function
289
290 Function Insert(index As Long, x As String, n As Long) As StringBuilder
291 rangeCheck(index)
292 If n < 0 Then
293 Throw New ArgumentOutOfRangeException("StringBuilder.Insert: An argument is out of range value.", "n")
294 End If
295 Dim len = x.Length
296 Dim lenTotal = len * n
297 Dim newSize = size + lenTotal
298 EnsureCapacity(newSize)
299 separateBuffer()
300
301 Dim i As Long
302 For i = 0 To ELM(n)
303 x.CopyTo(0, chars, size + i * len, len)
304 Next
305 size = newSize
306 Return This
307 End Function
308
309 Function Insert(i As Long, x As *StrChar, index As Long, count As Long) As StringBuilder
310 rangeCheck(i)
311 If x = 0 Then
312 Throw New ArgumentNullException("StringBuilder.Insert: An argument is null", "x")
313 ElseIf index < 0 Or count < 0 Then
314 Throw New ArgumentOutOfRangeException("StringBuilder.Append: One or more arguments are out of range value.", "index or count or both")
315 End If
316
317 Dim newSize = size + count
318 EnsureCapacity(newSize)
319 separateBuffer()
320 ActiveBasic.Strings.ChrMove(VarPtr(chars[i + count]), VarPtr(chars[i]), (size - i) As SIZE_T)
321 ActiveBasic.Strings.ChrCopy(VarPtr(chars[i]), VarPtr(x[index]), count As SIZE_T)
322 size = newSize
323 Return This
324 End Function
325
326Private
327 Sub insertCore(i As Long, s As String)
328 Dim newSize = size + s.Length
329 EnsureCapacity(newSize)
330 separateBuffer()
331 ActiveBasic.Strings.ChrMove(VarPtr(chars[i + s.Length]), VarPtr(chars[i]), (size - i) As SIZE_T)
332 s.CopyTo(0, chars, i, s.Length)
333 size = newSize
334 End Sub
335Public
336
337 Function Remove(startIndex As Long, length As Long) As StringBuilder
338 rangeCheck(startIndex, length)
339 separateBuffer()
340
341 Dim moveStart = startIndex + length
342 ActiveBasic.Strings.ChrMove(
343 VarPtr(chars[startIndex]), VarPtr(chars[moveStart]), (size - moveStart) As SIZE_T)
344 size -= length
345 Return This
346 End Function
347
348 Function Replace(oldChar As StrChar, newChar As StrChar) As StringBuilder
349 replaceCore(oldChar, newChar, 0, size)
350 Return This
351 End Function
352
353 Function Replace(oldStr As String, newStr As String) As StringBuilder
354 replaceCore(oldStr, newStr, 0, size)
355 Return This
356 End Function
357
358 Function Replace(oldChar As StrChar, newChar As StrChar, startIndex As Long, count As Long) As StringBuilder
359 rangeCheck(startIndex, count)
360 replaceCore(oldChar, newChar, startIndex, count)
361 Return This
362 End Function
363
364 Function Replace(oldStr As String, newStr As String, startIndex As Long, count As Long) As StringBuilder
365 rangeCheck(startIndex, count)
366 replaceCore(oldStr, newStr, startIndex, count)
367 Return This
368 End Function
369Private
370 Sub replaceCore(oldChar As StrChar, newChar As StrChar, start As Long, count As Long)
371 separateBuffer()
372 Dim i As Long
373 Dim last = ELM(start + count)
374 For i = start To last
375 If chars[i] = oldChar Then
376 chars[i] = newChar
377 End If
378 Next
379 End Sub
380
381 Sub replaceCore(oldStr As String, newStr As String, start As Long, count As Long)
382 If ActiveBasic.IsNothing(oldStr) Then
383 Throw New ArgumentNullException("StringBuilder.Replace: An argument is null", "oldStr")
384 ElseIf oldStr.Length = 0 Then
385 Throw New ArgumentException("StringBuilder.Replace: The argument 'oldStr' is empty string. ", "oldStr")
386 End If
387
388 Dim s = New StringBuilder(capacity, maxCapacity)
389 Dim curPos = start
390 Dim last = start + count
391 Do
392 Dim nextPos = ActiveBasic.Strings.ChrFind(VarPtr(chars[curPos]) As *StrChar, size As SIZE_T, StrPtr(oldStr), oldStr.Length As SIZE_T) As Long
393 If nextPos = -1 As SIZE_T Or curPos > last Then
394 s.appendCore(chars, curPos, size - curPos)
395 Exit Do
396 End If
397
398 s.appendCore(chars, curPos, nextPos As Long)
399 s.Append(newStr)
400 curPos += nextPos As Long + oldStr.Length
401 Loop
402 chars = s.chars
403 size = s.size
404 End Sub
405
406Public
407 Override Function ToString() As String
408 chars[size] = 0
409 Return New String(This)
410 End Function
411
412 Const Function ToString(startIndex As Long, length As Long) As String
413 rangeCheck(startIndex, length)
414 Return New String(chars, startIndex, length)
415 End Function
416
417 Const Function Operator [](i As Long) As StrChar
418 Return Chars[i]
419 End Function
420
421 Sub Operator []=(i As Long, c As StrChar)
422 Chars[i] = c
423 End Sub
424
425 'Properties
426 Const Function Capacity() As Long
427 Return capacity
428 End Function
429
430 Sub Capacity(c As Long)
431 If c < size Or c > MaxCapacity Then 'sizeとの比較でcが負の場合も対応
432 Throw New ArgumentOutOfRangeException("StringBuilder.Capacity: An argument is out of range value.", "c")
433 End If
434 EnsureCapacity(c)
435 End Sub
436
437 Const Function Chars(i As Long) As StrChar
438 If i >= Length Or i < 0 Then
439 Throw New IndexOutOfRangeException("StringBuilder.Chars: The index argument 'i' is out of range value.")
440 End If
441 Return chars[i]
442 End Function
443
444 Sub Chars(i As Long, c As StrChar)
445 If i >= Length Or i < 0 Then
446 Throw New ArgumentOutOfRangeException("StringBuilder.Chars: An argument is out of range value.", "i")
447 End If
448 chars[i] = c
449 End Sub
450
451 Const Function Length() As Long
452 Return size
453 End Function
454
455 Sub Length(i As Long)
456 EnsureCapacity(i) 'iが適切な値かどうかの確認はこの中で行う
457 If size < i Then
458 ActiveBasic.Strings.ChrFill(VarPtr(chars[size]), (i - size + 1) As SIZE_T, 0 As StrChar)
459 End If
460 size = i
461 End Sub
462
463 Const Function MaxCapacity() As Long
464 Return maxCapacity
465 End Function
466
467 Function __Chars() As *StrChar
468 Return chars
469 End Function
470
471 Sub __Stringized()
472 stringized = True
473 End Sub
474
475Private
476 Sub initialize(capacity As Long, maxCapacity = LONG_MAX As Long)
477 If capacity < 0 Or maxCapacity < 1 Or maxCapacity < capacity Then
478 Throw New ArgumentOutOfRangeException("StringBuilder constructor: One or more arguments are out of range value.", "capacity or maxCapacity or both")
479 End If
480
481 If capacity = 0 Then
482 This.capacity = 1024
483 Else
484 This.capacity = capacity
485 End If
486
487 This.maxCapacity = maxCapacity
488 This.size = 0
489 This.chars = GC_malloc_atomic((This.capacity + 1) * SizeOf (StrChar))
490 If chars = 0 Then
491 'Throw OutOfMemoryException
492 Debug
493 End If
494
495 End Sub
496
497 Sub initialize(s As String, startIndex As Long, length As Long, capacity As Long, maxCapacity = LONG_MAX As Long)
498 StringBuilder.rangeCheck2(s.Length, startIndex, length)
499
500 initialize(Math.Max(capacity, length), maxCapacity)
501
502 If Not String.IsNullOrEmpty(s) Then
503 s.CopyTo(startIndex, chars, 0, length)
504 size = length
505 End If
506 End Sub
507
508 Sub rangeCheck(index As Long)
509 If index < 0 Or index > size Then
510 Throw New ArgumentOutOfRangeException("StringBuilder: Index argument is out of range value.")
511 End If
512 End Sub
513
514 Sub rangeCheck(startIndex As Long, count As Long)
515 StringBuilder.rangeCheck2(size, startIndex, count)
516 End Sub
517
518 Static Sub rangeCheck2(length As Long, startIndex As Long, count As Long)
519 'length < 0は判定に入っていないことに注意
520 If startIndex < 0 Or count < 0 Or startIndex + count > length Then
521 Throw New ArgumentOutOfRangeException("StringBuilder: One or more arguments are out of range value.", "startIndex or count or both")
522 End If
523 End Sub
524
525 Sub separateBuffer()
526 If stringized Then
527 Dim newChars = GC_malloc_atomic(SizeOf (StrChar) * capacity) As *StrChar
528 ActiveBasic.Strings.ChrCopy(newChars, chars, capacity As SIZE_T)
529 chars = newChars
530 stringized = False
531 End If
532 End Sub
533
534 chars As *StrChar
535 maxCapacity As Long
536 capacity As Long
537 size As Long
538 stringized As Boolean
539End Class
540
541End Namespace 'Text
542End Namespace 'System
543
544'暫定
545Function StrPtr(sb As System.Text.StringBuilder) As *StrChar
546 Return sb.__Chars
547End Function
Note: See TracBrowser for help on using the repository browser.