Switch ReadFromBuffer to span

This commit is contained in:
Peter Butzhammer
2024-04-25 12:16:49 +02:00
parent c5a6b12843
commit b400a7215a
2 changed files with 22 additions and 19 deletions

View File

@@ -9,7 +9,7 @@ internal abstract class ConverterTestBase
public static MethodInfo CreateReadMethod(ConverterTestCase tc) public static MethodInfo CreateReadMethod(ConverterTestCase tc)
{ {
var convertMi = typeof(ValueConverter).GetMethod(nameof(ValueConverter.ReadFromBuffer)); var convertMi = typeof(ConverterTestBase).GetMethod(nameof(ReadFromBuffer));
var convert = convertMi!.MakeGenericMethod(tc.Value.GetType()); var convert = convertMi!.MakeGenericMethod(tc.Value.GetType());
return convert; return convert;
} }
@@ -67,12 +67,17 @@ internal abstract class ConverterTestBase
/// <summary> /// <summary>
/// This helper method exists, since I could not manage to invoke a generic method /// This helper method exists, since I could not manage to invoke a generic method
/// accepring a Span&lt;T&gt; as parameter. /// with a Span&lt;T&gt; parameter.
/// </summary> /// </summary>
public static void WriteToBuffer<TValue>(byte[] buffer, TValue value, VariableAddress address) public static void WriteToBuffer<TValue>(byte[] buffer, TValue value, VariableAddress address) =>
{
ValueConverter.WriteToBuffer(buffer, value, address); ValueConverter.WriteToBuffer(buffer, value, address);
}
/// <summary>
/// This helper method exists, since I could not manage to invoke a generic method
/// with a Span&lt;T&gt; parameter.
/// </summary>
public static TValue ReadFromBuffer<TValue>(byte[] buffer, VariableAddress address) =>
ValueConverter.ReadFromBuffer<TValue>(buffer, address);
public record ConverterTestCase(object Value, string Address, byte[] Data) public record ConverterTestCase(object Value, string Address, byte[] Data)
{ {

View File

@@ -143,42 +143,40 @@ internal static class ValueConverter
{ {
return address.Type switch return address.Type switch
{ {
DbType.String => ParseString(), DbType.String => ParseString(buffer),
DbType.WString => ParseWString(), DbType.WString => ParseWString(buffer),
DbType.Byte => Encoding.ASCII.GetString(buffer.ToArray()), DbType.Byte => Encoding.ASCII.GetString(buffer),
_ => throw new DataTypeMissmatchException($"Cannot read string from {address.Type}", typeof(string), address) _ => throw new DataTypeMissmatchException($"Cannot read string from {address.Type}", typeof(string), address)
}; };
string ParseString() string ParseString(Span<byte> data)
{ {
// First byte is maximal length // First byte is maximal length
// Second byte is actual length // Second byte is actual length
// https://support.industry.siemens.com/cs/mdm/109747174?c=94063831435&lc=de-DE // https://support.industry.siemens.com/cs/mdm/109747174?c=94063831435&lc=de-DE
var length = Math.Min(address.Length, buffer[1]); var length = Math.Min(address.Length, data[1]);
return Encoding.ASCII.GetString(buffer, 2, length); return Encoding.ASCII.GetString(data.Slice(2, length));
} }
string ParseWString() string ParseWString(Span<byte> data)
{ {
// First 2 bytes are maximal length // First 2 bytes are maximal length
// Second 2 bytes are actual length // Second 2 bytes are actual length
// https://support.industry.siemens.com/cs/mdm/109747174?c=94063855243&lc=de-DE // https://support.industry.siemens.com/cs/mdm/109747174?c=94063855243&lc=de-DE
// the length of the string is two bytes per // the length of the string is two bytes per character
var length = Math.Min(address.Length, BinaryPrimitives.ReadUInt16BigEndian(buffer.AsSpan(2, 2))) * 2; var length = Math.Min(address.Length, BinaryPrimitives.ReadUInt16BigEndian(data.Slice(2, 2))) * 2;
return Encoding.BigEndianUnicode.GetString(buffer, 4, length); return Encoding.BigEndianUnicode.GetString(data.Slice(4, length));
} }
} }
}, },
}; };
public static TValue ReadFromBuffer<TValue>(byte[] buffer, VariableAddress address) public static TValue ReadFromBuffer<TValue>(Span<byte> buffer, VariableAddress address)
{ {
// Todo: Change to Span<byte> when switched to newer .net
if (buffer.Length < address.BufferLength) if (buffer.Length < address.BufferLength)
throw new ArgumentException($"Buffer must be at least {address.BufferLength} bytes long for {address}", nameof(buffer)); throw new ArgumentException($"Buffer must be at least {address.BufferLength} bytes long for {address}", nameof(buffer));
@@ -204,7 +202,7 @@ internal static class ValueConverter
writeFunc(buffer, address, value); writeFunc(buffer, address, value);
} }
delegate object ReadFunc(byte[] data, VariableAddress address); delegate object ReadFunc(Span<byte> data, VariableAddress address);
[StructLayout(LayoutKind.Explicit)] [StructLayout(LayoutKind.Explicit)]
private struct UInt32SingleMap private struct UInt32SingleMap