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 <ucw/hashfunc.h>
16 #include <ucw/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 char *str)
69 const uns *u = (const uns *) str;
73 uns l = str_len_uns(*u++);
81 hash_string_aligned(const char *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 *buf, uns len)
102 const uns *u = (const uns *) buf;
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 char *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 char *str)
135 uns shift = UNALIGNED_PART(s, uns);
137 return hash_string_aligned(s);
144 uns modulo = i % sizeof(uns);
146 #ifdef CPU_LITTLE_ENDIAN
149 shift = sizeof(uns) - 1 - modulo;
152 hash = ROL(hash, SHIFT_BITS);
155 hash ^= s[i] << (shift * 8);
162 hash_block(const byte *buf, uns len)
164 uns shift = UNALIGNED_PART(buf, uns);
166 return hash_block_aligned(buf, len);
173 uns modulo = i % sizeof(uns);
175 #ifdef CPU_LITTLE_ENDIAN
178 shift = sizeof(uns) - 1 - modulo;
181 hash = ROL(hash, SHIFT_BITS);
184 hash ^= buf[i] << (shift * 8);
192 hash_string_nocase(const char *str)
199 uns modulo = i % sizeof(uns);
201 #ifdef CPU_LITTLE_ENDIAN
204 shift = sizeof(uns) - 1 - modulo;
207 hash = ROL(hash, SHIFT_BITS);
210 hash ^= Cupcase(s[i]) << (shift * 8);