-Added IJsonBufferPool, performance stuff

This commit is contained in:
James Newton-King
2015-11-12 22:08:39 +13:00
parent d91e8f4425
commit ac1a46bd14
19 changed files with 425 additions and 70 deletions
@@ -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 -1
View File
@@ -3,7 +3,9 @@
"exclude": [
],
"dependencies": {
"Newtonsoft.Json": ""
"Newtonsoft.Json": {
"target": "project"
}
},
"commands": {
"test": "xunit.runner.dnx -parallel none"
+22
View File
@@ -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);
}
}
+33 -3
View File
@@ -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 -36
View File
@@ -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>
+25 -2
View File
@@ -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)
+41 -4
View File
@@ -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();
}
}
+33 -18
View File
@@ -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; }
}
}
}