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

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

(SPrintF.ab) FormatIntegerExにStringBuilderを引数に取る版を追加。

File size: 14.5 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 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
322Private
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
331Public
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
365Private
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
402Public
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
471Private
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
530End Class
531
532End Namespace 'Text
533End Namespace 'System
534
535'暫定
536Function StrPtr(sb As System.Text.StringBuilder) As *StrChar
537 Return sb.__Chars
538End Function
Note: See TracBrowser for help on using the repository browser.