Compare commits

...

11 Commits
v1.3.0 ... main

8 changed files with 248 additions and 9 deletions

View File

@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
</state>
</component>

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework> <TargetFramework>net5.0</TargetFramework>
<RootNamespace>Exa</RootNamespace> <RootNamespace>Exa</RootNamespace>
<PackageId>ExaArray</PackageId> <PackageId>ExaArray</PackageId>
<Authors>Thorsten Sommer</Authors> <Authors>Thorsten Sommer</Authors>
@ -10,9 +10,9 @@
<PackageProjectUrl>https://github.com/SommerEngineering/ExaArray</PackageProjectUrl> <PackageProjectUrl>https://github.com/SommerEngineering/ExaArray</PackageProjectUrl>
<PackageLicenseExpression>BSD-3-Clause</PackageLicenseExpression> <PackageLicenseExpression>BSD-3-Clause</PackageLicenseExpression>
<RepositoryUrl>https://code.tsommer.org/thorsten/ExaArray</RepositoryUrl> <RepositoryUrl>https://code.tsommer.org/thorsten/ExaArray</RepositoryUrl>
<PackageVersion>1.3.0</PackageVersion> <PackageVersion>1.4.1-rc</PackageVersion>
<AssemblyVersion>1.3.0</AssemblyVersion> <AssemblyVersion>1.4.1</AssemblyVersion>
<FileVersion>1.3.0</FileVersion> <FileVersion>1.4.1</FileVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">

View File

@ -1,5 +1,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace Exa namespace Exa
{ {
@ -8,7 +11,8 @@ namespace Exa
/// to 4.6 quintillion (4,607,183,514,018,780,000) or 4.6 exa elements. /// to 4.6 quintillion (4,607,183,514,018,780,000) or 4.6 exa elements.
/// </summary> /// </summary>
/// <typeparam name="T">The desired type to use, e.g. byte, int, etc.</typeparam> /// <typeparam name="T">The desired type to use, e.g. byte, int, etc.</typeparam>
public sealed partial class ExaArray1D<T> [Serializable]
public sealed partial class ExaArray1D<T> : ISerializable
{ {
/// <summary> /// <summary>
/// Unfortunately, this seems to be the maximal number of entries an /// Unfortunately, this seems to be the maximal number of entries an
@ -218,5 +222,72 @@ namespace Exa
for (ulong n = 0; n < this.Length; n++) for (ulong n = 0; n < this.Length; n++)
yield return this[n]; yield return this[n];
} }
#region Store and load
/// <summary>
/// Stores the exa array into a stream. <b>Please read the remarks regarding security issues.</b>
/// </summary>
/// <remarks>
/// The data stored in this way should never be part of a public API. Serializing and
/// deserializing is not secure: an attacker can manipulate the data in a targeted
/// manner to compromise the API server, etc.
///
/// This method does not dispose the stream.
/// </remarks>
public void Store(Stream outputStream)
{
var formatter = new BinaryFormatter();
formatter.Serialize(outputStream, this);
}
/// <summary>
/// Restores an exa array from the given stream. <b>Please read the remarks regarding security issues.</b>
/// </summary>
/// <remarks>
/// The data loaded in this way should never be part of a public API. Serializing and
/// deserializing is not secure: an attacker can manipulate the data in a targeted
/// manner to compromise the API server, etc.
///
/// This method does not dispose the stream.
/// </remarks>
public static ExaArray1D<T> Restore(Stream inputStream)
{
var formatter = new BinaryFormatter();
return formatter.Deserialize(inputStream) as ExaArray1D<T>;
}
#endregion
#region Serialization
/// <summary>
/// This method serves for the serialization process. Do not call it manually.
/// </summary>
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("version", "v1");
info.AddValue("strategy", this.OptimizationStrategy, typeof(Strategy));
info.AddValue("length", this.Length);
info.AddValue("chunks", this.chunks, typeof(T[][]));
}
private ExaArray1D(SerializationInfo info, StreamingContext context)
{
switch (info.GetString("version"))
{
case "v1":
this.Length = info.GetUInt64("length");
this.chunks = info.GetValue("chunks", typeof(T[][])) as T[][];
this.OptimizationStrategy = (Strategy) info.GetValue("strategy", typeof(Strategy));
break;
}
this.chunks[0] ??= new T[0];
this.maxElements = this.OptimizationStrategy == Strategy.MAX_PERFORMANCE ? MAX_NUMBER_ELEMENTS_PERFORMANCE : MAX_NUMBER_ELEMENTS;
this.maxArrayCapacity = this.OptimizationStrategy == Strategy.MAX_PERFORMANCE ? MAX_CAPACITY_ARRAY_PERFORMANCE : MAX_CAPACITY_ARRAY;
}
#endregion
} }
} }

View File

@ -1,11 +1,15 @@
using System; using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace Exa namespace Exa
{ {
/// <summary> /// <summary>
/// The two-dimensional exa-scale array. Can grow up to 18,446,744,073,709,551,615 elements in total. /// The two-dimensional exa-scale array. Can grow up to 18,446,744,073,709,551,615 elements in total.
/// </summary> /// </summary>
public sealed class ExaArray2D<T> [Serializable]
public sealed class ExaArray2D<T> : ISerializable
{ {
/// <summary> /// <summary>
/// The total number of possible elements. /// The total number of possible elements.
@ -15,7 +19,14 @@ namespace Exa
private ulong sumLengthOrdinates = 0; private ulong sumLengthOrdinates = 0;
// Chunk storage: // Chunk storage:
private ExaArray1D<ExaArray1D<T>> chunks = new ExaArray1D<ExaArray1D<T>>(Strategy.MAX_PERFORMANCE); private readonly ExaArray1D<ExaArray1D<T>> chunks = new ExaArray1D<ExaArray1D<T>>(Strategy.MAX_PERFORMANCE);
/// <summary>
/// Constructs a two-dimensional exa-scale array.
/// </summary>
public ExaArray2D()
{
}
/// <summary> /// <summary>
/// Returns the current total number of elements across all dimensions. /// Returns the current total number of elements across all dimensions.
@ -72,5 +83,69 @@ namespace Exa
this.chunks[indexAbscissa][indexOrdinate] = value; this.chunks[indexAbscissa][indexOrdinate] = value;
} }
} }
#region Store and load
/// <summary>
/// Stores the exa array into a stream. <b>Please read the remarks regarding security issues.</b>
/// </summary>
/// <remarks>
/// The data stored in this way should never be part of a public API. Serializing and
/// deserializing is not secure: an attacker can manipulate the data in a targeted
/// manner to compromise the API server, etc.
///
/// This method does not dispose the stream.
/// </remarks>
public void Store(Stream outputStream)
{
var formatter = new BinaryFormatter();
formatter.Serialize(outputStream, this);
}
/// <summary>
/// Restores an exa array from the given stream. <b>Please read the remarks regarding security issues.</b>
/// </summary>
/// <remarks>
/// The data loaded in this way should never be part of a public API. Serializing and
/// deserializing is not secure: an attacker can manipulate the data in a targeted
/// manner to compromise the API server, etc.
///
/// This method does not dispose the stream.
/// </remarks>
public static ExaArray2D<T> Restore(Stream inputStream)
{
var formatter = new BinaryFormatter();
return formatter.Deserialize(inputStream) as ExaArray2D<T>;
}
#endregion
#region Serialization
/// <summary>
/// This method serves for the serialization process. Do not call it manually.
/// </summary>
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("version", "v1");
info.AddValue("length", this.Length);
info.AddValue("chunks", this.chunks, typeof(ExaArray1D<ExaArray1D<T>>));
}
private ExaArray2D(SerializationInfo info, StreamingContext context)
{
switch (info.GetString("version"))
{
case "v1":
this.sumLengthOrdinates = info.GetUInt64("length");
this.chunks = info.GetValue("chunks", typeof(ExaArray1D<ExaArray1D<T>>)) as ExaArray1D<ExaArray1D<T>>;
break;
default:
break;
}
}
#endregion
} }
} }

View File

@ -2,6 +2,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Exa; using Exa;
@ -12,6 +13,7 @@ namespace ExaArrayTests
[ExcludeFromCodeCoverage] [ExcludeFromCodeCoverage]
public class ExaArray1DTests public class ExaArray1DTests
{ {
[Serializable]
private class TestClass private class TestClass
{ {
public int Age { get; set; } public int Age { get; set; }
@ -734,5 +736,62 @@ namespace ExaArrayTests
TestContext.WriteLine($"Performing 100M assignments took {t2Times.Average()} ms (average) by means of the max. performance strategy (min={t2Times.Min()} ms, max={t2Times.Max()} ms)"); TestContext.WriteLine($"Performing 100M assignments took {t2Times.Average()} ms (average) by means of the max. performance strategy (min={t2Times.Min()} ms, max={t2Times.Max()} ms)");
} }
[Test]
[Category("cover")]
[Category("normal")]
public void StoreAndLoad01()
{
var exaA = new ExaArray1D<byte>();
exaA.Extend(5_000_000);
exaA[4_483_124] = 0xff;
var filename = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
using (var file = File.OpenWrite(filename))
{
exaA.Store(file);
}
using (var file = File.OpenRead(filename))
{
var exaB = ExaArray1D<byte>.Restore(file);
Assert.That(exaA.Length, Is.EqualTo(exaB.Length));
Assert.That(exaA[4_483_124], Is.EqualTo(0xff));
Assert.That(exaB[4_483_124], Is.EqualTo(0xff));
}
File.Delete(filename);
}
[Test]
[Category("cover")]
[Category("normal")]
public void StoreAndLoad02()
{
var exaA = new ExaArray1D<TestClass>();
exaA.Extend(100);
exaA[66] = new TestClass
{
Age = 55,
};
var filename = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
using (var file = File.OpenWrite(filename))
{
exaA.Store(file);
}
using (var file = File.OpenRead(filename))
{
var exaB = ExaArray1D<TestClass>.Restore(file);
Assert.That(exaA.Length, Is.EqualTo(exaB.Length));
Assert.That(exaA[66].Age, Is.EqualTo(55));
Assert.That(exaB[66].Age, Is.EqualTo(55));
}
File.Delete(filename);
}
} }
} }

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.IO;
using Exa; using Exa;
using NUnit.Framework; using NUnit.Framework;
@ -72,5 +73,31 @@ namespace ExaArrayTests
arr[1, UInt64.MaxValue - 1] = 6; arr[1, UInt64.MaxValue - 1] = 6;
}); });
} }
[Test]
[Category("cover")]
[Category("normal")]
public void StoreAndLoad01()
{
var exaA = new ExaArray2D<byte>();
exaA[5_000_124, 5_000_666] = 0xff;
var filename = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
using (var file = File.OpenWrite(filename))
{
exaA.Store(file);
}
using (var file = File.OpenRead(filename))
{
var exaB = ExaArray2D<byte>.Restore(file);
Assert.That(exaA.Length, Is.EqualTo(exaB.Length));
Assert.That(exaA[5_000_124, 5_000_666], Is.EqualTo(0xff));
Assert.That(exaB[5_000_124, 5_000_666], Is.EqualTo(0xff));
}
File.Delete(filename);
}
} }
} }

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework> <TargetFramework>net5.0</TargetFramework>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
</PropertyGroup> </PropertyGroup>

View File

@ -1,4 +1,6 @@
# ExaArray # ExaArray
ExaArray is a .NET library for exa-scale array-like structures. By using this library, it becomes possible to add up to 4.6 quintillion i.e. 4,607,183,514,018,780,000 elements into a one-dimensional array. When using `byte` for `T`, this would need approx. 4 EB of memory. The two-dimensional array can grow up to 18.4 quintillion i.e. 18,446,744,073,709,551,615 elements, though. ExaArray is a .NET library for exa-scale array-like structures. By using this library, it becomes possible to add up to 4.6 quintillion i.e. 4,607,183,514,018,780,000 elements into a one-dimensional array. When using `byte` for `T`, this would need approx. 4 EB of memory. The two-dimensional array can grow up to 18.4 quintillion i.e. 18,446,744,073,709,551,615 elements, though.
Extending the data structure performs as O(n) with O(m+n) of memory. Accessing the data performs as O(1), though. For the generic type `T`, any .NET type can be used: The ExaArray uses managed memory. Extending the data structure performs as O(n) with O(m+n) of memory. Accessing the data performs as O(1), though. For the generic type `T`, any .NET type can be used: The ExaArray uses managed memory.
Storing to and loading from an arbitrary stream is supported. The data stored in this way should never be part of a public API. Serializing and deserializing is not secure: an attacker can manipulate the data in a targeted manner to compromise the API server, etc.