public class SimpleHash { public static string ComputeHash(string plainText, string hashAlgorithm, byte[] saltBytes) { // If salt is not specified, generate it on the fly. if (saltBytes == null) { // Define min and max salt sizes. int minSaltSize = 4; int maxSaltSize = 8; // Generate a random number for the size of the salt. Random random = new Random(); int saltSize = random.Next(minSaltSize, maxSaltSize); // Allocate a byte array, which will hold the salt. saltBytes = new byte[saltSize]; // Initialize a random number generator. RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); // Fill the salt with cryptographically strong byte values. rng.GetNonZeroBytes(saltBytes); }
// Convert plain text into a byte array. byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
// Allocate array, which will hold plain text and salt. byte[] plainTextWithSaltBytes = new byte[plainTextBytes.Length + saltBytes.Length]; // Copy plain text bytes into resulting array. for (int i=0; i < plainTextBytes.Length; i++) plainTextWithSaltBytes[i] = plainTextBytes[i];
// Append salt bytes to the resulting array. for (int i=0; i < saltBytes.Length; i++) plainTextWithSaltBytes[plainTextBytes.Length + i] = saltBytes[i]; // Because we support multiple hashing algorithms, we must define // hash object as a common (abstract) base class. We will specify the // actual hashing algorithm class later during object creation. HashAlgorithm hash;
// Make sure hashing algorithm name is specified. if (hashAlgorithm == null) hashAlgorithm = "";
// Initialize appropriate hashing algorithm class. switch (hashAlgorithm.ToUpper()) { case "SHA1": hash = new SHA1Managed(); break; case "SHA256": hash = new SHA256Managed(); break; case "SHA384": hash = new SHA384Managed(); break; case "SHA512": hash = new SHA512Managed(); break; default: hash = new MD5CryptoServiceProvider(); break; }
// Compute hash value of our plain text with appended salt. byte[] hashBytes = hash.ComputeHash(plainTextWithSaltBytes);
// Create array which will hold hash and original salt bytes. byte[] hashWithSaltBytes = new byte[hashBytes.Length + saltBytes.Length];
// Copy hash bytes into resulting array. for (int i=0; i < hashBytes.Length; i++) hashWithSaltBytes[i] = hashBytes[i];
// Append salt bytes to the result. for (int i=0; i < saltBytes.Length; i++) hashWithSaltBytes[hashBytes.Length + i] = saltBytes[i];
// Convert result into a base64-encoded string. string hashValue = Convert.ToBase64String(hashWithSaltBytes);
// Return the result. return hashValue; } public static bool VerifyHash(string plainText, string hashAlgorithm, string hashValue) { // Convert base64-encoded hash value into a byte array. byte[] hashWithSaltBytes = Convert.FromBase64String(hashValue);
// We must know size of hash (without salt). int hashSizeInBits, hashSizeInBytes;
// Make sure that hashing algorithm name is specified. if (hashAlgorithm == null) hashAlgorithm = "";
// Size of hash is based on the specified algorithm. switch (hashAlgorithm.ToUpper()) { case "SHA1": hashSizeInBits = 160; break; case "SHA256": hashSizeInBits = 256; break; case "SHA384": hashSizeInBits = 384; break; case "SHA512": hashSizeInBits = 512; break; default: // Must be MD5 hashSizeInBits = 128; break; } // Convert size of hash from bits to bytes. hashSizeInBytes = hashSizeInBits / 8; // Make sure that the specified hash value is long enough. if (hashWithSaltBytes.Length < hashSizeInBytes) return false; // Allocate array to hold original salt bytes retrieved from hash. byte[] saltBytes = new byte[hashWithSaltBytes.Length - hashSizeInBytes]; // Copy salt from the end of the hash to the new array. for (int i=0; i < saltBytes.Length; i++) saltBytes[i] = hashWithSaltBytes[hashSizeInBytes + i]; // Compute a new hash string. string expectedHashString = ComputeHash(plainText, hashAlgorithm, saltBytes); // If the computed hash matches the specified hash, // the plain text value must be correct. return (hashValue == expectedHashString); } }
return (hash & 0x7FFFFFFF); } /**//* End Of JS Hash Function */
/**//** * PJW算法 */ public static int PJWHash(String str) { int BitsInUnsignedInt = 32; int ThreeQuarters = (BitsInUnsignedInt * 3) / 4; int OneEighth = BitsInUnsignedInt / 8; int HighBits = 0xFFFFFFFF << (BitsInUnsignedInt - OneEighth); int hash = 0; int test = 0;
for(int i = 0; i < str.length();i++) { hash = (hash << OneEighth) + str.charAt(i);
// return (hash & 0x7FFFFFFF); return hash; } /**//* End Of AP Hash Function */
/**//** * JAVA自己带的算法 */ public static int java(String str) { int h = 0; int off = 0; int len = str.length(); for (int i = 0; i < len; i++) { h = 31 * h + str.charAt(off++); } return h; }
/**//** * 混合hash算法,输出64位的值 */ public static long mixHash(String str) { long hash = str.hashCode(); hash <<= 32; hash |= FNVHash1(str); return hash; } }
.CPP的代码 /* Copyright 2000-2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * split from apache for general usage by Yankee * use system malloc instead of apr_pool ,although it is not so effiecient but suitable for small * scale usage. *///#include "apr_private.h"//#include "apr_general.h" //#include "apr_pools.h"#include "hash_modify.h"//#if APR_HAVE_STDLIB_H #include <stdlib.h> //#endif //#if APR_HAVE_STRING_H #include <string.h> //#endif /* * The internal form of a hash table. * * The table is an array indexed by the hash of the key; collisions * are resolved by hanging a linked list of hash entries off each * element of the array. Although this is a really simple design it * isn't too bad given that pools have a low allocation overhead. */typedef struct apr_hash_entry_t apr_hash_entry_t;struct apr_hash_entry_t { apr_hash_entry_t *next; unsigned int hash; const void *key; apr_ssize_t klen; const void *val; };/* * Data structure for iterating through a hash table. * * We keep a pointer to the next hash entry here to allow the current * hash entry to be freed or otherwise mangled between calls to * apr_hash_next(). */ struct apr_hash_index_t { apr_hash_t *ht; apr_hash_entry_t *this, *next; unsigned int index; };/* * The size of the array is always a power of two. We use the maximum * index rather than the size so that we can use bitwise-AND for * modular arithmetic. * The count of hash entries may be greater depending on the chosen * collision rate. */ struct apr_hash_t { apr_pool_t *pool; apr_hash_entry_t **array; apr_hash_index_t iterator; /* For apr_hash_first(NULL, ...) */ unsigned int count, max; };#define INITIAL_MAX 15 /* tunable == 2^n - 1 */ /* * Hash creation functions. */static apr_hash_entry_t **alloc_array(apr_hash_t *ht, unsigned int max) { return malloc(ht->pool, sizeof(*ht->array) * (max + 1)); }apr_hash_t * apr_hash_make(void) { apr_hash_t *ht; ht =malloc(pool, sizeof(apr_hash_t)); ht->pool = pool; ht->count = 0; ht->max = INITIAL_MAX; ht->array = alloc_array(ht, ht->max); return ht; } /* * Hash iteration functions. */apr_hash_index_t * apr_hash_next(apr_hash_index_t *hi) { hi->this = hi->next; while (!hi->this) { if (hi->index > hi->ht->max) return NULL; hi->this = hi->ht->array[hi->index++]; } hi->next = hi->this->next; return hi; }apr_hash_index_t * apr_hash_first(apr_pool_t *p, apr_hash_t *ht) { apr_hash_index_t *hi; if (p) hi = malloc(p, sizeof(*hi)); else hi = &ht->iterator; hi->ht = ht; hi->index = 0; hi->this = NULL; hi->next = NULL; return apr_hash_next(hi); }void apr_hash_this(apr_hash_index_t *hi, const void **key, apr_ssize_t *klen, void **val) { if (key) *key = hi->this->key; if (klen) *klen = hi->this->klen; if (val) *val = (void *)hi->this->val; } /* * Expanding a hash table */static void expand_array(apr_hash_t *ht) { apr_hash_index_t *hi; apr_hash_entry_t **new_array; unsigned int new_max; new_max = ht->max * 2 + 1; new_array = alloc_array(ht, new_max); for (hi = apr_hash_first(NULL, ht); hi; hi = apr_hash_next(hi)) { unsigned int i = hi->this->hash & new_max; hi->this->next = new_array[i]; new_array[i] = hi->this; } ht->array = new_array; ht->max = new_max; }
/* * This is where we keep the details of the hash function and control * the maximum collision rate. * * If val is non-NULL it creates and initializes a new hash entry if * there isn't already one there; it returns an updatable pointer so * that hash entries can be removed. */static apr_hash_entry_t **find_entry(apr_hash_t *ht, const void *key, apr_ssize_t klen, const void *val) { apr_hash_entry_t **hep, *he; const unsigned char *p; unsigned int hash; apr_ssize_t i; /* * This is the popular `times 33' hash algorithm which is used by * perl and also appears in Berkeley DB. This is one of the best * known hash functions for strings because it is both computed * very fast and distributes very well. * * The originator may be Dan Bernstein but the code in Berkeley DB * cites Chris Torek as the source. The best citation I have found * is "Chris Torek, Hash function for text in C, Usenet message * <[email protected]> in comp.lang.c , October, 1990." in Rich * Salz's USENIX 1992 paper about INN which can be found at * <http://citeseer.nj.nec.com/salz92internetnews.html>. * * The magic of number 33, i.e. why it works better than many other * constants, prime or not, has never been adequately explained by * anyone. So I try an explanation: if one experimentally tests all * multipliers between 1 and 256 (as I did while writing a low-level * data structure library some time ago) one detects that even * numbers are not useable at all. The remaining 128 odd numbers * (except for the number 1) work more or less all equally well. * They all distribute in an acceptable way and this way fill a hash * table with an average percent of approx. 86%. * * If one compares the chi^2 values of the variants (see * Bob Jenkins ``Hashing Frequently Asked Questions'' at * http://burtleburtle.net/bob/hash/hashfaq.html for a description * of chi^2), the number 33 not even has the best value. But the * number 33 and a few other equally good numbers like 17, 31, 63, * 127 and 129 have nevertheless a great advantage to the remaining * numbers in the large set of possible multipliers: their multiply * operation can be replaced by a faster operation based on just one * shift plus either a single addition or subtraction operation. And * because a hash function has to both distribute good _and_ has to * be very fast to compute, those few numbers should be preferred. * * -- Ralf S. Engelschall <[email protected]> */ hash = 0; if (klen == APR_HASH_KEY_STRING) { for (p = key; *p; p++) { hash = hash * 33 + *p; } klen = p - (const unsigned char *)key; } else { for (p = key, i = klen; i; i--, p++) { hash = hash * 33 + *p; } } /* scan linked list */ //???? for (hep = &ht->array[hash & ht->max], he = *hep; he; hep = &he->next, he = *hep) { if (he->hash == hash && he->klen == klen && memcmp(he->key, key, klen) == 0) break; } if (he || !val) return hep; /* add a new entry for non-NULL values */ he = malloc(ht->pool, sizeof(*he)); he->next = NULL; he->hash = hash; he->key = key; he->klen = klen; he->val = val; *hep = he; ht->count++; return hep; }apr_hash_t * apr_hash_copy(apr_pool_t *pool, const apr_hash_t *orig) { apr_hash_t *ht; apr_hash_entry_t *new_vals; unsigned int i, j; ht = apr_palloc(pool, sizeof(apr_hash_t) + sizeof(*ht->array) * (orig->max + 1) + sizeof(apr_hash_entry_t) * orig->count); ht->pool = pool; ht->count = orig->count; ht->max = orig->max; ht->array = (apr_hash_entry_t **)((char *)ht + sizeof(apr_hash_t)); new_vals = (apr_hash_entry_t *)((char *)(ht) + sizeof(apr_hash_t) + sizeof(*ht->array) * (orig->max + 1)); j = 0; for (i = 0; i <= ht->max; i++) { apr_hash_entry_t **new_entry = &(ht->array[i]); apr_hash_entry_t *orig_entry = orig->array[i]; while (orig_entry) { *new_entry = &new_vals[j++]; (*new_entry)->hash = orig_entry->hash; (*new_entry)->key = orig_entry->key; (*new_entry)->klen = orig_entry->klen; (*new_entry)->val = orig_entry->val; new_entry = &((*new_entry)->next); orig_entry = orig_entry->next; } *new_entry = NULL; } return ht; }
.h的文件/* Copyright 2000-2004 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */#ifndef APR_HASH_H #define APR_HASH_H/** * @file apr_hash.h * @brief APR Hash Tables */#ifdef __cplusplus extern "C" { #endif/** * @defgroup apr_hash Hash Tables * @ingroup APR * @{ *//** * When passing a key to apr_hash_set or apr_hash_get, this value can be * passed to indicate a string-valued key, and have apr_hash compute the * length automatically. * * @re apr_hash will use strlen(key) for the length. The null-terminator * is not included in the hash value (why throw a constant in?). * Since the hash table merely references the provided key (rather * than copying it), apr_hash_this() will return the null-term'd key. */ #define APR_HASH_KEY_STRING (-1)/** * Abstract type for hash tables. */ typedef struct apr_hash_t apr_hash_t;/** * Abstract type for scanning hash tables. */ typedef struct apr_hash_index_t apr_hash_index_t;/** * Create a hash table. * @param pool The pool to allocate the hash table out of * @return The hash table just created */ pr_hash_t * apr_hash_make(apr_pool_t *pool);/** * Make a copy of a hash table * @param pool The pool from which to allocate the new hash table * @param h The hash table to clone * @return The hash table just created * @re Makes a shallow copy */ apr_hash_t * apr_hash_copy(apr_pool_t *pool, const apr_hash_t *h);/** * Associate a value with a key in a hash table. * @param ht The hash table * @param key Pointer to the key * @param klen Length of the key. Can be APR_HASH_KEY_STRING to use the string length. * @param val Value to associate with the key * @re If the value is NULL the hash entry is deleted. */ void apr_hash_set(apr_hash_t *ht, const void *key, apr_ssize_t klen, const void *val);/** * Look up the value associated with a key in a hash table. * @param ht The hash table * @param key Pointer to the key * @param klen Length of the key. Can be APR_HASH_KEY_STRING to use the string length. * @return Returns NULL if the key is not present. */ void * apr_hash_get(apr_hash_t *ht, const void *key, apr_ssize_t klen);
/** * Start iterating over the entries in a hash table. * @param p The pool to allocate the apr_hash_index_t iterator. If this * pool is NULL, then an internal, non-thread-safe iterator is used. * @param ht The hash table * @re There is no restriction on adding or deleting hash entries during * an iteration (although the results may be unpredictable unless all you do * is delete the current entry) and multiple iterations can be in * progress at the same time. * @example */ /** * <PRE> * * int sum_values(apr_pool_t *p, apr_hash_t *ht) * { * apr_hash_index_t *hi; * void *val; * int sum = 0; * for (hi = apr_hash_first(p, ht); hi; hi = apr_hash_next(hi)) { * apr_hash_this(hi, NULL, NULL, &val); * sum += *(int *)val; * } * return sum; * } * </PRE> */ apr_hash_index_t * apr_hash_first(apr_pool_t *p, apr_hash_t *ht);/** * Continue iterating over the entries in a hash table. * @param hi The iteration state * @return a pointer to the updated iteration state. NULL if there are no more * entries. */ apr_hash_index_t * apr_hash_next(apr_hash_index_t *hi);/** * Get the current entry's details from the iteration state. * @param hi The iteration state * @param key Return pointer for the pointer to the key. * @param klen Return pointer for the key length. * @param val Return pointer for the associated value. * @re The return pointers should point to a variable that will be set to the * corresponding data, or they may be NULL if the data isn't interesting. */ void apr_hash_this(apr_hash_index_t *hi, const void **key, apr_ssize_t *klen, void **val);/** * Get the number of key/value pairs in the hash table. * @param ht The hash table * @return The number of key/value pairs in the hash table. */ unsigned int apr_hash_count(apr_hash_t *ht);/** * Merge two hash tables into one new hash table. The values of the overlay * hash override the values of the base if both have the same key. * @param p The pool to use for the new hash table * @param overlay The table to add to the initial table * @param base The table that represents the initial values of the new table * @return A new hash table containing all of the data from the two passed in */ apr_hash_t * apr_hash_overlay(apr_pool_t *p, const apr_hash_t *overlay, const apr_hash_t *base);/** * Merge two hash tables into one new hash table. If the same key * is present in both tables, call the supplied merge function to * produce a merged value for the key in the new table. * @param p The pool to use for the new hash table * @param h1 The first of the tables to merge * @param h2 The second of the tables to merge * @param merger A callback function to merge values, or NULL to * make values from h1 override values from h2 (same semantics as * apr_hash_overlay()) * @param data Client data to pass to the merger function * @return A new hash table containing all of the data from the two passed in */ apr_hash_t *apr_hash_merge(apr_pool_t *p, const apr_hash_t *h1, const apr_hash_t *h2, void * (*merger)(apr_pool_t *p, const void *key, apr_ssize_t klen, const void *h1_val, const void *h2_val, const void *data), const void *data);/** @} */#ifdef __cplusplus } #endif#endif /* !APR_HASH_H */
{
public static string ComputeHash(string plainText,
string hashAlgorithm,
byte[] saltBytes)
{
// If salt is not specified, generate it on the fly.
if (saltBytes == null)
{
// Define min and max salt sizes.
int minSaltSize = 4;
int maxSaltSize = 8; // Generate a random number for the size of the salt.
Random random = new Random();
int saltSize = random.Next(minSaltSize, maxSaltSize); // Allocate a byte array, which will hold the salt.
saltBytes = new byte[saltSize]; // Initialize a random number generator.
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); // Fill the salt with cryptographically strong byte values.
rng.GetNonZeroBytes(saltBytes);
}
// Convert plain text into a byte array.
byte[] plainTextBytes = Encoding.UTF8.GetBytes(plainText);
// Allocate array, which will hold plain text and salt.
byte[] plainTextWithSaltBytes =
new byte[plainTextBytes.Length + saltBytes.Length]; // Copy plain text bytes into resulting array.
for (int i=0; i < plainTextBytes.Length; i++)
plainTextWithSaltBytes[i] = plainTextBytes[i];
// Append salt bytes to the resulting array.
for (int i=0; i < saltBytes.Length; i++)
plainTextWithSaltBytes[plainTextBytes.Length + i] = saltBytes[i]; // Because we support multiple hashing algorithms, we must define
// hash object as a common (abstract) base class. We will specify the
// actual hashing algorithm class later during object creation.
HashAlgorithm hash;
// Make sure hashing algorithm name is specified.
if (hashAlgorithm == null)
hashAlgorithm = "";
// Initialize appropriate hashing algorithm class.
switch (hashAlgorithm.ToUpper())
{
case "SHA1":
hash = new SHA1Managed();
break; case "SHA256":
hash = new SHA256Managed();
break; case "SHA384":
hash = new SHA384Managed();
break; case "SHA512":
hash = new SHA512Managed();
break; default:
hash = new MD5CryptoServiceProvider();
break;
}
// Compute hash value of our plain text with appended salt.
byte[] hashBytes = hash.ComputeHash(plainTextWithSaltBytes);
// Create array which will hold hash and original salt bytes.
byte[] hashWithSaltBytes = new byte[hashBytes.Length +
saltBytes.Length];
// Copy hash bytes into resulting array.
for (int i=0; i < hashBytes.Length; i++)
hashWithSaltBytes[i] = hashBytes[i];
// Append salt bytes to the result.
for (int i=0; i < saltBytes.Length; i++)
hashWithSaltBytes[hashBytes.Length + i] = saltBytes[i];
// Convert result into a base64-encoded string.
string hashValue = Convert.ToBase64String(hashWithSaltBytes);
// Return the result.
return hashValue;
}
public static bool VerifyHash(string plainText,
string hashAlgorithm,
string hashValue)
{
// Convert base64-encoded hash value into a byte array.
byte[] hashWithSaltBytes = Convert.FromBase64String(hashValue);
// We must know size of hash (without salt).
int hashSizeInBits, hashSizeInBytes;
// Make sure that hashing algorithm name is specified.
if (hashAlgorithm == null)
hashAlgorithm = "";
// Size of hash is based on the specified algorithm.
switch (hashAlgorithm.ToUpper())
{
case "SHA1":
hashSizeInBits = 160;
break; case "SHA256":
hashSizeInBits = 256;
break; case "SHA384":
hashSizeInBits = 384;
break; case "SHA512":
hashSizeInBits = 512;
break; default: // Must be MD5
hashSizeInBits = 128;
break;
} // Convert size of hash from bits to bytes.
hashSizeInBytes = hashSizeInBits / 8; // Make sure that the specified hash value is long enough.
if (hashWithSaltBytes.Length < hashSizeInBytes)
return false; // Allocate array to hold original salt bytes retrieved from hash.
byte[] saltBytes = new byte[hashWithSaltBytes.Length -
hashSizeInBytes]; // Copy salt from the end of the hash to the new array.
for (int i=0; i < saltBytes.Length; i++)
saltBytes[i] = hashWithSaltBytes[hashSizeInBytes + i]; // Compute a new hash string.
string expectedHashString =
ComputeHash(plainText, hashAlgorithm, saltBytes); // If the computed hash matches the specified hash,
// the plain text value must be correct.
return (hashValue == expectedHashString);
}
}
http://www.microsoft.com/downloads/details.aspx?FamilyID=8c09fd61-3f26-4555-ae17-3121b4f51d4d&displaylang=en
http://forums.techpowerup.com/showthread.php?t=62293
* Hash算法大全<br>
* 推荐使用FNV1算法
* @algorithm None
* @author Goodzzp 2006-11-20
* @lastEdit Goodzzp 2006-11-20
* @editDetail Create
*/
public class HashAlgorithms
{
/**//**
* 加法hash
* @param key 字符串
* @param prime 一个质数
* @return hash结果
*/
public static int additiveHash(String key, int prime)
{
int hash, i;
for (hash = key.length(), i = 0; i < key.length(); i++)
hash += key.charAt(i);
return (hash % prime);
}
/**//**
* 旋转hash
* @param key 输入字符串
* @param prime 质数
* @return hash值
*/
public static int rotatingHash(String key, int prime)
{
int hash, i;
for (hash=key.length(), i=0; i<key.length(); ++i)
hash = (hash<<4)^(hash>>28)^key.charAt(i);
return (hash % prime);
// return (hash ^ (hash>>10) ^ (hash>>20));
}
// 替代:
// 使用:hash = (hash ^ (hash>>10) ^ (hash>>20)) & mask;
// 替代:hash %= prime; /**//**
* MASK值,随便找一个值,最好是质数
*/
static int M_MASK = 0x8765fed1;
/**//**
* 一次一个hash
* @param key 输入字符串
* @return 输出hash值
*/
public static int oneByOneHash(String key)
{
int hash, i;
for (hash=0, i=0; i<key.length(); ++i)
{
hash += key.charAt(i);
hash += (hash << 10);
hash ^= (hash >> 6);
}
hash += (hash << 3);
hash ^= (hash >> 11);
hash += (hash << 15);
// return (hash & M_MASK);
return hash;
}
/**//**
* Bernstein's hash
* @param key 输入字节数组
* @param level 初始hash常量
* @return 结果hash
*/
public static int bernstein(String key)
{
int hash = 0;
int i;
for (i=0; i<key.length(); ++i) hash = 33*hash + key.charAt(i);
return hash;
}
//
/**///// Pearson's Hash
// 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,计算crc,具体代码见其他
// 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);
// }
/**//**
* Universal Hashing
*/
public static int universal(char[]key, int mask, int[] tab)
{
int hash = key.length, i, len = key.length;
for (i=0; i<(len<<3); i+=8)
{
char k = key[i>>3];
if ((k&0x01) == 0) hash ^= tab[i+0];
if ((k&0x02) == 0) hash ^= tab[i+1];
if ((k&0x04) == 0) hash ^= tab[i+2];
if ((k&0x08) == 0) hash ^= tab[i+3];
if ((k&0x10) == 0) hash ^= tab[i+4];
if ((k&0x20) == 0) hash ^= tab[i+5];
if ((k&0x40) == 0) hash ^= tab[i+6];
if ((k&0x80) == 0) hash ^= tab[i+7];
}
return (hash & mask);
}
/**//**
* Zobrist Hashing
*/
public static int zobrist( char[] key,int mask, int[][] tab)
{
int hash, i;
for (hash=key.length, i=0; i<key.length; ++i)
hash ^= tab[i][key[i]];
return (hash & mask);
}
// LOOKUP3
// 见Bob Jenkins(3).c文件
// 32位FNV算法
static int M_SHIFT = 0;
/**//**
* 32位的FNV算法
* @param data 数组
* @return int值
*/
public static int FNVHash(byte[] data)
{
int hash = (int)2166136261L;
for(byte b : data)
hash = (hash * 16777619) ^ b;
if (M_SHIFT == 0)
return hash;
return (hash ^ (hash >> M_SHIFT)) & M_MASK;
}
/**//**
* 改进的32位FNV算法1
* @param data 数组
* @return int值
*/
public static int FNVHash1(byte[] data)
{
final int p = 16777619;
int hash = (int)2166136261L;
for(byte b:data)
hash = (hash ^ b) * p;
hash += hash << 13;
hash ^= hash >> 7;
hash += hash << 3;
hash ^= hash >> 17;
hash += hash << 5;
return hash;
}
* 改进的32位FNV算法1
* @param data 字符串
* @return int值
*/
public static int FNVHash1(String data)
{
final int p = 16777619;
int hash = (int)2166136261L;
for(int i=0;i<data.length();i++)
hash = (hash ^ data.charAt(i)) * p;
hash += hash << 13;
hash ^= hash >> 7;
hash += hash << 3;
hash ^= hash >> 17;
hash += hash << 5;
return hash;
}
/**//**
* Thomas Wang的算法,整数hash
*/
public static int intHash(int key)
{
key += ~(key << 15);
key ^= (key >>> 10);
key += (key << 3);
key ^= (key >>> 6);
key += ~(key << 11);
key ^= (key >>> 16);
return key;
}
/**//**
* RS算法hash
* @param str 字符串
*/
public static int RSHash(String str)
{
int b = 378551;
int a = 63689;
int hash = 0;
for(int i = 0; i < str.length(); i++)
{
hash = hash * a + str.charAt(i);
a = a * b;
}
return (hash & 0x7FFFFFFF);
}
/**//* End Of RS Hash Function */
/**//**
* JS算法
*/
public static int JSHash(String str)
{
int hash = 1315423911;
for(int i = 0; i < str.length(); i++)
{
hash ^= ((hash << 5) + str.charAt(i) + (hash >> 2));
}
return (hash & 0x7FFFFFFF);
}
/**//* End Of JS Hash Function */
/**//**
* PJW算法
*/
public static int PJWHash(String str)
{
int BitsInUnsignedInt = 32;
int ThreeQuarters = (BitsInUnsignedInt * 3) / 4;
int OneEighth = BitsInUnsignedInt / 8;
int HighBits = 0xFFFFFFFF << (BitsInUnsignedInt - OneEighth);
int hash = 0;
int test = 0;
for(int i = 0; i < str.length();i++)
{
hash = (hash << OneEighth) + str.charAt(i);
if((test = hash & HighBits) != 0)
{
hash = (( hash ^ (test >> ThreeQuarters)) & (~HighBits));
}
}
return (hash & 0x7FFFFFFF);
}
/**//* End Of P. J. Weinberger Hash Function */
/**//**
* ELF算法
*/
public static int ELFHash(String str)
{
int hash = 0;
int x = 0;
for(int i = 0; i < str.length(); i++)
{
hash = (hash << 4) + str.charAt(i);
if((x = (int)(hash & 0xF0000000L)) != 0)
{
hash ^= (x >> 24);
hash &= ~x;
}
}
return (hash & 0x7FFFFFFF);
}
/**//* End Of ELF Hash Function */
/**//**
* BKDR算法
*/
public static int BKDRHash(String str)
{
int seed = 131; // 31 131 1313 13131 131313 etc..
int hash = 0;
for(int i = 0; i < str.length(); i++)
{
hash = (hash * seed) + str.charAt(i);
}
return (hash & 0x7FFFFFFF);
}
/**//* End Of BKDR Hash Function */
/**//**
* SDBM算法
*/
public static int SDBMHash(String str)
{
int hash = 0;
for(int i = 0; i < str.length(); i++)
{
hash = str.charAt(i) + (hash << 6) + (hash << 16) - hash;
}
return (hash & 0x7FFFFFFF);
}
/**//* End Of SDBM Hash Function */
/**//**
* DJB算法
*/
public static int DJBHash(String str)
{
int hash = 5381;
for(int i = 0; i < str.length(); i++)
{
hash = ((hash << 5) + hash) + str.charAt(i);
}
return (hash & 0x7FFFFFFF);
}
/**//* End Of DJB Hash Function */
/**//**
* DEK算法
*/
public static int DEKHash(String str)
{
int hash = str.length();
for(int i = 0; i < str.length(); i++)
{
hash = ((hash << 5) ^ (hash >> 27)) ^ str.charAt(i);
}
return (hash & 0x7FFFFFFF);
}
/**//* End Of DEK Hash Function */
/**//**
* AP算法
*/
public static int APHash(String str)
{
int hash = 0;
for(int i = 0; i < str.length(); i++)
{
hash ^= ((i & 1) == 0) ? ( (hash << 7) ^ str.charAt(i) ^ (hash >> 3)) :
(~((hash << 11) ^ str.charAt(i) ^ (hash >> 5)));
}
// return (hash & 0x7FFFFFFF);
return hash;
}
/**//* End Of AP Hash Function */
/**//**
* JAVA自己带的算法
*/
public static int java(String str)
{
int h = 0;
int off = 0;
int len = str.length();
for (int i = 0; i < len; i++)
{
h = 31 * h + str.charAt(off++);
}
return h;
}
/**//**
* 混合hash算法,输出64位的值
*/
public static long mixHash(String str)
{
long hash = str.hashCode();
hash <<= 32;
hash |= FNVHash1(str);
return hash;
}
}
/* Copyright 2000-2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License. * split from apache for general usage by Yankee
* use system malloc instead of apr_pool ,although it is not so effiecient but suitable for small
* scale usage.
*///#include "apr_private.h"//#include "apr_general.h"
//#include "apr_pools.h"#include "hash_modify.h"//#if APR_HAVE_STDLIB_H
#include <stdlib.h>
//#endif
//#if APR_HAVE_STRING_H
#include <string.h>
//#endif
/*
* The internal form of a hash table.
*
* The table is an array indexed by the hash of the key; collisions
* are resolved by hanging a linked list of hash entries off each
* element of the array. Although this is a really simple design it
* isn't too bad given that pools have a low allocation overhead.
*/typedef struct apr_hash_entry_t apr_hash_entry_t;struct apr_hash_entry_t {
apr_hash_entry_t *next;
unsigned int hash;
const void *key;
apr_ssize_t klen;
const void *val;
};/*
* Data structure for iterating through a hash table.
*
* We keep a pointer to the next hash entry here to allow the current
* hash entry to be freed or otherwise mangled between calls to
* apr_hash_next().
*/
struct apr_hash_index_t {
apr_hash_t *ht;
apr_hash_entry_t *this, *next;
unsigned int index;
};/*
* The size of the array is always a power of two. We use the maximum
* index rather than the size so that we can use bitwise-AND for
* modular arithmetic.
* The count of hash entries may be greater depending on the chosen
* collision rate.
*/
struct apr_hash_t {
apr_pool_t *pool;
apr_hash_entry_t **array;
apr_hash_index_t iterator; /* For apr_hash_first(NULL, ...) */
unsigned int count, max;
};#define INITIAL_MAX 15 /* tunable == 2^n - 1 */
/*
* Hash creation functions.
*/static apr_hash_entry_t **alloc_array(apr_hash_t *ht, unsigned int max)
{
return malloc(ht->pool, sizeof(*ht->array) * (max + 1));
}apr_hash_t * apr_hash_make(void)
{
apr_hash_t *ht;
ht =malloc(pool, sizeof(apr_hash_t));
ht->pool = pool;
ht->count = 0;
ht->max = INITIAL_MAX;
ht->array = alloc_array(ht, ht->max);
return ht;
}
/*
* Hash iteration functions.
*/apr_hash_index_t * apr_hash_next(apr_hash_index_t *hi)
{
hi->this = hi->next;
while (!hi->this) {
if (hi->index > hi->ht->max)
return NULL; hi->this = hi->ht->array[hi->index++];
}
hi->next = hi->this->next;
return hi;
}apr_hash_index_t * apr_hash_first(apr_pool_t *p, apr_hash_t *ht)
{
apr_hash_index_t *hi;
if (p)
hi = malloc(p, sizeof(*hi));
else
hi = &ht->iterator; hi->ht = ht;
hi->index = 0;
hi->this = NULL;
hi->next = NULL;
return apr_hash_next(hi);
}void apr_hash_this(apr_hash_index_t *hi,
const void **key,
apr_ssize_t *klen,
void **val)
{
if (key) *key = hi->this->key;
if (klen) *klen = hi->this->klen;
if (val) *val = (void *)hi->this->val;
}
/*
* Expanding a hash table
*/static void expand_array(apr_hash_t *ht)
{
apr_hash_index_t *hi;
apr_hash_entry_t **new_array;
unsigned int new_max; new_max = ht->max * 2 + 1;
new_array = alloc_array(ht, new_max);
for (hi = apr_hash_first(NULL, ht); hi; hi = apr_hash_next(hi)) {
unsigned int i = hi->this->hash & new_max;
hi->this->next = new_array[i];
new_array[i] = hi->this;
}
ht->array = new_array;
ht->max = new_max;
}
* This is where we keep the details of the hash function and control
* the maximum collision rate.
*
* If val is non-NULL it creates and initializes a new hash entry if
* there isn't already one there; it returns an updatable pointer so
* that hash entries can be removed.
*/static apr_hash_entry_t **find_entry(apr_hash_t *ht,
const void *key,
apr_ssize_t klen,
const void *val)
{
apr_hash_entry_t **hep, *he;
const unsigned char *p;
unsigned int hash;
apr_ssize_t i; /*
* This is the popular `times 33' hash algorithm which is used by
* perl and also appears in Berkeley DB. This is one of the best
* known hash functions for strings because it is both computed
* very fast and distributes very well.
*
* The originator may be Dan Bernstein but the code in Berkeley DB
* cites Chris Torek as the source. The best citation I have found
* is "Chris Torek, Hash function for text in C, Usenet message
* <[email protected]> in comp.lang.c , October, 1990." in Rich
* Salz's USENIX 1992 paper about INN which can be found at
* <http://citeseer.nj.nec.com/salz92internetnews.html>.
*
* The magic of number 33, i.e. why it works better than many other
* constants, prime or not, has never been adequately explained by
* anyone. So I try an explanation: if one experimentally tests all
* multipliers between 1 and 256 (as I did while writing a low-level
* data structure library some time ago) one detects that even
* numbers are not useable at all. The remaining 128 odd numbers
* (except for the number 1) work more or less all equally well.
* They all distribute in an acceptable way and this way fill a hash
* table with an average percent of approx. 86%.
*
* If one compares the chi^2 values of the variants (see
* Bob Jenkins ``Hashing Frequently Asked Questions'' at
* http://burtleburtle.net/bob/hash/hashfaq.html for a description
* of chi^2), the number 33 not even has the best value. But the
* number 33 and a few other equally good numbers like 17, 31, 63,
* 127 and 129 have nevertheless a great advantage to the remaining
* numbers in the large set of possible multipliers: their multiply
* operation can be replaced by a faster operation based on just one
* shift plus either a single addition or subtraction operation. And
* because a hash function has to both distribute good _and_ has to
* be very fast to compute, those few numbers should be preferred.
*
* -- Ralf S. Engelschall <[email protected]>
*/
hash = 0;
if (klen == APR_HASH_KEY_STRING) {
for (p = key; *p; p++) {
hash = hash * 33 + *p;
}
klen = p - (const unsigned char *)key;
}
else {
for (p = key, i = klen; i; i--, p++) {
hash = hash * 33 + *p;
}
} /* scan linked list */
//????
for (hep = &ht->array[hash & ht->max], he = *hep;
he; hep = &he->next, he = *hep) {
if (he->hash == hash
&& he->klen == klen
&& memcmp(he->key, key, klen) == 0)
break;
}
if (he || !val)
return hep; /* add a new entry for non-NULL values */
he = malloc(ht->pool, sizeof(*he));
he->next = NULL;
he->hash = hash;
he->key = key;
he->klen = klen;
he->val = val;
*hep = he;
ht->count++;
return hep;
}apr_hash_t * apr_hash_copy(apr_pool_t *pool,
const apr_hash_t *orig)
{
apr_hash_t *ht;
apr_hash_entry_t *new_vals;
unsigned int i, j; ht = apr_palloc(pool, sizeof(apr_hash_t) +
sizeof(*ht->array) * (orig->max + 1) +
sizeof(apr_hash_entry_t) * orig->count);
ht->pool = pool;
ht->count = orig->count;
ht->max = orig->max;
ht->array = (apr_hash_entry_t **)((char *)ht + sizeof(apr_hash_t)); new_vals = (apr_hash_entry_t *)((char *)(ht) + sizeof(apr_hash_t) +
sizeof(*ht->array) * (orig->max + 1));
j = 0;
for (i = 0; i <= ht->max; i++) {
apr_hash_entry_t **new_entry = &(ht->array[i]);
apr_hash_entry_t *orig_entry = orig->array[i];
while (orig_entry) {
*new_entry = &new_vals[j++];
(*new_entry)->hash = orig_entry->hash;
(*new_entry)->key = orig_entry->key;
(*new_entry)->klen = orig_entry->klen;
(*new_entry)->val = orig_entry->val;
new_entry = &((*new_entry)->next);
orig_entry = orig_entry->next;
}
*new_entry = NULL;
}
return ht;
}
const void *key,
apr_ssize_t klen)
{
apr_hash_entry_t *he;
he = *find_entry(ht, key, klen, NULL);
if (he)
return (void *)he->val;
else
return NULL;
}void apr_hash_set(apr_hash_t *ht,
const void *key,
apr_ssize_t klen,
const void *val)
{
apr_hash_entry_t **hep;
hep = find_entry(ht, key, klen, val);
if (*hep) {
if (!val) {
/* delete entry */
*hep = (*hep)->next;
--ht->count;
}
else {
/* replace entry */
(*hep)->val = val;
/* check that the collision rate isn't too high */
if (ht->count > ht->max) {
expand_array(ht);
}
}
}
/* else key not present and val==NULL */
}unsigned intapr_hash_count(apr_hash_t *ht)
{
return ht->count;
}apr_hash_t* apr_hash_overlay(apr_pool_t *p,
const apr_hash_t *overlay,
const apr_hash_t *base)
{
return apr_hash_merge(p, overlay, base, NULL, NULL);
}apr_hash_t *apr_hash_merge(apr_pool_t *p,
const apr_hash_t *overlay,
const apr_hash_t *base,
void * (*merger)(apr_pool_t *p,
const void *key,
apr_ssize_t klen,
const void *h1_val,
const void *h2_val,
const void *data),
const void *data)
{
apr_hash_t *res;
apr_hash_entry_t *new_vals = NULL;
apr_hash_entry_t *iter;
apr_hash_entry_t *ent;
unsigned int i,j,k;
res = malloc(p, sizeof(apr_hash_t));
res->pool = p;
res->count = base->count;
res->max = (overlay->max > base->max) ? overlay->max : base->max;
if (base->count + overlay->count > res->max) {
res->max = res->max * 2 + 1;
}
res->array = alloc_array(res, res->max);
if (base->count + overlay->count) {
new_vals = malloc(p, sizeof(apr_hash_entry_t) *
(base->count + overlay->count));
}
j = 0;
for (k = 0; k <= base->max; k++) {
for (iter = base->array[k]; iter; iter = iter->next) {
i = iter->hash & res->max;
new_vals[j].klen = iter->klen;
new_vals[j].key = iter->key;
new_vals[j].val = iter->val;
new_vals[j].hash = iter->hash;
new_vals[j].next = res->array[i];
res->array[i] = &new_vals[j];
j++;
}
} for (k = 0; k <= overlay->max; k++) {
for (iter = overlay->array[k]; iter; iter = iter->next) {
i = iter->hash & res->max;
for (ent = res->array[i]; ent; ent = ent->next) {
if ((ent->klen == iter->klen) &&
(memcmp(ent->key, iter->key, iter->klen) == 0)) {
if (merger) {
ent->val = (*merger)(p, iter->key, iter->klen,
iter->val, ent->val, data);
}
else {
ent->val = iter->val;
}
break;
}
}
if (!ent) {
new_vals[j].klen = iter->klen;
new_vals[j].key = iter->key;
new_vals[j].val = iter->val;
new_vals[j].hash = iter->hash;
new_vals[j].next = res->array[i];
res->array[i] = &new_vals[j];
res->count++;
j++;
}
}
}
return res;
}
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/#ifndef APR_HASH_H
#define APR_HASH_H/**
* @file apr_hash.h
* @brief APR Hash Tables
*/#ifdef __cplusplus
extern "C" {
#endif/**
* @defgroup apr_hash Hash Tables
* @ingroup APR
* @{
*//**
* When passing a key to apr_hash_set or apr_hash_get, this value can be
* passed to indicate a string-valued key, and have apr_hash compute the
* length automatically.
*
* @re apr_hash will use strlen(key) for the length. The null-terminator
* is not included in the hash value (why throw a constant in?).
* Since the hash table merely references the provided key (rather
* than copying it), apr_hash_this() will return the null-term'd key.
*/
#define APR_HASH_KEY_STRING (-1)/**
* Abstract type for hash tables.
*/
typedef struct apr_hash_t apr_hash_t;/**
* Abstract type for scanning hash tables.
*/
typedef struct apr_hash_index_t apr_hash_index_t;/**
* Create a hash table.
* @param pool The pool to allocate the hash table out of
* @return The hash table just created
*/
pr_hash_t * apr_hash_make(apr_pool_t *pool);/**
* Make a copy of a hash table
* @param pool The pool from which to allocate the new hash table
* @param h The hash table to clone
* @return The hash table just created
* @re Makes a shallow copy
*/
apr_hash_t * apr_hash_copy(apr_pool_t *pool,
const apr_hash_t *h);/**
* Associate a value with a key in a hash table.
* @param ht The hash table
* @param key Pointer to the key
* @param klen Length of the key. Can be APR_HASH_KEY_STRING to use the string length.
* @param val Value to associate with the key
* @re If the value is NULL the hash entry is deleted.
*/
void apr_hash_set(apr_hash_t *ht, const void *key,
apr_ssize_t klen, const void *val);/**
* Look up the value associated with a key in a hash table.
* @param ht The hash table
* @param key Pointer to the key
* @param klen Length of the key. Can be APR_HASH_KEY_STRING to use the string length.
* @return Returns NULL if the key is not present.
*/
void * apr_hash_get(apr_hash_t *ht, const void *key,
apr_ssize_t klen);
* Start iterating over the entries in a hash table.
* @param p The pool to allocate the apr_hash_index_t iterator. If this
* pool is NULL, then an internal, non-thread-safe iterator is used.
* @param ht The hash table
* @re There is no restriction on adding or deleting hash entries during
* an iteration (although the results may be unpredictable unless all you do
* is delete the current entry) and multiple iterations can be in
* progress at the same time. * @example
*/
/**
* <PRE>
*
* int sum_values(apr_pool_t *p, apr_hash_t *ht)
* {
* apr_hash_index_t *hi;
* void *val;
* int sum = 0;
* for (hi = apr_hash_first(p, ht); hi; hi = apr_hash_next(hi)) {
* apr_hash_this(hi, NULL, NULL, &val);
* sum += *(int *)val;
* }
* return sum;
* }
* </PRE>
*/
apr_hash_index_t * apr_hash_first(apr_pool_t *p, apr_hash_t *ht);/**
* Continue iterating over the entries in a hash table.
* @param hi The iteration state
* @return a pointer to the updated iteration state. NULL if there are no more
* entries.
*/
apr_hash_index_t * apr_hash_next(apr_hash_index_t *hi);/**
* Get the current entry's details from the iteration state.
* @param hi The iteration state
* @param key Return pointer for the pointer to the key.
* @param klen Return pointer for the key length.
* @param val Return pointer for the associated value.
* @re The return pointers should point to a variable that will be set to the
* corresponding data, or they may be NULL if the data isn't interesting.
*/
void apr_hash_this(apr_hash_index_t *hi, const void **key,
apr_ssize_t *klen, void **val);/**
* Get the number of key/value pairs in the hash table.
* @param ht The hash table
* @return The number of key/value pairs in the hash table.
*/
unsigned int apr_hash_count(apr_hash_t *ht);/**
* Merge two hash tables into one new hash table. The values of the overlay
* hash override the values of the base if both have the same key.
* @param p The pool to use for the new hash table
* @param overlay The table to add to the initial table
* @param base The table that represents the initial values of the new table
* @return A new hash table containing all of the data from the two passed in
*/
apr_hash_t * apr_hash_overlay(apr_pool_t *p,
const apr_hash_t *overlay,
const apr_hash_t *base);/**
* Merge two hash tables into one new hash table. If the same key
* is present in both tables, call the supplied merge function to
* produce a merged value for the key in the new table.
* @param p The pool to use for the new hash table
* @param h1 The first of the tables to merge
* @param h2 The second of the tables to merge
* @param merger A callback function to merge values, or NULL to
* make values from h1 override values from h2 (same semantics as
* apr_hash_overlay())
* @param data Client data to pass to the merger function
* @return A new hash table containing all of the data from the two passed in
*/
apr_hash_t *apr_hash_merge(apr_pool_t *p,
const apr_hash_t *h1,
const apr_hash_t *h2,
void * (*merger)(apr_pool_t *p,
const void *key,
apr_ssize_t klen,
const void *h1_val,
const void *h2_val,
const void *data),
const void *data);/** @} */#ifdef __cplusplus
}
#endif#endif /* !APR_HASH_H */
计划使用FNVHash1算法来实现我的Hash