2 * UCW Library -- Hyper-super-meta-alt-control-shift extra fast
3 * str_len() and hash_*() routines
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>
10 * This software may be freely distributed and used according to the terms
11 * of the GNU Lesser General Public License.
15 #include "lib/hashfunc.h"
16 #include "lib/chartype.h"
18 /* The number of bits the hash in the function hash_*() is rotated by after
19 * every pass. It should be prime with the word size. */
22 /* A bit-mask which clears higher bytes than a given threshold. */
23 static uns mask_higher_bits[sizeof(uns)];
25 static void CONSTRUCTOR
30 for (i=0; i<sizeof(uns); i++)
32 str = (byte *) (mask_higher_bits + i);
35 for (j=i; j<sizeof(uns); j++)
40 static inline uns CONST
43 const uns sub = ~0U / 0xff;
44 const uns and = sub * 0x80;
47 a = ~x & (x - sub) & and;
49 * x_2 = x - 0x01010101;
51 * a = x_3 & 0x80808080;
53 * If all bytes of x are nonzero, then the highest bit of each byte of
54 * x_2 is lower or equal to the corresponding bit of x. Hence x_3 has
55 * all these highest bits cleared (the target bit is set iff the source
56 * bit has changed from 0 to 1). If a == 0, then we are sure there is
62 for (i=0; i<sizeof(uns) && bytes[i]; i++);
67 str_len_aligned(const byte *str)
69 const uns *u = (const uns *) str;
73 uns l = str_len_uns(*u++);
81 hash_string_aligned(const byte *str)
83 const uns *u = (const uns *) str;
87 uns last_len = str_len_uns(*u);
88 hash = ROL(hash, SHIFT_BITS);
89 if (last_len < sizeof(uns))
91 uns tmp = *u & mask_higher_bits[last_len];
100 hash_block_aligned(const byte *str, uns len)
102 const uns *u = (const uns *) str;
104 while (len >= sizeof(uns))
106 hash = ROL(hash, SHIFT_BITS) ^ *u++;
109 hash = ROL(hash, SHIFT_BITS) ^ (*u & mask_higher_bits[len]);
113 #ifndef CPU_ALLOW_UNALIGNED
115 str_len(const byte *str)
117 uns shift = UNALIGNED_PART(str, uns);
119 return str_len_aligned(str);
123 shift = sizeof(uns) - shift;
124 for (i=0; i<shift; i++)
127 return shift + str_len_aligned(str + shift);
132 hash_string(const byte *str)
134 uns shift = UNALIGNED_PART(str, uns);
136 return hash_string_aligned(str);
143 uns modulo = i % sizeof(uns);
145 #ifdef CPU_LITTLE_ENDIAN
148 shift = sizeof(uns) - 1 - modulo;
151 hash = ROL(hash, SHIFT_BITS);
154 hash ^= str[i] << (shift * 8);
161 hash_block(const byte *str, uns len)
163 uns shift = UNALIGNED_PART(str, uns);
165 return hash_block_aligned(str, len);
172 uns modulo = i % sizeof(uns);
174 #ifdef CPU_LITTLE_ENDIAN
177 shift = sizeof(uns) - 1 - modulo;
180 hash = ROL(hash, SHIFT_BITS);
183 hash ^= str[i] << (shift * 8);
191 hash_string_nocase(const byte *str)
197 uns modulo = i % sizeof(uns);
199 #ifdef CPU_LITTLE_ENDIAN
202 shift = sizeof(uns) - 1 - modulo;
205 hash = ROL(hash, SHIFT_BITS);
208 hash ^= Cupcase(str[i]) << (shift * 8);