-Improved memory usage

This commit is contained in:
James Newton-King
2013-04-20 15:45:34 +12:00
parent d53fe4ec59
commit c032b292bb
7 changed files with 219 additions and 70 deletions
+48 -1
View File
@@ -217,7 +217,7 @@ namespace Newtonsoft.Json
}
else
{
writer.Write(value.ToString(@"yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFF", CultureInfo.InvariantCulture));
WriteIsoDate(writer, value);
switch (kind)
{
@@ -232,6 +232,53 @@ namespace Newtonsoft.Json
}
}
internal static void WriteIsoDate(TextWriter writer, DateTime dt)
{
char[] chars = new char[27];
int length = 19;
IntToCharArray(chars, 0, dt.Year, 4);
chars[4] = '-';
IntToCharArray(chars, 5, dt.Month, 2);
chars[7] = '-';
IntToCharArray(chars, 8, dt.Day, 2);
chars[10] = 'T';
IntToCharArray(chars, 11, dt.Hour, 2);
chars[13] = ':';
IntToCharArray(chars, 14, dt.Minute, 2);
chars[16] = ':';
IntToCharArray(chars, 17, dt.Second, 2);
DateTime time = new DateTime(dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second);
int fraction = (int)(dt.Ticks - time.Ticks);
if (fraction != 0)
{
int digits = 7;
while ((fraction % 10) == 0)
{
digits--;
fraction /= 10;
}
chars[19] = '.';
IntToCharArray(chars, 20, fraction, digits);
length += digits + 1;
}
writer.Write(chars, 0, length);
}
private static void IntToCharArray(char[] text, int start, int value, int digits)
{
while (digits-- != 0)
{
text[start + digits] = (char)((value % 10) + 48);
value /= 10;
}
}
internal static void WriteDateTimeOffset(TextWriter writer, TimeSpan offset, DateFormatHandling format)
{
writer.Write((offset.Ticks >= 0L) ? "+" : "-");
+65 -33
View File
@@ -103,7 +103,7 @@ namespace Newtonsoft.Json
// current Token data
private JsonToken _tokenType;
private object _value;
private char _quoteChar;
internal char _quoteChar;
internal State _currentState;
internal ReadType _readType;
private JsonPosition _currentPosition;
@@ -380,6 +380,8 @@ namespace Newtonsoft.Json
{
_readType = ReadType.ReadAsDateTimeOffset;
JsonToken t;
do
{
if (!ReadInternal())
@@ -387,9 +389,13 @@ namespace Newtonsoft.Json
SetToken(JsonToken.None);
return null;
}
} while (TokenType == JsonToken.Comment);
else
{
t = TokenType;
}
} while (t == JsonToken.Comment);
if (TokenType == JsonToken.Date)
if (t == JsonToken.Date)
{
if (Value is DateTime)
SetToken(JsonToken.Date, new DateTimeOffset((DateTime)Value));
@@ -397,11 +403,11 @@ namespace Newtonsoft.Json
return (DateTimeOffset)Value;
}
if (TokenType == JsonToken.Null)
if (t == JsonToken.Null)
return null;
DateTimeOffset dt;
if (TokenType == JsonToken.String)
if (t == JsonToken.String)
{
string s = (string)Value;
if (string.IsNullOrEmpty(s))
@@ -421,10 +427,10 @@ namespace Newtonsoft.Json
}
}
if (TokenType == JsonToken.EndArray)
if (t == JsonToken.EndArray)
return null;
throw JsonReaderException.Create(this, "Error reading date. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
throw JsonReaderException.Create(this, "Error reading date. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, t));
}
#endif
@@ -432,6 +438,8 @@ namespace Newtonsoft.Json
{
_readType = ReadType.ReadAsBytes;
JsonToken t;
do
{
if (!ReadInternal())
@@ -439,7 +447,11 @@ namespace Newtonsoft.Json
SetToken(JsonToken.None);
return null;
}
} while (TokenType == JsonToken.Comment);
else
{
t = TokenType;
}
} while (t == JsonToken.Comment);
if (IsWrappedInTypeObject())
{
@@ -450,26 +462,28 @@ namespace Newtonsoft.Json
}
// attempt to convert possible base 64 string to bytes
if (TokenType == JsonToken.String)
if (t == JsonToken.String)
{
string s = (string)Value;
byte[] data = (s.Length == 0) ? new byte[0] : Convert.FromBase64String(s);
SetToken(JsonToken.Bytes, data);
return data;
}
if (TokenType == JsonToken.Null)
if (t == JsonToken.Null)
return null;
if (TokenType == JsonToken.Bytes)
if (t == JsonToken.Bytes)
return (byte[])Value;
if (TokenType == JsonToken.StartArray)
if (t == JsonToken.StartArray)
{
List<byte> data = new List<byte>();
while (ReadInternal())
{
switch (TokenType)
t = TokenType;
switch (t)
{
case JsonToken.Integer:
data.Add(Convert.ToByte(Value, CultureInfo.InvariantCulture));
@@ -482,23 +496,25 @@ namespace Newtonsoft.Json
// skip
break;
default:
throw JsonReaderException.Create(this, "Unexpected token when reading bytes: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
throw JsonReaderException.Create(this, "Unexpected token when reading bytes: {0}.".FormatWith(CultureInfo.InvariantCulture, t));
}
}
throw JsonReaderException.Create(this, "Unexpected end when reading bytes.");
}
if (TokenType == JsonToken.EndArray)
if (t == JsonToken.EndArray)
return null;
throw JsonReaderException.Create(this, "Error reading bytes. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
throw JsonReaderException.Create(this, "Error reading bytes. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, t));
}
internal decimal? ReadAsDecimalInternal()
{
_readType = ReadType.ReadAsDecimal;
JsonToken t;
do
{
if (!ReadInternal())
@@ -506,9 +522,13 @@ namespace Newtonsoft.Json
SetToken(JsonToken.None);
return null;
}
} while (TokenType == JsonToken.Comment);
else
{
t = TokenType;
}
} while (t == JsonToken.Comment);
if (TokenType == JsonToken.Integer || TokenType == JsonToken.Float)
if (t == JsonToken.Integer || t == JsonToken.Float)
{
if (!(Value is decimal))
SetToken(JsonToken.Float, Convert.ToDecimal(Value, CultureInfo.InvariantCulture));
@@ -516,11 +536,11 @@ namespace Newtonsoft.Json
return (decimal)Value;
}
if (TokenType == JsonToken.Null)
if (t == JsonToken.Null)
return null;
decimal d;
if (TokenType == JsonToken.String)
if (t == JsonToken.String)
{
string s = (string)Value;
if (string.IsNullOrEmpty(s))
@@ -540,16 +560,18 @@ namespace Newtonsoft.Json
}
}
if (TokenType == JsonToken.EndArray)
if (t == JsonToken.EndArray)
return null;
throw JsonReaderException.Create(this, "Error reading decimal. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
throw JsonReaderException.Create(this, "Error reading decimal. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, t));
}
internal int? ReadAsInt32Internal()
{
_readType = ReadType.ReadAsInt32;
JsonToken t;
do
{
if (!ReadInternal())
@@ -557,9 +579,13 @@ namespace Newtonsoft.Json
SetToken(JsonToken.None);
return null;
}
} while (TokenType == JsonToken.Comment);
else
{
t = TokenType;
}
} while (t == JsonToken.Comment);
if (TokenType == JsonToken.Integer || TokenType == JsonToken.Float)
if (t == JsonToken.Integer || t == JsonToken.Float)
{
if (!(Value is int))
SetToken(JsonToken.Integer, Convert.ToInt32(Value, CultureInfo.InvariantCulture));
@@ -567,11 +593,11 @@ namespace Newtonsoft.Json
return (int)Value;
}
if (TokenType == JsonToken.Null)
if (t == JsonToken.Null)
return null;
int i;
if (TokenType == JsonToken.String)
if (t == JsonToken.String)
{
string s = (string)Value;
if (string.IsNullOrEmpty(s))
@@ -591,7 +617,7 @@ namespace Newtonsoft.Json
}
}
if (TokenType == JsonToken.EndArray)
if (t == JsonToken.EndArray)
return null;
throw JsonReaderException.Create(this, "Error reading integer. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
@@ -601,6 +627,8 @@ namespace Newtonsoft.Json
{
_readType = ReadType.ReadAsString;
JsonToken t;
do
{
if (!ReadInternal())
@@ -608,15 +636,19 @@ namespace Newtonsoft.Json
SetToken(JsonToken.None);
return null;
}
} while (TokenType == JsonToken.Comment);
else
{
t = TokenType;
}
} while (t == JsonToken.Comment);
if (TokenType == JsonToken.String)
if (t == JsonToken.String)
return (string)Value;
if (TokenType == JsonToken.Null)
if (t == JsonToken.Null)
return null;
if (IsPrimitiveToken(TokenType))
if (IsPrimitiveToken(t))
{
if (Value != null)
{
@@ -631,10 +663,10 @@ namespace Newtonsoft.Json
}
}
if (TokenType == JsonToken.EndArray)
if (t == JsonToken.EndArray)
return null;
throw JsonReaderException.Create(this, "Error reading string. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, TokenType));
throw JsonReaderException.Create(this, "Error reading string. Unexpected token: {0}.".FormatWith(CultureInfo.InvariantCulture, t));
}
internal DateTime? ReadAsDateTimeInternal()
+5 -5
View File
@@ -78,7 +78,7 @@ namespace Newtonsoft.Json
_reader = reader;
_lineNumber = 1;
_chars = new char[4097];
_chars = new char[2049];
}
#if DEBUG
@@ -92,7 +92,7 @@ namespace Newtonsoft.Json
{
if (_buffer == null)
{
_buffer = new StringBuffer(4096);
_buffer = new StringBuffer(2048);
}
else
{
@@ -134,7 +134,7 @@ namespace Newtonsoft.Json
string text = _stringReference.ToString();
SetToken(JsonToken.String, text);
QuoteChar = quote;
_quoteChar = quote;
}
else
{
@@ -161,7 +161,7 @@ namespace Newtonsoft.Json
}
SetToken(JsonToken.String, text);
QuoteChar = quote;
_quoteChar = quote;
}
}
@@ -846,7 +846,7 @@ namespace Newtonsoft.Json
_charPos++;
SetToken(JsonToken.PropertyName, propertyName);
QuoteChar = quoteChar;
_quoteChar = quoteChar;
ClearRecentString();
return true;
@@ -70,11 +70,18 @@ namespace Newtonsoft.Json.Serialization
{
internal bool IsNullable;
internal bool IsConvertable;
internal bool IsSealed;
internal Type NonNullableUnderlyingType;
internal ReadType InternalReadType;
internal JsonContractType ContractType;
internal bool IsReadOnlyOrFixedSize;
private List<SerializationCallback> _onDeserializedCallbacks;
private IList<SerializationCallback> _onDeserializingCallbacks;
private IList<SerializationCallback> _onSerializedCallbacks;
private IList<SerializationCallback> _onSerializingCallbacks;
private IList<SerializationErrorCallback> _onErrorCallbacks;
/// <summary>
/// Gets the underlying type for the contract.
/// </summary>
@@ -107,31 +114,76 @@ namespace Newtonsoft.Json.Serialization
/// Gets or sets all methods called immediately after deserialization of the object.
/// </summary>
/// <value>The methods called immediately after deserialization of the object.</value>
public IList<SerializationCallback> OnDeserializedCallbacks { get; private set; }
public IList<SerializationCallback> OnDeserializedCallbacks
{
get
{
if (_onDeserializedCallbacks == null)
_onDeserializedCallbacks = new List<SerializationCallback>();
return _onDeserializedCallbacks;
}
}
/// <summary>
/// Gets or sets all methods called during deserialization of the object.
/// </summary>
/// <value>The methods called during deserialization of the object.</value>
public IList<SerializationCallback> OnDeserializingCallbacks { get; private set; }
public IList<SerializationCallback> OnDeserializingCallbacks
{
get
{
if (_onDeserializingCallbacks == null)
_onDeserializingCallbacks = new List<SerializationCallback>();
return _onDeserializingCallbacks;
}
}
/// <summary>
/// Gets or sets all methods called after serialization of the object graph.
/// </summary>
/// <value>The methods called after serialization of the object graph.</value>
public IList<SerializationCallback> OnSerializedCallbacks { get; private set; }
public IList<SerializationCallback> OnSerializedCallbacks
{
get
{
if (_onSerializedCallbacks == null)
_onSerializedCallbacks = new List<SerializationCallback>();
return _onSerializedCallbacks;
}
}
/// <summary>
/// Gets or sets all methods called before serialization of the object.
/// </summary>
/// <value>The methods called before serialization of the object.</value>
public IList<SerializationCallback> OnSerializingCallbacks { get; private set; }
public IList<SerializationCallback> OnSerializingCallbacks
{
get
{
if (_onSerializingCallbacks == null)
_onSerializingCallbacks = new List<SerializationCallback>();
return _onSerializingCallbacks;
}
}
/// <summary>
/// Gets or sets all method called when an error is thrown during the serialization of the object.
/// </summary>
/// <value>The methods called when an error is thrown during the serialization of the object.</value>
public IList<SerializationErrorCallback> OnErrorCallbacks { get; private set; }
public IList<SerializationErrorCallback> OnErrorCallbacks
{
get
{
if (_onErrorCallbacks == null)
_onErrorCallbacks = new List<SerializationErrorCallback>();
return _onErrorCallbacks;
}
}
/// <summary>
/// Gets or sets the method called immediately after deserialization of the object.
@@ -226,6 +278,8 @@ namespace Newtonsoft.Json.Serialization
UnderlyingType = underlyingType;
IsSealed = underlyingType.IsSealed();
IsNullable = ReflectionUtils.IsNullable(underlyingType);
NonNullableUnderlyingType = (IsNullable && ReflectionUtils.IsNullableType(underlyingType)) ? Nullable.GetUnderlyingType(underlyingType) : underlyingType;
@@ -233,6 +287,7 @@ namespace Newtonsoft.Json.Serialization
IsConvertable = ConvertUtils.IsConvertible(NonNullableUnderlyingType);
if (NonNullableUnderlyingType == typeof(byte[]))
{
InternalReadType = ReadType.ReadAsBytes;
@@ -263,51 +318,60 @@ namespace Newtonsoft.Json.Serialization
{
InternalReadType = ReadType.Read;
}
OnErrorCallbacks = new List<SerializationErrorCallback>();
OnSerializedCallbacks = new List<SerializationCallback>();
OnSerializingCallbacks = new List<SerializationCallback>();
OnDeserializedCallbacks = new List<SerializationCallback>();
OnDeserializingCallbacks = new List<SerializationCallback>();
}
internal void InvokeOnSerializing(object o, StreamingContext context)
{
foreach (SerializationCallback callback in OnSerializingCallbacks)
if (_onSerializingCallbacks != null)
{
callback(o, context);
foreach (SerializationCallback callback in _onSerializingCallbacks)
{
callback(o, context);
}
}
}
internal void InvokeOnSerialized(object o, StreamingContext context)
{
foreach (SerializationCallback callback in OnSerializedCallbacks)
if (_onSerializedCallbacks != null)
{
callback(o, context);
foreach (SerializationCallback callback in _onSerializedCallbacks)
{
callback(o, context);
}
}
}
internal void InvokeOnDeserializing(object o, StreamingContext context)
{
foreach (SerializationCallback callback in OnDeserializingCallbacks)
if (_onDeserializingCallbacks != null)
{
callback(o, context);
foreach (SerializationCallback callback in _onDeserializingCallbacks)
{
callback(o, context);
}
}
}
internal void InvokeOnDeserialized(object o, StreamingContext context)
{
foreach (SerializationCallback callback in OnDeserializedCallbacks)
if (_onDeserializedCallbacks != null)
{
callback(o, context);
foreach (SerializationCallback callback in _onDeserializedCallbacks)
{
callback(o, context);
}
}
}
internal void InvokeOnError(object o, StreamingContext context, ErrorContext errorContext)
{
foreach (SerializationErrorCallback callback in OnErrorCallbacks)
if (_onErrorCallbacks != null)
{
callback(o, context, errorContext);
foreach (SerializationErrorCallback callback in _onErrorCallbacks)
{
callback(o, context, errorContext);
}
}
}
@@ -133,7 +133,6 @@ namespace Newtonsoft.Json.Serialization
return Dictionary.TryGetValue(key, out item);
}
/// <summary>
/// Gets a property by property name.
/// </summary>
@@ -261,15 +261,17 @@ namespace Newtonsoft.Json.Serialization
case JsonToken.Bytes:
return EnsureType(reader, reader.Value, CultureInfo.InvariantCulture, contract, objectType);
case JsonToken.String:
string s = (string)reader.Value;
// convert empty string to null automatically for nullable types
if (string.IsNullOrEmpty((string)reader.Value) && objectType != typeof(string) && objectType != typeof(object) && contract != null && contract.IsNullable)
if (string.IsNullOrEmpty(s) && objectType != typeof(string) && objectType != typeof(object) && contract != null && contract.IsNullable)
return null;
// string that needs to be returned as a byte array should be base 64 decoded
if (objectType == typeof (byte[]))
return Convert.FromBase64String((string) reader.Value);
return Convert.FromBase64String(s);
return EnsureType(reader, reader.Value, CultureInfo.InvariantCulture, contract, objectType);
return EnsureType(reader, s, CultureInfo.InvariantCulture, contract, objectType);
case JsonToken.StartConstructor:
string constructorName = reader.Value.ToString();
@@ -778,6 +780,8 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
return true;
}
JsonToken tokenType = reader.TokenType;
if (property.PropertyContract == null)
property.PropertyContract = GetContractSafe(property.PropertyType);
@@ -785,7 +789,7 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
property.ObjectCreationHandling.GetValueOrDefault(Serializer.ObjectCreationHandling);
if ((objectCreationHandling != ObjectCreationHandling.Replace)
&& (reader.TokenType == JsonToken.StartArray || reader.TokenType == JsonToken.StartObject)
&& (tokenType == JsonToken.StartArray || tokenType == JsonToken.StartObject)
&& property.Readable)
{
currentValue = property.ValueProvider.GetValue(target);
@@ -806,7 +810,7 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
}
// test tokentype here because null might not be convertable to some types, e.g. ignoring null when applied to DateTime
if (property.NullValueHandling.GetValueOrDefault(Serializer.NullValueHandling) == NullValueHandling.Ignore && reader.TokenType == JsonToken.Null)
if (property.NullValueHandling.GetValueOrDefault(Serializer.NullValueHandling) == NullValueHandling.Ignore && tokenType == JsonToken.Null)
{
reader.Skip();
return true;
@@ -814,7 +818,7 @@ To fix this error either change the JSON to a {1} or change the deserialized typ
// test tokentype here because default value might not be convertable to actual type, e.g. default of "" for DateTime
if (HasFlag(property.DefaultValueHandling.GetValueOrDefault(Serializer.DefaultValueHandling), DefaultValueHandling.Ignore)
&& JsonReader.IsPrimitiveToken(reader.TokenType)
&& JsonReader.IsPrimitiveToken(tokenType)
&& MiscellaneousUtils.ValueEquals(reader.Value, property.GetResolvedDefaultValue()))
{
reader.Skip();
@@ -370,8 +370,9 @@ namespace Newtonsoft.Json.Serialization
int initialDepth = writer.Top;
foreach (JsonProperty property in contract.Properties)
for (int index = 0; index < contract.Properties.Count; index++)
{
JsonProperty property = contract.Properties[index];
try
{
object memberValue;
@@ -407,7 +408,7 @@ namespace Newtonsoft.Json.Serialization
property.PropertyContract = Serializer.ContractResolver.ResolveContract(property.PropertyType);
memberValue = property.ValueProvider.GetValue(value);
memberContract = (property.PropertyContract.UnderlyingType.IsSealed()) ? property.PropertyContract : GetContractSafe(memberValue);
memberContract = (property.PropertyContract.IsSealed) ? property.PropertyContract : GetContractSafe(memberValue);
if (ShouldWriteProperty(memberValue, property))
{
@@ -719,8 +720,10 @@ To fix this error either change the environment to be fully trusted, change the
int initialDepth = writer.Top;
foreach (JsonProperty property in contract.Properties)
for (int index = 0; index < contract.Properties.Count; index++)
{
JsonProperty property = contract.Properties[index];
// only write non-dynamic properties that have an explicit attribute
if (property.HasMemberAttribute)
{