From 0f455edb1eedc48543ebb8182933acfb69e885d9 Mon Sep 17 00:00:00 2001 From: Ahson Khan Date: Fri, 8 Jun 2018 16:47:10 -0700 Subject: [PATCH 1/8] Add support for BufferWriter to the JsonWriter --- .../System.Text.JsonLab.csproj | 1 + .../System/Text/Json/JsonWriter.cs | 166 +++++++++++++----- .../JsonWriterTests.cs | 26 ++- 3 files changed, 139 insertions(+), 54 deletions(-) diff --git a/src/System.Text.JsonLab/System.Text.JsonLab.csproj b/src/System.Text.JsonLab/System.Text.JsonLab.csproj index 1061cc23805..e70caf4e5c0 100644 --- a/src/System.Text.JsonLab/System.Text.JsonLab.csproj +++ b/src/System.Text.JsonLab/System.Text.JsonLab.csproj @@ -13,5 +13,6 @@ + diff --git a/src/System.Text.JsonLab/System/Text/Json/JsonWriter.cs b/src/System.Text.JsonLab/System/Text/Json/JsonWriter.cs index 1ae8875153d..eddcbca8569 100644 --- a/src/System.Text.JsonLab/System/Text/Json/JsonWriter.cs +++ b/src/System.Text.JsonLab/System/Text/Json/JsonWriter.cs @@ -3,30 +3,31 @@ using System.Buffers; using System.Buffers.Text; +using System.Buffers.Writer; using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace System.Text.JsonLab { - public struct JsonWriter + public ref struct JsonWriter { private static readonly byte[] s_newLineUtf8 = Encoding.UTF8.GetBytes(Environment.NewLine); private static readonly char[] s_newLineUtf16 = Environment.NewLine.ToCharArray(); - readonly bool _prettyPrint; - readonly IBufferWriter _bufferWriter; - readonly bool _isUtf8; + private readonly bool _prettyPrint; + private BufferWriter> _bufferWriter; + private readonly bool _isUtf8; - int _indent; - bool _firstItem; + private int _indent; + private bool _firstItem; /// /// Constructs a JSON writer with a specified . /// /// An instance of used for writing bytes to an output channel. /// Specifies whether to add whitespace to the output text for user readability. - public JsonWriter(IBufferWriter bufferWriter, bool isUtf8, bool prettyPrint = false) + public JsonWriter(BufferWriter> bufferWriter, bool isUtf8, bool prettyPrint = false) { _bufferWriter = bufferWriter; _prettyPrint = prettyPrint; @@ -58,7 +59,8 @@ public void WriteObjectStart() private void WriteStartUtf8(int bytesNeeded, byte token) { - Span byteBuffer = EnsureBuffer(bytesNeeded); + EnsureBuffer(bytesNeeded); + Span byteBuffer = _bufferWriter.Buffer; int idx = 0; if (!_firstItem) @@ -77,11 +79,13 @@ private void WriteStartUtf8(int bytesNeeded, byte token) byteBuffer[idx] = token; _bufferWriter.Advance(bytesNeeded); + _bufferWriter.Flush(); } private void WriteStartUtf16(int bytesNeeded, byte token) { - Span charBuffer = MemoryMarshal.Cast(EnsureBuffer(bytesNeeded)); + EnsureBuffer(bytesNeeded); + Span charBuffer = MemoryMarshal.Cast(_bufferWriter.Buffer); int idx = 0; if (!_firstItem) @@ -100,6 +104,7 @@ private void WriteStartUtf16(int bytesNeeded, byte token) charBuffer[idx] = (char)token; _bufferWriter.Advance(bytesNeeded); + _bufferWriter.Flush(); } /// @@ -129,7 +134,8 @@ public void WriteObjectStart(string name) private void WriteStartUtf8(ReadOnlySpan nameSpanByte, int bytesNeeded, byte token) { - Span byteBuffer = EnsureBuffer(bytesNeeded); + EnsureBuffer(bytesNeeded); + Span byteBuffer = _bufferWriter.Buffer; int idx = 0; if (!_firstItem) @@ -159,12 +165,14 @@ private void WriteStartUtf8(ReadOnlySpan nameSpanByte, int bytesNeeded, by byteBuffer[idx++] = token; _bufferWriter.Advance(idx); + _bufferWriter.Flush(); _firstItem = false; } private void WriteStartUtf16(ReadOnlySpan nameSpanChar, int bytesNeeded, byte token) { - Span charBuffer = MemoryMarshal.Cast(EnsureBuffer(bytesNeeded)); + EnsureBuffer(bytesNeeded); + Span charBuffer = MemoryMarshal.Cast(_bufferWriter.Buffer); int idx = 0; if (!_firstItem) @@ -189,6 +197,7 @@ private void WriteStartUtf16(ReadOnlySpan nameSpanChar, int bytesNeeded, b charBuffer[idx] = (char)token; _bufferWriter.Advance(bytesNeeded); + _bufferWriter.Flush(); _firstItem = false; } @@ -211,7 +220,8 @@ public void WriteObjectEnd() private void WriteEndUtf8(int bytesNeeded, byte token) { - Span byteBuffer = EnsureBuffer(bytesNeeded); + EnsureBuffer(bytesNeeded); + Span byteBuffer = _bufferWriter.Buffer; int idx = 0; if (_prettyPrint) @@ -219,11 +229,13 @@ private void WriteEndUtf8(int bytesNeeded, byte token) byteBuffer[idx] = token; _bufferWriter.Advance(bytesNeeded); + _bufferWriter.Flush(); } private void WriteEndUtf16(int bytesNeeded, byte token) { - Span charBuffer = MemoryMarshal.Cast(EnsureBuffer(bytesNeeded)); + EnsureBuffer(bytesNeeded); + Span charBuffer = MemoryMarshal.Cast(_bufferWriter.Buffer); int idx = 0; if (_prettyPrint) @@ -231,6 +243,7 @@ private void WriteEndUtf16(int bytesNeeded, byte token) charBuffer[idx] = (char)token; _bufferWriter.Advance(bytesNeeded); + _bufferWriter.Flush(); } /// @@ -321,7 +334,8 @@ public void WriteAttribute(string name, string value) private void WriteAttributeUtf8(ReadOnlySpan nameSpanByte, ReadOnlySpan valueSpanByte, int bytesNeeded) { - Span byteBuffer = EnsureBuffer(bytesNeeded); + EnsureBuffer(bytesNeeded); + Span byteBuffer = _bufferWriter.Buffer; int idx = 0; if (!_firstItem) @@ -361,12 +375,14 @@ private void WriteAttributeUtf8(ReadOnlySpan nameSpanByte, ReadOnlySpan nameSpanChar, ReadOnlySpan valueSpanChar, int bytesNeeded) { - Span charBuffer = MemoryMarshal.Cast(EnsureBuffer(bytesNeeded)); + EnsureBuffer(bytesNeeded); + Span charBuffer = MemoryMarshal.Cast(_bufferWriter.Buffer); int idx = 0; if (!_firstItem) @@ -395,6 +411,7 @@ private void WriteAttributeUtf16(ReadOnlySpan nameSpanChar, ReadOnlySpan nameSpanByte, int bytesNeeded) { - Span byteBuffer = EnsureBuffer(bytesNeeded); + EnsureBuffer(bytesNeeded); + Span byteBuffer = _bufferWriter.Buffer; int idx = 0; if (!_firstItem) @@ -594,12 +612,14 @@ private void WriteAttributeUtf8(ReadOnlySpan nameSpanByte, int bytesNeeded byteBuffer[idx++] = JsonConstants.Space; _bufferWriter.Advance(idx); + _bufferWriter.Flush(); _firstItem = false; } private void WriteAttributeUtf16(ReadOnlySpan nameSpanChar, int bytesNeeded) { - Span charBuffer = MemoryMarshal.Cast(EnsureBuffer(bytesNeeded)); + EnsureBuffer(bytesNeeded); + Span charBuffer = MemoryMarshal.Cast(_bufferWriter.Buffer); int idx = 0; if (!_firstItem) @@ -622,6 +642,7 @@ private void WriteAttributeUtf16(ReadOnlySpan nameSpanChar, int bytesNeede charBuffer[idx] = (char)JsonConstants.Space; _bufferWriter.Advance(bytesNeeded); + _bufferWriter.Flush(); _firstItem = false; } @@ -647,7 +668,8 @@ public void WriteValue(string value) private void WriteValueUtf8(ReadOnlySpan valueSpanByte, int bytesNeeded) { - Span byteBuffer = EnsureBuffer(bytesNeeded); + EnsureBuffer(bytesNeeded); + Span byteBuffer = _bufferWriter.Buffer; int idx = 0; if (!_firstItem) @@ -671,12 +693,14 @@ private void WriteValueUtf8(ReadOnlySpan valueSpanByte, int bytesNeeded) byteBuffer[idx++] = JsonConstants.Quote; _bufferWriter.Advance(idx); + _bufferWriter.Flush(); _firstItem = false; } private void WriteValueUtf16(ReadOnlySpan valueSpanChar, int bytesNeeded) { - Span charBuffer = MemoryMarshal.Cast(EnsureBuffer(bytesNeeded)); + EnsureBuffer(bytesNeeded); + Span charBuffer = MemoryMarshal.Cast(_bufferWriter.Buffer); int idx = 0; if (!_firstItem) @@ -694,6 +718,7 @@ private void WriteValueUtf16(ReadOnlySpan valueSpanChar, int bytesNeeded) charBuffer[idx] = (char)JsonConstants.Quote; _bufferWriter.Advance(bytesNeeded); + _bufferWriter.Flush(); _firstItem = false; } @@ -725,7 +750,8 @@ private void WriteValueUtf8(long value, int bytesNeeded) int digitCount = CountDigits((ulong)value); bytesNeeded += sizeof(byte) * digitCount; - Span byteBuffer = EnsureBuffer(bytesNeeded); + EnsureBuffer(bytesNeeded); + Span byteBuffer = _bufferWriter.Buffer; int idx = 0; if (!_firstItem) @@ -741,6 +767,7 @@ private void WriteValueUtf8(long value, int bytesNeeded) WriteDigitsUInt64D((ulong)value, byteBuffer.Slice(idx, digitCount)); _bufferWriter.Advance(bytesNeeded); + _bufferWriter.Flush(); } private void WriteValueUtf16(long value, int bytesNeeded) @@ -755,7 +782,8 @@ private void WriteValueUtf16(long value, int bytesNeeded) int digitCount = CountDigits((ulong)value); bytesNeeded += sizeof(char) * digitCount; - Span charBuffer = MemoryMarshal.Cast(EnsureBuffer(bytesNeeded)); + EnsureBuffer(bytesNeeded); + Span charBuffer = MemoryMarshal.Cast(_bufferWriter.Buffer); int idx = 0; if (!_firstItem) @@ -771,6 +799,7 @@ private void WriteValueUtf16(long value, int bytesNeeded) WriteDigitsUInt64D((ulong)value, charBuffer.Slice(idx, digitCount)); _bufferWriter.Advance(bytesNeeded); + _bufferWriter.Flush(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -1011,7 +1040,8 @@ public void WriteNull() if (_isUtf8) { int bytesNeeded = (_firstItem ? 0 : 1) + (_prettyPrint ? 2 + (_indent + 1) * 2 : 0) + JsonConstants.NullValue.Length; - Span byteBuffer = EnsureBuffer(bytesNeeded); + EnsureBuffer(bytesNeeded); + Span byteBuffer = _bufferWriter.Buffer; int idx = 0; if (_firstItem) { @@ -1039,12 +1069,14 @@ public void WriteNull() JsonConstants.NullValue.CopyTo(byteBuffer.Slice(idx)); _bufferWriter.Advance(bytesNeeded); + _bufferWriter.Flush(); } else { int charsNeeded = (_firstItem ? 0 : 1) + (_prettyPrint ? 2 + (_indent + 1) * 2 : 0); int bytesNeeded = charsNeeded * 2 + JsonConstants.NullValueUtf16.Length; - Span byteBuffer = EnsureBuffer(bytesNeeded); + EnsureBuffer(bytesNeeded); + Span byteBuffer = _bufferWriter.Buffer; Span charBuffer = MemoryMarshal.Cast(byteBuffer); int idx = 0; if (_firstItem) @@ -1073,6 +1105,7 @@ public void WriteNull() JsonConstants.NullValueUtf16.CopyTo(byteBuffer.Slice(idx * 2)); _bufferWriter.Advance(bytesNeeded); + _bufferWriter.Flush(); } } @@ -1080,105 +1113,141 @@ public void WriteNull() private void WriteNumberUtf8(long value) { //TODO: Optimize, this is too slow - var buffer = _bufferWriter.GetSpan(); + Span buffer = _bufferWriter.Buffer; int written; while (!CustomFormatter.TryFormat(value, buffer, out written, JsonConstants.NumberFormat, SymbolTable.InvariantUtf8)) - buffer = EnsureBuffer(); + { + EnsureBuffer(); + buffer = _bufferWriter.Buffer; + } _bufferWriter.Advance(written); + _bufferWriter.Flush(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void WriteNumberUtf16(long value) { //TODO: Optimize, this is too slow - var buffer = _bufferWriter.GetSpan(); + Span buffer = _bufferWriter.Buffer; int written; while (!CustomFormatter.TryFormat(value, buffer, out written, JsonConstants.NumberFormat, SymbolTable.InvariantUtf16)) - buffer = EnsureBuffer(); + { + EnsureBuffer(); + buffer = _bufferWriter.Buffer; + } _bufferWriter.Advance(written); + _bufferWriter.Flush(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void WriteNumber(ulong value) { - var buffer = _bufferWriter.GetSpan(); + Span buffer = _bufferWriter.Buffer; int written; while (!CustomFormatter.TryFormat(value, buffer, out written, JsonConstants.NumberFormat, SymbolTable.InvariantUtf8)) - buffer = EnsureBuffer(); + { + EnsureBuffer(); + buffer = _bufferWriter.Buffer; + } _bufferWriter.Advance(written); + _bufferWriter.Flush(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void WriteDateTime(DateTime value) { - var buffer = _bufferWriter.GetSpan(); + Span buffer = _bufferWriter.Buffer; int written; while (!CustomFormatter.TryFormat(value, buffer, out written, JsonConstants.DateTimeFormat, SymbolTable.InvariantUtf8)) - buffer = EnsureBuffer(); + { + EnsureBuffer(); + buffer = _bufferWriter.Buffer; + } _bufferWriter.Advance(written); + _bufferWriter.Flush(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void WriteDateTimeOffset(DateTimeOffset value) { - var buffer = _bufferWriter.GetSpan(); + Span buffer = _bufferWriter.Buffer; int written; while (!CustomFormatter.TryFormat(value, buffer, out written, JsonConstants.DateTimeFormat, SymbolTable.InvariantUtf8)) - buffer = EnsureBuffer(); + { + EnsureBuffer(); + buffer = _bufferWriter.Buffer; + } _bufferWriter.Advance(written); + _bufferWriter.Flush(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void WriteGuid(Guid value) { - var buffer = _bufferWriter.GetSpan(); + Span buffer = _bufferWriter.Buffer; int written; while (!CustomFormatter.TryFormat(value, buffer, out written, JsonConstants.GuidFormat, SymbolTable.InvariantUtf8)) - buffer = EnsureBuffer(); + { + EnsureBuffer(); + buffer = _bufferWriter.Buffer; + } _bufferWriter.Advance(written); + _bufferWriter.Flush(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void WriteJsonValueUtf8(ReadOnlySpan values) { - var buffer = _bufferWriter.GetSpan(); + Span buffer = _bufferWriter.Buffer; int written; while (!SymbolTable.InvariantUtf8.TryEncode(values, buffer, out int consumed, out written)) - buffer = EnsureBuffer(); + { + EnsureBuffer(); + buffer = _bufferWriter.Buffer; + } _bufferWriter.Advance(written); + _bufferWriter.Flush(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void WriteJsonValueUtf16(ReadOnlySpan values) { - var buffer = _bufferWriter.GetSpan(); + Span buffer = _bufferWriter.Buffer; int written; while (!SymbolTable.InvariantUtf16.TryEncode(values, buffer, out int consumed, out written)) - buffer = EnsureBuffer(); + { + EnsureBuffer(); + buffer = _bufferWriter.Buffer; + } _bufferWriter.Advance(written); + _bufferWriter.Flush(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void WriteControlUtf8(byte value) { - MemoryMarshal.GetReference(EnsureBuffer(1)) = value; + EnsureBuffer(1); + MemoryMarshal.GetReference(_bufferWriter.Buffer) = value; _bufferWriter.Advance(1); + _bufferWriter.Flush(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void WriteControlUtf16(byte value) { - var buffer = EnsureBuffer(2); + EnsureBuffer(2); + Span buffer = _bufferWriter.Buffer; Unsafe.As(ref MemoryMarshal.GetReference(buffer)) = (char)value; _bufferWriter.Advance(2); + _bufferWriter.Flush(); } // TODO: Once public methods are optimized, remove this. @@ -1209,7 +1278,8 @@ private void WriteSpacingUtf8(bool newline = true) var bytesNeeded = newline ? 2 : 0; bytesNeeded += (indent + 1) * 2; - var buffer = EnsureBuffer(bytesNeeded); + EnsureBuffer(bytesNeeded); + Span buffer = _bufferWriter.Buffer; ref byte utf8Bytes = ref MemoryMarshal.GetReference(buffer); int idx = 0; @@ -1226,6 +1296,7 @@ private void WriteSpacingUtf8(bool newline = true) } _bufferWriter.Advance(bytesNeeded); + _bufferWriter.Flush(); } // TODO: Once public methods are optimized, remove this. @@ -1239,7 +1310,8 @@ private void WriteSpacingUtf16(bool newline = true) bytesNeeded += (indent + 1) * 2; bytesNeeded *= sizeof(char); - var buffer = EnsureBuffer(bytesNeeded); + EnsureBuffer(bytesNeeded); + Span buffer = _bufferWriter.Buffer; var span = MemoryMarshal.Cast(buffer); ref char utf16Bytes = ref MemoryMarshal.GetReference(span); int idx = 0; @@ -1257,16 +1329,18 @@ private void WriteSpacingUtf16(bool newline = true) } _bufferWriter.Advance(bytesNeeded); + _bufferWriter.Flush(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private Span EnsureBuffer(int needed = 256) + private void EnsureBuffer(int needed = 256) { - Span buffer = _bufferWriter.GetSpan(needed); + _bufferWriter.Ensure(needed); + /*Span buffer = _bufferWriter.GetSpan(needed); if (buffer.Length < needed) JsonThrowHelper.ThrowOutOfMemoryException(); - return buffer; + return buffer;*/ } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/tests/System.Text.JsonLab.Tests/JsonWriterTests.cs b/tests/System.Text.JsonLab.Tests/JsonWriterTests.cs index 55015a9a659..196e0bfdd97 100644 --- a/tests/System.Text.JsonLab.Tests/JsonWriterTests.cs +++ b/tests/System.Text.JsonLab.Tests/JsonWriterTests.cs @@ -6,6 +6,8 @@ using System.Text.Formatting; using System.Buffers.Text; using System.IO; +using System.Buffers.Writer; +using System.Buffers; namespace System.Text.JsonLab.Tests { @@ -17,7 +19,8 @@ public class JsonWriterTests public void WriteJsonUtf8() { var formatter = new ArrayFormatter(1024, SymbolTable.InvariantUtf8); - var json = new JsonWriter(formatter, true, prettyPrint: false); + var bufferWriter = new BufferWriter>(formatter); + var json = new JsonWriter(bufferWriter, true, prettyPrint: false); Write(ref json); var formatted = formatter.Formatted; @@ -25,7 +28,8 @@ public void WriteJsonUtf8() Assert.Equal(expected, str.Replace(" ", "")); formatter.Clear(); - json = new JsonWriter(formatter, true, prettyPrint: true); + bufferWriter = new BufferWriter>(formatter); + json = new JsonWriter(bufferWriter, true, prettyPrint: true); Write(ref json); formatted = formatter.Formatted; @@ -37,7 +41,8 @@ public void WriteJsonUtf8() public void WriteJsonUtf16() { var formatter = new ArrayFormatter(1024, SymbolTable.InvariantUtf16); - var json = new JsonWriter(formatter, false, prettyPrint: false); + var bufferWriter = new BufferWriter>(formatter); + var json = new JsonWriter(bufferWriter, false, prettyPrint: false); Write(ref json); var formatted = formatter.Formatted; @@ -45,7 +50,8 @@ public void WriteJsonUtf16() Assert.Equal(expected, str.Replace(" ", "")); formatter.Clear(); - json = new JsonWriter(formatter, false, prettyPrint: true); + bufferWriter = new BufferWriter>(formatter); + json = new JsonWriter(bufferWriter, false, prettyPrint: true); Write(ref json); formatted = formatter.Formatted; @@ -86,7 +92,8 @@ public void WriteHelloWorldJsonUtf16(bool prettyPrint) string expectedStr = GetHelloWorldExpectedString(prettyPrint, isUtf8: false); var output = new ArrayFormatter(1024, SymbolTable.InvariantUtf16); - var jsonUtf16 = new JsonWriter(output, false, prettyPrint); + var bufferWriter = new BufferWriter>(output); + var jsonUtf16 = new JsonWriter(bufferWriter, false, prettyPrint); jsonUtf16.WriteObjectStart(); jsonUtf16.WriteAttribute("message", "Hello, World!"); @@ -106,7 +113,8 @@ public void WriteHelloWorldJsonUtf8(bool prettyPrint) string expectedStr = GetHelloWorldExpectedString(prettyPrint, isUtf8: true); var output = new ArrayFormatter(1024, SymbolTable.InvariantUtf8); - var jsonUtf8 = new JsonWriter(output, true, prettyPrint); + var bufferWriter = new BufferWriter>(output); + var jsonUtf8 = new JsonWriter(bufferWriter, true, prettyPrint); jsonUtf8.WriteObjectStart(); jsonUtf8.WriteAttribute("message", "Hello, World!"); @@ -128,7 +136,8 @@ public void WriteBasicJsonUtf16(bool prettyPrint) string expectedStr = GetExpectedString(prettyPrint, isUtf8: false, data); var output = new ArrayFormatter(1024, SymbolTable.InvariantUtf16); - var jsonUtf16 = new JsonWriter(output, false, prettyPrint); + var bufferWriter = new BufferWriter>(output); + var jsonUtf16 = new JsonWriter(bufferWriter, false, prettyPrint); jsonUtf16.WriteObjectStart(); jsonUtf16.WriteAttribute("age", 42); @@ -170,7 +179,8 @@ public void WriteBasicJsonUtf8(bool prettyPrint) string expectedStr = GetExpectedString(prettyPrint, isUtf8: true, data); var output = new ArrayFormatter(1024, SymbolTable.InvariantUtf8); - var jsonUtf8 = new JsonWriter(output, true, prettyPrint); + var bufferWriter = new BufferWriter>(output); + var jsonUtf8 = new JsonWriter(bufferWriter, true, prettyPrint); jsonUtf8.WriteObjectStart(); jsonUtf8.WriteAttribute("age", 42); From 7f106c8baa232c18c679dd820ac6bc8e03bed293 Mon Sep 17 00:00:00 2001 From: Ahson Khan Date: Mon, 11 Jun 2018 18:54:42 -0700 Subject: [PATCH 2/8] Fix uses of JsonWriter in perf tests and samples --- .../Shared/SampleServer.cs | 5 +++-- tests/Benchmarks/System.IO.Pipelines/E2E.cs | 6 ++++-- .../System.Text.JsonLab/JsonWriterPerf.cs | 18 ++++++++++-------- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/samples/LowAllocationWebServer/Shared/SampleServer.cs b/samples/LowAllocationWebServer/Shared/SampleServer.cs index 0c47539fa99..d643864a67f 100644 --- a/samples/LowAllocationWebServer/Shared/SampleServer.cs +++ b/samples/LowAllocationWebServer/Shared/SampleServer.cs @@ -9,6 +9,7 @@ using System.Threading; using System.Text.Http.Parser; using Microsoft.Net; +using System.Buffers.Writer; namespace LowAllocationWebServer { @@ -62,7 +63,7 @@ static void WriteResponseForGetJson(HttpRequest request, ReadOnlySequence response.AppendEoh(); // write response JSON - var jsonWriter = new JsonWriter(response, true, prettyPrint: false); + var jsonWriter = new JsonWriter(new BufferWriter>(response), true, prettyPrint: false); jsonWriter.WriteObjectStart(); jsonWriter.WriteArrayStart("values"); for (int i = 0; i < 5; i++) @@ -94,7 +95,7 @@ static void WriteResponseForPostJson(HttpRequest request, ReadOnlySequence response.AppendEoh(); // write response JSON - var jsonWriter = new JsonWriter(response, true, prettyPrint: false); + var jsonWriter = new JsonWriter(new BufferWriter>(response), true, prettyPrint: false); jsonWriter.WriteObjectStart(); jsonWriter.WriteArrayStart("values"); for (int i = 0; i < requestedCount; i++) diff --git a/tests/Benchmarks/System.IO.Pipelines/E2E.cs b/tests/Benchmarks/System.IO.Pipelines/E2E.cs index a2eeb4def15..81e36d436bd 100644 --- a/tests/Benchmarks/System.IO.Pipelines/E2E.cs +++ b/tests/Benchmarks/System.IO.Pipelines/E2E.cs @@ -2,7 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Buffers; using System.Buffers.Text; +using System.Buffers.Writer; using System.IO.Pipelines.Samples; using System.Text; using System.Text.Formatting; @@ -55,9 +57,9 @@ public void TechEmpowerJsonNoIO(int numberOfRequests, int concurrentConnections) formatter.Format("\r\nDate: {0:R}", DateTime.UtcNow); formatter.Append("Server: System.IO.Pipelines"); formatter.Append("\r\n\r\n"); - + // write body - var writer = new JsonWriter(formatter, true); + var writer = new JsonWriter(new BufferWriter>(formatter), true, true); writer.WriteObjectStart(); writer.WriteAttribute("message", "Hello, World!"); writer.WriteObjectEnd(); diff --git a/tests/Benchmarks/System.Text.JsonLab/JsonWriterPerf.cs b/tests/Benchmarks/System.Text.JsonLab/JsonWriterPerf.cs index c7ea17a76e0..4e6dc38bc00 100644 --- a/tests/Benchmarks/System.Text.JsonLab/JsonWriterPerf.cs +++ b/tests/Benchmarks/System.Text.JsonLab/JsonWriterPerf.cs @@ -2,7 +2,9 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using BenchmarkDotNet.Attributes; +using System.Buffers; using System.Buffers.Text; +using System.Buffers.Writer; using System.IO; using System.Text.Formatting; @@ -57,9 +59,9 @@ public void WriterSystemTextJsonBasic() { _arrayFormatter.Clear(); if (IsUTF8Encoded) - WriterSystemTextJsonBasicUtf8(Formatted, _arrayFormatter, _data); + WriterSystemTextJsonBasicUtf8(Formatted, new BufferWriter>(_arrayFormatter), _data); else - WriterSystemTextJsonBasicUtf16(Formatted, _arrayFormatter, _data); + WriterSystemTextJsonBasicUtf16(Formatted, new BufferWriter>(_arrayFormatter), _data); } [Benchmark] @@ -73,9 +75,9 @@ public void WriterSystemTextJsonHelloWorld() { _arrayFormatter.Clear(); if (IsUTF8Encoded) - WriterSystemTextJsonHelloWorldUtf8(Formatted, _arrayFormatter); + WriterSystemTextJsonHelloWorldUtf8(Formatted, new BufferWriter>(_arrayFormatter)); else - WriterSystemTextJsonHelloWorldUtf16(Formatted, _arrayFormatter); + WriterSystemTextJsonHelloWorldUtf16(Formatted, new BufferWriter>(_arrayFormatter)); } [Benchmark] @@ -100,7 +102,7 @@ private TextWriter GetWriter() return writer; } - private static void WriterSystemTextJsonBasicUtf8(bool formatted, ArrayFormatter output, int[] data) + private static void WriterSystemTextJsonBasicUtf8(bool formatted, BufferWriter> output, int[] data) { var json = new JsonWriter(output, true, formatted); @@ -129,7 +131,7 @@ private static void WriterSystemTextJsonBasicUtf8(bool formatted, ArrayFormatter json.WriteObjectEnd(); } - private static void WriterSystemTextJsonBasicUtf16(bool formatted, ArrayFormatter output, int[] data) + private static void WriterSystemTextJsonBasicUtf16(bool formatted, BufferWriter> output, int[] data) { var json = new JsonWriter(output, false, formatted); @@ -199,7 +201,7 @@ private static void WriterNewtonsoftBasic(bool formatted, TextWriter writer, int } } - private static void WriterSystemTextJsonHelloWorldUtf8(bool formatted, ArrayFormatter output) + private static void WriterSystemTextJsonHelloWorldUtf8(bool formatted, BufferWriter> output) { var json = new JsonWriter(output, true, formatted); @@ -208,7 +210,7 @@ private static void WriterSystemTextJsonHelloWorldUtf8(bool formatted, ArrayForm json.WriteObjectEnd(); } - private static void WriterSystemTextJsonHelloWorldUtf16(bool formatted, ArrayFormatter output) + private static void WriterSystemTextJsonHelloWorldUtf16(bool formatted, BufferWriter> output) { var json = new JsonWriter(output, false, formatted); From 57574dbe995c8af9fb5723b578ac0fcf8430cf7e Mon Sep 17 00:00:00 2001 From: Ahson Khan Date: Mon, 11 Jun 2018 19:36:41 -0700 Subject: [PATCH 3/8] Code clean up and change EnsureBuffer to return the span. --- .../System/Text/Json/JsonWriter.cs | 94 +++++++------------ tests/Benchmarks/System.IO.Pipelines/E2E.cs | 8 +- 2 files changed, 39 insertions(+), 63 deletions(-) diff --git a/src/System.Text.JsonLab/System/Text/Json/JsonWriter.cs b/src/System.Text.JsonLab/System/Text/Json/JsonWriter.cs index eddcbca8569..6855e85a3a1 100644 --- a/src/System.Text.JsonLab/System/Text/Json/JsonWriter.cs +++ b/src/System.Text.JsonLab/System/Text/Json/JsonWriter.cs @@ -59,8 +59,7 @@ public void WriteObjectStart() private void WriteStartUtf8(int bytesNeeded, byte token) { - EnsureBuffer(bytesNeeded); - Span byteBuffer = _bufferWriter.Buffer; + Span byteBuffer = EnsureBuffer(bytesNeeded); int idx = 0; if (!_firstItem) @@ -84,8 +83,7 @@ private void WriteStartUtf8(int bytesNeeded, byte token) private void WriteStartUtf16(int bytesNeeded, byte token) { - EnsureBuffer(bytesNeeded); - Span charBuffer = MemoryMarshal.Cast(_bufferWriter.Buffer); + Span charBuffer = MemoryMarshal.Cast(EnsureBuffer(bytesNeeded)); int idx = 0; if (!_firstItem) @@ -134,8 +132,7 @@ public void WriteObjectStart(string name) private void WriteStartUtf8(ReadOnlySpan nameSpanByte, int bytesNeeded, byte token) { - EnsureBuffer(bytesNeeded); - Span byteBuffer = _bufferWriter.Buffer; + Span byteBuffer = EnsureBuffer(bytesNeeded); int idx = 0; if (!_firstItem) @@ -171,8 +168,7 @@ private void WriteStartUtf8(ReadOnlySpan nameSpanByte, int bytesNeeded, by private void WriteStartUtf16(ReadOnlySpan nameSpanChar, int bytesNeeded, byte token) { - EnsureBuffer(bytesNeeded); - Span charBuffer = MemoryMarshal.Cast(_bufferWriter.Buffer); + Span charBuffer = MemoryMarshal.Cast(EnsureBuffer(bytesNeeded)); int idx = 0; if (!_firstItem) @@ -220,8 +216,7 @@ public void WriteObjectEnd() private void WriteEndUtf8(int bytesNeeded, byte token) { - EnsureBuffer(bytesNeeded); - Span byteBuffer = _bufferWriter.Buffer; + Span byteBuffer = EnsureBuffer(bytesNeeded); int idx = 0; if (_prettyPrint) @@ -234,8 +229,7 @@ private void WriteEndUtf8(int bytesNeeded, byte token) private void WriteEndUtf16(int bytesNeeded, byte token) { - EnsureBuffer(bytesNeeded); - Span charBuffer = MemoryMarshal.Cast(_bufferWriter.Buffer); + Span charBuffer = MemoryMarshal.Cast(EnsureBuffer(bytesNeeded)); int idx = 0; if (_prettyPrint) @@ -334,8 +328,7 @@ public void WriteAttribute(string name, string value) private void WriteAttributeUtf8(ReadOnlySpan nameSpanByte, ReadOnlySpan valueSpanByte, int bytesNeeded) { - EnsureBuffer(bytesNeeded); - Span byteBuffer = _bufferWriter.Buffer; + Span byteBuffer = EnsureBuffer(bytesNeeded); int idx = 0; if (!_firstItem) @@ -381,8 +374,7 @@ private void WriteAttributeUtf8(ReadOnlySpan nameSpanByte, ReadOnlySpan nameSpanChar, ReadOnlySpan valueSpanChar, int bytesNeeded) { - EnsureBuffer(bytesNeeded); - Span charBuffer = MemoryMarshal.Cast(_bufferWriter.Buffer); + Span charBuffer = MemoryMarshal.Cast(EnsureBuffer(bytesNeeded)); int idx = 0; if (!_firstItem) @@ -583,8 +575,7 @@ public void WriteAttributeNull(string name) private void WriteAttributeUtf8(ReadOnlySpan nameSpanByte, int bytesNeeded) { - EnsureBuffer(bytesNeeded); - Span byteBuffer = _bufferWriter.Buffer; + Span byteBuffer = EnsureBuffer(bytesNeeded); int idx = 0; if (!_firstItem) @@ -618,8 +609,7 @@ private void WriteAttributeUtf8(ReadOnlySpan nameSpanByte, int bytesNeeded private void WriteAttributeUtf16(ReadOnlySpan nameSpanChar, int bytesNeeded) { - EnsureBuffer(bytesNeeded); - Span charBuffer = MemoryMarshal.Cast(_bufferWriter.Buffer); + Span charBuffer = MemoryMarshal.Cast(EnsureBuffer(bytesNeeded)); int idx = 0; if (!_firstItem) @@ -668,8 +658,7 @@ public void WriteValue(string value) private void WriteValueUtf8(ReadOnlySpan valueSpanByte, int bytesNeeded) { - EnsureBuffer(bytesNeeded); - Span byteBuffer = _bufferWriter.Buffer; + Span byteBuffer = EnsureBuffer(bytesNeeded); int idx = 0; if (!_firstItem) @@ -699,8 +688,7 @@ private void WriteValueUtf8(ReadOnlySpan valueSpanByte, int bytesNeeded) private void WriteValueUtf16(ReadOnlySpan valueSpanChar, int bytesNeeded) { - EnsureBuffer(bytesNeeded); - Span charBuffer = MemoryMarshal.Cast(_bufferWriter.Buffer); + Span charBuffer = MemoryMarshal.Cast(EnsureBuffer(bytesNeeded)); int idx = 0; if (!_firstItem) @@ -750,8 +738,7 @@ private void WriteValueUtf8(long value, int bytesNeeded) int digitCount = CountDigits((ulong)value); bytesNeeded += sizeof(byte) * digitCount; - EnsureBuffer(bytesNeeded); - Span byteBuffer = _bufferWriter.Buffer; + Span byteBuffer = EnsureBuffer(bytesNeeded); int idx = 0; if (!_firstItem) @@ -782,8 +769,8 @@ private void WriteValueUtf16(long value, int bytesNeeded) int digitCount = CountDigits((ulong)value); bytesNeeded += sizeof(char) * digitCount; - EnsureBuffer(bytesNeeded); - Span charBuffer = MemoryMarshal.Cast(_bufferWriter.Buffer); + + Span charBuffer = MemoryMarshal.Cast(EnsureBuffer(bytesNeeded)); int idx = 0; if (!_firstItem) @@ -1040,8 +1027,7 @@ public void WriteNull() if (_isUtf8) { int bytesNeeded = (_firstItem ? 0 : 1) + (_prettyPrint ? 2 + (_indent + 1) * 2 : 0) + JsonConstants.NullValue.Length; - EnsureBuffer(bytesNeeded); - Span byteBuffer = _bufferWriter.Buffer; + Span byteBuffer = EnsureBuffer(bytesNeeded); int idx = 0; if (_firstItem) { @@ -1075,8 +1061,8 @@ public void WriteNull() { int charsNeeded = (_firstItem ? 0 : 1) + (_prettyPrint ? 2 + (_indent + 1) * 2 : 0); int bytesNeeded = charsNeeded * 2 + JsonConstants.NullValueUtf16.Length; - EnsureBuffer(bytesNeeded); - Span byteBuffer = _bufferWriter.Buffer; + + Span byteBuffer = EnsureBuffer(bytesNeeded); Span charBuffer = MemoryMarshal.Cast(byteBuffer); int idx = 0; if (_firstItem) @@ -1117,8 +1103,7 @@ private void WriteNumberUtf8(long value) int written; while (!CustomFormatter.TryFormat(value, buffer, out written, JsonConstants.NumberFormat, SymbolTable.InvariantUtf8)) { - EnsureBuffer(); - buffer = _bufferWriter.Buffer; + buffer = EnsureBuffer(); } _bufferWriter.Advance(written); @@ -1133,8 +1118,7 @@ private void WriteNumberUtf16(long value) int written; while (!CustomFormatter.TryFormat(value, buffer, out written, JsonConstants.NumberFormat, SymbolTable.InvariantUtf16)) { - EnsureBuffer(); - buffer = _bufferWriter.Buffer; + buffer = EnsureBuffer(); } _bufferWriter.Advance(written); @@ -1148,8 +1132,7 @@ private void WriteNumber(ulong value) int written; while (!CustomFormatter.TryFormat(value, buffer, out written, JsonConstants.NumberFormat, SymbolTable.InvariantUtf8)) { - EnsureBuffer(); - buffer = _bufferWriter.Buffer; + buffer = EnsureBuffer(); } _bufferWriter.Advance(written); @@ -1163,8 +1146,7 @@ private void WriteDateTime(DateTime value) int written; while (!CustomFormatter.TryFormat(value, buffer, out written, JsonConstants.DateTimeFormat, SymbolTable.InvariantUtf8)) { - EnsureBuffer(); - buffer = _bufferWriter.Buffer; + buffer = EnsureBuffer(); } _bufferWriter.Advance(written); @@ -1178,8 +1160,7 @@ private void WriteDateTimeOffset(DateTimeOffset value) int written; while (!CustomFormatter.TryFormat(value, buffer, out written, JsonConstants.DateTimeFormat, SymbolTable.InvariantUtf8)) { - EnsureBuffer(); - buffer = _bufferWriter.Buffer; + buffer = EnsureBuffer(); } _bufferWriter.Advance(written); @@ -1193,8 +1174,7 @@ private void WriteGuid(Guid value) int written; while (!CustomFormatter.TryFormat(value, buffer, out written, JsonConstants.GuidFormat, SymbolTable.InvariantUtf8)) { - EnsureBuffer(); - buffer = _bufferWriter.Buffer; + buffer = EnsureBuffer(); } _bufferWriter.Advance(written); @@ -1208,8 +1188,7 @@ private void WriteJsonValueUtf8(ReadOnlySpan values) int written; while (!SymbolTable.InvariantUtf8.TryEncode(values, buffer, out int consumed, out written)) { - EnsureBuffer(); - buffer = _bufferWriter.Buffer; + buffer = EnsureBuffer(); } _bufferWriter.Advance(written); @@ -1223,8 +1202,7 @@ private void WriteJsonValueUtf16(ReadOnlySpan values) int written; while (!SymbolTable.InvariantUtf16.TryEncode(values, buffer, out int consumed, out written)) { - EnsureBuffer(); - buffer = _bufferWriter.Buffer; + buffer = EnsureBuffer(); } _bufferWriter.Advance(written); @@ -1234,8 +1212,8 @@ private void WriteJsonValueUtf16(ReadOnlySpan values) [MethodImpl(MethodImplOptions.AggressiveInlining)] private void WriteControlUtf8(byte value) { - EnsureBuffer(1); - MemoryMarshal.GetReference(_bufferWriter.Buffer) = value; + Span buffer = EnsureBuffer(1); + MemoryMarshal.GetReference(buffer) = value; _bufferWriter.Advance(1); _bufferWriter.Flush(); } @@ -1243,8 +1221,7 @@ private void WriteControlUtf8(byte value) [MethodImpl(MethodImplOptions.AggressiveInlining)] private void WriteControlUtf16(byte value) { - EnsureBuffer(2); - Span buffer = _bufferWriter.Buffer; + Span buffer = EnsureBuffer(2); Unsafe.As(ref MemoryMarshal.GetReference(buffer)) = (char)value; _bufferWriter.Advance(2); _bufferWriter.Flush(); @@ -1278,8 +1255,7 @@ private void WriteSpacingUtf8(bool newline = true) var bytesNeeded = newline ? 2 : 0; bytesNeeded += (indent + 1) * 2; - EnsureBuffer(bytesNeeded); - Span buffer = _bufferWriter.Buffer; + Span buffer = EnsureBuffer(bytesNeeded); ref byte utf8Bytes = ref MemoryMarshal.GetReference(buffer); int idx = 0; @@ -1310,8 +1286,7 @@ private void WriteSpacingUtf16(bool newline = true) bytesNeeded += (indent + 1) * 2; bytesNeeded *= sizeof(char); - EnsureBuffer(bytesNeeded); - Span buffer = _bufferWriter.Buffer; + Span buffer = EnsureBuffer(bytesNeeded); var span = MemoryMarshal.Cast(buffer); ref char utf16Bytes = ref MemoryMarshal.GetReference(span); int idx = 0; @@ -1333,14 +1308,13 @@ private void WriteSpacingUtf16(bool newline = true) } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void EnsureBuffer(int needed = 256) + private Span EnsureBuffer(int needed = 256) { _bufferWriter.Ensure(needed); - /*Span buffer = _bufferWriter.GetSpan(needed); + Span buffer = _bufferWriter.Buffer; if (buffer.Length < needed) JsonThrowHelper.ThrowOutOfMemoryException(); - - return buffer;*/ + return buffer; } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/tests/Benchmarks/System.IO.Pipelines/E2E.cs b/tests/Benchmarks/System.IO.Pipelines/E2E.cs index 81e36d436bd..2e2230034a3 100644 --- a/tests/Benchmarks/System.IO.Pipelines/E2E.cs +++ b/tests/Benchmarks/System.IO.Pipelines/E2E.cs @@ -31,7 +31,8 @@ public class E2E [Arguments(10000, 256)] public void TechEmpowerHelloWorldNoIO(int numberOfRequests, int concurrentConnections) { - RawInMemoryHttpServer.Run(numberOfRequests, concurrentConnections, s_genericRequest, (request, response) => { + RawInMemoryHttpServer.Run(numberOfRequests, concurrentConnections, s_genericRequest, (request, response) => + { var formatter = new BufferWriterFormatter(response, SymbolTable.InvariantUtf8); formatter.Append("HTTP/1.1 200 OK"); formatter.Append("\r\nContent-Length: 13"); @@ -49,7 +50,8 @@ public void TechEmpowerHelloWorldNoIO(int numberOfRequests, int concurrentConnec [Arguments(10000, 256)] public void TechEmpowerJsonNoIO(int numberOfRequests, int concurrentConnections) { - RawInMemoryHttpServer.Run(numberOfRequests, concurrentConnections, s_genericRequest, (request, response) => { + RawInMemoryHttpServer.Run(numberOfRequests, concurrentConnections, s_genericRequest, (request, response) => + { var formatter = new BufferWriterFormatter(response, SymbolTable.InvariantUtf8); formatter.Append("HTTP/1.1 200 OK"); formatter.Append("\r\nContent-Length: 25"); @@ -57,7 +59,7 @@ public void TechEmpowerJsonNoIO(int numberOfRequests, int concurrentConnections) formatter.Format("\r\nDate: {0:R}", DateTime.UtcNow); formatter.Append("Server: System.IO.Pipelines"); formatter.Append("\r\n\r\n"); - + // write body var writer = new JsonWriter(new BufferWriter>(formatter), true, true); writer.WriteObjectStart(); From 45a103bc8b96e9b244d26830353a80438715cc23 Mon Sep 17 00:00:00 2001 From: Ahson Khan Date: Mon, 11 Jun 2018 19:39:55 -0700 Subject: [PATCH 4/8] Remove extra whitespace. --- src/System.Text.JsonLab/System/Text/Json/JsonWriter.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/System.Text.JsonLab/System/Text/Json/JsonWriter.cs b/src/System.Text.JsonLab/System/Text/Json/JsonWriter.cs index 6855e85a3a1..46606ad33ae 100644 --- a/src/System.Text.JsonLab/System/Text/Json/JsonWriter.cs +++ b/src/System.Text.JsonLab/System/Text/Json/JsonWriter.cs @@ -769,7 +769,6 @@ private void WriteValueUtf16(long value, int bytesNeeded) int digitCount = CountDigits((ulong)value); bytesNeeded += sizeof(char) * digitCount; - Span charBuffer = MemoryMarshal.Cast(EnsureBuffer(bytesNeeded)); int idx = 0; @@ -1061,7 +1060,6 @@ public void WriteNull() { int charsNeeded = (_firstItem ? 0 : 1) + (_prettyPrint ? 2 + (_indent + 1) * 2 : 0); int bytesNeeded = charsNeeded * 2 + JsonConstants.NullValueUtf16.Length; - Span byteBuffer = EnsureBuffer(bytesNeeded); Span charBuffer = MemoryMarshal.Cast(byteBuffer); int idx = 0; From 9c8e6665af0f0d8017f8d316c502bc4d9a6d0353 Mon Sep 17 00:00:00 2001 From: Ahson Khan Date: Tue, 12 Jun 2018 22:12:37 -0700 Subject: [PATCH 5/8] Remove chatty calls to Flush within the JsonWriter APIs --- .../System/Buffers/Writer/BufferWriterT.cs | 7 +---- .../System/Text/Json/JsonWriter.cs | 28 ------------------- .../System.Text.JsonLab/JsonWriterPerf.cs | 12 +++++--- 3 files changed, 9 insertions(+), 38 deletions(-) diff --git a/src/System.Buffers.ReaderWriter/System/Buffers/Writer/BufferWriterT.cs b/src/System.Buffers.ReaderWriter/System/Buffers/Writer/BufferWriterT.cs index 4b17d21f94e..0a73b0de2f0 100644 --- a/src/System.Buffers.ReaderWriter/System/Buffers/Writer/BufferWriterT.cs +++ b/src/System.Buffers.ReaderWriter/System/Buffers/Writer/BufferWriterT.cs @@ -56,12 +56,7 @@ public void Ensure(int count = 1) [MethodImpl(MethodImplOptions.NoInlining)] private void EnsureMore(int count = 0) { - var buffered = _buffered; - if (buffered > 0) - { - _buffered = 0; - _output.Advance(buffered); - } + Flush(); _span = _output.GetSpan(count); } diff --git a/src/System.Text.JsonLab/System/Text/Json/JsonWriter.cs b/src/System.Text.JsonLab/System/Text/Json/JsonWriter.cs index 0e122bbdc31..b9c6055509d 100644 --- a/src/System.Text.JsonLab/System/Text/Json/JsonWriter.cs +++ b/src/System.Text.JsonLab/System/Text/Json/JsonWriter.cs @@ -78,7 +78,6 @@ private void WriteStartUtf8(int bytesNeeded, byte token) byteBuffer[idx] = token; _bufferWriter.Advance(bytesNeeded); - _bufferWriter.Flush(); } private void WriteStartUtf16(int bytesNeeded, byte token) @@ -102,7 +101,6 @@ private void WriteStartUtf16(int bytesNeeded, byte token) charBuffer[idx] = (char)token; _bufferWriter.Advance(bytesNeeded); - _bufferWriter.Flush(); } /// @@ -162,7 +160,6 @@ private void WriteStartUtf8(ReadOnlySpan nameSpanByte, int bytesNeeded, by byteBuffer[idx++] = token; _bufferWriter.Advance(idx); - _bufferWriter.Flush(); _firstItem = false; } @@ -193,7 +190,6 @@ private void WriteStartUtf16(ReadOnlySpan nameSpanChar, int bytesNeeded, b charBuffer[idx] = (char)token; _bufferWriter.Advance(bytesNeeded); - _bufferWriter.Flush(); _firstItem = false; } @@ -224,7 +220,6 @@ private void WriteEndUtf8(int bytesNeeded, byte token) byteBuffer[idx] = token; _bufferWriter.Advance(bytesNeeded); - _bufferWriter.Flush(); } private void WriteEndUtf16(int bytesNeeded, byte token) @@ -237,7 +232,6 @@ private void WriteEndUtf16(int bytesNeeded, byte token) charBuffer[idx] = (char)token; _bufferWriter.Advance(bytesNeeded); - _bufferWriter.Flush(); } /// @@ -368,7 +362,6 @@ private void WriteAttributeUtf8(ReadOnlySpan nameSpanByte, ReadOnlySpan nameSpanChar, ReadOnlySpan nameSpanByte, int bytesNeeded byteBuffer[idx++] = JsonConstants.Space; _bufferWriter.Advance(idx); - _bufferWriter.Flush(); _firstItem = false; } @@ -632,7 +623,6 @@ private void WriteAttributeUtf16(ReadOnlySpan nameSpanChar, int bytesNeede charBuffer[idx] = (char)JsonConstants.Space; _bufferWriter.Advance(bytesNeeded); - _bufferWriter.Flush(); _firstItem = false; } @@ -682,7 +672,6 @@ private void WriteValueUtf8(ReadOnlySpan valueSpanByte, int bytesNeeded) byteBuffer[idx++] = JsonConstants.Quote; _bufferWriter.Advance(idx); - _bufferWriter.Flush(); _firstItem = false; } @@ -706,7 +695,6 @@ private void WriteValueUtf16(ReadOnlySpan valueSpanChar, int bytesNeeded) charBuffer[idx] = (char)JsonConstants.Quote; _bufferWriter.Advance(bytesNeeded); - _bufferWriter.Flush(); _firstItem = false; } @@ -754,7 +742,6 @@ private void WriteValueUtf8(long value, int bytesNeeded) WriteDigitsUInt64D((ulong)value, byteBuffer.Slice(idx, digitCount)); _bufferWriter.Advance(bytesNeeded); - _bufferWriter.Flush(); } private void WriteValueUtf16(long value, int bytesNeeded) @@ -785,7 +772,6 @@ private void WriteValueUtf16(long value, int bytesNeeded) WriteDigitsUInt64D((ulong)value, charBuffer.Slice(idx, digitCount)); _bufferWriter.Advance(bytesNeeded); - _bufferWriter.Flush(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -1054,7 +1040,6 @@ public void WriteNull() JsonConstants.NullValue.CopyTo(byteBuffer.Slice(idx)); _bufferWriter.Advance(bytesNeeded); - _bufferWriter.Flush(); } else { @@ -1090,7 +1075,6 @@ public void WriteNull() nullLiteral.CopyTo(byteBuffer.Slice(idx * 2)); _bufferWriter.Advance(bytesNeeded); - _bufferWriter.Flush(); } } @@ -1106,7 +1090,6 @@ private void WriteNumberUtf8(long value) } _bufferWriter.Advance(written); - _bufferWriter.Flush(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -1121,7 +1104,6 @@ private void WriteNumberUtf16(long value) } _bufferWriter.Advance(written); - _bufferWriter.Flush(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -1135,7 +1117,6 @@ private void WriteNumber(ulong value) } _bufferWriter.Advance(written); - _bufferWriter.Flush(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -1149,7 +1130,6 @@ private void WriteDateTime(DateTime value) } _bufferWriter.Advance(written); - _bufferWriter.Flush(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -1163,7 +1143,6 @@ private void WriteDateTimeOffset(DateTimeOffset value) } _bufferWriter.Advance(written); - _bufferWriter.Flush(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -1177,7 +1156,6 @@ private void WriteGuid(Guid value) } _bufferWriter.Advance(written); - _bufferWriter.Flush(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -1191,7 +1169,6 @@ private void WriteJsonValueUtf8(ReadOnlySpan values) } _bufferWriter.Advance(written); - _bufferWriter.Flush(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -1205,7 +1182,6 @@ private void WriteJsonValueUtf16(ReadOnlySpan values) } _bufferWriter.Advance(written); - _bufferWriter.Flush(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -1214,7 +1190,6 @@ private void WriteControlUtf8(byte value) Span buffer = EnsureBuffer(1); MemoryMarshal.GetReference(buffer) = value; _bufferWriter.Advance(1); - _bufferWriter.Flush(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -1223,7 +1198,6 @@ private void WriteControlUtf16(byte value) Span buffer = EnsureBuffer(2); Unsafe.As(ref MemoryMarshal.GetReference(buffer)) = (char)value; _bufferWriter.Advance(2); - _bufferWriter.Flush(); } // TODO: Once public methods are optimized, remove this. @@ -1271,7 +1245,6 @@ private void WriteSpacingUtf8(bool newline = true) } _bufferWriter.Advance(bytesNeeded); - _bufferWriter.Flush(); } // TODO: Once public methods are optimized, remove this. @@ -1303,7 +1276,6 @@ private void WriteSpacingUtf16(bool newline = true) } _bufferWriter.Advance(bytesNeeded); - _bufferWriter.Flush(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/tests/Benchmarks/System.Text.JsonLab/JsonWriterPerf.cs b/tests/Benchmarks/System.Text.JsonLab/JsonWriterPerf.cs index 4e6dc38bc00..64a7f1230ce 100644 --- a/tests/Benchmarks/System.Text.JsonLab/JsonWriterPerf.cs +++ b/tests/Benchmarks/System.Text.JsonLab/JsonWriterPerf.cs @@ -58,10 +58,12 @@ public void Setup() public void WriterSystemTextJsonBasic() { _arrayFormatter.Clear(); + var bufferWriter = new BufferWriter>(_arrayFormatter); if (IsUTF8Encoded) - WriterSystemTextJsonBasicUtf8(Formatted, new BufferWriter>(_arrayFormatter), _data); + WriterSystemTextJsonBasicUtf8(Formatted, bufferWriter, _data); else - WriterSystemTextJsonBasicUtf16(Formatted, new BufferWriter>(_arrayFormatter), _data); + WriterSystemTextJsonBasicUtf16(Formatted, bufferWriter, _data); + bufferWriter.Flush(); } [Benchmark] @@ -74,10 +76,12 @@ public void WriterNewtonsoftBasic() public void WriterSystemTextJsonHelloWorld() { _arrayFormatter.Clear(); + var bufferWriter = new BufferWriter>(_arrayFormatter); if (IsUTF8Encoded) - WriterSystemTextJsonHelloWorldUtf8(Formatted, new BufferWriter>(_arrayFormatter)); + WriterSystemTextJsonHelloWorldUtf8(Formatted, bufferWriter); else - WriterSystemTextJsonHelloWorldUtf16(Formatted, new BufferWriter>(_arrayFormatter)); + WriterSystemTextJsonHelloWorldUtf16(Formatted, bufferWriter); + bufferWriter.Flush(); } [Benchmark] From 5370b7b26ab29aacaafbb129d1ec3527650b4f7c Mon Sep 17 00:00:00 2001 From: Ahson Khan Date: Tue, 12 Jun 2018 22:30:12 -0700 Subject: [PATCH 6/8] Add Flush API and fix tests. --- src/System.Text.JsonLab/System/Text/Json/JsonWriter.cs | 2 ++ tests/Benchmarks/System.Text.JsonLab/JsonWriterPerf.cs | 6 ++++-- tests/System.Text.JsonLab.Tests/JsonWriterTests.cs | 7 +++++++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/System.Text.JsonLab/System/Text/Json/JsonWriter.cs b/src/System.Text.JsonLab/System/Text/Json/JsonWriter.cs index b9c6055509d..2dfaf973fd9 100644 --- a/src/System.Text.JsonLab/System/Text/Json/JsonWriter.cs +++ b/src/System.Text.JsonLab/System/Text/Json/JsonWriter.cs @@ -1078,6 +1078,8 @@ public void WriteNull() } } + public void Flush() => _bufferWriter.Flush(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] private void WriteNumberUtf8(long value) { diff --git a/tests/Benchmarks/System.Text.JsonLab/JsonWriterPerf.cs b/tests/Benchmarks/System.Text.JsonLab/JsonWriterPerf.cs index 64a7f1230ce..d42b232cde4 100644 --- a/tests/Benchmarks/System.Text.JsonLab/JsonWriterPerf.cs +++ b/tests/Benchmarks/System.Text.JsonLab/JsonWriterPerf.cs @@ -63,7 +63,6 @@ public void WriterSystemTextJsonBasic() WriterSystemTextJsonBasicUtf8(Formatted, bufferWriter, _data); else WriterSystemTextJsonBasicUtf16(Formatted, bufferWriter, _data); - bufferWriter.Flush(); } [Benchmark] @@ -81,7 +80,6 @@ public void WriterSystemTextJsonHelloWorld() WriterSystemTextJsonHelloWorldUtf8(Formatted, bufferWriter); else WriterSystemTextJsonHelloWorldUtf16(Formatted, bufferWriter); - bufferWriter.Flush(); } [Benchmark] @@ -133,6 +131,7 @@ private static void WriterSystemTextJsonBasicUtf8(bool formatted, BufferWriter> output, int[] data) @@ -162,6 +161,7 @@ private static void WriterSystemTextJsonBasicUtf16(bool formatted, BufferWriter< json.WriteArrayEnd(); json.WriteObjectEnd(); + json.Flush(); } private static void WriterNewtonsoftBasic(bool formatted, TextWriter writer, int[] data) @@ -212,6 +212,7 @@ private static void WriterSystemTextJsonHelloWorldUtf8(bool formatted, BufferWri json.WriteObjectStart(); json.WriteAttribute("message", "Hello, World!"); json.WriteObjectEnd(); + json.Flush(); } private static void WriterSystemTextJsonHelloWorldUtf16(bool formatted, BufferWriter> output) @@ -221,6 +222,7 @@ private static void WriterSystemTextJsonHelloWorldUtf16(bool formatted, BufferWr json.WriteObjectStart(); json.WriteAttribute("message", "Hello, World!"); json.WriteObjectEnd(); + json.Flush(); } private static void WriterNewtonsoftHelloWorld(bool formatted, TextWriter writer) diff --git a/tests/System.Text.JsonLab.Tests/JsonWriterTests.cs b/tests/System.Text.JsonLab.Tests/JsonWriterTests.cs index 196e0bfdd97..6cc6e38527d 100644 --- a/tests/System.Text.JsonLab.Tests/JsonWriterTests.cs +++ b/tests/System.Text.JsonLab.Tests/JsonWriterTests.cs @@ -82,6 +82,7 @@ static void Write(ref JsonWriter json) json.WriteValue(425123); json.WriteArrayEnd(); json.WriteObjectEnd(); + json.Flush(); } [Theory] @@ -98,6 +99,7 @@ public void WriteHelloWorldJsonUtf16(bool prettyPrint) jsonUtf16.WriteObjectStart(); jsonUtf16.WriteAttribute("message", "Hello, World!"); jsonUtf16.WriteObjectEnd(); + jsonUtf16.Flush(); ArraySegment formatted = output.Formatted; string actualStr = Encoding.Unicode.GetString(formatted.Array, formatted.Offset, formatted.Count); @@ -119,6 +121,7 @@ public void WriteHelloWorldJsonUtf8(bool prettyPrint) jsonUtf8.WriteObjectStart(); jsonUtf8.WriteAttribute("message", "Hello, World!"); jsonUtf8.WriteObjectEnd(); + jsonUtf8.Flush(); ArraySegment formatted = output.Formatted; string actualStr = Encoding.UTF8.GetString(formatted.Array, formatted.Offset, formatted.Count); @@ -163,6 +166,8 @@ public void WriteBasicJsonUtf16(bool prettyPrint) jsonUtf16.WriteObjectEnd(); + jsonUtf16.Flush(); + ArraySegment formatted = output.Formatted; string actualStr = Encoding.Unicode.GetString(formatted.Array, formatted.Offset, formatted.Count); @@ -206,6 +211,8 @@ public void WriteBasicJsonUtf8(bool prettyPrint) jsonUtf8.WriteObjectEnd(); + jsonUtf8.Flush(); + ArraySegment formatted = output.Formatted; string actualStr = Encoding.UTF8.GetString(formatted.Array, formatted.Offset, formatted.Count); From 1d2604910630b3b64f025bb7101165aaf8fefee2 Mon Sep 17 00:00:00 2001 From: Ahson Khan Date: Wed, 13 Jun 2018 00:03:50 -0700 Subject: [PATCH 7/8] Address PR feedback - make JsonWriter generic. --- .../Shared/SampleServer.cs | 5 ++-- .../System/Text/Json/JsonWriter.cs | 26 +++++++++++++++-- tests/Benchmarks/System.IO.Pipelines/E2E.cs | 4 +-- .../System.Text.JsonLab/JsonWriterPerf.cs | 28 ++++++++----------- .../JsonWriterTests.cs | 28 ++++++------------- 5 files changed, 47 insertions(+), 44 deletions(-) diff --git a/samples/LowAllocationWebServer/Shared/SampleServer.cs b/samples/LowAllocationWebServer/Shared/SampleServer.cs index d643864a67f..346a9bda818 100644 --- a/samples/LowAllocationWebServer/Shared/SampleServer.cs +++ b/samples/LowAllocationWebServer/Shared/SampleServer.cs @@ -9,7 +9,6 @@ using System.Threading; using System.Text.Http.Parser; using Microsoft.Net; -using System.Buffers.Writer; namespace LowAllocationWebServer { @@ -63,7 +62,7 @@ static void WriteResponseForGetJson(HttpRequest request, ReadOnlySequence response.AppendEoh(); // write response JSON - var jsonWriter = new JsonWriter(new BufferWriter>(response), true, prettyPrint: false); + JsonWriter jsonWriter = JsonWriter.Create(response, true, prettyPrint: false); jsonWriter.WriteObjectStart(); jsonWriter.WriteArrayStart("values"); for (int i = 0; i < 5; i++) @@ -95,7 +94,7 @@ static void WriteResponseForPostJson(HttpRequest request, ReadOnlySequence response.AppendEoh(); // write response JSON - var jsonWriter = new JsonWriter(new BufferWriter>(response), true, prettyPrint: false); + JsonWriter jsonWriter = JsonWriter.Create(response, true, prettyPrint: false); jsonWriter.WriteObjectStart(); jsonWriter.WriteArrayStart("values"); for (int i = 0; i < requestedCount; i++) diff --git a/src/System.Text.JsonLab/System/Text/Json/JsonWriter.cs b/src/System.Text.JsonLab/System/Text/Json/JsonWriter.cs index 2dfaf973fd9..a0fad0b18e9 100644 --- a/src/System.Text.JsonLab/System/Text/Json/JsonWriter.cs +++ b/src/System.Text.JsonLab/System/Text/Json/JsonWriter.cs @@ -10,13 +10,13 @@ namespace System.Text.JsonLab { - public ref struct JsonWriter + public ref struct JsonWriter where TBufferWriter : IBufferWriter { private static readonly byte[] s_newLineUtf8 = Encoding.UTF8.GetBytes(Environment.NewLine); private static readonly char[] s_newLineUtf16 = Environment.NewLine.ToCharArray(); private readonly bool _prettyPrint; - private BufferWriter> _bufferWriter; + private BufferWriter _bufferWriter; private readonly bool _isUtf8; private int _indent; @@ -27,7 +27,7 @@ public ref struct JsonWriter /// /// An instance of used for writing bytes to an output channel. /// Specifies whether to add whitespace to the output text for user readability. - public JsonWriter(BufferWriter> bufferWriter, bool isUtf8, bool prettyPrint = false) + public JsonWriter(BufferWriter bufferWriter, bool isUtf8, bool prettyPrint = false) { _bufferWriter = bufferWriter; _prettyPrint = prettyPrint; @@ -1557,4 +1557,24 @@ private int AddNewLineAndIndentation(Span buffer) return offset; } } + + //TODO: Move to a separate file + public static class JsonWriter + { + public static JsonWriter Create( + TBufferWriter bufferWriter, + bool isUtf8, + bool prettyPrint = false) where TBufferWriter : IBufferWriter + { + return new JsonWriter(BufferWriter.Create(bufferWriter), isUtf8, prettyPrint); + } + + public static JsonWriter Create( + BufferWriter bufferWriter, + bool isUtf8, + bool prettyPrint = false) where TBufferWriter : IBufferWriter + { + return new JsonWriter(bufferWriter, isUtf8, prettyPrint); + } + } } diff --git a/tests/Benchmarks/System.IO.Pipelines/E2E.cs b/tests/Benchmarks/System.IO.Pipelines/E2E.cs index 2e2230034a3..c1146f09367 100644 --- a/tests/Benchmarks/System.IO.Pipelines/E2E.cs +++ b/tests/Benchmarks/System.IO.Pipelines/E2E.cs @@ -2,9 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.Buffers; using System.Buffers.Text; -using System.Buffers.Writer; using System.IO.Pipelines.Samples; using System.Text; using System.Text.Formatting; @@ -61,7 +59,7 @@ public void TechEmpowerJsonNoIO(int numberOfRequests, int concurrentConnections) formatter.Append("\r\n\r\n"); // write body - var writer = new JsonWriter(new BufferWriter>(formatter), true, true); + JsonWriter> writer = JsonWriter.Create(formatter, true, true); writer.WriteObjectStart(); writer.WriteAttribute("message", "Hello, World!"); writer.WriteObjectEnd(); diff --git a/tests/Benchmarks/System.Text.JsonLab/JsonWriterPerf.cs b/tests/Benchmarks/System.Text.JsonLab/JsonWriterPerf.cs index d42b232cde4..48428a57a0a 100644 --- a/tests/Benchmarks/System.Text.JsonLab/JsonWriterPerf.cs +++ b/tests/Benchmarks/System.Text.JsonLab/JsonWriterPerf.cs @@ -2,9 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using BenchmarkDotNet.Attributes; -using System.Buffers; using System.Buffers.Text; -using System.Buffers.Writer; using System.IO; using System.Text.Formatting; @@ -58,11 +56,10 @@ public void Setup() public void WriterSystemTextJsonBasic() { _arrayFormatter.Clear(); - var bufferWriter = new BufferWriter>(_arrayFormatter); if (IsUTF8Encoded) - WriterSystemTextJsonBasicUtf8(Formatted, bufferWriter, _data); + WriterSystemTextJsonBasicUtf8(Formatted, _arrayFormatter, _data); else - WriterSystemTextJsonBasicUtf16(Formatted, bufferWriter, _data); + WriterSystemTextJsonBasicUtf16(Formatted, _arrayFormatter, _data); } [Benchmark] @@ -75,11 +72,10 @@ public void WriterNewtonsoftBasic() public void WriterSystemTextJsonHelloWorld() { _arrayFormatter.Clear(); - var bufferWriter = new BufferWriter>(_arrayFormatter); if (IsUTF8Encoded) - WriterSystemTextJsonHelloWorldUtf8(Formatted, bufferWriter); + WriterSystemTextJsonHelloWorldUtf8(Formatted, _arrayFormatter); else - WriterSystemTextJsonHelloWorldUtf16(Formatted, bufferWriter); + WriterSystemTextJsonHelloWorldUtf16(Formatted, _arrayFormatter); } [Benchmark] @@ -104,9 +100,9 @@ private TextWriter GetWriter() return writer; } - private static void WriterSystemTextJsonBasicUtf8(bool formatted, BufferWriter> output, int[] data) + private static void WriterSystemTextJsonBasicUtf8(bool formatted, ArrayFormatter output, int[] data) { - var json = new JsonWriter(output, true, formatted); + JsonWriter json = JsonWriter.Create(output, true, formatted); json.WriteObjectStart(); json.WriteAttribute("age", 42); @@ -134,9 +130,9 @@ private static void WriterSystemTextJsonBasicUtf8(bool formatted, BufferWriter> output, int[] data) + private static void WriterSystemTextJsonBasicUtf16(bool formatted, ArrayFormatter output, int[] data) { - var json = new JsonWriter(output, false, formatted); + JsonWriter json = JsonWriter.Create(output, false, formatted); json.WriteObjectStart(); json.WriteAttribute("age", 42); @@ -205,9 +201,9 @@ private static void WriterNewtonsoftBasic(bool formatted, TextWriter writer, int } } - private static void WriterSystemTextJsonHelloWorldUtf8(bool formatted, BufferWriter> output) + private static void WriterSystemTextJsonHelloWorldUtf8(bool formatted, ArrayFormatter output) { - var json = new JsonWriter(output, true, formatted); + JsonWriter json = JsonWriter.Create(output, true, formatted); json.WriteObjectStart(); json.WriteAttribute("message", "Hello, World!"); @@ -215,9 +211,9 @@ private static void WriterSystemTextJsonHelloWorldUtf8(bool formatted, BufferWri json.Flush(); } - private static void WriterSystemTextJsonHelloWorldUtf16(bool formatted, BufferWriter> output) + private static void WriterSystemTextJsonHelloWorldUtf16(bool formatted, ArrayFormatter output) { - var json = new JsonWriter(output, false, formatted); + JsonWriter json = JsonWriter.Create(output, false, formatted); json.WriteObjectStart(); json.WriteAttribute("message", "Hello, World!"); diff --git a/tests/System.Text.JsonLab.Tests/JsonWriterTests.cs b/tests/System.Text.JsonLab.Tests/JsonWriterTests.cs index 6cc6e38527d..3c94b0f7668 100644 --- a/tests/System.Text.JsonLab.Tests/JsonWriterTests.cs +++ b/tests/System.Text.JsonLab.Tests/JsonWriterTests.cs @@ -6,8 +6,6 @@ using System.Text.Formatting; using System.Buffers.Text; using System.IO; -using System.Buffers.Writer; -using System.Buffers; namespace System.Text.JsonLab.Tests { @@ -19,8 +17,7 @@ public class JsonWriterTests public void WriteJsonUtf8() { var formatter = new ArrayFormatter(1024, SymbolTable.InvariantUtf8); - var bufferWriter = new BufferWriter>(formatter); - var json = new JsonWriter(bufferWriter, true, prettyPrint: false); + JsonWriter json = JsonWriter.Create(formatter, true, prettyPrint: false); Write(ref json); var formatted = formatter.Formatted; @@ -28,8 +25,7 @@ public void WriteJsonUtf8() Assert.Equal(expected, str.Replace(" ", "")); formatter.Clear(); - bufferWriter = new BufferWriter>(formatter); - json = new JsonWriter(bufferWriter, true, prettyPrint: true); + json = JsonWriter.Create(formatter, true, prettyPrint: true); Write(ref json); formatted = formatter.Formatted; @@ -41,8 +37,7 @@ public void WriteJsonUtf8() public void WriteJsonUtf16() { var formatter = new ArrayFormatter(1024, SymbolTable.InvariantUtf16); - var bufferWriter = new BufferWriter>(formatter); - var json = new JsonWriter(bufferWriter, false, prettyPrint: false); + JsonWriter json = JsonWriter.Create(formatter, false, prettyPrint: false); Write(ref json); var formatted = formatter.Formatted; @@ -50,8 +45,7 @@ public void WriteJsonUtf16() Assert.Equal(expected, str.Replace(" ", "")); formatter.Clear(); - bufferWriter = new BufferWriter>(formatter); - json = new JsonWriter(bufferWriter, false, prettyPrint: true); + json = JsonWriter.Create(formatter, false, prettyPrint: true); Write(ref json); formatted = formatter.Formatted; @@ -60,7 +54,7 @@ public void WriteJsonUtf16() } static string expected = "{\"age\":30,\"first\":\"John\",\"last\":\"Smith\",\"phoneNumbers\":[\"425-000-1212\",\"425-000-1213\",null],\"address\":{\"street\":\"1MicrosoftWay\",\"city\":\"Redmond\",\"zip\":98052},\"values\":[425121,-425122,425123]}"; - static void Write(ref JsonWriter json) + static void Write(ref JsonWriter json) { json.WriteObjectStart(); json.WriteAttribute("age", 30); @@ -93,8 +87,7 @@ public void WriteHelloWorldJsonUtf16(bool prettyPrint) string expectedStr = GetHelloWorldExpectedString(prettyPrint, isUtf8: false); var output = new ArrayFormatter(1024, SymbolTable.InvariantUtf16); - var bufferWriter = new BufferWriter>(output); - var jsonUtf16 = new JsonWriter(bufferWriter, false, prettyPrint); + JsonWriter jsonUtf16 = JsonWriter.Create(output, false, prettyPrint); jsonUtf16.WriteObjectStart(); jsonUtf16.WriteAttribute("message", "Hello, World!"); @@ -115,8 +108,7 @@ public void WriteHelloWorldJsonUtf8(bool prettyPrint) string expectedStr = GetHelloWorldExpectedString(prettyPrint, isUtf8: true); var output = new ArrayFormatter(1024, SymbolTable.InvariantUtf8); - var bufferWriter = new BufferWriter>(output); - var jsonUtf8 = new JsonWriter(bufferWriter, true, prettyPrint); + JsonWriter jsonUtf8 = JsonWriter.Create(output, true, prettyPrint); jsonUtf8.WriteObjectStart(); jsonUtf8.WriteAttribute("message", "Hello, World!"); @@ -139,8 +131,7 @@ public void WriteBasicJsonUtf16(bool prettyPrint) string expectedStr = GetExpectedString(prettyPrint, isUtf8: false, data); var output = new ArrayFormatter(1024, SymbolTable.InvariantUtf16); - var bufferWriter = new BufferWriter>(output); - var jsonUtf16 = new JsonWriter(bufferWriter, false, prettyPrint); + JsonWriter jsonUtf16 = JsonWriter.Create(output, false, prettyPrint); jsonUtf16.WriteObjectStart(); jsonUtf16.WriteAttribute("age", 42); @@ -184,8 +175,7 @@ public void WriteBasicJsonUtf8(bool prettyPrint) string expectedStr = GetExpectedString(prettyPrint, isUtf8: true, data); var output = new ArrayFormatter(1024, SymbolTable.InvariantUtf8); - var bufferWriter = new BufferWriter>(output); - var jsonUtf8 = new JsonWriter(bufferWriter, true, prettyPrint); + JsonWriter jsonUtf8 = JsonWriter.Create(output, true, prettyPrint); jsonUtf8.WriteObjectStart(); jsonUtf8.WriteAttribute("age", 42); From e5f7f1ba652d8a4cb7ab955335c6f7fd83ddecec Mon Sep 17 00:00:00 2001 From: Ahson Khan Date: Wed, 13 Jun 2018 19:36:51 -0700 Subject: [PATCH 8/8] Revert "Address PR feedback - make JsonWriter generic." This reverts commit 1d2604910630b3b64f025bb7101165aaf8fefee2. --- .../Shared/SampleServer.cs | 5 ++-- .../System/Text/Json/JsonWriter.cs | 26 ++--------------- tests/Benchmarks/System.IO.Pipelines/E2E.cs | 4 ++- .../System.Text.JsonLab/JsonWriterPerf.cs | 28 +++++++++++-------- .../JsonWriterTests.cs | 28 +++++++++++++------ 5 files changed, 44 insertions(+), 47 deletions(-) diff --git a/samples/LowAllocationWebServer/Shared/SampleServer.cs b/samples/LowAllocationWebServer/Shared/SampleServer.cs index 346a9bda818..d643864a67f 100644 --- a/samples/LowAllocationWebServer/Shared/SampleServer.cs +++ b/samples/LowAllocationWebServer/Shared/SampleServer.cs @@ -9,6 +9,7 @@ using System.Threading; using System.Text.Http.Parser; using Microsoft.Net; +using System.Buffers.Writer; namespace LowAllocationWebServer { @@ -62,7 +63,7 @@ static void WriteResponseForGetJson(HttpRequest request, ReadOnlySequence response.AppendEoh(); // write response JSON - JsonWriter jsonWriter = JsonWriter.Create(response, true, prettyPrint: false); + var jsonWriter = new JsonWriter(new BufferWriter>(response), true, prettyPrint: false); jsonWriter.WriteObjectStart(); jsonWriter.WriteArrayStart("values"); for (int i = 0; i < 5; i++) @@ -94,7 +95,7 @@ static void WriteResponseForPostJson(HttpRequest request, ReadOnlySequence response.AppendEoh(); // write response JSON - JsonWriter jsonWriter = JsonWriter.Create(response, true, prettyPrint: false); + var jsonWriter = new JsonWriter(new BufferWriter>(response), true, prettyPrint: false); jsonWriter.WriteObjectStart(); jsonWriter.WriteArrayStart("values"); for (int i = 0; i < requestedCount; i++) diff --git a/src/System.Text.JsonLab/System/Text/Json/JsonWriter.cs b/src/System.Text.JsonLab/System/Text/Json/JsonWriter.cs index a0fad0b18e9..2dfaf973fd9 100644 --- a/src/System.Text.JsonLab/System/Text/Json/JsonWriter.cs +++ b/src/System.Text.JsonLab/System/Text/Json/JsonWriter.cs @@ -10,13 +10,13 @@ namespace System.Text.JsonLab { - public ref struct JsonWriter where TBufferWriter : IBufferWriter + public ref struct JsonWriter { private static readonly byte[] s_newLineUtf8 = Encoding.UTF8.GetBytes(Environment.NewLine); private static readonly char[] s_newLineUtf16 = Environment.NewLine.ToCharArray(); private readonly bool _prettyPrint; - private BufferWriter _bufferWriter; + private BufferWriter> _bufferWriter; private readonly bool _isUtf8; private int _indent; @@ -27,7 +27,7 @@ namespace System.Text.JsonLab /// /// An instance of used for writing bytes to an output channel. /// Specifies whether to add whitespace to the output text for user readability. - public JsonWriter(BufferWriter bufferWriter, bool isUtf8, bool prettyPrint = false) + public JsonWriter(BufferWriter> bufferWriter, bool isUtf8, bool prettyPrint = false) { _bufferWriter = bufferWriter; _prettyPrint = prettyPrint; @@ -1557,24 +1557,4 @@ private int AddNewLineAndIndentation(Span buffer) return offset; } } - - //TODO: Move to a separate file - public static class JsonWriter - { - public static JsonWriter Create( - TBufferWriter bufferWriter, - bool isUtf8, - bool prettyPrint = false) where TBufferWriter : IBufferWriter - { - return new JsonWriter(BufferWriter.Create(bufferWriter), isUtf8, prettyPrint); - } - - public static JsonWriter Create( - BufferWriter bufferWriter, - bool isUtf8, - bool prettyPrint = false) where TBufferWriter : IBufferWriter - { - return new JsonWriter(bufferWriter, isUtf8, prettyPrint); - } - } } diff --git a/tests/Benchmarks/System.IO.Pipelines/E2E.cs b/tests/Benchmarks/System.IO.Pipelines/E2E.cs index c1146f09367..2e2230034a3 100644 --- a/tests/Benchmarks/System.IO.Pipelines/E2E.cs +++ b/tests/Benchmarks/System.IO.Pipelines/E2E.cs @@ -2,7 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Buffers; using System.Buffers.Text; +using System.Buffers.Writer; using System.IO.Pipelines.Samples; using System.Text; using System.Text.Formatting; @@ -59,7 +61,7 @@ public void TechEmpowerJsonNoIO(int numberOfRequests, int concurrentConnections) formatter.Append("\r\n\r\n"); // write body - JsonWriter> writer = JsonWriter.Create(formatter, true, true); + var writer = new JsonWriter(new BufferWriter>(formatter), true, true); writer.WriteObjectStart(); writer.WriteAttribute("message", "Hello, World!"); writer.WriteObjectEnd(); diff --git a/tests/Benchmarks/System.Text.JsonLab/JsonWriterPerf.cs b/tests/Benchmarks/System.Text.JsonLab/JsonWriterPerf.cs index 48428a57a0a..d42b232cde4 100644 --- a/tests/Benchmarks/System.Text.JsonLab/JsonWriterPerf.cs +++ b/tests/Benchmarks/System.Text.JsonLab/JsonWriterPerf.cs @@ -2,7 +2,9 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using BenchmarkDotNet.Attributes; +using System.Buffers; using System.Buffers.Text; +using System.Buffers.Writer; using System.IO; using System.Text.Formatting; @@ -56,10 +58,11 @@ public void Setup() public void WriterSystemTextJsonBasic() { _arrayFormatter.Clear(); + var bufferWriter = new BufferWriter>(_arrayFormatter); if (IsUTF8Encoded) - WriterSystemTextJsonBasicUtf8(Formatted, _arrayFormatter, _data); + WriterSystemTextJsonBasicUtf8(Formatted, bufferWriter, _data); else - WriterSystemTextJsonBasicUtf16(Formatted, _arrayFormatter, _data); + WriterSystemTextJsonBasicUtf16(Formatted, bufferWriter, _data); } [Benchmark] @@ -72,10 +75,11 @@ public void WriterNewtonsoftBasic() public void WriterSystemTextJsonHelloWorld() { _arrayFormatter.Clear(); + var bufferWriter = new BufferWriter>(_arrayFormatter); if (IsUTF8Encoded) - WriterSystemTextJsonHelloWorldUtf8(Formatted, _arrayFormatter); + WriterSystemTextJsonHelloWorldUtf8(Formatted, bufferWriter); else - WriterSystemTextJsonHelloWorldUtf16(Formatted, _arrayFormatter); + WriterSystemTextJsonHelloWorldUtf16(Formatted, bufferWriter); } [Benchmark] @@ -100,9 +104,9 @@ private TextWriter GetWriter() return writer; } - private static void WriterSystemTextJsonBasicUtf8(bool formatted, ArrayFormatter output, int[] data) + private static void WriterSystemTextJsonBasicUtf8(bool formatted, BufferWriter> output, int[] data) { - JsonWriter json = JsonWriter.Create(output, true, formatted); + var json = new JsonWriter(output, true, formatted); json.WriteObjectStart(); json.WriteAttribute("age", 42); @@ -130,9 +134,9 @@ private static void WriterSystemTextJsonBasicUtf8(bool formatted, ArrayFormatter json.Flush(); } - private static void WriterSystemTextJsonBasicUtf16(bool formatted, ArrayFormatter output, int[] data) + private static void WriterSystemTextJsonBasicUtf16(bool formatted, BufferWriter> output, int[] data) { - JsonWriter json = JsonWriter.Create(output, false, formatted); + var json = new JsonWriter(output, false, formatted); json.WriteObjectStart(); json.WriteAttribute("age", 42); @@ -201,9 +205,9 @@ private static void WriterNewtonsoftBasic(bool formatted, TextWriter writer, int } } - private static void WriterSystemTextJsonHelloWorldUtf8(bool formatted, ArrayFormatter output) + private static void WriterSystemTextJsonHelloWorldUtf8(bool formatted, BufferWriter> output) { - JsonWriter json = JsonWriter.Create(output, true, formatted); + var json = new JsonWriter(output, true, formatted); json.WriteObjectStart(); json.WriteAttribute("message", "Hello, World!"); @@ -211,9 +215,9 @@ private static void WriterSystemTextJsonHelloWorldUtf8(bool formatted, ArrayForm json.Flush(); } - private static void WriterSystemTextJsonHelloWorldUtf16(bool formatted, ArrayFormatter output) + private static void WriterSystemTextJsonHelloWorldUtf16(bool formatted, BufferWriter> output) { - JsonWriter json = JsonWriter.Create(output, false, formatted); + var json = new JsonWriter(output, false, formatted); json.WriteObjectStart(); json.WriteAttribute("message", "Hello, World!"); diff --git a/tests/System.Text.JsonLab.Tests/JsonWriterTests.cs b/tests/System.Text.JsonLab.Tests/JsonWriterTests.cs index 3c94b0f7668..6cc6e38527d 100644 --- a/tests/System.Text.JsonLab.Tests/JsonWriterTests.cs +++ b/tests/System.Text.JsonLab.Tests/JsonWriterTests.cs @@ -6,6 +6,8 @@ using System.Text.Formatting; using System.Buffers.Text; using System.IO; +using System.Buffers.Writer; +using System.Buffers; namespace System.Text.JsonLab.Tests { @@ -17,7 +19,8 @@ public class JsonWriterTests public void WriteJsonUtf8() { var formatter = new ArrayFormatter(1024, SymbolTable.InvariantUtf8); - JsonWriter json = JsonWriter.Create(formatter, true, prettyPrint: false); + var bufferWriter = new BufferWriter>(formatter); + var json = new JsonWriter(bufferWriter, true, prettyPrint: false); Write(ref json); var formatted = formatter.Formatted; @@ -25,7 +28,8 @@ public void WriteJsonUtf8() Assert.Equal(expected, str.Replace(" ", "")); formatter.Clear(); - json = JsonWriter.Create(formatter, true, prettyPrint: true); + bufferWriter = new BufferWriter>(formatter); + json = new JsonWriter(bufferWriter, true, prettyPrint: true); Write(ref json); formatted = formatter.Formatted; @@ -37,7 +41,8 @@ public void WriteJsonUtf8() public void WriteJsonUtf16() { var formatter = new ArrayFormatter(1024, SymbolTable.InvariantUtf16); - JsonWriter json = JsonWriter.Create(formatter, false, prettyPrint: false); + var bufferWriter = new BufferWriter>(formatter); + var json = new JsonWriter(bufferWriter, false, prettyPrint: false); Write(ref json); var formatted = formatter.Formatted; @@ -45,7 +50,8 @@ public void WriteJsonUtf16() Assert.Equal(expected, str.Replace(" ", "")); formatter.Clear(); - json = JsonWriter.Create(formatter, false, prettyPrint: true); + bufferWriter = new BufferWriter>(formatter); + json = new JsonWriter(bufferWriter, false, prettyPrint: true); Write(ref json); formatted = formatter.Formatted; @@ -54,7 +60,7 @@ public void WriteJsonUtf16() } static string expected = "{\"age\":30,\"first\":\"John\",\"last\":\"Smith\",\"phoneNumbers\":[\"425-000-1212\",\"425-000-1213\",null],\"address\":{\"street\":\"1MicrosoftWay\",\"city\":\"Redmond\",\"zip\":98052},\"values\":[425121,-425122,425123]}"; - static void Write(ref JsonWriter json) + static void Write(ref JsonWriter json) { json.WriteObjectStart(); json.WriteAttribute("age", 30); @@ -87,7 +93,8 @@ public void WriteHelloWorldJsonUtf16(bool prettyPrint) string expectedStr = GetHelloWorldExpectedString(prettyPrint, isUtf8: false); var output = new ArrayFormatter(1024, SymbolTable.InvariantUtf16); - JsonWriter jsonUtf16 = JsonWriter.Create(output, false, prettyPrint); + var bufferWriter = new BufferWriter>(output); + var jsonUtf16 = new JsonWriter(bufferWriter, false, prettyPrint); jsonUtf16.WriteObjectStart(); jsonUtf16.WriteAttribute("message", "Hello, World!"); @@ -108,7 +115,8 @@ public void WriteHelloWorldJsonUtf8(bool prettyPrint) string expectedStr = GetHelloWorldExpectedString(prettyPrint, isUtf8: true); var output = new ArrayFormatter(1024, SymbolTable.InvariantUtf8); - JsonWriter jsonUtf8 = JsonWriter.Create(output, true, prettyPrint); + var bufferWriter = new BufferWriter>(output); + var jsonUtf8 = new JsonWriter(bufferWriter, true, prettyPrint); jsonUtf8.WriteObjectStart(); jsonUtf8.WriteAttribute("message", "Hello, World!"); @@ -131,7 +139,8 @@ public void WriteBasicJsonUtf16(bool prettyPrint) string expectedStr = GetExpectedString(prettyPrint, isUtf8: false, data); var output = new ArrayFormatter(1024, SymbolTable.InvariantUtf16); - JsonWriter jsonUtf16 = JsonWriter.Create(output, false, prettyPrint); + var bufferWriter = new BufferWriter>(output); + var jsonUtf16 = new JsonWriter(bufferWriter, false, prettyPrint); jsonUtf16.WriteObjectStart(); jsonUtf16.WriteAttribute("age", 42); @@ -175,7 +184,8 @@ public void WriteBasicJsonUtf8(bool prettyPrint) string expectedStr = GetExpectedString(prettyPrint, isUtf8: true, data); var output = new ArrayFormatter(1024, SymbolTable.InvariantUtf8); - JsonWriter jsonUtf8 = JsonWriter.Create(output, true, prettyPrint); + var bufferWriter = new BufferWriter>(output); + var jsonUtf8 = new JsonWriter(bufferWriter, true, prettyPrint); jsonUtf8.WriteObjectStart(); jsonUtf8.WriteAttribute("age", 42);