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