リンクが倍速くなるらしい「lld」を試す
最近、ビルトインのldによるリンクの遅さが気になってきた。
そこで、もっと高速なリンク方法がないか探してみたところ、いくつかの新しいリンカに辿り着いた。
GNU goldよりも2倍早いlld
高速なリンカとしてはGNU goldが割と有名らしいが、それよりも更に高速なlldというものを見つけた。
このページ曰く「GNU goldの2倍高速で」動作するらしい。
lldのインストール
Ubuntu 16.04 (Xenial Xerus) にはパッケージがあるようなので入れてみる
sudo apt -y install lld-4.0
これでld.lldが利用可能になる。
ついでに、ldのシンボリックリンク切り替えの設定もしておく。
参考: qiita.com
sudo update-alternatives --install "/usr/bin/ld" "ld" "/usr/bin/ld.lld" 30 sudo update-alternatives --install "/usr/bin/ld" "ld" "/usr/bin/ld.gold" 20 sudo update-alternatives --install "/usr/bin/ld" "ld" "/usr/bin/ld.bfd" 10
これで登録は完了で、あとは
sudo update-alternatives --config ld
とすることでldの切り替えができる。
実際に使ってみた感じとしてはやはり数倍早くなっている感じだ。
少し待たされるようなジョブも一瞬で終わるようになった。
おそらくconfigureの速度を大きく改善するであろう。
構造体のDictionaryでは直接値を変更できない
コンテナの返値が値型か参照型かに気をつけましょうねという話。
シチュエーション
例えば、以下のようなコードを書いてみたとする。
public class Program { struct MyStruct { public int val1; public int val2; } public static void Main() { var dic = new Dictionary<int, MyStruct>(); dic[0].val1 = 1; dic[0].val2 = 2; } }
自前の構造体をDictionaryに格納し、その値を変更するコードである。
しかし、これはコンパイルエラーになる。
error CS1612: 変数ではないため、'Dictionary.this[int]' の戻り値を変更できません
Dictionary内の要素に値を代入することができていないようだ。
dic[0]の返値は参照型ではなく値型
実は、これはMyStructが値型であることが原因である。
つまり、dic[0]というのは、dic内の0番目の要素のコピーであって、それに対していかなる操作を行ってもdic内の要素には一切影響しない。
上記のように[]で参照したものの値を直接書き換えたいならば、MyStructをclassにするしかない。
public class Program { class MyStruct { public int val1; public int val2; } public static void Main() { var dic = new Dictionary<int, MyStruct>(); dic.Add(0, new MyStruct()); dic[0].val1 = 1; dic[0].val2 = 2; } }
これならdic[0]はdic内の0番目の要素への参照となり、正しく動く。
C++ならコンテナは必ず参照型を返してくれるので、原因が分かるのに時間がかかった。
neosnippetに自分のスニペットを追加する
前回の記事ではneosnippetを導入したが、自作のスニペットを使いたくなったので方法をメモ。
neosnippetの設定
まずは、スニペットファイルの保存先を指定する。
プラグイン起動時の設定に一行追加する。
let g:neosnippet#snippets_directory = ~/.vim/dein/repos/github.com/Shougo/neosnippet-snippets/snippets/'
したら再起動する。
スニペットの編集
まずは、スニペットを追加したいタイプのファイルを開く。
そして、「:NeoSnippetEdit」とコマンドを入力する。
すると、スニペットの編集画面が開く。
スニペットの構文は以下の通り。
snippet [識別子] alias [略記法] <インデント>スニペット内容 <インデント>スニペット内容 …
スニペット内容は基本は展開したい内容をそのまま書く。
また、Ctrl+Kで順にカーソルが移動できるような場所は「${数字:デフォルト値}」として書けばよい。
終わったら「:w」で保存する。
以上でスニペットの追加は完了である。
OOP初心者がブロック崩しを作ってみる その2
※この記事は「OOP初心者がブロック崩しを作ってみる その1」の続きです
衝突判定を考える
さて、衝突判定のやり方を考えよう。
衝突はボールとReflectorの間で起こる。とりあえず以下のようにクラス分けしてみる。
ReflectorCollectionにReflectorを全て格納しておいて、Ball側から参照、衝突判定を行う。
move関数はBallに速度に従っての移動を指示する関数で、移動するたびに衝突判定を行う。
BallとReflectorのgetRect関数はそれぞれの専有する範囲を返す。(衝突判定に使用)
衝突判定を外に出す
これでも悪くはないが、Ballが「移動する物体」と「衝突する物体」の2つの役割を持っているので、分割したい。
ということで、衝突判定は外に出し、Ballは速度に従って移動することに専念することにする。
CollisionManagerが衝突判定を担当する。
流れとしては、
- Ballのmove関数が呼ばれる
- Ballが速度に従って移動
- BallがexecuteCollisionを呼ぶ
- CollisionManagerが全Reflectorと衝突判定
- CollisionManagerがgiveImpulseを呼び、ボールに力積を与える
という感じ。
Observerパターンを適用する
結合度の面から言えば、BallとCollisionManagerがお互いの関数を直接呼び出しているのであまり良くない。
そもそも、CollisionManagerはボールの移動をトリガーとして衝突判定を行うのである。
したがって、CollisionManagerがボールの移動を監視すれば良い。
つまり、Observerパターンを適用する。
move関数で移動した後、observerに移動を通知する。
これで多少はすっきりした。
Reflectorが衝突を知るには
ブロックのように衝突の有無を情報として必要とするReflectorが存在するので、それを通知する必要がある。
それもCollisionManagerが担当するのが妥当であろう。
以上のことを加味してまとめたクラス図はこうなった。
衝突判定に関しては概ねこのような感じでいいだろう。
次回予告
UMLをテキストで書ける「PlantUML」を試す
UML図を書くフリーのツールにはいろいろあるが、テキストコマンドで書けるものの一つに「PlantUML」がある。
テキストベースで書けると何がいいかというと、
- 保存・編集・移動・再利用が容易である
- Gitなどのバージョン管理システムとの親和性
などの点が挙げられる。
使い方等
PlantUML自体はJavaで書かれたテキストプロセッサであるが、Web上でこれを試せるサービスがある。
リファレンスはここにある。
クラス図・フローチャートのほかにも色々とかけるらしい。
使用例
テキスト
@startuml start :ボールを移動; repeat :Reflectorを一つ取り出す; if (ボールと衝突したか?) then (yes) :ボールの移動方向を変える; else (no) endif repeat while (Reflectorはあまだあるか?) stop @enduml
出力
これは積極的に使っていきたい。