目次
前言
Jenkins hash
大端小端
rot 宏
mix 宏
final 宏
hash 算法
murmur3 hash
Additive Hash
Rotating Hash
One-at-a-Time Hash
Bernstein hash
Goulburn Hash
Murmur Hash
Pearson Hash
CRC Hashing
Generalized CRC Hashing
Zobrist Hashing
ホームページ データベース mysql チュートリアル memcached 源码阅读之 字符串 hash 与 搜集的一些 字符串 hash

memcached 源码阅读之 字符串 hash 与 搜集的一些 字符串 hash

Jun 07, 2016 pm 04:41 PM
hash memcached ソースコード 読む

前言 在 memcached 源码阅读之 hash table文章的最后我说了,要研究一下 memcached 的 字符串 hash 方法的。 现在就开始记录下研究的结果。 Jenkins hash jenkins 的位置在 jenkins_hash.c . 大端小端 Little-Endian就是低位字节排放在内存的低地址端,高位

cover

前言

在 memcached 源码阅读之 hash table文章的最后我说了,要研究一下 memcached 的 字符串 hash 方法的。
现在就开始记录下研究的结果。

Jenkins hash

jenkins 的位置在 jenkins_hash.c .

大端小端

Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
举一个例子,比如数字0x12 34 56 78在内存中的表示形式为:

1)大端模式:  
低地址 -----------------> 高地址  
0x12  |  0x34  |  0x56  |  0x78  
2)小端模式:  
低地址 ------------------> 高地址  
0x78  |  0x56  |  0x34  |  0x12  
ログイン後にコピー
#if ENDIAN_BIG == 1
# define HASH_LITTLE_ENDIAN 0
# define HASH_BIG_ENDIAN 1
#else
# if ENDIAN_LITTLE == 1
#  define HASH_LITTLE_ENDIAN 1
#  define HASH_BIG_ENDIAN 0
# else
#  define HASH_LITTLE_ENDIAN 0
#  define HASH_BIG_ENDIAN 0
# endif
#endif
ログイン後にコピー

rot 宏

看到的第一个是 rot 宏。
这个宏的作用是循环左移若干位。

#define rot(x,k) (((x)<<(k)) ^ ((x)>>(32-(k))))
ログイン後にコピー

mix 宏

一个可逆的加密。
This is reversible, so any information in (a,b,c) before mix() is still in (a,b,c) after mix().

#define mix(a,b,c) \
{ \
  a -= c;  a ^= rot(c, 4);  c += b; \
  b -= a;  b ^= rot(a, 6);  a += c; \
  c -= b;  c ^= rot(b, 8);  b += a; \
  a -= c;  a ^= rot(c,16);  c += b; \
  b -= a;  b ^= rot(a,19);  a += c; \
  c -= b;  c ^= rot(b, 4);  b += a; \
}
ログイン後にコピー

final 宏

final mixing of 3 32-bit values (a,b,c) into c
将 a,b,c 合并到 c中。

#define final(a,b,c) \
{ \
  c ^= b; c -= rot(b,14); \
  a ^= c; a -= rot(c,11); \
  b ^= a; b -= rot(a,25); \
  c ^= b; c -= rot(b,16); \
  a ^= c; a -= rot(c,4);  \
  b ^= a; b -= rot(a,14); \
  c ^= b; c -= rot(b,24); \
}
ログイン後にコピー

hash 算法

源代码中大端小端,而且还分是 0x3 还是 0x1,这个目前就不知道干什么了。

uint32_t jenkins_hash( const void *key, size_t length) {
    uint32_t a,b,c;
    a = b = c = 0xdeadbeef + ((uint32_t)length) + 0;
    const char *k = (const char *)key;
    while (length > 12) {
        a += ((uint32_t)k[0])<<24;
        a += ((uint32_t)k[1])<<16;
        a += ((uint32_t)k[2])<<8;
        a += ((uint32_t)k[3]);
        b += ((uint32_t)k[4])<<24;
        b += ((uint32_t)k[5])<<16;
        b += ((uint32_t)k[6])<<8;
        b += ((uint32_t)k[7]);
        c += ((uint32_t)k[8])<<24;
        c += ((uint32_t)k[9])<<16;
        c += ((uint32_t)k[10])<<8;
        c += ((uint32_t)k[11]);
        mix(a,b,c);
        length -= 12;
        k += 12;
    }
    switch(length) {
    case 12:
        c+=k[11];
    case 11:
        c+=((uint32_t)k[10])<<8;
    case 10:
        c+=((uint32_t)k[9])<<16;
    case 9 :
        c+=((uint32_t)k[8])<<24;
    case 8 :
        b+=k[7];
    case 7 :
        b+=((uint32_t)k[6])<<8;
    case 6 :
        b+=((uint32_t)k[5])<<16;
    case 5 :
        b+=((uint32_t)k[4])<<24;
    case 4 :
        a+=k[3];
    case 3 :
        a+=((uint32_t)k[2])<<8;
    case 2 :
        a+=((uint32_t)k[1])<<16;
    case 1 :
        a+=((uint32_t)k[0])<<24;
        break;
    case 0 :
        return c;
    }
    final(a,b,c);
    return c;
}
ログイン後にコピー

看完这个代码,我们可以给他缩短一下。

uint32_t jenkins_hash( const void *key, size_t length) {
    uint32_t a,b,c;
    a = b = c = 0xdeadbeef + ((uint32_t)length) + 0;
    const char *k = (const char *)key;
    while (length >= 12) {
        a += *((uint32_t*)(k+0));
        b += *((uint32_t*)(k+4));
        c += *((uint32_t*)(k+8));
        mix(a,b,c);
        length -= 12;
        k += 12;
    }
    if(length == 0) {
        return c;
    }
    switch(length) {
        case 11:
            c+=((uint32_t)k[10])<<8;
        case 10:
            c+=((uint32_t)k[9])<<16;
        case 9 :
            c+=((uint32_t)k[8])<<24;
        case 8 :
            b += *((uint32_t*)(k+4));
            a += *((uint32_t*)(k+0));
            break;
        case 7 :
            b+=((uint32_t)k[6])<<8;
        case 6 :
            b+=((uint32_t)k[5])<<16;
        case 5 :
            b+=((uint32_t)k[4])<<24;
        case 4 :
            a += *((uint32_t*)(k+0));
            break;
        case 3 :
            a+=((uint32_t)k[2])<<8;
        case 2 :
            a+=((uint32_t)k[1])<<16;
        case 1 :
            a+=((uint32_t)k[0])<<24;
    }
    final(a,b,c);
    return c;
}
ログイン後にコピー

murmur3 hash

murmur3 hash 的位置在 murmur3_hash.c .

//不检查数据越界问题,主要用于得到一些随机数字
#define    FORCE_INLINE inline __attribute__((always_inline))
//循环左移
static inline uint32_t ROTL32 ( uint32_t x, int8_t r ) {
    return (x << r) | (x >> (32 - r));
}
//得到指针p位置的值,i可能为负数
static FORCE_INLINE uint32_t getblock32 ( const uint32_t * p, int i ) {
    return p[i];
}
static FORCE_INLINE uint32_t fmix32 ( uint32_t h ) {
    h ^= h >> 16;
    h *= 0x85ebca6b;
    h ^= h >> 13;
    h *= 0xc2b2ae35;
    h ^= h >> 16;
    return h;
}
uint32_t MurmurHash3_x86_32 ( const void * key, size_t length) {
    const uint8_t * data = (const uint8_t*)key;
    const int nblocks = length / 4;
    uint32_t h1 = 0;
    uint32_t c1 = 0xcc9e2d51;
    uint32_t c2 = 0x1b873593;
    const uint32_t * blocks = (const uint32_t *)(data + nblocks*4);
    for(int i = -nblocks; i; i++) {
        uint32_t k1 = getblock32(blocks,i);
        k1 *= c1;
        k1 = ROTL32(k1,15);
        k1 *= c2;
        h1 ^= k1;
        h1 = ROTL32(h1,13);
        h1 = h1*5+0xe6546b64;
    }
    const uint8_t * tail = (const uint8_t*)(data + nblocks*4);
    uint32_t k1 = 0;
    switch(length & 3) {
        case 3:
            k1 ^= tail[2] << 16;
        case 2:
            k1 ^= tail[1] << 8;
        case 1:
            k1 ^= tail[0];
            k1 *= c1;
            k1 = ROTL32(k1,15);
            k1 *= c2;
            h1 ^= k1;
    };
    h1 ^= length;
    h1 = fmix32(h1);
    return h1;
}
ログイン後にコピー

Additive Hash

ub4 additive(char *key, ub4 len, ub4 prime){
    ub4 hash, i;
    for (hash=len, i=0; i<len; ++i) 
        hash += key[i];
    return (hash % prime);
}
ログイン後にコピー

Rotating Hash

ub4 rotating(char *key, ub4 len, ub4 prime){
    ub4 hash, i;
    for (hash=len, i=0; i<len; ++i)
        hash = (hash<<4)^(hash>>28)^key[i];
    return (hash % prime);
}
ログイン後にコピー

One-at-a-Time Hash

ub4 one_at_a_time(char *key, ub4 len){
    ub4   hash, i;
    for (hash=0, i=0; i<len; ++i){
        hash += key[i];
        hash += (hash << 10);
        hash ^= (hash >> 6);
    }
    hash += (hash << 3);
    hash ^= (hash >> 11);
    hash += (hash << 15);
    return (hash & mask);
}
ログイン後にコピー

Bernstein hash

ub4 bernstein(ub1 *key, ub4 len, ub4 level){
    ub4 hash = level;
    ub4 i;
    for (i=0; i<len; ++i) hash = 33*hash + key[i];
    return hash;
}
ログイン後にコピー

Goulburn Hash

u4 goulburn( const unsigned char *cp, size_t len, uint32_t last_value){
    register u4 h = last_value;
    int u;
    for( u=0; u<len; ++u ) {
        h += g_table0[ cp[u] ];
        h ^= (h << 3) ^ (h >> 29);
        h += g_table1[ h >> 25 ];
        h ^= (h << 14) ^ (h >> 18);
        h += 1783936964UL;
    }
    return h;
}
ログイン後にコピー

Murmur Hash

uint32_t MurmurHash1 ( const void * key, int len, uint32_t seed ){ const unsigned int m = 0xc6a4a793;

const int r = 16;
unsigned int h = seed ^ (len * m);
//----------
const unsigned char * data = (const unsigned char *)key;
while(len >= 4){
    unsigned int k = *(unsigned int *)data;
    h += k;
    h *= m;
    h ^= h >> 16;
    data += 4;
    len -= 4;
}
//----------
switch(len){
    case 3:
    h += data[2] << 16;
    case 2:
    h += data[1] << 8;
    case 1:
    h += data[0];
    h *= m;
    h ^= h >> r;
};
//----------
h *= m;
h ^= h >> 10;
h *= m;
h ^= h >> 17;
return h;
ログイン後にコピー

}

Pearson Hash

//This preinitializes tab[] to an arbitrary permutation of 0 .. 255.
char pearson(char *key, ub4 len, char tab[256]){
    char hash;
    ub4  i;
    for (hash=len, i=0; i<len; ++i) 
        hash=tab[hash^key[i]];
    return (hash);
}
ログイン後にコピー

CRC Hashing

ub4 crc(char *key, ub4 len, ub4 mask, ub4 tab[256]){
    ub4 hash, i;
    for (hash=len, i=0; i<len; ++i)
        hash = (hash >> 8) ^ tab[(hash & 0xff) ^ key[i]];
    return (hash & mask);
}
ログイン後にコピー

Generalized CRC Hashing

//The size of tab[] is the maximum number of input bits. 
//Values in tab[] are chosen at random. 
ub4 universal(char *key, ub4 len, ub4 mask, ub4 tab[MAXBITS]){
    ub4 hash, i;
    for (hash=len, i=0; i<(len<<3); i+=8){
        register char k = key[i>>3];
        if (k&0x01) hash ^= tab[i+0];
        if (k&0x02) hash ^= tab[i+1];
        if (k&0x04) hash ^= tab[i+2];
        if (k&0x08) hash ^= tab[i+3];
        if (k&0x10) hash ^= tab[i+4];
        if (k&0x20) hash ^= tab[i+5];
        if (k&0x40) hash ^= tab[i+6];
        if (k&0x80) hash ^= tab[i+7];
    }
    return (hash & mask);
}
ログイン後にコピー

Zobrist Hashing

ub4 zobrist( char *key, ub4 len, ub4 mask, ub4 tab[MAXBYTES][256]){
    ub4 hash, i;
    for (hash=len, i=0; i<len; ++i)
        hash ^= tab[i][key[i]];
    return (hash & mask);
}
ログイン後にコピー
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

PHPでint型をstringに変換する方法を詳しく解説 PHPでint型をstringに変換する方法を詳しく解説 Mar 26, 2024 am 11:45 AM

PHPでint型をstring型に変換する方法を詳しく解説 PHPの開発では、int型をstring型に変換する必要に遭遇することがよくあります。この変換はさまざまな方法で実現できますが、この記事では、読者の理解を深めるために、具体的なコード例とともに、いくつかの一般的な方法を詳しく紹介します。 1. PHP の組み込み関数 strval() を使用する PHP には、さまざまな型の変数を文字列型に変換できる組み込み関数 strval() が用意されています。 int型をstring型に変換する必要がある場合、

イマーシブ リーダーで Microsoft Reader Coach を使用する方法 イマーシブ リーダーで Microsoft Reader Coach を使用する方法 Mar 09, 2024 am 09:34 AM

この記事では、Windows PC のイマーシブ リーダーで Microsoft Reading Coach を使用する方法を説明します。読書指導機能は、生徒や個人が読書を練習し、読み書き能力を伸ばすのに役立ちます。サポートされているアプリケーションで文章や文書を読むことから始めます。これに基づいて、Reading Coach ツールによって読書レポートが生成されます。読書レポートには、読書の正確さ、読むのにかかった時間、1分あたりの正解単語数、読書中に最も難しいと感じた単語が表示されます。単語を練習することもできるので、一般的な読解力の向上にも役立ちます。現在、Office または Microsoft365 (OneNote for Web および Word for We を含む) のみ

Golang で文字列が特定の文字で始まるかどうかを確認するにはどうすればよいですか? Golang で文字列が特定の文字で始まるかどうかを確認するにはどうすればよいですか? Mar 12, 2024 pm 09:42 PM

Golang で文字列が特定の文字で始まるかどうかを確認するにはどうすればよいですか? Golang でプログラミングする場合、文字列が特定の文字で始まるかどうかを確認する必要がある状況によく遭遇します。この要件を満たすために、Golang の strings パッケージによって提供される関数を使用してこれを実現できます。次に、Golangを使って文字列が特定の文字で始まるかどうかを確認する方法を、具体的なコード例とともに詳しく紹介します。 Golang では、strings パッケージの HasPrefix を使用できます。

Golang 文字列が指定された文字で終わるかどうかを判断する方法 Golang 文字列が指定された文字で終わるかどうかを判断する方法 Mar 12, 2024 pm 04:48 PM

タイトル: Golang で文字列が特定の文字で終わるかどうかを判断する方法 Go 言語では、文字列が特定の文字で終わるかどうかを判断する必要があることがあります。これは文字列を処理するときに非常に一般的です。この記事では、Go 言語を使用してこの関数を実装する方法と、参考用のコード例を紹介します。まず、Golang で文字列が指定された文字で終わるかどうかを判断する方法を見てみましょう。 Golang の文字列内の文字はインデックス作成によって取得でき、文字列の長さは次のようになります。

python_python の繰り返し文字列チュートリアルで文字列を繰り返す方法 python_python の繰り返し文字列チュートリアルで文字列を繰り返す方法 Apr 02, 2024 pm 03:58 PM

1. まず pycharm を開いて、pycharm ホームページに入ります。 2. 次に、新しい Python スクリプトを作成し、右クリックして [新規] をクリックし、[Pythonfile] をクリックします。 3. 文字列、コード: s="-" を入力します。 4. 次に、文字列内のシンボルを 20 回繰り返す必要があります (コード: s1=s*20)。 5. 印刷出力コード、コード: print(s1) を入力します。 6. 最後にスクリプトを実行すると、下部に戻り値が表示されます。 - 20 回繰り返しました。

PHPで16進数を文字列に変換するときに中国語が文字化けする問題を解決する方法 PHPで16進数を文字列に変換するときに中国語が文字化けする問題を解決する方法 Mar 04, 2024 am 09:36 AM

PHP で 16 進数の文字列を変換するときに中国語の文字化けを解決する方法. PHP プログラミングでは、16 進数で表された文字列を通常の中国語の文字に変換する必要がある状況に遭遇することがあります。しかし、この変換の過程で、場合によっては中国語の文字化けが発生することがあります。この記事では、PHPで16進数を文字列に変換する際に中国語が文字化けする問題を解決する方法と、具体的なコード例を紹介します。 16 進数の変換には hex2bin() 関数を使用します。PHP の組み込み hex2bin() 関数は 1 を変換できます

PHP 文字列マッチングのヒント: あいまいな組み込み式を避ける PHP 文字列マッチングのヒント: あいまいな組み込み式を避ける Feb 29, 2024 am 08:06 AM

PHP 文字列マッチングのヒント: あいまいな組み込み式を避ける PHP 開発では、文字列マッチングは一般的なタスクであり、通常は特定のテキスト コンテンツを検索したり、入力形式を検証したりするために使用されます。ただし、一致の精度を確保するために、曖昧な包含式の使用を避ける必要がある場合があります。この記事では、PHP で文字列マッチングを行うときにあいまいな包含式を回避するためのテクニックをいくつか紹介し、具体的なコード例を示します。完全一致には preg_match() 関数を使用します。 PHP では、preg_mat を使用できます。

PHP 文字列操作: スペースを効果的に削除する実用的な方法 PHP 文字列操作: スペースを効果的に削除する実用的な方法 Mar 24, 2024 am 11:45 AM

PHP 文字列操作: スペースを効果的に削除する実用的な方法 PHP 開発では、文字列からスペースを削除する必要がある状況によく遭遇します。スペースを削除すると文字列がきれいになり、その後のデータ処理と表示が容易になります。この記事では、スペースを削除するための効果的かつ実践的な方法をいくつか紹介し、具体的なコード例を添付します。方法1: PHP組み込み関数trim()を使用する PHP組み込み関数trim()を使用すると、文字列の両端のスペース(スペース、タブ、改行などを含む)を削除でき、非常に便利で簡単です。使用します。

See all articles