Implement EnumAdapter

#17
This commit is contained in:
Alexander Luzgarev 2025-03-15 09:04:47 +01:00
parent d41020c6b8
commit 5a2226629a
9 changed files with 130 additions and 22 deletions

View File

@ -10,8 +10,11 @@ namespace MatFileHandler.Tests
/// <summary>
/// Tests of Matlab array manipulation.
/// </summary>
public class ArrayHandlingTests : IDisposable
public sealed class ArrayHandlingTests : IDisposable
{
/// <summary>
/// Setup for array handling tests.
/// </summary>
public ArrayHandlingTests()
{
Builder = new DataBuilder();
@ -108,7 +111,7 @@ namespace MatFileHandler.Tests
var file = Builder.NewFile(new List<IVariable>());
Assert.NotNull(file);
}
private static void TestCreateArrayOf<T>()
where T : struct
{
@ -116,8 +119,12 @@ namespace MatFileHandler.Tests
Assert.NotNull(array);
}
/// <summary>
/// Cleanup.
/// </summary>
public void Dispose()
{
}
}
}

View File

@ -164,6 +164,23 @@ namespace MatFileHandler.Tests
Assert.Null(array.ConvertToComplexArray());
}
/// <summary>
/// Test reading an enumeration.
/// </summary>
[Fact]
public void TestEnum()
{
var matFile = GetTests("good")["enum"];
var days = matFile["days"].Value;
var enumeration = new EnumAdapter(days);
Assert.Equal(5, enumeration.Values.Count);
Assert.Equal("Wednesday", enumeration.ValueNames[enumeration.Values[0]]);
Assert.Equal("Saturday", enumeration.ValueNames[enumeration.Values[1]]);
Assert.Equal("Monday", enumeration.ValueNames[enumeration.Values[2]]);
Assert.Equal("Wednesday", enumeration.ValueNames[enumeration.Values[3]]);
Assert.Equal("Saturday", enumeration.ValueNames[enumeration.Values[4]]);
}
/// <summary>
/// Test reading a structure array.
/// </summary>
@ -487,6 +504,9 @@ namespace MatFileHandler.Tests
Assert.Null(d0);
}
/// <summary>
/// Test 3-dimensional arrays.
/// </summary>
[Fact]
public void Test_3DArrays()
{
@ -518,7 +538,10 @@ namespace MatFileHandler.Tests
Assert.Equal(expected, obj.ConvertToMultidimensionalDoubleArray());
Assert.Null(obj.ConvertTo2dDoubleArray());
}
/// <summary>
/// Test four-dimensional arrays.
/// </summary>
[Fact]
public void Test_4DArrays()
{

Binary file not shown.

View File

@ -258,7 +258,7 @@ namespace MatFileHandler
}
else
{
return new Opaque(name, typeDescription, className, new int[] { }, data);
return new Opaque(name, typeDescription, className, new int[] { }, data, subsystemData);
}
}

View File

@ -0,0 +1,60 @@
// Copyright 2017-2018 Alexander Luzgarev
namespace MatFileHandler
{
/// <summary>
/// A better interface for using enum adapter.
/// </summary>
public class EnumAdapter
{
/// <summary>
/// Initializes a new instance of the <see cref="EnumAdapter"/> class.
/// </summary>
/// <param name="array">Source enum object.</param>
public EnumAdapter(IArray array)
{
var matObject = array as Opaque;
if (matObject?.RawData is not IStructureArray rawData)
{
throw new HandlerException("Cannot extract data for the enum adapter.");
}
if (rawData["ValueNames"] is not IArrayOf<uint> valueNamesData)
{
throw new HandlerException("Cannot extract data for the enum adapter.");
}
var numberOfNames = valueNamesData.Count;
var valueNames = new string[numberOfNames];
var names = matObject.SubsystemData.FieldNames;
for (var i = 0; i < numberOfNames; i++)
{
valueNames[i] = names[valueNamesData[i] - 1];
}
if (rawData["ValueIndices"] is not IArrayOf<uint> valueIndices)
{
throw new HandlerException("Cannot extract data for the enum adapter.");
}
ClassName = matObject.ClassName;
ValueNames = valueNames;
Values = valueIndices;
}
/// <summary>
/// Gets name of the enumeration class.
/// </summary>
public string ClassName { get; }
/// <summary>
/// Gets names of the enumeration values.
/// </summary>
public string[] ValueNames { get; }
/// <summary>
/// Gets indices of values stored in the variable.
/// </summary>
public IArrayOf<uint> Values { get; }
}
}

View File

@ -26,12 +26,14 @@ namespace MatFileHandler
/// <param name="className">Class name.</param>
/// <param name="dimensions">Dimensions of the object.</param>
/// <param name="rawData">Raw object's data.</param>
public Opaque(string name, string typeDescription, string className, int[] dimensions, DataElement rawData)
/// <param name="subsystemData">Subsystem data.</param>
public Opaque(string name, string typeDescription, string className, int[] dimensions, DataElement rawData, SubsystemData subsystemData)
: base(new ArrayFlags(ArrayType.MxOpaque, 0), dimensions, name)
{
TypeDescription = typeDescription ?? throw new ArgumentNullException(nameof(typeDescription));
ClassName = className ?? throw new ArgumentNullException(nameof(className));
RawData = rawData ?? throw new ArgumentNullException(nameof(rawData));
SubsystemData = subsystemData ?? throw new ArgumentNullException(nameof(subsystemData));
}
/// <summary>
@ -49,6 +51,11 @@ namespace MatFileHandler
/// </summary>
public string TypeDescription { get; }
/// <summary>
/// Gets subsystem data.
/// </summary>
public SubsystemData SubsystemData { get; }
/// <inheritdoc />
public override Complex[]? ConvertToComplexArray() => null;

View File

@ -12,8 +12,6 @@ namespace MatFileHandler
/// </summary>
internal class OpaqueLink : Opaque, IMatObject
{
private readonly SubsystemData subsystemData;
/// <summary>
/// Initializes a new instance of the <see cref="OpaqueLink"/> class.
/// </summary>
@ -34,11 +32,10 @@ namespace MatFileHandler
int[] indexToObjectId,
int classIndex,
SubsystemData subsystemData)
: base(name, typeDescription, className, dimensions, data)
: base(name, typeDescription, className, dimensions, data, subsystemData)
{
IndexToObjectId = indexToObjectId ?? throw new ArgumentNullException(nameof(indexToObjectId));
ClassIndex = classIndex;
this.subsystemData = subsystemData ?? throw new ArgumentNullException(nameof(subsystemData));
}
/// <summary>
@ -74,9 +71,9 @@ namespace MatFileHandler
/// <summary>
/// Gets name of this object's class.
/// </summary>
public override string ClassName => subsystemData.ClassInformation[ClassIndex].Name;
public override string ClassName => SubsystemData.ClassInformation[ClassIndex].Name;
private string[] FieldNamesArray => subsystemData.ClassInformation[ClassIndex].FieldNames.ToArray();
private string[] FieldNamesArray => SubsystemData.ClassInformation[ClassIndex].FieldNames.ToArray();
/// <inheritdoc />
public IArray this[string field, params int[] list]
@ -108,7 +105,7 @@ namespace MatFileHandler
private bool TryGetValue(string field, out IArray? output, params int[] list)
{
var index = Dimensions.DimFlatten(list);
var maybeFieldIndex = subsystemData.ClassInformation[ClassIndex].FindField(field);
var maybeFieldIndex = SubsystemData.ClassInformation[ClassIndex].FindField(field);
if (!(maybeFieldIndex is int fieldIndex))
{
output = default;
@ -122,9 +119,9 @@ namespace MatFileHandler
}
var objectId = IndexToObjectId[index];
var objectInfo = subsystemData.ObjectInformation[objectId];
var objectInfo = SubsystemData.ObjectInformation[objectId];
var fieldId = objectInfo.FieldLinks[fieldIndex];
output = subsystemData.Data[fieldId];
output = SubsystemData.Data[fieldId];
return true;
}

View File

@ -29,15 +29,18 @@ namespace MatFileHandler
/// </summary>
/// <param name="classInformation">Information about the classes.</param>
/// <param name="objectInformation">Information about the objects.</param>
/// <param name="fieldNames">Field names.</param>
/// <param name="data">Field values.</param>
public SubsystemData(
Dictionary<int, ClassInfo> classInformation,
Dictionary<int, ObjectInfo> objectInformation,
string[] fieldNames,
Dictionary<int, IArray> data)
{
_realData = new RealSubsystemData(
classInformation,
objectInformation,
fieldNames,
data);
}
@ -59,6 +62,12 @@ namespace MatFileHandler
public Dictionary<int, ObjectInfo> ObjectInformation =>
_realData?.ObjectInformation ?? throw new HandlerException("Subsystem data missing.");
/// <summary>
/// Gets field names.
/// </summary>
public string[] FieldNames =>
_realData?.FieldNames ?? throw new HandlerException("Subsystem data missing.");
/// <summary>
/// Initialize this object from another object.
/// This ugly hack allows us to read the opaque objects and store references to
@ -71,6 +80,7 @@ namespace MatFileHandler
_realData = new RealSubsystemData(
data.ClassInformation,
data.ObjectInformation,
data.FieldNames,
data.Data);
}
@ -147,14 +157,17 @@ namespace MatFileHandler
/// </summary>
/// <param name="classInformation">Class information.</param>
/// <param name="objectInformation">Object information.</param>
/// <param name="fieldNames">Field names.</param>
/// <param name="data">Data.</param>
public RealSubsystemData(
Dictionary<int, ClassInfo> classInformation,
Dictionary<int, ObjectInfo> objectInformation,
string[] fieldNames,
IReadOnlyDictionary<int, IArray> data)
{
ClassInformation = classInformation ?? throw new ArgumentNullException(nameof(classInformation));
ObjectInformation = objectInformation ?? throw new ArgumentNullException(nameof(objectInformation));
FieldNames = fieldNames;
Data = data ?? throw new ArgumentNullException(nameof(data));
}
@ -172,6 +185,11 @@ namespace MatFileHandler
/// Gets information about all the objects occurring in the file.
/// </summary>
public Dictionary<int, ObjectInfo> ObjectInformation { get; }
/// <summary>
/// Gets field names.
/// </summary>
public string[] FieldNames { get; }
}
}
}

View File

@ -2,6 +2,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
@ -58,7 +59,7 @@ namespace MatFileHandler
data[i] = TransformOpaqueData(opaqueData[i + 2], subsystemData);
}
return new SubsystemData(classInformation, objectInformation, data);
return new SubsystemData(classInformation, objectInformation, fieldNames, data);
}
private static Dictionary<int, Dictionary<int, int>> ReadObjectPositionsToValues(byte[] info, int[] offsets, int numberOfObjectPositions)
@ -303,20 +304,15 @@ namespace MatFileHandler
{
var next = BitConverter.ToInt32(bytes, position);
position += 4;
if (next == 0)
if (next == bytes.Length)
{
if (position % 8 != 0)
{
position += 4;
}
break;
}
offsets.Add(next);
}
return (offsets.ToArray(), position);
return (offsets.ToArray(), 40);
}
private static IArray TransformOpaqueData(IArray array, SubsystemData subsystemData)