タイトルの通り,長大サイズの配列を提供するライブラリを作ったので,それに合わせて紹介記事も書いてみました。
尚,作ってみたいという動機だけで開発したため,使う機会があるかどうかや実用性については私にも分かりません。
ライブラリ情報
- 名称:LongArrayLib
- 使用言語:C#
- Github: https://github.com/Funny-Silkie/LongArrayLib
- Nuget:未整備,需要があれば検討
- 対象バージョン:.NET7.0 & .NET8.0
- ライセンス:MIT
実装
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>.Enumerator は IEnumerator<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* に変換 |