Skip to content

Commit 6964727

Browse files
committed
Do some sillyness to avoid large allocations
1 parent 6df4f3a commit 6964727

File tree

1 file changed

+119
-24
lines changed

1 file changed

+119
-24
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,119 @@
1-
// Licensed to the .NET Foundation under one or more agreements.
2-
// The .NET Foundation licenses this file to you under the MIT license.
3-
// See the LICENSE file in the project root for more information.
4-
5-
using System;
6-
using System.IO;
7-
using System.Xml.Linq;
8-
9-
#nullable enable
10-
11-
namespace Microsoft.DotNet.XHarness.TestRunners.Xunit;
12-
13-
internal class WasmXmlResultWriter
14-
{
15-
public static void WriteOnSingleLine(XElement assembliesElement)
16-
{
17-
using var ms = new MemoryStream();
18-
assembliesElement.Save(ms);
19-
ms.TryGetBuffer(out var bytes);
20-
var base64 = Convert.ToBase64String(bytes, Base64FormattingOptions.None);
21-
Console.WriteLine($"STARTRESULTXML {bytes.Count} {base64} ENDRESULTXML");
22-
Console.WriteLine($"Finished writing {bytes.Count} bytes of RESULTXML");
23-
}
24-
}
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
using System.IO;
7+
using System.Runtime.InteropServices;
8+
using System.Xml.Linq;
9+
using System.Text;
10+
using System.Security.Cryptography;
11+
12+
#nullable enable
13+
14+
namespace Microsoft.DotNet.XHarness.TestRunners.Xunit;
15+
16+
internal class WasmXmlResultWriter
17+
{
18+
#if !NET || DEBUG
19+
public static void WriteOnSingleLine(XElement assembliesElement)
20+
{
21+
using var ms = new MemoryStream();
22+
assembliesElement.Save(ms);
23+
ms.TryGetBuffer(out var bytes);
24+
var base64 = Convert.ToBase64String(bytes, Base64FormattingOptions.None);
25+
Console.WriteLine($"STARTRESULTXML {bytes.Count} {base64} ENDRESULTXML");
26+
Console.WriteLine($"Finished writing {bytes.Count} bytes of RESULTXML");
27+
}
28+
#else
29+
private class ToBase64CharTransform : ICryptoTransform
30+
{
31+
private readonly ToBase64Transform _base64Transform = new ToBase64Transform();
32+
33+
public int InputBlockSize => _base64Transform.InputBlockSize;
34+
public int OutputBlockSize => _base64Transform.OutputBlockSize * 2;
35+
public bool CanTransformMultipleBlocks => _base64Transform.CanTransformMultipleBlocks;
36+
public bool CanReuseTransform => _base64Transform.CanReuseTransform;
37+
38+
public void Dispose()
39+
{
40+
_base64Transform.Dispose();
41+
}
42+
43+
public int TransformBlock(
44+
byte[] inputBuffer, int inputOffset, int inputCount,
45+
byte[] outputBuffer, int outputOffset)
46+
{
47+
int totalBytesWritten = 0;
48+
int inputProcessed = 0;
49+
50+
while (inputProcessed < inputCount)
51+
{
52+
int bytesToProcess = Math.Min(InputBlockSize, inputCount - inputProcessed);
53+
54+
// Calculate positions in the output buffer
55+
int base64OutputStart = outputOffset + totalBytesWritten + OutputBlockSize / 2;
56+
int base64OutputLength = _base64Transform.OutputBlockSize;
57+
58+
// Apply Base64 transformation directly to the second half of the output buffer
59+
int base64BytesWritten = _base64Transform.TransformBlock(
60+
inputBuffer, inputOffset + inputProcessed, bytesToProcess,
61+
outputBuffer, base64OutputStart);
62+
63+
var outputSpan = MemoryMarshal.Cast<byte, char>(outputBuffer.AsSpan(outputOffset + totalBytesWritten, OutputBlockSize));
64+
for (int i = 0; i < base64BytesWritten; i++)
65+
{
66+
char base64Char = (char)outputBuffer[base64OutputStart + i];
67+
outputSpan[i] = base64Char;
68+
}
69+
70+
inputProcessed += bytesToProcess;
71+
totalBytesWritten += base64BytesWritten * 2;
72+
}
73+
74+
return totalBytesWritten;
75+
}
76+
77+
public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
78+
{
79+
// Apply Base64 transformation to the final block
80+
byte[] base64Buffer = _base64Transform.TransformFinalBlock(inputBuffer, inputOffset, inputCount);
81+
82+
// Expand each Base64 byte to two bytes in the output buffer
83+
byte[] outputBuffer = new byte[base64Buffer.Length * 2];
84+
Span<char> outputSpan = MemoryMarshal.Cast<byte, char>(outputBuffer.AsSpan());
85+
for (int i = 0; i < base64Buffer.Length; i++)
86+
{
87+
// Convert each byte to a char
88+
char base64Char = (char)base64Buffer[i];
89+
outputSpan[i] = base64Char;
90+
}
91+
92+
return outputBuffer;
93+
}
94+
}
95+
96+
public static void WriteOnSingleLine(XElement assembliesElement)
97+
{
98+
using var ms = new MemoryStream();
99+
using var transform = new ToBase64CharTransform();
100+
using var cryptoStream = new CryptoStream(ms, transform, CryptoStreamMode.Write);
101+
102+
// Create a StreamWriter to write the XML content to the CryptoStream
103+
using var xmlWriter = new StreamWriter(cryptoStream, Encoding.UTF8);
104+
105+
assembliesElement.Save(xmlWriter);
106+
107+
// Ensure all data is flushed through the CryptoStream
108+
xmlWriter.Flush();
109+
cryptoStream.FlushFinalBlock();
110+
111+
ms.TryGetBuffer(out var bytes);
112+
var charData = MemoryMarshal.Cast<byte,char>(bytes);
113+
114+
// Output the result
115+
Console.WriteLine($"STARTRESULTXML {charData.Length} {charData} ENDRESULTXML");
116+
Console.WriteLine($"Finished writing {charData.Length} bytes of RESULTXML");
117+
}
118+
#endif
119+
}

0 commit comments

Comments
 (0)