2015-08-26 07:17:56 -04:00
|
|
|
//
|
|
|
|
// System.String.cs
|
|
|
|
//
|
|
|
|
// Authors:
|
|
|
|
// Patrik Torstensson
|
|
|
|
// Jeffrey Stedfast (fejj@ximian.com)
|
|
|
|
// Dan Lewis (dihlewis@yahoo.co.uk)
|
|
|
|
// Sebastien Pouliot <sebastien@ximian.com>
|
|
|
|
// Marek Safar (marek.safar@seznam.cz)
|
|
|
|
// Andreas Nahr (Classdevelopment@A-SoftTech.com)
|
|
|
|
//
|
|
|
|
// (C) 2001 Ximian, Inc. http://www.ximian.com
|
|
|
|
// Copyright (C) 2004-2005 Novell (http://www.novell.com)
|
|
|
|
// Copyright (c) 2012 Xamarin, Inc (http://www.xamarin.com)
|
|
|
|
//
|
|
|
|
// Permission is hereby granted, free of charge, to any person obtaining
|
|
|
|
// a copy of this software and associated documentation files (the
|
|
|
|
// "Software"), to deal in the Software without restriction, including
|
|
|
|
// without limitation the rights to use, copy, modify, merge, publish,
|
|
|
|
// distribute, sublicense, and/or sell copies of the Software, and to
|
|
|
|
// permit persons to whom the Software is furnished to do so, subject to
|
|
|
|
// the following conditions:
|
|
|
|
//
|
|
|
|
// The above copyright notice and this permission notice shall be
|
|
|
|
// included in all copies or substantial portions of the Software.
|
|
|
|
//
|
|
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
|
|
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
|
|
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
|
|
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
|
|
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
|
|
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
//
|
|
|
|
//
|
|
|
|
|
2018-08-07 15:19:03 +00:00
|
|
|
#if BIT64
|
|
|
|
using nuint = System.UInt64;
|
|
|
|
#else
|
|
|
|
using nuint = System.UInt32;
|
|
|
|
#endif
|
|
|
|
|
2015-08-26 07:17:56 -04:00
|
|
|
using System.Runtime.CompilerServices;
|
|
|
|
using System.Text;
|
2018-05-10 08:37:03 +00:00
|
|
|
using System.Globalization;
|
|
|
|
using System.Collections;
|
|
|
|
using System.Collections.Generic;
|
2018-08-07 15:19:03 +00:00
|
|
|
using System.Runtime.InteropServices;
|
2018-10-09 08:20:59 +00:00
|
|
|
using System.Diagnostics;
|
2015-08-26 07:17:56 -04:00
|
|
|
|
|
|
|
namespace System
|
|
|
|
{
|
|
|
|
partial class String
|
|
|
|
{
|
2018-05-10 08:37:03 +00:00
|
|
|
[NonSerialized]
|
|
|
|
int _stringLength;
|
|
|
|
[NonSerialized]
|
|
|
|
char _firstChar;
|
2018-01-29 19:03:06 +00:00
|
|
|
|
2018-05-10 08:37:03 +00:00
|
|
|
public static readonly String Empty;
|
2015-08-26 07:17:56 -04:00
|
|
|
|
2018-10-09 08:20:59 +00:00
|
|
|
public int Length => _stringLength;
|
|
|
|
|
2015-08-26 07:17:56 -04:00
|
|
|
internal unsafe int IndexOfUnchecked (string value, int startIndex, int count)
|
|
|
|
{
|
|
|
|
int valueLen = value.Length;
|
|
|
|
if (count < valueLen)
|
|
|
|
return -1;
|
|
|
|
|
2018-05-10 08:37:03 +00:00
|
|
|
if (valueLen == 0)
|
2015-08-26 07:17:56 -04:00
|
|
|
return startIndex;
|
|
|
|
|
2018-05-10 08:37:03 +00:00
|
|
|
fixed (char* thisptr = &_firstChar, valueptr = value) {
|
2015-08-26 07:17:56 -04:00
|
|
|
char* ap = thisptr + startIndex;
|
|
|
|
char* thisEnd = ap + count - valueLen + 1;
|
|
|
|
while (ap != thisEnd) {
|
|
|
|
if (*ap == *valueptr) {
|
|
|
|
for (int i = 1; i < valueLen; i++) {
|
|
|
|
if (ap[i] != valueptr[i])
|
|
|
|
goto NextVal;
|
|
|
|
}
|
|
|
|
return (int)(ap - thisptr);
|
|
|
|
}
|
|
|
|
NextVal:
|
|
|
|
ap++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2018-09-05 08:26:42 +00:00
|
|
|
[CLSCompliant(false)]
|
|
|
|
public static String Concat(Object arg0, Object arg1, Object arg2, Object arg3, __arglist)
|
|
|
|
{
|
|
|
|
// Added to maintain backward compatibility, see https://github.com/mono/mono/issues/9996
|
|
|
|
throw new PlatformNotSupportedException();
|
|
|
|
}
|
|
|
|
|
2018-05-10 08:37:03 +00:00
|
|
|
internal unsafe int IndexOfUncheckedIgnoreCase (string value, int startIndex, int count)
|
2015-08-26 07:17:56 -04:00
|
|
|
{
|
2018-05-10 08:37:03 +00:00
|
|
|
int valueLen = value.Length;
|
|
|
|
if (count < valueLen)
|
2015-08-26 07:17:56 -04:00
|
|
|
return -1;
|
|
|
|
|
2018-05-10 08:37:03 +00:00
|
|
|
if (valueLen == 0)
|
|
|
|
return startIndex;
|
2015-08-26 07:17:56 -04:00
|
|
|
|
2018-05-10 08:37:03 +00:00
|
|
|
var ti = CultureInfo.InvariantCulture.TextInfo;
|
2015-08-26 07:17:56 -04:00
|
|
|
|
2018-05-10 08:37:03 +00:00
|
|
|
fixed (char* thisptr = &_firstChar, valueptr = value) {
|
|
|
|
char* ap = thisptr + startIndex;
|
|
|
|
char* thisEnd = ap + count - valueLen + 1;
|
|
|
|
char valueUpper = ti.ToUpper (*valueptr);
|
|
|
|
while (ap != thisEnd) {
|
|
|
|
if (ti.ToUpper (*ap) == valueUpper) {
|
|
|
|
for (int i = 1; i < valueLen; i++) {
|
|
|
|
if (ti.ToUpper (ap[i]) != ti.ToUpper (valueptr [i]))
|
|
|
|
goto NextVal;
|
2015-08-26 07:17:56 -04:00
|
|
|
}
|
2018-05-10 08:37:03 +00:00
|
|
|
return (int)(ap - thisptr);
|
2015-08-26 07:17:56 -04:00
|
|
|
}
|
2018-05-10 08:37:03 +00:00
|
|
|
NextVal:
|
|
|
|
ap++;
|
2015-08-26 07:17:56 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2018-05-10 08:37:03 +00:00
|
|
|
internal unsafe int LastIndexOfUnchecked (string value, int startIndex, int count)
|
2015-08-26 07:17:56 -04:00
|
|
|
{
|
2018-05-10 08:37:03 +00:00
|
|
|
int valueLen = value.Length;
|
|
|
|
if (count < valueLen)
|
2015-08-26 07:17:56 -04:00
|
|
|
return -1;
|
|
|
|
|
2018-05-10 08:37:03 +00:00
|
|
|
if (valueLen == 0)
|
|
|
|
return startIndex;
|
2015-08-26 07:17:56 -04:00
|
|
|
|
2018-05-10 08:37:03 +00:00
|
|
|
fixed (char* thisptr = &_firstChar, valueptr = value) {
|
|
|
|
char* ap = thisptr + startIndex;
|
2015-08-26 07:17:56 -04:00
|
|
|
|
2018-05-10 08:37:03 +00:00
|
|
|
char* thisEnd = ap - count + valueLen - 1;
|
|
|
|
char* valueEnd = valueptr + valueLen - 1;
|
2015-08-26 07:17:56 -04:00
|
|
|
|
2018-05-10 08:37:03 +00:00
|
|
|
while (ap != thisEnd) {
|
|
|
|
if (*ap == *valueEnd) {
|
|
|
|
char* apEnd = ap;
|
|
|
|
while (valueptr != valueEnd) {
|
|
|
|
valueEnd--;
|
|
|
|
ap--;
|
|
|
|
if (*ap != *valueEnd) {
|
|
|
|
valueEnd = valueptr + valueLen - 1;
|
|
|
|
ap = apEnd;
|
|
|
|
goto NextVal;
|
|
|
|
}
|
|
|
|
}
|
2015-08-26 07:17:56 -04:00
|
|
|
|
2018-05-10 08:37:03 +00:00
|
|
|
return (int)(ap - thisptr);
|
2015-08-26 07:17:56 -04:00
|
|
|
}
|
2018-05-10 08:37:03 +00:00
|
|
|
NextVal:
|
|
|
|
ap--;
|
2015-08-26 07:17:56 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-10 08:37:03 +00:00
|
|
|
return -1;
|
2015-08-26 07:17:56 -04:00
|
|
|
}
|
|
|
|
|
2018-05-10 08:37:03 +00:00
|
|
|
internal unsafe int LastIndexOfUncheckedIgnoreCase (string value, int startIndex, int count)
|
2015-08-26 07:17:56 -04:00
|
|
|
{
|
2018-05-10 08:37:03 +00:00
|
|
|
int valueLen = value.Length;
|
|
|
|
if (count < valueLen)
|
|
|
|
return -1;
|
2015-08-26 07:17:56 -04:00
|
|
|
|
2018-05-10 08:37:03 +00:00
|
|
|
if (valueLen == 0)
|
|
|
|
return startIndex;
|
2015-08-26 07:17:56 -04:00
|
|
|
|
2018-05-10 08:37:03 +00:00
|
|
|
var ti = CultureInfo.InvariantCulture.TextInfo;
|
2015-08-26 07:17:56 -04:00
|
|
|
|
2018-05-10 08:37:03 +00:00
|
|
|
fixed (char* thisptr = &_firstChar, valueptr = value) {
|
|
|
|
char* ap = thisptr + startIndex;
|
2015-08-26 07:17:56 -04:00
|
|
|
|
2018-05-10 08:37:03 +00:00
|
|
|
char* thisEnd = ap - count + valueLen - 1;
|
|
|
|
char* valueEnd = valueptr + valueLen - 1;
|
2015-08-26 07:17:56 -04:00
|
|
|
|
2018-05-10 08:37:03 +00:00
|
|
|
var valueEndUpper = ti.ToUpper (*valueEnd);
|
2015-08-26 07:17:56 -04:00
|
|
|
|
2018-05-10 08:37:03 +00:00
|
|
|
while (ap != thisEnd) {
|
|
|
|
if (ti.ToUpper (*ap) == valueEndUpper) {
|
|
|
|
char* apEnd = ap;
|
|
|
|
while (valueptr != valueEnd) {
|
|
|
|
valueEnd--;
|
|
|
|
ap--;
|
|
|
|
if (ti.ToUpper (*ap) != ti.ToUpper (*valueEnd)) {
|
|
|
|
valueEnd = valueptr + valueLen - 1;
|
|
|
|
ap = apEnd;
|
|
|
|
goto NextVal;
|
|
|
|
}
|
|
|
|
}
|
2015-08-26 07:17:56 -04:00
|
|
|
|
2018-05-10 08:37:03 +00:00
|
|
|
return (int)(ap - thisptr);
|
2015-08-26 07:17:56 -04:00
|
|
|
}
|
2018-05-10 08:37:03 +00:00
|
|
|
NextVal:
|
|
|
|
ap--;
|
2015-08-26 07:17:56 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-10 08:37:03 +00:00
|
|
|
return -1;
|
2015-08-26 07:17:56 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
internal bool StartsWithOrdinalUnchecked (String value)
|
|
|
|
{
|
2018-05-10 08:37:03 +00:00
|
|
|
if (this.Length < value.Length || _firstChar != value._firstChar)
|
|
|
|
return false;
|
2015-08-26 07:17:56 -04:00
|
|
|
|
2018-08-07 15:19:03 +00:00
|
|
|
return value.Length == 1 ?
|
|
|
|
true :
|
|
|
|
SpanHelpers.SequenceEqual (
|
|
|
|
ref Unsafe.As<char, byte> (ref this.GetRawStringData ()),
|
|
|
|
ref Unsafe.As<char, byte> (ref value.GetRawStringData ()),
|
|
|
|
((nuint)value.Length) * 2);
|
2015-08-26 07:17:56 -04:00
|
|
|
}
|
|
|
|
|
2018-05-10 08:37:03 +00:00
|
|
|
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
|
|
|
internal extern static String FastAllocateString (int length);
|
2015-08-26 07:17:56 -04:00
|
|
|
|
|
|
|
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
|
|
|
private extern static string InternalIsInterned (string str);
|
|
|
|
|
|
|
|
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
|
|
|
private extern static string InternalIntern (string str);
|
|
|
|
|
2018-05-10 08:37:03 +00:00
|
|
|
static unsafe int FastCompareStringHelper (uint* strAChars, int countA, uint* strBChars, int countB)
|
|
|
|
{
|
|
|
|
// CoreRT implementation has alignment issues
|
|
|
|
char* ap = (char*) strAChars;
|
|
|
|
char* bp = (char*) strBChars;
|
|
|
|
char* end = ap + Math.Min (countA, countB);
|
|
|
|
while (ap < end) {
|
|
|
|
if (*ap != *bp)
|
|
|
|
return (int)*ap - (int)*bp;
|
|
|
|
ap++;
|
|
|
|
bp++;
|
|
|
|
}
|
|
|
|
return countA - countB;
|
|
|
|
}
|
|
|
|
|
2015-08-26 07:17:56 -04:00
|
|
|
internal static unsafe void CharCopy (char *dest, char *src, int count) {
|
|
|
|
// Same rules as for memcpy, but with the premise that
|
|
|
|
// chars can only be aligned to even addresses if their
|
|
|
|
// enclosing types are correctly aligned
|
|
|
|
if ((((int)(byte*)dest | (int)(byte*)src) & 3) != 0) {
|
|
|
|
if (((int)(byte*)dest & 2) != 0 && ((int)(byte*)src & 2) != 0 && count > 0) {
|
|
|
|
((short*)dest) [0] = ((short*)src) [0];
|
|
|
|
dest++;
|
|
|
|
src++;
|
|
|
|
count--;
|
|
|
|
}
|
|
|
|
if ((((int)(byte*)dest | (int)(byte*)src) & 2) != 0) {
|
|
|
|
Buffer.memcpy2 ((byte*)dest, (byte*)src, count * 2);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Buffer.memcpy4 ((byte*)dest, (byte*)src, count * 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
#region Runtime method-to-ir dependencies
|
|
|
|
|
|
|
|
/* helpers used by the runtime as well as above or eslewhere in corlib */
|
|
|
|
static unsafe void memset (byte *dest, int val, int len)
|
|
|
|
{
|
|
|
|
if (len < 8) {
|
|
|
|
while (len != 0) {
|
|
|
|
*dest = (byte)val;
|
|
|
|
++dest;
|
|
|
|
--len;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (val != 0) {
|
|
|
|
val = val | (val << 8);
|
|
|
|
val = val | (val << 16);
|
|
|
|
}
|
|
|
|
// align to 4
|
|
|
|
int rest = (int)dest & 3;
|
|
|
|
if (rest != 0) {
|
|
|
|
rest = 4 - rest;
|
|
|
|
len -= rest;
|
|
|
|
do {
|
|
|
|
*dest = (byte)val;
|
|
|
|
++dest;
|
|
|
|
--rest;
|
|
|
|
} while (rest != 0);
|
|
|
|
}
|
|
|
|
while (len >= 16) {
|
|
|
|
((int*)dest) [0] = val;
|
|
|
|
((int*)dest) [1] = val;
|
|
|
|
((int*)dest) [2] = val;
|
|
|
|
((int*)dest) [3] = val;
|
|
|
|
dest += 16;
|
|
|
|
len -= 16;
|
|
|
|
}
|
|
|
|
while (len >= 4) {
|
|
|
|
((int*)dest) [0] = val;
|
|
|
|
dest += 4;
|
|
|
|
len -= 4;
|
|
|
|
}
|
|
|
|
// tail bytes
|
|
|
|
while (len > 0) {
|
|
|
|
*dest = (byte)val;
|
|
|
|
dest++;
|
|
|
|
len--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsafe void memcpy (byte *dest, byte *src, int size)
|
|
|
|
{
|
|
|
|
Buffer.Memcpy (dest, src, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Used by the runtime */
|
|
|
|
internal static unsafe void bzero (byte *dest, int len) {
|
|
|
|
memset (dest, 0, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
internal static unsafe void bzero_aligned_1 (byte *dest, int len) {
|
|
|
|
((byte*)dest) [0] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal static unsafe void bzero_aligned_2 (byte *dest, int len) {
|
|
|
|
((short*)dest) [0] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal static unsafe void bzero_aligned_4 (byte *dest, int len) {
|
|
|
|
((int*)dest) [0] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal static unsafe void bzero_aligned_8 (byte *dest, int len) {
|
|
|
|
((long*)dest) [0] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
internal static unsafe void memcpy_aligned_1 (byte *dest, byte *src, int size) {
|
|
|
|
((byte*)dest) [0] = ((byte*)src) [0];
|
|
|
|
}
|
|
|
|
|
|
|
|
internal static unsafe void memcpy_aligned_2 (byte *dest, byte *src, int size) {
|
|
|
|
((short*)dest) [0] = ((short*)src) [0];
|
|
|
|
}
|
|
|
|
|
|
|
|
internal static unsafe void memcpy_aligned_4 (byte *dest, byte *src, int size) {
|
|
|
|
((int*)dest) [0] = ((int*)src) [0];
|
|
|
|
}
|
|
|
|
|
|
|
|
internal static unsafe void memcpy_aligned_8 (byte *dest, byte *src, int size) {
|
|
|
|
((long*)dest) [0] = ((long*)src) [0];
|
|
|
|
}
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
// Certain constructors are redirected to CreateString methods with
|
|
|
|
// matching argument list. The this pointer should not be used.
|
|
|
|
|
2018-05-10 08:37:03 +00:00
|
|
|
unsafe String CreateString (sbyte* value)
|
2015-08-26 07:17:56 -04:00
|
|
|
{
|
2018-05-10 08:37:03 +00:00
|
|
|
return Ctor (value);
|
2015-08-26 07:17:56 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
unsafe String CreateString (sbyte* value, int startIndex, int length)
|
|
|
|
{
|
2018-05-10 08:37:03 +00:00
|
|
|
return Ctor (value, startIndex, length);
|
2015-08-26 07:17:56 -04:00
|
|
|
}
|
|
|
|
|
2018-05-10 08:37:03 +00:00
|
|
|
unsafe string CreateString (char* value)
|
2015-08-26 07:17:56 -04:00
|
|
|
{
|
2018-05-10 08:37:03 +00:00
|
|
|
return Ctor (value);
|
2015-08-26 07:17:56 -04:00
|
|
|
}
|
|
|
|
|
2018-05-10 08:37:03 +00:00
|
|
|
unsafe string CreateString (char* value, int startIndex, int length)
|
2015-08-26 07:17:56 -04:00
|
|
|
{
|
2018-05-10 08:37:03 +00:00
|
|
|
return Ctor (value, startIndex, length);
|
2015-08-26 07:17:56 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
string CreateString (char [] val, int startIndex, int length)
|
|
|
|
{
|
2018-05-10 08:37:03 +00:00
|
|
|
return Ctor (val, startIndex, length);
|
2015-08-26 07:17:56 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
string CreateString (char [] val)
|
|
|
|
{
|
2018-05-10 08:37:03 +00:00
|
|
|
return Ctor (val);
|
2015-08-26 07:17:56 -04:00
|
|
|
}
|
|
|
|
|
2018-05-10 08:37:03 +00:00
|
|
|
string CreateString (char c, int count)
|
2015-08-26 07:17:56 -04:00
|
|
|
{
|
2018-05-10 08:37:03 +00:00
|
|
|
return Ctor (c, count);
|
2015-08-26 07:17:56 -04:00
|
|
|
}
|
|
|
|
|
2018-05-10 08:37:03 +00:00
|
|
|
unsafe String CreateString (sbyte* value, int startIndex, int length, Encoding enc)
|
2015-08-26 07:17:56 -04:00
|
|
|
{
|
2018-05-10 08:37:03 +00:00
|
|
|
return Ctor (value, startIndex, length, enc);
|
2015-08-26 07:17:56 -04:00
|
|
|
}
|
2018-01-29 19:03:06 +00:00
|
|
|
|
2018-05-10 08:37:03 +00:00
|
|
|
String CreateString (ReadOnlySpan<char> value)
|
2018-01-29 19:03:06 +00:00
|
|
|
{
|
2018-05-10 08:37:03 +00:00
|
|
|
return Ctor (value);
|
2018-01-29 19:03:06 +00:00
|
|
|
}
|
2018-04-24 09:31:23 +00:00
|
|
|
|
|
|
|
[IndexerName ("Chars")]
|
|
|
|
public char this [int index] {
|
|
|
|
[IntrinsicAttribute]
|
|
|
|
get {
|
2018-05-10 08:37:03 +00:00
|
|
|
if ((uint)index >= _stringLength)
|
2018-04-24 09:31:23 +00:00
|
|
|
ThrowHelper.ThrowIndexOutOfRangeException ();
|
|
|
|
|
2018-05-10 08:37:03 +00:00
|
|
|
return Unsafe.Add (ref _firstChar, index);
|
2018-04-24 09:31:23 +00:00
|
|
|
}
|
|
|
|
}
|
2018-05-10 08:37:03 +00:00
|
|
|
|
|
|
|
public static String Intern (String str)
|
|
|
|
{
|
|
|
|
if (str == null) {
|
|
|
|
throw new ArgumentNullException ("str");
|
|
|
|
}
|
|
|
|
|
|
|
|
return InternalIntern (str);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String IsInterned (String str)
|
|
|
|
{
|
|
|
|
if (str == null)
|
|
|
|
throw new ArgumentNullException ("str");
|
|
|
|
|
|
|
|
return InternalIsInterned (str);
|
|
|
|
}
|
|
|
|
|
|
|
|
int LegacyStringGetHashCode ()
|
|
|
|
{
|
|
|
|
int hash1 = 5381;
|
|
|
|
int hash2 = hash1;
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
fixed (char *src = this) {
|
|
|
|
int c;
|
|
|
|
char *s = src;
|
|
|
|
while ((c = s[0]) != 0) {
|
|
|
|
hash1 = ((hash1 << 5) + hash1) ^ c;
|
|
|
|
c = s [1];
|
|
|
|
if (c == 0)
|
|
|
|
break;
|
|
|
|
hash2 = ((hash2 << 5) + hash2) ^ c;
|
|
|
|
s += 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return hash1 + (hash2 * 1566083941);
|
|
|
|
}
|
2015-08-26 07:17:56 -04:00
|
|
|
}
|
|
|
|
}
|