RB_TEST_P(x)

https://github.com/ruby/ruby/blob/ruby_2_6/include/ruby/ruby.h#L478

#define RB_TEST(v) !(((VALUE)(v) & (VALUE)~RUBY_Qnil) == 0)
#define RB_NIL_P(v) !((VALUE)(v) != RUBY_Qnil)
#define RTEST(v) RB_TEST(v)
#define NIL_P(v) RB_NIL_P(v)

RB_TEST(v) の定義はこれだった。これは、x が false か nil 以外だったら真、というもの。Ruby では nil もしくは false だったら偽、という定義と同じものだ。C コード中で if (RB_TEST(v)) {...} みたいに、Ruby 的に真だったら、みたいに書く時に使う。

ついでに、NIL_P(v) の定義もある。Qnilそれと等しいかどうか、をチェックしている。いちいち、!(v != Qnil) と二重否定にしているのは、... なんで?

https://github.com/ruby/ruby/commit/8497a7b9187a05210a4f6b842d06d1268d704d35

if NIL_P(x) { ... } と(if RTEST(x) { ... } だったっけ? という話も)C で書いたパッチが来たから、括弧を省略できないようにしたらしい...。

そういえば、例によって RB_TEST に RTEST、RB_NIL_P に NIL_P、RUBY_Qnil には Qnil という別名がついている。歴史的には逆で、先に RTEST とかがあった。RubyAPI であることを強調するために RB_ prefix を付けている。

さて、RB_TEST(v) の実装に戻ると、!((v & ~Qnil) == 0) だったら真らしい。このビット演算は何をしているのか?

Ruby において、偽の値は falesnil で、それぞれ C では QfalseQnil という値である。つまり、素直に書くと、!((v) == Qnil) || (v) == Qfalse) とすれば良い。それがなぜ論理演算になるのか?

実は、Qfalse は 0 で、Qnil0b0100 == 0x08 という値である。展開すると !(v == 0x08 || v == 0x00) こうなる。つまり、v が 0b0000 もしくは 0b0100 であれば偽ということになる。この二つの違いは 0b0100 の 1 bit だけなので、この bit 以外が 0 であれば、Qfalse もしくは Qnil である、と言える。つまり、v の 3 bit 目を 0 にしておけば、あとは全体が 0 であるかをチェックすれば偽であると言える。これを実装するのが (v & ~Qnil) == 0 という式である。

なぜ論理式にするか、というと、分岐が1個減って、もしかしたらちょっと速くなるかも、ということで、こういう式になっている。

ちなみに、gcc では、最適化オプションによって、素直に (v == Qnil || v == Qfalse) と書いても (v & ~Qnil) == 0 と同じコードが出力される。賢い。clang では、真面目に2回チェックしていた。