concurrent_hash_map の HashCompare 引数を独自の型で動作するようにする方法はいくつかあります。
HashCompare 引数を明示的に指定します。
tbb_hash_compare<Key> を HashCompare のデフォルトにして、次のいずれかの操作を行います。
tbb_hash_compare<Key> テンプレートの特殊化を定義します。
tbb_hasher(Key) 関数のオーバーロードを定義します。
ライブラリーによって提供される tbb_hasher(Key) の定義に依存します。
tbb_hasher 関数は、次の型向けに事前に定義されています。
size_t に変換可能な型 (整数型など)。
ポインター型。
std::basic_string のインスタンス。
std::pair<Key1,Key2>,(tbb_hasher(Key) および tbb_hasher(Key2) が定義される)。
例えば、Foo 型のキーがあり、operator== が Foo 用に定義されている場合、tbb_hasher を次のように定義します。
size_t tbb_hasher(const Foo& f) { size_t h = ...f のハッシュコードを計算... return h; };
一般に、tbb_hash_compare<Key> または HashCompare の定義は 2 つの署名を提供します。
Key を size_t にマップする hash メソッド
2 つのキーが等しいかどうかを判断する equal メソッド
2 つのキーが等しい場合、同じ値にハッシュしなければならない ため、署名は自然に単一クラスになります。そうしないと、ハッシュテーブルは動作しません。常に 0 にハッシュすれば当然この要件を満たすことができますが、非常に効率が悪くなります。各キーが異なる値にハッシュされるのが理想的です。少なくとも、2 つの別のキーが同じ値にハッシュされる可能性を低くしておく必要があります。
異なるインスタンスで異なる動作が必要でなければ、HashCompare のメソッドは static です。この場合、HashCompare を引数とするコンストラクターを使用して concurrent_hash_map を構築します。次のサンプルは、インスタンス依存のメソッドを使用した以前のサンプルのバリエーションです。インスタンスは、内部フラグ ignore_case に基づいて、大文字/小文字を区別するハッシュまたは区別しないハッシュを行い、比較します。
// ユーザー定義型を扱うハッシュと比較操作を定義する構造体 class VariantHashCompare { // true の場合、文字列の大文字/小文字は無視される bool ignore_case; public: size_t hash(const string& x) const { size_t h = 0; for(const char* s = x.c_str(); *s; s++) h = (h*16777179)^*(ignore_case?tolower(*s):*s); return h; } // 文字列が等しい場合は true bool equal(const string& x, const string& y) const { if( ignore_case ) strcasecmp(x.c_str(), y.c_str())==0; else return x==y; } VariantHashCompare(bool ignore_case_) : ignore_case(ignore_case_) {} }; typedef concurrent_hash_map<string,int, VariantHashCompare> VariantStringTable; VariantStringTable CaseSensitiveTable(VariantHashCompare(false)); VariantStringTable CaseInsensitiveTable(VariantHashCompare(true));
examples/concurrent_hash_map/count_strings ディレクトリーには、concurrent_hash_map を使用して複数のプロセッサーがヒストグラムを協調して構築できる完全なサンプルが含まれています。