Rogue Wave バナー
前へマニュアルの先頭へ目次次へ

5.9 挿入子関数の改善

ここでは、挿入子関数の改善方法について検討します。巨大な国別コードテーブルがあって、国別コードへのアクセスに時間がかかる状況を想定します。挿入子関数のパフォーマンスは、国別コードテーブルをキャッシュして直接アクセスするようにし、パフォーマンスのオーバーヘッドをなくすことで最適化することができます。

5.9.1 基本キャッシュ

次のコードでは、基本キャッシュを行います。ストリームのロケールオブジェクトから電話ファセットオブジェクトを取り出し、国別コードテーブルを静的変数にコピーします。

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);
}

ストリームに組み込まれたロケールオブジェクトは変更されましたが、キャッシュされた静的国別コードテーブルが変更されなかった状況を想定してみます。キャッシュがデータで一杯になると、ストリームのロケールオブジェクトを変更しても、この挿入子関数のキャッシュは変更されません。これは望ましいことではありません。必要な対策は、新しいロケールオブジェクトが組み込まれるたびに何らかの通知を行って、キャッシュを更新することです。

5.9.2 コールバック関数の登録

以下の例では、コールバック関数で通知を行います。コールバック関数の登録は入出力ストリームで行います。クラス 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 でアクセスすることができます。

5.9.3 挿入子の改善

挿入子に関して、改善すべきところはすべて改善してきました。必要に応じてキャッシュを更新するコールバック関数が挿入子によって登録されます。登録は、クラス 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 月