Blame src/khash.h

Packit Service 20376f
/* The MIT License
Packit Service 20376f
Packit Service 20376f
   Copyright (c) 2008, 2009, 2011 by Attractive Chaos <attractor@live.co.uk>
Packit Service 20376f
Packit Service 20376f
   Permission is hereby granted, free of charge, to any person obtaining
Packit Service 20376f
   a copy of this software and associated documentation files (the
Packit Service 20376f
   "Software"), to deal in the Software without restriction, including
Packit Service 20376f
   without limitation the rights to use, copy, modify, merge, publish,
Packit Service 20376f
   distribute, sublicense, and/or sell copies of the Software, and to
Packit Service 20376f
   permit persons to whom the Software is furnished to do so, subject to
Packit Service 20376f
   the following conditions:
Packit Service 20376f
Packit Service 20376f
   The above copyright notice and this permission notice shall be
Packit Service 20376f
   included in all copies or substantial portions of the Software.
Packit Service 20376f
Packit Service 20376f
   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Packit Service 20376f
   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Packit Service 20376f
   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Packit Service 20376f
   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
Packit Service 20376f
   BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
Packit Service 20376f
   ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
Packit Service 20376f
   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
Packit Service 20376f
   SOFTWARE.
Packit Service 20376f
*/
Packit Service 20376f
Packit Service 20376f
/*
Packit Service 20376f
  An example:
Packit Service 20376f
Packit Service 20376f
#include "khash.h"
Packit Service 20376f
KHASH_MAP_INIT_INT(32, char)
Packit Service 20376f
int main() {
Packit Service 20376f
	int ret, is_missing;
Packit Service 20376f
	khiter_t k;
Packit Service 20376f
	khash_t(32) *h = kh_init(32);
Packit Service 20376f
	k = kh_put(32, h, 5, &ret;;
Packit Service 20376f
	kh_value(h, k) = 10;
Packit Service 20376f
	k = kh_get(32, h, 10);
Packit Service 20376f
	is_missing = (k == kh_end(h));
Packit Service 20376f
	k = kh_get(32, h, 5);
Packit Service 20376f
	kh_del(32, h, k);
Packit Service 20376f
	for (k = kh_begin(h); k != kh_end(h); ++k)
Packit Service 20376f
		if (kh_exist(h, k)) kh_value(h, k) = 1;
Packit Service 20376f
	kh_destroy(32, h);
Packit Service 20376f
	return 0;
Packit Service 20376f
}
Packit Service 20376f
*/
Packit Service 20376f
Packit Service 20376f
/*
Packit Service 20376f
  2013-05-02 (0.2.8):
Packit Service 20376f
Packit Service 20376f
	* Use quadratic probing. When the capacity is power of 2, stepping function
Packit Service 20376f
	  i*(i+1)/2 guarantees to traverse each bucket. It is better than double
Packit Service 20376f
	  hashing on cache performance and is more robust than linear probing.
Packit Service 20376f
Packit Service 20376f
	  In theory, double hashing should be more robust than quadratic probing.
Packit Service 20376f
	  However, my implementation is probably not for large hash tables, because
Packit Service 20376f
	  the second hash function is closely tied to the first hash function,
Packit Service 20376f
	  which reduce the effectiveness of double hashing.
Packit Service 20376f
Packit Service 20376f
	Reference: http://research.cs.vt.edu/AVresearch/hashing/quadratic.php
Packit Service 20376f
Packit Service 20376f
  2011-12-29 (0.2.7):
Packit Service 20376f
Packit Service 20376f
    * Minor code clean up; no actual effect.
Packit Service 20376f
Packit Service 20376f
  2011-09-16 (0.2.6):
Packit Service 20376f
Packit Service 20376f
	* The capacity is a power of 2. This seems to dramatically improve the
Packit Service 20376f
	  speed for simple keys. Thank Zilong Tan for the suggestion. Reference:
Packit Service 20376f
Packit Service 20376f
	   - http://code.google.com/p/ulib/
Packit Service 20376f
	   - http://nothings.org/computer/judy/
Packit Service 20376f
Packit Service 20376f
	* Allow to optionally use linear probing which usually has better
Packit Service 20376f
	  performance for random input. Double hashing is still the default as it
Packit Service 20376f
	  is more robust to certain non-random input.
Packit Service 20376f
Packit Service 20376f
	* Added Wang's integer hash function (not used by default). This hash
Packit Service 20376f
	  function is more robust to certain non-random input.
Packit Service 20376f
Packit Service 20376f
  2011-02-14 (0.2.5):
Packit Service 20376f
Packit Service 20376f
    * Allow to declare global functions.
Packit Service 20376f
Packit Service 20376f
  2009-09-26 (0.2.4):
Packit Service 20376f
Packit Service 20376f
    * Improve portability
Packit Service 20376f
Packit Service 20376f
  2008-09-19 (0.2.3):
Packit Service 20376f
Packit Service 20376f
	* Corrected the example
Packit Service 20376f
	* Improved interfaces
Packit Service 20376f
Packit Service 20376f
  2008-09-11 (0.2.2):
Packit Service 20376f
Packit Service 20376f
	* Improved speed a little in kh_put()
Packit Service 20376f
Packit Service 20376f
  2008-09-10 (0.2.1):
Packit Service 20376f
Packit Service 20376f
	* Added kh_clear()
Packit Service 20376f
	* Fixed a compiling error
Packit Service 20376f
Packit Service 20376f
  2008-09-02 (0.2.0):
Packit Service 20376f
Packit Service 20376f
	* Changed to token concatenation which increases flexibility.
Packit Service 20376f
Packit Service 20376f
  2008-08-31 (0.1.2):
Packit Service 20376f
Packit Service 20376f
	* Fixed a bug in kh_get(), which has not been tested previously.
Packit Service 20376f
Packit Service 20376f
  2008-08-31 (0.1.1):
Packit Service 20376f
Packit Service 20376f
	* Added destructor
Packit Service 20376f
*/
Packit Service 20376f
Packit Service 20376f
Packit Service 20376f
#ifndef __AC_KHASH_H
Packit Service 20376f
#define __AC_KHASH_H
Packit Service 20376f
Packit Service 20376f
/*!
Packit Service 20376f
  @header
Packit Service 20376f
Packit Service 20376f
  Generic hash table library.
Packit Service 20376f
 */
Packit Service 20376f
Packit Service 20376f
#define AC_VERSION_KHASH_H "0.2.8"
Packit Service 20376f
Packit Service 20376f
#include <stdlib.h>
Packit Service 20376f
#include <string.h>
Packit Service 20376f
#include <limits.h>
Packit Service 20376f
Packit Service 20376f
/* compiler specific configuration */
Packit Service 20376f
Packit Service 20376f
#if UINT_MAX == 0xffffffffu
Packit Service 20376f
typedef unsigned int khint32_t;
Packit Service 20376f
#elif ULONG_MAX == 0xffffffffu
Packit Service 20376f
typedef unsigned long khint32_t;
Packit Service 20376f
#endif
Packit Service 20376f
Packit Service 20376f
#if ULONG_MAX == ULLONG_MAX
Packit Service 20376f
typedef unsigned long khint64_t;
Packit Service 20376f
#else
Packit Service 20376f
typedef unsigned long long khint64_t;
Packit Service 20376f
#endif
Packit Service 20376f
Packit Service 20376f
#ifndef kh_inline
Packit Service 20376f
#ifdef _MSC_VER
Packit Service 20376f
#define kh_inline __inline
Packit Service 20376f
#else
Packit Service 20376f
#define kh_inline inline
Packit Service 20376f
#endif
Packit Service 20376f
#endif /* kh_inline */
Packit Service 20376f
Packit Service 20376f
typedef khint32_t khint_t;
Packit Service 20376f
typedef khint_t khiter_t;
Packit Service 20376f
Packit Service 20376f
#define __ac_isempty(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&2)
Packit Service 20376f
#define __ac_isdel(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&1)
Packit Service 20376f
#define __ac_iseither(flag, i) ((flag[i>>4]>>((i&0xfU)<<1))&3)
Packit Service 20376f
#define __ac_set_isdel_false(flag, i) (flag[i>>4]&=~(1ul<<((i&0xfU)<<1)))
Packit Service 20376f
#define __ac_set_isempty_false(flag, i) (flag[i>>4]&=~(2ul<<((i&0xfU)<<1)))
Packit Service 20376f
#define __ac_set_isboth_false(flag, i) (flag[i>>4]&=~(3ul<<((i&0xfU)<<1)))
Packit Service 20376f
#define __ac_set_isdel_true(flag, i) (flag[i>>4]|=1ul<<((i&0xfU)<<1))
Packit Service 20376f
Packit Service 20376f
#define __ac_fsize(m) ((m) < 16? 1 : (m)>>4)
Packit Service 20376f
Packit Service 20376f
#ifndef kroundup32
Packit Service 20376f
#define kroundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x))
Packit Service 20376f
#endif
Packit Service 20376f
Packit Service 20376f
#ifndef kcalloc
Packit Service 20376f
#define kcalloc(N,Z) calloc(N,Z)
Packit Service 20376f
#endif
Packit Service 20376f
#ifndef kmalloc
Packit Service 20376f
#define kmalloc(Z) malloc(Z)
Packit Service 20376f
#endif
Packit Service 20376f
#ifndef krealloc
Packit Service 20376f
#define krealloc(P,Z) realloc(P,Z)
Packit Service 20376f
#endif
Packit Service 20376f
#ifndef kreallocarray
Packit Service 20376f
#define kreallocarray(P,N,Z) ((SIZE_MAX - N < Z) ? NULL : krealloc(P, (N*Z)))
Packit Service 20376f
#endif
Packit Service 20376f
#ifndef kfree
Packit Service 20376f
#define kfree(P) free(P)
Packit Service 20376f
#endif
Packit Service 20376f
Packit Service 20376f
static const double __ac_HASH_UPPER = 0.77;
Packit Service 20376f
Packit Service 20376f
#define __KHASH_TYPE(name, khkey_t, khval_t) \
Packit Service 20376f
	typedef struct kh_##name##_s { \
Packit Service 20376f
		khint_t n_buckets, size, n_occupied, upper_bound; \
Packit Service 20376f
		khint32_t *flags; \
Packit Service 20376f
		khkey_t *keys; \
Packit Service 20376f
		khval_t *vals; \
Packit Service 20376f
	} kh_##name##_t;
Packit Service 20376f
Packit Service 20376f
#define __KHASH_PROTOTYPES(name, khkey_t, khval_t)	 					\
Packit Service 20376f
	extern kh_##name##_t *kh_init_##name(void);							\
Packit Service 20376f
	extern void kh_destroy_##name(kh_##name##_t *h);					\
Packit Service 20376f
	extern void kh_clear_##name(kh_##name##_t *h);						\
Packit Service 20376f
	extern khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key); 	\
Packit Service 20376f
	extern int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets); \
Packit Service 20376f
	extern khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret); \
Packit Service 20376f
	extern void kh_del_##name(kh_##name##_t *h, khint_t x);
Packit Service 20376f
Packit Service 20376f
#define __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
Packit Service 20376f
	SCOPE kh_##name##_t *kh_init_##name(void) {							\
Packit Service 20376f
		return (kh_##name##_t*)kcalloc(1, sizeof(kh_##name##_t));		\
Packit Service 20376f
	}																	\
Packit Service 20376f
	SCOPE void kh_destroy_##name(kh_##name##_t *h)						\
Packit Service 20376f
	{																	\
Packit Service 20376f
		if (h) {														\
Packit Service 20376f
			kfree((void *)h->keys); kfree(h->flags);					\
Packit Service 20376f
			kfree((void *)h->vals);										\
Packit Service 20376f
			kfree(h);													\
Packit Service 20376f
		}																\
Packit Service 20376f
	}																	\
Packit Service 20376f
	SCOPE void kh_clear_##name(kh_##name##_t *h)						\
Packit Service 20376f
	{																	\
Packit Service 20376f
		if (h && h->flags) {											\
Packit Service 20376f
			memset(h->flags, 0xaa, __ac_fsize(h->n_buckets) * sizeof(khint32_t)); \
Packit Service 20376f
			h->size = h->n_occupied = 0;								\
Packit Service 20376f
		}																\
Packit Service 20376f
	}																	\
Packit Service 20376f
	SCOPE khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key) 	\
Packit Service 20376f
	{																	\
Packit Service 20376f
		if (h->n_buckets) {												\
Packit Service 20376f
			khint_t k, i, last, mask, step = 0; \
Packit Service 20376f
			mask = h->n_buckets - 1;									\
Packit Service 20376f
			k = __hash_func(key); i = k & mask;							\
Packit Service 20376f
			last = i; \
Packit Service 20376f
			while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \
Packit Service 20376f
				i = (i + (++step)) & mask; \
Packit Service 20376f
				if (i == last) return h->n_buckets;						\
Packit Service 20376f
			}															\
Packit Service 20376f
			return __ac_iseither(h->flags, i)? h->n_buckets : i;		\
Packit Service 20376f
		} else return 0;												\
Packit Service 20376f
	}																	\
Packit Service 20376f
	SCOPE int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets) \
Packit Service 20376f
	{ /* This function uses 0.25*n_buckets bytes of working space instead of [sizeof(key_t+val_t)+.25]*n_buckets. */ \
Packit Service 20376f
		khint32_t *new_flags = 0;										\
Packit Service 20376f
		khint_t j = 1;													\
Packit Service 20376f
		{																\
Packit Service 20376f
			kroundup32(new_n_buckets); 									\
Packit Service 20376f
			if (new_n_buckets < 4) new_n_buckets = 4;					\
Packit Service 20376f
			if (h->size >= (khint_t)(new_n_buckets * __ac_HASH_UPPER + 0.5)) j = 0;	/* requested size is too small */ \
Packit Service 20376f
			else { /* hash table size to be changed (shrink or expand); rehash */ \
Packit Service 20376f
				new_flags = (khint32_t*)kreallocarray(NULL, __ac_fsize(new_n_buckets), sizeof(khint32_t)); \
Packit Service 20376f
				if (!new_flags) return -1;								\
Packit Service 20376f
				memset(new_flags, 0xaa, __ac_fsize(new_n_buckets) * sizeof(khint32_t)); \
Packit Service 20376f
				if (h->n_buckets < new_n_buckets) {	/* expand */		\
Packit Service 20376f
					khkey_t *new_keys = (khkey_t*)kreallocarray((void *)h->keys, new_n_buckets, sizeof(khkey_t)); \
Packit Service 20376f
					if (!new_keys) { kfree(new_flags); return -1; }		\
Packit Service 20376f
					h->keys = new_keys;									\
Packit Service 20376f
					if (kh_is_map) {									\
Packit Service 20376f
						khval_t *new_vals = (khval_t*)kreallocarray((void *)h->vals, new_n_buckets, sizeof(khval_t)); \
Packit Service 20376f
						if (!new_vals) { kfree(new_flags); return -1; }	\
Packit Service 20376f
						h->vals = new_vals;								\
Packit Service 20376f
					}													\
Packit Service 20376f
				} /* otherwise shrink */								\
Packit Service 20376f
			}															\
Packit Service 20376f
		}																\
Packit Service 20376f
		if (j) { /* rehashing is needed */								\
Packit Service 20376f
			for (j = 0; j != h->n_buckets; ++j) {						\
Packit Service 20376f
				if (__ac_iseither(h->flags, j) == 0) {					\
Packit Service 20376f
					khkey_t key = h->keys[j];							\
Packit Service 20376f
					khval_t val;										\
Packit Service 20376f
					khint_t new_mask;									\
Packit Service 20376f
					new_mask = new_n_buckets - 1; 						\
Packit Service 20376f
					if (kh_is_map) val = h->vals[j];					\
Packit Service 20376f
					__ac_set_isdel_true(h->flags, j);					\
Packit Service 20376f
					while (1) { /* kick-out process; sort of like in Cuckoo hashing */ \
Packit Service 20376f
						khint_t k, i, step = 0; \
Packit Service 20376f
						k = __hash_func(key);							\
Packit Service 20376f
						i = k & new_mask;								\
Packit Service 20376f
						while (!__ac_isempty(new_flags, i)) i = (i + (++step)) & new_mask; \
Packit Service 20376f
						__ac_set_isempty_false(new_flags, i);			\
Packit Service 20376f
						if (i < h->n_buckets && __ac_iseither(h->flags, i) == 0) { /* kick out the existing element */ \
Packit Service 20376f
							{ khkey_t tmp = h->keys[i]; h->keys[i] = key; key = tmp; } \
Packit Service 20376f
							if (kh_is_map) { khval_t tmp = h->vals[i]; h->vals[i] = val; val = tmp; } \
Packit Service 20376f
							__ac_set_isdel_true(h->flags, i); /* mark it as deleted in the old hash table */ \
Packit Service 20376f
						} else { /* write the element and jump out of the loop */ \
Packit Service 20376f
							h->keys[i] = key;							\
Packit Service 20376f
							if (kh_is_map) h->vals[i] = val;			\
Packit Service 20376f
							break;										\
Packit Service 20376f
						}												\
Packit Service 20376f
					}													\
Packit Service 20376f
				}														\
Packit Service 20376f
			}															\
Packit Service 20376f
			if (h->n_buckets > new_n_buckets) { /* shrink the hash table */ \
Packit Service 20376f
				h->keys = (khkey_t*)kreallocarray((void *)h->keys, new_n_buckets, sizeof(khkey_t)); \
Packit Service 20376f
				if (kh_is_map) h->vals = (khval_t*)kreallocarray((void *)h->vals, new_n_buckets, sizeof(khval_t)); \
Packit Service 20376f
			}															\
Packit Service 20376f
			kfree(h->flags); /* free the working space */				\
Packit Service 20376f
			h->flags = new_flags;										\
Packit Service 20376f
			h->n_buckets = new_n_buckets;								\
Packit Service 20376f
			h->n_occupied = h->size;									\
Packit Service 20376f
			h->upper_bound = (khint_t)(h->n_buckets * __ac_HASH_UPPER + 0.5); \
Packit Service 20376f
		}																\
Packit Service 20376f
		return 0;														\
Packit Service 20376f
	}																	\
Packit Service 20376f
	SCOPE khint_t kh_put_##name(kh_##name##_t *h, khkey_t key, int *ret) \
Packit Service 20376f
	{																	\
Packit Service 20376f
		khint_t x;														\
Packit Service 20376f
		if (h->n_occupied >= h->upper_bound) { /* update the hash table */ \
Packit Service 20376f
			if (h->n_buckets > (h->size<<1)) {							\
Packit Service 20376f
				if (kh_resize_##name(h, h->n_buckets - 1) < 0) { /* clear "deleted" elements */ \
Packit Service 20376f
					*ret = -1; return h->n_buckets;						\
Packit Service 20376f
				}														\
Packit Service 20376f
			} else if (kh_resize_##name(h, h->n_buckets + 1) < 0) { /* expand the hash table */ \
Packit Service 20376f
				*ret = -1; return h->n_buckets;							\
Packit Service 20376f
			}															\
Packit Service 20376f
		} /* TODO: to implement automatically shrinking; resize() already support shrinking */ \
Packit Service 20376f
		{																\
Packit Service 20376f
			khint_t k, i, site, last, mask = h->n_buckets - 1, step = 0; \
Packit Service 20376f
			x = site = h->n_buckets; k = __hash_func(key); i = k & mask; \
Packit Service 20376f
			if (__ac_isempty(h->flags, i)) x = i; /* for speed up */	\
Packit Service 20376f
			else {														\
Packit Service 20376f
				last = i; \
Packit Service 20376f
				while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \
Packit Service 20376f
					if (__ac_isdel(h->flags, i)) site = i;				\
Packit Service 20376f
					i = (i + (++step)) & mask; \
Packit Service 20376f
					if (i == last) { x = site; break; }					\
Packit Service 20376f
				}														\
Packit Service 20376f
				if (x == h->n_buckets) {								\
Packit Service 20376f
					if (__ac_isempty(h->flags, i) && site != h->n_buckets) x = site; \
Packit Service 20376f
					else x = i;											\
Packit Service 20376f
				}														\
Packit Service 20376f
			}															\
Packit Service 20376f
		}																\
Packit Service 20376f
		if (__ac_isempty(h->flags, x)) { /* not present at all */		\
Packit Service 20376f
			h->keys[x] = key;											\
Packit Service 20376f
			__ac_set_isboth_false(h->flags, x);							\
Packit Service 20376f
			++h->size; ++h->n_occupied;									\
Packit Service 20376f
			*ret = 1;													\
Packit Service 20376f
		} else if (__ac_isdel(h->flags, x)) { /* deleted */				\
Packit Service 20376f
			h->keys[x] = key;											\
Packit Service 20376f
			__ac_set_isboth_false(h->flags, x);							\
Packit Service 20376f
			++h->size;													\
Packit Service 20376f
			*ret = 2;													\
Packit Service 20376f
		} else *ret = 0; /* Don't touch h->keys[x] if present and not deleted */ \
Packit Service 20376f
		return x;														\
Packit Service 20376f
	}																	\
Packit Service 20376f
	SCOPE void kh_del_##name(kh_##name##_t *h, khint_t x)				\
Packit Service 20376f
	{																	\
Packit Service 20376f
		if (x != h->n_buckets && !__ac_iseither(h->flags, x)) {			\
Packit Service 20376f
			__ac_set_isdel_true(h->flags, x);							\
Packit Service 20376f
			--h->size;													\
Packit Service 20376f
		}																\
Packit Service 20376f
	}
Packit Service 20376f
Packit Service 20376f
#define KHASH_DECLARE(name, khkey_t, khval_t)		 					\
Packit Service 20376f
	__KHASH_TYPE(name, khkey_t, khval_t) 								\
Packit Service 20376f
	__KHASH_PROTOTYPES(name, khkey_t, khval_t)
Packit Service 20376f
Packit Service 20376f
#define KHASH_INIT2(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
Packit Service 20376f
	__KHASH_TYPE(name, khkey_t, khval_t) 								\
Packit Service 20376f
	__KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal)
Packit Service 20376f
Packit Service 20376f
#define KHASH_INIT(name, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \
Packit Service 20376f
	KHASH_INIT2(name, static kh_inline, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal)
Packit Service 20376f
Packit Service 20376f
/* --- BEGIN OF HASH FUNCTIONS --- */
Packit Service 20376f
Packit Service 20376f
/*! @function
Packit Service 20376f
  @abstract     Integer hash function
Packit Service 20376f
  @param  key   The integer [khint32_t]
Packit Service 20376f
  @return       The hash value [khint_t]
Packit Service 20376f
 */
Packit Service 20376f
#define kh_int_hash_func(key) (khint32_t)(key)
Packit Service 20376f
/*! @function
Packit Service 20376f
  @abstract     Integer comparison function
Packit Service 20376f
 */
Packit Service 20376f
#define kh_int_hash_equal(a, b) ((a) == (b))
Packit Service 20376f
/*! @function
Packit Service 20376f
  @abstract     64-bit integer hash function
Packit Service 20376f
  @param  key   The integer [khint64_t]
Packit Service 20376f
  @return       The hash value [khint_t]
Packit Service 20376f
 */
Packit Service 20376f
#define kh_int64_hash_func(key) (khint32_t)((key)>>33^(key)^(key)<<11)
Packit Service 20376f
/*! @function
Packit Service 20376f
  @abstract     64-bit integer comparison function
Packit Service 20376f
 */
Packit Service 20376f
#define kh_int64_hash_equal(a, b) ((a) == (b))
Packit Service 20376f
/*! @function
Packit Service 20376f
  @abstract     const char* hash function
Packit Service 20376f
  @param  s     Pointer to a null terminated string
Packit Service 20376f
  @return       The hash value
Packit Service 20376f
 */
Packit Service 20376f
static kh_inline khint_t __ac_X31_hash_string(const char *s)
Packit Service 20376f
{
Packit Service 20376f
	khint_t h = (khint_t)*s;
Packit Service 20376f
	if (h) for (++s ; *s; ++s) h = (h << 5) - h + (khint_t)*s;
Packit Service 20376f
	return h;
Packit Service 20376f
}
Packit Service 20376f
/*! @function
Packit Service 20376f
  @abstract     Another interface to const char* hash function
Packit Service 20376f
  @param  key   Pointer to a null terminated string [const char*]
Packit Service 20376f
  @return       The hash value [khint_t]
Packit Service 20376f
 */
Packit Service 20376f
#define kh_str_hash_func(key) __ac_X31_hash_string(key)
Packit Service 20376f
/*! @function
Packit Service 20376f
  @abstract     Const char* comparison function
Packit Service 20376f
 */
Packit Service 20376f
#define kh_str_hash_equal(a, b) (strcmp(a, b) == 0)
Packit Service 20376f
Packit Service 20376f
static kh_inline khint_t __ac_Wang_hash(khint_t key)
Packit Service 20376f
{
Packit Service 20376f
    key += ~(key << 15);
Packit Service 20376f
    key ^=  (key >> 10);
Packit Service 20376f
    key +=  (key << 3);
Packit Service 20376f
    key ^=  (key >> 6);
Packit Service 20376f
    key += ~(key << 11);
Packit Service 20376f
    key ^=  (key >> 16);
Packit Service 20376f
    return key;
Packit Service 20376f
}
Packit Service 20376f
#define kh_int_hash_func2(k) __ac_Wang_hash((khint_t)key)
Packit Service 20376f
Packit Service 20376f
/* --- END OF HASH FUNCTIONS --- */
Packit Service 20376f
Packit Service 20376f
/* Other convenient macros... */
Packit Service 20376f
Packit Service 20376f
/*!
Packit Service 20376f
  @abstract Type of the hash table.
Packit Service 20376f
  @param  name  Name of the hash table [symbol]
Packit Service 20376f
 */
Packit Service 20376f
#define khash_t(name) kh_##name##_t
Packit Service 20376f
Packit Service 20376f
/*! @function
Packit Service 20376f
  @abstract     Initiate a hash table.
Packit Service 20376f
  @param  name  Name of the hash table [symbol]
Packit Service 20376f
  @return       Pointer to the hash table [khash_t(name)*]
Packit Service 20376f
 */
Packit Service 20376f
#define kh_init(name) kh_init_##name()
Packit Service 20376f
Packit Service 20376f
/*! @function
Packit Service 20376f
  @abstract     Destroy a hash table.
Packit Service 20376f
  @param  name  Name of the hash table [symbol]
Packit Service 20376f
  @param  h     Pointer to the hash table [khash_t(name)*]
Packit Service 20376f
 */
Packit Service 20376f
#define kh_destroy(name, h) kh_destroy_##name(h)
Packit Service 20376f
Packit Service 20376f
/*! @function
Packit Service 20376f
  @abstract     Reset a hash table without deallocating memory.
Packit Service 20376f
  @param  name  Name of the hash table [symbol]
Packit Service 20376f
  @param  h     Pointer to the hash table [khash_t(name)*]
Packit Service 20376f
 */
Packit Service 20376f
#define kh_clear(name, h) kh_clear_##name(h)
Packit Service 20376f
Packit Service 20376f
/*! @function
Packit Service 20376f
  @abstract     Resize a hash table.
Packit Service 20376f
  @param  name  Name of the hash table [symbol]
Packit Service 20376f
  @param  h     Pointer to the hash table [khash_t(name)*]
Packit Service 20376f
  @param  s     New size [khint_t]
Packit Service 20376f
 */
Packit Service 20376f
#define kh_resize(name, h, s) kh_resize_##name(h, s)
Packit Service 20376f
Packit Service 20376f
/*! @function
Packit Service 20376f
  @abstract     Insert a key to the hash table.
Packit Service 20376f
  @param  name  Name of the hash table [symbol]
Packit Service 20376f
  @param  h     Pointer to the hash table [khash_t(name)*]
Packit Service 20376f
  @param  k     Key [type of keys]
Packit Service 20376f
  @param  r     Extra return code: -1 if the operation failed;
Packit Service 20376f
                0 if the key is present in the hash table;
Packit Service 20376f
                1 if the bucket is empty (never used); 2 if the element in
Packit Service 20376f
				the bucket has been deleted [int*]
Packit Service 20376f
  @return       Iterator to the inserted element [khint_t]
Packit Service 20376f
 */
Packit Service 20376f
#define kh_put(name, h, k, r) kh_put_##name(h, k, r)
Packit Service 20376f
Packit Service 20376f
/*! @function
Packit Service 20376f
  @abstract     Retrieve a key from the hash table.
Packit Service 20376f
  @param  name  Name of the hash table [symbol]
Packit Service 20376f
  @param  h     Pointer to the hash table [khash_t(name)*]
Packit Service 20376f
  @param  k     Key [type of keys]
Packit Service 20376f
  @return       Iterator to the found element, or kh_end(h) if the element is absent [khint_t]
Packit Service 20376f
 */
Packit Service 20376f
#define kh_get(name, h, k) kh_get_##name(h, k)
Packit Service 20376f
Packit Service 20376f
/*! @function
Packit Service 20376f
  @abstract     Remove a key from the hash table.
Packit Service 20376f
  @param  name  Name of the hash table [symbol]
Packit Service 20376f
  @param  h     Pointer to the hash table [khash_t(name)*]
Packit Service 20376f
  @param  k     Iterator to the element to be deleted [khint_t]
Packit Service 20376f
 */
Packit Service 20376f
#define kh_del(name, h, k) kh_del_##name(h, k)
Packit Service 20376f
Packit Service 20376f
/*! @function
Packit Service 20376f
  @abstract     Test whether a bucket contains data.
Packit Service 20376f
  @param  h     Pointer to the hash table [khash_t(name)*]
Packit Service 20376f
  @param  x     Iterator to the bucket [khint_t]
Packit Service 20376f
  @return       1 if containing data; 0 otherwise [int]
Packit Service 20376f
 */
Packit Service 20376f
#define kh_exist(h, x) (!__ac_iseither((h)->flags, (x)))
Packit Service 20376f
Packit Service 20376f
/*! @function
Packit Service 20376f
  @abstract     Get key given an iterator
Packit Service 20376f
  @param  h     Pointer to the hash table [khash_t(name)*]
Packit Service 20376f
  @param  x     Iterator to the bucket [khint_t]
Packit Service 20376f
  @return       Key [type of keys]
Packit Service 20376f
 */
Packit Service 20376f
#define kh_key(h, x) ((h)->keys[x])
Packit Service 20376f
Packit Service 20376f
/*! @function
Packit Service 20376f
  @abstract     Get value given an iterator
Packit Service 20376f
  @param  h     Pointer to the hash table [khash_t(name)*]
Packit Service 20376f
  @param  x     Iterator to the bucket [khint_t]
Packit Service 20376f
  @return       Value [type of values]
Packit Service 20376f
  @discussion   For hash sets, calling this results in segfault.
Packit Service 20376f
 */
Packit Service 20376f
#define kh_val(h, x) ((h)->vals[x])
Packit Service 20376f
Packit Service 20376f
/*! @function
Packit Service 20376f
  @abstract     Alias of kh_val()
Packit Service 20376f
 */
Packit Service 20376f
#define kh_value(h, x) ((h)->vals[x])
Packit Service 20376f
Packit Service 20376f
/*! @function
Packit Service 20376f
  @abstract     Get the start iterator
Packit Service 20376f
  @param  h     Pointer to the hash table [khash_t(name)*]
Packit Service 20376f
  @return       The start iterator [khint_t]
Packit Service 20376f
 */
Packit Service 20376f
#define kh_begin(h) (khint_t)(0)
Packit Service 20376f
Packit Service 20376f
/*! @function
Packit Service 20376f
  @abstract     Get the end iterator
Packit Service 20376f
  @param  h     Pointer to the hash table [khash_t(name)*]
Packit Service 20376f
  @return       The end iterator [khint_t]
Packit Service 20376f
 */
Packit Service 20376f
#define kh_end(h) ((h)->n_buckets)
Packit Service 20376f
Packit Service 20376f
/*! @function
Packit Service 20376f
  @abstract     Get the number of elements in the hash table
Packit Service 20376f
  @param  h     Pointer to the hash table [khash_t(name)*]
Packit Service 20376f
  @return       Number of elements in the hash table [khint_t]
Packit Service 20376f
 */
Packit Service 20376f
#define kh_size(h) ((h)->size)
Packit Service 20376f
Packit Service 20376f
/*! @function
Packit Service 20376f
  @abstract     Get the number of buckets in the hash table
Packit Service 20376f
  @param  h     Pointer to the hash table [khash_t(name)*]
Packit Service 20376f
  @return       Number of buckets in the hash table [khint_t]
Packit Service 20376f
 */
Packit Service 20376f
#define kh_n_buckets(h) ((h)->n_buckets)
Packit Service 20376f
Packit Service 20376f
/*! @function
Packit Service 20376f
  @abstract     Iterate over the entries in the hash table
Packit Service 20376f
  @param  h     Pointer to the hash table [khash_t(name)*]
Packit Service 20376f
  @param  kvar  Variable to which key will be assigned
Packit Service 20376f
  @param  vvar  Variable to which value will be assigned
Packit Service 20376f
  @param  code  Block of code to execute
Packit Service 20376f
 */
Packit Service 20376f
#define kh_foreach(h, kvar, vvar, code) { khint_t __i;		\
Packit Service 20376f
	for (__i = kh_begin(h); __i != kh_end(h); ++__i) {		\
Packit Service 20376f
		if (!kh_exist(h,__i)) continue;						\
Packit Service 20376f
		(kvar) = kh_key(h,__i);								\
Packit Service 20376f
		(vvar) = kh_val(h,__i);								\
Packit Service 20376f
		code;												\
Packit Service 20376f
	} }
Packit Service 20376f
Packit Service 20376f
/*! @function
Packit Service 20376f
  @abstract     Iterate over the values in the hash table
Packit Service 20376f
  @param  h     Pointer to the hash table [khash_t(name)*]
Packit Service 20376f
  @param  vvar  Variable to which value will be assigned
Packit Service 20376f
  @param  code  Block of code to execute
Packit Service 20376f
 */
Packit Service 20376f
#define kh_foreach_value(h, vvar, code) { khint_t __i;		\
Packit Service 20376f
	for (__i = kh_begin(h); __i != kh_end(h); ++__i) {		\
Packit Service 20376f
		if (!kh_exist(h,__i)) continue;						\
Packit Service 20376f
		(vvar) = kh_val(h,__i);								\
Packit Service 20376f
		code;												\
Packit Service 20376f
	} }
Packit Service 20376f
Packit Service 20376f
/* More conenient interfaces */
Packit Service 20376f
Packit Service 20376f
/*! @function
Packit Service 20376f
  @abstract     Instantiate a hash set containing integer keys
Packit Service 20376f
  @param  name  Name of the hash table [symbol]
Packit Service 20376f
 */
Packit Service 20376f
#define KHASH_SET_INIT_INT(name)										\
Packit Service 20376f
	KHASH_INIT(name, khint32_t, char, 0, kh_int_hash_func, kh_int_hash_equal)
Packit Service 20376f
Packit Service 20376f
/*! @function
Packit Service 20376f
  @abstract     Instantiate a hash map containing integer keys
Packit Service 20376f
  @param  name  Name of the hash table [symbol]
Packit Service 20376f
  @param  khval_t  Type of values [type]
Packit Service 20376f
 */
Packit Service 20376f
#define KHASH_MAP_INIT_INT(name, khval_t)								\
Packit Service 20376f
	KHASH_INIT(name, khint32_t, khval_t, 1, kh_int_hash_func, kh_int_hash_equal)
Packit Service 20376f
Packit Service 20376f
/*! @function
Packit Service 20376f
  @abstract     Instantiate a hash map containing 64-bit integer keys
Packit Service 20376f
  @param  name  Name of the hash table [symbol]
Packit Service 20376f
 */
Packit Service 20376f
#define KHASH_SET_INIT_INT64(name)										\
Packit Service 20376f
	KHASH_INIT(name, khint64_t, char, 0, kh_int64_hash_func, kh_int64_hash_equal)
Packit Service 20376f
Packit Service 20376f
/*! @function
Packit Service 20376f
  @abstract     Instantiate a hash map containing 64-bit integer keys
Packit Service 20376f
  @param  name  Name of the hash table [symbol]
Packit Service 20376f
  @param  khval_t  Type of values [type]
Packit Service 20376f
 */
Packit Service 20376f
#define KHASH_MAP_INIT_INT64(name, khval_t)								\
Packit Service 20376f
	KHASH_INIT(name, khint64_t, khval_t, 1, kh_int64_hash_func, kh_int64_hash_equal)
Packit Service 20376f
Packit Service 20376f
typedef const char *kh_cstr_t;
Packit Service 20376f
/*! @function
Packit Service 20376f
  @abstract     Instantiate a hash map containing const char* keys
Packit Service 20376f
  @param  name  Name of the hash table [symbol]
Packit Service 20376f
 */
Packit Service 20376f
#define KHASH_SET_INIT_STR(name)										\
Packit Service 20376f
	KHASH_INIT(name, kh_cstr_t, char, 0, kh_str_hash_func, kh_str_hash_equal)
Packit Service 20376f
Packit Service 20376f
/*! @function
Packit Service 20376f
  @abstract     Instantiate a hash map containing const char* keys
Packit Service 20376f
  @param  name  Name of the hash table [symbol]
Packit Service 20376f
  @param  khval_t  Type of values [type]
Packit Service 20376f
 */
Packit Service 20376f
#define KHASH_MAP_INIT_STR(name, khval_t)								\
Packit Service 20376f
	KHASH_INIT(name, kh_cstr_t, khval_t, 1, kh_str_hash_func, kh_str_hash_equal)
Packit Service 20376f
Packit Service 20376f
#endif /* __AC_KHASH_H */