
このドキュメントでは、新しい nsString クラスの構造を手短に記し、メモリ管理上のインプリメント、最適化、国際化、使用パターン、を明確にすることを意図しています。
おことわり: 私は、絶対的に string クラスを嫌っています。だれも 2 人以上のプログラマが納得するものを発明していません。そう、ならばなぜ私はこれを提案しているのか? いいでしょう、nsString は私たちにいまのところよく仕えていますが、手直しを必要としています。そして、XPCOM は実際に一人前になっています。そのため、nsString もそこに加らなくてはなりません。
nsString クラスは、デフォルトのインプリメンテーションとして Gecko (とその他のモジュール) のすべてを通して使われる wide character の文字列です。しかし、処理すべきインプリメンテーションの細部がいくつかある、という問題を抱えており、それはこのドキュメントの主題でもあります。現在のインプリメントで欠けているものは、
新しい nsStrImpl インプリメンテーションの顕著な特徴は
新しい構造の基礎となるデータタイプは、以下に示す struct nsStrImpl です。
struct nsStrImpl {
PRInt32 mLength;
void* mBuffer;
PRInt32 mCapacity;
char mCharSize;
char mUnused;
// そして今は、nsStrImpl API のための...
static void EnsureCapacity(nsStrImpl& aString,PRUint32 aNewLength);
static void GrowCapacity(nsStrImpl& aString,PRUint32 aNewLength);
static void Append(nsStrImpl& aDest,const nsStrImpl& aSource,PRUint32 anOffset,PRInt32 aCount);
static void AppendCString(nsStrImpl& aDest,const char* aSource,PRUint32 anOffset,PRInt32 aCount);
static void Assign(nsStrImpl& aDest,const nsStrImpl& aSource,PRUint32 anOffset,PRInt32 aCount);
static void AssignCString(nsStrImpl& aDest,const char* aSource,PRUint32 anOffset,PRInt32 aCount);
// char もしくは、既存文字列の部分の代入...
static void Insert(nsStrImpl& aDest,PRUint32 aDestOffset,
const nsStrImpl& aSource,PRUint32 aSrcOffset,PRInt32 aCount);
static void InsertCString(nsStrImpl& aDest,PRUint32 aDestOffset,
const char* aSource,PRUint32 aSrcOffset,PRInt32 aCount);
static void InsertChar(nsStrImpl& aDest,PRUint32 aDestOffset,char theChar);
static void InsertChar(nsStrImpl& aDest,PRUint32 aDestOffset,PRUnichar theUnichar);
static void InsertChar(nsStrImpl& aDest,PRUint32 aDestOffset,PRInt32 theQuadChar);
static void Delete(nsStrImpl& aDest,PRUint32 aDestOffset,PRUint32 aCount);
static void Truncate(nsStrImpl& aDest,PRUint32 aDestOffset);
static PRInt32 Compare(const nsStrImpl& aDest,const nsStrImpl& aSource,
PRInt32 aCount,PRBool aIgnoreCase);
};
nsString クラスは今でも nsStrImpl クラスのサブクラス (ラッパー) として私たちとともにあります。デフォルトで、nsStrings は 2 バイト UCS2 文字格納モデルを使います。 nsString クラスは機能性を nsStrImpl スタティックライブラリから得ているため、とても軽量です。上記した nsStrImpl の API に加えて、nsString、nsAutoString、nsCString はいずれも、構築、検索、比較のための追加の API (それらはすべて、nsStrImpl の API よりグレードの低いものです) を提供します。また、新しい nsString インタフェースは、mozilla/base/src/nsString.h で築かれた既存の nsString クラスにあるインタフェースをまったく真似ていることも記しておきます。
私たちは、独自のものであるスタックベースのバッファを提供する nsAutoString をいまだに提供しています。このとても有用なクラスはプログラマに、ヒープベースのアロケーションを減らす上に、 nsString/nsStrImpl インプリメンテーションをうまく利用することを許しています。 nsAutoString に改善が加えられ、独自の内部バッファではなく、任意サイズのスタックベースバッファが使用できるようになりました。これは、文字列格納のために効率的な (一時) スタックバッファを使いつづけながら、特に必要のあるときは、おまけの格納エリアを使用できる、ということを意味します (複雑に聞こえますが、実際には簡単なことです)。このクラスは nsString や nsStrImpl と完全に共同で使うことが出来ます。
軽便さ、スレッド、Gecko の安全性プロセスを増すために、私は私たちの文字列クラスの派生物それぞれの使用に関して以下のルールを勧めます。
|
|
|
|---|---|
| nsStrImpl | nsStrImpl 関数ライブラリとリンクされたモジュールの間を文字列を通すときに使ってください。 |
| nsString | 管理範囲があなたのプロセスの中に限って生存するとわかっているオブジェクトの中だけローカルにこれらを使ってください。これらは、たいがい他のモジュールの中のオブジェクトには露出しないのがいいでしょう。 |
| nsAutoString | 絶対に必要なのでなければ、ヒープのアロケーションを被りたくない場合だけ限定的にこれらを使ってください。 |
| nsCString | nsString と同じですが、地域化を考えるために慎重に使われるべきです。 |
| nsIString | nsStrImpl インプリメンテーションを使わないだろうモジュールの間を文字列を通すときに使ってください。これは最も一般的なアプローチです。しかし、参照をカウントした文字列を提供します。 |
このインプリメンテーションに関して、密接に関連するものがあります。特に、Gecko 全体にわたる API の変化です。中でも、public な API で、 API 中に nsStrings を使用することは推奨されなくなるでしょう。これら API のものは nsStrImpl 参照を代わりに使って書き直される必要があるでしょう。別の方法として、プログラマはモジュールの間を nsIStrings を通すことができます。
その他の (主に国際化チームの) 関心は、少しだけでもの 1 バイト (ASCII) nsCString 使用法に関するものです。国際化チームは、もしその使用法に適切な制限がなされなければ、収拾の付かない状態になるだろう、と正しい意見を述べました。問題は、プログラマが ASCII 文字列に関して行なう推測に起因します。典型的な推測は、文字列を UCS2 文字列と仮定するようなコードと相互にかかわる必要はないだろう、というものです。この仮定は、たいてい間違っています。そして、ソースを各国化する私たちの能力を妨げるでしょう。
(ASCII) nsCString のものは以下の文脈で有用だと認識されています。
私は、最初のケースだけが、規範の面から見て正当であると主張したいと思います。国際化チームの人々は、パフォーマンス上は不利な場合でも、wide 文字列を使って、1 バイト型が必要なら変換するのがよりよいと、と言うでしょう。私は慣習法を認めなければならないため、私は nsCString を利用可能としましたが、慎重に使われるべきであるということを注意しておきます。
新しい構造の主要な機能拡張は、差込可能なメモリアロケータです。すべての nsString のサブクラスは、自身のデフォルトのアロケートのインプリメンテーションを提供しています。しかし、プログラマがそれを使うかどうかは自由です。新しいプロトタイプ nsStrImpl、nsString クラスでは、アロケータは文字列の構築の間に組み込まれる備えつけのメンバです (デフォルトでグローバルのアロケータに共有されます)。
メモ: COM ルールはだれでも同じアロケータを使う必要があることを意味します。そのアロケータは CoGetMalloc() と呼ばれるグローバル COM サービス経由で取得します。プログラマは彼ら自身の方針を組み込むことができるため、私たちの nsStrImpl はアロケータパターンを使います。しかし、これはマルチプロセス環境でアロケーションをシンプルにもします。 string がそれ自身の (共有の) アロケータをこの目的で返すことができることがすなわち十分であるかどうか疑っています。
私たちの最小限の nsIMemoryAgent インタフェースはちょうど nsString の慣習をサポートするのに十分であり、一般的メモリアロケーション慣習を提供するように拡張されるでしょう。これがその API です。
class nsIMemoryAgent : nsISupports {
void* New(nsInt32 aSize)=0; // alloc と realloc 両方のために使われます
void* Delete(void* aPtr)=0;
};
新しい nsStrImpl/nsString インプリメンテーションは私たちの国際化チームの主要な関心の最低 2 つを扱っています。まず、nsStrImpl は、構築、比較、代入の間に使うための文字セット変換機構を提供します。(これらは、国際化チームのレビューと移植を待つために、今日はずされました)。次に、プログラマがさまざまな方法で文字クラスを誤用することを防ぐことに関心があります。すなわち、
このページは2007年 10月 1日, 18:17に更新されました by Yoshino