diff options
Diffstat (limited to 'lib/hash.c')
-rw-r--r-- | lib/hash.c | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/lib/hash.c b/lib/hash.c new file mode 100644 index 000000000..af8f21bb1 --- /dev/null +++ b/lib/hash.c @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2008, 2009 Nicira Networks. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include <config.h> +#include "hash.h" +#include <string.h> + +/* Returns the hash of the 'n' 32-bit words at 'p', starting from 'basis'. + * 'p' must be properly aligned. */ +uint32_t +hash_words(const uint32_t *p, size_t n, uint32_t basis) +{ + uint32_t a, b, c; + + a = b = c = 0xdeadbeef + (((uint32_t) n) << 2) + basis; + + while (n > 3) { + a += p[0]; + b += p[1]; + c += p[2]; + HASH_MIX(a, b, c); + n -= 3; + p += 3; + } + + switch (n) { + case 3: + c += p[2]; + /* fall through */ + case 2: + b += p[1]; + /* fall through */ + case 1: + a += p[0]; + HASH_FINAL(a, b, c); + /* fall through */ + case 0: + break; + } + return c; +} + +/* Returns the hash of the 'n' bytes at 'p', starting from 'basis'. */ +uint32_t +hash_bytes(const void *p_, size_t n, uint32_t basis) +{ + const uint8_t *p = p_; + uint32_t a, b, c; + uint32_t tmp[3]; + + a = b = c = 0xdeadbeef + n + basis; + + while (n >= sizeof tmp) { + memcpy(tmp, p, sizeof tmp); + a += tmp[0]; + b += tmp[1]; + c += tmp[2]; + HASH_MIX(a, b, c); + n -= sizeof tmp; + p += sizeof tmp; + } + + if (n) { + tmp[0] = tmp[1] = tmp[2] = 0; + memcpy(tmp, p, n); + a += tmp[0]; + b += tmp[1]; + c += tmp[2]; + HASH_FINAL(a, b, c); + } + + return c; +} |