2 * Hyper-super-meta-alt-control-shift extra fast str_len() and hash_*()
5 * It is always at least as fast as the classical strlen() routine and for
6 * strings longer than 100 characters, it is substantially faster.
8 * (c) 2002, Robert Spalek <robert@ucw.cz>
12 #include "lib/hashfunc.h"
13 #include "lib/chartype.h"
15 /* The number of bits the hash in the function hash_*() is rotated by after
16 * every pass. It should be prime with the word size. */
19 /* A bit-mask which clears higher bytes than a given threshold. */
20 static uns mask_higher_bits[sizeof(uns)];
22 static void CONSTRUCTOR
27 for (i=0; i<sizeof(uns); i++)
29 str = (byte *) (mask_higher_bits + i);
32 for (j=i; j<sizeof(uns); j++)
37 static inline uns CONST
40 const uns sub = ~0U / 0xff;
41 const uns and = sub * 0x80;
44 a = ~x & (x - sub) & and;
46 * x_2 = x - 0x01010101;
48 * a = x_3 & 0x80808080;
50 * If all bytes of x are nonzero, then the highest bit of each byte of
51 * x_2 is lower or equal to the corresponding bit of x. Hence x_3 has
52 * all these highest bits cleared (the target bit is set iff the source
53 * bit has changed from 0 to 1). If a == 0, then we are sure there is
59 for (i=0; i<sizeof(uns) && bytes[i]; i++);
64 str_len_aligned(const byte *str)
66 const uns *u = (const uns *) str;
70 uns l = str_len_uns(*u++);
78 hash_string_aligned(const byte *str)
80 const uns *u = (const uns *) str;
84 uns last_len = str_len_uns(*u);
85 hash = ROL(hash, SHIFT_BITS);
86 if (last_len < sizeof(uns))
88 uns tmp = *u & mask_higher_bits[last_len];
97 hash_block_aligned(const byte *str, uns len)
99 const uns *u = (const uns *) str;
101 while (len >= sizeof(uns))
103 hash = ROL(hash, SHIFT_BITS) ^ *u++;
106 hash = ROL(hash, SHIFT_BITS) ^ (*u & mask_higher_bits[len]);
110 #ifndef CPU_ALLOW_UNALIGNED
112 str_len(const byte *str)
114 uns shift = UNALIGNED_PART(str, uns);
116 return str_len_aligned(str);
120 shift = sizeof(uns) - shift;
121 for (i=0; i<shift; i++)
124 return shift + str_len_aligned(str + shift);
129 hash_string(const byte *str)
131 uns shift = UNALIGNED_PART(str, uns);
133 return hash_string_aligned(str);
140 uns modulo = i % sizeof(uns);
142 #ifdef CPU_LITTLE_ENDIAN
145 shift = sizeof(uns) - 1 - modulo;
148 hash = ROL(hash, SHIFT_BITS);
151 hash ^= str[i] << (shift * 8);
158 hash_block(const byte *str, uns len)
160 uns shift = UNALIGNED_PART(str, uns);
162 return hash_block_aligned(str, len);
169 uns modulo = i % sizeof(uns);
171 #ifdef CPU_LITTLE_ENDIAN
174 shift = sizeof(uns) - 1 - modulo;
177 hash = ROL(hash, SHIFT_BITS);
180 hash ^= str[i] << (shift * 8);
188 hash_string_nocase(const byte *str)
194 uns modulo = i % sizeof(uns);
196 #ifdef CPU_LITTLE_ENDIAN
199 shift = sizeof(uns) - 1 - modulo;
202 hash = ROL(hash, SHIFT_BITS);
205 hash ^= Cupcase(str[i]) << (shift * 8);