-Added IJsonBufferPool, performance stuff
This commit is contained in:
@@ -44,6 +44,11 @@ using NUnit.Framework;
|
||||
#endif
|
||||
using Newtonsoft.Json;
|
||||
using System.IO;
|
||||
#if NET20
|
||||
using Newtonsoft.Json.Utilities.LinqBridge;
|
||||
#else
|
||||
using System.Linq;
|
||||
#endif
|
||||
using System.Xml;
|
||||
using Newtonsoft.Json.Utilities;
|
||||
|
||||
@@ -1168,6 +1173,74 @@ third line", jsonTextReader.Value);
|
||||
Assert.AreEqual("type", reader.Value);
|
||||
}
|
||||
|
||||
public class FakeBufferPool : IJsonBufferPool<char>
|
||||
{
|
||||
public readonly IList<char[]> FreeBuffers = new List<char[]>();
|
||||
public readonly IList<char[]> UsedBuffers = new List<char[]>();
|
||||
|
||||
public char[] RentBuffer(int minSize)
|
||||
{
|
||||
char[] buffer = FreeBuffers.FirstOrDefault(b => b.Length >= minSize);
|
||||
if (buffer != null)
|
||||
{
|
||||
FreeBuffers.Remove(buffer);
|
||||
UsedBuffers.Add(buffer);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
buffer = new char[minSize];
|
||||
UsedBuffers.Add(buffer);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public void ReturnBuffer(ref char[] buffer)
|
||||
{
|
||||
UsedBuffers.Remove(buffer);
|
||||
if (!FreeBuffers.Contains(buffer))
|
||||
{
|
||||
FreeBuffers.Add(buffer);
|
||||
}
|
||||
|
||||
buffer = null;
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void BufferTest()
|
||||
{
|
||||
string json = @"{
|
||||
""CPU"": ""Intel"",
|
||||
""Description"": ""Amazing!\nBuy now!"",
|
||||
""Drives"": [
|
||||
""DVD read/writer"",
|
||||
""500 gigabyte hard drive""
|
||||
]
|
||||
}";
|
||||
|
||||
FakeBufferPool bufferPool = new FakeBufferPool();
|
||||
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
using (JsonTextReader reader = new JsonTextReader(new StringReader(json)))
|
||||
{
|
||||
reader.BufferPool = bufferPool;
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
if ((i + 1) % 100 == 0)
|
||||
{
|
||||
Console.WriteLine("Allocated buffers: " + bufferPool.FreeBuffers.Count);
|
||||
}
|
||||
}
|
||||
|
||||
Assert.AreEqual(2, bufferPool.FreeBuffers.Count);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ReadNullTerminatorStrings()
|
||||
{
|
||||
|
||||
@@ -1271,7 +1271,7 @@ _____'propertyName': NaN,
|
||||
{
|
||||
StringWriter swNew = new StringWriter();
|
||||
char[] buffer = null;
|
||||
JavaScriptUtils.WriteEscapedJavaScriptString(swNew, c.ToString(), '"', true, JavaScriptUtils.DoubleQuoteCharEscapeFlags, StringEscapeHandling.Default, ref buffer);
|
||||
JavaScriptUtils.WriteEscapedJavaScriptString(swNew, c.ToString(), '"', true, JavaScriptUtils.DoubleQuoteCharEscapeFlags, StringEscapeHandling.Default, null, ref buffer);
|
||||
|
||||
StringWriter swOld = new StringWriter();
|
||||
WriteEscapedJavaScriptStringOld(swOld, c.ToString(), '"', true);
|
||||
|
||||
@@ -430,7 +430,7 @@ If attributes are not mentioned, default values are used in each case.
|
||||
using (StringWriter w = StringUtils.CreateStringWriter(StringUtils.GetLength(text) ?? 16))
|
||||
{
|
||||
char[] buffer = null;
|
||||
JavaScriptUtils.WriteEscapedJavaScriptString(w, text, '"', true, JavaScriptUtils.DoubleQuoteCharEscapeFlags, StringEscapeHandling.Default, ref buffer);
|
||||
JavaScriptUtils.WriteEscapedJavaScriptString(w, text, '"', true, JavaScriptUtils.DoubleQuoteCharEscapeFlags, StringEscapeHandling.Default, null, ref buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -136,5 +136,60 @@ namespace Newtonsoft.Json.Tests.Utilities
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void HexParse()
|
||||
{
|
||||
HexParseSame("0000");
|
||||
HexParseSame("1234");
|
||||
HexParseSame("4321");
|
||||
HexParseSame("abcd");
|
||||
HexParseSame("dcba");
|
||||
HexParseSame("ffff");
|
||||
HexParseSame("ABCD");
|
||||
HexParseSame("DCBA");
|
||||
HexParseSame("FFFF");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void HexParseOffset()
|
||||
{
|
||||
int value = ConvertUtils.HexTextToInt("!0000".ToCharArray(), 1, 5);
|
||||
Assert.AreEqual(0, value);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void HexParseError()
|
||||
{
|
||||
ExceptionAssert.Throws<FormatException>(() =>
|
||||
{
|
||||
ConvertUtils.HexTextToInt("-100".ToCharArray(), 0, 4);
|
||||
}, "Invalid hex character: -");
|
||||
ExceptionAssert.Throws<FormatException>(() =>
|
||||
{
|
||||
ConvertUtils.HexTextToInt("000g".ToCharArray(), 0, 4);
|
||||
}, "Invalid hex character: g");
|
||||
ExceptionAssert.Throws<FormatException>(() =>
|
||||
{
|
||||
ConvertUtils.HexTextToInt(" ssd".ToCharArray(), 0, 4);
|
||||
}, "Invalid hex character: ");
|
||||
ExceptionAssert.Throws<FormatException>(() =>
|
||||
{
|
||||
ConvertUtils.HexTextToInt("000:".ToCharArray(), 0, 4);
|
||||
}, "Invalid hex character: :");
|
||||
ExceptionAssert.Throws<FormatException>(() =>
|
||||
{
|
||||
ConvertUtils.HexTextToInt("000G".ToCharArray(), 0, 4);
|
||||
}, "Invalid hex character: G");
|
||||
}
|
||||
|
||||
private void HexParseSame(string text)
|
||||
{
|
||||
int v1 = int.Parse(text, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
|
||||
|
||||
int v2 = ConvertUtils.HexTextToInt(text.ToCharArray(), 0, 4);
|
||||
|
||||
Assert.AreEqual(v1, v2, "Invalid result when parsing hex text: " + text);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,9 @@
|
||||
"exclude": [
|
||||
],
|
||||
"dependencies": {
|
||||
"Newtonsoft.Json": ""
|
||||
"Newtonsoft.Json": {
|
||||
"target": "project"
|
||||
}
|
||||
},
|
||||
"commands": {
|
||||
"test": "xunit.runner.dnx -parallel none"
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
namespace Newtonsoft.Json
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides an interface for using pooled buffers.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The buffer type content.</typeparam>
|
||||
public interface IJsonBufferPool<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// Rent a buffer from the pool. This buffer must be returned when it is no longer needed.
|
||||
/// </summary>
|
||||
/// <param name="minSize">The minimum required size of the buffer. The returned buffer may be larger.</param>
|
||||
/// <returns>The rented buffer from the pool.</returns>
|
||||
T[] RentBuffer(int minSize);
|
||||
|
||||
/// <summary>
|
||||
/// Return a buffer to the pool.
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer that is being returned.</param>
|
||||
void ReturnBuffer(ref T[] buffer);
|
||||
}
|
||||
}
|
||||
@@ -173,7 +173,15 @@ namespace Newtonsoft.Json
|
||||
public DateTimeZoneHandling DateTimeZoneHandling
|
||||
{
|
||||
get { return _dateTimeZoneHandling; }
|
||||
set { _dateTimeZoneHandling = value; }
|
||||
set
|
||||
{
|
||||
if (value < DateTimeZoneHandling.Local || value > DateTimeZoneHandling.RoundtripKind)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("value");
|
||||
}
|
||||
|
||||
_dateTimeZoneHandling = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -182,7 +190,21 @@ namespace Newtonsoft.Json
|
||||
public DateParseHandling DateParseHandling
|
||||
{
|
||||
get { return _dateParseHandling; }
|
||||
set { _dateParseHandling = value; }
|
||||
set
|
||||
{
|
||||
if (value < DateParseHandling.None ||
|
||||
#if !NET20
|
||||
value > DateParseHandling.DateTimeOffset
|
||||
#else
|
||||
value > DateParseHandling.DateTime
|
||||
#endif
|
||||
)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("value");
|
||||
}
|
||||
|
||||
_dateParseHandling = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -191,7 +213,15 @@ namespace Newtonsoft.Json
|
||||
public FloatParseHandling FloatParseHandling
|
||||
{
|
||||
get { return _floatParseHandling; }
|
||||
set { _floatParseHandling = value; }
|
||||
set
|
||||
{
|
||||
if (value < FloatParseHandling.Double || value > FloatParseHandling.Decimal)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("value");
|
||||
}
|
||||
|
||||
_floatParseHandling = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -54,7 +54,6 @@ namespace Newtonsoft.Json
|
||||
{
|
||||
private const char UnicodeReplacementChar = '\uFFFD';
|
||||
private const int MaximumJavascriptIntegerCharacterLength = 380;
|
||||
|
||||
private readonly TextReader _reader;
|
||||
private char[] _chars;
|
||||
private int _charsUsed;
|
||||
@@ -62,8 +61,9 @@ namespace Newtonsoft.Json
|
||||
private int _lineStartPos;
|
||||
private int _lineNumber;
|
||||
private bool _isEndOfFile;
|
||||
private StringBuffer _buffer;
|
||||
private StringBuffer _stringBuffer;
|
||||
private StringReference _stringReference;
|
||||
private IJsonBufferPool<char> _bufferPool;
|
||||
internal PropertyNameTable NameTable;
|
||||
|
||||
/// <summary>
|
||||
@@ -77,7 +77,6 @@ namespace Newtonsoft.Json
|
||||
|
||||
_reader = reader;
|
||||
_lineNumber = 1;
|
||||
_chars = new char[1025];
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
@@ -87,18 +86,29 @@ namespace Newtonsoft.Json
|
||||
}
|
||||
#endif
|
||||
|
||||
private StringBuffer GetBuffer()
|
||||
/// <summary>
|
||||
/// Gets or sets the reader's character buffer pool.
|
||||
/// </summary>
|
||||
public IJsonBufferPool<char> BufferPool
|
||||
{
|
||||
if (_buffer == null)
|
||||
get { return _bufferPool; }
|
||||
set
|
||||
{
|
||||
_buffer = new StringBuffer(1025);
|
||||
}
|
||||
else
|
||||
{
|
||||
_buffer.Position = 0;
|
||||
}
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException("value");
|
||||
}
|
||||
|
||||
return _buffer;
|
||||
_bufferPool = value;
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsureBufferNotEmpty()
|
||||
{
|
||||
if (_stringBuffer.IsEmpty)
|
||||
{
|
||||
_stringBuffer = new StringBuffer(_bufferPool, 1025);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnNewLine(int pos)
|
||||
@@ -214,10 +224,12 @@ namespace Newtonsoft.Json
|
||||
int newArrayLength = Math.Max(_chars.Length * 2, _charsUsed + charsRequired + 1);
|
||||
|
||||
// increase the size of the buffer
|
||||
char[] dst = new char[newArrayLength];
|
||||
char[] dst = BufferUtils.RentBuffer(_bufferPool, newArrayLength);
|
||||
|
||||
BlockCopyChars(_chars, 0, dst, 0, _chars.Length);
|
||||
|
||||
BufferUtils.ReturnBuffer(_bufferPool, ref _chars);
|
||||
|
||||
_chars = dst;
|
||||
}
|
||||
else
|
||||
@@ -227,11 +239,13 @@ namespace Newtonsoft.Json
|
||||
if (remainingCharCount + charsRequired + 1 >= _chars.Length)
|
||||
{
|
||||
// the remaining count plus the required is bigger than the current buffer size
|
||||
char[] dst = new char[remainingCharCount + charsRequired + 1];
|
||||
char[] dst = BufferUtils.RentBuffer(_bufferPool, remainingCharCount + charsRequired + 1);
|
||||
|
||||
if (remainingCharCount > 0)
|
||||
BlockCopyChars(_chars, _charPos, dst, 0, remainingCharCount);
|
||||
|
||||
BufferUtils.ReturnBuffer(_bufferPool, ref _chars);
|
||||
|
||||
_chars = dst;
|
||||
}
|
||||
else
|
||||
@@ -374,6 +388,11 @@ namespace Newtonsoft.Json
|
||||
|
||||
internal override bool ReadInternal()
|
||||
{
|
||||
if (_chars == null)
|
||||
{
|
||||
_chars = BufferUtils.RentBuffer(_bufferPool, 1024);
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
switch (_currentState)
|
||||
@@ -422,7 +441,7 @@ namespace Newtonsoft.Json
|
||||
int charPos = _charPos;
|
||||
int initialPosition = _charPos;
|
||||
int lastWritePosition = _charPos;
|
||||
StringBuffer buffer = null;
|
||||
_stringBuffer.Position = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
@@ -530,10 +549,9 @@ namespace Newtonsoft.Json
|
||||
highSurrogate = UnicodeReplacementChar;
|
||||
}
|
||||
|
||||
if (buffer == null)
|
||||
buffer = GetBuffer();
|
||||
EnsureBufferNotEmpty();
|
||||
|
||||
WriteCharToBuffer(buffer, highSurrogate, lastWritePosition, escapeStartPos);
|
||||
WriteCharToBuffer(highSurrogate, lastWritePosition, escapeStartPos);
|
||||
lastWritePosition = _charPos;
|
||||
}
|
||||
else
|
||||
@@ -553,10 +571,8 @@ namespace Newtonsoft.Json
|
||||
throw JsonReaderException.Create(this, "Bad JSON escape sequence: {0}.".FormatWith(CultureInfo.InvariantCulture, @"\" + currentChar));
|
||||
}
|
||||
|
||||
if (buffer == null)
|
||||
buffer = GetBuffer();
|
||||
|
||||
WriteCharToBuffer(buffer, writeChar, lastWritePosition, escapeStartPos);
|
||||
EnsureBufferNotEmpty();
|
||||
WriteCharToBuffer(writeChar, lastWritePosition, escapeStartPos);
|
||||
|
||||
lastWritePosition = charPos;
|
||||
break;
|
||||
@@ -582,13 +598,14 @@ namespace Newtonsoft.Json
|
||||
}
|
||||
else
|
||||
{
|
||||
if (buffer == null)
|
||||
buffer = GetBuffer();
|
||||
EnsureBufferNotEmpty();
|
||||
|
||||
if (charPos > lastWritePosition)
|
||||
buffer.Append(_chars, lastWritePosition, charPos - lastWritePosition);
|
||||
{
|
||||
_stringBuffer.Append(_bufferPool, _chars, lastWritePosition, charPos - lastWritePosition);
|
||||
}
|
||||
|
||||
_stringReference = new StringReference(buffer.GetInternalBuffer(), 0, buffer.Position);
|
||||
_stringReference = new StringReference(_stringBuffer.InternalBuffer, 0, _stringBuffer.Position);
|
||||
}
|
||||
|
||||
charPos++;
|
||||
@@ -600,14 +617,14 @@ namespace Newtonsoft.Json
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteCharToBuffer(StringBuffer buffer, char writeChar, int lastWritePosition, int writeToPosition)
|
||||
private void WriteCharToBuffer(char writeChar, int lastWritePosition, int writeToPosition)
|
||||
{
|
||||
if (writeToPosition > lastWritePosition)
|
||||
{
|
||||
buffer.Append(_chars, lastWritePosition, writeToPosition - lastWritePosition);
|
||||
_stringBuffer.Append(_bufferPool, _chars, lastWritePosition, writeToPosition - lastWritePosition);
|
||||
}
|
||||
|
||||
buffer.Append(writeChar);
|
||||
_stringBuffer.Append(_bufferPool, writeChar);
|
||||
}
|
||||
|
||||
private char ParseUnicode()
|
||||
@@ -615,8 +632,7 @@ namespace Newtonsoft.Json
|
||||
char writeChar;
|
||||
if (EnsureChars(4, true))
|
||||
{
|
||||
string hexValues = new string(_chars, _charPos, 4);
|
||||
char hexChar = Convert.ToChar(int.Parse(hexValues, NumberStyles.HexNumber, NumberFormatInfo.InvariantInfo));
|
||||
char hexChar = Convert.ToChar(ConvertUtils.HexTextToInt(_chars, _charPos, _charPos + 4));
|
||||
writeChar = hexChar;
|
||||
|
||||
_charPos += 4;
|
||||
@@ -699,9 +715,7 @@ namespace Newtonsoft.Json
|
||||
|
||||
private void ClearRecentString()
|
||||
{
|
||||
if (_buffer != null)
|
||||
_buffer.Position = 0;
|
||||
|
||||
_stringBuffer.Position = 0;
|
||||
_stringReference = new StringReference();
|
||||
}
|
||||
|
||||
@@ -1623,6 +1637,11 @@ namespace Newtonsoft.Json
|
||||
{
|
||||
base.Close();
|
||||
|
||||
if (_chars != null)
|
||||
{
|
||||
BufferUtils.ReturnBuffer(_bufferPool, ref _chars);
|
||||
}
|
||||
|
||||
if (CloseInput && _reader != null)
|
||||
{
|
||||
#if !(DOTNET || PORTABLE40 || PORTABLE)
|
||||
@@ -1632,8 +1651,7 @@ namespace Newtonsoft.Json
|
||||
#endif
|
||||
}
|
||||
|
||||
if (_buffer != null)
|
||||
_buffer.Clear();
|
||||
_stringBuffer.Clear(_bufferPool);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -49,6 +49,7 @@ namespace Newtonsoft.Json
|
||||
private bool _quoteName;
|
||||
private bool[] _charEscapeFlags;
|
||||
private char[] _writeBuffer;
|
||||
private IJsonBufferPool<char> _bufferPool;
|
||||
private char[] _indentChars;
|
||||
|
||||
private Base64Encoder Base64Encoder
|
||||
@@ -62,6 +63,23 @@ namespace Newtonsoft.Json
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the writer's character buffer pool.
|
||||
/// </summary>
|
||||
public IJsonBufferPool<char> BufferPool
|
||||
{
|
||||
get { return _bufferPool; }
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
throw new ArgumentNullException("value");
|
||||
}
|
||||
|
||||
_bufferPool = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets how many IndentChars to write for each level in the hierarchy when <see cref="Formatting"/> is set to <c>Formatting.Indented</c>.
|
||||
/// </summary>
|
||||
@@ -151,6 +169,8 @@ namespace Newtonsoft.Json
|
||||
{
|
||||
base.Close();
|
||||
|
||||
BufferUtils.ReturnBuffer(_bufferPool, ref _writeBuffer);
|
||||
|
||||
if (CloseOutput && _writer != null)
|
||||
{
|
||||
#if !(DOTNET || PORTABLE40 || PORTABLE)
|
||||
@@ -380,7 +400,7 @@ namespace Newtonsoft.Json
|
||||
private void WriteEscapedString(string value, bool quote)
|
||||
{
|
||||
EnsureWriteBuffer();
|
||||
JavaScriptUtils.WriteEscapedJavaScriptString(_writer, value, _quoteChar, quote, _charEscapeFlags, StringEscapeHandling, ref _writeBuffer);
|
||||
JavaScriptUtils.WriteEscapedJavaScriptString(_writer, value, _quoteChar, quote, _charEscapeFlags, StringEscapeHandling, _bufferPool, ref _writeBuffer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -714,7 +734,10 @@ namespace Newtonsoft.Json
|
||||
private void EnsureWriteBuffer()
|
||||
{
|
||||
if (_writeBuffer == null)
|
||||
_writeBuffer = new char[35]; // maximum buffer sized used when writing iso date
|
||||
{
|
||||
// maximum buffer sized used when writing iso date
|
||||
_writeBuffer = BufferUtils.RentBuffer(_bufferPool, 35);
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteIntegerValue(long value)
|
||||
|
||||
@@ -222,7 +222,15 @@ namespace Newtonsoft.Json
|
||||
public Formatting Formatting
|
||||
{
|
||||
get { return _formatting; }
|
||||
set { _formatting = value; }
|
||||
set
|
||||
{
|
||||
if (value < Formatting.None || value > Formatting.Indented)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("value");
|
||||
}
|
||||
|
||||
_formatting = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -231,7 +239,15 @@ namespace Newtonsoft.Json
|
||||
public DateFormatHandling DateFormatHandling
|
||||
{
|
||||
get { return _dateFormatHandling; }
|
||||
set { _dateFormatHandling = value; }
|
||||
set
|
||||
{
|
||||
if (value < DateFormatHandling.IsoDateFormat || value > DateFormatHandling.MicrosoftDateFormat)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("value");
|
||||
}
|
||||
|
||||
_dateFormatHandling = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -240,7 +256,15 @@ namespace Newtonsoft.Json
|
||||
public DateTimeZoneHandling DateTimeZoneHandling
|
||||
{
|
||||
get { return _dateTimeZoneHandling; }
|
||||
set { _dateTimeZoneHandling = value; }
|
||||
set
|
||||
{
|
||||
if (value < DateTimeZoneHandling.Local || value > DateTimeZoneHandling.RoundtripKind)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("value");
|
||||
}
|
||||
|
||||
_dateTimeZoneHandling = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -251,6 +275,11 @@ namespace Newtonsoft.Json
|
||||
get { return _stringEscapeHandling; }
|
||||
set
|
||||
{
|
||||
if (value < StringEscapeHandling.Default || value > StringEscapeHandling.EscapeHtml)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("value");
|
||||
}
|
||||
|
||||
_stringEscapeHandling = value;
|
||||
OnStringEscapeHandlingChanged();
|
||||
}
|
||||
@@ -269,7 +298,15 @@ namespace Newtonsoft.Json
|
||||
public FloatFormatHandling FloatFormatHandling
|
||||
{
|
||||
get { return _floatFormatHandling; }
|
||||
set { _floatFormatHandling = value; }
|
||||
set
|
||||
{
|
||||
if (value < FloatFormatHandling.String || value > FloatFormatHandling.DefaultValue)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("value");
|
||||
}
|
||||
|
||||
_floatFormatHandling = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -103,6 +103,7 @@
|
||||
<Compile Include="FloatParseHandling.cs" />
|
||||
<Compile Include="FormatterAssemblyStyle.cs" />
|
||||
<Compile Include="Formatting.cs" />
|
||||
<Compile Include="IJsonBufferPool.cs" />
|
||||
<Compile Include="JsonConstructorAttribute.cs" />
|
||||
<Compile Include="JsonDictionaryAttribute.cs" />
|
||||
<Compile Include="JsonException.cs" />
|
||||
|
||||
@@ -116,6 +116,7 @@
|
||||
<Compile Include="FloatParseHandling.cs" />
|
||||
<Compile Include="FormatterAssemblyStyle.cs" />
|
||||
<Compile Include="Formatting.cs" />
|
||||
<Compile Include="IJsonBufferPool.cs" />
|
||||
<Compile Include="JsonConstructorAttribute.cs" />
|
||||
<Compile Include="JsonDictionaryAttribute.cs" />
|
||||
<Compile Include="JsonException.cs" />
|
||||
|
||||
@@ -113,6 +113,7 @@
|
||||
<Compile Include="Converters\VersionConverter.cs" />
|
||||
<Compile Include="FloatFormatHandling.cs" />
|
||||
<Compile Include="FloatParseHandling.cs" />
|
||||
<Compile Include="IJsonBufferPool.cs" />
|
||||
<Compile Include="JsonDictionaryAttribute.cs" />
|
||||
<Compile Include="JsonException.cs" />
|
||||
<Compile Include="DateFormatHandling.cs" />
|
||||
|
||||
@@ -77,6 +77,7 @@
|
||||
<Compile Include="FloatParseHandling.cs" />
|
||||
<Compile Include="FormatterAssemblyStyle.cs" />
|
||||
<Compile Include="Formatting.cs" />
|
||||
<Compile Include="IJsonBufferPool.cs" />
|
||||
<Compile Include="IJsonLineInfo.cs" />
|
||||
<Compile Include="JsonArrayAttribute.cs" />
|
||||
<Compile Include="JsonConstructorAttribute.cs" />
|
||||
|
||||
@@ -82,6 +82,7 @@
|
||||
<Compile Include="FloatParseHandling.cs" />
|
||||
<Compile Include="FormatterAssemblyStyle.cs" />
|
||||
<Compile Include="Formatting.cs" />
|
||||
<Compile Include="IJsonBufferPool.cs" />
|
||||
<Compile Include="IJsonLineInfo.cs" />
|
||||
<Compile Include="JsonArrayAttribute.cs" />
|
||||
<Compile Include="JsonConstructorAttribute.cs" />
|
||||
|
||||
@@ -81,6 +81,7 @@
|
||||
<Compile Include="FloatFormatHandling.cs" />
|
||||
<Compile Include="FormatterAssemblyStyle.cs" />
|
||||
<Compile Include="Formatting.cs" />
|
||||
<Compile Include="IJsonBufferPool.cs" />
|
||||
<Compile Include="IJsonLineInfo.cs" />
|
||||
<Compile Include="JsonArrayAttribute.cs" />
|
||||
<Compile Include="JsonConstructorAttribute.cs" />
|
||||
|
||||
@@ -858,5 +858,35 @@ namespace Newtonsoft.Json.Utilities
|
||||
return Guid.TryParseExact(s, "D", out g);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static int HexTextToInt(char[] text, int start, int end)
|
||||
{
|
||||
int value = 0;
|
||||
for (int i = start; i < end; i++)
|
||||
{
|
||||
value += HexCharToInt(text[i]) << ((end - 1 - i) * 4);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private static int HexCharToInt(char ch)
|
||||
{
|
||||
if (ch <= 57 && ch >= 48)
|
||||
{
|
||||
return ch - 48;
|
||||
}
|
||||
|
||||
if (ch <= 70 && ch >= 65)
|
||||
{
|
||||
return ch - 55;
|
||||
}
|
||||
|
||||
if (ch <= 102 && ch >= 97)
|
||||
{
|
||||
return ch - 87;
|
||||
}
|
||||
|
||||
throw new FormatException("Invalid hex character: " + ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,46 @@ using System.Linq;
|
||||
|
||||
namespace Newtonsoft.Json.Utilities
|
||||
{
|
||||
internal static class BufferUtils
|
||||
{
|
||||
public static char[] RentBuffer(IJsonBufferPool<char> bufferPool, int minSize)
|
||||
{
|
||||
if (bufferPool == null)
|
||||
{
|
||||
return new char[minSize];
|
||||
}
|
||||
|
||||
return bufferPool.RentBuffer(minSize);
|
||||
}
|
||||
|
||||
public static void ReturnBuffer(IJsonBufferPool<char> bufferPool, ref char[] buffer)
|
||||
{
|
||||
if (bufferPool == null)
|
||||
{
|
||||
buffer = null;
|
||||
return;
|
||||
}
|
||||
|
||||
bufferPool.ReturnBuffer(ref buffer);
|
||||
}
|
||||
|
||||
public static void EnsureBufferSize(IJsonBufferPool<char> bufferPool, int size, ref char[] buffer)
|
||||
{
|
||||
if (bufferPool == null)
|
||||
{
|
||||
buffer = new char[size];
|
||||
return;
|
||||
}
|
||||
|
||||
if (buffer != null)
|
||||
{
|
||||
bufferPool.ReturnBuffer(ref buffer);
|
||||
}
|
||||
|
||||
buffer = bufferPool.RentBuffer(size);
|
||||
}
|
||||
}
|
||||
|
||||
internal static class JavaScriptUtils
|
||||
{
|
||||
internal static readonly bool[] SingleQuoteCharEscapeFlags = new bool[128];
|
||||
@@ -100,7 +140,7 @@ namespace Newtonsoft.Json.Utilities
|
||||
}
|
||||
|
||||
public static void WriteEscapedJavaScriptString(TextWriter writer, string s, char delimiter, bool appendDelimiters,
|
||||
bool[] charEscapeFlags, StringEscapeHandling stringEscapeHandling, ref char[] writeBuffer)
|
||||
bool[] charEscapeFlags, StringEscapeHandling stringEscapeHandling, IJsonBufferPool<char> bufferPool, ref char[] writeBuffer)
|
||||
{
|
||||
// leading delimiter
|
||||
if (appendDelimiters)
|
||||
@@ -162,7 +202,9 @@ namespace Newtonsoft.Json.Utilities
|
||||
else
|
||||
{
|
||||
if (writeBuffer == null || writeBuffer.Length < UnicodeTextLength)
|
||||
writeBuffer = new char[UnicodeTextLength];
|
||||
{
|
||||
BufferUtils.EnsureBufferSize(bufferPool, UnicodeTextLength, ref writeBuffer);
|
||||
}
|
||||
|
||||
StringUtils.ToCharAsUnicode(c, writeBuffer);
|
||||
|
||||
@@ -189,13 +231,15 @@ namespace Newtonsoft.Json.Utilities
|
||||
|
||||
if (writeBuffer == null || writeBuffer.Length < length)
|
||||
{
|
||||
char[] newBuffer = new char[length];
|
||||
char[] newBuffer = BufferUtils.RentBuffer(bufferPool, length);
|
||||
|
||||
// the unicode text is already in the buffer
|
||||
// copy it over when creating new buffer
|
||||
if (isEscapedUnicodeText)
|
||||
Array.Copy(writeBuffer, newBuffer, UnicodeTextLength);
|
||||
|
||||
BufferUtils.ReturnBuffer(bufferPool, ref writeBuffer);
|
||||
|
||||
writeBuffer = newBuffer;
|
||||
}
|
||||
|
||||
@@ -248,7 +292,7 @@ namespace Newtonsoft.Json.Utilities
|
||||
using (StringWriter w = StringUtils.CreateStringWriter(StringUtils.GetLength(value) ?? 16))
|
||||
{
|
||||
char[] buffer = null;
|
||||
WriteEscapedJavaScriptString(w, value, delimiter, appendDelimiters, charEscapeFlags, stringEscapeHandling, ref buffer);
|
||||
WriteEscapedJavaScriptString(w, value, delimiter, appendDelimiters, charEscapeFlags, stringEscapeHandling, null, ref buffer);
|
||||
return w.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,60 +30,75 @@ namespace Newtonsoft.Json.Utilities
|
||||
/// <summary>
|
||||
/// Builds a string. Unlike StringBuilder this class lets you reuse it's internal buffer.
|
||||
/// </summary>
|
||||
internal class StringBuffer
|
||||
internal struct StringBuffer
|
||||
{
|
||||
private char[] _buffer;
|
||||
private int _position;
|
||||
|
||||
private static readonly char[] EmptyBuffer = new char[0];
|
||||
|
||||
public int Position
|
||||
{
|
||||
get { return _position; }
|
||||
set { _position = value; }
|
||||
}
|
||||
|
||||
public StringBuffer()
|
||||
public bool IsEmpty
|
||||
{
|
||||
_buffer = EmptyBuffer;
|
||||
get { return _buffer == null; }
|
||||
}
|
||||
|
||||
public StringBuffer(int initalSize)
|
||||
public StringBuffer(IJsonBufferPool<char> bufferPool, int initalSize) : this(BufferUtils.RentBuffer(bufferPool, initalSize))
|
||||
{
|
||||
_buffer = new char[initalSize];
|
||||
}
|
||||
|
||||
public void Append(char value)
|
||||
private StringBuffer(char[] buffer)
|
||||
{
|
||||
_buffer = buffer;
|
||||
_position = 0;
|
||||
}
|
||||
|
||||
public void Append(IJsonBufferPool<char> bufferPool, char value)
|
||||
{
|
||||
// test if the buffer array is large enough to take the value
|
||||
if (_position == _buffer.Length)
|
||||
EnsureSize(1);
|
||||
{
|
||||
EnsureSize(bufferPool, 1);
|
||||
}
|
||||
|
||||
// set value and increment poisition
|
||||
_buffer[_position++] = value;
|
||||
}
|
||||
|
||||
public void Append(char[] buffer, int startIndex, int count)
|
||||
public void Append(IJsonBufferPool<char> bufferPool, char[] buffer, int startIndex, int count)
|
||||
{
|
||||
if (_position + count >= _buffer.Length)
|
||||
EnsureSize(count);
|
||||
{
|
||||
EnsureSize(bufferPool, count);
|
||||
}
|
||||
|
||||
Array.Copy(buffer, startIndex, _buffer, _position, count);
|
||||
|
||||
_position += count;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
public void Clear(IJsonBufferPool<char> bufferPool)
|
||||
{
|
||||
_buffer = EmptyBuffer;
|
||||
if (_buffer != null)
|
||||
{
|
||||
BufferUtils.ReturnBuffer(bufferPool, ref _buffer);
|
||||
_buffer = null;
|
||||
}
|
||||
_position = 0;
|
||||
}
|
||||
|
||||
private void EnsureSize(int appendLength)
|
||||
private void EnsureSize(IJsonBufferPool<char> bufferPool, int appendLength)
|
||||
{
|
||||
char[] newBuffer = new char[(_position + appendLength) * 2];
|
||||
char[] newBuffer = BufferUtils.RentBuffer(bufferPool, (_position + appendLength) * 2);
|
||||
|
||||
Array.Copy(_buffer, newBuffer, _position);
|
||||
if (_buffer != null)
|
||||
{
|
||||
Array.Copy(_buffer, newBuffer, _position);
|
||||
BufferUtils.ReturnBuffer(bufferPool, ref _buffer);
|
||||
}
|
||||
|
||||
_buffer = newBuffer;
|
||||
}
|
||||
@@ -99,9 +114,9 @@ namespace Newtonsoft.Json.Utilities
|
||||
return new string(_buffer, start, length);
|
||||
}
|
||||
|
||||
public char[] GetInternalBuffer()
|
||||
public char[] InternalBuffer
|
||||
{
|
||||
return _buffer;
|
||||
get { return _buffer; }
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user