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

Last change on this file since 221 was 221, checked in by dai, 17 years ago

Stringクラスのコンストラクタに0バイトのChar配列を引き渡すとString.Charsへのメモリ確保が行われないバグを修正。
SimpleTestCaseプロジェクトをアップロード

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