RapidXml RapidXmlの中身を追ってみた話
あいさつ
どうも、はかせです。
今回はRapidXmlの中身を追ってみた話です。
実際RapidXmlのXML解析以外にも個人的に勉強になった部分もあるので
その部分もまとめていきます。
XML解析方法
RapidXmlは極めて単純な方法でXMLファイルを解析しています。
その方法とは
XMLデータをオンメモリで持ち一文字ずつ比較する
です。
全てのデータをchar*型でオンメモリに展開し、
char*を一文字ずつチェックしてノードにデータを落とし込んでいます。
おそらく最速を目指すにはファイルI/Oを極力減らす必要があったからでしょうね。
そのためコード的には再起処理がバンバン入りまくって
追っかけるのに骨が折れますが、やってること自体は単純でした。
テンプレート+ダックタイピングの使い方
これが今のところライブラリを追っかけていて
一番勉強になったとこです。
この機能の仕組みや有用性自体は私も過去に記事にしました。
hakase0274.hatenablog.com
では、何が勉強になったかというとこの仕組みの使い方です。
私が上げた記事や実際に私が使っているのは
インスタンスをメソッドの引数に渡しインスタンスメソッドを呼ぶ
ことで多様性を実現しています。
class Interface { virtual void Show() = 0; } class Hoge : public Interface { void Show() override { std::cout << "Hoge"; } } class Fuga: public Interface { void Show() override { std::cout << "Fuga"; } } void InterfaceCall(Interface* interface) { interface->Show(); } int main { Hoge hoge = new Hoge(); InterfaceCall(hoge); delete hoge; Fuga fuga = new Fuga(); InterfaceCall(fuga); delete fuga; }
RapidXmlではクラス(構造体)を宣言し
テンプレート引数にそのクラスを受け取る
ことで多様性を実現しています。
struct Hoge { void Show { std::cout << "Hoge"; } } struct Fuga { void Show { std::cout << "Fuga"; } } template<class T> void InterfaceCall() { T::Show(); } int main() { InterfaceCall<Hoge>(); InterfaceCall<Fuga>(); }
こうすることでクラスの宣言だけで
私がやっていたことを実現できます。
unsigned charを配列の添え字にする
これは実際どこまで有用なのかはまだわかりかねますが、
こんなやり方あったんだーと思ったので書いておきます。
とはいっても難しいキャストとかをするわけではありません。
charやunsigend charは元々8ビットで表現される値です。
その値をUnicodeなりShift-Jisなりで解釈して文字にしていたわけです。
つまり所詮値なので配列の添え字にできます。
なので256の長さのint配列でも宣言して対応表を作れば
各文字ごとに判定などができます。
(RapidXmlもこの対応表を作ってパースしている)
あとがき
今回はRapidXmlの中身を追っかけて得た知見まとめでした。
C++erにとっては当たり前の技術なのかもですが、
私的には新発見だったので今回まとめてみました。
UE4、boostとライブラリは読んできましたが、
巨大すぎて今の私には追い切れていない部分が多々ありました。
その点今回読んでいるRapidXmlは一つのヘッダファイルで構成されている
比較的小さいライブラリのため、追いかけやすく勉強しやすいです。
こういう小さいライブラリを読んで
少しずつでもステップアップしていきたいところですね。
それでは今回はこの辺でノシ
追記
ブログアクセスしたとき一覧表示される機能を外しました。
というのもこの機能があるとトップページにアクセスできず
アドセンスの審査が通らないからです。
(2019/07/19)