From 90297804e16da121ed28543923abf5b3d93f7901 Mon Sep 17 00:00:00 2001 From: JamesNK Date: Sun, 8 Jan 2012 00:54:53 +0000 Subject: [PATCH] -Performance improvements --- .../Converters/RegexConverter.cs | 8 +-- Src/Newtonsoft.Json/JsonConvert.cs | 50 +++++++------- Src/Newtonsoft.Json/JsonSerializer.cs | 2 + Src/Newtonsoft.Json/JsonTextReader.cs | 54 +++++++++------ Src/Newtonsoft.Json/JsonTextWriter.cs | 17 ++--- Src/Newtonsoft.Json/JsonWriter.cs | 24 ++++--- .../Serialization/JsonPropertyCollection.cs | 24 ++++++- .../JsonSerializerInternalReader.cs | 2 +- .../Utilities/JavaScriptUtils.cs | 66 +++++++++++-------- 9 files changed, 149 insertions(+), 98 deletions(-) diff --git a/Src/Newtonsoft.Json/Converters/RegexConverter.cs b/Src/Newtonsoft.Json/Converters/RegexConverter.cs index 72c5c8a9..bd589bc3 100644 --- a/Src/Newtonsoft.Json/Converters/RegexConverter.cs +++ b/Src/Newtonsoft.Json/Converters/RegexConverter.cs @@ -93,8 +93,8 @@ namespace Newtonsoft.Json.Converters private object ReadBson(BsonReader reader) { - string regexText = (string)reader.Value; - int patternOptionDelimiterIndex = regexText.LastIndexOf(@"/"); + string regexText = (string) reader.Value; + int patternOptionDelimiterIndex = regexText.LastIndexOf('/'); string patternText = regexText.Substring(1, patternOptionDelimiterIndex - 1); string optionsText = regexText.Substring(patternOptionDelimiterIndex + 1); @@ -134,7 +134,7 @@ namespace Newtonsoft.Json.Converters reader.Read(); - return new Regex(pattern, (RegexOptions)options); + return new Regex(pattern, (RegexOptions) options); } /// @@ -149,4 +149,4 @@ namespace Newtonsoft.Json.Converters return (objectType == typeof (Regex)); } } -} +} \ No newline at end of file diff --git a/Src/Newtonsoft.Json/JsonConvert.cs b/Src/Newtonsoft.Json/JsonConvert.cs index 5697d5fc..88407c5f 100644 --- a/Src/Newtonsoft.Json/JsonConvert.cs +++ b/Src/Newtonsoft.Json/JsonConvert.cs @@ -119,7 +119,7 @@ namespace Newtonsoft.Json writer.Write(@"""\/Date("); writer.Write(javaScriptTicks); - + switch (kind) { case DateTimeKind.Local: @@ -184,14 +184,14 @@ namespace Newtonsoft.Json private static long UniversialTicksToJavaScriptTicks(long universialTicks) { - long javaScriptTicks = (universialTicks - InitialJavaScriptDateTicks) / 10000; + long javaScriptTicks = (universialTicks - InitialJavaScriptDateTicks)/10000; return javaScriptTicks; } internal static DateTime ConvertJavaScriptTicksToDateTime(long javaScriptTicks) { - DateTime dateTime = new DateTime((javaScriptTicks * 10000) + InitialJavaScriptDateTicks, DateTimeKind.Utc); + DateTime dateTime = new DateTime((javaScriptTicks*10000) + InitialJavaScriptDateTicks, DateTimeKind.Utc); return dateTime; } @@ -311,7 +311,7 @@ namespace Newtonsoft.Json private static string EnsureDecimalPlace(double value, string text) { - if (double.IsNaN(value) || double.IsInfinity(value) || text.IndexOf('.') != -1 || text.IndexOf('E') != -1) + if (double.IsNaN(value) || double.IsInfinity(value) || text.IndexOf('.') != -1 || text.IndexOf('E') != -1 || text.IndexOf('e') != -1) return text; return text + ".0"; @@ -463,7 +463,7 @@ namespace Newtonsoft.Json #if !PocketPC && !NET20 else if (value is DateTimeOffset) { - return ToString((DateTimeOffset)value); + return ToString((DateTimeOffset) value); } #endif else if (value is Guid) @@ -514,16 +514,16 @@ namespace Newtonsoft.Json type = Nullable.GetUnderlyingType(type); #if !PocketPC && !NET20 - if (type == typeof(DateTimeOffset)) + if (type == typeof (DateTimeOffset)) return true; #endif - if (type == typeof(byte[])) + if (type == typeof (byte[])) return true; - if (type == typeof(Uri)) + if (type == typeof (Uri)) return true; - if (type == typeof(TimeSpan)) + if (type == typeof (TimeSpan)) return true; - if (type == typeof(Guid)) + if (type == typeof (Guid)) return true; return IsJsonPrimitiveTypeCode(Type.GetTypeCode(type)); @@ -562,7 +562,7 @@ namespace Newtonsoft.Json /// A JSON string representation of the object. public static string SerializeObject(object value) { - return SerializeObject(value, Formatting.None, (JsonSerializerSettings)null); + return SerializeObject(value, Formatting.None, (JsonSerializerSettings) null); } /// @@ -575,7 +575,7 @@ namespace Newtonsoft.Json /// public static string SerializeObject(object value, Formatting formatting) { - return SerializeObject(value, formatting, (JsonSerializerSettings)null); + return SerializeObject(value, formatting, (JsonSerializerSettings) null); } /// @@ -599,8 +599,8 @@ namespace Newtonsoft.Json public static string SerializeObject(object value, Formatting formatting, params JsonConverter[] converters) { JsonSerializerSettings settings = (converters != null && converters.Length > 0) - ? new JsonSerializerSettings { Converters = converters } - : null; + ? new JsonSerializerSettings {Converters = converters} + : null; return SerializeObject(value, formatting, settings); } @@ -638,7 +638,7 @@ namespace Newtonsoft.Json /// The deserialized object from the Json string. public static object DeserializeObject(string value) { - return DeserializeObject(value, null, (JsonSerializerSettings)null); + return DeserializeObject(value, null, (JsonSerializerSettings) null); } /// @@ -663,7 +663,7 @@ namespace Newtonsoft.Json /// The deserialized object from the Json string. public static object DeserializeObject(string value, Type type) { - return DeserializeObject(value, type, (JsonSerializerSettings)null); + return DeserializeObject(value, type, (JsonSerializerSettings) null); } /// @@ -674,7 +674,7 @@ namespace Newtonsoft.Json /// The deserialized object from the Json string. public static T DeserializeObject(string value) { - return DeserializeObject(value, (JsonSerializerSettings)null); + return DeserializeObject(value, (JsonSerializerSettings) null); } /// @@ -702,7 +702,7 @@ namespace Newtonsoft.Json /// The deserialized object from the JSON string. public static T DeserializeObject(string value, params JsonConverter[] converters) { - return (T)DeserializeObject(value, typeof(T), converters); + return (T) DeserializeObject(value, typeof (T), converters); } /// @@ -717,7 +717,7 @@ namespace Newtonsoft.Json /// The deserialized object from the JSON string. public static T DeserializeObject(string value, JsonSerializerSettings settings) { - return (T)DeserializeObject(value, typeof(T), settings); + return (T) DeserializeObject(value, typeof (T), settings); } /// @@ -730,8 +730,8 @@ namespace Newtonsoft.Json public static object DeserializeObject(string value, Type type, params JsonConverter[] converters) { JsonSerializerSettings settings = (converters != null && converters.Length > 0) - ? new JsonSerializerSettings { Converters = converters } - : null; + ? new JsonSerializerSettings {Converters = converters} + : null; return DeserializeObject(value, type, settings); } @@ -831,7 +831,7 @@ namespace Newtonsoft.Json /// A JSON string of the XmlNode. public static string SerializeXmlNode(XmlNode node, Formatting formatting, bool omitRootObject) { - XmlNodeConverter converter = new XmlNodeConverter { OmitRootObject = omitRootObject }; + XmlNodeConverter converter = new XmlNodeConverter {OmitRootObject = omitRootObject}; return SerializeObject(node, formatting, converter); } @@ -873,7 +873,7 @@ namespace Newtonsoft.Json converter.DeserializeRootElementName = deserializeRootElementName; converter.WriteArrayAttribute = writeArrayAttribute; - return (XmlDocument)DeserializeObject(value, typeof(XmlDocument), converter); + return (XmlDocument) DeserializeObject(value, typeof (XmlDocument), converter); } #endif @@ -908,7 +908,7 @@ namespace Newtonsoft.Json /// A JSON string of the XNode. public static string SerializeXNode(XObject node, Formatting formatting, bool omitRootObject) { - XmlNodeConverter converter = new XmlNodeConverter { OmitRootObject = omitRootObject }; + XmlNodeConverter converter = new XmlNodeConverter {OmitRootObject = omitRootObject}; return SerializeObject(node, formatting, converter); } @@ -950,7 +950,7 @@ namespace Newtonsoft.Json converter.DeserializeRootElementName = deserializeRootElementName; converter.WriteArrayAttribute = writeArrayAttribute; - return (XDocument)DeserializeObject(value, typeof(XDocument), converter); + return (XDocument) DeserializeObject(value, typeof (XDocument), converter); } #endif } diff --git a/Src/Newtonsoft.Json/JsonSerializer.cs b/Src/Newtonsoft.Json/JsonSerializer.cs index d1bcc168..fbbc33a8 100644 --- a/Src/Newtonsoft.Json/JsonSerializer.cs +++ b/Src/Newtonsoft.Json/JsonSerializer.cs @@ -458,7 +458,9 @@ namespace Newtonsoft.Json internal static JsonConverter GetMatchingConverter(IList converters, Type objectType) { +#if DEBUG ValidationUtils.ArgumentNotNull(objectType, "objectType"); +#endif if (converters != null) { diff --git a/Src/Newtonsoft.Json/JsonTextReader.cs b/Src/Newtonsoft.Json/JsonTextReader.cs index 34835898..26cf0d8f 100644 --- a/Src/Newtonsoft.Json/JsonTextReader.cs +++ b/Src/Newtonsoft.Json/JsonTextReader.cs @@ -112,7 +112,7 @@ namespace Newtonsoft.Json { SetToken(JsonToken.String, text); QuoteChar = quote; - } + } } } @@ -216,7 +216,7 @@ namespace Newtonsoft.Json TimeSpan offset = TimeSpan.FromHours(hours) + TimeSpan.FromMinutes(minutes); if (negative) offset = offset.Negate(); - + return offset; } @@ -298,7 +298,7 @@ namespace Newtonsoft.Json break; } - return (char)value; + return (char) value; } private bool HasNext() @@ -417,20 +417,20 @@ namespace Newtonsoft.Json public override decimal? ReadAsDecimal() { _readType = ReadType.ReadAsDecimal; - + do { if (!ReadInternal()) throw CreateJsonReaderException("Unexpected end when reading decimal: Line {0}, position {1}.", _currentLineNumber, _currentLinePosition); } while (TokenType == JsonToken.Comment); - + if (TokenType == JsonToken.Null) return null; if (TokenType == JsonToken.Float) - return (decimal?)Value; + return (decimal?) Value; decimal d; - if (TokenType == JsonToken.String && decimal.TryParse((string)Value, NumberStyles.Number, Culture, out d)) + if (TokenType == JsonToken.String && decimal.TryParse((string) Value, NumberStyles.Number, Culture, out d)) { SetToken(JsonToken.Float, d); return d; @@ -457,10 +457,10 @@ namespace Newtonsoft.Json if (TokenType == JsonToken.Null) return null; if (TokenType == JsonToken.Date) - return (DateTimeOffset)Value; + return (DateTimeOffset) Value; DateTimeOffset dt; - if (TokenType == JsonToken.String && DateTimeOffset.TryParse((string)Value, Culture, DateTimeStyles.None, out dt)) + if (TokenType == JsonToken.String && DateTimeOffset.TryParse((string) Value, Culture, DateTimeStyles.None, out dt)) { SetToken(JsonToken.Date, dt); return dt; @@ -685,7 +685,7 @@ namespace Newtonsoft.Json case 'n': if (HasNext()) { - char next = (char)PeekNext(); + char next = (char) PeekNext(); if (next == 'u') ParseNull(); @@ -828,16 +828,22 @@ namespace Newtonsoft.Json object numberValue; JsonToken numberType; - bool nonBase10 = (firstChar == '0' && !number.StartsWith("0.", StringComparison.OrdinalIgnoreCase)); + bool singleDigit = (char.IsDigit(firstChar) && number.Length == 1); + bool nonBase10 = (firstChar == '0' && number.Length > 1 && number[1] != '.'); if (_readType == ReadType.ReadAsDecimal) { - if (nonBase10) + if (singleDigit) + { + // digit char values start at 48 + numberValue = (decimal)firstChar - 48; + } + else if (nonBase10) { // decimal.Parse doesn't support parsing hexadecimal values long integer = number.StartsWith("0x", StringComparison.OrdinalIgnoreCase) - ? Convert.ToInt64(number, 16) - : Convert.ToInt64(number, 8); + ? Convert.ToInt64(number, 16) + : Convert.ToInt64(number, 8); numberValue = Convert.ToDecimal(integer); } @@ -850,14 +856,21 @@ namespace Newtonsoft.Json } else { - if (nonBase10) + if (singleDigit) { - numberValue = number.StartsWith("0x", StringComparison.OrdinalIgnoreCase) - ? Convert.ToInt64(number, 16) - : Convert.ToInt64(number, 8); + // digit char values start at 48 + numberValue = (long)firstChar - 48; numberType = JsonToken.Integer; } - else if (number.IndexOf(".", StringComparison.OrdinalIgnoreCase) != -1 || number.IndexOf("e", StringComparison.OrdinalIgnoreCase) != -1) + else if (nonBase10) + { + numberValue = number.StartsWith("0x", StringComparison.OrdinalIgnoreCase) + ? Convert.ToInt64(number, 16) + : Convert.ToInt64(number, 8); + numberType = JsonToken.Integer; + } + // it's faster to do 3 indexof with single characters than an indexofany + else if (number.IndexOf('.') != -1 || number.IndexOf('E') != -1 || number.IndexOf('e') != -1) { numberValue = Convert.ToDouble(number, CultureInfo.InvariantCulture); numberType = JsonToken.Float; @@ -935,8 +948,7 @@ namespace Newtonsoft.Json break; } i++; - } - while (i < value.Length && ((currentChar = MoveNext()) != '\0' || !_end)); + } while (i < value.Length && ((currentChar = MoveNext()) != '\0' || !_end)); return (i == value.Length); } diff --git a/Src/Newtonsoft.Json/JsonTextWriter.cs b/Src/Newtonsoft.Json/JsonTextWriter.cs index 7ffc941a..7e3d1dc9 100644 --- a/Src/Newtonsoft.Json/JsonTextWriter.cs +++ b/Src/Newtonsoft.Json/JsonTextWriter.cs @@ -211,17 +211,14 @@ namespace Newtonsoft.Json /// protected override void WriteIndent() { - if (Formatting == Formatting.Indented) + _writer.Write(Environment.NewLine); + + // levels of indentation multiplied by the indent count + int currentIndentCount = Top*_indentation; + + for (int i = 0; i < currentIndentCount; i++) { - _writer.Write(Environment.NewLine); - - // levels of indentation multiplied by the indent count - int currentIndentCount = Top * _indentation; - - for (int i = 0; i < currentIndentCount; i++) - { - _writer.Write(_indentChar); - } + _writer.Write(_indentChar); } } diff --git a/Src/Newtonsoft.Json/JsonWriter.cs b/Src/Newtonsoft.Json/JsonWriter.cs index 03ac0b25..f782b41a 100644 --- a/Src/Newtonsoft.Json/JsonWriter.cs +++ b/Src/Newtonsoft.Json/JsonWriter.cs @@ -522,8 +522,11 @@ namespace Newtonsoft.Json { JsonToken token = GetCloseTokenForType(Pop()); - if (_currentState != State.ObjectStart && _currentState != State.ArrayStart) - WriteIndent(); + if (_formatting == Formatting.Indented) + { + if (_currentState != State.ObjectStart && _currentState != State.ArrayStart) + WriteIndent(); + } WriteEnd(token); } @@ -616,13 +619,16 @@ namespace Newtonsoft.Json WriteIndentSpace(); } - WriteState writeState = WriteState; - - // don't indent a property when it is the first token to be written (i.e. at the start) - if ((tokenBeingWritten == JsonToken.PropertyName && writeState != WriteState.Start) || - writeState == WriteState.Array || writeState == WriteState.Constructor) + if (_formatting == Formatting.Indented) { - WriteIndent(); + WriteState writeState = WriteState; + + // don't indent a property when it is the first token to be written (i.e. at the start) + if ((tokenBeingWritten == JsonToken.PropertyName && writeState != WriteState.Start) || + writeState == WriteState.Array || writeState == WriteState.Constructor) + { + WriteIndent(); + } } _currentState = newState; @@ -1196,7 +1202,7 @@ namespace Newtonsoft.Json private void Dispose(bool disposing) { - if (WriteState != WriteState.Closed) + if (_currentState != State.Closed) Close(); } } diff --git a/Src/Newtonsoft.Json/Serialization/JsonPropertyCollection.cs b/Src/Newtonsoft.Json/Serialization/JsonPropertyCollection.cs index e65fe139..5c2d525e 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonPropertyCollection.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonPropertyCollection.cs @@ -43,7 +43,7 @@ namespace Newtonsoft.Json.Serialization /// Initializes a new instance of the class. /// /// The type. - public JsonPropertyCollection(Type type) + public JsonPropertyCollection(Type type) : base(StringComparer.Ordinal) { ValidationUtils.ArgumentNotNull(type, "type"); _type = type; @@ -100,6 +100,18 @@ namespace Newtonsoft.Json.Serialization return property; } + private bool TryGetValue(string key, out JsonProperty item) + { + if (Dictionary == null) + { + item = default(JsonProperty); + return false; + } + + return Dictionary.TryGetValue(key, out item); + } + + /// /// Gets a property by property name. /// @@ -108,6 +120,16 @@ namespace Newtonsoft.Json.Serialization /// A matching property if found. public JsonProperty GetProperty(string propertyName, StringComparison comparisonType) { + // KeyedCollection has an ordinal comparer + if (comparisonType == StringComparison.Ordinal) + { + JsonProperty property; + if (TryGetValue(propertyName, out property)) + return property; + + return null; + } + foreach (JsonProperty property in this) { if (string.Equals(propertyName, property.PropertyName, comparisonType)) diff --git a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs index 98ad5ed8..14cc050e 100644 --- a/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs +++ b/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs @@ -480,7 +480,7 @@ namespace Newtonsoft.Json.Serialization private bool HasDefinedType(Type type) { - return (type != null && type != typeof (object) && !typeof (JToken).IsAssignableFrom(type) + return (type != null && type != typeof (object) && !typeof (JToken).IsSubclassOf(type) #if !(NET35 || NET20 || WINDOWS_PHONE) && type != typeof (IDynamicMetaObjectProvider) #endif diff --git a/Src/Newtonsoft.Json/Utilities/JavaScriptUtils.cs b/Src/Newtonsoft.Json/Utilities/JavaScriptUtils.cs index b5023943..d4ee35ed 100644 --- a/Src/Newtonsoft.Json/Utilities/JavaScriptUtils.cs +++ b/Src/Newtonsoft.Json/Utilities/JavaScriptUtils.cs @@ -35,21 +35,29 @@ namespace Newtonsoft.Json.Utilities { internal static class JavaScriptUtils { - public static void WriteEscapedJavaScriptString(TextWriter writer, string value, char delimiter, bool appendDelimiters) + public static void WriteEscapedJavaScriptString(TextWriter writer, string s, char delimiter, bool appendDelimiters) { // leading delimiter if (appendDelimiters) writer.Write(delimiter); - if (value != null) + if (s != null) { - int lastWritePosition = 0; - int skipped = 0; char[] chars = null; + int lastWritePosition = -1; - for (int i = 0; i < value.Length; i++) + for (var index = 0; index < s.Length; ++index) { - char c = value[i]; + var c = s[index]; + + if (c >= ' ' && c < 128 && c != '\"' && c != '\\' && c != '\'') + { + if (lastWritePosition == -1) + lastWritePosition = index; + + continue; + } + string escapedValue; switch (c) @@ -94,35 +102,39 @@ namespace Newtonsoft.Json.Utilities break; } - if (escapedValue != null) + if (escapedValue == null) + { + if (lastWritePosition == -1) + lastWritePosition = index; + + continue; + } + + if (lastWritePosition != -1) { if (chars == null) - chars = value.ToCharArray(); + chars = s.ToCharArray(); - // write skipped text - if (skipped > 0) - { - writer.Write(chars, lastWritePosition, skipped); - skipped = 0; - } + writer.Write(chars, lastWritePosition, index - lastWritePosition); + lastWritePosition = -1; + } - // write escaped value and note position - writer.Write(escapedValue); - lastWritePosition = i + 1; + writer.Write(escapedValue); + } + + if (lastWritePosition != -1) + { + if (lastWritePosition == 0) + { + writer.Write(s); } else { - skipped++; - } - } + if (chars == null) + chars = s.ToCharArray(); - // write any remaining skipped text - if (skipped > 0) - { - if (lastWritePosition == 0) - writer.Write(value); - else - writer.Write(chars, lastWritePosition, skipped); + writer.Write(chars, lastWritePosition, s.Length - lastWritePosition); + } } }