-Reduced string allocations
This commit is contained in:
@@ -1183,7 +1183,8 @@ _____'propertyName': NaN
|
||||
Console.WriteLine("Position: " + (int)c);
|
||||
|
||||
StringWriter swNew = new StringWriter();
|
||||
JavaScriptUtils.WriteEscapedJavaScriptString(swNew, c.ToString(), '"', true, JavaScriptUtils.DoubleQuoteCharEscapeFlags, StringEscapeHandling.Default);
|
||||
char[] buffer = null;
|
||||
JavaScriptUtils.WriteEscapedJavaScriptString(swNew, c.ToString(), '"', true, JavaScriptUtils.DoubleQuoteCharEscapeFlags, StringEscapeHandling.Default, ref buffer);
|
||||
|
||||
StringWriter swOld = new StringWriter();
|
||||
WriteEscapedJavaScriptStringOld(swOld, c.ToString(), '"', true);
|
||||
|
||||
@@ -324,7 +324,8 @@ If attributes are not mentioned, default values are used in each case.
|
||||
{
|
||||
using (StringWriter w = StringUtils.CreateStringWriter(StringUtils.GetLength(text) ?? 16))
|
||||
{
|
||||
JavaScriptUtils.WriteEscapedJavaScriptString(w, text, '"', true, JavaScriptUtils.DoubleQuoteCharEscapeFlags, StringEscapeHandling.Default);
|
||||
char[] buffer = null;
|
||||
JavaScriptUtils.WriteEscapedJavaScriptString(w, text, '"', true, JavaScriptUtils.DoubleQuoteCharEscapeFlags, StringEscapeHandling.Default, ref buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -75,4 +75,4 @@ using System.Security;
|
||||
// You can specify all the values or you can default the Revision and Build Numbers
|
||||
// by using the '*' as shown below:
|
||||
[assembly: AssemblyVersion("4.5.0.0")]
|
||||
[assembly: AssemblyFileVersion("5.0.4.16021")]
|
||||
[assembly: AssemblyFileVersion("5.0.4.16022")]
|
||||
|
||||
@@ -648,6 +648,11 @@ namespace Newtonsoft.Json
|
||||
if (ReadData(true) == 0)
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
_charPos = charPos - 1;
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case '-':
|
||||
case '+':
|
||||
@@ -1187,7 +1192,7 @@ namespace Newtonsoft.Json
|
||||
}
|
||||
else
|
||||
{
|
||||
numberValue = ConvertUtils.IntParseFast(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length);
|
||||
numberValue = ConvertUtils.Int32Parse(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length);
|
||||
}
|
||||
|
||||
numberType = JsonToken.Integer;
|
||||
@@ -1238,11 +1243,17 @@ namespace Newtonsoft.Json
|
||||
}
|
||||
else
|
||||
{
|
||||
string number = _stringReference.ToString();
|
||||
|
||||
// it's faster to do 3 indexof with single characters than an indexofany
|
||||
if (number.IndexOf('.') != -1 || number.IndexOf('E') != -1 || number.IndexOf('e') != -1)
|
||||
long value;
|
||||
ParseResult parseResult = ConvertUtils.Int64TryParse(_stringReference.Chars, _stringReference.StartIndex, _stringReference.Length, out value);
|
||||
if (parseResult == ParseResult.Success)
|
||||
{
|
||||
numberValue = value;
|
||||
numberType = JsonToken.Integer;
|
||||
}
|
||||
else if (parseResult == ParseResult.Invalid)
|
||||
{
|
||||
string number = _stringReference.ToString();
|
||||
|
||||
if (_floatParseHandling == FloatParseHandling.Decimal)
|
||||
numberValue = decimal.Parse(number, NumberStyles.Number | NumberStyles.AllowExponent, CultureInfo.InvariantCulture);
|
||||
else
|
||||
@@ -1250,24 +1261,20 @@ namespace Newtonsoft.Json
|
||||
|
||||
numberType = JsonToken.Float;
|
||||
}
|
||||
else if (parseResult == ParseResult.Overflow)
|
||||
{
|
||||
#if !(NET20 || NET35 || SILVERLIGHT || PORTABLE40 || PORTABLE)
|
||||
string number = _stringReference.ToString();
|
||||
numberValue = BigInteger.Parse(number, CultureInfo.InvariantCulture);
|
||||
numberType = JsonToken.Integer;
|
||||
#else
|
||||
// todo - validate number was a valid integer to make sure overflow was the reason for failure
|
||||
throw JsonReaderException.Create(this, "JSON integer {0} is too large or small for an Int64.".FormatWith(CultureInfo.InvariantCulture, _stringReference.ToString()));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
long value;
|
||||
if (long.TryParse(number, out value))
|
||||
{
|
||||
numberValue = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if !(NET20 || NET35 || SILVERLIGHT || PORTABLE40 || PORTABLE)
|
||||
numberValue = BigInteger.Parse(number, CultureInfo.InvariantCulture);
|
||||
#else
|
||||
// todo - validate number was a valid integer to make sure overflow was the reason for failure
|
||||
throw JsonReaderException.Create(this, "JSON integer {0} is too large or small for an Int64.".FormatWith(CultureInfo.InvariantCulture, number));
|
||||
#endif
|
||||
}
|
||||
|
||||
numberType = JsonToken.Integer;
|
||||
throw JsonReaderException.Create(this, "Unknown error parsing integer.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,7 +214,7 @@ namespace Newtonsoft.Json
|
||||
{
|
||||
InternalWritePropertyName(name);
|
||||
|
||||
JavaScriptUtils.WriteEscapedJavaScriptString(_writer, name, _quoteChar, _quoteName, _charEscapeFlags, StringEscapeHandling);
|
||||
WriteEscapedString(name);
|
||||
|
||||
_writer.Write(':');
|
||||
}
|
||||
@@ -230,7 +230,7 @@ namespace Newtonsoft.Json
|
||||
|
||||
if (escape)
|
||||
{
|
||||
JavaScriptUtils.WriteEscapedJavaScriptString(_writer, name, _quoteChar, _quoteName, _charEscapeFlags, StringEscapeHandling);
|
||||
WriteEscapedString(name);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -364,7 +364,13 @@ namespace Newtonsoft.Json
|
||||
if (value == null)
|
||||
WriteValueInternal(JsonConvert.Null, JsonToken.Null);
|
||||
else
|
||||
JavaScriptUtils.WriteEscapedJavaScriptString(_writer, value, _quoteChar, true, _charEscapeFlags, StringEscapeHandling);
|
||||
WriteEscapedString(value);
|
||||
}
|
||||
|
||||
private void WriteEscapedString(string value)
|
||||
{
|
||||
EnsureWriteBuffer();
|
||||
JavaScriptUtils.WriteEscapedJavaScriptString(_writer, value, _quoteChar, true, _charEscapeFlags, StringEscapeHandling, ref _writeBuffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -92,6 +92,6 @@ using System.Security;
|
||||
// You can specify all the values or you can default the Revision and Build Numbers
|
||||
// by using the '*' as shown below:
|
||||
[assembly: AssemblyVersion("4.5.0.0")]
|
||||
[assembly: AssemblyFileVersion("5.0.4.16021")]
|
||||
[assembly: AssemblyFileVersion("5.0.4.16022")]
|
||||
|
||||
[assembly: CLSCompliant(true)]
|
||||
|
||||
@@ -98,6 +98,14 @@ namespace Newtonsoft.Json.Utilities
|
||||
public PrimitiveTypeCode TypeCode { get; set; }
|
||||
}
|
||||
|
||||
internal enum ParseResult
|
||||
{
|
||||
None,
|
||||
Success,
|
||||
Overflow,
|
||||
Invalid
|
||||
}
|
||||
|
||||
internal static class ConvertUtils
|
||||
{
|
||||
private static readonly Dictionary<Type, PrimitiveTypeCode> TypeCodeMap =
|
||||
@@ -205,7 +213,7 @@ namespace Newtonsoft.Json.Utilities
|
||||
#if !(NETFX_CORE || PORTABLE)
|
||||
public static TypeInformation GetTypeInformation(IConvertible convertable)
|
||||
{
|
||||
TypeInformation typeInformation = PrimitiveTypeCodes[(int) convertable.GetTypeCode()];
|
||||
TypeInformation typeInformation = PrimitiveTypeCodes[(int)convertable.GetTypeCode()];
|
||||
return typeInformation;
|
||||
}
|
||||
#endif
|
||||
@@ -224,7 +232,7 @@ namespace Newtonsoft.Json.Utilities
|
||||
public static TimeSpan ParseTimeSpan(string input)
|
||||
{
|
||||
#if !(NET35 || NET20 || PORTABLE40)
|
||||
return TimeSpan.Parse((string) input, CultureInfo.InvariantCulture);
|
||||
return TimeSpan.Parse((string)input, CultureInfo.InvariantCulture);
|
||||
#else
|
||||
return TimeSpan.Parse((string)input);
|
||||
#endif
|
||||
@@ -316,14 +324,14 @@ namespace Newtonsoft.Json.Utilities
|
||||
|
||||
public static object FromBigInteger(BigInteger i, Type targetType)
|
||||
{
|
||||
if (targetType == typeof (decimal))
|
||||
return (decimal) i;
|
||||
if (targetType == typeof (double))
|
||||
return (double) i;
|
||||
if (targetType == typeof (float))
|
||||
return (float) i;
|
||||
if (targetType == typeof (ulong))
|
||||
return (ulong) i;
|
||||
if (targetType == typeof(decimal))
|
||||
return (decimal)i;
|
||||
if (targetType == typeof(double))
|
||||
return (double)i;
|
||||
if (targetType == typeof(float))
|
||||
return (float)i;
|
||||
if (targetType == typeof(ulong))
|
||||
return (ulong)i;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -337,6 +345,7 @@ namespace Newtonsoft.Json.Utilities
|
||||
#endif
|
||||
|
||||
#region Convert
|
||||
|
||||
/// <summary>
|
||||
/// Converts the value to the specified type.
|
||||
/// </summary>
|
||||
@@ -377,18 +386,18 @@ namespace Newtonsoft.Json.Utilities
|
||||
#endif
|
||||
|
||||
if (initialValue is byte[] && targetType == typeof(Guid))
|
||||
return new Guid((byte[]) initialValue);
|
||||
return new Guid((byte[])initialValue);
|
||||
|
||||
if (initialValue is string)
|
||||
{
|
||||
if (targetType == typeof (Guid))
|
||||
return new Guid((string) initialValue);
|
||||
if (targetType == typeof (Uri))
|
||||
return new Uri((string) initialValue, UriKind.RelativeOrAbsolute);
|
||||
if (targetType == typeof(Guid))
|
||||
return new Guid((string)initialValue);
|
||||
if (targetType == typeof(Uri))
|
||||
return new Uri((string)initialValue, UriKind.RelativeOrAbsolute);
|
||||
if (targetType == typeof(TimeSpan))
|
||||
return ParseTimeSpan((string) initialValue);
|
||||
return ParseTimeSpan((string)initialValue);
|
||||
if (typeof(Type).IsAssignableFrom(targetType))
|
||||
return Type.GetType((string) initialValue, true);
|
||||
return Type.GetType((string)initialValue, true);
|
||||
}
|
||||
|
||||
#if !(NET20 || NET35 || SILVERLIGHT || PORTABLE40 || PORTABLE)
|
||||
@@ -431,7 +440,7 @@ namespace Newtonsoft.Json.Utilities
|
||||
{
|
||||
if (ReflectionUtils.IsNullable(targetType))
|
||||
return EnsureTypeAssignable(null, initialType, targetType);
|
||||
|
||||
|
||||
throw new Exception("Can not convert null {0} into non-nullable {1}.".FormatWith(CultureInfo.InvariantCulture, initialType, targetType));
|
||||
}
|
||||
#endif
|
||||
@@ -446,6 +455,7 @@ namespace Newtonsoft.Json.Utilities
|
||||
#endregion
|
||||
|
||||
#region TryConvert
|
||||
|
||||
/// <summary>
|
||||
/// Converts the value to the specified type.
|
||||
/// </summary>
|
||||
@@ -469,9 +479,11 @@ namespace Newtonsoft.Json.Utilities
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ConvertOrCast
|
||||
|
||||
/// <summary>
|
||||
/// Converts the value to the specified type. If the value is unable to be converted, the
|
||||
/// value is checked whether it assignable to the specified type.
|
||||
@@ -498,6 +510,7 @@ namespace Newtonsoft.Json.Utilities
|
||||
|
||||
return EnsureTypeAssignable(initialValue, ReflectionUtils.GetObjectType(initialValue), targetType);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private static object EnsureTypeAssignable(object value, Type initialType, Type targetType)
|
||||
@@ -567,12 +580,12 @@ namespace Newtonsoft.Json.Utilities
|
||||
}
|
||||
}
|
||||
|
||||
public static int IntParseFast(char[] value, int start, int length)
|
||||
public static int Int32Parse(char[] chars, int start, int length)
|
||||
{
|
||||
if (length == 0)
|
||||
throw new FormatException("Input string was not in a correct format.");
|
||||
|
||||
bool isNegative = (value[start] == '-');
|
||||
bool isNegative = (chars[start] == '-');
|
||||
|
||||
if (isNegative)
|
||||
{
|
||||
@@ -584,27 +597,76 @@ namespace Newtonsoft.Json.Utilities
|
||||
length--;
|
||||
}
|
||||
|
||||
checked
|
||||
int result = 0;
|
||||
int end = start + length;
|
||||
|
||||
for (int i = start; i < end; i++)
|
||||
{
|
||||
int result = 0;
|
||||
int end = start + length;
|
||||
for (int i = start; i < end; i++)
|
||||
{
|
||||
char c = value[i];
|
||||
int c = chars[i] - '0';
|
||||
|
||||
if (c < '0' || c > '9')
|
||||
throw new FormatException("Input string was not in a correct format.");
|
||||
if (c < 0 || c > 9)
|
||||
throw new FormatException("Input string was not in a correct format.");
|
||||
|
||||
result = 10*result + -(c - 48);
|
||||
}
|
||||
int newValue = (10*result) - c;
|
||||
|
||||
// go from negative to positive to avoids overflow
|
||||
// negative can be slightly bigger than positive
|
||||
if (!isNegative)
|
||||
result = -result;
|
||||
// overflow has caused the number to loop around
|
||||
if (newValue > result)
|
||||
throw new OverflowException();
|
||||
|
||||
return result;
|
||||
result = newValue;
|
||||
}
|
||||
|
||||
// go from negative to positive to avoids overflow
|
||||
// negative can be slightly bigger than positive
|
||||
if (!isNegative)
|
||||
result = -result;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static ParseResult Int64TryParse(char[] chars, int start, int length, out long value)
|
||||
{
|
||||
value = 0;
|
||||
|
||||
if (length == 0)
|
||||
return ParseResult.Invalid;
|
||||
|
||||
bool isNegative = (chars[start] == '-');
|
||||
|
||||
if (isNegative)
|
||||
{
|
||||
// text just a negative sign
|
||||
if (length == 1)
|
||||
return ParseResult.Invalid;
|
||||
|
||||
start++;
|
||||
length--;
|
||||
}
|
||||
|
||||
int end = start + length;
|
||||
|
||||
for (int i = start; i < end; i++)
|
||||
{
|
||||
int c = chars[i] - '0';
|
||||
|
||||
if (c < 0 || c > 9)
|
||||
return ParseResult.Invalid;
|
||||
|
||||
long newValue = (10*value) - c;
|
||||
|
||||
// overflow has caused the number to loop around
|
||||
if (newValue > value)
|
||||
return ParseResult.Overflow;
|
||||
|
||||
value = newValue;
|
||||
}
|
||||
|
||||
// go from negative to positive to avoids overflow
|
||||
// negative can be slightly bigger than positive
|
||||
if (!isNegative)
|
||||
value = -value;
|
||||
|
||||
return ParseResult.Success;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -71,7 +71,8 @@ namespace Newtonsoft.Json.Utilities
|
||||
|
||||
private const string EscapedUnicodeText = "!";
|
||||
|
||||
public static void WriteEscapedJavaScriptString(TextWriter writer, string s, char delimiter, bool appendDelimiters, bool[] charEscapeFlags, StringEscapeHandling stringEscapeHandling)
|
||||
public static void WriteEscapedJavaScriptString(TextWriter writer, string s, char delimiter, bool appendDelimiters,
|
||||
bool[] charEscapeFlags, StringEscapeHandling stringEscapeHandling, ref char[] writeBuffer)
|
||||
{
|
||||
// leading delimiter
|
||||
if (appendDelimiters)
|
||||
@@ -79,8 +80,6 @@ namespace Newtonsoft.Json.Utilities
|
||||
|
||||
if (s != null)
|
||||
{
|
||||
char[] chars = null;
|
||||
char[] unicodeBuffer = null;
|
||||
int lastWritePosition = 0;
|
||||
|
||||
for (int i = 0; i < s.Length; i++)
|
||||
@@ -134,10 +133,10 @@ namespace Newtonsoft.Json.Utilities
|
||||
}
|
||||
else
|
||||
{
|
||||
if (unicodeBuffer == null)
|
||||
unicodeBuffer = new char[6];
|
||||
if (writeBuffer == null)
|
||||
writeBuffer = new char[6];
|
||||
|
||||
StringUtils.ToCharAsUnicode(c, unicodeBuffer);
|
||||
StringUtils.ToCharAsUnicode(c, writeBuffer);
|
||||
|
||||
// slightly hacky but it saves multiple conditions in if test
|
||||
escapedValue = EscapedUnicodeText;
|
||||
@@ -153,20 +152,36 @@ namespace Newtonsoft.Json.Utilities
|
||||
if (escapedValue == null)
|
||||
continue;
|
||||
|
||||
bool isEscapedUnicodeText = string.Equals(escapedValue, EscapedUnicodeText);
|
||||
|
||||
if (i > lastWritePosition)
|
||||
{
|
||||
if (chars == null)
|
||||
chars = s.ToCharArray();
|
||||
int length = i - lastWritePosition + ((isEscapedUnicodeText) ? 6 : 0);
|
||||
int start = (isEscapedUnicodeText) ? 6 : 0;
|
||||
|
||||
if (writeBuffer == null || writeBuffer.Length < length)
|
||||
{
|
||||
char[] newBuffer = new char[length];
|
||||
|
||||
// the unicode text is already in the buffer
|
||||
// copy it over when creating new buffer
|
||||
if (isEscapedUnicodeText)
|
||||
Array.Copy(writeBuffer, newBuffer, 6);
|
||||
|
||||
writeBuffer = newBuffer;
|
||||
}
|
||||
|
||||
s.CopyTo(lastWritePosition, writeBuffer, start, length - start);
|
||||
|
||||
// write unchanged chars before writing escaped text
|
||||
writer.Write(chars, lastWritePosition, i - lastWritePosition);
|
||||
writer.Write(writeBuffer, start, length - start);
|
||||
}
|
||||
|
||||
lastWritePosition = i + 1;
|
||||
if (!string.Equals(escapedValue, EscapedUnicodeText))
|
||||
if (!isEscapedUnicodeText)
|
||||
writer.Write(escapedValue);
|
||||
else
|
||||
writer.Write(unicodeBuffer);
|
||||
writer.Write(writeBuffer, 0, 6);
|
||||
}
|
||||
|
||||
if (lastWritePosition == 0)
|
||||
@@ -176,11 +191,15 @@ namespace Newtonsoft.Json.Utilities
|
||||
}
|
||||
else
|
||||
{
|
||||
if (chars == null)
|
||||
chars = s.ToCharArray();
|
||||
int length = s.Length - lastWritePosition;
|
||||
|
||||
if (writeBuffer == null || writeBuffer.Length < length)
|
||||
writeBuffer = new char[length];
|
||||
|
||||
s.CopyTo(lastWritePosition, writeBuffer, 0, length);
|
||||
|
||||
// write remaining text
|
||||
writer.Write(chars, lastWritePosition, s.Length - lastWritePosition);
|
||||
writer.Write(writeBuffer, 0, length);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,7 +212,8 @@ namespace Newtonsoft.Json.Utilities
|
||||
{
|
||||
using (StringWriter w = StringUtils.CreateStringWriter(StringUtils.GetLength(value) ?? 16))
|
||||
{
|
||||
WriteEscapedJavaScriptString(w, value, delimiter, appendDelimiters, (delimiter == '"') ? DoubleQuoteCharEscapeFlags : SingleQuoteCharEscapeFlags, StringEscapeHandling.Default);
|
||||
char[] buffer = null;
|
||||
WriteEscapedJavaScriptString(w, value, delimiter, appendDelimiters, (delimiter == '"') ? DoubleQuoteCharEscapeFlags : SingleQuoteCharEscapeFlags, StringEscapeHandling.Default, ref buffer);
|
||||
return w.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user