Upgrade to Pro — share decks privately, control downloads, hide ads and more …

UniNativeLinq - Unity2018時代のNativeArray<T>用LINQ

pCYSl5EDgo
October 23, 2019

UniNativeLinq - Unity2018時代のNativeArray<T>用LINQ

Unity2018.1から登場したNativeArrayにより、プログラマーはGC管理領域外の連続的メモリを扱えるようになった。
しかし、NativeArrayは構造体であるが故に既存のLINQ to Objectsではアロケーション地獄になってしまう。
この問題を解決しうるライブラリがUniNativeLinqである。
https://github.com/pCYSl5EDgo/UniNativeLinq-EditorExtension

pCYSl5EDgo

October 23, 2019
Tweet

Other Decks in Programming

Transcript

  1. IEnumerable<T>の陥穽 LINQ IEnumerable<T> Where<T>(this IEnumerable<T> collection, Func<T, bool> predicate) Whereなどの呼び出し毎にGC

    Alloc発生 ゆえにインゲームではLINQ禁止が多い ※抽象クラスIterator<TSource>を継承した WhereArrayIterator<TSource>などが実際の戻り値の型
  2. LINQ to NativeArray<T> UniNativeLinq named by Decoc@Ash_Yin Core MIT License

    : コア機能に限定、拡張メソッドなしunitypackage配布 Full MIT License : 全APIを自由に利用可能 unitypackage配布 Editor Extension GPLv3 GPLv3:必要なAPIだけに絞れる 全て無料で利用可能 unitypackage形式とプロプライエタリでも使えるEditor Extension → BOOTHやAsset Storeに出す可能性がある
  3. ここが嬉しい UniNativeLinq(1/5) using文との相性問題を解決可能 従来 using(var array = new NativeArray<int>(10, Allocator.Temp))

    array[0] = 10; // using変数は書き換え不能 コンパイルエラー UniNativeLinq using(var array = new NativeArray<int>(10, Allocator.Temp)) array.AsRefEnumerable()[0] = 10;
  4. ここが嬉しいUniNativeLinq(2/5) インデクサアクセスの戻り値が参照 従来 // NativeArray<Matrix4x4> array; var item = array[0];

    item[0, 3] = 10f; array[0] = item; UniNativeLinq // NativeArray<Matrix4x4> array; array.AsRefEnumerable()[0][0, 3] = 10f;
  5. ここが嬉しいUniNativeLinq(3/5) byte[]への変換が簡単 従来 // NativeArray<Matrix4x4> array; unsafe{ byte* ptr =

    (byte*)array.GetUnsafePtr(); int count = array.Length * sizeof(Matrix4x4); byteArray = new byte[count]; fixed(byte* dst = &byteArray[0]){ UnsafeUtility.MemCpy(dst, ptr, count); } } UniNativeLinq // byte[] byteArray; byteArray = array .AsRefEnumerable() .Cast<Matrix4x4, byte>() .ToArray();
  6. ここが嬉しいUniNativeLinq(5/5) C#7.3環境でもunmanagedな総称型のポインタをある程度扱える 従来 var ptr = ((int, int)*)UnsafeUtility.Malloc(8, Allocator.Temp); //

    C#7.3でエラー UniNativeLinq var ptr = NativeEnumerable.Create<(int, int)>(1, Allocator.Temp).Ptr; ※明示的に型名を書くとコンパイルエラーになるが、varならOK! C#コンパイラがゆるがば過ぎて少し心配になる……ならない?
  7. 謝辞とクレジット表記(2/3) @adarapata様主催のゆに茶会scene 6参加者の方々 @adarapata, @monry, @TANY_FMPMD, @taptappun, @TEST_H_, @mid_zzz (アルファベット順)

    Assets以下にデータとしてDLLを含める方法について @toriae_zu_様 登壇に使用したアバターである「ツバキ」の作者 https://hub.vroid.com/characters/4054644065668079297/models/7173510333740850936
  8. おまけ(1/27) APIの基本設計(IRefEnumerable) interface IRefEnumerable<TEnumerator, T> : IEnumerable<T> where T :

    unmanaged where TEnumerator : struct, IRefEnumerator<T> { TEnumerator GetEnumerator(); }
  9. おまけ(5/27) APIの基本設計(IRefEnumerator) interface IRefEnumerator<T> : IEnumerator<T> where T : unmanaged

    { ref T Current { get; } bool MoveNext(); ref T TryGetNext(out bool success); bool TryMoveNext(out T value); }
  10. おまけ(6/27) APIの基本設計(IRefEnumerator) ref T Current { get; } 基本 foreach(ref

    var item in collection)と書くのに必須 構造体のコピーコストを避けられる
  11. おまけ(9/27) APIの基本設計(IRefAction/IRefFunc) 一例 public struct SelectEnumerable<TPrevEnumerable, TPrevEnumerator, TPrev, T, TAction>

    : IRefEnumerable<SelectEnumerable<TPrevEnumerable, TPrevEnumerator, TPrev, T, TAction>.Enumerator, T>, IEnumerable<T>, IEnumerable where TPrevEnumerable : struct, IRefEnumerable<TPrevEnumerator, TPrev> where TPrevEnumerator : struct, IRefEnumerator<TPrev> where TPrev : unmanaged where T : unmanaged where TAction : struct, IRefAction<TPrev, T> 型と制約が⾧い!⾧過ぎる!
  12. おまけ(10/27) APIの基本設計(IRefAction/IRefFunc) SelectEnumerable`5の注目点は where TAction where struct, IRefAction<TPrev, T> interface

    IRefAction<T0, T1>{void Execute(ref T0 arg0,ref T1 arg1)} 構造体の型に処理内容を紐付ける
  13. おまけ(12/27) APIの基本設計(IRefAction/IRefFunc) // 一例 : NativeArray<long> array internal readonly struct

    LessThan : IRefFunc<long, bool> { private readonly long comparer; public LessThan(long comparer) => this.comparer = comparer; public bool Calc(ref long value) => value < comparer; } foreach(ref var item in array.Where(new LessThan(114514L))){ item = 1919810L; }
  14. おまけ(15/27) C#の言語仕様(1/4) public static T<A> To<T,A> (this IEnumerable<A> xs) where

    T : <>, new(), ICollection<> { var ta = new T<A>(); foreach(var x in xs) ta.Add(x); return ta; } /// 別の部分 var data = Enumerable.Range(0, 20); var set = data.To<HashSet<>, int>(); var link = data.To<LinkedList<>, int>(); var list = data.To<List<>, int>(); 10までお預け ナンデ? ※言語仕様は変化します
  15. おまけ(16/27) C#の言語仕様(2/4) T a r g e t T y

    p e d N e w C#8で入る予定だった 入らなかった……