Unify HDF and old-style datatypes

This commit is contained in:
Alexander Luzgarev 2019-03-20 22:15:22 +01:00
parent 433dca8c69
commit bdd04a80b7
11 changed files with 18 additions and 450 deletions

View File

@ -64,7 +64,7 @@ namespace MatFileHandler
{ {
var flags = ConstructArrayFlags(ArrayType.MxCell); var flags = ConstructArrayFlags(ArrayType.MxCell);
var elements = Enumerable.Repeat(MatArray.Empty() as IArray, dimensions.NumberOfElements()).ToList(); var elements = Enumerable.Repeat(MatArray.Empty() as IArray, dimensions.NumberOfElements()).ToList();
return new MatCellArray(flags, dimensions, string.Empty, elements); return new MatCellArray(dimensions, elements);
} }
/// <summary> /// <summary>

View File

@ -223,7 +223,7 @@ namespace MatFileHandler
elements.Add(element); elements.Add(element);
} }
return new MatCellArray(flags, dimensions, name, elements); return new MatCellArray(dimensions, elements);
} }
private DataElementWithArrayFlags ContinueReadingOpaque(BinaryReader reader) private DataElementWithArrayFlags ContinueReadingOpaque(BinaryReader reader)

View File

@ -1,45 +0,0 @@
using System.Numerics;
namespace MatFileHandler.Hdf
{
internal class Array : IArray
{
/// <summary>
/// Initializes a new instance of the <see cref="Array"/> class.
/// </summary>
/// <param name="dimensions">Dimensions of the array.</param>
protected Array(
int[] dimensions)
{
Dimensions = dimensions;
}
/// <inheritdoc />
public int[] Dimensions { get; }
/// <inheritdoc />
public int Count => Dimensions.NumberOfElements();
/// <summary>
/// Returns a new empty array.
/// </summary>
/// <returns>Empty array.</returns>
public static Array Empty()
{
return new Array(System.Array.Empty<int>());
}
public virtual double[] ConvertToDoubleArray()
{
return null;
}
public virtual Complex[] ConvertToComplexArray()
{
return null;
}
/// <inheritdoc />
public bool IsEmpty => Dimensions.Length == 0;
}
}

View File

@ -1,24 +0,0 @@
using System.Collections.Generic;
using System.Linq;
namespace MatFileHandler.Hdf
{
internal class CellArray : Array, ICellArray
{
public CellArray(int[] dimensions, IEnumerable<IArray> elements)
: base(dimensions)
{
Data = elements.ToArray();
}
/// <inheritdoc />
public IArray[] Data { get; }
/// <inheritdoc />
public IArray this[params int[] indices]
{
get => Data[Dimensions.DimFlatten(indices)];
set => Data[Dimensions.DimFlatten(indices)] = value;
}
}
}

View File

@ -1,41 +0,0 @@
using System;
using System.Linq;
using System.Numerics;
namespace MatFileHandler.Hdf
{
internal class CharArray : Array, ICharArray
{
public CharArray(int[] dimensions, string data)
: base(dimensions)
{
StringData = data;
}
public override double[] ConvertToDoubleArray()
{
return Data.Select(Convert.ToDouble).ToArray();
}
public override Complex[] ConvertToComplexArray()
{
return ConvertToDoubleArray().Select(x => new Complex(x, 0.0)).ToArray();
}
public char[] Data => StringData.ToCharArray();
public char this[params int[] list]
{
get => StringData[Dimensions.DimFlatten(list)];
set {
var chars = StringData.ToCharArray();
chars[Dimensions.DimFlatten(list)] = value;
StringData = chars.ToString();
}
}
public string String => StringData;
private string StringData { get; set; }
}
}

View File

@ -1,97 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
namespace MatFileHandler.Hdf
{
/// <summary>
/// A numerical array.
/// </summary>
/// <typeparam name="T">Element type.</typeparam>
internal class NumericalArrayOf<T> : Array, IArrayOf<T>
where T : struct
{
/// <summary>
/// Initializes a new instance of the <see cref="NumericalArrayOf{T}"/> class.
/// </summary>
/// <param name="dimensions">Dimensions of the array.</param>
/// <param name="name">Array name.</param>
/// <param name="data">Array contents.</param>
public NumericalArrayOf(int[] dimensions, T[] data)
: base(dimensions)
{
Data = data;
}
/// <inheritdoc />
public T[] Data { get; }
/// <inheritdoc />
public T this[params int[] list]
{
get => Data[Dimensions.DimFlatten(list)];
set => Data[Dimensions.DimFlatten(list)] = value;
}
/// <summary>
/// Tries to convert the array to an array of Double values.
/// </summary>
/// <returns>Array of values of the array, converted to Double, or null if the conversion is not possible.</returns>
public override double[] ConvertToDoubleArray()
{
return Data as double[] ?? Data.Select(x => Convert.ToDouble((object)x)).ToArray();
}
/// <summary>
/// Tries to convert the array to an array of Complex values.
/// </summary>
/// <returns>Array of values of the array, converted to Complex, or null if the conversion is not possible.</returns>
public override Complex[] ConvertToComplexArray()
{
if (Data is Complex[])
{
return Data as Complex[];
}
if (Data is ComplexOf<sbyte>[])
{
return ConvertToComplex(Data as ComplexOf<sbyte>[]);
}
if (Data is ComplexOf<byte>[])
{
return ConvertToComplex(Data as ComplexOf<byte>[]);
}
if (Data is ComplexOf<short>[])
{
return ConvertToComplex(Data as ComplexOf<short>[]);
}
if (Data is ComplexOf<ushort>[])
{
return ConvertToComplex(Data as ComplexOf<ushort>[]);
}
if (Data is ComplexOf<int>[])
{
return ConvertToComplex(Data as ComplexOf<int>[]);
}
if (Data is ComplexOf<uint>[])
{
return ConvertToComplex(Data as ComplexOf<uint>[]);
}
if (Data is ComplexOf<long>[])
{
return ConvertToComplex(Data as ComplexOf<long>[]);
}
if (Data is ComplexOf<ulong>[])
{
return ConvertToComplex(Data as ComplexOf<ulong>[]);
}
return ConvertToDoubleArray().Select(x => new Complex(x, 0.0)).ToArray();
}
private static Complex[] ConvertToComplex<TS>(IEnumerable<ComplexOf<TS>> array)
where TS : struct
{
return array.Select(x => new Complex(Convert.ToDouble(x.Real), Convert.ToDouble(x.Imaginary))).ToArray();
}
}
}

View File

@ -1,85 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
namespace MatFileHandler.Hdf
{
/// <summary>
/// Sparse array.
/// </summary>
/// <typeparam name="T">Element type.</typeparam>
/// <remarks>Possible values of T: Double, Complex, Boolean.</remarks>
internal class SparseArrayOf<T> : Array, ISparseArrayOf<T>
where T : struct
{
/// <summary>
/// Initializes a new instance of the <see cref="SparseArrayOf{T}"/> class.
/// </summary>
/// <param name="dimensions">Dimensions of the array.</param>
/// <param name="data">Array contents.</param>
public SparseArrayOf(
int[] dimensions,
Dictionary<(int, int), T> data)
: base(dimensions)
{
DataDictionary = data;
}
/// <inheritdoc />
T[] IArrayOf<T>.Data =>
Enumerable.Range(0, Dimensions[0] * Dimensions[1])
.Select(i => this[i])
.ToArray();
/// <inheritdoc />
public IReadOnlyDictionary<(int, int), T> Data => DataDictionary;
private Dictionary<(int, int), T> DataDictionary { get; }
/// <inheritdoc />
public T this[params int[] list]
{
get
{
var rowAndColumn = GetRowAndColumn(list);
return DataDictionary.ContainsKey(rowAndColumn) ? DataDictionary[rowAndColumn] : default(T);
}
set => DataDictionary[GetRowAndColumn(list)] = value;
}
/// <summary>
/// Tries to convert the array to an array of Double values.
/// </summary>
/// <returns>Array of values of the array, converted to Double, or null if the conversion is not possible.</returns>
public override double[] ConvertToDoubleArray()
{
var data = ((IArrayOf<T>)this).Data;
return data as double[] ?? data.Select(x => Convert.ToDouble(x)).ToArray();
}
/// <summary>
/// Tries to convert the array to an array of Complex values.
/// </summary>
/// <returns>Array of values of the array, converted to Complex, or null if the conversion is not possible.</returns>
public override Complex[] ConvertToComplexArray()
{
var data = ((IArrayOf<T>)this).Data;
return data as Complex[] ?? ConvertToDoubleArray().Select(x => new Complex(x, 0.0)).ToArray();
}
private (int row, int column) GetRowAndColumn(int[] indices)
{
switch (indices.Length)
{
case 1:
return (indices[0] % Dimensions[0], indices[0] / Dimensions[0]);
case 2:
return (indices[0], indices[1]);
default:
throw new NotSupportedException("Invalid index for sparse array.");
}
}
}
}

View File

@ -1,140 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace MatFileHandler.Hdf
{
internal class StructureArray : Array, IStructureArray
{
public StructureArray(
int[] dimensions,
Dictionary<string, List<IArray>> fields)
: base(dimensions)
{
Fields = fields;
}
/// <inheritdoc />
public IEnumerable<string> FieldNames => Fields.Keys;
/// <summary>
/// Gets null: not implemented.
/// </summary>
public IReadOnlyDictionary<string, IArray>[] Data => null;
/// <summary>
/// Gets a dictionary that maps field names to lists of values.
/// </summary>
internal Dictionary<string, List<IArray>> Fields { get; }
/// <inheritdoc />
public IArray this[string field, params int[] list]
{
get => Fields[field][Dimensions.DimFlatten(list)];
set => Fields[field][Dimensions.DimFlatten(list)] = value;
}
/// <inheritdoc />
IReadOnlyDictionary<string, IArray> IArrayOf<IReadOnlyDictionary<string, IArray>>.this[params int[] list]
{
get => ExtractStructure(Dimensions.DimFlatten(list));
set => throw new NotSupportedException(
"Cannot set structure elements via this[params int[]] indexer. Use this[string, int[]] instead.");
}
private IReadOnlyDictionary<string, IArray> ExtractStructure(int i)
{
return new HdfStructureArrayElement(this, i);
}
/// <summary>
/// Provides access to an element of a structure array by fields.
/// </summary>
internal class HdfStructureArrayElement : IReadOnlyDictionary<string, IArray>
{
/// <summary>
/// Initializes a new instance of the <see cref="HdfStructureArrayElement"/> class.
/// </summary>
/// <param name="parent">Parent structure array.</param>
/// <param name="index">Index in the structure array.</param>
internal HdfStructureArrayElement(StructureArray parent, int index)
{
Parent = parent;
Index = index;
}
/// <summary>
/// Gets the number of fields.
/// </summary>
public int Count => Parent.Fields.Count;
/// <summary>
/// Gets a list of all fields.
/// </summary>
public IEnumerable<string> Keys => Parent.Fields.Keys;
/// <summary>
/// Gets a list of all values.
/// </summary>
public IEnumerable<IArray> Values => Parent.Fields.Values.Select(array => array[Index]);
private StructureArray Parent { get; }
private int Index { get; }
/// <summary>
/// Gets the value of a given field.
/// </summary>
/// <param name="key">Field name.</param>
/// <returns>The corresponding value.</returns>
public IArray this[string key] => Parent.Fields[key][Index];
/// <summary>
/// Enumerates fieldstructure/value pairs of the dictionary.
/// </summary>
/// <returns>All field/value pairs in the structure.</returns>
public IEnumerator<KeyValuePair<string, IArray>> GetEnumerator()
{
foreach (var field in Parent.Fields)
{
yield return new KeyValuePair<string, IArray>(field.Key, field.Value[Index]);
}
}
/// <summary>
/// Enumerates field/value pairs of the structure.
/// </summary>
/// <returns>All field/value pairs in the structure.</returns>
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
/// <summary>
/// Checks if the structure has a given field.
/// </summary>
/// <param name="key">Field name</param>
/// <returns>True iff the structure has a given field.</returns>
public bool ContainsKey(string key) => Parent.Fields.ContainsKey(key);
/// <summary>
/// Tries to get the value of a given field.
/// </summary>
/// <param name="key">Field name.</param>
/// <param name="value">Value (or null if the field is not present).</param>
/// <returns>Success status of the query.</returns>
public bool TryGetValue(string key, out IArray value)
{
var success = Parent.Fields.TryGetValue(key, out var array);
if (!success)
{
value = default(IArray);
return false;
}
value = array[Index];
return true;
}
}
}
}

View File

@ -186,15 +186,17 @@ namespace MatFileHandler
} }
} }
return new CellArray(dims, elements); return new MatCellArray(dims, elements);
} }
private static IArray ReadCharArray(Dataset dataset, int[] dims) private static IArray ReadCharArray(Dataset dataset, int[] dims)
{ {
var storageSize = dataset.GetStorageSize(); var storageSize = dataset.GetStorageSize();
var data = ReadDataset(dataset, Hdf.Type.NativeUInt16, storageSize); var data = ReadDataset(dataset, Hdf.Type.NativeUInt16, storageSize);
var uInt16Data = new ushort[data.Length / sizeof(ushort)];
Buffer.BlockCopy(data, 0, uInt16Data, 0, data.Length);
var str = Encoding.Unicode.GetString(data); var str = Encoding.Unicode.GetString(data);
return new CharArray(dims, str); return new MatCharArrayOf<ushort>(dims, uInt16Data, str);
} }
private static (T[] real, T[] imaginary) ReadComplexData<T>( private static (T[] real, T[] imaginary) ReadComplexData<T>(
@ -226,7 +228,7 @@ namespace MatFileHandler
switch (arrayType) switch (arrayType)
{ {
case MatlabClass.MEmpty: case MatlabClass.MEmpty:
return Hdf.Array.Empty(); return MatArray.Empty();
case MatlabClass.MLogical: case MatlabClass.MLogical:
return ReadNumericalArray<bool>(dataset, dims, arrayType); return ReadNumericalArray<bool>(dataset, dims, arrayType);
case MatlabClass.MChar: case MatlabClass.MChar:
@ -321,7 +323,7 @@ namespace MatFileHandler
switch (arrayType) switch (arrayType)
{ {
case MatlabClass.MEmpty: case MatlabClass.MEmpty:
return Hdf.Array.Empty(); return MatArray.Empty();
case MatlabClass.MLogical: case MatlabClass.MLogical:
return ReadSparseArray<bool>(group.Id, arrayType); return ReadSparseArray<bool>(group.Id, arrayType);
case MatlabClass.MInt8: case MatlabClass.MInt8:
@ -390,7 +392,7 @@ namespace MatFileHandler
convertedRealData as double[], convertedRealData as double[],
convertedImaginaryData as double[]) convertedImaginaryData as double[])
.ToArray(); .ToArray();
return new NumericalArrayOf<Complex>(dims, complexData); return new MatNumericalArrayOf<Complex>(dims, complexData);
} }
else else
{ {
@ -399,7 +401,7 @@ namespace MatFileHandler
convertedRealData, convertedRealData,
convertedImaginaryData) convertedImaginaryData)
.ToArray(); .ToArray();
return new NumericalArrayOf<ComplexOf<T>>(dims, complexData); return new MatNumericalArrayOf<ComplexOf<T>>(dims, complexData);
} }
} }
@ -410,7 +412,7 @@ namespace MatFileHandler
var data = ReadDataset(dataset, H5tTypeFromHdfMatlabClass(arrayType), dataSize); var data = ReadDataset(dataset, H5tTypeFromHdfMatlabClass(arrayType), dataSize);
var convertedData = ConvertDataToProperType<T>(data, arrayType); var convertedData = ConvertDataToProperType<T>(data, arrayType);
return new NumericalArrayOf<T>(dims, convertedData); return new MatNumericalArrayOf<T>(dims, convertedData);
} }
private static IArray ReadSparseArray<T>(long groupId, MatlabClass arrayType) private static IArray ReadSparseArray<T>(long groupId, MatlabClass arrayType)
@ -469,7 +471,7 @@ namespace MatFileHandler
rowIndex, rowIndex,
columnIndex, columnIndex,
j => complexData[j]); j => complexData[j]);
return new SparseArrayOf<Complex>(dims, complexDataDictionary); return new MatSparseArrayOf<Complex>(dims, complexDataDictionary);
} }
else else
{ {
@ -483,7 +485,7 @@ namespace MatFileHandler
rowIndex, rowIndex,
columnIndex, columnIndex,
j => complexData[j]); j => complexData[j]);
return new SparseArrayOf<ComplexOf<T>>(dims, complexDataDictionary); return new MatSparseArrayOf<ComplexOf<T>>(dims, complexDataDictionary);
} }
} }
@ -496,7 +498,7 @@ namespace MatFileHandler
var elements = ConvertDataToProperType<T>(d, arrayType); var elements = ConvertDataToProperType<T>(d, arrayType);
var dataDictionary = var dataDictionary =
DataExtraction.ConvertMatlabSparseToDictionary(rowIndex, columnIndex, j => elements[j]); DataExtraction.ConvertMatlabSparseToDictionary(rowIndex, columnIndex, j => elements[j]);
return new SparseArrayOf<T>(dims, dataDictionary); return new MatSparseArrayOf<T>(dims, dataDictionary);
} }
} }
} }
@ -547,7 +549,7 @@ namespace MatFileHandler
} }
} }
return new StructureArray(dimensions, dictionary); return new MatStructureArray(dimensions, dictionary);
} }
} }
else else

View File

@ -13,11 +13,9 @@ namespace MatFileHandler
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="MatCellArray"/> class. /// Initializes a new instance of the <see cref="MatCellArray"/> class.
/// </summary> /// </summary>
/// <param name="flags">Array properties.</param>
/// <param name="dimensions">Dimensions of the array.</param> /// <param name="dimensions">Dimensions of the array.</param>
/// <param name="name">Array name.</param>
/// <param name="elements">Array elements.</param> /// <param name="elements">Array elements.</param>
public MatCellArray(ArrayFlags flags, int[] dimensions, string name, IEnumerable<IArray> elements) public MatCellArray(int[] dimensions, IEnumerable<IArray> elements)
: base(dimensions) : base(dimensions)
{ {
Data = elements.ToArray(); Data = elements.ToArray();

View File

@ -1,7 +1,7 @@
using HDF.PInvoke; using System;
using System;
using System.IO; using System.IO;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using HDF.PInvoke;
namespace MatFileHandler namespace MatFileHandler
{ {