ここでは、挿入子関数の改善方法について検討します。巨大な国別コードテーブルがあって、国別コードへのアクセスに時間がかかる状況を想定します。挿入子関数のパフォーマンスは、国別コードテーブルをキャッシュして直接アクセスするようにし、パフォーマンスのオーバーヘッドをなくすことで最適化することができます。
次のコードでは、基本キャッシュを行います。ストリームのロケールオブジェクトから電話ファセットオブジェクトを取り出し、国別コードテーブルを静的変数にコピーします。
ostream& operator<<(ostream& os, const phoneNo& pn)
{
locale loc = os.getloc();
const phone_put& ppFacet = use_facet<phone_put> (loc);
// 基本キャッシュ
static prefixMap_t codes = *(ppFacet.country_codes());
// キャッシュコードを使用した高度な出力
...
return (os);
}
ストリームに組み込まれたロケールオブジェクトは変更されましたが、キャッシュされた静的国別コードテーブルが変更されなかった状況を想定してみます。キャッシュがデータで一杯になると、ストリームのロケールオブジェクトを変更しても、この挿入子関数のキャッシュは変更されません。これは望ましいことではありません。必要な対策は、新しいロケールオブジェクトが組み込まれるたびに何らかの通知を行って、キャッシュを更新することです。
以下の例では、コールバック関数で通知を行います。コールバック関数の登録は入出力ストリームで行います。クラス ios_base で次のように宣言します。
enum event { erase_event, imbue_event, copyfmt_event }; //1
typedef void (*event_callback) (event, ios_base&, int index);
void register_callback (event_callback fn, int index); //2
| //1 | 登録したコールバック関数は、次の 3 つのイベントに呼び出されます。
|
| //2 | register_callback()
関数では、コールバック関数と、ストリームの
parray までのインデックスを登録します。imbue()、copyfmt()、
~ios_base() に対する呼び出しの間に、関数 fn
は引数インデックスとともに呼び出されます。イベントが発生すると、登録された関数は、登録時とは逆の順序で呼び出されます。
parray は、基底クラス ios_base の静的配列です。この配列までのインデックスを使用するには、xalloc() を使用します。また配列にアクセスするには pword(index) か iword(index) を使用します。図 16 にその方法を示します。 図 16 -- 静的配列 parray
|
キャッシュを更新するコールバック関数をインストールするには、parray までのインデックスを検索してキャッシュを作成し、そのコールバック関数をコンストラクタに登録するクラスを実装します。以下のコードに、その方法を示します。
class registerCallback_t {
public:
registerCallback_t(ostream& os
,ios_base::event_callback fct
,prefixMap_t* codes)
{
int index = os.xalloc(); //1
os.pword(index) = codes; //2
os.register_callback(fct,index); //3
}
};
| //1 | 配列までのインデックスを、xalloc() で検索します。 |
| //2 | コードテーブルまでのポインタを pword() で配列に格納します。 |
| //3 | コールバック関数とインデックスを登録します。 |
parray までのインデックスを使用して、実際のコールバック関数が後でキャッシュにアクセスします。
この段階では、ストリームのロケールを変更するたびにキャッシュを更新するコールバック関数がまだ必要です。以下のコードは、そのようなコールバック関数を示したものです。
void cacheCountryCodes(ios_base::event event
,ios_base& str,int cache)
{ if (event == ios_base::imbue_event) //1
{
locale loc = str.getloc();
const phone_put<char>& ppFacet =
use_facet<phone_put<char> > (loc); //2
*((phone_put::prefixMap_t*) str.pword(cache)) =
*(ppFacet.country_codes()); //3
}
}
| //1 | イベントが、組み込んだロケールの変更であるかどうかを調べます。 |
| //2 | ストリームのロケールから電話番号ファセットを検索します。 |
| //3 | キャッシュに国別コードテーブルを保存します。キャッシュは、ストリームの parray でアクセスすることができます。 |
挿入子に関して、改善すべきところはすべて改善してきました。必要に応じてキャッシュを更新するコールバック関数が挿入子によって登録されます。登録は、クラス registerCallback_t の静的変数の宣言によって 1 回だけ行われます。
ostream& operator<<(ostream& os, const phoneNo& pn)
{
static phone_put::prefixMap_t codes =
*(use_facet<phone_put>(os.getloc()).country_codes()); //1
static registerCallback_t cache(os,cacheCountryCodes,&codes);//2
// some sophisticated output using the cached codes
...
}
| //1 | 現在の国別コードテーブルがキャッシュされます。 |
| //2 | コールバック関数 cacheCountryCodes が登録されます。 |
Copyright (c) 1998, Rogue Wave Software, Inc.
このマニュアルに関する誤りのご指摘やご質問は、電子メールにてお送りください。
OEM リリース, 1998 年 6 月