Blame liblttng-ust/lttng-hash-helper.h

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 */