もう今年の1/6が終わっちゃったんだぜ?

2月28日木曜日、雨

早いもので2月が終わった。ということは……。

つい二週間ほど前に「3/24、つまり1/8が終わったんだね!」とチームメンバーに言ったら、きょとんとされてしまった。
1年は12か月。2月の半ばということは3/24(=1.5/12)が過ぎた。そういう理屈だったんだけれど分母を倍にして整数にするあたりに飛躍があるのか、わかってもらえなかった。
1.5/12というのは説明のためにひねり出したもので、僕はつるつるっと自然に3/24という数字が頭に浮かんだんだけれど、これは一般的な考え方じゃあないんだろうか?

まあいい。

* * *

朝、あまりに眠くて辛かったので会社に連絡を入れてお昼まで寝ていた。

さすがに休むという選択肢は選びづらく起きだして出社したんだけれど、胸がいたくて深く息を吸えなかった。浅めに呼吸していればそのうち去ってくれる。たまにあることなので慌てはしないんだけれど不便だ。
実際30分もしないうちに戻ってくれたんだけれど、以前までより痛みがさるまでの時間が長かったのが嫌だった。

朝から雨。

傘をさすのが面倒になっているので今日も帽子をかぶり上着(シェルウェア)のフードをかぶるだけで外に出た。このスタイルは入江亜紀『北北西に雲と往け』。アイスランドの人たちが傘をささないというのを読んで影響されて真似をしている。そして面白いことに、特段の不便がない。
ただし靴だけは何とかしないといけない。持っている靴、どれもこれも雨の中履いていると沁みてきて寒いったらない。

* * *

if (!initialized) {
  ...
}

的なコードを見ていておもいだした。かつてのゲームプログラミングでは、こういう条件分岐がうっとおしいので「自己書き換え」により分岐を無くしてしまうという話を。

実際に見たことはないので想像でしかないのだけれど、こんな感じのものだったんだろう。

func:
  branch @func_init # 初期化処理にジャンプ
  ...
  ret # 呼び出し元に戻る
func_init:
  store @func, NOP # 処理 func の入り口の branch を NOP で置き換える
  ...
  branch @func + 1 # 処理 func の branch の次(主処理)にジャンプ

コード自身がコードを書き換えて無駄な比較や分岐をせずに済ますというの、あまりにカッコよくてシビれる。

残念なことに現代の OS 上で動くアプリケーションは、そのコードテキストは読み取り専用領域にロードされるため、こういった古き良きマジカルなコードは実行できない。
そしてそれ以前に高級言語ではこういう表現が許されていない。

関数ポインターを使えば、ちょっとくらい似た感じのことはできる。

void (*func)() = func_with_init; // 初回は初期化処理を実行
void func_main() { /* 主処理 */ }
void func_with_init() {
  func = func_main(); // 次回から主処理を呼び出すよう関数を置き換え
  /* ただ一度だけ実行する初期化処理 */
  func_main(); // 初期化後に主処理にジャンプ
}

だいたいこんな感じの仕込みをして、関数そのものを呼び出す代わりに func() と関数ポインター越しに処理を呼び出す。こうすれば条件分岐なしに、初回の呼び出しのときだけ初期化コードが走るという環境が実現できる。

オブジェクト指向言語なら関数オブジェクトを使う……かな?

interface Func {
  void invoke();
}

public class FuncImpl implements Func {
  public static Func instance = new FuncWithInit();

  @Override
  void invoke() { ... }

  private FuncImpl() { ... }

  private FuncWithInit implements Func {
    @Override
    void invoke() {
      instance = new FuncImpl();
      // 初期化処理
      instance.invoke();
    }
}

利用コードでは FuncImpl.instance.invoke() みたいに…… わかりにくいな。

この記事が気に入ったらサポートをしてみませんか?