ホーム < ゲームつくろー! < ツール編


その10 文字列→32bitハッシュ値変換クラス(v1.02)


 不定長の文字列に対応する32bitのハッシュ値を算出してくれるクラスです。

名前 バージョン 公開日
32bitハッシュクラス 1.02 2011. 5. 6

バージョンレポートはこちら

 長短様々な文字列から一意の値(ハッシュ値)が算出できると色々な局面で役立ちます。例えば、リストの中から同じ文字列を探す場合、まともにやると頻繁な文字列の比較作業が発生します。これが値となると非常に単純且つ高速に比較作業が行えます。私が役立ったのがテクスチャの管理クラスを作った時です。それまではmap<string, IDirect3DTexture9>という文字列をキーとするマップを使っていたのですが、これがmap<unsigned, IDirect3DTexture9>と値をキーとするマップに変更できました。また独自のバイナリリソースファイルを作る時にいつも困るのが「これが何の情報であるか」を表すヘッダーの埋め込みです。「MaterialData」のような文字列を埋め込んでも良いのですが、この場合「バイナリファイルを見るとばれるなぁ」「構造体に文字配列変数が入るのかぁ・・・う〜ん、長さ制限が必要だしファイル解析時の比較作業も面倒だし・・・」などやっぱり気になる弊害が出てきます。これが値になっているとバイナリファイルを見ても文字列として認識できませんし、構造体を作っても整数値として高速な比較ができるようになります。

 本章のHash32クラスは文字列に対応する32bit整数ハッシュ値を算出してくれるクラスです。CRC32ハッシュを用いています。使い方は極めて簡単です(^-^)


○ 定義

名前空間 ヘッダー
Dix DixHash32.h


○ 32bitハッシュクラスメンバメソッド

公開メンバメソッド 説明 使い方 備考
Hash32();
Hash32(const char* str)
Hash32(const char* str, unsigned len)
コンストラクタ Hash32 hash("This is a Test");
Hash32 hash2(memBlock, memBlock.size());
文字列を渡せるのはコンストラクタのみです。内部で32bit符号なし整数ハッシュ値が算出され格納されます。2つ目のコンストラクタは文字列以外の何らかのメモリブロックからハッシュ値を作るのに使用します。デフォルトコンストラクタは常にハッシュ値が0となります。
~Hash( void ) デストラクタ - -
unsigned get() const ハッシュ値を取得 Hash32 hash("Test");
unsigned val = hash.get()
ハッシュ値を取得します。


演算子 説明 使い方 備考
bool operator ==(const char *str) const
bool operator ==(const Hash32 &src) const
文字列と比較 Hash32 hash("Test")
if ( hash == "Test")
   printf("Same");
既存のハッシュ値と文字列から算出されるハッシュ値とを比較します。
bool operator <(const Hash32 &src) const
bool operator <(const char *str) const

bool operator >(const Hash32 &src) const
bool operator >(const char *str) const
文字列と比較 Hash32 hash("Test")
std::map<>if ( hash == "Test")
   printf("Same");
既存のハッシュ値と文字列から算出されるハッシュ値とを比較します。
operator unsigned() const ハッシュ値を取得 Hash32 hash("Test");
unsigned val = hash;
ハッシュ値を取得します。unsignedとして扱われます。


○ バージョンレポート

v1.00
・ 初出実装

v1.00 -> v1.01 (2011. 3. 31)
・ ハッシュ値計算時にCRC配列の参照オーバーランがあったバグを修正

v1.01 -> v1.02 (2011. 5. 6)
・ 整数値をハッシュ化する際に前回の文字数が参照されていたバグを修正

○ 使い方

#include <tchar.h>
#include <stdio.h>
#include "DixHash32.h"
#include <string.h>
#include <map>

const char str[] = "This is a pen. This pen is mine.";
const char miss_str[] = "This is a pen. This pen is mine!"; // 最後が[!]

int _tmain(int argc, _TCHAR* argv[])
{
    Dix::Hash32 hash(str);
    Dix::Hash32 miss_hash(miss_str);

    // 大小比較
    bool b_more_than = hash > miss_hash;
    bool b_less_than = hash < miss_hash;
    bool b_equal = hash == miss_hash;
    bool b_not_equal = hash != miss_hash;

    // 代入チェック
    Dix::Hash32 h = hash;
    Dix::Hash32 h2;
    h2 = miss_hash;

    // 値取得
    printf("%s = [%u]\n", str, hash.get());
    unsigned miss_val = miss_hash;
    printf("%s = [%u]\n", miss_str, miss_val);

    // 不正値チェック
    Dix::Hash32 eh(0); // NULL
    Dix::Hash32 eh2(0, 123); // NULLなのに長さ指定しちゃった


    std::map<Dix::Hash32, std::string> strMap;
    strMap.insert( std::pair<Dix::Hash32, std::string>(Dix::Hash32("Test1"), "Test1") );
    strMap.insert( std::pair<Dix::Hash32, std::string>(Dix::Hash32("Test2"), "Test2") );
    strMap.insert( std::pair<Dix::Hash32, std::string>(Dix::Hash32("Test3"), "Test3") );

    // 既存文字列検索
    std::map<Dix::Hash32, std::string>::iterator it = strMap.find( Dix::Hash32("Test2") );
    if ( it != strMap.end() )
        printf("文字列ありました\n");
    else
        printf("文字列なかったよ(クラスにバグがあるぜ)\n");

    std::map<Dix::Hash32, std::string>::iterator it2 = strMap.find( Dix::Hash32("Test7") );
    if ( it2 == strMap.end() )
        printf("文字列見つからなかったけど正解\n");
    else
        printf("文字列みつかっちゃった(クラスにバグがあるぜ)\n");

    return 0;
}