TL;DR
これを見たとき、目から鱗が落ちた。
一般的な話
今まで、0~nまでのレンジチェックをするときは以下のように書いていた
if (index < 0 || index >= _size) throw new ArgumentException();
よくあるパターンなんだけど、値域の判定が2度入る。
ListのIndexerがしてたこと
if ((uint)index >= (uint)_size) throw new ArgumentException();
こんな風にuint
にキャストしてチェックすることで判定を一度にすることが出来ている 1 。
で、List
のIndexerみたいに、ほぼほぼ正しい値域を伴って高頻度に呼ばれる様な場合、チェックを1回すっ飛ばせるコトは凄くでかいんじゃないかなと思ったし、こんなコト考えつかなかったのですげーなと思った。
なんでこんなコトが出来るのか
C#では、int
は32bit符号ありuint
は32bit符号無しの整数であり2、符号表現は2の補数となっている3。
で、intとuintの差は整数のビットをどのように解釈するのかという差のみなので、キャストにかかるコストは実質0となる3。
ここで、符号表現が2の補数であるから、負数をuint
として解釈したとき、とり得る全ての負数はint.MaxValue
をuint
で表現したときよりも大きくなる。
このことから、1度のレンジチェックで[0,n)
のレンジチェックを完了できることになる。
興味深かったので小ネタとしてまとめてみた次第。