source: Include/Classes/System/String.ab @ 182

Last change on this file since 182 was 182, checked in by dai, 16 years ago

_System_StrCmpのオーバーロードが解決できないバグを修正。

File size: 16.1 KB
Line 
1' Classes/System/String.ab
2
3#require <basic/function.sbp>
4
5#ifdef __STRING_IS_NOT_ALWAYS_UNICODE
6TypeDef StrChar = Char
7#ifndef UNICODE
8#define __STRING_IS_NOT_UNICODE
9#endif
10#else
11TypeDef StrChar = WCHAR
12#ifndef UNICODE
13#define __STRING_UNICODE_WINDOWS_ANSI
14#endif
15#endif
16
17Class String
18    m_Length As Long
19Public
20    Chars As *StrChar
21
22    Sub String()
23        Chars = 0
24        m_Length = 0
25    End Sub
26
27    Sub String(initStr As *Byte)
28        String()
29        Assign(initStr As PCTSTR)
30    End Sub
31
32    Sub String(initStr As PCSTR)
33        String()
34        Assign(initStr)
35    End Sub
36
37    Sub String(initStr As PCSTR, length As Long)
38        String()
39        Assign(initStr, length)
40    End Sub
41
42    Sub String(initStr As PCWSTR)
43        String()
44        Assign(initStr)
45    End Sub
46
47    Sub String(initStr As PCWSTR, length As Long)
48        String()
49        Assign(initStr, length)
50    End Sub
51
52    Sub String(ByRef initStr As String)
53        String()
54        Assign(initStr)
55    End Sub
56
57    Sub String(length As Long)
58        String()
59        ReSize(length)
60    End Sub
61
62    Sub String(initChar As StrChar, length As Long)
63        ReSize(length, initChar)
64    End Sub
65
66    Sub ~String()
67        _System_free(Chars)
68        Chars = 0
69#ifdef _DEBUG
70        m_Length = 0
71#endif
72    End Sub
73
74    Const Function Length() As Long
75        Return m_Length
76    End Function
77
78    Function Operator() As *StrChar
79        Return Chars
80    End Function
81
82    Sub Operator = (ByRef objString As String)
83        Assign(objString.Chars, objString.m_Length)
84    End Sub
85
86    Sub Operator = (text As *Byte)
87        Assign(text As PCTSTR)
88    End Sub
89
90    Sub Operator = (text As PCSTR)
91        Assign(text)
92    End Sub
93
94    Sub Operator = (text As PCWSTR)
95        Assign(text)
96    End Sub
97
98    Const Function Operator [] (n As Long) As StrChar
99#ifdef _DEBUG
100        If n > Length Then
101            'Throw ArgumentOutOfRangeException
102            Debug
103        End If
104#endif
105        Return Chars[n]
106    End Function
107
108    Sub Operator []= (n As Long, c As StrChar)
109#ifdef _DEBUG
110        If n >= Length Then
111            'Throw ArgumentOutOfRangeException
112            Debug
113        End If
114#endif
115        Chars[n] = c
116    End Sub
117
118    Const Function Operator + (text As *Byte) As String
119        Return Concat(text As PCTSTR, lstrlen(text))
120    End Function
121
122    Const Function Operator + (text As PCSTR) As String
123        Return Concat(text, lstrlenA(text))
124    End Function
125
126    Const Function Operator + (text As PCWSTR) As String
127        Return Concat(text, lstrlenW(text))
128    End Function
129
130    Const Function Operator + (ByRef objString As String) As String
131        Return Concat(objString.Chars, objString.m_Length)
132    End Function
133
134    Const Function Operator & (text As PCSTR) As String
135        Dim tempString = This + text
136        Return tempString
137    End Function
138
139    Const Function Operator & (text As PCWSTR) As String
140        Dim tempString = This + text
141        Return tempString
142    End Function
143
144    Const Function Operator & (ByRef objString As String) As String
145        Dim tempString = This + objString
146        Return tempString
147    End Function
148
149    Const Function Operator == (ByRef objString As String) As Boolean
150        Return _System_StrCmp(This.Chars, objString.Chars) = 0
151    End Function
152
153    Const Function Operator == (text As *StrChar) As Long
154        Return _System_StrCmp(This.Chars, text) = 0
155    End Function
156
157    Const Function Operator <> (ByRef objString As String) As Boolean
158        Return _System_StrCmp(This.Chars, objString.Chars) <> 0
159    End Function
160
161    Const Function Operator <> (text As *StrChar) As Boolean
162        Return _System_StrCmp(This.Chars, text) <> 0
163    End Function
164
165    Const Function Operator < (ByRef objString As String) As Boolean
166        Return _System_StrCmp(This.Chars, objString.Chars) < 0
167    End Function
168
169    Const Function Operator < (text As *StrChar) As Boolean
170        Return _System_StrCmp(This.Chars, text) < 0
171    End Function
172
173    Const Function Operator > (ByRef objString As String) As Boolean
174        Return _System_StrCmp(This.Chars, objString.Chars) > 0
175    End Function
176
177    Const Function Operator > (text As *StrChar) As Boolean
178        Return _System_StrCmp(This.Chars, text) > 0
179    End Function
180
181    Const Function Operator <= (ByRef objString As String) As Boolean
182        Return _System_StrCmp(This.Chars, objString.Chars) <= 0
183    End Function
184
185    Const Function Operator <= (text As *StrChar) As Boolean
186        Return _System_StrCmp(This.Chars, text) <= 0
187    End Function
188
189    Const Function Operator >= (ByRef objString As String) As Boolean
190        Return _System_StrCmp(This.Chars, objString.Chars) >= 0
191    End Function
192
193    Const Function Operator >= (text As *StrChar) As Boolean
194        Return _System_StrCmp(This.Chars, text) >= 0
195    End Function
196
197    Const Function StrPtr() As *StrChar
198        Return Chars
199    End Function
200
201    Sub ReSize(allocLength As Long)
202        If allocLength < 0 Then Exit Sub
203        If allocLength > m_Length Then
204            Dim oldLength As Long
205            oldLength = m_Length
206            If AllocStringBuffer(allocLength) <> 0 Then
207                ZeroMemory(VarPtr(Chars[oldLength]), SizeOf (StrChar) * (m_Length - oldLength + 1))
208            End If
209        Else
210            m_Length = allocLength
211            Chars[m_Length] = 0
212        End If
213    End Sub
214
215    Sub ReSize(allocLength As Long, c As StrChar)
216        If allocLength < 0 Then
217            Exit Sub
218        ElseIf allocLength > m_Length Then
219            Dim oldLength As Long
220            oldLength = m_Length
221            If AllocStringBuffer(allocLength) <> 0 Then
222                Dim p = VarPtr(Chars[oldLength]) As *StrChar
223                Dim fillLen = m_Length - oldLength
224                Dim i As Long
225                For i = 0 To ELM(fillLen)
226                    p[i] = c
227                Next
228            End If
229        Else
230            m_Length = allocLength
231        End If
232        Chars[m_Length] = 0
233    End Sub
234
235    Sub Assign(text As PCSTR, textLengthA As Long)
236#ifdef __STRING_IS_NOT_UNICODE
237        AssignFromStrChar(text, textLengthA)
238#else
239        Dim textLengthW = MultiByteToWideChar(CP_THREAD_ACP, 0, text, textLengthA, 0, 0)
240        If AllocStringBuffer(textLengthW) <> 0 Then
241            MultiByteToWideChar(CP_THREAD_ACP, 0, text, textLengthA, Chars, textLengthW)
242        End If
243#endif
244    End Sub
245
246    Sub Assign(text As PCWSTR, textLengthW As Long)
247#ifdef __STRING_IS_NOT_UNICODE
248        Dim textLengthA = WideCharToMultiByte(CP_THREAD_ACP, 0, text, textLengthW, 0, 0, 0, 0)
249        If AllocStringBuffer(textLengthA) <> 0 Then
250            WideCharToMultiByte(CP_THREAD_ACP, 0, text, textLengthW, Chars, textLengthA, 0, 0)
251        End If
252#else
253        AssignFromStrChar(text, textLengthW)
254#endif
255    End Sub
256
257    Sub Assign(ByRef objString As String)
258        Assign(objString.Chars, objString.m_Length)
259    End Sub
260
261    Sub Assign(text As PCSTR)
262        If text Then
263            Assign(text, lstrlenA(text))
264        Else
265            If Chars <> 0 Then
266                Chars[0] = 0
267            End If
268            m_Length = 0
269        End If
270    End Sub
271
272    Sub Assign(text As PCWSTR)
273        If text Then
274            Assign(text, lstrlenW(text))
275        Else
276            If Chars <> 0 Then
277                Chars[0] = 0
278            End If
279            m_Length = 0
280        End If
281    End Sub
282
283    Sub Append(text As *StrChar, textLength As Long)
284        Dim prevLen As Long
285        prevLen = m_Length
286        If AllocStringBuffer(m_Length + textLength) <> 0 Then
287            memcpy(VarPtr(Chars[prevLen]), text, SizeOf (StrChar) * textLength)
288            Chars[m_Length] = 0
289        End If
290    End Sub
291
292    Sub Append(text As *StrChar)
293        Append(text, lstrlen(text))
294    End Sub
295
296    Sub Append(ByRef str As String)
297        Append(str.Chars, str.m_Length)
298    End Sub
299
300    Const Function Clone() As String
301        Return This
302    End Function
303Private
304    Static Const Function ConcatStrChar(text1 As *StrChar, text1Length As Long, text2 As *StrChar, text2Length As Long) As String
305        With ConcatStrChar
306            .AllocStringBuffer(text1Length + text2Length)
307            memcpy(.Chars, text1, SizeOf (StrChar) * text1Length)
308            memcpy(VarPtr(.Chars[text1Length]), text2, SizeOf (StrChar) * text2Length)
309            .Chars[text1Length + text2Length] = 0
310        End With
311    End Function
312Public
313    Const Function Concat(text As PCSTR, len As Long) As String
314#ifdef __STRING_IS_NOT_UNICODE
315        Return ConcatStrChar(This.Chars, m_Length, text, len)
316#else
317        With Concat
318            Dim lenW = MultiByteToWideChar(CP_THREAD_ACP, 0, text, len, 0, 0)
319            .AllocStringBuffer(m_Length + lenW)
320            memcpy(.Chars, This.Chars, m_Length)
321            MultiByteToWideChar(CP_THREAD_ACP, 0, text, len, VarPtr(.Chars[m_Length]), lenW)
322            .Chars[m_Length + lenW] = 0
323        End With
324#endif
325    End Function
326
327    Const Function Concat(text As PCWSTR, len As Long) As String
328#ifdef __STRING_IS_NOT_UNICODE
329        With Concat
330            Dim lenA = MultiByteToWideChar(CP_THREAD_ACP, 0, text, len, 0, 0, 0, 0)
331            .AllocStringBuffer(m_Length + lenA)
332            memcpy(.Chars, This.Chars, m_Length)
333            MultiByteToWideChar(CP_THREAD_ACP, 0, text, len, VarPtr(.Chars[m_Length]), lenA, 0, 0)
334            .Chars[m_Length + lenA] = 0
335        End With
336#else
337        Return ConcatStrChar(This.Chars, m_Length, text, len)
338#endif
339    End Function
340    Const Function Contains(ByRef objString As String) As Boolean
341        Return IndexOf(objString, 0, m_Length) >= 0
342    End Function
343
344    Const Function Contains(lpszText As *StrChar) As Boolean
345        Return IndexOf(lpszText, 0, m_Length) >= 0
346    End Function
347
348    Const Function IndexOf(lpszText As *StrChar) As Long
349        Return IndexOf(lpszText, 0, m_Length)
350    End Function
351
352    Const Function IndexOf(lpszText As *StrChar, startIndex As Long) As Long
353        Return IndexOf(lpszText, startIndex, m_Length - startIndex)
354    End Function
355
356    Const Function IndexOf(lpszText As *StrChar, startIndex As Long, count As Long) As Long
357        Dim length = lstrlen(lpszText)
358
359        If startIndex < 0 Then Return -1
360        If count < 1 Or count + startIndex > m_Length Then Return -1
361        If length > m_Length Then Return -1
362
363        If length = 0 Then Return startIndex
364
365        Dim i As Long, j As Long
366        For i = startIndex To startIndex + count - 1
367            For j = 0 To length - 1
368                If Chars[i + j] = lpszText[j] Then
369                    If j = length - 1 Then Return i
370                Else
371                    Exit For
372                End If
373            Next
374        Next
375        Return -1
376    End Function
377
378    Const Function LastIndexOf(lpszText As *StrChar) As Long
379        Return LastIndexOf(lpszText, m_Length - 1, m_Length)
380    End Function
381
382    Const Function LastIndexOf(lpszText As *StrChar, startIndex As Long) As Long
383        Return LastIndexOf(lpszText As *StrChar, startIndex, startIndex + 1)
384    End Function
385
386    Const Function LastIndexOf(lpszText As *StrChar, startIndex As Long, count As Long) As Long
387        Dim length = lstrlen(lpszText)
388
389        If startIndex < 0 Or startIndex > m_Length - 1 Then Return -1
390        If count < 1 Or count > startIndex + 2 Then Return -1
391        If length > m_Length Then Return -1
392
393        If length = 0 Then Return startIndex
394
395        Dim i As Long, j As Long
396        For i = startIndex To  startIndex - count + 1 Step -1
397            For j = length - 1 To 0 Step -1
398                If Chars[i + j] = lpszText[j] Then
399                    If j = 0 Then Return i
400                Else
401                    Exit For
402                End If
403            Next
404        Next
405        Return -1
406    End Function
407
408    Const Function StartsWith(lpszText As *StrChar) As Boolean
409        Return IndexOf(lpszText) = 0
410    End Function
411
412    Const Function EndsWith(lpszText As *StrChar) As Boolean
413        Return LastIndexOf(lpszText) = m_Length - lstrlen(lpszText)
414    End Function
415
416    Const Function Insert(startIndex As Long, text As String) As String
417        Return Insert(startIndex, text.Chars, text.Length)
418    End Function
419
420    Const Function Insert(startIndex As Long, text As *StrChar) As String
421        Return Insert(startIndex, text, lstrlen(text))
422    End Function
423
424    Const Function Insert(startIndex As Long, text As *StrChar, length As Long) As String
425        If startIndex < 0 Or startIndex > m_Length Or length < 0 Then
426            Debug 'ArgumentOutOfRangeException
427
428        End If
429        Insert.ReSize(m_Length + length)
430        memcpy(Insert.Chars, Chars, SizeOf (StrChar) * startIndex)
431        memcpy(VarPtr(Insert.Chars[startIndex]), text, SizeOf (StrChar) * length)
432        memcpy(VarPtr(Insert.Chars[startIndex + length]), VarPtr(Chars[startIndex]), SizeOf (StrChar) * (m_Length - startIndex + 1))
433    End Function
434
435    Const Function SubString(startIndex As Long) As String
436        Return SubString(startIndex, m_Length - startIndex)
437    End Function
438
439    Const Function SubString(startIndex As Long, length As Long) As String
440        If startIndex < 0 Or length <= 0 Then Return ""
441        If startIndex + length > m_Length Then Return ""
442
443        Dim temp As String
444        temp.AllocStringBuffer(length)
445        memcpy(temp.Chars, VarPtr(Chars[startIndex]), SizeOf (StrChar) * length)
446        Chars[m_Length] = 0
447        Return temp
448    End Function
449
450    Const Function Remove(startIndex As Long) As String
451        If startIndex < 0 Or startIndex > m_Length Then
452            Debug 'ArgumentOutOfRangeException
453        End If
454
455        Remove.ReSize(startIndex)
456        memcpy(Remove.Chars, This.Chars, SizeOf (StrChar) * startIndex)
457    End Function
458
459    Const Function Remove(startIndex As Long, count As Long) As String
460        If startIndex < 0 Or count < 0 Or startIndex + count > m_Length Then
461            Debug 'ArgumentOutOfRangeException
462        End If
463
464        Remove.ReSize(m_Length - count)
465        memcpy(Remove.Chars, This.Chars, SizeOf (StrChar) * startIndex)
466        memcpy(VarPtr(Remove.Chars[startIndex]), VarPtr(This.Chars[startIndex + count]), SizeOf (StrChar) * (m_Length - startIndex - count))
467    End Function
468/*
469    Static Function IsNullOrEmpty(s As String) As Boolean
470        If s <> Nothing Then
471            If s.m_Length > 0 Then
472                Return True
473            End If
474        End If
475        Return False
476    End Function
477*/
478    Const Function Replace(oldChar As StrChar, newChar As StrChar) As String
479        Replace = Copy(This)
480        With Replace
481            Dim i As Long
482            For i = 0 To ELM(.m_Length)
483                If .Chars[i] = oldChar Then
484                    .Chars[i] = newChar
485                End If
486            Next
487        End With
488    End Function
489
490    Const Function Replace(ByRef oldStr As String, ByRef newStr As String) As String
491'       If oldStr = Nothing Then Throw ArgumentNullException
492'
493'       If newStr = Nothing Then
494'           Return ReplaceCore(oldStr, oldStr.m_Length, "", 0)
495'       Else
496            Return ReplaceCore(oldStr, oldStr.m_Length, newStr, newStr.m_Length)
497'       End If
498    End Function
499
500    Const Function Replace(oldStr As *StrChar, newStr As *StrChar)
501        If oldStr = 0 Then Debug 'Throw ArgumentNullException
502        If newStr = 0 Then newStr = ""
503        Return ReplaceCore(oldStr, lstrlen(oldStr), newStr, lstrlen(newStr)) As String
504    End Function
505
506    Const Function Replace(oldStr As *StrChar, oldLen As Long, newStr As *StrChar, newLen As Long) As String
507        If oldStr = 0 Then Debug 'Throw ArgumentNullException
508        If newStr = 0 Then
509            newStr = ""
510            newLen = 0
511        End If
512        Return ReplaceCore(oldStr, oldLen, newStr, newLen)
513    End Function
514
515    Const Function ToLower() As String
516        ToLower.ReSize(m_Length)
517        Dim i As Long
518        For i = 0 To ELM(m_Length)
519            ToLower.Chars[i] = _System_ASCII_ToLower(Chars[i])
520        Next
521    End Function
522
523    Const Function ToUpper() As String
524        ToUpper.ReSize(m_Length)
525        Dim i As Long
526        For i = 0 To ELM(m_Length)
527            ToUpper.Chars[i] = _System_ASCII_ToUpper(Chars[i])
528        Next
529    End Function
530
531    Sub Swap(ByRef x As String)
532        Dim tempLen As Long
533        Dim tempChars As *StrChar
534        tempLen = x.m_Length
535        tempChars = x.Chars
536        x.m_Length = This.m_Length
537        x.Chars = This.Chars
538        This.m_Length = tempLen
539        This.Chars = tempChars
540    End Sub
541
542    Override Function ToString() As String
543        Return This
544    End Function
545
546    Static Function Copy(s As String) As String
547        Copy.ReSize(s.m_Length)
548        memcpy(Copy.Chars, This.Chars, SizeOf (StrChar) * m_Length)
549    End Function
550
551    Override Function GetHashCode() As Long
552#ifdef __STRING_IS_NOT_UNICODE
553        Dim size = (m_Length + 1) >> 1
554#else
555        Dim size = m_Length
556#endif
557        Return _System_GetHashFromWordArray(Chars As *Word, size)
558    End Function
559Private
560    ' メモリ確保に失敗すると元の文字列は失われない。(例外安全でいう強い保障)
561    Function AllocStringBuffer(textLength As Long) As *StrChar
562        If textLength < 0 Then
563            Return 0
564        ElseIf textLength > m_Length Then
565            AllocStringBuffer = _System_realloc(Chars, SizeOf(StrChar) * (textLength + 1))
566            If AllocStringBuffer <> 0 Then
567                m_Length = textLength
568                Chars = AllocStringBuffer
569            End If
570        Else
571            m_Length = textLength
572            AllocStringBuffer = Chars
573        End If
574    End Function
575
576    Function ReplaceCore(oldStr As *StrChar, oldLen As Long, newStr As *StrChar, newLen As Long) As String
577        If oldLen = 0 Then
578            Debug 'Throw ArgumentException
579        End If
580        Dim tmp As String
581        With tmp
582            Dim current = 0 As Long
583            Do
584                Dim pos = IndexOf(oldStr, current)
585                If pos = -1 Then
586                    Exit Do
587                End If
588                .Append(VarPtr(Chars[current]), pos - current)
589                .Append(newStr, newLen)
590                current = pos + oldLen
591            Loop
592            .Append(VarPtr(Chars[current]), m_Length - current)
593        End With
594        Return tmp
595    End Function
596
597    Sub AssignFromStrChar(text As *StrChar, textLength As Long)
598        If text = Chars Then Exit Sub
599        If AllocStringBuffer(textLength) <> 0 Then
600            memcpy(Chars, text, SizeOf (StrChar) * textLength)
601            Chars[m_Length] = 0
602        End If
603    End Sub
604End Class
Note: See TracBrowser for help on using the repository browser.