HashCompare の詳細

concurrent_hash_mapHashCompare 引数を独自の型で動作するようにする方法はいくつかあります。

tbb_hasher 関数は、次の型向けに事前に定義されています。

例えば、Foo 型のキーがあり、operator==Foo 用に定義されている場合、tbb_hasher を次のように定義します。

size_t tbb_hasher(const Foo& f) {
    size_t h = ...f のハッシュコードを計算...
    return h;
};

一般に、tbb_hash_compare<Key> または HashCompare の定義は 2 つの署名を提供します。

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 を使用して複数のプロセッサーがヒストグラムを協調して構築できる完全なサンプルが含まれています。