Fixnum

IMMEDIATE_P(v) でもっともポピュラーなものは Fixnum だろう。下位 1 bit が 1 であれば(v&1 であれば)Fixnum だ。

さて、そもそも Fixnum ってなんだっけ。Ruby 2.4 で消滅したクラスだった。範囲つき整数であり、範囲を超えると Bignum になった。Bignum は、メモリがある限り、(絶対値が)大きな整数を表現できる。Ruby 2.4 では、Fixnum と Bignum は消滅し、Integer に統合された。実装が違うだけで、同じ整数を表現するため、そこに別々のクラスを用意するのは、あまり意味が無いだろう、ということで統合された(もともと、Bignum と Fixnum の親クラスとして Integer クラス自体は存在していた)。Ruby プログラマからみると、Fixnum と Bignum はシームレスに変換されるため、意識することはない、と思う。厳密には、同じ値なのに別々の object_id が帰ってくることがあったりするのが Bignum が Fixnum と同じところだ。

Bignum と Fixnum は Integer に統合されたが、実装レベルでは依然としてこの二つは残っている。Bignum はメモリを確保するので毎回メモリアロケーションするが、Fixnum は special const なので、VALUE に埋め込まれるのでメモリ確保は不要である。

さて、Fixnum の範囲は何かというと、63bit か 31 bit で表現できる値となる。LSB 1 bit を識別のために利用するので、63 or 31 bit しか利用できないのだ。

#define RB_INT2FIX(i) (((VALUE)(i))<<1 | RUBY_FIXNUM_FLAG)
#define INT2FIX(i) RB_INT2FIX(i)

C の int の値を、Fixnum でその値を表現する VALUE に変換するには、この INT2FIX(v) を利用する。1 bit 左シフとして(2倍して)、RUBY_FIXNUM_FLAG つまり 0x01 を or する。簡単。同じく、Fixnum から int に変換するには 1 bit 右シフトすれば良い。

VALUE に埋め込む値なので、Fixnum として存在できるオブジェクトの数は決まっている。逆の言い方をすると、Fixnum オブジェクトは、起動時にすでにすべて作成されているとも言える。1 という数値リテラルは、MRI から検索し、存在した Fixnum オブジェクトを取り出した、とも言える。