2011年6月4日土曜日

コンパイルタイム文字列ハッシュ化

こちらの記事に
http://d.hatena.ne.jp/yupo5656/20040613/p1
コンパイル時に文字列リテラルに指定のアルゴリズムによる計算を施し、整数に変換するには?
と言うのがあったので参考にしてみました。

template <std::size_t N> inline hash32 hashStringStatic(const char (&str)[N]) { return crc32(N-1, reinterpret_cast<const char (&)[N-1]>(str)); } template <std::size_t N> inline hash32 crc32(hash32 hash, const char (&str)[N]) { return crc32( (hash >> 8) ^ crctbl[(unsigned char)((hash & 0xff) ^ str[N-1])], reinterpret_cast<const char (&)[N-1]>(str) );< } template<> inline hash32 crc32<1>(hash32 hash, const char (&str)[1]) { return (hash >> 8) ^ crctbl[(unsigned char)((hash & 0xff) ^ str[0])]; } typedef unsigned int hash32; // ハッシュテーブル static const hash32 crctbl[256] = { 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
です。
crc32の処理を再帰テンプレートで展開するわけなのですが、最適化でたしかに直値になっているかんじでした。
このアルゴリズムの都合のいいところは、単純な再帰型に出来たので楽でした。
他のハッシュアルゴリズムは展開できるか知りません。

ちなみにコンパイルタイムではないものも用意してみました。
inline hash32 hashStringDynamic(const std::string str)
{
const std::size_t len = str.length();
hash32 hash = len;
for ( std::size_t i = 0; i < len; i++ )
{
// static版に揃えるためけつから求める
const std::size_t index = len-1-i;
hash = (hash >> 8) ^ crctab[(unsigned char)((hash & 0xff) ^ str[index])];
}
return hash;
}
そんでですね、

ソース内に
 hash32 hash = hashStringStatic("sh/bokenasu.fx");
とかやっとくと数字になって入ってるみたいな。
こいつをフライウエイトのキーに使えば見やすく処理も速いのかなと思ったのです。
ただこれはもちろんリテラル文字にしか使えないので使うときにはどうなるのかとても注意が必要です。ただ、これだと、オリジナルの文字列が失われるので実際にファイル名等の文字列が必要なときに困ります。
そこで

struct hashString
{
hashString(hash32 hash_, char* str_)
: hash(hash_)
, str(str_)
{}
const hash32 hash;
const char* str;
};
#define HashString(x) hashString(hashStringStatic(x), x)

っつーのを作ってみたのですが、どうですか?
instance func(hashString hash)
{
 auto ite = m_kMap.find(hash.hash);
 if(m_kMap.end()!=ite) return ite->second;
 m_kMap[hash.hash]=new instance(hash.str);
 return m_kMap[hash.hash];
}
instance = func(HashString("sh/bokenasubi.fx"));
みたいな事やれば良いんじゃないでしょうか?

つか本当にアセンブラレベルで直値になっているかが重要なんですけど、どうなんですかね?

ぶっちゃけ、アセットなんかは全部外部の定義ファイルに書いて読み込む事になるので、リテラル文字限定ってのはまあ使えないわけですが。。。
外部ファイルから読み込む場合は予めもっとシノニムの起きづらいmd5で文字列をハッシュ化したものを文字列とペアで記述しておけばいいですかね。


0 件のコメント:

コメントを投稿