Closed ufcpp closed 11 months ago
恒 例 行 事
https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-8/
i >= 0 && j >= 0;
を (i | j) >= 0
に置き換えたりx ? 1 : 0
の類が「false/trueが内部的に0/1」を使って素通しにarray[i % array.Length]
s.Length >= N && s[^N]
new DateTime(2023, 9, 1)
みたいなのが(long Ticks の定数に)折りたたまれるようにList<T>.Enumerator
とかが改善の対象にT
が sealed のときの is T[]
が高速に(共変チェックを削れる)async Task<int> X() => 0;
とか)が、キャッシュされた Task<T>
を返す0.ToString()
とかでテーブルから "0"
を返してたの、0~9まで だったのを 0~299 までで同じことやるようにb
フォーマット(ToString("b")
で2進数文字列化)Span<char>
TryFormat と Utf8.TryFormat がほぼ同パフォーマンスref readonly の一番のモチベーション:
using System.Runtime.InteropServices;
// こういうのとか
var s1 = MemoryMarshal.CreateReadOnlySpan(0, 1);
// こういうのが大変まずい。
int x = 123;
var y = 256;
var s2 = MemoryMarshal.CreateReadOnlySpan(x + y, 1);
// 一時変数が使ってる領域どこか未定義。下手したらレジスターで完結しててどこも指せない。
VS の更新したらちゃんと、↓がInlineArray使うようになった。
Span<string> s = ["", "a", "abc"];
foreach (var x in s) Console.WriteLine(x);
Array.Empty 最適化(配列 or ReadOnly 系インターフェイスのみ)もかかる。
IReadOnlyList<int> list = []; // Array.Empty<int>() と一緒。
dotnet build だと使わない… また微妙にコンパイラーのバージョン違うんだ。
VS側コンパイラーでもまだ IImmutableList (インターフェイス)のコレクション式はダメ。
プライマリコンストラクター引数の2重バッキングフィールドに対する警告出るようになってた。
class A(int x)
{
private int _x = x; // CS9124
public int X { get; } = x; // CS9124
public int Y => x; // この行がなければ別に CS9124 は出ない。
}
https://twitter.com/ufcpp/status/1702562859564273980
readonly系インターフェイスの場合はイテレーターと同じような(GetEnumeratorで新規インスタンス作らない)型を生成して使うようになる予定(作業真っ最中)。
roslyn の 69623 GA までには(merge 済みなので多分次のリリースには)入るはず。
public static void m1(IEnumerable<int>? x)
{
foreach (var item in x ?? []) // Array.Empty<int>()
{
}
}
public static void m2(IList<int>? x)
{
foreach (var item in x ?? []) // new List<int>()
{
}
}
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// こいつはマジでまずい。
// temporary 変数の参照って何?
int x = 123;
var y = 1;
var span = MemoryMarshal.CreateReadOnlySpan(x + y, 1);
// これのせいで、前までは in にできなかった。
// 前までは ref だったので、
ref readonly var r = ref x;
var s1 = MemoryMarshal.CreateReadOnlySpan(
ref Unsafe.AsRef(in r), // in を ref に置き換える Unsafe やくざ
1);
// これからは in r が行ける。
var s2 = MemoryMarshal.CreateReadOnlySpan(in r, 1);
using System.Runtime.InteropServices;
var s1 = MemoryMarshal.CreateReadOnlySpan(123, 1);
Console.WriteLine(s1[0]);
var s2 = MemoryMarshal.CreateReadOnlySpan(456, 1);
Console.WriteLine(s2[0]);
var s3 = MemoryMarshal.CreateReadOnlySpan(789, 1);
Console.WriteLine(s3[0]);
Console.WriteLine(s1[0]); // こいつも 789 に書き変わってる
Console.WriteLine(s2[0]); // 同上
// (環境依存、未定義動作)
struct A
{
// 現在有効
public readonly ref readonly int M1(ref readonly int x) => ref x;
// 可能性出てきた
public readonly ref readonly int M2(readonly ref readonly int x) => ref x;
}
primary ctor 化
partial class A(int x) // 未使用引数警告あり
{
public int x;
public int Y => x; // この x はフィールドの x。
}
class B
{
public int _x;
/// <summary>
/// コンストラクター
/// </summary>
/// <param name="x">x のさまりー</param>
public B(int x) { _x = x; }
}
↓ IDE0290 リファクタリング
/// <summary>
/// コンストラクター
/// </summary>
/// <param name="x">x のさまりー</param>
class B(int x)
{
public int _x = x;
}
/// <summary>
/// クラス
/// </summary>
class B
{
public int _x;
/// <summary>
/// コンストラクター
/// </summary>
/// <param name="x">x のさまりー</param>
public B(int x) { _x = x; }
}
↓ IDE0290
/// <summary>
/// クラス
/// </summary>
/// <remarks>
/// コンストラクター
/// </remarks>
/// <param name="x">x のさまりー</param>
class B(int x)
{
public int _x = x;
}
<summary/>
はバグったww
永久ループはしなかった。
using System.Runtime.InteropServices;
List<int> list = [1, 2, 3, 4, 5, 6, 7, 8, 9];
CollectionsMarshal.SetCount(list, 4);
foreach (var item in list)
{
Console.Write($"{item} ");
}
Console.WriteLine();
CollectionsMarshal.SetCount(list, 8); // Grow で再アロケーション要らないくらいの長さの時は値が復活。
//CollectionsMarshal.SetCount(list, 100); // Grow で再確保必要な場合は復活しない。
foreach (var item in list)
{
Console.Write($"{item} ");
}
Console.WriteLine();
配信URL: https://www.youtube.com/watch?v=qaEfydb4B4U
公式アナウンス:
C# がらみ:
ReadOnlySpan 相手にコレクション式を使ったとき、まだ配列が new されてそう↓コンパイルエラーに。
↓通るようになった(ref readonly)。