|
Packit |
c04fcb |
#ifndef _LTTNG_HASH_HELPER_H
|
|
Packit |
c04fcb |
#define _LTTNG_HASH_HELPER_H
|
|
Packit |
c04fcb |
|
|
Packit |
c04fcb |
/*
|
|
Packit |
c04fcb |
* lttng-hash-helper.h
|
|
Packit |
c04fcb |
*
|
|
Packit |
c04fcb |
* LTTng hash table helpers.
|
|
Packit |
c04fcb |
*
|
|
Packit |
c04fcb |
* Copyright (C) 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
|
|
Packit |
c04fcb |
*
|
|
Packit |
c04fcb |
* This library is free software; you can redistribute it and/or
|
|
Packit |
c04fcb |
* modify it under the terms of the GNU Lesser General Public
|
|
Packit |
c04fcb |
* License as published by the Free Software Foundation; only
|
|
Packit |
c04fcb |
* version 2.1 of the License.
|
|
Packit |
c04fcb |
*
|
|
Packit |
c04fcb |
* This library is distributed in the hope that it will be useful,
|
|
Packit |
c04fcb |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
c04fcb |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
c04fcb |
* Lesser General Public License for more details.
|
|
Packit |
c04fcb |
*
|
|
Packit |
c04fcb |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit |
c04fcb |
* License along with this library; if not, write to the Free Software
|
|
Packit |
c04fcb |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
Packit |
c04fcb |
*/
|
|
Packit |
c04fcb |
|
|
Packit |
c04fcb |
#include <assert.h>
|
|
Packit |
c04fcb |
#include <stdint.h>
|
|
Packit |
c04fcb |
#include <urcu/compiler.h>
|
|
Packit |
c04fcb |
|
|
Packit |
c04fcb |
/*
|
|
Packit |
c04fcb |
* Hash function
|
|
Packit |
c04fcb |
* Source: http://burtleburtle.net/bob/c/lookup3.c
|
|
Packit |
c04fcb |
* Originally Public Domain
|
|
Packit |
c04fcb |
*/
|
|
Packit |
c04fcb |
|
|
Packit |
c04fcb |
#define rot(x, k) (((x) << (k)) | ((x) >> (32 - (k))))
|
|
Packit |
c04fcb |
|
|
Packit |
c04fcb |
#define mix(a, b, c) \
|
|
Packit |
c04fcb |
do { \
|
|
Packit |
c04fcb |
a -= c; a ^= rot(c, 4); c += b; \
|
|
Packit |
c04fcb |
b -= a; b ^= rot(a, 6); a += c; \
|
|
Packit |
c04fcb |
c -= b; c ^= rot(b, 8); b += a; \
|
|
Packit |
c04fcb |
a -= c; a ^= rot(c, 16); c += b; \
|
|
Packit |
c04fcb |
b -= a; b ^= rot(a, 19); a += c; \
|
|
Packit |
c04fcb |
c -= b; c ^= rot(b, 4); b += a; \
|
|
Packit |
c04fcb |
} while (0)
|
|
Packit |
c04fcb |
|
|
Packit |
c04fcb |
#define final(a, b, c) \
|
|
Packit |
c04fcb |
{ \
|
|
Packit |
c04fcb |
c ^= b; c -= rot(b, 14); \
|
|
Packit |
c04fcb |
a ^= c; a -= rot(c, 11); \
|
|
Packit |
c04fcb |
b ^= a; b -= rot(a, 25); \
|
|
Packit |
c04fcb |
c ^= b; c -= rot(b, 16); \
|
|
Packit |
c04fcb |
a ^= c; a -= rot(c, 4);\
|
|
Packit |
c04fcb |
b ^= a; b -= rot(a, 14); \
|
|
Packit |
c04fcb |
c ^= b; c -= rot(b, 24); \
|
|
Packit |
c04fcb |
}
|
|
Packit |
c04fcb |
|
|
Packit |
c04fcb |
static inline __attribute__((unused))
|
|
Packit |
c04fcb |
uint32_t lttng_hash_u32(
|
|
Packit |
c04fcb |
const uint32_t *k, /* the key, an array of uint32_t values */
|
|
Packit |
c04fcb |
size_t length, /* the length of the key, in uint32_ts */
|
|
Packit |
c04fcb |
uint32_t initval) /* the previous hash, or an arbitrary value */
|
|
Packit |
c04fcb |
{
|
|
Packit |
c04fcb |
uint32_t a, b, c;
|
|
Packit |
c04fcb |
|
|
Packit |
c04fcb |
/* Set up the internal state */
|
|
Packit |
c04fcb |
a = b = c = 0xdeadbeef + (((uint32_t) length) << 2) + initval;
|
|
Packit |
c04fcb |
|
|
Packit |
c04fcb |
/*----------------------------------------- handle most of the key */
|
|
Packit |
c04fcb |
while (length > 3) {
|
|
Packit |
c04fcb |
a += k[0];
|
|
Packit |
c04fcb |
b += k[1];
|
|
Packit |
c04fcb |
c += k[2];
|
|
Packit |
c04fcb |
mix(a, b, c);
|
|
Packit |
c04fcb |
length -= 3;
|
|
Packit |
c04fcb |
k += 3;
|
|
Packit |
c04fcb |
}
|
|
Packit |
c04fcb |
|
|
Packit |
c04fcb |
/*----------------------------------- handle the last 3 uint32_t's */
|
|
Packit |
c04fcb |
switch (length) { /* all the case statements fall through */
|
|
Packit |
c04fcb |
case 3: c += k[2];
|
|
Packit |
c04fcb |
case 2: b += k[1];
|
|
Packit |
c04fcb |
case 1: a += k[0];
|
|
Packit |
c04fcb |
final(a, b, c);
|
|
Packit |
c04fcb |
case 0: /* case 0: nothing left to add */
|
|
Packit |
c04fcb |
break;
|
|
Packit |
c04fcb |
}
|
|
Packit |
c04fcb |
/*---------------------------------------------- report the result */
|
|
Packit |
c04fcb |
return c;
|
|
Packit |
c04fcb |
}
|
|
Packit |
c04fcb |
|
|
Packit |
c04fcb |
static inline
|
|
Packit |
c04fcb |
void lttng_hashword2(
|
|
Packit |
c04fcb |
const uint32_t *k, /* the key, an array of uint32_t values */
|
|
Packit |
c04fcb |
size_t length, /* the length of the key, in uint32_ts */
|
|
Packit |
c04fcb |
uint32_t *pc, /* IN: seed OUT: primary hash value */
|
|
Packit |
c04fcb |
uint32_t *pb) /* IN: more seed OUT: secondary hash value */
|
|
Packit |
c04fcb |
{
|
|
Packit |
c04fcb |
uint32_t a, b, c;
|
|
Packit |
c04fcb |
|
|
Packit |
c04fcb |
/* Set up the internal state */
|
|
Packit |
c04fcb |
a = b = c = 0xdeadbeef + ((uint32_t) (length << 2)) + *pc;
|
|
Packit |
c04fcb |
c += *pb;
|
|
Packit |
c04fcb |
|
|
Packit |
c04fcb |
/*----------------------------------------- handle most of the key */
|
|
Packit |
c04fcb |
while (length > 3) {
|
|
Packit |
c04fcb |
a += k[0];
|
|
Packit |
c04fcb |
b += k[1];
|
|
Packit |
c04fcb |
c += k[2];
|
|
Packit |
c04fcb |
mix(a, b, c);
|
|
Packit |
c04fcb |
length -= 3;
|
|
Packit |
c04fcb |
k += 3;
|
|
Packit |
c04fcb |
}
|
|
Packit |
c04fcb |
|
|
Packit |
c04fcb |
/*----------------------------------- handle the last 3 uint32_t's */
|
|
Packit |
c04fcb |
switch (length) { /* all the case statements fall through */
|
|
Packit |
c04fcb |
case 3: c += k[2];
|
|
Packit |
c04fcb |
case 2: b += k[1];
|
|
Packit |
c04fcb |
case 1: a += k[0];
|
|
Packit |
c04fcb |
final(a, b, c);
|
|
Packit |
c04fcb |
case 0: /* case 0: nothing left to add */
|
|
Packit |
c04fcb |
break;
|
|
Packit |
c04fcb |
}
|
|
Packit |
c04fcb |
/*---------------------------------------------- report the result */
|
|
Packit |
c04fcb |
*pc = c;
|
|
Packit |
c04fcb |
*pb = b;
|
|
Packit |
c04fcb |
}
|
|
Packit |
c04fcb |
|
|
Packit |
c04fcb |
#if (CAA_BITS_PER_LONG == 32)
|
|
Packit |
c04fcb |
static inline
|
|
Packit |
c04fcb |
unsigned long lttng_hash_mix(const void *_key, size_t length, unsigned long seed)
|
|
Packit |
c04fcb |
{
|
|
Packit |
c04fcb |
unsigned int key = (unsigned int) _key;
|
|
Packit |
c04fcb |
|
|
Packit |
c04fcb |
assert(length == sizeof(unsigned int));
|
|
Packit |
c04fcb |
return lttng_hash_u32(&key, 1, seed);
|
|
Packit |
c04fcb |
}
|
|
Packit |
c04fcb |
#else
|
|
Packit |
c04fcb |
static inline
|
|
Packit |
c04fcb |
unsigned long lttng_hash_mix(const void *_key, size_t length, unsigned long seed)
|
|
Packit |
c04fcb |
{
|
|
Packit |
c04fcb |
union {
|
|
Packit |
c04fcb |
uint64_t v64;
|
|
Packit |
c04fcb |
uint32_t v32[2];
|
|
Packit |
c04fcb |
} v;
|
|
Packit |
c04fcb |
union {
|
|
Packit |
c04fcb |
uint64_t v64;
|
|
Packit |
c04fcb |
uint32_t v32[2];
|
|
Packit |
c04fcb |
} key;
|
|
Packit |
c04fcb |
|
|
Packit |
c04fcb |
assert(length == sizeof(unsigned long));
|
|
Packit |
c04fcb |
v.v64 = (uint64_t) seed;
|
|
Packit |
c04fcb |
key.v64 = (uint64_t) _key;
|
|
Packit |
c04fcb |
lttng_hashword2(key.v32, 2, &v.v32[0], &v.v32[1]);
|
|
Packit |
c04fcb |
return v.v64;
|
|
Packit |
c04fcb |
}
|
|
Packit |
c04fcb |
#endif
|
|
Packit |
c04fcb |
|
|
Packit |
c04fcb |
#endif /* _LTTNG_HASH_HELPER_H */
|