First iteration of hash table

This commit is contained in:
Nils O. Selåsdal
2013-10-17 21:00:05 +02:00
parent 2d680052b2
commit 987db2d096
3 changed files with 365 additions and 0 deletions
+214
View File
@@ -0,0 +1,214 @@
#ifndef UC_HTABLE_H_
#define UC_HTABLE_H_
#include <stddef.h>
/** Building block for hash table.
* The hash table is stored using a chained list of buckets.
* Nodes with different hash value can be stored in the same bucket.
*
*
* The hash table manages only the hash value, not the equality
* between nodes.
*
* It's up to the user to check for duplicate values
* before adding nodes if dublicates are not desired.
*
* Finding a node must be done in a user specific way,
* normally by iterating over all nodes with the desidred
* hash, and deciding in some other way whether it is the desidred
* node.
*/
/** Node the hashtable tracks.
* Will normally be embedded inside another struct
*/
struct UHNode {
//cached value of the hash
size_t hash;
//pointer to next in same bucket
struct UHNode *next;
};
/**
* The hash table struct
*/
struct UHTable {
size_t cnt_elements;
size_t cnt_buckets;
struct UHNode **buckets;
};
/**
* Initialize a hash table.
* @param table hash table to initialize
* @param buckets number of buckets
* @return 0 on success, errno if malloc fails or buckets == 0
*/
int uc_htable_init(struct UHTable *table, size_t buckets);
/**
* Frees resources of the hash table.
* @param table hash table to free (does not free @table itself
*/
void uc_htable_destroy(struct UHTable *table);
/**
* @param table
* @param hash find the bucket from this hash value
* @return the bucket number for the given hash
*/
static inline size_t uc_htable_bucket(const struct UHTable *table, size_t hash)
{
return hash % table->cnt_buckets;
}
/**
* Get the first bucket node for the given hash.
* The returned node might not have the same hash, since different
* nodes can share the same bucket.
*
* @param table table
* @param hash hash
*/
static inline struct UHNode *uc_htable_first_bucket(const struct UHTable *table, size_t hash)
{
size_t bucket = uc_htable_bucket(table, hash);
return table->buckets[bucket];
}
/**
* Get the next node in the bucket.
* @return next node or NULL
*/
static inline struct UHNode *uc_htable_next_bucket(const struct UHNode *node)
{
return node->next;
}
/**
* Get the first node that have the given hash
* @param table table
* @param hash hash
* @return first node with the given hash or NULL
*/
struct UHNode *uc_htable_first_hash(const struct UHTable *table, size_t hash);
//internal helper
struct UHNode *uc_htable_next_hash_hlp(struct UHNode *next, size_t hash);
/**
* Get the next node with the same hash
* @param node previous node
* @return next node with the same hash as node or NULL
*/
static inline struct UHNode *uc_htable_next_hash(const struct UHNode *node)
{
return uc_htable_next_hash_hlp(node->next, node->hash);
}
//internal helper
struct UHNode *uc_htable_next_hlp(struct UHTable *table, size_t bucket);
/** Get the first node in the hash table
*
* @param table table
* @return first node or NULL
*/
static inline struct UHNode *uc_htable_first(struct UHTable *table)
{
return uc_htable_next_hlp(table, 0);
}
/** Get the next node in the hash table
*
* @param table table
* @param node previous node
* @return first node or NULL
*/
struct UHNode *uc_htable_next(struct UHTable *table, struct UHNode *node);
/**
* Swap 2 hash tables.
*
* @param a first table
* @param b second table
*/
void uc_htable_swap(struct UHTable *a, struct UHTable *b);
#define UC_HTABLE_FOREACH_BUCKET(table, node_iter, hash)\
for ((node_iter) = uc_htable_first_bucket((table), (hash));\
(node_iter) != NULL;\
(node_iter) = uc_htable_next_bucket((node_iter)))
#define UC_HTABLE_FOREACH_HASH(table, node_iter, hash)\
for ((node_iter) = uc_htable_first_hash((table), (hash));\
(node_iter) != NULL;\
(node_iter) = uc_htable_next_hash((node_iter)))
#define UC_HTABLE_FOREACH(table, node_iter, hash)\
for ((node_iter) = uc_htable_first((table));\
(node_iter) != NULL;\
(node_iter) = uc_htable_next((table), (node_iter)))
/**
* Check if the given node pointer exists in the hash table
*
* @param table table
* @param node node to check for
* @return 0 if the node does not exist in table non-0 if it does
*/
int uc_htable_has_node(struct UHTable *table, struct UHNode *node);
/**
*
* @return 0 if table is empty non-0 if it contains any nodes
*/
static inline int uc_htable_isempty(const struct UHTable *table)
{
return table->cnt_elements == 0;
}
/**
* Get number of elements in the hash table.
*
* @rparam table table
* @return number of elements
*/
static inline size_t uc_htable_count(const struct UHTable *table)
{
return table->cnt_elements;
}
/** Clears all nodes from the hash table, making it empty.
* No memory is released.
* @param table table to clear
*/
void uc_htable_clear(struct UHTable *table);
/** Insert a new node.
* The new node pointer must exist as long as it is part of the
* hash table. The hash table does not check for duplicates in any way.
*
* @param table table to insert into
* @param node new node to insert.
* @param hash hash value of the new node
*/
void uc_htable_insert(struct UHTable *table, struct UHNode *node, size_t hash);
/** Resize the hash table. This changes the number of buckets, and re-inserts
* all nodes.
*
* @param table table to resize
* @param buckets new number of buckets, must be > 0
* @return 0 on success, errno if malloc fails or buckets == 0
*/
int uc_htable_resize(struct UHTable *table, size_t buckets);
#endif