Skip to content

Commit

Permalink
Improve ArraySegmentStream hotpath (#2241)
Browse files Browse the repository at this point in the history
- Improve the encoding/decoding hotpath in the `ArraySegmentStream` by adding override for ReadByte/WriteByte and enforce inlining.
  • Loading branch information
mregen committed Jul 27, 2023
1 parent 8c2bf35 commit 9256c2e
Showing 1 changed file with 84 additions and 12 deletions.
96 changes: 84 additions & 12 deletions Stack/Opc.Ua.Core/Stack/Bindings/ArraySegmentStream.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

using System;
using System.IO;
using System.Runtime.CompilerServices;

namespace Opc.Ua.Bindings
{
Expand Down Expand Up @@ -131,6 +132,31 @@ public override long Position
}
}

/// <summary cref="Stream.ReadByte()" />
public override int ReadByte()
{
do
{
// check for end of stream.
if (m_currentBuffer.Array == null)
{
return -1;
}

int bytesLeft = GetBufferCount(m_bufferIndex) - m_currentPosition;

// copy the bytes requested.
if (bytesLeft > 0)
{
return m_currentBuffer.Array[m_currentBuffer.Offset + m_currentPosition++];
}

// move to next buffer.
SetCurrentBuffer(m_bufferIndex + 1);

} while (true);
}

/// <summary cref="Stream.Read(byte[], int, int)" />
public override int Read(byte[] buffer, int offset, int count)
{
Expand Down Expand Up @@ -222,26 +248,47 @@ public override void SetLength(long value)
throw new NotSupportedException();
}

/// <summary cref="Stream.Write(byte[],int,int)" />
public override void Write(byte[] buffer, int offset, int count)
/// <summary cref="Stream.WriteByte(byte)" />
public override void WriteByte(byte value)
{
while (count > 0)
do
{
// check for end of stream.
if (m_currentBuffer.Array == null)
// allocate new buffer if necessary
CheckEndOfStream();

int bytesLeft = m_currentBuffer.Count - m_currentPosition;

// copy the bytes requested.
if (bytesLeft >= 1)
{
if (m_bufferManager == null)
m_currentBuffer.Array[m_currentBuffer.Offset + m_currentPosition] = value;
m_currentPosition++;

if (m_bufferIndex == m_buffers.Count - 1)
{
throw new IOException("Attempt to write past end of stream.");
if (m_endOfLastBuffer < m_currentPosition)
{
m_endOfLastBuffer = m_currentPosition;
}
}

byte[] newBuffer = m_bufferManager.TakeBuffer(m_bufferSize, "ArraySegmentStream.Write");
m_buffers.Add(new ArraySegment<byte>(newBuffer, m_start, m_count));
m_endOfLastBuffer = 0;

SetCurrentBuffer(m_buffers.Count - 1);
return;
}

// move to next buffer.
SetCurrentBuffer(m_bufferIndex + 1);

} while (true);
}

/// <summary cref="Stream.Write(byte[],int,int)" />
public override void Write(byte[] buffer, int offset, int count)
{
while (count > 0)
{
// check for end of stream.
CheckEndOfStream();

int bytesLeft = m_currentBuffer.Count - m_currentPosition;

// copy the bytes requested.
Expand Down Expand Up @@ -278,6 +325,7 @@ public override void Write(byte[] buffer, int offset, int count)
/// <summary>
/// Sets the current buffer.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void SetCurrentBuffer(int index)
{
if (index < 0 || index >= m_buffers.Count)
Expand Down Expand Up @@ -334,6 +382,7 @@ private int GetAbsolutePosition()
/// <summary>
/// Returns the number of bytes used in the buffer.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private int GetBufferCount(int index)
{
if (index == m_buffers.Count - 1)
Expand All @@ -343,6 +392,29 @@ private int GetBufferCount(int index)

return m_buffers[index].Count;
}

/// <summary>
/// Check if end of stream is reached and take new buffer if necessary.
/// </summary>
/// <exception cref="IOException">Throws if end of stream is reached.</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void CheckEndOfStream()
{
// check for end of stream.
if (m_currentBuffer.Array == null)
{
if (m_bufferManager == null)
{
throw new IOException("Attempt to write past end of stream.");
}

byte[] newBuffer = m_bufferManager.TakeBuffer(m_bufferSize, "ArraySegmentStream.Write");
m_buffers.Add(new ArraySegment<byte>(newBuffer, m_start, m_count));
m_endOfLastBuffer = 0;

SetCurrentBuffer(m_buffers.Count - 1);
}
}
#endregion

#region Private Fields
Expand Down

0 comments on commit 9256c2e

Please sign in to comment.