emacsでauto-insert

emacsC++のコードを書いてるとき、

  1. 行頭にエンコーディングの指定を書く
  2. headerでインクルードガードを書く

という定形作業が毎回発生してうっとおしいのでどうにかしたい。

下記のサイトを参考にemacsにテンプレを導入してみる。(ほぼそのままですが)
http://www.02.246.ne.jp/~torutk/cxx/emacs/mode_extension.html
http://d.hatena.ne.jp/higepon/20080731/1217491155

あと、最近ファイルをキャメルケースで、インクルードガードをスネークケースで書くことが多いので、インクルードガードをスネークケースに変換するように処理を追加。
キャメルケースとスネークケースの変換関数は以下のサイトのを利用。
http://recyclebin5385.blog13.fc2.com/blog-category-4.html

;; 自動挿入の設定
(require 'autoinsert)
;; テンプレート格納用ディレクト
(setq auto-insert-directory "~/.emacs.d/insert/")
;; ファイル拡張子とテンプレートの対応
(setq auto-insert-alist
(append '(
("\\.cpp$" . ["template.cpp" my-template])
("\\.h$" . ["template.h" my-template])
) auto-insert-alist))
(add-hook 'find-file-hooks 'auto-insert)

;; 変換ルールの定義
(require 'cl)
(defvar template-replacements-alists
'*1 t))))
)
)

;; 変換実行の定義
(defun my-template ()
(time-stamp)
(mapc #'(lambda(c)
(progn
(goto-char (point-min))
(replace-string (car c) (funcall (cdr c)) nil)))
template-replacements-alists)
(goto-char (point-max))
(message "done."))
(add-hook 'find-file-not-found-hooks 'auto-insert)

すごい短いけど。テンプレはこんな感じ。
template.h

/* -*- coding:utf-8 -*- */

#ifndef %include-guard%
#define %include-guard%



#endif // %include-guard%

template.cpp

/* -*- coding:utf-8 -*- */

実行してみるとこんな感じ。

固定の文言の追加とかもできるからいろいろ便利。

*1:"%file%" . (lambda () (file-name-nondirectory (buffer-file-name)))) ("%file-without-ext%" . (lambda () (file-name-sans-extension (file-name-nondirectory (buffer-file-name))))) ("%include-guard%" . (lambda () (format "%s_H" (camel-to-snake (file-name-sans-extension (file-name-nondirectory buffer-file-name

デザインパターンを覚えたい (Interpreter)

Interpreterパターン

構文解析を行うパターン。各文規則に対してクラスを割り当て、逐次でパースすることで実行に持っていく。
ポイントは

  • 文規則のクラスを再帰的に呼び出すことで、構文木を生成する
  • 独自表現が使えるため、プログラムの柔軟性が高まる

とかかな。これをうまく実装できるとかなりプログラムの柔軟性が上がりそうな予感がする。一方で、他のパターンに比べてなんとなく毛色が違うように感じなくもない。

実装。四則演算電卓。
http://dl.dropbox.com/u/7810000/code/design_pattern/interpreter.zip
なお、実装のBNF記法は下記サイトを参考にしてます。
http://d.hatena.ne.jp/yo-kun/20080522/p1
今回の実装のBNFは以下のようなつもり。

::= { + | - }*
::= { * | / }*
::= | ( )

実行。トークン分解はStringTokenizerに丸投げなため、式の各要素の間に必ずスペースを入れないとうまく動作しません。

$ ./run.sh
*** welcome to Calculator ***
plese type "q" if you want to exit calculator
calc> 2 * ( 4 + 3 / ( 3 - 1 ) )
INFO: parsed exp = "2.0*(4.0+3.0/(3.0-1.0))"
reuslt = 11.0
calc> q

ポイントはNodeインターフェースかな?四則演算で出てくる式、項、因数、数値はすべてこのNodeインターフェースの実装として書かれています。

public interface Node {
    public abstract void parse(Context context) throws ParseException;
    public abstract double getResult() throws CalcException;
}

実際に計算するcalculatorクラスでは、トップのノードからNodeインターフェースの関数を再帰的に呼ぶことで解析・計算をしている。

public class Calculator {
    private static Calculator instance = null;
    private Calculator() {}

    public static Calculator getInstance() {
        if (instance == null) instance = new Calculator();
        return instance;
    }

    public double calc(String exp) {
        Context context = new Context(exp);
        // ルートノード
        Node rootNode = new ExpNode();

        try {
            // 構文解析メソッドを再帰的に実行
            rootNode.parse(context);
        } catch (ParseException e) {
            System.out.println("ERROR: parseException: " + e.getMessage());
            return 0.0;
        }

        // ここのtoStringも再帰的に実行
        System.out.println("INFO: parsed exp = \"" + rootNode.toString() + "\"");

        double result = 0.0;
        try {
            // 計算メソッドも再帰的に実行
            result = rootNode.getResult();
        } catch (CalcException e) {
            System.out.println("ERROR: calcException: " + e.getMessage());
            return 0.0;
        }

        return result;
    }
}


仕事が忙しくなって休みの日にぐだぐだしてたせいでInterpreterパターンの実装が非常に遅くなったけど、なんとかこれでGoFの23パターンの実装が一段落したわけだ。よかったよかった。次はマルチスレッドのパターン・・・といくのが自然な流れな気もするけど、デザインパターン以外もやりたい今日この頃。

デザインパターンを覚えたい (Command)

Commandパターン

種々のコマンドをクラスとして表現するパターン。ポイントは、

  • 各コマンドに対してクラスを割り当てることでコマンドの追加・管理が容易になる
  • 共通の実行形式にすることで、タスクリストによる逐次処理とかが実装しやすい

とかかなぁ。うーん、個人的にうまくメリットを整理できてない。コマンドをクラスにしているのが最大のポイント?やってる事自体は普通な気がしたりしてます。

実装。ls, pwd, cdを持つ簡易コンソール作ります。
http://dl.dropbox.com/u/7810000/code/design_pattern/command.zip

実行。抜けるときはexit。

$ ./run.sh
console> pwd
/Users/xxx/tmp/command
console> ls
### /Users/xxx/tmp/command ###
build.xml
classes
run.sh
src
console> cd src
console> pwd
/Users/xxx/tmp/command/src
console> ls . .. console
### /Users/xxx/tmp/command/src/. ###
console
Main.java
### /Users/xxx/tmp/command/src/.. ###
build.xml
classes
run.sh
src
### /Users/xxx/tmp/command/src/console ###
command
Console.java
console> exit

ポイントはcommandの実行部分かな。どのコマンドも同じ方法で実行している。

public class Console {
    public void execute() {
        try {
            BufferedReader input = new BufferedReader(new InputStreamReader(System.in));

            String line;
            System.out.print("console> ");
            while ((line = input.readLine()) != null) {
                String[] inputs = line.split(" ");

                if (inputs.length < 1) {
                    showUsage();
                }

                if (inputs[0].equals("exit")) {
                    break;
                }
                else {
                    CommandFactory factory = CommandFactory.getInstance();
                    Command command = factory.getCommand(inputs[0]);
                    if (command != null) {
                        int argNum = inputs.length - 1;
                        String[] args = new String[argNum];
                        for (int i=1; i<inputs.length; i++) {
                            args[i-1] = inputs[i];
                        }

                        /* コマンドは違っても実行方法は同じ */
                        command.execute(args);
                    } else {
                        showUsage();
                    }
                }

                System.out.print("console> ");
            }

            input.close();

        } catch (Exception e) {
            System.out.println("Exception: " + e);
        }
    }

    private void showUsage() {
        System.out.println("### possible command list ###");
        System.out.println("pwd           : show current directory");
        System.out.println("cd path       : change directory");
        System.out.println("ls [path ...] : listup files");
        System.out.println("exit          : terminate this console");
    }
}

うーん、しかしこの実装、本のクラス図と結構形が違う気がしなくもない。もしかしてなにかCommandパターンの実装間違ってたりして。

デザインパターンを覚えたい (Proxy)

Proxyパターン

必要になってから作るパターン。実際の処理との間に一段クラスをかませることで、必要になるまで実処理の実行を抑止させる。
ポイントは

  • ワンクッション挟むことで途中までの処理を肩代わりさせる
  • 使う側からはProxyも実処理も透過的に見せる

とかかな。ホンダとDecoratorパターンとの類似性を指摘してるけど、個人的にはChain of Responsibilityパターンとなんとなく類似性を感じる。

実装。サンプルと若干かぶるけど、ファイル書き込みのProxy。
http://dl.dropbox.com/u/7810000/code/design_pattern/proxy.zip

実行。test.txtというファイルができます。

$ ant test
Buildfile: /Users/xxx/tmp/proxy/build.xml

build:

test:
[java] ProxyWriter: create
[java] ProxyWriter: pushString [hoge]
[java] ProxyWriter: pushString [fuga]
[java] ProxyWriter: pushString [puni]
[java] ProxyWriter: saveString
[java] RealWriter: create
[java] RealWriter: saveString

BUILD SUCCESSFUL
Total time: 0 seconds
$ cat test.txt
hoge
fuga
puni

ポイントはProxy内でファイル保存のタイミングでRealを呼び出しているところ。

public class ProxyWriter implements Writer {
    private List<String> lines;
    private Writer real = null;

    public ProxyWriter() {
        System.out.println("ProxyWriter: create");
        lines = new ArrayList<String>();
    }

    public void pushString(String str) {
        System.out.println("ProxyWriter: pushString [" + str + "]");
        lines.add(str);
    }

    public void saveString(String file) {
        System.out.println("ProxyWriter: saveString");
        /* RealWriterに仕事を渡す */
        if (real == null) real = new RealWriter(lines);
        real.saveString(file);
    }
}

デザインパターンを覚えたい (Flyweight)

Flyweightパターン

共有で用いるインスタンスをプールし、使いまわすパターン。ポイントは

  • 無駄なnewが減る
  • メモリが節約できる

GCがない言語とかだとnewそのものが減るのは安全性の観点でも効果がありそう。個人的にはSingletonとあんま違わないように見えなくもない。

実装。今回は以下のような実装で速度比較してみる。

  1. Flyweightで共有するクラスとして以下のようなクラスを用意する
    • コンストラクタ内でint型の1024要素の配列をnewする
    • 中身は空のexecuteメソッドを実装する
    • HogeFlyweight, FugaFlyweight, PuniFlyweightの3つのクラスを用意 (中身は同じ)
  2. 上記の3つのクラスの生成/実行を計1000000回実行し、プールする場合としない場合で速度を比較
    • 要するに3 * 1000000 = 3000000回の生成/実行を行う

3つ同じクラスを用意しているのは、Flyweightっぽい実装にしたかっただけで特に意味はありません
http://dl.dropbox.com/u/7810000/code/design_pattern/flyweight.zip

実行。

$ ant test
Buildfile: /Users/xxx/tmp/flyweight/build.xml

build:

test:
[java] without flyweight : 2003 msec
[java] with flyweight : 118 msec

BUILD SUCCESSFUL
Total time: 2 seconds

今回の実験条件ではFlyweightを使った方が速いことがわかります。

実装のポイントは、poolからインスタンスを再利用しているところ。

public class FlyweightFactory {
    private static FlyweightFactory instance = null;
    private Map<String, Flyweight> pool;

    private FlyweightFactory() {
        pool = new HashMap<String, Flyweight>();
    }
    public static FlyweightFactory getInstance() {
        if (instance == null) instance = new FlyweightFactory();
        return instance;
    }

    public Flyweight getFlyweight(String type, boolean usePool) {
        if (usePool) {
            if (pool.containsKey(type)) return pool.get(type);
            else {
                if (type == "hoge") pool.put(type, new HogeFlyweight());
                else if (type == "fuga") pool.put(type, new FugaFlyweight());
                else if (type == "puni") pool.put(type, new PuniFlyweight());
                else return null;

                return pool.get(type);
            }
        } else {
            if (type == "hoge") return new HogeFlyweight();
            else if (type == "fuga") return new FugaFlyweight();
            else if (type == "puni") return new PuniFlyweight();
            else return null;
        }
    }
}

# nullのreturnとか実装が汚いのは勘弁してくだしあ><

ちなみに、はじめintの配列とかなにも生成しない空クラスで実験した場合はFlyweightを使わない方が速かったです。
これは、おそらくFlyweightのMapから要素を探索する部分がボトルネックになったせいで、
共有するインスタンスの生成コストによっては毎回生成するというスタンスもありなのかもしれません。

デザインパターンを覚えたい (State)

Stateパターン

各状態に対して固有のクラスとして表現するパターン。特徴は

  • 状態変化を単純なインスタンスの差し替えで表現できる
  • 新しい状態の追加が用意

といったところ。クラス図だけ見るとStrategyパターンと同じだけど、違いは何だろ。
Strategyパターンは手順/動作に主眼を置くのに対して。Stateは状態に主眼を置いてる点?

実装。よくあるフラグ変化を手軽に実装してみる。
http://dl.dropbox.com/u/7810000/code/design_pattern/state.zip

実行。

$ ant test
Buildfile: /Users/xxx/tmp/state/build.xml

build:

test:
[java] 勇者:そうだ、関所を通ろう!
[java] 守兵:ここは関所だ。許可証の持たぬ者を通すわけにはいかない。早々に立ち去れい。
[java] 勇者:許可証を手に入れないと。。。
[java] ...許可証を手に入れた!
[java] 勇者:関所に再チャレンジだ!
[java] 守兵:ここは関所だ。許可証を持っているようだな。通るがよい。
[java] 勇者:いざ新天地へ!

BUILD SUCCESSFUL
Total time: 3 seconds

ポイントはContext中でのStateの扱い方。下記のようにインスタンスを入れかえることで状態遷移していて、実際の実行部分の形は変わらない。

public class GateContext implements Context {
    private State gateState;

    public GateContext() {
        gateState = CloseGateState.getInstance();
    }

    public boolean passGate() {
        return gateState.tryToPass();
    }

    public void changeState(StateFlag flag) {
        if (flag == StateFlag.GATE_OPEN) {
            gateState = OpenGateState.getInstance();
        } else if (flag == StateFlag.GATE_CLOSE) {
            gateState = CloseGateState.getInstance();
        }
    }
}

デザインパターンを覚えたい (Memento)

Mementoパターン

状態の履歴を保存するパターン。対象のインスタンスの情報を保持するMementoクラスを作成する。
ポイントは

  • 保存・復元を行うクラスのインスタンス状態を保持するクラスを用意することで、内部状態操作を閉じた範囲で行える

こと。インスタンスを復元には内部状態にアクセスする必要があるけど、不用意にpublicにするとカプセル化の意味がなくなってします。
Mementoパターンではこのような内部操作を限定された範囲で行うようにできるとかなんとか。

実装。コンソール迷路探索ゲーム。
http://dl.dropbox.com/u/7810000/code/design_pattern/memento.zip

実行。今回はコンソール入力がカラムので起動はコマンド経由で。

$ ./run.sh
--- 中略 ---
##############################
#S ###### ###################
# ######## ###################
# ##### ## ###################
# ###################
####### ## ###################
####### ## ## ################
###### ## #############
################ #############
################ #############
####### #############
####### ##### ################
####### ##### ################
#### ## ################
#### #########################
#### #########################
#### #########################
#### #########################
#### ##### ## ################
### ##### #############
#### ##### ## ## #############
#### ## ## ##### #############
### ##### #############
#### ##### ##### #############
################ #############
############### #######
################ ##### #######
###################### #######
###################### @ ###
##############################

--- possible command ---
map : show map
l : go left
r : go right
save : save current state
load : load saved state
exit : end game

input>

レイアウトが崩れまくりんぐ/(^o^)\ナンテコッタイ。とりあえずsaveとload機能があるのがポイント。
ちなみに、迷路の生成方法は、下記サイトのクラスタリングによる方法を使ってます。
http://apollon.issp.u-tokyo.ac.jp/~watanabe/tips/maze.html

実装では迷路本体であるMazeクラスのなかでMementoの作成、復元を行なっている。

public class Maze {

    public void saveMemento() {
        memento = new Memento(xSize, ySize);

        memento.setCurX(curX);
        memento.setCurY(curY);

        for (int y=1; y<=ySize; y++) {
            for (int x=1; x<=xSize; x++) {
                memento.setVisit(x, y, map[y][x].getVisit());
            }
        }
    }

    public boolean restoreMemento() {
        if (memento == null) return false;

        curX = memento.getCurX();
        curY = memento.getCurY();

        for (int y=1; y<=ySize; y++) {
            for (int x=1; x<=xSize; x++) {
                map[y][x].setVisit(memento.getVisit(x, y));
            }
        }

        return true;
    }

}

Mementoクラスは以下のとおり。wide intearfaceとnarrow interfaceは全然意識してないので、実装としてはいまいちだと思う。

public class Memento {
    private int curX, curY;
    private boolean visitMap[][];

    protected Memento(int xSize, int ySize) {
        this.curX = -1;
        this.curY = -1;

        visitMap = new boolean[ySize+2][xSize+2];
    }

    protected void setCurX(int curX) {
        this.curX = curX;
    }

    public int getCurX() {
        return curX;
    }

    protected void setCurY(int curY) {
        this.curY = curY;
    }

    public int getCurY() {
        return curY;
    }

    protected void setVisit(int x, int y, boolean visit) {
        visitMap[y][x] = visit;
    }

    public boolean getVisit(int x, int y) {
        return visitMap[y][x];
    }
}

実装の中で、コンソールのクラスがすごく汚くなってるけど、これはCommandパターンをやるときにでも整理するかも。