テキストエディタ実装技術 |
[ index | 前のドキュメント | 次のドキュメント | このドキュメントのソース ] |
■ CStringListEE の高速化 |
CStringList aList のデータを最初から順に参照する場合、以下のように POSITION オブジェクトを使い、ノードを順にたどるのが普通である。この方法であればシーケンシャルアクセスにかかる時間は極めて少ない。 |
POSITION pos = aList.GetHeadPosition(); // 最初のノードへのポインタを取得 while( pos != NULL ) { // ポインタが有効な間 CString text = aList.GetNext(pos); // ポイントしてるノードのテキストを取得し、次のノードへ ..... } |
CStringListEE でも同様に POSITION でのノード指定とノード移動を可能にすれば、先のシーケンシャルアクセスが高速化できる。しかし、POSITION は CStringList に強く依存するし、クラスの実装の都合がインタフェースに影響するのはエディットエンジンの設計としは好ましくない。そこで、直前にアクセスされた行番号とノードを覚えておき、getText() で指定された行番号が覚えておいた行の次であれば、覚えているノードの次のノードのテキストを返すようにする。 |
メンバ変数に直前にアクセスされたの行番号、ノードへのポインタを追加する。これらのデータをキャッシュと呼ぶことにする。 |
class CStringListEE : public CEditEngine { CStringList m_editBuf; int m_lastLine; // 直前にアクセスされた行番号 POSITION m_lastPos; // 直前にアクセスされた行ノードへのポインタ ..... } |
CStringListEE::getText() の実装では、キャッシュが有効で、キャッシュの次の行番号であれば、ノードを移動しテキストを返すようにする。実装は以下のようになる。 |
bool CStringListEE::getText( int line, // 行番号 [0..N-1] CString &text) // output:指定行の文字列 { if( m_lastPos != NULL ) { if( line == m_lastLine + 1 ) { // 次の行を参照 m_lastLine += 1; m_editBuf.GetNext(m_lastPos); text = m_editBuf.GetAt(m_lastPos); return true; } } POSITION pos = m_editBuf.FindIndex(line); // 行番号 if( pos == NULL ) // 指定行が存在しない場合 return false; text = m_editBuf.GetAt(pos); m_lastLine = line; m_lastPos = pos; return true; } |
このキャッシュを用いた実装でシーケンシャルアクセスのパフォーマンス計測を行ってみた。以前の結果は、 |
CStringListEE: シーケンシャルアクセス(1000 行、最初から最後):0.000 sec シーケンシャルアクセス(10000 行、最初から最後):0.321 sec シーケンシャルアクセス(20000 行、最初から最後):3.255 sec シーケンシャルアクセス(30000 行、最初から最後):16.714 sec |
だったのが、 |
CStringListEE: シーケンシャルアクセス(1000 行、最初から最後):0.000 sec シーケンシャルアクセス(10000 行、最初から最後):0.010 sec シーケンシャルアクセス(20000 行、最初から最後):0.010 sec シーケンシャルアクセス(30000 行、最初から最後):0.010 sec |
となった。 |
このように直前にアクセスされた行番号とノードを覚えておき、その情報からノードを高速に取得する手法を行番号キャッシュ法と呼ぶ。 |
[ index | 前のドキュメント | 次のドキュメント | このドキュメントのソース ] |