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

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

SPrintf関数の実装

File size: 13.8 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        If s = 0 Then
123            If startIndex = 0 And count = 0 Then
124                Return This
125            Else
126                'Throw ArgumentNullException
127            End If
128        End If
129        StringBuilder.rangeCheck2(s.Length, startIndex, count)
130        appendCore(s, startIndex, count)
131        Return This
132    End Function
133
134    Function Append(s As *StrChar, startIndex As Long, count As Long) As StringBuilder
135        If s = 0 Then
136            If startIndex = 0 And count = 0 Then
137                Return This
138            Else
139                'Throw ArgumentNullException
140            End If
141        ElseIf startIndex < 0 Or count < 0 Then
142            'Throw ArgumentOutOfRangeException
143        End If
144        appendCore(s, startIndex, count)
145        Return This
146    End Function
147Private
148    Sub appendCore(s As *StrChar, start As Long, count As Long)
149        EnsureCapacity(size + count)
150        separateBuffer()
151        ActiveBasic.Strings.ChrCopy(VarPtr(chars[size]), VarPtr(s[start]), count As SIZE_T)
152        size += count
153    End Sub
154
155    Sub appendCore(s As String, start As Long, count As Long)
156        EnsureCapacity(size + count)
157        separateBuffer()
158        s.CopyTo(start, chars, size, count)
159        size += count
160    End Sub
161Public
162    'AppendFormat
163
164    Function AppendLine() As StringBuilder
165        separateBuffer()
166        Append(Environment.NewLine)
167        Return This
168    End Function
169
170    Function AppendLine(s As String) As StringBuilder
171        EnsureCapacity(Capacity + s.Length + Environment.NewLine.Length)
172        separateBuffer()
173        Append(s)
174        Append(Environment.NewLine)
175        Return This
176    End Function
177
178    Const Sub CopyTo(sourceIndex As Long, ByRef dest[] As StrChar, destIndex As Long, count As Long)
179        If dest = 0 Then
180            'Throw ArgumentNullException
181        ElseIf size < sourceIndex + count Or sourceIndex < 0 Or destIndex < 0 Or count < 0 Then
182            'Throw ArgumentOutOfRangeException
183        End If
184
185        memcpy(VarPtr(dest[destIndex]), VarPtr(chars[sourceIndex]), count * SizeOf (StrChar))
186    End Sub
187
188    Function EnsureCapacity(c As Long) As Long
189        If c < 0 Or c > MaxCapacity Then
190            'Throw ArgumentOutOfRangeException
191        ElseIf c > Capacity Then
192            Dim p = GC_malloc_atomic((c + 1) * SizeOf (StrChar)) As *StrChar
193            If p = 0 Then
194                'Throw OutOfMemoryException
195                Debug
196            End If
197            ActiveBasic.Strings.ChrCopy(p, chars, size As SIZE_T)
198            chars = p
199            capacity = c
200            stringized = False
201        End If
202    End Function
203
204    'Override Function Equals(o As Object) As Boolean
205
206    Const Function Equals(s As StringBuilder) As Boolean
207        Return ActiveBasic.Strings.StrCmp(chars, s.chars) = 0 _
208            And capacity = s.capacity _
209            And maxCapacity = s.maxCapacity
210    End Function
211
212    Override Function GetHashCode() As Long
213#ifdef __STRING_IS_NOT_UNICODE
214        Dim n = (size + 1) >> 1
215#else
216        Dim n = size
217#endif
218        Return _System_GetHashFromWordArray(chars As *Word, n As SIZE_T) Xor capacity Xor maxCapacity
219    End Function
220
221    Function Insert(i As Long, x As Boolean) As StringBuilder
222        rangeCheck(i)
223        insertCore(i, Str$(x))
224        Return This
225    End Function
226
227    Function Insert(i As Long, x As StrChar) As StringBuilder
228        Insert(i, VarPtr(x), 0, 1)
229        Return This
230    End Function
231#ifdef __STRING_IS_NOT_UNICODE
232    Function Insert(i As Long, x As Word) As StringBuilder
233        rangeCheck(i)
234        insertCore(i, Str$(x As DWord))
235        Return This
236    End Function
237#else
238    Function Insert(i As Long, x As SByte) As StringBuilder
239        rangeCheck(i)
240        insertCore(i, Str$(x As Long))
241        Return This
242    End Function
243#endif
244
245    Function Insert(i As Long, x As Byte) 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 Integer) 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 Long) 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 DWord) As StringBuilder
264        rangeCheck(i)
265        insertCore(i, Str$(x))
266        Return This
267    End Function
268
269    Function Insert(i As Long, x As Int64) As StringBuilder
270        rangeCheck(i)
271        insertCore(i, Str$(x))
272        Return This
273    End Function
274
275    Function Insert(i As Long, x As Single) As StringBuilder
276        rangeCheck(i)
277        insertCore(i, Str$(x))
278        Return This
279    End Function
280
281    Function Insert(i As Long, x As Double) As StringBuilder
282        rangeCheck(i)
283        insertCore(i, Str$(x))
284        Return This
285    End Function
286
287    Function Insert(i As Long, s As String) As StringBuilder
288        rangeCheck(i)
289        insertCore(i, s)
290        Return This
291    End Function
292
293    Function Insert(i As Long, o As Object) As StringBuilder
294        rangeCheck(i)
295        insertCore(i, o.ToString)
296        Return This
297    End Function
298
299    Function Insert(index As Long, x As String, n As Long) As StringBuilder
300        rangeCheck(index)
301        If n < 0 Then
302            'Throw New ArgumentOutOfRangeException
303            Debug
304        End If
305        Dim len = x.Length
306        Dim lenTotal = len * n
307        Dim newSize = size + lenTotal
308        EnsureCapacity(newSize)
309        separateBuffer()
310
311        ' TODO: fix me!(定義されていない変数iが使われています)
312        'ActiveBasic.Strings.ChrMove(VarPtr(chars[i + lenTotal]), VarPtr(chars[i]), (size - index) As SIZE_T)
313
314        Dim i As Long
315        For i = 0 To ELM(n)
316            x.CopyTo(0, chars, size + i * len, len)
317        Next
318        size = newSize
319        Return This
320    End Function
321
322
323    Function Insert(i As Long, x As *StrChar, index As Long, count As Long) As StringBuilder
324        rangeCheck(i)
325        If x = 0 Then
326            'Throw New ArgumentNullException
327            Debug
328        ElseIf index < 0 Or count < 0 Then
329            'Throw New ArgumentNullException
330            Debug
331        End If
332
333        Dim newSize = size + count
334        EnsureCapacity(newSize)
335        separateBuffer()
336        ActiveBasic.Strings.ChrMove(VarPtr(chars[i + count]), VarPtr(chars[i]), (size - i) As SIZE_T)
337        ActiveBasic.Strings.ChrCopy(VarPtr(chars[i]), VarPtr(x[index]), count As SIZE_T)
338        size = newSize
339        Return This
340    End Function
341
342Private
343    Sub insertCore(i As Long, s As String)
344        Dim newSize = size + s.Length
345        EnsureCapacity(newSize)
346        separateBuffer()
347        ActiveBasic.Strings.ChrMove(VarPtr(chars[i + s.Length]), VarPtr(chars[i]), (size - i) As SIZE_T)
348        s.CopyTo(0, chars, i, s.Length)
349        size = newSize
350    End Sub
351Public
352
353    Function Remove(startIndex As Long, length As Long) As StringBuilder
354        rangeCheck(startIndex, length)
355        separateBuffer()
356
357        Dim moveStart = startIndex + length
358        ActiveBasic.Strings.ChrMove(
359            VarPtr(chars[startIndex]), VarPtr(chars[moveStart]), (size - moveStart) As SIZE_T)
360        size -= length
361        Return This
362    End Function
363
364    Function Replace(oldChar As StrChar, newChar As StrChar) As StringBuilder
365        replaceCore(oldChar, newChar, 0, size)
366        Return This
367    End Function
368
369    Function Replace(oldStr As String, newStr As String) As StringBuilder
370        replaceCore(oldStr, newStr, 0, size)
371        Return This
372    End Function
373
374    Function Replace(oldChar As StrChar, newChar As StrChar, startIndex As Long, count As Long) As StringBuilder
375        rangeCheck(startIndex, count)
376        replaceCore(oldChar, newChar, startIndex, count)
377        Return This
378    End Function
379
380    Function Replace(oldStr As String, newStr As String, startIndex As Long, count As Long) As StringBuilder
381        rangeCheck(startIndex, count)
382        replaceCore(oldStr, newStr, startIndex, count)
383        Return This
384    End Function
385Private
386    Sub replaceCore(oldChar As StrChar, newChar As StrChar, start As Long, count As Long)
387        separateBuffer()
388        Dim i As Long
389        Dim last = ELM(start + count)
390        For i = start To last
391            If chars[i] = oldChar Then
392                chars[i] = newChar
393            End If
394        Next
395    End Sub
396
397    Sub replaceCore(oldStr As String, newStr As String, start As Long, count As Long)
398        If Object.ReferenceEquals(oldStr, Nothing) Then
399            'Throw ArgumentNullException
400            Debug
401        ElseIf oldStr.Length = 0 Then
402            'Throw ArgumentException
403            Debug
404        End If
405
406        Dim s = New StringBuilder(capacity, maxCapacity)
407        Dim curPos = 0 As Long
408        Do
409            Dim nextPos = ActiveBasic.Strings.ChrFind(VarPtr(chars[curPos]) As *StrChar, size As SIZE_T, StrPtr(oldStr), oldStr.Length As SIZE_T) As Long
410            If nextPos = -1 As SIZE_T Then
411                Exit Sub
412            End If
413           
414            s.appendCore(chars, curPos, nextPos)
415            s.Append(newStr)
416            curPos += nextPos + oldStr.Length
417        Loop
418        chars = s.chars
419        size = s.size
420    End Sub
421
422Public
423    Override Function ToString() As String
424        chars[size] = 0
425        Return New String(This)
426    End Function
427
428    Const Function ToString(startIndex As Long, length As Long) As String
429        rangeCheck(startIndex, length)
430        Return New String(chars, startIndex, length)
431    End Function
432
433    Const Function Operator [](i As Long) As StrChar
434        Return Chars[i]
435    End Function
436
437    Sub Operator []=(i As Long, c As StrChar)
438        Chars[i] = c
439    End Sub
440
441    'Properties
442    Const Function Capacity() As Long
443        Return capacity
444    End Function
445
446    Sub Capacity(c As Long)
447        If c < size Or c > MaxCapacity Then 'sizeとの比較でcが負の場合も対応
448            'Throw ArgumentOutOfRangeException
449        End If
450        EnsureCapacity(c)
451    End Sub
452
453    Const Function Chars(i As Long) As StrChar
454        If i >= Length Or i < 0 Then
455            'Throw IndexOutOfRangeException
456            Debug
457        End If
458        Return chars[i]
459    End Function
460
461    Sub Chars(i As Long, c As StrChar)
462        If i >= Length Or i < 0 Then
463            'Throw ArgumentOutOfRangeException
464            Debug
465        End If
466        chars[i] = c
467    End Sub
468
469    Const Function Length() As Long
470        Return size
471    End Function
472
473    Sub Length(i As Long)
474        EnsureCapacity(i) 'iが適切な値かどうかの確認はこの中で行う
475        If size < i Then
476            ActiveBasic.Strings.ChrFill(VarPtr(chars[size]), (i - size + 1) As SIZE_T, 0 As StrChar)
477        End If
478        size = i
479    End Sub
480
481    Const Function MaxCapacity() As Long
482        Return maxCapacity
483    End Function
484
485    Function __Chars() As *StrChar
486        Return chars
487    End Function
488
489    Sub __Stringized()
490        stringized = True
491    End Sub
492
493Private
494    Sub initialize(capacity As Long, maxCapacity = LONG_MAX As Long)
495        If capacity < 0 Or maxCapacity < 1 Or maxCapacity < capacity Then
496            'Throw ArgumentOutOfRangeException
497        End If
498
499        If capacity = 0 Then
500            This.capacity = 1024
501        Else
502            This.capacity = capacity
503        End If
504
505        This.maxCapacity = maxCapacity
506        This.size = 0
507        This.chars = GC_malloc_atomic((This.capacity + 1) * SizeOf (StrChar))
508        If chars = 0 Then
509            'Throw OutOfMemoryException
510            Debug
511        End If
512
513    End Sub
514
515    Sub initialize(s As String, startIndex As Long, length As Long, capacity As Long, maxCapacity = LONG_MAX As Long)
516        StringBuilder.rangeCheck2(s.Length, startIndex, length)
517
518        initialize(Math.Max(capacity, length), maxCapacity)
519
520        If Not String.IsNullOrEmpty(s) Then
521            s.CopyTo(startIndex, chars, 0, length)
522            size = length
523        End If
524    End Sub
525
526    Sub rangeCheck(index As Long)
527        If index < 0 Or index > size Then
528            'Throw ArgumentOutOfRangeException
529            Debug
530        End If
531    End Sub
532
533    Sub rangeCheck(startIndex As Long, count As Long)
534        StringBuilder.rangeCheck2(size, startIndex, count)
535    End Sub
536
537    Static Sub rangeCheck2(length As Long, startIndex As Long, count As Long)
538        'length < 0は判定に入っていないことに注意
539        If startIndex < 0 Or count < 0 Or startIndex + count > length Then
540            'Throw ArgumentOutOfRangeException
541            Debug
542        End If
543    End Sub
544
545    Sub separateBuffer()
546        If stringized Then
547            Dim newChars = GC_malloc_atomic(SizeOf (StrChar) * capacity) As *StrChar
548            ActiveBasic.Strings.ChrCopy(newChars, chars, capacity As SIZE_T)
549            chars = newChars
550            stringized = False
551        End If
552    End Sub
553
554    chars As *StrChar
555    maxCapacity As Long
556    capacity As Long
557    size As Long
558    stringized As Boolean
559End Class
560
561End Namespace 'Text
562End Namespace 'System
563
564'暫定
565Function StrPtr(sb As System.Text.StringBuilder) As *StrChar
566    Return sb.__Chars
567End Function
Note: See TracBrowser for help on using the repository browser.