PHP 8.3 で Randomizer に追加される float 取得関数の区間判別の実装
PHP 8.3 で Randomizer に浮動小数点数のメソッドが追加される。 gh#9679
最小値、最大値と区間の開閉を表す enum IntervalBoundary (ClosedClosed, ClosedOpen, OpenClosed, OpenOpen) を指定して浮動小数点値の乱数を生成できる。
当初この機能の実装では、区間の種類の判別を文字列比較して行っていた。
if (zend_string_equals_literal(bounds_name, "ClosedOpen"))
というのも pure enum を高速に比較する手段が今のところなく、名前を比較するしかないらしい。
これについてパフォーマンス的にどうなんだろう、と言うことでコードが修正された結果、こうなった。
bounds_type = ZSTR_VAL(bounds_name)[0] + ZSTR_LEN(bounds_name); ... case 'C' + sizeof("ClosedOpen") - 1:
enum の値は既に網羅されていて将来的に変わらないので、先頭文字と長さの和が固有になることを利用して O(1) でハッシュ化できる (PHP の string 長は既知のため) ということらしい。
0123456789ab ClosedClosed = 'C' + 12 = 79 ClosedOpen = 'C' + 10 = 77 OpenClosed = 'O' + 10 = 89 OpenOpen = 'O' + 8 = 87
しかし単純に6、7文字目に注目しても判別できそうだ。
こういうのはどうか。
bounds_type = ZSTR_VAL(bounds_name)[6]; ... case "ClosedOpen"[6]:
しかしこれは C++ では OK だが、C ではコンパイルできなかった。仕様はあたっていないものの、case の値を定数と見做してくれないらしい。
もちろん case 'O': // Closed[O]pen のようにすれば通りはするが、元のコードより見劣りする。残念。