summaryrefslogtreecommitdiff
path: root/src/inc/sstring.inl
diff options
context:
space:
mode:
Diffstat (limited to 'src/inc/sstring.inl')
-rw-r--r--src/inc/sstring.inl2279
1 files changed, 2279 insertions, 0 deletions
diff --git a/src/inc/sstring.inl b/src/inc/sstring.inl
new file mode 100644
index 0000000000..88139ad0cc
--- /dev/null
+++ b/src/inc/sstring.inl
@@ -0,0 +1,2279 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+//
+
+#ifndef _SSTRING_INL_
+#define _SSTRING_INL_
+
+#include "sstring.h"
+
+#if defined(_MSC_VER)
+#pragma inline_depth (20)
+#endif
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable:4702) // Disable bogus unreachable code warning
+#endif // _MSC_VER
+
+//#define SSTRING_EXTRA_CHECKS
+#ifdef SSTRING_EXTRA_CHECKS
+#define SS_CONTRACT CONTRACT
+#define SS_CONTRACT_VOID CONTRACT_VOID
+#define SS_CONTRACT_END CONTRACT_END
+#define SS_RETURN RETURN
+#define SS_CONSTRUCTOR_CHECK CONSTRUCTOR_CHECK
+#define SS_PRECONDITION PRECONDITION
+#define SS_POSTCONDITION POSTCONDITION
+
+#else //SSTRING_EXTRA_CHECKS
+
+#define SS_CONTRACT(x) CONTRACTL
+#define SS_CONTRACT_VOID CONTRACTL
+#define SS_CONTRACT_END CONTRACTL_END
+#define SS_RETURN return
+#define SS_CONSTRUCTOR_CHECK
+#define SS_PRECONDITION(x)
+#define SS_POSTCONDITION(x)
+//Do I need this instance check at all?
+
+#endif
+
+
+// ---------------------------------------------------------------------------
+// Inline implementations. Pay no attention to that man behind the curtain.
+// ---------------------------------------------------------------------------
+
+//----------------------------------------------------------------------------
+// Default constructor. Sets the string to the empty string.
+//----------------------------------------------------------------------------
+inline SString::SString()
+ : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
+{
+#ifdef SSTRING_EXTRA_CHECKS
+ CONTRACT_VOID
+ {
+ CONSTRUCTOR_CHECK;
+ POSTCONDITION(IsEmpty());
+ NOTHROW;
+ SO_TOLERANT;
+ GC_NOTRIGGER;
+ }
+ CONTRACT_END;
+
+ RETURN;
+#else
+ STATIC_CONTRACT_NOTHROW;
+ STATIC_CONTRACT_SO_TOLERANT;
+ STATIC_CONTRACT_GC_NOTRIGGER;
+ STATIC_CONTRACT_SUPPORTS_DAC_HOST_ONLY;
+#endif
+}
+
+inline SString::SString(void *buffer, COUNT_T size)
+ : SBuffer(Prealloc, buffer, size)
+{
+ SS_CONTRACT_VOID
+ {
+ SS_CONSTRUCTOR_CHECK;
+ PRECONDITION(CheckPointer(buffer));
+ PRECONDITION(CheckSize(size));
+ SS_POSTCONDITION(IsEmpty());
+ NOTHROW;
+ GC_NOTRIGGER;
+ SUPPORTS_DAC_HOST_ONLY;
+ }
+ SS_CONTRACT_END;
+
+ if (size < sizeof(WCHAR))
+ {
+ // Ignore the useless buffer
+ SetImmutable(s_EmptyBuffer, sizeof(s_EmptyBuffer));
+ }
+ else
+ {
+ SBuffer::TweakSize(sizeof(WCHAR));
+ GetRawUnicode()[0] = 0;
+ }
+
+ SS_RETURN;
+}
+
+inline SString::SString(const SString &s)
+ : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
+{
+ SS_CONTRACT_VOID
+ {
+ SS_CONSTRUCTOR_CHECK;
+ PRECONDITION(s.Check());
+ SS_POSTCONDITION(Equals(s));
+ THROWS;
+ GC_NOTRIGGER;
+ }
+ SS_CONTRACT_END;
+
+ Set(s);
+
+ SS_RETURN;
+}
+
+inline SString::SString(const SString &s1, const SString &s2)
+ : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
+{
+ SS_CONTRACT_VOID
+ {
+ SS_CONSTRUCTOR_CHECK;
+ PRECONDITION(s1.Check());
+ PRECONDITION(s2.Check());
+ THROWS;
+ GC_NOTRIGGER;
+ }
+ SS_CONTRACT_END;
+
+ Set(s1, s2);
+
+ SS_RETURN;
+}
+
+inline SString::SString(const SString &s1, const SString &s2, const SString &s3)
+ : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
+{
+ SS_CONTRACT_VOID
+ {
+ SS_CONSTRUCTOR_CHECK;
+ PRECONDITION(s1.Check());
+ PRECONDITION(s2.Check());
+ PRECONDITION(s3.Check());
+ THROWS;
+ GC_NOTRIGGER;
+ }
+ SS_CONTRACT_END;
+
+ Set(s1, s2, s3);
+
+ SS_RETURN;
+}
+
+inline SString::SString(const SString &s1, const SString &s2, const SString &s3, const SString &s4)
+ : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
+{
+ SS_CONTRACT_VOID
+ {
+ SS_CONSTRUCTOR_CHECK;
+ PRECONDITION(s1.Check());
+ PRECONDITION(s2.Check());
+ PRECONDITION(s3.Check());
+ PRECONDITION(s4.Check());
+ THROWS;
+ }
+ SS_CONTRACT_END;
+
+ Set(s1, s2, s3, s4);
+
+ SS_RETURN;
+}
+
+inline SString::SString(const SString &s, const CIterator &i, COUNT_T count)
+ : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
+{
+ SS_CONTRACT_VOID
+ {
+ SS_CONSTRUCTOR_CHECK;
+ PRECONDITION(s.Check());
+ PRECONDITION(i.Check());
+ PRECONDITION(CheckCount(count));
+ SS_POSTCONDITION(s.Match(i, *this));
+ SS_POSTCONDITION(GetRawCount() == count);
+ THROWS;
+ GC_NOTRIGGER;
+ }
+ SS_CONTRACT_END;
+
+ Set(s, i, count);
+
+ SS_RETURN;
+}
+
+inline SString::SString(const SString &s, const CIterator &start, const CIterator &end)
+ : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
+{
+ SS_CONTRACT_VOID
+ {
+ SS_CONSTRUCTOR_CHECK;
+ PRECONDITION(s.Check());
+ PRECONDITION(start.Check());
+ PRECONDITION(s.CheckIteratorRange(start));
+ PRECONDITION(end.Check());
+ PRECONDITION(s.CheckIteratorRange(end));
+ PRECONDITION(start <= end);
+ SS_POSTCONDITION(s.Match(start, *this));
+ SS_POSTCONDITION(GetRawCount() == (COUNT_T) (end - start));
+ THROWS;
+ GC_NOTRIGGER;
+ }
+ SS_CONTRACT_END;
+
+ Set(s, start, end);
+
+ SS_RETURN;
+}
+
+inline SString::SString(const WCHAR *string)
+ : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
+{
+ SS_CONTRACT_VOID
+ {
+ SS_CONSTRUCTOR_CHECK;
+ PRECONDITION(CheckPointer(string, NULL_OK));
+ THROWS;
+ GC_NOTRIGGER;
+ }
+ SS_CONTRACT_END;
+
+ Set(string);
+
+ SS_RETURN;
+}
+
+inline SString::SString(const WCHAR *string, COUNT_T count)
+ : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
+{
+ SS_CONTRACT_VOID
+ {
+ SS_CONSTRUCTOR_CHECK;
+ PRECONDITION(CheckPointer(string, NULL_OK));
+ PRECONDITION(CheckCount(count));
+ THROWS;
+ GC_NOTRIGGER;
+ }
+ SS_CONTRACT_END;
+
+ Set(string, count);
+
+ SS_RETURN;
+}
+
+inline SString::SString(enum tagASCII, const ASCII *string)
+ : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
+{
+ SS_CONTRACT_VOID
+ {
+ SS_CONSTRUCTOR_CHECK;
+ PRECONDITION(CheckPointer(string, NULL_OK));
+ PRECONDITION(CheckASCIIString(string));
+ THROWS;
+ GC_NOTRIGGER;
+ }
+ SS_CONTRACT_END;
+
+ SetASCII(string);
+
+ SS_RETURN;
+}
+
+inline SString::SString(enum tagASCII, const ASCII *string, COUNT_T count)
+ : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
+{
+ SS_CONTRACT_VOID
+ {
+ SS_CONSTRUCTOR_CHECK;
+ PRECONDITION(CheckPointer(string, NULL_OK));
+ PRECONDITION(CheckASCIIString(string, count));
+ PRECONDITION(CheckCount(count));
+ THROWS;
+ GC_NOTRIGGER;
+ }
+ SS_CONTRACT_END;
+
+ SetASCII(string, count);
+
+ SS_RETURN;
+}
+
+inline SString::SString(tagUTF8 dummytag, const UTF8 *string)
+ : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
+{
+ SS_CONTRACT_VOID
+ {
+ SS_CONSTRUCTOR_CHECK;
+ // !!! Check for illegal UTF8 encoding?
+ PRECONDITION(CheckPointer(string, NULL_OK));
+ THROWS;
+ GC_NOTRIGGER;
+ SUPPORTS_DAC;
+ }
+ SS_CONTRACT_END;
+
+ SetUTF8(string);
+
+ SS_RETURN;
+}
+
+inline SString::SString(tagUTF8 dummytag, const UTF8 *string, COUNT_T count)
+ : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
+{
+ SS_CONTRACT_VOID
+ {
+ SS_CONSTRUCTOR_CHECK;
+ // !!! Check for illegal UTF8 encoding?
+ PRECONDITION(CheckPointer(string, NULL_OK));
+ PRECONDITION(CheckCount(count));
+ THROWS;
+ GC_NOTRIGGER;
+ }
+ SS_CONTRACT_END;
+
+ SetUTF8(string, count);
+
+ SS_RETURN;
+}
+
+inline SString::SString(tagANSI dummytag, const ANSI *string)
+ : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
+{
+ SS_CONTRACT_VOID
+ {
+ SS_CONSTRUCTOR_CHECK;
+ PRECONDITION(CheckPointer(string, NULL_OK));
+ THROWS;
+ GC_NOTRIGGER;
+ }
+ SS_CONTRACT_END;
+
+ SetANSI(string);
+
+ SS_RETURN;
+}
+
+inline SString::SString(tagANSI dummytag, const ANSI *string, COUNT_T count)
+ : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
+{
+ SS_CONTRACT_VOID
+ {
+ SS_CONSTRUCTOR_CHECK;
+ PRECONDITION(CheckPointer(string, NULL_OK));
+ PRECONDITION(CheckCount(count));
+ THROWS;
+ GC_NOTRIGGER;
+ }
+ SS_CONTRACT_END;
+
+ SetANSI(string, count);
+
+ SS_RETURN;
+}
+
+inline SString::SString(WCHAR character)
+ : SBuffer(Immutable, s_EmptyBuffer, sizeof(s_EmptyBuffer))
+{
+ SS_CONTRACT_VOID
+ {
+ SS_CONSTRUCTOR_CHECK;
+ THROWS;
+ GC_NOTRIGGER;
+ }
+ SS_CONTRACT_END;
+
+ Set(character);
+
+ SS_RETURN;
+}
+
+inline SString::SString(tagLiteral dummytag, const ASCII *literal)
+ : SBuffer(Immutable, (const BYTE *) literal, (COUNT_T) (strlen(literal)+1)*sizeof(CHAR))
+{
+ SS_CONTRACT_VOID
+ {
+ SS_CONSTRUCTOR_CHECK;
+ PRECONDITION(CheckPointer(literal));
+ PRECONDITION(CheckASCIIString(literal));
+ NOTHROW;
+ GC_NOTRIGGER;
+ SUPPORTS_DAC_HOST_ONLY;
+ }
+ SS_CONTRACT_END;
+
+ SetRepresentation(REPRESENTATION_ASCII);
+
+ SS_RETURN;
+}
+
+inline SString::SString(tagUTF8Literal dummytag, const UTF8 *literal)
+ : SBuffer(Immutable, (const BYTE *) literal, (COUNT_T) (strlen(literal)+1)*sizeof(CHAR))
+{
+ SS_CONTRACT_VOID
+ {
+ SS_CONSTRUCTOR_CHECK;
+ PRECONDITION(CheckPointer(literal));
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ SS_CONTRACT_END;
+
+ SetRepresentation(REPRESENTATION_UTF8);
+
+ SS_RETURN;
+}
+
+inline SString::SString(tagLiteral dummytag, const WCHAR *literal)
+ : SBuffer(Immutable, (const BYTE *) literal, (COUNT_T) (wcslen(literal)+1)*sizeof(WCHAR))
+{
+ SS_CONTRACT_VOID
+ {
+ SS_CONSTRUCTOR_CHECK;
+ PRECONDITION(CheckPointer(literal));
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ SS_CONTRACT_END;
+
+ SetRepresentation(REPRESENTATION_UNICODE);
+ SetNormalized();
+
+ SS_RETURN;
+}
+
+inline SString::SString(tagLiteral dummytag, const WCHAR *literal, COUNT_T count)
+ : SBuffer(Immutable, (const BYTE *) literal, (count + 1) * sizeof(WCHAR))
+{
+ SS_CONTRACT_VOID
+ {
+ SS_CONSTRUCTOR_CHECK;
+ PRECONDITION(CheckPointer(literal));
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ SS_CONTRACT_END;
+
+ SetRepresentation(REPRESENTATION_UNICODE);
+ SetNormalized();
+
+ SS_RETURN;
+}
+
+//-----------------------------------------------------------------------------
+// Set this string to s
+// s - source string
+//-----------------------------------------------------------------------------
+inline void SString::Set(const SString &s)
+{
+ SS_CONTRACT_VOID
+ {
+ INSTANCE_CHECK;
+ PRECONDITION(s.Check());
+ SS_POSTCONDITION(Equals(s));
+ THROWS;
+ GC_NOTRIGGER;
+ SUPPORTS_DAC;
+ }
+ SS_CONTRACT_END;
+
+ SBuffer::Set(s);
+ SetRepresentation(s.GetRepresentation());
+ ClearNormalized();
+
+ SS_RETURN;
+}
+
+//-----------------------------------------------------------------------------
+// Set this string to concatenation of s1 and s2
+//-----------------------------------------------------------------------------
+inline void SString::Set(const SString &s1, const SString &s2)
+{
+ SS_CONTRACT_VOID
+ {
+ INSTANCE_CHECK;
+ PRECONDITION(s1.Check());
+ PRECONDITION(s2.Check());
+ THROWS;
+ GC_NOTRIGGER;
+ }
+ SS_CONTRACT_END;
+
+ Preallocate(s1.GetCount() + s2.GetCount());
+
+ Set(s1);
+ Append(s2);
+
+ SS_RETURN;
+}
+
+//-----------------------------------------------------------------------------
+// Set this string to concatenation of s1, s2, and s3
+//-----------------------------------------------------------------------------
+inline void SString::Set(const SString &s1, const SString &s2, const SString &s3)
+{
+ SS_CONTRACT_VOID
+ {
+ INSTANCE_CHECK;
+ PRECONDITION(s1.Check());
+ PRECONDITION(s2.Check());
+ PRECONDITION(s3.Check());
+ THROWS;
+ GC_NOTRIGGER;
+ }
+ SS_CONTRACT_END;
+
+ Preallocate(s1.GetCount() + s2.GetCount() + s3.GetCount());
+
+ Set(s1);
+ Append(s2);
+ Append(s3);
+
+ SS_RETURN;
+}
+
+//-----------------------------------------------------------------------------
+// Set this string to concatenation of s1, s2, s3, and s4
+//-----------------------------------------------------------------------------
+inline void SString::Set(const SString &s1, const SString &s2, const SString &s3, const SString &s4)
+{
+ SS_CONTRACT_VOID
+ {
+ INSTANCE_CHECK;
+ PRECONDITION(s1.Check());
+ PRECONDITION(s2.Check());
+ PRECONDITION(s3.Check());
+ PRECONDITION(s4.Check());
+ THROWS;
+ GC_NOTRIGGER;
+ }
+ SS_CONTRACT_END;
+
+ Preallocate(s1.GetCount() + s2.GetCount() + s3.GetCount() + s4.GetCount());
+
+ Set(s1);
+ Append(s2);
+ Append(s3);
+ Append(s4);
+
+ SS_RETURN;
+}
+
+//-----------------------------------------------------------------------------
+// Set this string to the substring from s.
+// s - the source string
+// start - the character to start at
+// length - number of characters to copy from s.
+//-----------------------------------------------------------------------------
+inline void SString::Set(const SString &s, const CIterator &i, COUNT_T count)
+{
+ SS_CONTRACT_VOID
+ {
+ INSTANCE_CHECK;
+ PRECONDITION(s.Check());
+ PRECONDITION(i.Check());
+ PRECONDITION(CheckCount(count));
+ SS_POSTCONDITION(s.Match(i, *this));
+ SS_POSTCONDITION(GetRawCount() == count);
+ THROWS;
+ GC_NOTRIGGER;
+ }
+ SS_CONTRACT_END;
+
+ // @todo: detect case where we can reuse literal?
+ Resize(count, s.GetRepresentation());
+ SBuffer::Copy(SBuffer::Begin(), i.m_ptr, count<<i.m_characterSizeShift);
+ NullTerminate();
+
+ SS_RETURN;
+}
+
+//-----------------------------------------------------------------------------
+// Set this string to the substring from s.
+// s - the source string
+// start - the position to start
+// end - the position to end (exclusive)
+//-----------------------------------------------------------------------------
+inline void SString::Set(const SString &s, const CIterator &start, const CIterator &end)
+{
+ SS_CONTRACT_VOID
+ {
+ INSTANCE_CHECK;
+ PRECONDITION(s.Check());
+ PRECONDITION(start.Check());
+ PRECONDITION(s.CheckIteratorRange(start));
+ PRECONDITION(end.Check());
+ PRECONDITION(s.CheckIteratorRange(end));
+ PRECONDITION(end >= start);
+ SS_POSTCONDITION(s.Match(start, *this));
+ SS_POSTCONDITION(GetRawCount() == (COUNT_T) (end - start));
+ THROWS;
+ GC_NOTRIGGER;
+ }
+ SS_CONTRACT_END;
+
+ Set(s, start, end - start);
+
+ SS_RETURN;
+}
+
+// Return a global empty string
+inline const SString &SString::Empty()
+{
+#ifdef SSTRING_EXTRA_CHECKS
+ CONTRACTL
+ {
+ // POSTCONDITION(RETVAL.IsEmpty());
+ PRECONDITION(CheckStartup());
+ NOTHROW;
+ GC_NOTRIGGER;
+ CANNOT_TAKE_LOCK;
+ SO_TOLERANT;
+ SUPPORTS_DAC;
+ }
+ CONTRACTL_END;
+#else
+ STATIC_CONTRACT_NOTHROW;
+ STATIC_CONTRACT_GC_NOTRIGGER;
+ STATIC_CONTRACT_CANNOT_TAKE_LOCK;
+ STATIC_CONTRACT_SO_TOLERANT;
+ STATIC_CONTRACT_SUPPORTS_DAC;
+#endif
+
+ _ASSERTE(s_Empty != NULL); // Did you call SString::Startup()?
+ return *s_Empty;
+}
+
+// Get a const pointer to the internal buffer as a unicode string.
+inline const WCHAR *SString::GetUnicode() const
+{
+ SS_CONTRACT(const WCHAR *)
+ {
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(this));
+ SS_POSTCONDITION(CheckPointer(RETVAL));
+ if (IsRepresentation(REPRESENTATION_UNICODE)) NOTHROW; else THROWS;
+ GC_NOTRIGGER;
+ SUPPORTS_DAC;
+ }
+ SS_CONTRACT_END;
+
+ if (this == NULL)
+ SS_RETURN NULL;
+
+ ConvertToUnicode();
+
+ SS_RETURN GetRawUnicode();
+}
+
+// Normalize the string to unicode. This will make many operations nonfailing.
+inline void SString::Normalize() const
+{
+ SS_CONTRACT_VOID
+ {
+ INSTANCE_CHECK;
+ SS_POSTCONDITION(IsNormalized());
+ THROWS_UNLESS_NORMALIZED;
+ GC_NOTRIGGER;
+ }
+ SS_CONTRACT_END;
+
+ ConvertToUnicode();
+ SetNormalized();
+
+ SS_RETURN;
+}
+
+// Get a const pointer to the internal buffer as a unicode string.
+inline const WCHAR *SString::GetUnicode(const CIterator &i) const
+{
+ SS_CONTRACT(const WCHAR *)
+ {
+ INSTANCE_CHECK;
+ PRECONDITION(CheckIteratorRange(i));
+ THROWS_UNLESS_NORMALIZED;
+ GC_NOTRIGGER;
+ }
+ SS_CONTRACT_END;
+
+ PRECONDITION(CheckPointer(this));
+
+ ConvertToUnicode(i);
+
+ SS_RETURN i.GetUnicode();
+}
+
+// Append s to the end of this string.
+inline void SString::Append(const SString &s)
+{
+ SS_CONTRACT_VOID
+ {
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(this));
+ PRECONDITION(s.Check());
+ THROWS;
+ SUPPORTS_DAC_HOST_ONLY;
+ }
+ SS_CONTRACT_END;
+
+ Insert(End(), s);
+
+ SS_RETURN;
+}
+
+inline void SString::Append(const WCHAR *string)
+{
+ SS_CONTRACT_VOID
+ {
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(this));
+ PRECONDITION(CheckPointer(string));
+ THROWS;
+ SUPPORTS_DAC_HOST_ONLY;
+ }
+ SS_CONTRACT_END;
+
+ // Wrap the string in temporary SString without copying it
+ SString s(SString::Literal, string);
+ s.ClearImmutable();
+ Append(s);
+
+ SS_RETURN;
+}
+
+inline void SString::AppendASCII(const CHAR *string)
+{
+ SS_CONTRACT_VOID
+ {
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(this));
+ PRECONDITION(CheckPointer(string));
+ THROWS;
+ }
+ SS_CONTRACT_END;
+
+ StackSString s(SString::Ascii, string);
+ Append(s);
+
+ SS_RETURN;
+}
+
+inline void SString::AppendUTF8(const CHAR *string)
+{
+ SS_CONTRACT_VOID
+ {
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(this));
+ PRECONDITION(CheckPointer(string));
+ THROWS;
+ }
+ SS_CONTRACT_END;
+
+ StackSString s(SString::Utf8, string);
+ Append(s);
+
+ SS_RETURN;
+}
+
+inline void SString::Append(const WCHAR c)
+{
+ SS_CONTRACT_VOID
+ {
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(this));
+ THROWS;
+ }
+ SS_CONTRACT_END;
+
+ InlineSString<2 * sizeof(c)> s(c);
+ Append(s);
+
+ SS_RETURN;
+}
+
+inline void SString::AppendUTF8(const CHAR c)
+{
+ SS_CONTRACT_VOID
+ {
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(this));
+ THROWS;
+ SUPPORTS_DAC_HOST_ONLY;
+ }
+ SS_CONTRACT_END;
+
+ InlineSString<2 * sizeof(c)> s(SString::Utf8, c);
+ Append(s);
+
+ SS_RETURN;
+}
+
+// Turn this on to test that these if you are testing common scenarios dealing with
+// ASCII strings that do not touch the cases where this family of function differs
+// in behavior for expected reasons.
+//#define VERIFY_CRT_EQUIVALNCE 1
+
+// Helpers for CRT function equivalance.
+/* static */
+inline int __cdecl SString::_stricmp(const CHAR *buffer1, const CHAR *buffer2) {
+ WRAPPER_NO_CONTRACT;
+ int returnValue = CaseCompareHelperA(buffer1, buffer2, 0, s_defaultLCID, TRUE, FALSE);
+#ifdef VERIFY_CRT_EQUIVALNCE
+ _ASSERTE((returnValue == 0) == (::_stricmp(buffer1, buffer2) == 0));
+#endif
+ return returnValue;
+
+}
+
+/* static */
+inline int __cdecl SString::_strnicmp(const CHAR *buffer1, const CHAR *buffer2, COUNT_T count) {
+ WRAPPER_NO_CONTRACT;
+ int returnValue = CaseCompareHelperA(buffer1, buffer2, count, s_defaultLCID, TRUE, TRUE);
+#ifdef VERIFY_CRT_EQUIVALNCE
+ _ASSERTE((returnValue == 0) == (::_strnicmp(buffer1, buffer2, count) == 0));
+#endif
+ return returnValue;
+}
+
+/* static */
+inline int __cdecl SString::_wcsicmp(const WCHAR *buffer1, const WCHAR *buffer2) {
+ WRAPPER_NO_CONTRACT;
+ int returnValue = CaseCompareHelper(buffer1, buffer2, 0, s_defaultLCID, TRUE, FALSE);
+#ifdef VERIFY_CRT_EQUIVALNCE
+ _ASSERTE((returnValue == 0) == (::_wcsicmp(buffer1, buffer2) == 0));
+#endif
+ return returnValue;
+
+}
+
+/* static */
+inline int __cdecl SString::_wcsnicmp(const WCHAR *buffer1, const WCHAR *buffer2, COUNT_T count) {
+ WRAPPER_NO_CONTRACT;
+ int returnValue = CaseCompareHelper(buffer1, buffer2, count, s_defaultLCID, TRUE, TRUE);
+#ifdef VERIFY_CRT_EQUIVALNCE
+ _ASSERTE((returnValue == 0) == (::_wcsnicmp(buffer1, buffer2, count) == 0));
+#endif
+ return returnValue;
+}
+
+inline int SString::_tstricmp(const CHAR *buffer1, const CHAR *buffer2)
+{
+ return _stricmp(buffer1, buffer2);
+}
+
+inline int SString::_tstricmp(const WCHAR *buffer1, const WCHAR *buffer2)
+{
+ return _wcsicmp(buffer1, buffer2);
+}
+
+inline int SString::_tstrnicmp(const CHAR *buffer1, const CHAR *buffer2, COUNT_T count)
+{
+ return _strnicmp(buffer1, buffer2, count);
+}
+
+inline int SString::_tstrnicmp(const WCHAR *buffer1, const WCHAR *buffer2, COUNT_T count)
+{
+ return _wcsnicmp(buffer1, buffer2, count);
+}
+
+inline ULONG SString::HashCaseInsensitive() const
+{
+ WRAPPER_NO_CONTRACT;
+ return HashCaseInsensitive(s_defaultLCID);
+}
+
+inline int SString::CompareCaseInsensitive(const SString &s) const
+{
+ WRAPPER_NO_CONTRACT;
+ return CompareCaseInsensitive(s, s_defaultLCID);
+}
+
+inline BOOL SString::EqualsCaseInsensitive(const SString &s) const
+{
+ WRAPPER_NO_CONTRACT;
+ return EqualsCaseInsensitive(s, s_defaultLCID);
+}
+
+inline BOOL SString::MatchCaseInsensitive(const CIterator &i, const SString &s) const
+{
+ WRAPPER_NO_CONTRACT;
+ return MatchCaseInsensitive(i, s, s_defaultLCID);
+}
+
+inline BOOL SString::MatchCaseInsensitive(const CIterator &i, WCHAR c) const
+{
+ WRAPPER_NO_CONTRACT;
+ return MatchCaseInsensitive(i, c, s_defaultLCID);
+}
+
+inline BOOL SString::Match(const CIterator &i, WCHAR c) const
+{
+ SS_CONTRACT(BOOL)
+ {
+ GC_NOTRIGGER;
+ INSTANCE_CHECK;
+ PRECONDITION(CheckIteratorRange(i));
+ NOTHROW;
+ }
+ SS_CONTRACT_END;
+
+ // End() will not throw here
+ CONTRACT_VIOLATION(ThrowsViolation);
+ SS_RETURN (i < End() && i[0] == c);
+}
+
+inline BOOL SString::Skip(CIterator &i, const SString &s) const
+{
+ SS_CONTRACT(BOOL)
+ {
+ GC_NOTRIGGER;
+ INSTANCE_CHECK;
+ PRECONDITION(CheckIteratorRange(i));
+ PRECONDITION(s.Check());
+ THROWS_UNLESS_BOTH_NORMALIZED(s);
+ }
+ SS_CONTRACT_END;
+
+ if (Match(i, s))
+ {
+ i += s.GetRawCount();
+ SS_RETURN TRUE;
+ }
+ else
+ SS_RETURN FALSE;
+}
+
+inline BOOL SString::Skip(CIterator &i, WCHAR c) const
+{
+ SS_CONTRACT(BOOL)
+ {
+ GC_NOTRIGGER;
+ INSTANCE_CHECK;
+ PRECONDITION(CheckIteratorRange(i));
+ NOTHROW;
+ }
+ SS_CONTRACT_END;
+
+ if (Match(i, c))
+ {
+ i++;
+ SS_RETURN TRUE;
+ }
+ else
+ SS_RETURN FALSE;
+}
+
+// Find string within this string. Return TRUE and update iterator if found
+inline BOOL SString::Find(CIterator &i, const WCHAR *string) const
+{
+ SS_CONTRACT(BOOL)
+ {
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(this));
+ PRECONDITION(CheckIteratorRange(i));
+ PRECONDITION(CheckPointer(string));
+ SS_POSTCONDITION(RETVAL == Match(i, SString(string)));
+ THROWS;
+ }
+ SS_CONTRACT_END;
+
+ StackSString s(string);
+ SS_RETURN Find(i, s);
+}
+
+inline BOOL SString::FindASCII(CIterator &i, const CHAR *string) const
+{
+ SS_CONTRACT(BOOL)
+ {
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(this));
+ PRECONDITION(CheckIteratorRange(i));
+ PRECONDITION(CheckPointer(string));
+ SS_POSTCONDITION(RETVAL == Match(i, SString(SString::Ascii, string)));
+ THROWS;
+ }
+ SS_CONTRACT_END;
+
+ StackSString s(SString::Ascii, string);
+ SS_RETURN Find(i, s);
+}
+
+inline BOOL SString::FindUTF8(CIterator &i, const CHAR *string) const
+{
+ SS_CONTRACT(BOOL)
+ {
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(this));
+ PRECONDITION(CheckIteratorRange(i));
+ PRECONDITION(CheckPointer(string));
+ SS_POSTCONDITION(RETVAL == Match(i, SString(SString::Ascii, string)));
+ THROWS;
+ }
+ SS_CONTRACT_END;
+
+ StackSString s(SString::Utf8, string);
+ SS_RETURN Find(i, s);
+}
+
+inline BOOL SString::FindBack(CIterator &i, const WCHAR *string) const
+{
+ SS_CONTRACT(BOOL)
+ {
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(this));
+ PRECONDITION(CheckIteratorRange(i));
+ PRECONDITION(CheckPointer(string));
+ SS_POSTCONDITION(RETVAL == Match(i, SString(string)));
+ THROWS;
+ }
+ SS_CONTRACT_END;
+
+ StackSString s(string);
+ SS_RETURN FindBack(i, s);
+}
+
+inline BOOL SString::FindBackASCII(CIterator &i, const CHAR *string) const
+{
+ SS_CONTRACT(BOOL)
+ {
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(this));
+ PRECONDITION(CheckIteratorRange(i));
+ PRECONDITION(CheckPointer(string));
+ SS_POSTCONDITION(RETVAL == Match(i, SString(SString::Ascii, string)));
+ THROWS;
+ }
+ SS_CONTRACT_END;
+
+ StackSString s(SString::Ascii, string);
+ SS_RETURN FindBack(i, s);
+}
+
+inline BOOL SString::FindBackUTF8(CIterator &i, const CHAR *string) const
+{
+ SS_CONTRACT(BOOL)
+ {
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(this));
+ PRECONDITION(CheckIteratorRange(i));
+ PRECONDITION(CheckPointer(string));
+ SS_POSTCONDITION(RETVAL == Match(i, SString(SString::Ascii, string)));
+ THROWS;
+ }
+ SS_CONTRACT_END;
+
+ StackSString s(SString::Utf8, string);
+ SS_RETURN FindBack(i, s);
+}
+
+// Insert string at iterator position
+inline void SString::Insert(const Iterator &i, const SString &s)
+{
+ SS_CONTRACT_VOID
+ {
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(this));
+ PRECONDITION(CheckIteratorRange(i));
+ PRECONDITION(s.Check());
+ THROWS;
+ SUPPORTS_DAC_HOST_ONLY;
+ }
+ SS_CONTRACT_END;
+
+ Replace(i, 0, s);
+
+ SS_RETURN;
+}
+
+inline void SString::Insert(const Iterator &i, const WCHAR *string)
+{
+ SS_CONTRACT_VOID
+ {
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(this));
+ PRECONDITION(CheckIteratorRange(i));
+ PRECONDITION(CheckPointer(string));
+ THROWS;
+ }
+ SS_CONTRACT_END;
+
+ StackSString s(string);
+ Replace(i, 0, s);
+
+ SS_RETURN;
+}
+
+inline void SString::InsertASCII(const Iterator &i, const CHAR *string)
+{
+ SS_CONTRACT_VOID
+ {
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(this));
+ PRECONDITION(CheckIteratorRange(i));
+ PRECONDITION(CheckPointer(string));
+ THROWS;
+ }
+ SS_CONTRACT_END;
+
+ StackSString s(SString::Ascii, string);
+ Replace(i, 0, s);
+
+ SS_RETURN;
+}
+
+inline void SString::InsertUTF8(const Iterator &i, const CHAR *string)
+{
+ SS_CONTRACT_VOID
+ {
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(this));
+ PRECONDITION(CheckIteratorRange(i));
+ PRECONDITION(CheckPointer(string));
+ THROWS;
+ }
+ SS_CONTRACT_END;
+
+ StackSString s(SString::Utf8, string);
+ Replace(i, 0, s);
+
+ SS_RETURN;
+}
+
+// Delete string at iterator position
+inline void SString::Delete(const Iterator &i, COUNT_T length)
+{
+ SS_CONTRACT_VOID
+ {
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(this));
+ PRECONDITION(CheckIteratorRange(i, length));
+ THROWS;
+ SUPPORTS_DAC_HOST_ONLY;
+ }
+ SS_CONTRACT_END;
+
+ Replace(i, length, Empty());
+
+ SS_RETURN;
+}
+
+// Preallocate some space for the string buffer
+inline void SString::Preallocate(COUNT_T characters) const
+{
+ WRAPPER_NO_CONTRACT;
+
+ // Assume unicode since we may get converted
+ SBuffer::Preallocate(characters * sizeof(WCHAR));
+}
+
+// Trim unused space from the buffer
+inline void SString::Trim() const
+{
+ WRAPPER_NO_CONTRACT;
+
+ if (GetRawCount() == 0)
+ {
+ // Share the global empty string buffer.
+ const_cast<SString *>(this)->SBuffer::SetImmutable(s_EmptyBuffer, sizeof(s_EmptyBuffer));
+ }
+ else
+ {
+ SBuffer::Trim();
+ }
+}
+
+// RETURN true if the string is empty.
+inline BOOL SString::IsEmpty() const
+{
+ SS_CONTRACT(BOOL)
+ {
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(this));
+ NOTHROW;
+ SO_TOLERANT;
+ SUPPORTS_DAC;
+ }
+ SS_CONTRACT_END;
+
+ SS_RETURN (GetRawCount() == 0);
+}
+
+// RETURN true if the string rep is ASCII.
+inline BOOL SString::IsASCII() const
+{
+ SS_CONTRACT(BOOL)
+ {
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(this));
+ NOTHROW;
+ SO_TOLERANT;
+ }
+ SS_CONTRACT_END;
+
+ SS_RETURN IsRepresentation(REPRESENTATION_ASCII);
+}
+
+// Get the number of characters in the string (excluding the terminating NULL)
+inline COUNT_T SString::GetCount() const
+{
+ SS_CONTRACT(COUNT_T)
+ {
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(this));
+ SS_POSTCONDITION(CheckCount(RETVAL));
+ THROWS_UNLESS_NORMALIZED;
+ SUPPORTS_DAC;
+ }
+ SS_CONTRACT_END;
+
+ ConvertToFixed();
+
+ SS_RETURN SizeToCount(GetSize());
+}
+
+// Private helpers:
+// Return the current size of the string (even if it is multibyte)
+inline COUNT_T SString::GetRawCount() const
+{
+ WRAPPER_NO_CONTRACT;
+
+ return SizeToCount(GetSize());
+}
+
+// Private helpers:
+// get string contents as a particular character set:
+
+inline ASCII *SString::GetRawASCII() const
+{
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ return (ASCII *) m_buffer;
+}
+
+inline UTF8 *SString::GetRawUTF8() const
+{
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ return (UTF8 *) m_buffer;
+}
+
+inline ANSI *SString::GetRawANSI() const
+{
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ return (ANSI *) m_buffer;
+}
+
+inline WCHAR *SString::GetRawUnicode() const
+{
+ LIMITED_METHOD_CONTRACT;
+ SUPPORTS_DAC_HOST_ONLY;
+
+ return (WCHAR *)m_buffer;
+}
+
+// Private helper:
+// get the representation (ansi, unicode, utf8)
+inline SString::Representation SString::GetRepresentation() const
+{
+ WRAPPER_NO_CONTRACT;
+
+ return (Representation) SBuffer::GetRepresentationField();
+}
+
+// Private helper.
+// Set the representation.
+inline void SString::SetRepresentation(SString::Representation representation)
+{
+#ifdef SSTRING_EXTRA_CHECKS
+ CONTRACT_VOID
+ {
+ GC_NOTRIGGER;
+ NOTHROW;
+ PRECONDITION(CheckPointer(this));
+ PRECONDITION(CheckRepresentation(representation));
+ POSTCONDITION(GetRepresentation() == representation);
+ }
+ CONTRACT_END;
+#else //SSTRING_EXTRA_CHECKS
+ STATIC_CONTRACT_NOTHROW;
+ STATIC_CONTRACT_GC_NOTRIGGER;
+ STATIC_CONTRACT_SUPPORTS_DAC_HOST_ONLY;
+#endif //SSTRING_EXTRA_CHECKS
+
+ SBuffer::SetRepresentationField((int) representation);
+
+ SS_RETURN;
+}
+
+// Private helper:
+// Get the amount to shift the byte size to get a character count
+inline int SString::GetCharacterSizeShift() const
+{
+ WRAPPER_NO_CONTRACT;
+
+ // Note that the flag is backwards; we want the default
+ // value to match the default representation (empty)
+ return (GetRepresentation()&REPRESENTATION_SINGLE_MASK) == 0;
+}
+
+//----------------------------------------------------------------------------
+// Private helper.
+// We know the buffer should be m_count characters. Place a null terminator
+// in the buffer to make our internal string null-terminated at that length.
+//----------------------------------------------------------------------------
+FORCEINLINE void SString::NullTerminate()
+{
+ SUPPORTS_DAC_HOST_ONLY;
+#ifdef SSTRING_EXTRA_CHECKS
+ CONTRACT_VOID
+ {
+ POSTCONDITION(CheckPointer(this));
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ CONTRACT_END;
+#else //SSTRING_EXTRA_CHECKS
+ STATIC_CONTRACT_NOTHROW;
+ STATIC_CONTRACT_GC_NOTRIGGER;
+#endif //SSTRING_EXTRA_CHECKS
+
+ BYTE *end = m_buffer + GetSize();
+
+ if (GetRepresentation()&REPRESENTATION_SINGLE_MASK)
+ {
+ ((CHAR *)end)[-1] = 0;
+ }
+ else
+ {
+ ((WCHAR *)end)[-1] = 0;
+ }
+
+ SS_RETURN;
+}
+
+//----------------------------------------------------------------------------
+// private helper
+// Return true if the string is a literal.
+// A literal string has immutable memory.
+//----------------------------------------------------------------------------
+inline BOOL SString::IsLiteral() const
+{
+ WRAPPER_NO_CONTRACT;
+
+ return SBuffer::IsImmutable() && (m_buffer != s_EmptyBuffer);
+}
+
+//----------------------------------------------------------------------------
+// private helper:
+// RETURN true if the string allocated (and should delete) its buffer.
+// IsAllocated() will RETURN false for Literal strings and
+// stack-based strings (the buffer is on the stack)
+//----------------------------------------------------------------------------
+inline BOOL SString::IsAllocated() const
+{
+ WRAPPER_NO_CONTRACT;
+
+ return SBuffer::IsAllocated();
+}
+
+//----------------------------------------------------------------------------
+// Return true after we call OpenBuffer(), but before we close it.
+// All SString operations are illegal while the buffer is open.
+//----------------------------------------------------------------------------
+#if _DEBUG
+inline BOOL SString::IsBufferOpen() const
+{
+ WRAPPER_NO_CONTRACT;
+
+ return SBuffer::IsOpened();
+}
+#endif
+
+//----------------------------------------------------------------------------
+// Return true if we've scanned the string to see if it is in the ASCII subset.
+//----------------------------------------------------------------------------
+inline BOOL SString::IsASCIIScanned() const
+{
+ WRAPPER_NO_CONTRACT;
+ SUPPORTS_DAC;
+
+ return SBuffer::IsFlag1();
+}
+
+//----------------------------------------------------------------------------
+// Set that we've scanned the string to see if it is in the ASCII subset.
+//----------------------------------------------------------------------------
+inline void SString::SetASCIIScanned() const
+{
+ WRAPPER_NO_CONTRACT;
+ SUPPORTS_DAC_HOST_ONLY;
+
+ const_cast<SString *>(this)->SBuffer::SetFlag1();
+}
+
+//----------------------------------------------------------------------------
+// Return true if we've normalized the string to unicode
+//----------------------------------------------------------------------------
+inline BOOL SString::IsNormalized() const
+{
+ WRAPPER_NO_CONTRACT;
+ SUPPORTS_DAC;
+
+ return SBuffer::IsFlag3();
+}
+
+//----------------------------------------------------------------------------
+// Set that we've normalized the string to unicode
+//----------------------------------------------------------------------------
+inline void SString::SetNormalized() const
+{
+ WRAPPER_NO_CONTRACT;
+
+ const_cast<SString *>(this)->SBuffer::SetFlag3();
+}
+
+//----------------------------------------------------------------------------
+// Clear normalization
+//----------------------------------------------------------------------------
+inline void SString::ClearNormalized() const
+{
+ WRAPPER_NO_CONTRACT;
+ SUPPORTS_DAC_HOST_ONLY;
+
+ const_cast<SString *>(this)->SBuffer::ClearFlag3();
+}
+
+//----------------------------------------------------------------------------
+// Private helper.
+// Check to see if the string representation has single byte size
+//----------------------------------------------------------------------------
+inline BOOL SString::IsSingleByte() const
+{
+ STATIC_CONTRACT_NOTHROW;
+ STATIC_CONTRACT_GC_NOTRIGGER;
+
+ return ((GetRepresentation()&REPRESENTATION_SINGLE_MASK) != 0);
+}
+
+//----------------------------------------------------------------------------
+// Private helper.
+// Check to see if the string representation has fixed size characters
+//----------------------------------------------------------------------------
+inline BOOL SString::IsFixedSize() const
+{
+ STATIC_CONTRACT_NOTHROW;
+ STATIC_CONTRACT_GC_NOTRIGGER;
+ STATIC_CONTRACT_SUPPORTS_DAC;
+
+ if (GetRepresentation()&REPRESENTATION_VARIABLE_MASK)
+ return ((GetRepresentation() == REPRESENTATION_ANSI) && !s_IsANSIMultibyte);
+ else
+ return TRUE;
+}
+
+//----------------------------------------------------------------------------
+// Private helper.
+// Check to see if the string representation is appropriate for iteration
+//----------------------------------------------------------------------------
+inline BOOL SString::IsIteratable() const
+{
+ STATIC_CONTRACT_NOTHROW;
+ STATIC_CONTRACT_GC_NOTRIGGER;
+ STATIC_CONTRACT_SUPPORTS_DAC;
+
+ // Note that in many cases ANSI may be fixed width. However we
+ // currently still do not allow iterating on them, because we would have to
+ // do character-by-character conversion on a character dereference (which must
+ // go to unicode) . We may want to adjust this going forward to
+ // depending on perf in the non-ASCII but fixed width ANSI case.
+
+ return ((GetRepresentation()&REPRESENTATION_VARIABLE_MASK) == 0);
+}
+
+//----------------------------------------------------------------------------
+// Private helper
+// Return the size of the given string in bytes
+// in the given representation.
+// count does not include the null-terminator, but the RETURN value does.
+//----------------------------------------------------------------------------
+inline COUNT_T SString::CountToSize(COUNT_T count) const
+{
+ SS_CONTRACT(COUNT_T)
+ {
+ GC_NOTRIGGER;
+ PRECONDITION(CheckCount(count));
+ SS_POSTCONDITION(SizeToCount(RETVAL) == count);
+ NOTHROW;
+ SUPPORTS_DAC;
+ }
+ SS_CONTRACT_END;
+
+ SS_RETURN (count+1) << GetCharacterSizeShift();
+}
+
+//----------------------------------------------------------------------------
+// Private helper.
+// Return the maxmimum count of characters that could fit in a buffer of
+// 'size' bytes in the given representation.
+// 'size' includes the null terminator, but the RETURN value does not.
+//----------------------------------------------------------------------------
+inline COUNT_T SString::SizeToCount(COUNT_T size) const
+{
+ SS_CONTRACT(COUNT_T)
+ {
+ GC_NOTRIGGER;
+ PRECONDITION(CheckSize(size));
+ SS_POSTCONDITION(CountToSize(RETVAL) == size);
+ NOTHROW;
+ SO_TOLERANT;
+ SUPPORTS_DAC;
+ }
+ SS_CONTRACT_END;
+
+ SS_RETURN (size >> GetCharacterSizeShift()) - 1;
+}
+
+//----------------------------------------------------------------------------
+// Private helper.
+// Return the maxmimum count of characters that could fit in the current
+// buffer including NULL terminator.
+//----------------------------------------------------------------------------
+inline COUNT_T SString::GetBufferSizeInCharIncludeNullChar() const
+{
+ STATIC_CONTRACT_GC_NOTRIGGER;
+ STATIC_CONTRACT_NOTHROW;
+ STATIC_CONTRACT_SO_TOLERANT;
+ STATIC_CONTRACT_SUPPORTS_DAC;
+
+ return (GetSize() >> GetCharacterSizeShift());
+}
+
+
+
+//----------------------------------------------------------------------------
+// Assert helper
+// Asser that the iterator is within the given string.
+//----------------------------------------------------------------------------
+inline CHECK SString::CheckIteratorRange(const CIterator &i) const
+{
+ CANNOT_HAVE_CONTRACT;
+ CHECK(i >= Begin());
+ CHECK(i <= End()); // Note that it's OK to look at the terminating null
+ CHECK_OK;
+}
+
+//----------------------------------------------------------------------------
+// Assert helper
+// Asser that the iterator is within the given string.
+//----------------------------------------------------------------------------
+inline CHECK SString::CheckIteratorRange(const CIterator &i, COUNT_T length) const
+{
+ CANNOT_HAVE_CONTRACT;
+ CHECK(i >= Begin());
+ CHECK(i + length <= End()); // Note that it's OK to look at the terminating null
+ CHECK_OK;
+}
+
+//----------------------------------------------------------------------------
+// Assert that the string is empty
+//----------------------------------------------------------------------------
+inline CHECK SString::CheckEmpty() const
+{
+ CANNOT_HAVE_CONTRACT;
+ CHECK(IsEmpty());
+ CHECK_OK;
+}
+
+//----------------------------------------------------------------------------
+// Check the range of a count
+//----------------------------------------------------------------------------
+inline CHECK SString::CheckCount(COUNT_T count)
+{
+ CANNOT_HAVE_CONTRACT;
+ CHECK(CheckSize(count*sizeof(WCHAR)));
+ CHECK_OK;
+}
+
+//----------------------------------------------------------------------------
+// Check the representation field
+//----------------------------------------------------------------------------
+inline CHECK SString::CheckRepresentation(int representation)
+{
+ CANNOT_HAVE_CONTRACT;
+#ifdef SSTRING_CONSOLECODEPAGE
+ CHECK(representation == REPRESENTATION_EMPTY
+ || representation == REPRESENTATION_UNICODE
+ || representation == REPRESENTATION_ASCII
+ || representation == REPRESENTATION_UTF8
+ || representation == REPRESENTATION_ANSI
+ || representation == REPRESENTATION_CONSOLE);
+#else
+ CHECK(representation == REPRESENTATION_EMPTY
+ || representation == REPRESENTATION_UNICODE
+ || representation == REPRESENTATION_ASCII
+ || representation == REPRESENTATION_UTF8
+ || representation == REPRESENTATION_ANSI);
+#endif
+ CHECK((representation & REPRESENTATION_MASK) == representation);
+
+ CHECK_OK;
+}
+
+#if CHECK_INVARIANTS
+//----------------------------------------------------------------------------
+// Assert helper. Check that the string only uses the ASCII subset of
+// codes.
+//----------------------------------------------------------------------------
+inline CHECK SString::CheckASCIIString(const CHAR *string)
+{
+ CANNOT_HAVE_CONTRACT;
+ if (string != NULL)
+ CHECK(CheckASCIIString(string, (int) strlen(string)));
+ CHECK_OK;
+}
+
+inline CHECK SString::CheckASCIIString(const CHAR *string, COUNT_T count)
+{
+ CANNOT_HAVE_CONTRACT;
+#if _DEBUG
+ const CHAR *sEnd = string + count;
+ while (string < sEnd)
+ {
+ CHECK_MSG((*string & 0x80) == 0x00, "Found non-ASCII character in string.");
+ string++;
+ }
+#endif
+ CHECK_OK;
+}
+
+//----------------------------------------------------------------------------
+// Check routine and invariants.
+//----------------------------------------------------------------------------
+
+inline CHECK SString::Check() const
+{
+ CANNOT_HAVE_CONTRACT;
+ CHECK(SBuffer::Check());
+ CHECK_OK;
+}
+
+inline CHECK SString::Invariant() const
+{
+ CANNOT_HAVE_CONTRACT;
+ CHECK(SBuffer::Invariant());
+ CHECK_OK;
+}
+
+inline CHECK SString::InternalInvariant() const
+{
+ CANNOT_HAVE_CONTRACT;
+ CHECK(SBuffer::InternalInvariant());
+ CHECK(SBuffer::GetSize() >= 2);
+ if (IsNormalized())
+ CHECK(IsRepresentation(REPRESENTATION_UNICODE));
+ CHECK_OK;
+}
+#endif // CHECK_INVARIANTS
+
+//----------------------------------------------------------------------------
+// Return a writeable buffer that can store 'countChars'+1 unicode characters.
+// Call CloseBuffer when done.
+//----------------------------------------------------------------------------
+inline WCHAR *SString::OpenUnicodeBuffer(COUNT_T countChars)
+{
+ SS_CONTRACT(WCHAR*)
+ {
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(this));
+ PRECONDITION(CheckCount(countChars));
+#if _DEBUG
+ SS_POSTCONDITION(IsBufferOpen());
+#endif
+ SS_POSTCONDITION(GetRawCount() == countChars);
+ SS_POSTCONDITION(GetRepresentation() == REPRESENTATION_UNICODE || countChars == 0);
+ SS_POSTCONDITION(CheckPointer(RETVAL));
+ THROWS;
+ }
+ SS_CONTRACT_END;
+
+ OpenBuffer(REPRESENTATION_UNICODE, countChars);
+ SS_RETURN GetRawUnicode();
+}
+
+//----------------------------------------------------------------------------
+// Return a copy of the underlying buffer, the caller is responsible for managing
+// the returned memory
+//----------------------------------------------------------------------------
+inline WCHAR *SString::GetCopyOfUnicodeString()
+{
+ SS_CONTRACT(WCHAR*)
+ {
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(this));
+ SS_POSTCONDITION(CheckPointer(buffer));
+ THROWS;
+ }
+ SS_CONTRACT_END;
+ NewArrayHolder<WCHAR> buffer = NULL;
+
+ buffer = new WCHAR[GetCount() +1];
+ wcscpy_s(buffer, GetCount() + 1, GetUnicode());
+
+ SS_RETURN buffer.Extract();
+}
+
+//----------------------------------------------------------------------------
+// Return a writeable buffer that can store 'countChars'+1 ansi characters.
+// Call CloseBuffer when done.
+//----------------------------------------------------------------------------
+inline ANSI *SString::OpenANSIBuffer(COUNT_T countChars)
+{
+ SS_CONTRACT(ANSI*)
+ {
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(this));
+ PRECONDITION(CheckCount(countChars));
+#if _DEBUG
+ SS_POSTCONDITION(IsBufferOpen());
+#endif
+ SS_POSTCONDITION(GetRawCount() == countChars);
+ SS_POSTCONDITION(GetRepresentation() == REPRESENTATION_ANSI || countChars == 0);
+ SS_POSTCONDITION(CheckPointer(RETVAL));
+ THROWS;
+ }
+ SS_CONTRACT_END;
+
+ OpenBuffer(REPRESENTATION_ANSI, countChars);
+ SS_RETURN GetRawANSI();
+}
+
+//----------------------------------------------------------------------------
+// Return a writeable buffer that can store 'countChars'+1 ansi characters.
+// Call CloseBuffer when done.
+//----------------------------------------------------------------------------
+inline UTF8 *SString::OpenUTF8Buffer(COUNT_T countBytes)
+{
+ SS_CONTRACT(UTF8*)
+ {
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(this));
+ PRECONDITION(CheckCount(countBytes));
+#if _DEBUG
+ SS_POSTCONDITION(IsBufferOpen());
+#endif
+ SS_POSTCONDITION(GetRawCount() == countBytes);
+ SS_POSTCONDITION(GetRepresentation() == REPRESENTATION_UTF8 || countBytes == 0);
+ SS_POSTCONDITION(CheckPointer(RETVAL));
+ THROWS;
+ }
+ SS_CONTRACT_END;
+
+ OpenBuffer(REPRESENTATION_UTF8, countBytes);
+ SS_RETURN GetRawUTF8();
+}
+
+//----------------------------------------------------------------------------
+// Private helper to open a raw buffer.
+// Called by public functions to open the buffer in the specific
+// representation.
+// While the buffer is opened, all other operations are illegal. Call
+// CloseBuffer() when done.
+//----------------------------------------------------------------------------
+inline void SString::OpenBuffer(SString::Representation representation, COUNT_T countChars)
+{
+#ifdef SSTRING_EXTRA_CHECKS
+ CONTRACT_VOID
+ {
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(this));
+ PRECONDITION_MSG(!IsBufferOpen(), "Can't nest calls to OpenBuffer()");
+ PRECONDITION(CheckRepresentation(representation));
+ PRECONDITION(CheckSize(countChars));
+#if _DEBUG
+ POSTCONDITION(IsBufferOpen());
+#endif
+ POSTCONDITION(GetRawCount() == countChars);
+ POSTCONDITION(GetRepresentation() == representation || countChars == 0);
+ THROWS;
+ }
+ CONTRACT_END;
+#else
+ STATIC_CONTRACT_GC_NOTRIGGER;
+ STATIC_CONTRACT_THROWS;
+#endif
+
+ Resize(countChars, representation);
+
+ SBuffer::OpenRawBuffer(CountToSize(countChars));
+
+ SS_RETURN;
+}
+
+//----------------------------------------------------------------------------
+// Get the max size that can be passed to OpenUnicodeBuffer without causing
+// allocations.
+//----------------------------------------------------------------------------
+inline COUNT_T SString::GetUnicodeAllocation()
+{
+ CONTRACTL
+ {
+ INSTANCE_CHECK;
+ NOTHROW;
+ GC_NOTRIGGER;
+ }
+ CONTRACTL_END;
+
+ COUNT_T allocation = GetAllocation();
+ return ( (allocation > sizeof(WCHAR))
+ ? (allocation - sizeof(WCHAR)) / sizeof(WCHAR) : 0 );
+}
+
+//----------------------------------------------------------------------------
+// Close an open buffer. Assumes that we wrote exactly number of characters
+// we requested in OpenBuffer.
+//----------------------------------------------------------------------------
+inline void SString::CloseBuffer()
+{
+ SS_CONTRACT_VOID
+ {
+ GC_NOTRIGGER;
+#if _DEBUG
+ PRECONDITION_MSG(IsBufferOpen(), "Can only CloseBuffer() after a call to OpenBuffer()");
+#endif
+ SS_POSTCONDITION(CheckPointer(this));
+ THROWS;
+ }
+ SS_CONTRACT_END;
+
+ SBuffer::CloseRawBuffer();
+ NullTerminate();
+
+ SS_RETURN;
+}
+
+//----------------------------------------------------------------------------
+// CloseBuffer() tells the SString that we're done using the unsafe buffer.
+// countChars is the count of characters actually used (so we can set m_count).
+// This is important if we request a buffer larger than what we actually
+// used.
+//----------------------------------------------------------------------------
+inline void SString::CloseBuffer(COUNT_T finalCount)
+{
+ SS_CONTRACT_VOID
+ {
+ GC_NOTRIGGER;
+#if _DEBUG
+ PRECONDITION_MSG(IsBufferOpen(), "Can only CloseBuffer() after a call to OpenBuffer()");
+#endif
+ PRECONDITION(CheckSize(finalCount));
+ SS_POSTCONDITION(CheckPointer(this));
+ SS_POSTCONDITION(GetRawCount() == finalCount);
+ THROWS;
+ }
+ SS_CONTRACT_END;
+
+ SBuffer::CloseRawBuffer(CountToSize(finalCount));
+ NullTerminate();
+
+ SS_RETURN;
+}
+
+//----------------------------------------------------------------------------
+// EnsureWritable
+// Ensures that the buffer is writable
+//----------------------------------------------------------------------------
+inline void SString::EnsureWritable() const
+{
+#ifdef SSTRING_EXTRA_CHECKS
+ CONTRACT_VOID
+ {
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(this));
+ POSTCONDITION(!IsLiteral());
+ THROWS;
+ }
+ CONTRACT_END;
+#else //SSTRING_EXTRA_CHECKS
+ STATIC_CONTRACT_GC_NOTRIGGER;
+ STATIC_CONTRACT_THROWS;
+#endif //SSTRING_EXTRA_CHECKS
+
+ if (IsLiteral())
+ const_cast<SString *>(this)->Resize(GetRawCount(), GetRepresentation(), PRESERVE);
+
+ SS_RETURN;
+}
+
+//-----------------------------------------------------------------------------
+// Convert the internal representation to be a fixed size
+//-----------------------------------------------------------------------------
+inline void SString::ConvertToFixed() const
+{
+ SS_CONTRACT_VOID
+ {
+ GC_NOTRIGGER;
+ SS_PRECONDITION(CheckPointer(this));
+ SS_POSTCONDITION(IsFixedSize());
+ THROWS_UNLESS_NORMALIZED;
+ SUPPORTS_DAC;
+ }
+ SS_CONTRACT_END;
+
+ // If we're already fixed size, great.
+ if (IsFixedSize())
+ SS_RETURN;
+
+ // See if we can coerce it to ASCII.
+ if (ScanASCII())
+ SS_RETURN;
+
+ // Convert to unicode then.
+ ConvertToUnicode();
+
+ SS_RETURN;
+}
+
+//-----------------------------------------------------------------------------
+// Convert the internal representation to be an iteratable one (current
+// requirements here are that it be trivially convertable to unicode chars.)
+//-----------------------------------------------------------------------------
+inline void SString::ConvertToIteratable() const
+{
+ SS_CONTRACT_VOID
+ {
+ GC_NOTRIGGER;
+ SS_PRECONDITION(CheckPointer(this));
+ SS_POSTCONDITION(IsIteratable());
+ THROWS_UNLESS_NORMALIZED;
+ SUPPORTS_DAC;
+ }
+ SS_CONTRACT_END;
+
+ // If we're already iteratable, great.
+ if (IsIteratable())
+ SS_RETURN;
+
+ // See if we can coerce it to ASCII.
+ if (ScanASCII())
+ SS_RETURN;
+
+ // Convert to unicode then.
+ ConvertToUnicode();
+
+ SS_RETURN;
+}
+
+//-----------------------------------------------------------------------------
+// Create iterators on the string.
+//-----------------------------------------------------------------------------
+
+inline SString::UIterator SString::BeginUnicode()
+{
+ SS_CONTRACT(SString::UIterator)
+ {
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(this));
+ SS_POSTCONDITION(CheckValue(RETVAL));
+ THROWS;
+ }
+ SS_CONTRACT_END;
+
+ ConvertToUnicode();
+ EnsureWritable();
+
+ SS_RETURN UIterator(this, 0);
+}
+
+inline SString::UIterator SString::EndUnicode()
+{
+ SS_CONTRACT(SString::UIterator)
+ {
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(this));
+ SS_POSTCONDITION(CheckValue(RETVAL));
+ THROWS;
+ }
+ SS_CONTRACT_END;
+
+ ConvertToUnicode();
+ EnsureWritable();
+
+ SS_RETURN UIterator(this, GetCount());
+}
+
+//-----------------------------------------------------------------------------
+// Create CIterators on the string.
+//-----------------------------------------------------------------------------
+
+FORCEINLINE SString::CIterator SString::Begin() const
+{
+ SS_CONTRACT(SString::CIterator)
+ {
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(this));
+ SS_POSTCONDITION(CheckValue(RETVAL));
+ THROWS_UNLESS_NORMALIZED;
+ }
+ SS_CONTRACT_END;
+
+ ConvertToIteratable();
+
+ SS_RETURN CIterator(this, 0);
+}
+
+FORCEINLINE SString::CIterator SString::End() const
+{
+ SS_CONTRACT(SString::CIterator)
+ {
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(this));
+ SS_POSTCONDITION(CheckValue(RETVAL));
+ THROWS_UNLESS_NORMALIZED;
+ }
+ SS_CONTRACT_END;
+
+ ConvertToIteratable();
+
+ SS_RETURN CIterator(this, GetCount());
+}
+
+//-----------------------------------------------------------------------------
+// Create Iterators on the string.
+//-----------------------------------------------------------------------------
+
+FORCEINLINE SString::Iterator SString::Begin()
+{
+ SS_CONTRACT(SString::Iterator)
+ {
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(this));
+ SS_POSTCONDITION(CheckValue(RETVAL));
+ THROWS; // EnsureMutable always throws
+ SUPPORTS_DAC;
+ }
+ SS_CONTRACT_END;
+
+ ConvertToIteratable();
+ EnsureMutable();
+
+ SS_RETURN Iterator(this, 0);
+}
+
+FORCEINLINE SString::Iterator SString::End()
+{
+ SS_CONTRACT(SString::Iterator)
+ {
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(this));
+ SS_POSTCONDITION(CheckValue(RETVAL));
+ THROWS; // EnsureMutable always Throws
+ SUPPORTS_DAC;
+ }
+ SS_CONTRACT_END;
+
+ ConvertToIteratable();
+ EnsureMutable();
+
+ SS_RETURN Iterator(this, GetCount());
+}
+
+//-----------------------------------------------------------------------------
+// CIterator support routines
+//-----------------------------------------------------------------------------
+
+inline SString::Index::Index()
+{
+ LIMITED_METHOD_CONTRACT;
+}
+
+inline SString::Index::Index(SString *string, SCOUNT_T index)
+ : SBuffer::Index(string, index<<string->GetCharacterSizeShift())
+{
+ SS_CONTRACT_VOID
+ {
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(string));
+ PRECONDITION(string->IsIteratable());
+ PRECONDITION(DoCheck(0));
+ SS_POSTCONDITION(CheckPointer(this));
+ // POSTCONDITION(Subtract(string->Begin()) == index); contract violation - fix later
+ NOTHROW;
+ CANNOT_TAKE_LOCK;
+ SUPPORTS_DAC;
+ }
+ SS_CONTRACT_END;
+
+ m_characterSizeShift = string->GetCharacterSizeShift();
+
+ SS_RETURN;
+}
+
+inline BYTE &SString::Index::GetAt(SCOUNT_T delta) const
+{
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ return m_ptr[delta<<m_characterSizeShift];
+}
+
+inline void SString::Index::Skip(SCOUNT_T delta)
+{
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ m_ptr += (delta<<m_characterSizeShift);
+}
+
+inline SCOUNT_T SString::Index::Subtract(const Index &i) const
+{
+ LIMITED_METHOD_DAC_CONTRACT;
+
+ return (SCOUNT_T) ((m_ptr - i.m_ptr)>>m_characterSizeShift);
+}
+
+inline CHECK SString::Index::DoCheck(SCOUNT_T delta) const
+{
+ CANNOT_HAVE_CONTRACT;
+#if _DEBUG
+ const SString *string = (const SString *) GetContainerDebug();
+
+ CHECK(m_ptr + (delta<<m_characterSizeShift) >= string->m_buffer);
+ CHECK(m_ptr + (delta<<m_characterSizeShift) < string->m_buffer + string->GetSize());
+#endif
+ CHECK_OK;
+}
+
+inline void SString::Index::Resync(const SString *string, BYTE *ptr) const
+{
+ WRAPPER_NO_CONTRACT;
+ SUPPORTS_DAC;
+
+ SBuffer::Index::Resync(string, ptr);
+
+ const_cast<SString::Index*>(this)->m_characterSizeShift = string->GetCharacterSizeShift();
+}
+
+
+inline const WCHAR *SString::Index::GetUnicode() const
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return (const WCHAR *) m_ptr;
+}
+
+inline const CHAR *SString::Index::GetASCII() const
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return (const CHAR *) m_ptr;
+}
+
+inline WCHAR SString::Index::operator*() const
+{
+ WRAPPER_NO_CONTRACT;
+ SUPPORTS_DAC;
+
+ if (m_characterSizeShift == 0)
+ return *(CHAR*)&GetAt(0);
+ else
+ return *(WCHAR*)&GetAt(0);
+}
+
+inline void SString::Index::operator->() const
+{
+ LIMITED_METHOD_CONTRACT;
+}
+
+inline WCHAR SString::Index::operator[](int index) const
+{
+ WRAPPER_NO_CONTRACT;
+
+ if (m_characterSizeShift == 0)
+ return *(CHAR*)&GetAt(index);
+ else
+ return *(WCHAR*)&GetAt(index);
+}
+
+//-----------------------------------------------------------------------------
+// Iterator support routines
+//-----------------------------------------------------------------------------
+
+inline SString::UIndex::UIndex()
+{
+ LIMITED_METHOD_CONTRACT;
+}
+
+inline SString::UIndex::UIndex(SString *string, SCOUNT_T index)
+ : SBuffer::Index(string, index*sizeof(WCHAR))
+{
+ SS_CONTRACT_VOID
+ {
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(string));
+ PRECONDITION(string->IsRepresentation(REPRESENTATION_UNICODE));
+ PRECONDITION(DoCheck(0));
+ SS_POSTCONDITION(CheckPointer(this));
+ NOTHROW;
+ CANNOT_TAKE_LOCK;
+ }
+ SS_CONTRACT_END;
+
+ SS_RETURN;
+}
+
+inline WCHAR &SString::UIndex::GetAt(SCOUNT_T delta) const
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return ((WCHAR*)m_ptr)[delta];
+}
+
+inline void SString::UIndex::Skip(SCOUNT_T delta)
+{
+ LIMITED_METHOD_CONTRACT;
+
+ m_ptr += delta * sizeof(WCHAR);
+}
+
+inline SCOUNT_T SString::UIndex::Subtract(const UIndex &i) const
+{
+ WRAPPER_NO_CONTRACT;
+
+ return (SCOUNT_T) (GetUnicode() - i.GetUnicode());
+}
+
+inline CHECK SString::UIndex::DoCheck(SCOUNT_T delta) const
+{
+ CANNOT_HAVE_CONTRACT;
+#if _DEBUG
+ const SString *string = (const SString *) GetContainerDebug();
+
+ CHECK(GetUnicode() + delta >= string->GetRawUnicode());
+ CHECK(GetUnicode() + delta <= string->GetRawUnicode() + string->GetCount());
+#endif
+
+ CHECK_OK;
+}
+
+inline WCHAR *SString::UIndex::GetUnicode() const
+{
+ LIMITED_METHOD_CONTRACT;
+
+ return (WCHAR*) m_ptr;
+}
+
+//-----------------------------------------------------------------------------
+// Opaque scratch buffer class routines
+//-----------------------------------------------------------------------------
+inline SString::AbstractScratchBuffer::AbstractScratchBuffer(void *buffer, COUNT_T size)
+ : SString(buffer, size)
+{
+ SS_CONTRACT_VOID
+ {
+ GC_NOTRIGGER;
+ PRECONDITION(CheckPointer(buffer));
+ PRECONDITION(CheckCount(size));
+ NOTHROW;
+ }
+ SS_CONTRACT_END;
+
+ SS_RETURN;
+}
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif // _MSC_VER
+
+#endif // _SSTRING_INL_