1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4
5//
6
7#ifndef _SSTRING_INL_
8#define _SSTRING_INL_
9
10#include "sstring.h"
11
12#if defined(_MSC_VER)
13#pragma inline_depth (20)
14#endif
15
16#ifdef _MSC_VER
17#pragma warning(push)
18#pragma warning(disable:4702) // Disable bogus unreachable code warning
19#endif // _MSC_VER
20
21//#define SSTRING_EXTRA_CHECKS
22#ifdef SSTRING_EXTRA_CHECKS
23#define SS_CONTRACT CONTRACT
24#define SS_CONTRACT_VOID CONTRACT_VOID
25#define SS_CONTRACT_END CONTRACT_END
26#define SS_RETURN RETURN
27#define SS_CONSTRUCTOR_CHECK CONSTRUCTOR_CHECK
28#define SS_PRECONDITION PRECONDITION
29#define SS_POSTCONDITION POSTCONDITION
30
31#else //SSTRING_EXTRA_CHECKS
32
33#define SS_CONTRACT(x) CONTRACTL
34#define SS_CONTRACT_VOID CONTRACTL
35#define SS_CONTRACT_END CONTRACTL_END
36#define SS_RETURN return
37#define SS_CONSTRUCTOR_CHECK
38#define SS_PRECONDITION(x)
39#define SS_POSTCONDITION(x)
40//Do I need this instance check at all?
41
42#endif
43
44
45// ---------------------------------------------------------------------------
46// Inline implementations. Pay no attention to that man behind the curtain.
47// ---------------------------------------------------------------------------
48
49//----------------------------------------------------------------------------
50// Default constructor. Sets the string to the empty string.
51//----------------------------------------------------------------------------
52inline SString::SString()
53 : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
54{
55#ifdef SSTRING_EXTRA_CHECKS
56 CONTRACT_VOID
57 {
58 CONSTRUCTOR_CHECK;
59 POSTCONDITION(IsEmpty());
60 NOTHROW;
61 SO_TOLERANT;
62 GC_NOTRIGGER;
63 }
64 CONTRACT_END;
65
66 RETURN;
67#else
68 STATIC_CONTRACT_NOTHROW;
69 STATIC_CONTRACT_SO_TOLERANT;
70 STATIC_CONTRACT_GC_NOTRIGGER;
71 STATIC_CONTRACT_SUPPORTS_DAC_HOST_ONLY;
72#endif
73}
74
75inline SString::SString(void *buffer, COUNT_T size)
76 : SBuffer(Prealloc, buffer, size)
77{
78 SS_CONTRACT_VOID
79 {
80 SS_CONSTRUCTOR_CHECK;
81 PRECONDITION(CheckPointer(buffer));
82 PRECONDITION(CheckSize(size));
83 SS_POSTCONDITION(IsEmpty());
84 NOTHROW;
85 GC_NOTRIGGER;
86 SUPPORTS_DAC_HOST_ONLY;
87 }
88 SS_CONTRACT_END;
89
90 if (size < sizeof(WCHAR))
91 {
92 // Ignore the useless buffer
93 SetImmutable(s_EmptyBuffer, sizeof(s_EmptyBuffer));
94 }
95 else
96 {
97 SBuffer::TweakSize(sizeof(WCHAR));
98 GetRawUnicode()[0] = 0;
99 }
100
101 SS_RETURN;
102}
103
104inline SString::SString(const SString &s)
105 : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
106{
107 SS_CONTRACT_VOID
108 {
109 SS_CONSTRUCTOR_CHECK;
110 PRECONDITION(s.Check());
111 SS_POSTCONDITION(Equals(s));
112 THROWS;
113 GC_NOTRIGGER;
114 }
115 SS_CONTRACT_END;
116
117 Set(s);
118
119 SS_RETURN;
120}
121
122inline SString::SString(const SString &s1, const SString &s2)
123 : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
124{
125 SS_CONTRACT_VOID
126 {
127 SS_CONSTRUCTOR_CHECK;
128 PRECONDITION(s1.Check());
129 PRECONDITION(s2.Check());
130 THROWS;
131 GC_NOTRIGGER;
132 }
133 SS_CONTRACT_END;
134
135 Set(s1, s2);
136
137 SS_RETURN;
138}
139
140inline SString::SString(const SString &s1, const SString &s2, const SString &s3)
141 : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
142{
143 SS_CONTRACT_VOID
144 {
145 SS_CONSTRUCTOR_CHECK;
146 PRECONDITION(s1.Check());
147 PRECONDITION(s2.Check());
148 PRECONDITION(s3.Check());
149 THROWS;
150 GC_NOTRIGGER;
151 }
152 SS_CONTRACT_END;
153
154 Set(s1, s2, s3);
155
156 SS_RETURN;
157}
158
159inline SString::SString(const SString &s1, const SString &s2, const SString &s3, const SString &s4)
160 : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
161{
162 SS_CONTRACT_VOID
163 {
164 SS_CONSTRUCTOR_CHECK;
165 PRECONDITION(s1.Check());
166 PRECONDITION(s2.Check());
167 PRECONDITION(s3.Check());
168 PRECONDITION(s4.Check());
169 THROWS;
170 }
171 SS_CONTRACT_END;
172
173 Set(s1, s2, s3, s4);
174
175 SS_RETURN;
176}
177
178inline SString::SString(const SString &s, const CIterator &i, COUNT_T count)
179 : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
180{
181 SS_CONTRACT_VOID
182 {
183 SS_CONSTRUCTOR_CHECK;
184 PRECONDITION(s.Check());
185 PRECONDITION(i.Check());
186 PRECONDITION(CheckCount(count));
187 SS_POSTCONDITION(s.Match(i, *this));
188 SS_POSTCONDITION(GetRawCount() == count);
189 THROWS;
190 GC_NOTRIGGER;
191 }
192 SS_CONTRACT_END;
193
194 Set(s, i, count);
195
196 SS_RETURN;
197}
198
199inline SString::SString(const SString &s, const CIterator &start, const CIterator &end)
200 : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
201{
202 SS_CONTRACT_VOID
203 {
204 SS_CONSTRUCTOR_CHECK;
205 PRECONDITION(s.Check());
206 PRECONDITION(start.Check());
207 PRECONDITION(s.CheckIteratorRange(start));
208 PRECONDITION(end.Check());
209 PRECONDITION(s.CheckIteratorRange(end));
210 PRECONDITION(start <= end);
211 SS_POSTCONDITION(s.Match(start, *this));
212 SS_POSTCONDITION(GetRawCount() == (COUNT_T) (end - start));
213 THROWS;
214 GC_NOTRIGGER;
215 }
216 SS_CONTRACT_END;
217
218 Set(s, start, end);
219
220 SS_RETURN;
221}
222
223inline SString::SString(const WCHAR *string)
224 : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
225{
226 SS_CONTRACT_VOID
227 {
228 SS_CONSTRUCTOR_CHECK;
229 PRECONDITION(CheckPointer(string, NULL_OK));
230 THROWS;
231 GC_NOTRIGGER;
232 }
233 SS_CONTRACT_END;
234
235 Set(string);
236
237 SS_RETURN;
238}
239
240inline SString::SString(const WCHAR *string, COUNT_T count)
241 : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
242{
243 SS_CONTRACT_VOID
244 {
245 SS_CONSTRUCTOR_CHECK;
246 PRECONDITION(CheckPointer(string, NULL_OK));
247 PRECONDITION(CheckCount(count));
248 THROWS;
249 GC_NOTRIGGER;
250 }
251 SS_CONTRACT_END;
252
253 Set(string, count);
254
255 SS_RETURN;
256}
257
258inline SString::SString(enum tagASCII, const ASCII *string)
259 : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
260{
261 SS_CONTRACT_VOID
262 {
263 SS_CONSTRUCTOR_CHECK;
264 PRECONDITION(CheckPointer(string, NULL_OK));
265 PRECONDITION(CheckASCIIString(string));
266 THROWS;
267 GC_NOTRIGGER;
268 }
269 SS_CONTRACT_END;
270
271 SetASCII(string);
272
273 SS_RETURN;
274}
275
276inline SString::SString(enum tagASCII, const ASCII *string, COUNT_T count)
277 : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
278{
279 SS_CONTRACT_VOID
280 {
281 SS_CONSTRUCTOR_CHECK;
282 PRECONDITION(CheckPointer(string, NULL_OK));
283 PRECONDITION(CheckASCIIString(string, count));
284 PRECONDITION(CheckCount(count));
285 THROWS;
286 GC_NOTRIGGER;
287 }
288 SS_CONTRACT_END;
289
290 SetASCII(string, count);
291
292 SS_RETURN;
293}
294
295inline SString::SString(tagUTF8 dummytag, const UTF8 *string)
296 : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
297{
298 SS_CONTRACT_VOID
299 {
300 SS_CONSTRUCTOR_CHECK;
301 // !!! Check for illegal UTF8 encoding?
302 PRECONDITION(CheckPointer(string, NULL_OK));
303 THROWS;
304 GC_NOTRIGGER;
305 SUPPORTS_DAC;
306 }
307 SS_CONTRACT_END;
308
309 SetUTF8(string);
310
311 SS_RETURN;
312}
313
314inline SString::SString(tagUTF8 dummytag, const UTF8 *string, COUNT_T count)
315 : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
316{
317 SS_CONTRACT_VOID
318 {
319 SS_CONSTRUCTOR_CHECK;
320 // !!! Check for illegal UTF8 encoding?
321 PRECONDITION(CheckPointer(string, NULL_OK));
322 PRECONDITION(CheckCount(count));
323 THROWS;
324 GC_NOTRIGGER;
325 }
326 SS_CONTRACT_END;
327
328 SetUTF8(string, count);
329
330 SS_RETURN;
331}
332
333inline SString::SString(tagANSI dummytag, const ANSI *string)
334 : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
335{
336 SS_CONTRACT_VOID
337 {
338 SS_CONSTRUCTOR_CHECK;
339 PRECONDITION(CheckPointer(string, NULL_OK));
340 THROWS;
341 GC_NOTRIGGER;
342 }
343 SS_CONTRACT_END;
344
345 SetANSI(string);
346
347 SS_RETURN;
348}
349
350inline SString::SString(tagANSI dummytag, const ANSI *string, COUNT_T count)
351 : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
352{
353 SS_CONTRACT_VOID
354 {
355 SS_CONSTRUCTOR_CHECK;
356 PRECONDITION(CheckPointer(string, NULL_OK));
357 PRECONDITION(CheckCount(count));
358 THROWS;
359 GC_NOTRIGGER;
360 }
361 SS_CONTRACT_END;
362
363 SetANSI(string, count);
364
365 SS_RETURN;
366}
367
368inline SString::SString(WCHAR character)
369 : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
370{
371 SS_CONTRACT_VOID
372 {
373 SS_CONSTRUCTOR_CHECK;
374 THROWS;
375 GC_NOTRIGGER;
376 }
377 SS_CONTRACT_END;
378
379 Set(character);
380
381 SS_RETURN;
382}
383
384inline SString::SString(tagLiteral dummytag, const ASCII *literal)
385 : SBuffer(Immutable, (const BYTE *) literal, (COUNT_T) (strlen(literal)+1)*sizeof(CHAR))
386{
387 SS_CONTRACT_VOID
388 {
389 SS_CONSTRUCTOR_CHECK;
390 PRECONDITION(CheckPointer(literal));
391 PRECONDITION(CheckASCIIString(literal));
392 NOTHROW;
393 GC_NOTRIGGER;
394 SUPPORTS_DAC_HOST_ONLY;
395 }
396 SS_CONTRACT_END;
397
398 SetRepresentation(REPRESENTATION_ASCII);
399
400 SS_RETURN;
401}
402
403inline SString::SString(tagUTF8Literal dummytag, const UTF8 *literal)
404 : SBuffer(Immutable, (const BYTE *) literal, (COUNT_T) (strlen(literal)+1)*sizeof(CHAR))
405{
406 SS_CONTRACT_VOID
407 {
408 SS_CONSTRUCTOR_CHECK;
409 PRECONDITION(CheckPointer(literal));
410 NOTHROW;
411 GC_NOTRIGGER;
412 }
413 SS_CONTRACT_END;
414
415 SetRepresentation(REPRESENTATION_UTF8);
416
417 SS_RETURN;
418}
419
420inline SString::SString(tagLiteral dummytag, const WCHAR *literal)
421 : SBuffer(Immutable, (const BYTE *) literal, (COUNT_T) (wcslen(literal)+1)*sizeof(WCHAR))
422{
423 SS_CONTRACT_VOID
424 {
425 SS_CONSTRUCTOR_CHECK;
426 PRECONDITION(CheckPointer(literal));
427 NOTHROW;
428 GC_NOTRIGGER;
429 }
430 SS_CONTRACT_END;
431
432 SetRepresentation(REPRESENTATION_UNICODE);
433 SetNormalized();
434
435 SS_RETURN;
436}
437
438inline SString::SString(tagLiteral dummytag, const WCHAR *literal, COUNT_T count)
439 : SBuffer(Immutable, (const BYTE *) literal, (count + 1) * sizeof(WCHAR))
440{
441 SS_CONTRACT_VOID
442 {
443 SS_CONSTRUCTOR_CHECK;
444 PRECONDITION(CheckPointer(literal));
445 NOTHROW;
446 GC_NOTRIGGER;
447 }
448 SS_CONTRACT_END;
449
450 SetRepresentation(REPRESENTATION_UNICODE);
451 SetNormalized();
452
453 SS_RETURN;
454}
455
456//-----------------------------------------------------------------------------
457// Set this string to s
458// s - source string
459//-----------------------------------------------------------------------------
460inline void SString::Set(const SString &s)
461{
462 SS_CONTRACT_VOID
463 {
464 INSTANCE_CHECK;
465 PRECONDITION(s.Check());
466 SS_POSTCONDITION(Equals(s));
467 THROWS;
468 GC_NOTRIGGER;
469 SUPPORTS_DAC;
470 }
471 SS_CONTRACT_END;
472
473 SBuffer::Set(s);
474 SetRepresentation(s.GetRepresentation());
475 ClearNormalized();
476
477 SS_RETURN;
478}
479
480//-----------------------------------------------------------------------------
481// Set this string to concatenation of s1 and s2
482//-----------------------------------------------------------------------------
483inline void SString::Set(const SString &s1, const SString &s2)
484{
485 SS_CONTRACT_VOID
486 {
487 INSTANCE_CHECK;
488 PRECONDITION(s1.Check());
489 PRECONDITION(s2.Check());
490 THROWS;
491 GC_NOTRIGGER;
492 }
493 SS_CONTRACT_END;
494
495 Preallocate(s1.GetCount() + s2.GetCount());
496
497 Set(s1);
498 Append(s2);
499
500 SS_RETURN;
501}
502
503//-----------------------------------------------------------------------------
504// Set this string to concatenation of s1, s2, and s3
505//-----------------------------------------------------------------------------
506inline void SString::Set(const SString &s1, const SString &s2, const SString &s3)
507{
508 SS_CONTRACT_VOID
509 {
510 INSTANCE_CHECK;
511 PRECONDITION(s1.Check());
512 PRECONDITION(s2.Check());
513 PRECONDITION(s3.Check());
514 THROWS;
515 GC_NOTRIGGER;
516 }
517 SS_CONTRACT_END;
518
519 Preallocate(s1.GetCount() + s2.GetCount() + s3.GetCount());
520
521 Set(s1);
522 Append(s2);
523 Append(s3);
524
525 SS_RETURN;
526}
527
528//-----------------------------------------------------------------------------
529// Set this string to concatenation of s1, s2, s3, and s4
530//-----------------------------------------------------------------------------
531inline void SString::Set(const SString &s1, const SString &s2, const SString &s3, const SString &s4)
532{
533 SS_CONTRACT_VOID
534 {
535 INSTANCE_CHECK;
536 PRECONDITION(s1.Check());
537 PRECONDITION(s2.Check());
538 PRECONDITION(s3.Check());
539 PRECONDITION(s4.Check());
540 THROWS;
541 GC_NOTRIGGER;
542 }
543 SS_CONTRACT_END;
544
545 Preallocate(s1.GetCount() + s2.GetCount() + s3.GetCount() + s4.GetCount());
546
547 Set(s1);
548 Append(s2);
549 Append(s3);
550 Append(s4);
551
552 SS_RETURN;
553}
554
555//-----------------------------------------------------------------------------
556// Set this string to the substring from s.
557// s - the source string
558// start - the character to start at
559// length - number of characters to copy from s.
560//-----------------------------------------------------------------------------
561inline void SString::Set(const SString &s, const CIterator &i, COUNT_T count)
562{
563 SS_CONTRACT_VOID
564 {
565 INSTANCE_CHECK;
566 PRECONDITION(s.Check());
567 PRECONDITION(i.Check());
568 PRECONDITION(CheckCount(count));
569 SS_POSTCONDITION(s.Match(i, *this));
570 SS_POSTCONDITION(GetRawCount() == count);
571 THROWS;
572 GC_NOTRIGGER;
573 }
574 SS_CONTRACT_END;
575
576 // @todo: detect case where we can reuse literal?
577 Resize(count, s.GetRepresentation());
578 SBuffer::Copy(SBuffer::Begin(), i.m_ptr, count<<i.m_characterSizeShift);
579 NullTerminate();
580
581 SS_RETURN;
582}
583
584//-----------------------------------------------------------------------------
585// Set this string to the substring from s.
586// s - the source string
587// start - the position to start
588// end - the position to end (exclusive)
589//-----------------------------------------------------------------------------
590inline void SString::Set(const SString &s, const CIterator &start, const CIterator &end)
591{
592 SS_CONTRACT_VOID
593 {
594 INSTANCE_CHECK;
595 PRECONDITION(s.Check());
596 PRECONDITION(start.Check());
597 PRECONDITION(s.CheckIteratorRange(start));
598 PRECONDITION(end.Check());
599 PRECONDITION(s.CheckIteratorRange(end));
600 PRECONDITION(end >= start);
601 SS_POSTCONDITION(s.Match(start, *this));
602 SS_POSTCONDITION(GetRawCount() == (COUNT_T) (end - start));
603 THROWS;
604 GC_NOTRIGGER;
605 }
606 SS_CONTRACT_END;
607
608 Set(s, start, end - start);
609
610 SS_RETURN;
611}
612
613// Return a global empty string
614inline const SString &SString::Empty()
615{
616#ifdef SSTRING_EXTRA_CHECKS
617 CONTRACTL
618 {
619 // POSTCONDITION(RETVAL.IsEmpty());
620 PRECONDITION(CheckStartup());
621 NOTHROW;
622 GC_NOTRIGGER;
623 CANNOT_TAKE_LOCK;
624 SO_TOLERANT;
625 SUPPORTS_DAC;
626 }
627 CONTRACTL_END;
628#else
629 STATIC_CONTRACT_NOTHROW;
630 STATIC_CONTRACT_GC_NOTRIGGER;
631 STATIC_CONTRACT_CANNOT_TAKE_LOCK;
632 STATIC_CONTRACT_SO_TOLERANT;
633 STATIC_CONTRACT_SUPPORTS_DAC;
634#endif
635
636 _ASSERTE(s_Empty != NULL); // Did you call SString::Startup()?
637 return *s_Empty;
638}
639
640// Get a const pointer to the internal buffer as a unicode string.
641inline const WCHAR *SString::GetUnicode() const
642{
643 SS_CONTRACT(const WCHAR *)
644 {
645 GC_NOTRIGGER;
646 PRECONDITION(CheckPointer(this));
647 SS_POSTCONDITION(CheckPointer(RETVAL));
648 if (IsRepresentation(REPRESENTATION_UNICODE)) NOTHROW; else THROWS;
649 GC_NOTRIGGER;
650 SUPPORTS_DAC;
651 }
652 SS_CONTRACT_END;
653
654 if (this == NULL)
655 SS_RETURN NULL;
656
657 ConvertToUnicode();
658
659 SS_RETURN GetRawUnicode();
660}
661
662// Normalize the string to unicode. This will make many operations nonfailing.
663inline void SString::Normalize() const
664{
665 SS_CONTRACT_VOID
666 {
667 INSTANCE_CHECK;
668 SS_POSTCONDITION(IsNormalized());
669 THROWS_UNLESS_NORMALIZED;
670 GC_NOTRIGGER;
671 }
672 SS_CONTRACT_END;
673
674 ConvertToUnicode();
675 SetNormalized();
676
677 SS_RETURN;
678}
679
680// Get a const pointer to the internal buffer as a unicode string.
681inline const WCHAR *SString::GetUnicode(const CIterator &i) const
682{
683 SS_CONTRACT(const WCHAR *)
684 {
685 INSTANCE_CHECK;
686 PRECONDITION(CheckIteratorRange(i));
687 THROWS_UNLESS_NORMALIZED;
688 GC_NOTRIGGER;
689 }
690 SS_CONTRACT_END;
691
692 PRECONDITION(CheckPointer(this));
693
694 ConvertToUnicode(i);
695
696 SS_RETURN i.GetUnicode();
697}
698
699// Append s to the end of this string.
700inline void SString::Append(const SString &s)
701{
702 SS_CONTRACT_VOID
703 {
704 GC_NOTRIGGER;
705 PRECONDITION(CheckPointer(this));
706 PRECONDITION(s.Check());
707 THROWS;
708 SUPPORTS_DAC_HOST_ONLY;
709 }
710 SS_CONTRACT_END;
711
712 Insert(End(), s);
713
714 SS_RETURN;
715}
716
717inline void SString::Append(const WCHAR *string)
718{
719 SS_CONTRACT_VOID
720 {
721 GC_NOTRIGGER;
722 PRECONDITION(CheckPointer(this));
723 PRECONDITION(CheckPointer(string));
724 THROWS;
725 SUPPORTS_DAC_HOST_ONLY;
726 }
727 SS_CONTRACT_END;
728
729 // Wrap the string in temporary SString without copying it
730 SString s(SString::Literal, string);
731 s.ClearImmutable();
732 Append(s);
733
734 SS_RETURN;
735}
736
737inline void SString::AppendASCII(const CHAR *string)
738{
739 SS_CONTRACT_VOID
740 {
741 GC_NOTRIGGER;
742 PRECONDITION(CheckPointer(this));
743 PRECONDITION(CheckPointer(string));
744 THROWS;
745 }
746 SS_CONTRACT_END;
747
748 StackSString s(SString::Ascii, string);
749 Append(s);
750
751 SS_RETURN;
752}
753
754inline void SString::AppendUTF8(const CHAR *string)
755{
756 SS_CONTRACT_VOID
757 {
758 GC_NOTRIGGER;
759 PRECONDITION(CheckPointer(this));
760 PRECONDITION(CheckPointer(string));
761 THROWS;
762 }
763 SS_CONTRACT_END;
764
765 StackSString s(SString::Utf8, string);
766 Append(s);
767
768 SS_RETURN;
769}
770
771inline void SString::Append(const WCHAR c)
772{
773 SS_CONTRACT_VOID
774 {
775 GC_NOTRIGGER;
776 PRECONDITION(CheckPointer(this));
777 THROWS;
778 }
779 SS_CONTRACT_END;
780
781 InlineSString<2 * sizeof(c)> s(c);
782 Append(s);
783
784 SS_RETURN;
785}
786
787inline void SString::AppendUTF8(const CHAR c)
788{
789 SS_CONTRACT_VOID
790 {
791 GC_NOTRIGGER;
792 PRECONDITION(CheckPointer(this));
793 THROWS;
794 SUPPORTS_DAC_HOST_ONLY;
795 }
796 SS_CONTRACT_END;
797
798 InlineSString<2 * sizeof(c)> s(SString::Utf8, c);
799 Append(s);
800
801 SS_RETURN;
802}
803
804// Turn this on to test that these if you are testing common scenarios dealing with
805// ASCII strings that do not touch the cases where this family of function differs
806// in behavior for expected reasons.
807//#define VERIFY_CRT_EQUIVALNCE 1
808
809// Helpers for CRT function equivalance.
810/* static */
811inline int __cdecl SString::_stricmp(const CHAR *buffer1, const CHAR *buffer2) {
812 WRAPPER_NO_CONTRACT;
813 int returnValue = CaseCompareHelperA(buffer1, buffer2, 0, s_defaultLCID, TRUE, FALSE);
814#ifdef VERIFY_CRT_EQUIVALNCE
815 _ASSERTE((returnValue == 0) == (::_stricmp(buffer1, buffer2) == 0));
816#endif
817 return returnValue;
818
819}
820
821/* static */
822inline int __cdecl SString::_strnicmp(const CHAR *buffer1, const CHAR *buffer2, COUNT_T count) {
823 WRAPPER_NO_CONTRACT;
824 int returnValue = CaseCompareHelperA(buffer1, buffer2, count, s_defaultLCID, TRUE, TRUE);
825#ifdef VERIFY_CRT_EQUIVALNCE
826 _ASSERTE((returnValue == 0) == (::_strnicmp(buffer1, buffer2, count) == 0));
827#endif
828 return returnValue;
829}
830
831/* static */
832inline int __cdecl SString::_wcsicmp(const WCHAR *buffer1, const WCHAR *buffer2) {
833 WRAPPER_NO_CONTRACT;
834 int returnValue = CaseCompareHelper(buffer1, buffer2, 0, s_defaultLCID, TRUE, FALSE);
835#ifdef VERIFY_CRT_EQUIVALNCE
836 _ASSERTE((returnValue == 0) == (::_wcsicmp(buffer1, buffer2) == 0));
837#endif
838 return returnValue;
839
840}
841
842/* static */
843inline int __cdecl SString::_wcsnicmp(const WCHAR *buffer1, const WCHAR *buffer2, COUNT_T count) {
844 WRAPPER_NO_CONTRACT;
845 int returnValue = CaseCompareHelper(buffer1, buffer2, count, s_defaultLCID, TRUE, TRUE);
846#ifdef VERIFY_CRT_EQUIVALNCE
847 _ASSERTE((returnValue == 0) == (::_wcsnicmp(buffer1, buffer2, count) == 0));
848#endif
849 return returnValue;
850}
851
852inline int SString::_tstricmp(const CHAR *buffer1, const CHAR *buffer2)
853{
854 return _stricmp(buffer1, buffer2);
855}
856
857inline int SString::_tstricmp(const WCHAR *buffer1, const WCHAR *buffer2)
858{
859 return _wcsicmp(buffer1, buffer2);
860}
861
862inline int SString::_tstrnicmp(const CHAR *buffer1, const CHAR *buffer2, COUNT_T count)
863{
864 return _strnicmp(buffer1, buffer2, count);
865}
866
867inline int SString::_tstrnicmp(const WCHAR *buffer1, const WCHAR *buffer2, COUNT_T count)
868{
869 return _wcsnicmp(buffer1, buffer2, count);
870}
871
872inline ULONG SString::HashCaseInsensitive() const
873{
874 WRAPPER_NO_CONTRACT;
875 return HashCaseInsensitive(s_defaultLCID);
876}
877
878inline int SString::CompareCaseInsensitive(const SString &s) const
879{
880 WRAPPER_NO_CONTRACT;
881 return CompareCaseInsensitive(s, s_defaultLCID);
882}
883
884inline BOOL SString::EqualsCaseInsensitive(const SString &s) const
885{
886 WRAPPER_NO_CONTRACT;
887 return EqualsCaseInsensitive(s, s_defaultLCID);
888}
889
890inline BOOL SString::MatchCaseInsensitive(const CIterator &i, const SString &s) const
891{
892 WRAPPER_NO_CONTRACT;
893 return MatchCaseInsensitive(i, s, s_defaultLCID);
894}
895
896inline BOOL SString::MatchCaseInsensitive(const CIterator &i, WCHAR c) const
897{
898 WRAPPER_NO_CONTRACT;
899 return MatchCaseInsensitive(i, c, s_defaultLCID);
900}
901
902inline BOOL SString::Match(const CIterator &i, WCHAR c) const
903{
904 SS_CONTRACT(BOOL)
905 {
906 GC_NOTRIGGER;
907 INSTANCE_CHECK;
908 PRECONDITION(CheckIteratorRange(i));
909 NOTHROW;
910 }
911 SS_CONTRACT_END;
912
913 // End() will not throw here
914 CONTRACT_VIOLATION(ThrowsViolation);
915 SS_RETURN (i < End() && i[0] == c);
916}
917
918inline BOOL SString::Skip(CIterator &i, const SString &s) const
919{
920 SS_CONTRACT(BOOL)
921 {
922 GC_NOTRIGGER;
923 INSTANCE_CHECK;
924 PRECONDITION(CheckIteratorRange(i));
925 PRECONDITION(s.Check());
926 THROWS_UNLESS_BOTH_NORMALIZED(s);
927 }
928 SS_CONTRACT_END;
929
930 if (Match(i, s))
931 {
932 i += s.GetRawCount();
933 SS_RETURN TRUE;
934 }
935 else
936 SS_RETURN FALSE;
937}
938
939inline BOOL SString::Skip(CIterator &i, WCHAR c) const
940{
941 SS_CONTRACT(BOOL)
942 {
943 GC_NOTRIGGER;
944 INSTANCE_CHECK;
945 PRECONDITION(CheckIteratorRange(i));
946 NOTHROW;
947 }
948 SS_CONTRACT_END;
949
950 if (Match(i, c))
951 {
952 i++;
953 SS_RETURN TRUE;
954 }
955 else
956 SS_RETURN FALSE;
957}
958
959// Find string within this string. Return TRUE and update iterator if found
960inline BOOL SString::Find(CIterator &i, const WCHAR *string) const
961{
962 SS_CONTRACT(BOOL)
963 {
964 GC_NOTRIGGER;
965 PRECONDITION(CheckPointer(this));
966 PRECONDITION(CheckIteratorRange(i));
967 PRECONDITION(CheckPointer(string));
968 SS_POSTCONDITION(RETVAL == Match(i, SString(string)));
969 THROWS;
970 }
971 SS_CONTRACT_END;
972
973 StackSString s(string);
974 SS_RETURN Find(i, s);
975}
976
977inline BOOL SString::FindASCII(CIterator &i, const CHAR *string) const
978{
979 SS_CONTRACT(BOOL)
980 {
981 GC_NOTRIGGER;
982 PRECONDITION(CheckPointer(this));
983 PRECONDITION(CheckIteratorRange(i));
984 PRECONDITION(CheckPointer(string));
985 SS_POSTCONDITION(RETVAL == Match(i, SString(SString::Ascii, string)));
986 THROWS;
987 }
988 SS_CONTRACT_END;
989
990 StackSString s(SString::Ascii, string);
991 SS_RETURN Find(i, s);
992}
993
994inline BOOL SString::FindUTF8(CIterator &i, const CHAR *string) const
995{
996 SS_CONTRACT(BOOL)
997 {
998 GC_NOTRIGGER;
999 PRECONDITION(CheckPointer(this));
1000 PRECONDITION(CheckIteratorRange(i));
1001 PRECONDITION(CheckPointer(string));
1002 SS_POSTCONDITION(RETVAL == Match(i, SString(SString::Ascii, string)));
1003 THROWS;
1004 }
1005 SS_CONTRACT_END;
1006
1007 StackSString s(SString::Utf8, string);
1008 SS_RETURN Find(i, s);
1009}
1010
1011inline BOOL SString::FindBack(CIterator &i, const WCHAR *string) const
1012{
1013 SS_CONTRACT(BOOL)
1014 {
1015 GC_NOTRIGGER;
1016 PRECONDITION(CheckPointer(this));
1017 PRECONDITION(CheckIteratorRange(i));
1018 PRECONDITION(CheckPointer(string));
1019 SS_POSTCONDITION(RETVAL == Match(i, SString(string)));
1020 THROWS;
1021 }
1022 SS_CONTRACT_END;
1023
1024 StackSString s(string);
1025 SS_RETURN FindBack(i, s);
1026}
1027
1028inline BOOL SString::FindBackASCII(CIterator &i, const CHAR *string) const
1029{
1030 SS_CONTRACT(BOOL)
1031 {
1032 GC_NOTRIGGER;
1033 PRECONDITION(CheckPointer(this));
1034 PRECONDITION(CheckIteratorRange(i));
1035 PRECONDITION(CheckPointer(string));
1036 SS_POSTCONDITION(RETVAL == Match(i, SString(SString::Ascii, string)));
1037 THROWS;
1038 }
1039 SS_CONTRACT_END;
1040
1041 StackSString s(SString::Ascii, string);
1042 SS_RETURN FindBack(i, s);
1043}
1044
1045inline BOOL SString::FindBackUTF8(CIterator &i, const CHAR *string) const
1046{
1047 SS_CONTRACT(BOOL)
1048 {
1049 GC_NOTRIGGER;
1050 PRECONDITION(CheckPointer(this));
1051 PRECONDITION(CheckIteratorRange(i));
1052 PRECONDITION(CheckPointer(string));
1053 SS_POSTCONDITION(RETVAL == Match(i, SString(SString::Ascii, string)));
1054 THROWS;
1055 }
1056 SS_CONTRACT_END;
1057
1058 StackSString s(SString::Utf8, string);
1059 SS_RETURN FindBack(i, s);
1060}
1061
1062// Insert string at iterator position
1063inline void SString::Insert(const Iterator &i, const SString &s)
1064{
1065 SS_CONTRACT_VOID
1066 {
1067 GC_NOTRIGGER;
1068 PRECONDITION(CheckPointer(this));
1069 PRECONDITION(CheckIteratorRange(i));
1070 PRECONDITION(s.Check());
1071 THROWS;
1072 SUPPORTS_DAC_HOST_ONLY;
1073 }
1074 SS_CONTRACT_END;
1075
1076 Replace(i, 0, s);
1077
1078 SS_RETURN;
1079}
1080
1081inline void SString::Insert(const Iterator &i, const WCHAR *string)
1082{
1083 SS_CONTRACT_VOID
1084 {
1085 GC_NOTRIGGER;
1086 PRECONDITION(CheckPointer(this));
1087 PRECONDITION(CheckIteratorRange(i));
1088 PRECONDITION(CheckPointer(string));
1089 THROWS;
1090 }
1091 SS_CONTRACT_END;
1092
1093 StackSString s(string);
1094 Replace(i, 0, s);
1095
1096 SS_RETURN;
1097}
1098
1099inline void SString::InsertASCII(const Iterator &i, const CHAR *string)
1100{
1101 SS_CONTRACT_VOID
1102 {
1103 GC_NOTRIGGER;
1104 PRECONDITION(CheckPointer(this));
1105 PRECONDITION(CheckIteratorRange(i));
1106 PRECONDITION(CheckPointer(string));
1107 THROWS;
1108 }
1109 SS_CONTRACT_END;
1110
1111 StackSString s(SString::Ascii, string);
1112 Replace(i, 0, s);
1113
1114 SS_RETURN;
1115}
1116
1117inline void SString::InsertUTF8(const Iterator &i, const CHAR *string)
1118{
1119 SS_CONTRACT_VOID
1120 {
1121 GC_NOTRIGGER;
1122 PRECONDITION(CheckPointer(this));
1123 PRECONDITION(CheckIteratorRange(i));
1124 PRECONDITION(CheckPointer(string));
1125 THROWS;
1126 }
1127 SS_CONTRACT_END;
1128
1129 StackSString s(SString::Utf8, string);
1130 Replace(i, 0, s);
1131
1132 SS_RETURN;
1133}
1134
1135// Delete string at iterator position
1136inline void SString::Delete(const Iterator &i, COUNT_T length)
1137{
1138 SS_CONTRACT_VOID
1139 {
1140 GC_NOTRIGGER;
1141 PRECONDITION(CheckPointer(this));
1142 PRECONDITION(CheckIteratorRange(i, length));
1143 THROWS;
1144 SUPPORTS_DAC_HOST_ONLY;
1145 }
1146 SS_CONTRACT_END;
1147
1148 Replace(i, length, Empty());
1149
1150 SS_RETURN;
1151}
1152
1153// Preallocate some space for the string buffer
1154inline void SString::Preallocate(COUNT_T characters) const
1155{
1156 WRAPPER_NO_CONTRACT;
1157
1158 // Assume unicode since we may get converted
1159 SBuffer::Preallocate(characters * sizeof(WCHAR));
1160}
1161
1162// Trim unused space from the buffer
1163inline void SString::Trim() const
1164{
1165 WRAPPER_NO_CONTRACT;
1166
1167 if (GetRawCount() == 0)
1168 {
1169 // Share the global empty string buffer.
1170 const_cast<SString *>(this)->SBuffer::SetImmutable(s_EmptyBuffer, sizeof(s_EmptyBuffer));
1171 }
1172 else
1173 {
1174 SBuffer::Trim();
1175 }
1176}
1177
1178// RETURN true if the string is empty.
1179inline BOOL SString::IsEmpty() const
1180{
1181 SS_CONTRACT(BOOL)
1182 {
1183 GC_NOTRIGGER;
1184 PRECONDITION(CheckPointer(this));
1185 NOTHROW;
1186 SO_TOLERANT;
1187 SUPPORTS_DAC;
1188 }
1189 SS_CONTRACT_END;
1190
1191 SS_RETURN (GetRawCount() == 0);
1192}
1193
1194// RETURN true if the string rep is ASCII.
1195inline BOOL SString::IsASCII() const
1196{
1197 SS_CONTRACT(BOOL)
1198 {
1199 GC_NOTRIGGER;
1200 PRECONDITION(CheckPointer(this));
1201 NOTHROW;
1202 SO_TOLERANT;
1203 }
1204 SS_CONTRACT_END;
1205
1206 SS_RETURN IsRepresentation(REPRESENTATION_ASCII);
1207}
1208
1209// Get the number of characters in the string (excluding the terminating NULL)
1210inline COUNT_T SString::GetCount() const
1211{
1212 SS_CONTRACT(COUNT_T)
1213 {
1214 GC_NOTRIGGER;
1215 PRECONDITION(CheckPointer(this));
1216 SS_POSTCONDITION(CheckCount(RETVAL));
1217 THROWS_UNLESS_NORMALIZED;
1218 SUPPORTS_DAC;
1219 }
1220 SS_CONTRACT_END;
1221
1222 ConvertToFixed();
1223
1224 SS_RETURN SizeToCount(GetSize());
1225}
1226
1227// Private helpers:
1228// Return the current size of the string (even if it is multibyte)
1229inline COUNT_T SString::GetRawCount() const
1230{
1231 WRAPPER_NO_CONTRACT;
1232
1233 return SizeToCount(GetSize());
1234}
1235
1236// Private helpers:
1237// get string contents as a particular character set:
1238
1239inline ASCII *SString::GetRawASCII() const
1240{
1241 LIMITED_METHOD_DAC_CONTRACT;
1242
1243 return (ASCII *) m_buffer;
1244}
1245
1246inline UTF8 *SString::GetRawUTF8() const
1247{
1248 LIMITED_METHOD_DAC_CONTRACT;
1249
1250 return (UTF8 *) m_buffer;
1251}
1252
1253inline ANSI *SString::GetRawANSI() const
1254{
1255 LIMITED_METHOD_DAC_CONTRACT;
1256
1257 return (ANSI *) m_buffer;
1258}
1259
1260inline WCHAR *SString::GetRawUnicode() const
1261{
1262 LIMITED_METHOD_CONTRACT;
1263 SUPPORTS_DAC_HOST_ONLY;
1264
1265 return (WCHAR *)m_buffer;
1266}
1267
1268// Private helper:
1269// get the representation (ansi, unicode, utf8)
1270inline SString::Representation SString::GetRepresentation() const
1271{
1272 WRAPPER_NO_CONTRACT;
1273
1274 return (Representation) SBuffer::GetRepresentationField();
1275}
1276
1277// Private helper.
1278// Set the representation.
1279inline void SString::SetRepresentation(SString::Representation representation)
1280{
1281#ifdef SSTRING_EXTRA_CHECKS
1282 CONTRACT_VOID
1283 {
1284 GC_NOTRIGGER;
1285 NOTHROW;
1286 PRECONDITION(CheckPointer(this));
1287 PRECONDITION(CheckRepresentation(representation));
1288 POSTCONDITION(GetRepresentation() == representation);
1289 }
1290 CONTRACT_END;
1291#else //SSTRING_EXTRA_CHECKS
1292 STATIC_CONTRACT_NOTHROW;
1293 STATIC_CONTRACT_GC_NOTRIGGER;
1294 STATIC_CONTRACT_SUPPORTS_DAC_HOST_ONLY;
1295#endif //SSTRING_EXTRA_CHECKS
1296
1297 SBuffer::SetRepresentationField((int) representation);
1298
1299 SS_RETURN;
1300}
1301
1302// Private helper:
1303// Get the amount to shift the byte size to get a character count
1304inline int SString::GetCharacterSizeShift() const
1305{
1306 WRAPPER_NO_CONTRACT;
1307
1308 // Note that the flag is backwards; we want the default
1309 // value to match the default representation (empty)
1310 return (GetRepresentation()&REPRESENTATION_SINGLE_MASK) == 0;
1311}
1312
1313//----------------------------------------------------------------------------
1314// Private helper.
1315// We know the buffer should be m_count characters. Place a null terminator
1316// in the buffer to make our internal string null-terminated at that length.
1317//----------------------------------------------------------------------------
1318FORCEINLINE void SString::NullTerminate()
1319{
1320 SUPPORTS_DAC_HOST_ONLY;
1321#ifdef SSTRING_EXTRA_CHECKS
1322 CONTRACT_VOID
1323 {
1324 POSTCONDITION(CheckPointer(this));
1325 NOTHROW;
1326 GC_NOTRIGGER;
1327 }
1328 CONTRACT_END;
1329#else //SSTRING_EXTRA_CHECKS
1330 STATIC_CONTRACT_NOTHROW;
1331 STATIC_CONTRACT_GC_NOTRIGGER;
1332#endif //SSTRING_EXTRA_CHECKS
1333
1334 BYTE *end = m_buffer + GetSize();
1335
1336 if (GetRepresentation()&REPRESENTATION_SINGLE_MASK)
1337 {
1338 ((CHAR *)end)[-1] = 0;
1339 }
1340 else
1341 {
1342 ((WCHAR *)end)[-1] = 0;
1343 }
1344
1345 SS_RETURN;
1346}
1347
1348//----------------------------------------------------------------------------
1349// private helper
1350// Return true if the string is a literal.
1351// A literal string has immutable memory.
1352//----------------------------------------------------------------------------
1353inline BOOL SString::IsLiteral() const
1354{
1355 WRAPPER_NO_CONTRACT;
1356
1357 return SBuffer::IsImmutable() && (m_buffer != s_EmptyBuffer);
1358}
1359
1360//----------------------------------------------------------------------------
1361// private helper:
1362// RETURN true if the string allocated (and should delete) its buffer.
1363// IsAllocated() will RETURN false for Literal strings and
1364// stack-based strings (the buffer is on the stack)
1365//----------------------------------------------------------------------------
1366inline BOOL SString::IsAllocated() const
1367{
1368 WRAPPER_NO_CONTRACT;
1369
1370 return SBuffer::IsAllocated();
1371}
1372
1373//----------------------------------------------------------------------------
1374// Return true after we call OpenBuffer(), but before we close it.
1375// All SString operations are illegal while the buffer is open.
1376//----------------------------------------------------------------------------
1377#if _DEBUG
1378inline BOOL SString::IsBufferOpen() const
1379{
1380 WRAPPER_NO_CONTRACT;
1381
1382 return SBuffer::IsOpened();
1383}
1384#endif
1385
1386//----------------------------------------------------------------------------
1387// Return true if we've scanned the string to see if it is in the ASCII subset.
1388//----------------------------------------------------------------------------
1389inline BOOL SString::IsASCIIScanned() const
1390{
1391 WRAPPER_NO_CONTRACT;
1392 SUPPORTS_DAC;
1393
1394 return SBuffer::IsFlag1();
1395}
1396
1397//----------------------------------------------------------------------------
1398// Set that we've scanned the string to see if it is in the ASCII subset.
1399//----------------------------------------------------------------------------
1400inline void SString::SetASCIIScanned() const
1401{
1402 WRAPPER_NO_CONTRACT;
1403 SUPPORTS_DAC_HOST_ONLY;
1404
1405 const_cast<SString *>(this)->SBuffer::SetFlag1();
1406}
1407
1408//----------------------------------------------------------------------------
1409// Return true if we've normalized the string to unicode
1410//----------------------------------------------------------------------------
1411inline BOOL SString::IsNormalized() const
1412{
1413 WRAPPER_NO_CONTRACT;
1414 SUPPORTS_DAC;
1415
1416 return SBuffer::IsFlag3();
1417}
1418
1419//----------------------------------------------------------------------------
1420// Set that we've normalized the string to unicode
1421//----------------------------------------------------------------------------
1422inline void SString::SetNormalized() const
1423{
1424 WRAPPER_NO_CONTRACT;
1425
1426 const_cast<SString *>(this)->SBuffer::SetFlag3();
1427}
1428
1429//----------------------------------------------------------------------------
1430// Clear normalization
1431//----------------------------------------------------------------------------
1432inline void SString::ClearNormalized() const
1433{
1434 WRAPPER_NO_CONTRACT;
1435 SUPPORTS_DAC_HOST_ONLY;
1436
1437 const_cast<SString *>(this)->SBuffer::ClearFlag3();
1438}
1439
1440//----------------------------------------------------------------------------
1441// Private helper.
1442// Check to see if the string representation has single byte size
1443//----------------------------------------------------------------------------
1444inline BOOL SString::IsSingleByte() const
1445{
1446 STATIC_CONTRACT_NOTHROW;
1447 STATIC_CONTRACT_GC_NOTRIGGER;
1448
1449 return ((GetRepresentation()&REPRESENTATION_SINGLE_MASK) != 0);
1450}
1451
1452//----------------------------------------------------------------------------
1453// Private helper.
1454// Check to see if the string representation has fixed size characters
1455//----------------------------------------------------------------------------
1456inline BOOL SString::IsFixedSize() const
1457{
1458 STATIC_CONTRACT_NOTHROW;
1459 STATIC_CONTRACT_GC_NOTRIGGER;
1460 STATIC_CONTRACT_SUPPORTS_DAC;
1461
1462 if (GetRepresentation()&REPRESENTATION_VARIABLE_MASK)
1463 return ((GetRepresentation() == REPRESENTATION_ANSI) && !s_IsANSIMultibyte);
1464 else
1465 return TRUE;
1466}
1467
1468//----------------------------------------------------------------------------
1469// Private helper.
1470// Check to see if the string representation is appropriate for iteration
1471//----------------------------------------------------------------------------
1472inline BOOL SString::IsIteratable() const
1473{
1474 STATIC_CONTRACT_NOTHROW;
1475 STATIC_CONTRACT_GC_NOTRIGGER;
1476 STATIC_CONTRACT_SUPPORTS_DAC;
1477
1478 // Note that in many cases ANSI may be fixed width. However we
1479 // currently still do not allow iterating on them, because we would have to
1480 // do character-by-character conversion on a character dereference (which must
1481 // go to unicode) . We may want to adjust this going forward to
1482 // depending on perf in the non-ASCII but fixed width ANSI case.
1483
1484 return ((GetRepresentation()&REPRESENTATION_VARIABLE_MASK) == 0);
1485}
1486
1487//----------------------------------------------------------------------------
1488// Private helper
1489// Return the size of the given string in bytes
1490// in the given representation.
1491// count does not include the null-terminator, but the RETURN value does.
1492//----------------------------------------------------------------------------
1493inline COUNT_T SString::CountToSize(COUNT_T count) const
1494{
1495 SS_CONTRACT(COUNT_T)
1496 {
1497 GC_NOTRIGGER;
1498 PRECONDITION(CheckCount(count));
1499 SS_POSTCONDITION(SizeToCount(RETVAL) == count);
1500 NOTHROW;
1501 SUPPORTS_DAC;
1502 }
1503 SS_CONTRACT_END;
1504
1505 SS_RETURN (count+1) << GetCharacterSizeShift();
1506}
1507
1508//----------------------------------------------------------------------------
1509// Private helper.
1510// Return the maxmimum count of characters that could fit in a buffer of
1511// 'size' bytes in the given representation.
1512// 'size' includes the null terminator, but the RETURN value does not.
1513//----------------------------------------------------------------------------
1514inline COUNT_T SString::SizeToCount(COUNT_T size) const
1515{
1516 SS_CONTRACT(COUNT_T)
1517 {
1518 GC_NOTRIGGER;
1519 PRECONDITION(CheckSize(size));
1520 SS_POSTCONDITION(CountToSize(RETVAL) == size);
1521 NOTHROW;
1522 SO_TOLERANT;
1523 SUPPORTS_DAC;
1524 }
1525 SS_CONTRACT_END;
1526
1527 SS_RETURN (size >> GetCharacterSizeShift()) - 1;
1528}
1529
1530//----------------------------------------------------------------------------
1531// Private helper.
1532// Return the maxmimum count of characters that could fit in the current
1533// buffer including NULL terminator.
1534//----------------------------------------------------------------------------
1535inline COUNT_T SString::GetBufferSizeInCharIncludeNullChar() const
1536{
1537 STATIC_CONTRACT_GC_NOTRIGGER;
1538 STATIC_CONTRACT_NOTHROW;
1539 STATIC_CONTRACT_SO_TOLERANT;
1540 STATIC_CONTRACT_SUPPORTS_DAC;
1541
1542 return (GetSize() >> GetCharacterSizeShift());
1543}
1544
1545
1546
1547//----------------------------------------------------------------------------
1548// Assert helper
1549// Asser that the iterator is within the given string.
1550//----------------------------------------------------------------------------
1551inline CHECK SString::CheckIteratorRange(const CIterator &i) const
1552{
1553 CANNOT_HAVE_CONTRACT;
1554 CHECK(i >= Begin());
1555 CHECK(i <= End()); // Note that it's OK to look at the terminating null
1556 CHECK_OK;
1557}
1558
1559//----------------------------------------------------------------------------
1560// Assert helper
1561// Asser that the iterator is within the given string.
1562//----------------------------------------------------------------------------
1563inline CHECK SString::CheckIteratorRange(const CIterator &i, COUNT_T length) const
1564{
1565 CANNOT_HAVE_CONTRACT;
1566 CHECK(i >= Begin());
1567 CHECK(i + length <= End()); // Note that it's OK to look at the terminating null
1568 CHECK_OK;
1569}
1570
1571//----------------------------------------------------------------------------
1572// Assert that the string is empty
1573//----------------------------------------------------------------------------
1574inline CHECK SString::CheckEmpty() const
1575{
1576 CANNOT_HAVE_CONTRACT;
1577 CHECK(IsEmpty());
1578 CHECK_OK;
1579}
1580
1581//----------------------------------------------------------------------------
1582// Check the range of a count
1583//----------------------------------------------------------------------------
1584inline CHECK SString::CheckCount(COUNT_T count)
1585{
1586 CANNOT_HAVE_CONTRACT;
1587 CHECK(CheckSize(count*sizeof(WCHAR)));
1588 CHECK_OK;
1589}
1590
1591//----------------------------------------------------------------------------
1592// Check the representation field
1593//----------------------------------------------------------------------------
1594inline CHECK SString::CheckRepresentation(int representation)
1595{
1596 CANNOT_HAVE_CONTRACT;
1597#ifdef SSTRING_CONSOLECODEPAGE
1598 CHECK(representation == REPRESENTATION_EMPTY
1599 || representation == REPRESENTATION_UNICODE
1600 || representation == REPRESENTATION_ASCII
1601 || representation == REPRESENTATION_UTF8
1602 || representation == REPRESENTATION_ANSI
1603 || representation == REPRESENTATION_CONSOLE);
1604#else
1605 CHECK(representation == REPRESENTATION_EMPTY
1606 || representation == REPRESENTATION_UNICODE
1607 || representation == REPRESENTATION_ASCII
1608 || representation == REPRESENTATION_UTF8
1609 || representation == REPRESENTATION_ANSI);
1610#endif
1611 CHECK((representation & REPRESENTATION_MASK) == representation);
1612
1613 CHECK_OK;
1614}
1615
1616#if CHECK_INVARIANTS
1617//----------------------------------------------------------------------------
1618// Assert helper. Check that the string only uses the ASCII subset of
1619// codes.
1620//----------------------------------------------------------------------------
1621inline CHECK SString::CheckASCIIString(const CHAR *string)
1622{
1623 CANNOT_HAVE_CONTRACT;
1624 if (string != NULL)
1625 CHECK(CheckASCIIString(string, (int) strlen(string)));
1626 CHECK_OK;
1627}
1628
1629inline CHECK SString::CheckASCIIString(const CHAR *string, COUNT_T count)
1630{
1631 CANNOT_HAVE_CONTRACT;
1632#if _DEBUG
1633 const CHAR *sEnd = string + count;
1634 while (string < sEnd)
1635 {
1636 CHECK_MSG((*string & 0x80) == 0x00, "Found non-ASCII character in string.");
1637 string++;
1638 }
1639#endif
1640 CHECK_OK;
1641}
1642
1643//----------------------------------------------------------------------------
1644// Check routine and invariants.
1645//----------------------------------------------------------------------------
1646
1647inline CHECK SString::Check() const
1648{
1649 CANNOT_HAVE_CONTRACT;
1650 CHECK(SBuffer::Check());
1651 CHECK_OK;
1652}
1653
1654inline CHECK SString::Invariant() const
1655{
1656 CANNOT_HAVE_CONTRACT;
1657 CHECK(SBuffer::Invariant());
1658 CHECK_OK;
1659}
1660
1661inline CHECK SString::InternalInvariant() const
1662{
1663 CANNOT_HAVE_CONTRACT;
1664 CHECK(SBuffer::InternalInvariant());
1665 CHECK(SBuffer::GetSize() >= 2);
1666 if (IsNormalized())
1667 CHECK(IsRepresentation(REPRESENTATION_UNICODE));
1668 CHECK_OK;
1669}
1670#endif // CHECK_INVARIANTS
1671
1672//----------------------------------------------------------------------------
1673// Return a writeable buffer that can store 'countChars'+1 unicode characters.
1674// Call CloseBuffer when done.
1675//----------------------------------------------------------------------------
1676inline WCHAR *SString::OpenUnicodeBuffer(COUNT_T countChars)
1677{
1678 SS_CONTRACT(WCHAR*)
1679 {
1680 GC_NOTRIGGER;
1681 PRECONDITION(CheckPointer(this));
1682 PRECONDITION(CheckCount(countChars));
1683#if _DEBUG
1684 SS_POSTCONDITION(IsBufferOpen());
1685#endif
1686 SS_POSTCONDITION(GetRawCount() == countChars);
1687 SS_POSTCONDITION(GetRepresentation() == REPRESENTATION_UNICODE || countChars == 0);
1688 SS_POSTCONDITION(CheckPointer(RETVAL));
1689 THROWS;
1690 }
1691 SS_CONTRACT_END;
1692
1693 OpenBuffer(REPRESENTATION_UNICODE, countChars);
1694 SS_RETURN GetRawUnicode();
1695}
1696
1697//----------------------------------------------------------------------------
1698// Return a copy of the underlying buffer, the caller is responsible for managing
1699// the returned memory
1700//----------------------------------------------------------------------------
1701inline WCHAR *SString::GetCopyOfUnicodeString()
1702{
1703 SS_CONTRACT(WCHAR*)
1704 {
1705 GC_NOTRIGGER;
1706 PRECONDITION(CheckPointer(this));
1707 SS_POSTCONDITION(CheckPointer(buffer));
1708 THROWS;
1709 }
1710 SS_CONTRACT_END;
1711 NewArrayHolder<WCHAR> buffer = NULL;
1712
1713 buffer = new WCHAR[GetCount() +1];
1714 wcscpy_s(buffer, GetCount() + 1, GetUnicode());
1715
1716 SS_RETURN buffer.Extract();
1717}
1718
1719//----------------------------------------------------------------------------
1720// Return a writeable buffer that can store 'countChars'+1 ansi characters.
1721// Call CloseBuffer when done.
1722//----------------------------------------------------------------------------
1723inline ANSI *SString::OpenANSIBuffer(COUNT_T countChars)
1724{
1725 SS_CONTRACT(ANSI*)
1726 {
1727 GC_NOTRIGGER;
1728 PRECONDITION(CheckPointer(this));
1729 PRECONDITION(CheckCount(countChars));
1730#if _DEBUG
1731 SS_POSTCONDITION(IsBufferOpen());
1732#endif
1733 SS_POSTCONDITION(GetRawCount() == countChars);
1734 SS_POSTCONDITION(GetRepresentation() == REPRESENTATION_ANSI || countChars == 0);
1735 SS_POSTCONDITION(CheckPointer(RETVAL));
1736 THROWS;
1737 }
1738 SS_CONTRACT_END;
1739
1740 OpenBuffer(REPRESENTATION_ANSI, countChars);
1741 SS_RETURN GetRawANSI();
1742}
1743
1744//----------------------------------------------------------------------------
1745// Return a writeable buffer that can store 'countChars'+1 ansi characters.
1746// Call CloseBuffer when done.
1747//----------------------------------------------------------------------------
1748inline UTF8 *SString::OpenUTF8Buffer(COUNT_T countBytes)
1749{
1750 SS_CONTRACT(UTF8*)
1751 {
1752 GC_NOTRIGGER;
1753 PRECONDITION(CheckPointer(this));
1754 PRECONDITION(CheckCount(countBytes));
1755#if _DEBUG
1756 SS_POSTCONDITION(IsBufferOpen());
1757#endif
1758 SS_POSTCONDITION(GetRawCount() == countBytes);
1759 SS_POSTCONDITION(GetRepresentation() == REPRESENTATION_UTF8 || countBytes == 0);
1760 SS_POSTCONDITION(CheckPointer(RETVAL));
1761 THROWS;
1762 }
1763 SS_CONTRACT_END;
1764
1765 OpenBuffer(REPRESENTATION_UTF8, countBytes);
1766 SS_RETURN GetRawUTF8();
1767}
1768
1769//----------------------------------------------------------------------------
1770// Private helper to open a raw buffer.
1771// Called by public functions to open the buffer in the specific
1772// representation.
1773// While the buffer is opened, all other operations are illegal. Call
1774// CloseBuffer() when done.
1775//----------------------------------------------------------------------------
1776inline void SString::OpenBuffer(SString::Representation representation, COUNT_T countChars)
1777{
1778#ifdef SSTRING_EXTRA_CHECKS
1779 CONTRACT_VOID
1780 {
1781 GC_NOTRIGGER;
1782 PRECONDITION(CheckPointer(this));
1783 PRECONDITION_MSG(!IsBufferOpen(), "Can't nest calls to OpenBuffer()");
1784 PRECONDITION(CheckRepresentation(representation));
1785 PRECONDITION(CheckSize(countChars));
1786#if _DEBUG
1787 POSTCONDITION(IsBufferOpen());
1788#endif
1789 POSTCONDITION(GetRawCount() == countChars);
1790 POSTCONDITION(GetRepresentation() == representation || countChars == 0);
1791 THROWS;
1792 }
1793 CONTRACT_END;
1794#else
1795 STATIC_CONTRACT_GC_NOTRIGGER;
1796 STATIC_CONTRACT_THROWS;
1797#endif
1798
1799 Resize(countChars, representation);
1800
1801 SBuffer::OpenRawBuffer(CountToSize(countChars));
1802
1803 SS_RETURN;
1804}
1805
1806//----------------------------------------------------------------------------
1807// Get the max size that can be passed to OpenUnicodeBuffer without causing
1808// allocations.
1809//----------------------------------------------------------------------------
1810inline COUNT_T SString::GetUnicodeAllocation()
1811{
1812 CONTRACTL
1813 {
1814 INSTANCE_CHECK;
1815 NOTHROW;
1816 GC_NOTRIGGER;
1817 }
1818 CONTRACTL_END;
1819
1820 COUNT_T allocation = GetAllocation();
1821 return ( (allocation > sizeof(WCHAR))
1822 ? (allocation - sizeof(WCHAR)) / sizeof(WCHAR) : 0 );
1823}
1824
1825//----------------------------------------------------------------------------
1826// Close an open buffer. Assumes that we wrote exactly number of characters
1827// we requested in OpenBuffer.
1828//----------------------------------------------------------------------------
1829inline void SString::CloseBuffer()
1830{
1831 SS_CONTRACT_VOID
1832 {
1833 GC_NOTRIGGER;
1834#if _DEBUG
1835 PRECONDITION_MSG(IsBufferOpen(), "Can only CloseBuffer() after a call to OpenBuffer()");
1836#endif
1837 SS_POSTCONDITION(CheckPointer(this));
1838 THROWS;
1839 }
1840 SS_CONTRACT_END;
1841
1842 SBuffer::CloseRawBuffer();
1843 NullTerminate();
1844
1845 SS_RETURN;
1846}
1847
1848//----------------------------------------------------------------------------
1849// CloseBuffer() tells the SString that we're done using the unsafe buffer.
1850// countChars is the count of characters actually used (so we can set m_count).
1851// This is important if we request a buffer larger than what we actually
1852// used.
1853//----------------------------------------------------------------------------
1854inline void SString::CloseBuffer(COUNT_T finalCount)
1855{
1856 SS_CONTRACT_VOID
1857 {
1858 GC_NOTRIGGER;
1859#if _DEBUG
1860 PRECONDITION_MSG(IsBufferOpen(), "Can only CloseBuffer() after a call to OpenBuffer()");
1861#endif
1862 PRECONDITION(CheckSize(finalCount));
1863 SS_POSTCONDITION(CheckPointer(this));
1864 SS_POSTCONDITION(GetRawCount() == finalCount);
1865 THROWS;
1866 }
1867 SS_CONTRACT_END;
1868
1869 SBuffer::CloseRawBuffer(CountToSize(finalCount));
1870 NullTerminate();
1871
1872 SS_RETURN;
1873}
1874
1875//----------------------------------------------------------------------------
1876// EnsureWritable
1877// Ensures that the buffer is writable
1878//----------------------------------------------------------------------------
1879inline void SString::EnsureWritable() const
1880{
1881#ifdef SSTRING_EXTRA_CHECKS
1882 CONTRACT_VOID
1883 {
1884 GC_NOTRIGGER;
1885 PRECONDITION(CheckPointer(this));
1886 POSTCONDITION(!IsLiteral());
1887 THROWS;
1888 }
1889 CONTRACT_END;
1890#else //SSTRING_EXTRA_CHECKS
1891 STATIC_CONTRACT_GC_NOTRIGGER;
1892 STATIC_CONTRACT_THROWS;
1893#endif //SSTRING_EXTRA_CHECKS
1894
1895 if (IsLiteral())
1896 const_cast<SString *>(this)->Resize(GetRawCount(), GetRepresentation(), PRESERVE);
1897
1898 SS_RETURN;
1899}
1900
1901//-----------------------------------------------------------------------------
1902// Convert the internal representation to be a fixed size
1903//-----------------------------------------------------------------------------
1904inline void SString::ConvertToFixed() const
1905{
1906 SS_CONTRACT_VOID
1907 {
1908 GC_NOTRIGGER;
1909 SS_PRECONDITION(CheckPointer(this));
1910 SS_POSTCONDITION(IsFixedSize());
1911 THROWS_UNLESS_NORMALIZED;
1912 SUPPORTS_DAC;
1913 }
1914 SS_CONTRACT_END;
1915
1916 // If we're already fixed size, great.
1917 if (IsFixedSize())
1918 SS_RETURN;
1919
1920 // See if we can coerce it to ASCII.
1921 if (ScanASCII())
1922 SS_RETURN;
1923
1924 // Convert to unicode then.
1925 ConvertToUnicode();
1926
1927 SS_RETURN;
1928}
1929
1930//-----------------------------------------------------------------------------
1931// Convert the internal representation to be an iteratable one (current
1932// requirements here are that it be trivially convertable to unicode chars.)
1933//-----------------------------------------------------------------------------
1934inline void SString::ConvertToIteratable() const
1935{
1936 SS_CONTRACT_VOID
1937 {
1938 GC_NOTRIGGER;
1939 SS_PRECONDITION(CheckPointer(this));
1940 SS_POSTCONDITION(IsIteratable());
1941 THROWS_UNLESS_NORMALIZED;
1942 SUPPORTS_DAC;
1943 }
1944 SS_CONTRACT_END;
1945
1946 // If we're already iteratable, great.
1947 if (IsIteratable())
1948 SS_RETURN;
1949
1950 // See if we can coerce it to ASCII.
1951 if (ScanASCII())
1952 SS_RETURN;
1953
1954 // Convert to unicode then.
1955 ConvertToUnicode();
1956
1957 SS_RETURN;
1958}
1959
1960//-----------------------------------------------------------------------------
1961// Create iterators on the string.
1962//-----------------------------------------------------------------------------
1963
1964inline SString::UIterator SString::BeginUnicode()
1965{
1966 SS_CONTRACT(SString::UIterator)
1967 {
1968 GC_NOTRIGGER;
1969 PRECONDITION(CheckPointer(this));
1970 SS_POSTCONDITION(CheckValue(RETVAL));
1971 THROWS;
1972 }
1973 SS_CONTRACT_END;
1974
1975 ConvertToUnicode();
1976 EnsureWritable();
1977
1978 SS_RETURN UIterator(this, 0);
1979}
1980
1981inline SString::UIterator SString::EndUnicode()
1982{
1983 SS_CONTRACT(SString::UIterator)
1984 {
1985 GC_NOTRIGGER;
1986 PRECONDITION(CheckPointer(this));
1987 SS_POSTCONDITION(CheckValue(RETVAL));
1988 THROWS;
1989 }
1990 SS_CONTRACT_END;
1991
1992 ConvertToUnicode();
1993 EnsureWritable();
1994
1995 SS_RETURN UIterator(this, GetCount());
1996}
1997
1998//-----------------------------------------------------------------------------
1999// Create CIterators on the string.
2000//-----------------------------------------------------------------------------
2001
2002FORCEINLINE SString::CIterator SString::Begin() const
2003{
2004 SS_CONTRACT(SString::CIterator)
2005 {
2006 GC_NOTRIGGER;
2007 PRECONDITION(CheckPointer(this));
2008 SS_POSTCONDITION(CheckValue(RETVAL));
2009 THROWS_UNLESS_NORMALIZED;
2010 }
2011 SS_CONTRACT_END;
2012
2013 ConvertToIteratable();
2014
2015 SS_RETURN CIterator(this, 0);
2016}
2017
2018FORCEINLINE SString::CIterator SString::End() const
2019{
2020 SS_CONTRACT(SString::CIterator)
2021 {
2022 GC_NOTRIGGER;
2023 PRECONDITION(CheckPointer(this));
2024 SS_POSTCONDITION(CheckValue(RETVAL));
2025 THROWS_UNLESS_NORMALIZED;
2026 }
2027 SS_CONTRACT_END;
2028
2029 ConvertToIteratable();
2030
2031 SS_RETURN CIterator(this, GetCount());
2032}
2033
2034//-----------------------------------------------------------------------------
2035// Create Iterators on the string.
2036//-----------------------------------------------------------------------------
2037
2038FORCEINLINE SString::Iterator SString::Begin()
2039{
2040 SS_CONTRACT(SString::Iterator)
2041 {
2042 GC_NOTRIGGER;
2043 PRECONDITION(CheckPointer(this));
2044 SS_POSTCONDITION(CheckValue(RETVAL));
2045 THROWS; // EnsureMutable always throws
2046 SUPPORTS_DAC;
2047 }
2048 SS_CONTRACT_END;
2049
2050 ConvertToIteratable();
2051 EnsureMutable();
2052
2053 SS_RETURN Iterator(this, 0);
2054}
2055
2056FORCEINLINE SString::Iterator SString::End()
2057{
2058 SS_CONTRACT(SString::Iterator)
2059 {
2060 GC_NOTRIGGER;
2061 PRECONDITION(CheckPointer(this));
2062 SS_POSTCONDITION(CheckValue(RETVAL));
2063 THROWS; // EnsureMutable always Throws
2064 SUPPORTS_DAC;
2065 }
2066 SS_CONTRACT_END;
2067
2068 ConvertToIteratable();
2069 EnsureMutable();
2070
2071 SS_RETURN Iterator(this, GetCount());
2072}
2073
2074//-----------------------------------------------------------------------------
2075// CIterator support routines
2076//-----------------------------------------------------------------------------
2077
2078inline SString::Index::Index()
2079{
2080 LIMITED_METHOD_CONTRACT;
2081}
2082
2083inline SString::Index::Index(SString *string, SCOUNT_T index)
2084 : SBuffer::Index(string, index<<string->GetCharacterSizeShift())
2085{
2086 SS_CONTRACT_VOID
2087 {
2088 GC_NOTRIGGER;
2089 PRECONDITION(CheckPointer(string));
2090 PRECONDITION(string->IsIteratable());
2091 PRECONDITION(DoCheck(0));
2092 SS_POSTCONDITION(CheckPointer(this));
2093 // POSTCONDITION(Subtract(string->Begin()) == index); contract violation - fix later
2094 NOTHROW;
2095 CANNOT_TAKE_LOCK;
2096 SUPPORTS_DAC;
2097 }
2098 SS_CONTRACT_END;
2099
2100 m_characterSizeShift = string->GetCharacterSizeShift();
2101
2102 SS_RETURN;
2103}
2104
2105inline BYTE &SString::Index::GetAt(SCOUNT_T delta) const
2106{
2107 LIMITED_METHOD_DAC_CONTRACT;
2108
2109 return m_ptr[delta<<m_characterSizeShift];
2110}
2111
2112inline void SString::Index::Skip(SCOUNT_T delta)
2113{
2114 LIMITED_METHOD_DAC_CONTRACT;
2115
2116 m_ptr += (delta<<m_characterSizeShift);
2117}
2118
2119inline SCOUNT_T SString::Index::Subtract(const Index &i) const
2120{
2121 LIMITED_METHOD_DAC_CONTRACT;
2122
2123 return (SCOUNT_T) ((m_ptr - i.m_ptr)>>m_characterSizeShift);
2124}
2125
2126inline CHECK SString::Index::DoCheck(SCOUNT_T delta) const
2127{
2128 CANNOT_HAVE_CONTRACT;
2129#if _DEBUG
2130 const SString *string = (const SString *) GetContainerDebug();
2131
2132 CHECK(m_ptr + (delta<<m_characterSizeShift) >= string->m_buffer);
2133 CHECK(m_ptr + (delta<<m_characterSizeShift) < string->m_buffer + string->GetSize());
2134#endif
2135 CHECK_OK;
2136}
2137
2138inline void SString::Index::Resync(const SString *string, BYTE *ptr) const
2139{
2140 WRAPPER_NO_CONTRACT;
2141 SUPPORTS_DAC;
2142
2143 SBuffer::Index::Resync(string, ptr);
2144
2145 const_cast<SString::Index*>(this)->m_characterSizeShift = string->GetCharacterSizeShift();
2146}
2147
2148
2149inline const WCHAR *SString::Index::GetUnicode() const
2150{
2151 LIMITED_METHOD_CONTRACT;
2152
2153 return (const WCHAR *) m_ptr;
2154}
2155
2156inline const CHAR *SString::Index::GetASCII() const
2157{
2158 LIMITED_METHOD_CONTRACT;
2159
2160 return (const CHAR *) m_ptr;
2161}
2162
2163inline WCHAR SString::Index::operator*() const
2164{
2165 WRAPPER_NO_CONTRACT;
2166 SUPPORTS_DAC;
2167
2168 if (m_characterSizeShift == 0)
2169 return *(CHAR*)&GetAt(0);
2170 else
2171 return *(WCHAR*)&GetAt(0);
2172}
2173
2174inline void SString::Index::operator->() const
2175{
2176 LIMITED_METHOD_CONTRACT;
2177}
2178
2179inline WCHAR SString::Index::operator[](int index) const
2180{
2181 WRAPPER_NO_CONTRACT;
2182
2183 if (m_characterSizeShift == 0)
2184 return *(CHAR*)&GetAt(index);
2185 else
2186 return *(WCHAR*)&GetAt(index);
2187}
2188
2189//-----------------------------------------------------------------------------
2190// Iterator support routines
2191//-----------------------------------------------------------------------------
2192
2193inline SString::UIndex::UIndex()
2194{
2195 LIMITED_METHOD_CONTRACT;
2196}
2197
2198inline SString::UIndex::UIndex(SString *string, SCOUNT_T index)
2199 : SBuffer::Index(string, index*sizeof(WCHAR))
2200{
2201 SS_CONTRACT_VOID
2202 {
2203 GC_NOTRIGGER;
2204 PRECONDITION(CheckPointer(string));
2205 PRECONDITION(string->IsRepresentation(REPRESENTATION_UNICODE));
2206 PRECONDITION(DoCheck(0));
2207 SS_POSTCONDITION(CheckPointer(this));
2208 NOTHROW;
2209 CANNOT_TAKE_LOCK;
2210 }
2211 SS_CONTRACT_END;
2212
2213 SS_RETURN;
2214}
2215
2216inline WCHAR &SString::UIndex::GetAt(SCOUNT_T delta) const
2217{
2218 LIMITED_METHOD_CONTRACT;
2219
2220 return ((WCHAR*)m_ptr)[delta];
2221}
2222
2223inline void SString::UIndex::Skip(SCOUNT_T delta)
2224{
2225 LIMITED_METHOD_CONTRACT;
2226
2227 m_ptr += delta * sizeof(WCHAR);
2228}
2229
2230inline SCOUNT_T SString::UIndex::Subtract(const UIndex &i) const
2231{
2232 WRAPPER_NO_CONTRACT;
2233
2234 return (SCOUNT_T) (GetUnicode() - i.GetUnicode());
2235}
2236
2237inline CHECK SString::UIndex::DoCheck(SCOUNT_T delta) const
2238{
2239 CANNOT_HAVE_CONTRACT;
2240#if _DEBUG
2241 const SString *string = (const SString *) GetContainerDebug();
2242
2243 CHECK(GetUnicode() + delta >= string->GetRawUnicode());
2244 CHECK(GetUnicode() + delta <= string->GetRawUnicode() + string->GetCount());
2245#endif
2246
2247 CHECK_OK;
2248}
2249
2250inline WCHAR *SString::UIndex::GetUnicode() const
2251{
2252 LIMITED_METHOD_CONTRACT;
2253
2254 return (WCHAR*) m_ptr;
2255}
2256
2257//-----------------------------------------------------------------------------
2258// Opaque scratch buffer class routines
2259//-----------------------------------------------------------------------------
2260inline SString::AbstractScratchBuffer::AbstractScratchBuffer(void *buffer, COUNT_T size)
2261 : SString(buffer, size)
2262{
2263 SS_CONTRACT_VOID
2264 {
2265 GC_NOTRIGGER;
2266 PRECONDITION(CheckPointer(buffer));
2267 PRECONDITION(CheckCount(size));
2268 NOTHROW;
2269 }
2270 SS_CONTRACT_END;
2271
2272 SS_RETURN;
2273}
2274
2275#ifdef _MSC_VER
2276#pragma warning(pop)
2277#endif // _MSC_VER
2278
2279#endif // _SSTRING_INL_
2280