forked from amkovkov/GranuSightSoftware2
feat: add MDA serializer
utility for serialization and deserialization of multi-dimensional arrays
This commit is contained in:
@@ -0,0 +1,123 @@
|
||||
using System.Text;
|
||||
using System.IO.Compression;
|
||||
|
||||
namespace GSS2.Core.Utils;
|
||||
|
||||
// Формат файла MultiDimensionalArray:
|
||||
// 4 байта [MDA_ fourcc]
|
||||
// 4 байта [int32 array_rang]
|
||||
// 4 байта * array_rang [int32 array_shape]
|
||||
// data compressed with zlib
|
||||
public static class MultiDimensionalArraySerializer
|
||||
{
|
||||
public const string FOURCC = "MDA\0";
|
||||
|
||||
public static void Serialize(Stream stream, Array array)
|
||||
{
|
||||
var shape = GetShape(array);
|
||||
long totalLength = GetTotalLength(shape);
|
||||
|
||||
using (var writer = new BinaryWriter(stream, Encoding.ASCII, true))
|
||||
{
|
||||
writer.Write(Encoding.ASCII.GetBytes(FOURCC));
|
||||
|
||||
writer.Write(array.Rank);
|
||||
|
||||
foreach (var length in shape)
|
||||
writer.Write(length);
|
||||
}
|
||||
|
||||
using (var zip = new ZLibStream(stream, CompressionMode.Compress))
|
||||
using (var writer = new BinaryWriter(zip))
|
||||
for (long i = 0; i < totalLength; i++)
|
||||
{
|
||||
int[] indices = GetIndices(i, shape);
|
||||
var value = array.GetValue(indices);
|
||||
switch (value)
|
||||
{
|
||||
case bool v: writer.Write(v); break;
|
||||
case byte v: writer.Write(v); break;
|
||||
case sbyte v: writer.Write(v); break;
|
||||
case short v: writer.Write(v); break;
|
||||
case ushort v: writer.Write(v); break;
|
||||
case int v: writer.Write(v); break;
|
||||
case uint v: writer.Write(v); break;
|
||||
case long v: writer.Write(v); break;
|
||||
case ulong v: writer.Write(v); break;
|
||||
case double v: writer.Write(v); break;
|
||||
case float v: writer.Write(v); break;
|
||||
default: throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Array Deserialize<T>(Stream stream) where T : unmanaged
|
||||
{
|
||||
int rank;
|
||||
int[] shape;
|
||||
using (var reader = new BinaryReader(stream, Encoding.ASCII, true))
|
||||
{
|
||||
var fourcc = Encoding.ASCII.GetString(reader.ReadBytes(4));
|
||||
if (fourcc != FOURCC)
|
||||
throw new FormatException();
|
||||
|
||||
rank = reader.ReadInt32();
|
||||
|
||||
shape = Enumerable.Range(0, rank)
|
||||
.Select(_ => reader.ReadInt32())
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
long totalLength = GetTotalLength(shape);
|
||||
|
||||
var array = Array.CreateInstance(typeof(T), shape);
|
||||
|
||||
using (var zip = new ZLibStream(stream, CompressionMode.Decompress))
|
||||
using (var reader = new BinaryReader(zip))
|
||||
for (long i = 0; i < totalLength; i++)
|
||||
{
|
||||
int[] indices = GetIndices(i, shape);
|
||||
switch (Type.GetTypeCode(typeof(T)))
|
||||
{
|
||||
case TypeCode.Boolean: array.SetValue(reader.ReadBoolean(), indices); break;
|
||||
case TypeCode.Byte: array.SetValue(reader.ReadByte(), indices); break;
|
||||
case TypeCode.SByte: array.SetValue(reader.ReadSByte(), indices); break;
|
||||
case TypeCode.Int16: array.SetValue(reader.ReadInt16(), indices); break;
|
||||
case TypeCode.UInt16: array.SetValue(reader.ReadUInt16(), indices); break;
|
||||
case TypeCode.Int32: array.SetValue(reader.ReadInt32(), indices); break;
|
||||
case TypeCode.UInt32: array.SetValue(reader.ReadUInt32(), indices); break;
|
||||
case TypeCode.Int64: array.SetValue(reader.ReadInt64(), indices); break;
|
||||
case TypeCode.UInt64: array.SetValue(reader.ReadUInt64(), indices); break;
|
||||
case TypeCode.Double: array.SetValue(reader.ReadDouble(), indices); break;
|
||||
case TypeCode.Single: array.SetValue(reader.ReadSingle(), indices); break;
|
||||
default: throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
private static int[] GetIndices(long linearIndex, int[] lengths)
|
||||
{
|
||||
var indices = new int[lengths.Length];
|
||||
|
||||
for (int dim = lengths.Length - 1; dim >= 0; dim--)
|
||||
{
|
||||
indices[dim] = (int)(linearIndex % lengths[dim]);
|
||||
linearIndex /= lengths[dim];
|
||||
}
|
||||
|
||||
return indices;
|
||||
}
|
||||
private static long GetTotalLength(params int[] shape)
|
||||
{
|
||||
long totalLength = shape.First();
|
||||
foreach (var length in shape.Skip(1))
|
||||
totalLength *= length;
|
||||
return totalLength;
|
||||
}
|
||||
private static int[] GetShape(Array array) =>
|
||||
Enumerable.Range(0, array.Rank)
|
||||
.Select(array.GetLength)
|
||||
.ToArray();
|
||||
}
|
||||
Reference in New Issue
Block a user