00001 /* -*- mode: C++; c-file-style: "stroustrup"; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ 00002 /********************************************************************* 00003 * 00004 * Filename : compute.h (hash) 00005 * C header. 00006 * 00007 * Functions to compute hash values. 00008 * 00009 * This file is a part of the UPPAAL toolkit. 00010 * Copyright (c) 1995 - 2003, Uppsala University and Aalborg University. 00011 * All right reserved. 00012 * 00013 * Not reviewed yet. 00014 * $Id: compute.h,v 1.6 2005/04/22 15:20:10 adavid Exp $ 00015 * 00016 **********************************************************************/ 00017 00018 #ifndef INCLUDE_HASH_COMPUTE_H 00019 #define INCLUDE_HASH_COMPUTE_H 00020 00021 #include <assert.h> 00022 #include <string.h> 00023 #include "base/inttypes.h" 00024 00025 #ifdef __cplusplus 00026 extern "C" { 00027 #endif 00028 00029 /** 00030 * Hash mix found at http://burtleburtle.net/bob/hash/ 00031 * Original comments from the author: 00032 * -------------------------------------------------------------------- 00033 * mix -- mix 3 32-bit values reversibly. 00034 * For every delta with one or two bit set, and the deltas of all three 00035 * high bits or all three low bits, whether the original value of a,b,c 00036 * is almost all zero or is uniformly distributed, 00037 * * If mix() is run forward or backward, at least 32 bits in a,b,c 00038 * have at least 1/4 probability of changing. 00039 * * If mix() is run forward, every bit of c will change between 1/3 and 00040 * 2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.) 00041 * mix() takes 36 machine instructions, but only 18 cycles on a superscalar 00042 * machine (like a Pentium or a Sparc). No faster mixer seems to work, 00043 * that's the result of my brute-force search. There were about 2^^68 00044 * hashes to choose from. I only tested about a billion of those. 00045 * -------------------------------------------------------------------- 00046 * NOTE: the hash function based on this hash mix is much faster than 00047 * MD5 hashing and gives exactly the same results. 00048 */ 00049 #define HASH_MIX(a,b,c) \ 00050 { \ 00051 a -= b; a -= c; a ^= (c>>13); \ 00052 b -= c; b -= a; b ^= (a<<8); \ 00053 c -= a; c -= b; c ^= (b>>13); \ 00054 a -= b; a -= c; a ^= (c>>12); \ 00055 b -= c; b -= a; b ^= (a<<16); \ 00056 c -= a; c -= b; c ^= (b>>5); \ 00057 a -= b; a -= c; a ^= (c>>3); \ 00058 b -= c; b -= a; b ^= (a<<10); \ 00059 c -= a; c -= b; c ^= (b>>15); \ 00060 } 00061 00062 /** Compute hash value for different data types. 00063 * @param data: data to read. 00064 * @param length: number of types to read 00065 * @param initval: used to initialize the hash computation. 00066 * initval is useful when computing a composite hash 00067 * involving different data types. It is then possible 00068 * to chain the hash computation. 00069 * @pre pointers are 32 bits aligned. 00070 * @return: hash value. 00071 * @note the following calls may not necessarily return 00072 * the same result: 00073 * hash_computeU32((uint32_t*)data, 32, initval) 00074 * hash_computeU16((uint16_t*)data, 64, initval) 00075 * hash_computeU8((uint8_t*)data, 128, initval) 00076 */ 00077 uint32_t hash_computeU32(const uint32_t *data, size_t length, uint32_t initval); 00078 uint32_t hash_computeU16(const uint16_t *data, size_t length, uint32_t initval); 00079 uint32_t hash_computeU8( const uint8_t *data, size_t length, uint32_t initval); 00080 00081 00082 /** Wrapper functions for convenience. 00083 * Wrap types of input data: support for 00084 * int32_t => uint32_t 00085 * int16_t => uint16_t 00086 * int8_t => uint8_t 00087 * char[] => uint8_t 00088 */ 00089 static inline 00090 uint32_t hash_computeI32(const int32_t *data, size_t length, uint32_t initval) 00091 { 00092 return hash_computeU32((uint32_t*)data, length, initval); 00093 } 00094 00095 static inline 00096 uint32_t hash_computeI16(const int16_t *data, size_t length, uint32_t initval) 00097 { 00098 return hash_computeU16((uint16_t*)data, length, initval); 00099 } 00100 00101 static inline 00102 uint32_t hash_computeI8(const int8_t *data, size_t length, uint32_t initval) 00103 { 00104 return hash_computeU8((uint8_t*)data, length, initval); 00105 } 00106 00107 static inline 00108 uint32_t hash_computeStr(const char *str, uint32_t initval) 00109 { 00110 assert(sizeof(char) == sizeof(uint8_t)); 00111 return hash_computeU8((uint8_t*)str, strlen(str), initval); 00112 } 00113 00114 /** Compute a new hash from 3 previous hash values. 00115 * @param a,b,c: values to combine. 00116 * @return a mixed hashed value. 00117 */ 00118 static inline 00119 uint32_t hash_compute(uint32_t a, uint32_t b, uint32_t c) 00120 { 00121 HASH_MIX(a, b, c); 00122 return c; 00123 } 00124 00125 #ifdef __cplusplus 00126 } 00127 #endif 00128 00129 #endif // INCLUDE_HASH_COMPUTE_H