LoginSignup
2
1

Array.MaxLength を超えたサイズの配列を扱えるライブラリを作ってみた

Posted at

タイトルの通り,長大サイズの配列を提供するライブラリを作ったので,それに合わせて紹介記事も書いてみました。
尚,作ってみたいという動機だけで開発したため,使う機会があるかどうかや実用性については私にも分かりません。

ライブラリ情報

実装

LongArray<T> クラスがその配列クラスに該当します。
インデクサ,配列長共に64-bit符号付き整数(long)で定義されており,理論上は long.MaxValue まで要素数を設定できます。
ここで「理論上」としているのは,要素数を long.MaxValue ( $2^{63}-1$)とすると byte 配列でもメモリ上のサイズが約8 EiBになるためです。

取り回しは.NETの配列(T[])に極力寄せており,検索やコピー,ソートといった一連のメソッドが用意されています。
.NETの配列と異なる要素としては,IndexOf() などの検索系のメソッドや ForEach() といった要素に変更を与えないメソッドは基本的に LongArray<T> に直接実装している点があります。
これはコードを書く上で一々 Array.XXX(array) とするより array.XXX() とした方がすっきりするためです。
Resize()Sort() といった要素に変更の生じる処理は LongArray<T> クラスには実装されておらず,静的クラスである LongArray に実装されています。
また,内部で malloc をしている都合上, IDisposable を実装しています。
使い終わったら Dispose() を呼び出してメモリを解放する必要があります。

using LongArrayLib;

// 長さ5の配列を生成
using var array = new LongArray<long>(5L);
// 要素を設定
for (long i = 0L; i < array.Length; i++) array[i] = -i;

// 検索などは LongArray<T> インスタンスから呼び出し
Console.WriteLine(array.IndexOf(-2L)); // 出力:2
// ソートなどは LongArray クラスから呼び出し
LongArray.Sort(array); // ソート

Console.WriteLine(array.FindLast(x => x < 0L)); // 出力:-1

LongArray<T> は.NETの配列と同じように LongArray<T> は読み取り専用コレクションとして実装されています。
そのため ICollection<T> インターフェイス経由で Add(T)Clear() を呼び出そうとしても NotSupportedException がスローされます。
インデクサに関してもsetterは存在せず,getterで ref T を返すことで値の設定を可能にしています。

当ライブラリでは LongArray<T> の実装だけでなく,既存の型との互換性も考慮しており,Span<T>Memory<T>ReadOnlySequence<T>T[] との相互変換の他,LINQには ToLongArray<T>(IEnumerable<T>)Stream には Read(LongArray<T>, long, long)Write(LongArray<T>, long, long) といった拡張も定義されています。

using LongArrayLib;
using System.Buffers;

var array = new byte[4096];
using var stream = new FileStream(..);

// LINQの拡張,IEnumerable<T> → LongArray<T>
using LongArray<byte> buffer = array.ToLongArray();

// Stream の拡張(Async版もあり)
stream.Write(buffer, 0L, buffer.Length);
stream.Read(buffer, 0L, buffer.Length);

// 型変換
Span<byte> span = buffer.AsSpan();
Memory<byte> memory = buffer.AsMemory();
ReadOnlySequence<byte> sequence = buffer.AsReadOnlySequence();

そしてC#12で新たに実装されたコレクション式にも対応しています。

using LongArrayLib;

// コレクション式からインスタンス生成
using LongArray<int> array = [0, 1, 2, 3, 4];
Console.WriteLine(string.Join(',', array)); // 出力:0,1,2,3,4

機能一覧

LongArray<T>LongArray の実装に絞っています。
これ以外に様々な拡張メソッドが記述されており,既存の型との互換性を担保しています。

生成

機能名 対応する.NETの実装 備考
new LongArray<T>(long, bool) new T[int] 第二引数を false にするとゼロ埋めをしない
LongArray.Create<T>(params T[]) N/A
LongArray.Create<T>(ReadOnlySpan<T> N/A コレクション式対応用

列挙

機能名 対応する.NETの実装 備考
LongArray<T>.GetEnumerator() T[].GetEnumerator() LongArray<T>.EnumeratorIEnumerator<T> を実装
LongArray<T>.GetSpanEnumerator(int) N/A ReadOnly<T> に分割して列挙,foreach に入れて回すことも可能
`LongArray.ForEach(Action) Array.ForEach<T>(Action<T>)
LongArray<T>.ForEachChunk<TArg>(ReadOnlySpanAction<T, TArg>, TArg, int) N/A ReadOnly<T> に分割して処理

取得

機能名 対応する.NETの実装 備考
LongArray<T>.this[long] T[int] ref T を返す
LongArray<T>.this[int] T[int] ref T を返す
LongArray<T>.this[Index] T[Index] ref T を返す
LongArray<T>.this[Range] T[Range] LongArray<T> を返す
LongArray<T>.GetRange(long, long) N/A List<T>.GetRange(int, int) と同じ取り回し

コピー

機能名 対応する.NETの実装 備考
LongArray<T>.CopyTo(T[], int) T[].CopyTo(Array, int)
LongArray<T>.CopyTo(LongArray<T>, int) T[].CopyTo(Array, int)
LongArray<T>.CopyTo(Memory<T>) MemoryExtensions.CopyTo(this T[], Memory<T>)
LongArray<T>.CopyTo(Span<T>) MemoryExtensions.CopyTo(this T[], Span<T>)
LongArray.Copy<T>(LongArray<T>, LongArray<T>, long) Array.Copy(Array, Array, int)
LongArray.Copy<T>(T[], LongArray<T>, int) Array.Copy(Array, Array, int) .NET配列 → LongArray<T>へのコピー
LongArray.Copy<T>(LongArray<T>, T[], int) Array.Copy(Array, Array, int) LongArray<T> → .NET配列へのコピー
LongArray.Copy<T>(LongArray<T>, long, LongArray<T>, long, long) Array.Copy(Array, int, Array, int, int)
LongArray.Copy<T>(T[], int, LongArray<T>, long, int) Array.Copy(Array, int, Array, int, int) .NET配列 → LongArray<T>へのコピー
LongArray.Copy<T>(LongArray<T>, long, T[], int, int) Array.Copy(Array, int, Array, int, int) LongArray<T> → .NET配列へのコピー
LongArray<T>.Clone() T[].Clone()

検索

機能名 対応する.NETの実装 備考
LongArray<T>.Contains(T) Array.Contains(T)
LongArray<T>.IndexOf(T) Array.IndexOf(T)
LongArray<T>.IndexOf(T, long) Array.IndexOf(T), int
LongArray<T>.IndexOf(T, long, long) Array.IndexOf(T), int, int
LongArray<T>.LastIndexOf(T) Array.LastIndexOf(T)
LongArray<T>.LastIndexOf(T, long) Array.LastIndexOf(T), int
LongArray<T>.LastIndexOf(T, long, long) Array.LastIndexOf(T), int, int
LongArray<T>.Exists(Predicate<T>) Array.Exists(Predicate<T>)
LongArray<T>.TrueForAll(Predicate<T>) Array.TrueForAll(Predicate<T>)
LongArray<T>.Find(Predicate<T>) Array.Find(Predicate<T>)
LongArray<T>.FindIndex(Predicate<T>) Array.FindIndex(Predicate<T>)
LongArray<T>.FindIndex(Predicate<T>, long) Array.FindIndex(Predicate<T>, int)
LongArray<T>.FindIndex(Predicate<T>, long, long) Array.FindIndex(Predicate<T>, int, int)
LongArray<T>.FindLast(Predicate<T>) Array.FindLast(Predicate<T>)
LongArray<T>.FindLastIndex(Predicate<T>) Array.FindLastIndex(Predicate<T>)
LongArray<T>.FindLastIndex(Predicate<T>, long) Array.FindLastIndex(Predicate<T>, int)
LongArray<T>.FindLastIndex(Predicate<T>, long, long) Array.FindLastIndex(Predicate<T>, int, int)
LongArray<T>.FindAll(Predicate<T>) Array.FindAll(Predicate<T>)
LongArray<T>.BinarySearch(T) Array.BinarySearch(T)
LongArray<T>.BinarySearch(T, IComparer<T>?) Array.BinarySearch(T, IComparer<T>?)
LongArray<T>.BinarySearch(long, long, T) Array.BinarySearch(long, long, T)
LongArray<T>.BinarySearch(long, long, T, IComparer<T>?) Array.BinarySearch(long, long, T, IComparer<T>?)

編集

機能名 対応する.NETの実装 備考
LongArray.Resize<T>(ref LongArray<T>? long) Array.Resize<T>(ref T[]?, int)
LongArray.Clear<T>(LongArray<T>) Array.Clear<T>(T[])
LongArray.Clear<T>(LongArray<T>, long, long) Array.Clear<T>(T[], int, int)
LongArray.Fill<T>(LongArray<T>, T) Array.Fill<T>(T[], T)
LongArray.Fill<T>(LongArray<T>, T, long, long) Array.Fill<T>(T[], T, int, int)

ソート

機能名 対応する.NETの実装 備考
LongArray.Sort<T>(LongArray<T>) Array.Sort<T>(T[])
LongArray.Sort<T>(LongArray<T>, IComparer<T>?) Array.Sort<T>(T[], IComparer<T>?)
LongArray.Sort<T>(LongArray<T>, long, long) Array.Sort<T>(T[], int, int)
LongArray.Sort<T>(LongArray<T>, long, long, IComparer<T>?) Array.Sort<T>(T[], int, int, IComparer<T>?)
LongArray.Sort<T>(LongArray<T>, Comparison<T>) Array.Sort<T>(T[], Comparison<T>)
LongArray.Sort<TKey, TValue>(LongArray<TKey>, LongArray<TValue>?) Array.Sort<TKey>(TKey[], TValue[]?)
LongArray.Sort<TKey, TValue>(LongArray<TKey>, LongArray<TValue>?, IComparer<TKey>?) Array.Sort<TKey>(TKey[], TValue[]?, IComparer<TKey>?)
LongArray.Sort<TKey, TValue>(LongArray<TKey>, LongArray<TValue>?, long, long) Array.Sort<TKey>(TKey[], TValue[]?, int, int)
LongArray.Sort<TKey, TValue>(LongArray<TKey>, LongArray<TValue>?, long, long, IComparer<TKey>?) Array.Sort<TKey>(TKey[], TValue[]?, int, int, IComparer<TKey>?)
LongArray.Reverse<T>(LongArray<T>) Array.Reverse<T>(T[])
LongArray.Reverse<T>(LongArray<T>, long, long) Array.Reverse<T>(T[], int, int)

変換

機能名 対応する.NETの実装 備考
LongArray<T>.ConvertAll<TOut>(Converter<T, TOut>) Array.ConvertAll<TIn, TOut>(Converter<TIn, TOut>)
LongArray<T>.ToArray() N/A T[] に変換
LongArray<T>.AsPointer() N/A void* に変換
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1