-Improve performance and memory usage when serializing Unicode characters
This commit is contained in:
@@ -94,6 +94,7 @@ namespace Newtonsoft.Json.Tests
|
||||
JsonNetWithIsoConverter,
|
||||
JsonNetBinary,
|
||||
JsonNetLinq,
|
||||
JsonNetManual,
|
||||
BinaryFormatter,
|
||||
JavaScriptSerializer,
|
||||
DataContractSerializer,
|
||||
@@ -132,6 +133,7 @@ namespace Newtonsoft.Json.Tests
|
||||
BenchmarkSerializeMethod(SerializeMethod.DataContractJsonSerializer, value);
|
||||
BenchmarkSerializeMethod(SerializeMethod.JsonNet, value);
|
||||
BenchmarkSerializeMethod(SerializeMethod.JsonNetLinq, value);
|
||||
BenchmarkSerializeMethod(SerializeMethod.JsonNetManual, value);
|
||||
BenchmarkSerializeMethod(SerializeMethod.JsonNetWithIsoConverter, value);
|
||||
BenchmarkSerializeMethod(SerializeMethod.JsonNetBinary, value);
|
||||
}
|
||||
@@ -513,6 +515,69 @@ namespace Newtonsoft.Json.Tests
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SerializeMethod.JsonNetManual:
|
||||
{
|
||||
TestClass c = value as TestClass;
|
||||
if (c != null)
|
||||
{
|
||||
StringWriter sw = new StringWriter();
|
||||
JsonTextWriter writer = new JsonTextWriter(sw);
|
||||
writer.WriteStartObject();
|
||||
writer.WritePropertyName("strings");
|
||||
writer.WriteStartArray();
|
||||
foreach (string s in c.strings)
|
||||
{
|
||||
writer.WriteValue(s);
|
||||
}
|
||||
writer.WriteEndArray();
|
||||
writer.WritePropertyName("dictionary");
|
||||
writer.WriteStartObject();
|
||||
foreach (KeyValuePair<string, int> keyValuePair in c.dictionary)
|
||||
{
|
||||
writer.WritePropertyName(keyValuePair.Key);
|
||||
writer.WriteValue(keyValuePair.Value);
|
||||
}
|
||||
writer.WriteEndObject();
|
||||
writer.WritePropertyName("Name");
|
||||
writer.WriteValue(c.Name);
|
||||
writer.WritePropertyName("Now");
|
||||
writer.WriteValue(c.Now);
|
||||
writer.WritePropertyName("BigNumber");
|
||||
writer.WriteValue(c.BigNumber);
|
||||
writer.WritePropertyName("Address1");
|
||||
writer.WriteStartObject();
|
||||
writer.WritePropertyName("Street");
|
||||
writer.WriteValue(c.BigNumber);
|
||||
writer.WritePropertyName("Street");
|
||||
writer.WriteValue(c.BigNumber);
|
||||
writer.WritePropertyName("Street");
|
||||
writer.WriteValue(c.BigNumber);
|
||||
writer.WriteEndObject();
|
||||
writer.WritePropertyName("Addresses");
|
||||
writer.WriteStartArray();
|
||||
foreach (Address address in c.Addresses)
|
||||
{
|
||||
writer.WriteStartObject();
|
||||
writer.WritePropertyName("Street");
|
||||
writer.WriteValue(address.Street);
|
||||
writer.WritePropertyName("Phone");
|
||||
writer.WriteValue(address.Phone);
|
||||
writer.WritePropertyName("Entered");
|
||||
writer.WriteValue(address.Entered);
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
writer.WriteEndArray();
|
||||
writer.WriteEndObject();
|
||||
|
||||
writer.Flush();
|
||||
json = sw.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
json = string.Empty;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SerializeMethod.JsonNetBinary:
|
||||
{
|
||||
MemoryStream ms = new MemoryStream(Buffer);
|
||||
@@ -695,6 +760,14 @@ namespace Newtonsoft.Json.Tests
|
||||
BenchmarkSerializeMethod(SerializeMethod.JsonNetBinary, rootValue);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void SerializeUnicodeChars()
|
||||
{
|
||||
string s = (new string('\0', 30));
|
||||
|
||||
BenchmarkSerializeMethod(SerializeMethod.JsonNet, s);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void JObjectToString()
|
||||
{
|
||||
|
||||
@@ -35,6 +35,8 @@ namespace Newtonsoft.Json.Utilities
|
||||
{
|
||||
internal static class JavaScriptUtils
|
||||
{
|
||||
private const string EscapedUnicodeText = "!";
|
||||
|
||||
public static void WriteEscapedJavaScriptString(TextWriter writer, string s, char delimiter, bool appendDelimiters)
|
||||
{
|
||||
// leading delimiter
|
||||
@@ -44,6 +46,7 @@ namespace Newtonsoft.Json.Utilities
|
||||
if (s != null)
|
||||
{
|
||||
char[] chars = null;
|
||||
char[] unicodeBuffer = null;
|
||||
int lastWritePosition = 0;
|
||||
|
||||
for (int i = 0; i < s.Length; i++)
|
||||
@@ -94,7 +97,20 @@ namespace Newtonsoft.Json.Utilities
|
||||
escapedValue = "\\\"";
|
||||
break;
|
||||
default:
|
||||
escapedValue = (c <= '\u001f') ? StringUtils.ToCharAsUnicode(c) : null;
|
||||
if (c <= '\u001f')
|
||||
{
|
||||
if (unicodeBuffer == null)
|
||||
unicodeBuffer = new char[6];
|
||||
|
||||
StringUtils.ToCharAsUnicode(c, unicodeBuffer);
|
||||
|
||||
// slightly hacky but it saves multiple conditions in if test
|
||||
escapedValue = EscapedUnicodeText;
|
||||
}
|
||||
else
|
||||
{
|
||||
escapedValue = null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -111,7 +127,10 @@ namespace Newtonsoft.Json.Utilities
|
||||
}
|
||||
|
||||
lastWritePosition = i + 1;
|
||||
writer.Write(escapedValue);
|
||||
if (!string.Equals(escapedValue, EscapedUnicodeText))
|
||||
writer.Write(escapedValue);
|
||||
else
|
||||
writer.Write(unicodeBuffer);
|
||||
}
|
||||
|
||||
if (lastWritePosition == 0)
|
||||
|
||||
@@ -45,9 +45,8 @@ namespace Newtonsoft.Json.Utilities
|
||||
public static char IntToHex(int n)
|
||||
{
|
||||
if (n <= 9)
|
||||
{
|
||||
return (char)(n + 48);
|
||||
}
|
||||
|
||||
return (char)((n - 10) + 97);
|
||||
}
|
||||
|
||||
|
||||
@@ -117,14 +117,14 @@ namespace Newtonsoft.Json.Utilities
|
||||
return value.Length;
|
||||
}
|
||||
|
||||
public static string ToCharAsUnicode(char c)
|
||||
public static void ToCharAsUnicode(char c, char[] buffer)
|
||||
{
|
||||
char h1 = MathUtils.IntToHex((c >> 12) & '\x000f');
|
||||
char h2 = MathUtils.IntToHex((c >> 8) & '\x000f');
|
||||
char h3 = MathUtils.IntToHex((c >> 4) & '\x000f');
|
||||
char h4 = MathUtils.IntToHex(c & '\x000f');
|
||||
|
||||
return new string(new[] { '\\', 'u', h1, h2, h3, h4 });
|
||||
buffer[0] = '\\';
|
||||
buffer[1] = 'u';
|
||||
buffer[2] = MathUtils.IntToHex((c >> 12) & '\x000f');
|
||||
buffer[3] = MathUtils.IntToHex((c >> 8) & '\x000f');
|
||||
buffer[4] = MathUtils.IntToHex((c >> 4) & '\x000f');
|
||||
buffer[5] = MathUtils.IntToHex(c & '\x000f');
|
||||
}
|
||||
|
||||
public static TSource ForgivingCaseSensitiveFind<TSource>(this IEnumerable<TSource> source, Func<TSource, string> valueSelector, string testValue)
|
||||
|
||||
Reference in New Issue
Block a user