0

特定のエンコーディング(UTF-8、UTF-16、UTF-16LE、UTF-16BEなど)のバイトシーケンスを追加したいCFMutableStringオブジェクトがあります。

私が持っている最も効率的な方法は次のとおりです。

CFStringRef tmp = CFStringCreateWithBytesNoCopy(kCFAllocatorDefault, bytes, numBytes, encoding, NO, kCFAllocatorNull);
CFStringAppend(myMutableString, tmp);
CFRelease(tmp);

そうするためのより良い方法はありますか?

4

1 に答える 1

0

あなたが実際に効率について質問していると思います(CPU時間のように)、そしてあなたは実際にあなたの文字列構築にボトルネックを持っていると思います。有用性の高いものから順にいくつかのアイデアを捨てていきます。

CFStringCreateByCombiningStrings多くの場合、1つの大きな文字列にたくさんのものを追加し、 /を使用することで時間を20〜50%短縮できます-[NSArray componentsJoinedByString:]

CFStringRef tmp = CFStringCreateWithBytesNoCopy(kCFAllocatorDefault, bytes, numBytes, encoding, NO, kCFAllocatorNull);
CFStringAppend(myMutableString, tmp);
CFRelease(tmp);    

…これを行う:

CFStringRef tmp = CFStringCreateWithBytesNoCopy(kCFAllocatorDefault, bytes, numBytes, encoding, NO, kCFAllocatorNull);
CFArrayAppendValue(myMutableArray, tmp);
CFRelease(tmp);
// ... after you've finished accumulating everything
CFString *myString = CFStringCreateByCombiningStrings(kCFAllocatorDefault, myMutableArray, kEmptyString);

最終的には文字列のサイズがわかっている場合があります。最初のCFStringCreateMutable/ の呼び出しで適切な容量を使用することで、時間を少し短縮できます-[NSMutableString stringWithCapacity:]。もちろん、この最適化はアレイの結合と互換性がありません。

変換コストの一部を回避できます。また、配列結合を使用していない場合は、一時的なCFString作成コストを回避できます。

CFString明らかに、右エンディアンUTF-16はの「文字」と同じものであるため、を使用するだけで済みますCFStringCreateWithCharactersNoCopy。またはCFStringAppendCharacters

間違ったエンディアンのUTF-16の場合、「NoCopy」は役に立たず、少しでも傷つく可能性があります。また、特にインプレースで実行できる場合は、バイトを右端のUTF-16にスワップするだけで、汎用変換よりも高速に実行できる可能性があります。これが(特に大きな文字列で)高速であるとは思いませんが、これが本当にボトルネックである場合は、試してタイミングをとる価値があります。

ポインタを2バイトシフトすると、BOMプレフィックス付きのUTF-16がどちらかになります。

UTF-8の場合も、「NoCopy」は役に立たず、少し傷つく可能性があります。しかし、明らかに変換を行う必要があります。CFよりも高速なデコーダーを見つけて書き込むことができるかもしれませんが、エンディアンが間違っているUTF-16よりもはるかに少ない可能性があります。ただし、。を使用して一時文字列をスキップすることはできますCFStringAppendCString

また、それほど可能性は低いですが、他のUnicodeライブラリがCFを気に入っているiconvicu、CFに見合うだけの余裕を持って打ち負かす可能性もあります。その場合は、最初にすべてを右エンディアンUTF-16に入れ、次にCFStringCreateWithCharacters(配列結合を使用している場合)またはCFStringAppendCharacters(そうでない場合)。

次に、アロケータとリカウントには常にトリックがあります。文字列と配列のストレージ用のゾーンアロケータを作成し、何もしないCFArrayCallbacksを作成すると、数回のmalloc呼び出しだけで、ほとんど再カウントせずにすべてを構築できます。すべてをゾーンのフロアにドロップして、一度解放します。componentsJoinedByString:(もちろん、デフォルトのアロケータを使用します)。

もちろん、いくつかの追加のアプリケーション知識があれば、あらゆる種類のことが可能になるかもしれません。ばかばかしいほど明白なケースを取り上げるために、すべて16バイト値の16進エンコーディングである文字列の束を追加するとします。その場合は、32 * n + 1の大きなブロックを1つ割り当て、unicharコピーするだけでUTFを「デコード」し(右エンディアンUTF-16)、ポインターから1バイトオフセットしてコピーします(間違ったエンディアンUTF-16)。または、バイトを0と交互に(UTF-8)、次に1つの大きなを実行しCFStringCreateWithCharactersNoCopyます。

于 2013-03-22T01:14:29.757 に答える