1
2
3
4
5
6 using System.Collections;
7
8 namespace System
9 {
10 public typedef String<char> string;
11 public typedef String<wchar> wstring;
12 public typedef String<uchar> ustring;
13
14 public nothrow const char* EmptyString(char x)
15 {
16 return "";
17 }
18
19 public nothrow const wchar* EmptyString(wchar x)
20 {
21 return w"";
22 }
23
24 public nothrow const uchar* EmptyString(uchar x)
25 {
26 return u"";
27 }
28
29 public class String<CharT>
30 {
31 public typedef RandomAccessIter<CharT, const CharT&, const CharT*> ConstIterator;
32 public typedef RandomAccessIter<CharT, CharT&, CharT*> Iterator;
33
34 public inline nothrow String() : chars(null), len(0), res(0)
35 {
36 }
37 public inline nothrow String(const CharT* chars_) : len(StrLen(chars_)), res(0), chars(null)
38 {
39 if (len > 0)
40 {
41 Reserve(len);
42 StrCopy(chars, chars_);
43 }
44 }
45 public inline nothrow String(const CharT* chars_, long length_) : len(0), res(0), chars(null)
46 {
47 if (length_ > 0)
48 {
49 Reserve(length_);
50 len = StrCopy(chars, chars_, length_);
51 }
52 }
53 public inline nothrow String(const CharT* begin, const CharT* end) : this(begin, end - begin)
54 {
55 }
56 public nothrow String(const String<CharT>& that) : len(that.len), res(0), chars(null)
57 {
58 if (len > 0)
59 {
60 Reserve(len);
61 StrCopy(chars, that.chars);
62 }
63 }
64 public nothrow String(String<CharT>&& that) : len(that.len), res(that.res), chars(that.chars)
65 {
66 that.len = 0;
67 that.res = 0;
68 that.chars = null;
69 }
70 public inline explicit nothrow String(CharT c) : len(1), res(0), chars(null)
71 {
72 Reserve(1);
73 chars[0] = c;
74 chars[1] = '\0';
75 }
76 public nothrow String(CharT c, long n) : len(n), res(0), chars(null)
77 {
78 if (n > 0)
79 {
80 Reserve(n);
81 for (long i = 0; i < n; ++i;)
82 {
83 chars[i] = c;
84 }
85 chars[n] = '\0';
86 }
87 }
88 public nothrow void operator=(const String<CharT>& that)
89 {
90 Deallocate();
91 Reserve(that.len);
92 len = that.len;
93 if (len > 0)
94 {
95 StrCopy(chars, that.chars);
96 }
97 }
98 public inline nothrow void operator=(String<CharT>&& that)
99 {
100 Swap(len, that.len);
101 Swap(res, that.res);
102 Swap(chars, that.chars);
103 }
104 public ~String()
105 {
106 Deallocate();
107 }
108 public inline nothrow long Length() const
109 {
110 return len;
111 }
112 public inline nothrow long Capacity() const
113 {
114 return res;
115 }
116 public inline nothrow bool IsEmpty() const
117 {
118 return len == 0;
119 }
120 public nothrow void Clear()
121 {
122 Deallocate();
123 }
124 public inline nothrow const CharT* Chars() const
125 {
126 if (chars != null)
127 {
128 return chars;
129 }
130 return EmptyString(CharT());
131 }
132 public inline CharT operator[](long index) const
133 {
134 if (index < 0 || index >= len)
135 {
136 ThrowIndexOutOfBoundsException();
137 }
138 return chars[index];
139 }
140 public inline CharT& operator[](long index)
141 {
142 if (index < 0 || index >= len)
143 {
144 ThrowIndexOutOfBoundsException();
145 }
146 return chars[index];
147 }
148 public nothrow void Reserve(long minLen)
149 {
150 if (minLen > 0)
151 {
152 long minRes = minLen + 1;
153 if (minRes > res)
154 {
155 Grow(minRes);
156 }
157 }
158 }
159 public inline nothrow String<CharT>& Append(CharT c)
160 {
161 Reserve(len + 1);
162 chars[len] = c;
163 chars[++len] = '\0';
164 return *this;
165 }
166 public String<CharT>& Append(CharT c, long count)
167 {
168 if (count < 0)
169 {
170 ThrowInvalidParameterException();
171 }
172 if (count > 0)
173 {
174 Reserve(len + count);
175 for (long i = 0; i < count; ++i;)
176 {
177 chars[len++] = c;
178 }
179 chars[len] = '\0';
180 }
181 return *this;
182 }
183 public inline nothrow String<CharT>& Append(const CharT* that)
184 {
185 AppendFrom(that, StrLen(that));
186 return *this;
187 }
188 public inline nothrow String<CharT>& Append(const CharT* that, long count)
189 {
190 AppendFrom(that, count);
191 return *this;
192 }
193 public inline nothrow String<CharT>& Append(const String<CharT>& that)
194 {
195 AppendFrom(that.chars, that.len);
196 return *this;
197 }
198 public void Insert(long index, CharT c)
199 {
200 if (index < 0)
201 {
202 ThrowIndexOutOfBoundsException();
203 }
204 if (index >= len)
205 {
206 Append(c);
207 }
208 else
209 {
210 Reserve(len + 1);
211 for (long i = len - 1; i >= index; --i;)
212 {
213 chars[i + 1] = chars[i];
214 }
215 chars[index] = c;
216 ++len;
217 chars[len] = '\0';
218 }
219 }
220 public void Insert(long index, const String<CharT>& that)
221 {
222 if (index < 0)
223 {
224 ThrowIndexOutOfBoundsException();
225 }
226 if (that.IsEmpty()) return;
227 if (index >= len)
228 {
229 Append(that);
230 }
231 else
232 {
233 Reserve(len + that.len);
234 for (long i = len - 1; i >= index; --i;)
235 {
236 chars[i + that.len] = chars[i];
237 }
238 for (long i = 0; i < that.len; ++i;)
239 {
240 chars[index + i] = that.chars[i];
241 }
242 len = len + that.len;
243 chars[len] = '\0';
244 }
245 }
246 public void Remove(long index, long count)
247 {
248 if (index < 0)
249 {
250 ThrowIndexOutOfBoundsException();
251 }
252 if (count < 0)
253 {
254 ThrowInvalidParameterException();
255 }
256 if (IsEmpty()) return;
257 if (index > len)
258 {
259 index = len;
260 }
261 if (index + count > len)
262 {
263 count = len - index;
264 }
265 for (long i = index; i < len - count; ++i;)
266 {
267 chars[i] = chars[i + count];
268 }
269 len = len - count;
270 chars[len] = '\0';
271 }
272 public nothrow void Replace(CharT oldChar, CharT newChar)
273 {
274 long n = len;
275 for (long i = 0; i < n; ++i;)
276 {
277 if (chars[i] == oldChar)
278 {
279 chars[i] = newChar;
280 }
281 }
282 }
283 public nothrow void Replace(const String<CharT>& oldString, const String<CharT>& newString)
284 {
285 long oldLen = oldString.Length();
286 long newLen = newString.Length();
287 long pos = Find(oldString);
288 while (pos != -1)
289 {
290 Remove(pos, oldLen);
291 Insert(pos, newString);
292 pos = Find(oldString, pos + newLen);
293 }
294 }
295 public nothrow String<CharT> Substring(long start) const
296 {
297 if (start >= 0 && start < len)
298 {
299 return String<CharT>(chars + start);
300 }
301 return String<CharT>();
302 }
303 public nothrow String<CharT> Substring(long start, long length) const
304 {
305 if (start >= 0 && start < len)
306 {
307 return String<CharT>(chars + start, length);
308 }
309 return String<CharT>();
310 }
311 public inline nothrow Iterator Begin()
312 {
313 return Iterator(chars);
314 }
315 public inline nothrow ConstIterator Begin() const
316 {
317 return ConstIterator(chars);
318 }
319 public inline nothrow ConstIterator CBegin() const
320 {
321 return ConstIterator(chars);
322 }
323 public inline nothrow Iterator End()
324 {
325 if (chars != null)
326 {
327 return Iterator(chars + len);
328 }
329 return Iterator(null);
330 }
331 public inline nothrow ConstIterator End() const
332 {
333 if (chars != null)
334 {
335 return ConstIterator(chars + len);
336 }
337 return ConstIterator(null);
338 }
339 public inline nothrow ConstIterator CEnd() const
340 {
341 if (chars != null)
342 {
343 return ConstIterator(chars + len);
344 }
345 return ConstIterator(null);
346 }
347 public nothrow bool StartsWith(const String<CharT>& prefix) const
348 {
349 long n = prefix.len;
350 if (len < n) return false;
351 for (long i = 0; i < n; ++i;)
352 {
353 if (chars[i] != prefix[i]) return false;
354 }
355 return true;
356 }
357 public nothrow bool EndsWith(const String<CharT>& suffix) const
358 {
359 long n = len;
360 long m = suffix.len;
361 if (n < m) return false;
362 for (long i = 0; i < m; ++i;)
363 {
364 if (chars[i + n - m] != suffix[i]) return false;
365 }
366 return true;
367 }
368 public List<String<CharT>> Split(CharT c)
369 {
370 List<String<CharT>> result;
371 long start = 0;
372 for (long i = 0; i < len; ++i;)
373 {
374 if (chars[i] == c)
375 {
376 result.Add(Substring(start, i - start));
377 start = i + 1;
378 }
379 }
380 if (start < len)
381 {
382 result.Add(Substring(start));
383 }
384 return result;
385 }
386 public List<String<CharT>> Split(const String<CharT>& s)
387 {
388 List<String<CharT>> result;
389 long start = 0;
390 while (start < len)
391 {
392 long end = Find(s, start);
393 if (end != -1)
394 {
395 result.Add(Substring(start, end));
396 start = end + s.len;
397 }
398 else
399 {
400 result.Add(Substring(start));
401 start = len;
402 }
403 }
404 return result;
405 }
406 public inline nothrow long Find(CharT x) const
407 {
408 return Find(x, 0);
409 }
410 public inline long Find(CharT x, long start) const
411 {
412 if (start < 0)
413 {
414 ThrowInvalidParameterException();
415 }
416 for (long i = start; i < len; ++i;)
417 {
418 if (chars[i] == x)
419 {
420 return i;
421 }
422 }
423 return -1;
424 }
425 public inline nothrow long RFind(CharT x) const
426 {
427 return RFind(x, len - 1);
428 }
429 public inline long RFind(CharT x, long start) const
430 {
431 if (start >= len)
432 {
433 ThrowInvalidParameterException();
434 }
435 for (long i = start; i >= 0; --i;)
436 {
437 if (chars[i] == x)
438 {
439 return i;
440 }
441 }
442 return -1;
443 }
444 public inline nothrow long Find(const String<CharT>& s) const
445 {
446 return Find(s, 0);
447 }
448 public long Find(const String<CharT>& s, long start) const
449 {
450 if (start < 0)
451 {
452 ThrowInvalidParameterException();
453 }
454 if (s.IsEmpty()) return start;
455 long n = s.Length();
456 CharT x = s[0];
457 long i = Find(x, start);
458 while (i != -1)
459 {
460 if (len < i + n) return -1;
461 bool found = true;
462 for (long k = 1; k < n; ++k;)
463 {
464 if (chars[i + k] != s[k])
465 {
466 found = false;
467 break;
468 }
469 }
470 if (found)
471 {
472 return i;
473 }
474 i = Find(x, i + 1);
475 }
476 return -1;
477 }
478 public nothrow long RFind(const String<CharT>& s) const
479 {
480 return RFind(s, len - 1);
481 }
482 public long RFind(const String<CharT>& s, long start) const
483 {
484 if (start >= len)
485 {
486 ThrowInvalidParameterException();
487 }
488 if (s.IsEmpty()) return start;
489 long n = s.Length();
490 CharT x = s[0];
491 long i = RFind(x, start);
492 while (i != -1)
493 {
494 if (len >= i + n)
495 {
496 bool found = true;
497 for (long k = 1; k < n; ++k;)
498 {
499 if (chars[i + k] != s[k])
500 {
501 found = false;
502 break;
503 }
504 }
505 if (found)
506 {
507 return i;
508 }
509 }
510 i = RFind(x, i - 1);
511 }
512 return -1;
513 }
514 private nothrow void AppendFrom(const CharT* that, long thatLen)
515 {
516 long newLen = len + thatLen;
517 if (newLen > 0)
518 {
519 Reserve(newLen);
520 newLen = len + StrCopy(chars + len, that, thatLen);
521 }
522 len = newLen;
523 }
524 private nothrow void Grow(long minRes)
525 {
526 minRes = MemGrow(minRes);
527 #if (MEM_DEBUG)
528 CharT* newChars = cast<CharT*>(MemAlloc(sizeof(CharT) * minRes, typename(*this)));
529 #else
530 CharT* newChars = cast<CharT*>(MemAlloc(sizeof(CharT) * minRes));
531 #endif
532 if (chars != null)
533 {
534 StrCopy(newChars, chars);
535 MemFree(chars);
536 }
537 chars = newChars;
538 res = minRes;
539 }
540 private nothrow void Deallocate()
541 {
542 len = 0;
543 if (res != 0)
544 {
545 MemFree(chars);
546 res = 0;
547 }
548 chars = null;
549 }
550 private long len;
551 private long res;
552 private CharT* chars;
553 }
554
555 public nothrow bool operator==<CharT>(const String<CharT>& left, const String<CharT>& right)
556 {
557 long len = left.Length();
558 if (len != right.Length()) return false;
559 for (long i = 0; i < len; ++i;)
560 {
561 if (left[i] != right[i])
562 {
563 return false;
564 }
565 }
566 return true;
567 }
568
569 public nothrow bool operator<<CharT>(const String<CharT>& left, const String<CharT>& right)
570 {
571 long leftLen = left.Length();
572 long rightLen = right.Length();
573 if (leftLen == 0 && rightLen > 0) return true;
574 if (leftLen > 0 && rightLen == 0) return false;
575 long n = Min(leftLen, rightLen);
576 for (long i = 0; i < n; ++i;)
577 {
578 CharT l = left[i];
579 CharT r = right[i];
580 if (l < r) return true;
581 if (l > r) return false;
582 }
583 if (leftLen < rightLen) return true;
584 return false;
585 }
586
587 public nothrow String<CharT> operator+<CharT>(const String<CharT>& first, const String<CharT>& second)
588 {
589 String<CharT> temp(first);
590 temp.Append(second);
591 return temp;
592 }
593
594 public nothrow String<CharT> operator+<CharT>(const String<CharT>& first, const CharT* second)
595 {
596 String<CharT> temp(first);
597 temp.Append(second);
598 return temp;
599 }
600
601 public nothrow String<CharT> operator+<CharT>(const CharT* first, const String<CharT>& second)
602 {
603 String<CharT> temp(first);
604 temp.Append(second);
605 return temp;
606 }
607
608 public bool LastComponentsEqual<CharT>(const String<CharT>& s0, const String<CharT>& s1, CharT componentSeparator)
609 {
610 List<String<CharT>> c0 = s0.Split(componentSeparator);
611 List<String<CharT>> c1 = s1.Split(componentSeparator);
612 long n0 = c0.Count();
613 long n1 = c1.Count();
614 long n = Min(n0, n1);
615 for (long i = 0; i < n; ++i;)
616 {
617 if (c0[n0 - i - 1] != c1[n1 - i - 1]) return false;
618 }
619 return true;
620 }
621
622 public ustring ToLower(const ustring& s)
623 {
624 ustring lower;
625 for (uchar c : s)
626 {
627 lower.Append(ToLower(c));
628 }
629 return lower;
630 }
631
632 public ustring ToUpper(const ustring& s)
633 {
634 ustring upper;
635 for (uchar c : s)
636 {
637 upper.Append(ToUpper(c));
638 }
639 return upper;
640 }
641
642 public wstring ToLower(const wstring& s)
643 {
644 return ToUtf16(ToLower(ToUtf32(s)));
645 }
646
647 public wstring ToUpper(const wstring& s)
648 {
649 return ToUtf16(ToUpper(ToUtf32(s)));
650 }
651
652 public string ToLower(const string& s)
653 {
654 return ToUtf8(ToLower(ToUtf32(s)));
655 }
656
657 public string ToUpper(const string& s)
658 {
659 return ToUtf8(ToUpper(ToUtf32(s)));
660 }
661 }