Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactoring the header and source file documentation #26

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 0 additions & 40 deletions hashmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@ static void *(*_malloc)(size_t) = NULL;
static void *(*_realloc)(void *, size_t) = NULL;
static void (*_free)(void *) = NULL;

// hashmap_set_allocator allows for configuring a custom allocator for
// all hashmap library operations. This function, if needed, should be called
// only once at startup and a prior to calling hashmap_new().
void hashmap_set_allocator(void *(*malloc)(size_t), void (*free)(void*))
{
_malloc = malloc;
Expand Down Expand Up @@ -135,23 +132,6 @@ struct hashmap *hashmap_new_with_allocator(
}


// hashmap_new returns a new hash map.
// Param `elsize` is the size of each element in the tree. Every element that
// is inserted, deleted, or retrieved will be this size.
// Param `cap` is the default lower capacity of the hashmap. Setting this to
// zero will default to 16.
// Params `seed0` and `seed1` are optional seed values that are passed to the
// following `hash` function. These can be any value you wish but it's often
// best to use randomly generated values.
// Param `hash` is a function that generates a hash value for an item. It's
// important that you provide a good hash function, otherwise it will perform
// poorly or be vulnerable to Denial-of-service attacks. This implementation
// comes with two helper functions `hashmap_sip()` and `hashmap_murmur()`.
// Param `compare` is a function that compares items in the tree. See the
// qsort stdlib function for an example of how this function works.
// The hashmap must be freed with hashmap_free().
// Param `elfree` is a function that frees a specific item. This should be NULL
// unless you're storing some kind of reference data in the hash.
struct hashmap *hashmap_new(size_t elsize, size_t cap,
uint64_t seed0, uint64_t seed1,
uint64_t (*hash)(const void *item,
Expand Down Expand Up @@ -179,12 +159,6 @@ static void free_elements(struct hashmap *map) {
}


// hashmap_clear quickly clears the map.
// Every item is called with the element-freeing function given in hashmap_new,
// if present, to free any data referenced in the elements of the hashmap.
// When the update_cap is provided, the map's capacity will be updated to match
// the currently number of allocated buckets. This is an optimization to ensure
// that this operation does not perform any allocations.
void hashmap_clear(struct hashmap *map, bool update_cap) {
map->count = 0;
free_elements(map);
Expand Down Expand Up @@ -245,10 +219,6 @@ static bool resize(struct hashmap *map, size_t new_cap) {
return true;
}

// hashmap_set inserts or replaces an item in the hash map. If an item is
// replaced then it is returned otherwise NULL is returned. This operation
// may allocate memory. If the system is unable to allocate additional
// memory then NULL is returned and hashmap_oom() returns true.
void *hashmap_set(struct hashmap *map, const void *item) {
if (!item) {
panic("item is null");
Expand Down Expand Up @@ -293,8 +263,6 @@ void *hashmap_set(struct hashmap *map, const void *item) {
}
}

// hashmap_get returns the item based on the provided key. If the item is not
// found then NULL is returned.
void *hashmap_get(struct hashmap *map, const void *key) {
if (!key) {
panic("key is null");
Expand All @@ -315,9 +283,6 @@ void *hashmap_get(struct hashmap *map, const void *key) {
}
}

// hashmap_probe returns the item in the bucket at position or NULL if an item
// is not set for that bucket. The position is 'moduloed' by the number of
// buckets in the hashmap.
void *hashmap_probe(struct hashmap *map, uint64_t position) {
size_t i = position & map->mask;
struct bucket *bucket = bucket_at(map, i);
Expand All @@ -328,8 +293,6 @@ void *hashmap_probe(struct hashmap *map, uint64_t position) {
}


// hashmap_delete removes an item from the hash map and returns it. If the
// item is not found then NULL is returned.
void *hashmap_delete(struct hashmap *map, void *key) {
if (!key) {
panic("key is null");
Expand Down Expand Up @@ -371,7 +334,6 @@ void *hashmap_delete(struct hashmap *map, void *key) {
}
}

// hashmap_count returns the number of items in the hash map.
size_t hashmap_count(struct hashmap *map) {
return map->count;
}
Expand Down Expand Up @@ -596,14 +558,12 @@ static void MM86128(const void *key, const int len, uint32_t seed, void *out) {
((uint32_t*)out)[3] = h4;
}

// hashmap_sip returns a hash value for `data` using SipHash-2-4.
uint64_t hashmap_sip(const void *data, size_t len,
uint64_t seed0, uint64_t seed1)
{
return SIP64((uint8_t*)data, len, seed0, seed1);
}

// hashmap_murmur returns a hash value for `data` using Murmur3_86_128.
uint64_t hashmap_murmur(const void *data, size_t len,
uint64_t seed0, uint64_t seed1)
{
Expand Down
149 changes: 131 additions & 18 deletions hashmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,45 +11,158 @@

struct hashmap;

struct hashmap *hashmap_new(size_t elsize, size_t cap,
/**
* @brief Create a new hashmap
*
* @param elsize The size of each element in the tree. Every element that is inserted, deleted or retreived will be this size.
* @param cap The default lower capacity of the hashmap. Setting this to zero will default to 16.
* @param seed0 Value passed to the following `hash` function. These can be any value you wish but it's often best to use randomly generated values.(Optional)
* @param seed1 Value passed to the following `hash` function. These can be any value you wish but it's often best to use randomly generated values.(Optional)
* @param hash Function that generate a hash value for an item.
* @param compare Function that compare items in the tree.
* @param elfree Function that frees a specific item. This should be NULL unless sorting some kind of reference data in the hash
* @param udata
*
* @note It's important to provide a good hash function, otherwise it will perform poorly or be vulnerable to Denial-of-service attacks.
* @note This implementation comes with two helper functions `hashmap_sip()` and `hashmap_murmur().
* @return New hashmap
*
*/
struct hashmap *hashmap_new(size_t elsize, size_t cap,
uint64_t seed0, uint64_t seed1,
uint64_t (*hash)(const void *item,
uint64_t (*hash)(const void *item,
uint64_t seed0, uint64_t seed1),
int (*compare)(const void *a, const void *b,
int (*compare)(const void *a, const void *b,
void *udata),
void (*elfree)(void *item),
void *udata);

/**
* @brief Crate a new hash map using a custom allocator
*
* @note See hashmap_new for more information
* @return struct hashmap*
*/
struct hashmap *hashmap_new_with_allocator(
void *(*malloc)(size_t),
void *(*realloc)(void *, size_t),
void (*free)(void*),
size_t elsize, size_t cap,
uint64_t seed0, uint64_t seed1,
uint64_t (*hash)(const void *item,
uint64_t seed0, uint64_t seed1),
int (*compare)(const void *a, const void *b,
void *udata),
void (*elfree)(void *item),
void *udata);
void *(*malloc)(size_t),
void *(*realloc)(void *, size_t),
void (*free)(void *),
size_t elsize, size_t cap,
uint64_t seed0, uint64_t seed1,
uint64_t (*hash)(const void *item,
uint64_t seed0, uint64_t seed1),
int (*compare)(const void *a, const void *b,
void *udata),
void (*elfree)(void *item),
void *udata);

/**
* @brief Free the hash map after usage
*
* @param map Pointer to the hash map to be freed
*/
void hashmap_free(struct hashmap *map);

/**
* @brief Quicly clears the map.
*
* @param map Hash map to be cleared
* @param update_cap If provided the map's capacity will be updated to match the currently number of allocated buckets.
* @note This is an optimization to ensure that this operation does not perform any allocations.
*/
void hashmap_clear(struct hashmap *map, bool update_cap);

/**
* @brief
*
* @param map Hash map to get the size of.
* @return Return the number of items in the hash map
*/
size_t hashmap_count(struct hashmap *map);

/**
* @brief Function that checks for memeory when using the hashmap_set() function.
*
* @param map Hash map in the subject
* @return true if the last hashmap_set() call failed due to memory leak.
* @return false if the last hashmap_set() call is successful.
*/
bool hashmap_oom(struct hashmap *map);

/**
* @brief Get the item based on the provided key
*
* @param map Hash map to look in it
* @param item Item to look for in the provided hash map
* @return NULL if the item is not found
*/
void *hashmap_get(struct hashmap *map, const void *item);

/**
* @brief Insert or replace an item in the hash map.
*
* @param map Hash map to insert into.
* @param item Item to be inserted.
* @return If item is replaced it is returned else NULL
* @note If the system is unable to allocate memory then NULL is returned and the hashmap_oom() return true.
*/
void *hashmap_set(struct hashmap *map, const void *item);

/**
* @brief Remove an item from the hash map
*
* @param map Hash map to delete from.
* @param item Item to delete from the hash map.
* @return Item removed from the hash map. If not found returns NULL
*/
void *hashmap_delete(struct hashmap *map, void *item);

/**
* @brief Returns the item in the bucket at position or NULL if an item is not set for that bucket.
*
* @param map Hash map to look in it.
* @param position Index of the element to extract.
*/
void *hashmap_probe(struct hashmap *map, uint64_t position);

/**
* @brief Iterates over all items in the hash map.
*
* @param map Hash map to iterate over
* @param iter Can return false to stop iteration early.
* @param udata
* @return true if the iteration is fully completed, false if the iteration is stopped early.
*/
bool hashmap_scan(struct hashmap *map,
bool (*iter)(const void *item, void *udata), void *udata);

/**
* @brief iterates one key at a time yielding a reference to an
entry at each iteration. Useful to write simple loops and avoid writing
dedicated callbacks and udata structures, as in hashmap_scan.
*
* @param map Hash map handle
* @param i Pointer to a size_t cursor that should be initialized to 0 at the beginning of the loop.
* @param item Void pointer pointer that is populated with the retrieved item.
* @return true if an item was received
* @return false if the end of the iteration was reached.
*/
bool hashmap_iter(struct hashmap *map, size_t *i, void **item);

uint64_t hashmap_sip(const void *data, size_t len,
/**
* @brief Return a hash value for `data` using SipHash-2-4
*
*/
uint64_t hashmap_sip(const void *data, size_t len,
uint64_t seed0, uint64_t seed1);
uint64_t hashmap_murmur(const void *data, size_t len,
uint64_t seed0, uint64_t seed1);

/**
* @brief Returns a hash value for `data` using Murmur3_86_128.
*/
uint64_t hashmap_murmur(const void *data, size_t len,
uint64_t seed0, uint64_t seed1);

// DEPRECATED: use `hashmap_new_with_allocator`
void hashmap_set_allocator(void *(*malloc)(size_t), void (*free)(void*));
void hashmap_set_allocator(void *(*malloc)(size_t), void (*free)(void *));

#endif