/**
 * Collection of key/value pairs. Keys and values are generic pointer to client's
 * defined data types. For keys, an hash function must be provided to the
 * constructor and a key comparison function must be provided as well.
 * The hash table must be released with memory_dispose(); keys and values are
 * automatically released at that moment as well.
 * 
 * @file
 * @author Umberto Salsi <salsi@icosaedro.it>
 * @version $Date: 2017/10/08 23:51:58 $
 */

#ifndef HASHTABLE_H
#define HASHTABLE_H

#ifdef hashtable_IMPORT
	#define EXTERN
#else
	#define EXTERN extern
#endif

/**
 * Key/value hash table, object of this module.
 */
typedef struct hashtable_Type hashtable_Type;

/**
 * Prototype of the client's function that returns the hash given a key.
 */
typedef int (*hashtable_getKeyHash)(void *key);

/**
 * Prototype of the client's function that compares two keys for equality.
 * This function must return true if the two keys are equal, false otherwise.
 */
typedef int (*hashtable_equalKeys)(void *key1, void *key2);

/**
 * Returns a new, empty hash table.
 * @param getKeyHash Function that calculates the hash of a key.
 * @param equalKeys Function that compares two keys for equality.
 * @return New, empty hash table. Must be released with memory_dispose();
 * all the key/value pairs are released along with the hash table.
 */
EXTERN hashtable_Type *hashtable_new(
	hashtable_getKeyHash getKeyHash,
	hashtable_equalKeys equalKeys);

/**
 * Returns the number of key/value pairs in the table.
 * @param ht
 * @return Number of key/value pairs in the table.
 */
EXTERN int hashtable_length(hashtable_Type *ht);

/**
 * Add a new key/value pair to the hash table. If key already present, replaces
 * the old value and the old value is released from memory.
 * @param ht
 * @param key
 * @param value
 */
EXTERN void hashtable_put(hashtable_Type *ht, void *key, void *value);

/**
 * Returns the value corresponding to the given key.
 * @param ht
 * @param key
 * @return Value corresponding to the given key, or NULL if not found.
 */
EXTERN void *hashtable_get(hashtable_Type *ht, void *key);

/**
 * Removes and releases from memory a key/value pair given the key.
 * Does nothing if not found.
 * @param ht
 * @param key
 */
EXTERN void hashtable_remove(hashtable_Type *ht, void *key);

/**
 * Returns a key from which to start a sequential scanning of all the keys.
 * Next keys can be retrieved invoking hashtable_nextKey().
 * The returned key can be used to retrieve the value, change the value and to
 * remove the associated key/pair.
 * @param ht
 * @return First key, or NULL if the hash table is empty.
 */
EXTERN void *hashtable_firstKey(hashtable_Type *ht);

/**
 * Returns the next key for sequential scanning.
 * The returned key can be used to retrieve the value, change the value and to
 * remove the associated key/pair.
 * @param ht
 * @return Next key, or NULL if the hash table is empty. A NULL value may be
 * returned if some new kay/value pair has been added.
 */
EXTERN void *hashtable_nextKey(hashtable_Type *ht);

/**
 * Proposed generic hash function for a block of bytes.
 * @param buf Pointer to a block of data.
 * @param buf_len Number of bytes, non negative.
 * @return Hash value.
 */
EXTERN int hashtable_getHashOfMem(void *buf, int buf_len);

/**
 * Proposed generic hash function for NUL-terminates string.
 * @param s NUL-terminates string.
 * @return Hash value.
 */
EXTERN int hashtable_getHashOfString(void *s);

/**
 * Proposed generic comparison function for NUL-terminated strings.
 * This implementation merely returns strcmp(a,b) == 0.
 * @param a A string.
 * @param b Another string.
 * @return True if the two strings are equal.
 */
EXTERN int hashtable_equalStrings(void *a, void *b);

EXTERN void hashtable_report(hashtable_Type *ht);

#undef EXTERN
#endif
