blob: 9815a6fa10f05740abf8464d972d15b7c2850c92 [file] [log] [blame]
/* libnih
*
* Copyright © 2009 Scott James Remnant <scott@netsplit.com>.
* Copyright © 2009 Canonical Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef NIH_HASH_H
#define NIH_HASH_H
/**
* Provides a generic hash table implementation using NihList for the bins,
* which means that entries may be freely moved between lists and hash
* tables.
*
* Members are identified by a constant key, which is used for both hashing
* and comparison. The key function takes a given member (referenced by
* its list head) and returns a pointer, this pointer is passed to the
* hash function for hashing and the comparison function for comparison.
*
* The key, hash and comparison function are given when creating the hash
* table with nih_hash_new().
*
* The most common use of this pointer is a string, generally a constant
* one found as the first member in the structure after the list head.
* For this case, you may use nih_hash_string_new() instead.
*
* Entries may be added to a hash table using nih_hash_add(), no assumption
* is made about whether duplicate entries are permitted or not. To add
* and fail if the entry already exists use nih_hash_add_unique(), to add
* and replace an existing entry use nih_hash_replace().
*
* The hash table may be iterated with nih_hash_search(), passing the return
* value to subsequent calls iterates all values with the given key.
*
* To lookup the first value nih_hash_lookup() is a convenient simpler
* function.
**/
#include <nih/macros.h>
#include <nih/list.h>
/**
* NihKeyFunction:
* @entry: entry to key.
*
* This function is used to obtain a constant key for a given table entry.
*
* Returns: constant key from entry.
**/
typedef const void *(*NihKeyFunction) (NihList *entry);
/**
* NihHashFunction:
* @key: key to hash.
*
* This function is used to generate a 32-bit hash for a given constant
* key, this will be bounded by the hash size automatically.
*
* Returns: 32-bit hash.
**/
typedef uint32_t (*NihHashFunction) (const void *key);
/**
* NihCmpFunction:
* @key1: key to compare,
* @key2: key to compare against.
*
* This function is used to compare constant keys from two given table
* entries.
*
* Returns: integer less than, equal to or greater than zero if @key1 is
* respectively less then, equal to or greater than @key2.
**/
typedef int (*NihCmpFunction) (const void *key1, const void *key2);
/**
* NihHash:
* @bins: array of bins,
* @size: size of bins array,
* @key_function: function used to obtain keys for entries,
* @hash_function: function used to obtain hash of keys,
* @cmp_function: function used to compare keys.
*
* This structure represents a hash table which is more efficient for
* looking up members than an ordinary list.
*
* Individual members of the hash table are NihList members as are the
* bins themselves, so to remove an entry from the table you can just
* use nih_list_remove().
**/
typedef struct nih_hash {
NihList *bins;
size_t size;
NihKeyFunction key_function;
NihHashFunction hash_function;
NihCmpFunction cmp_function;
} NihHash;
/**
* NIH_HASH_FOREACH:
* @hash: hash table to iterate,
* @iter: name of iterator variable.
*
* Expands to nested for statements that iterate over each entry in each
* bin of @hash, except the bin head pointer, setting @iter to each entry
* for the block within the loop. A variable named _@iter_i is used to
* iterate the hash bins.
*
* This is the cheapest form of iteration, however it is not safe to perform
* various modifications to the hash; most importantly, you must not change
* the member being iterated in any way, including removing it from the hash
* or freeing it. If you need to do that, use NIH_HASH_FOREACH_SAFE() instead.
*
* However since it doesn't modify the hash being iterated in any way, it
* is safe to traverse or iterate the hash again while iterating.
**/
#define NIH_HASH_FOREACH(hash, iter) \
for (size_t _##iter##_i = 0; _##iter##_i < (hash)->size; \
_##iter##_i++) \
NIH_LIST_FOREACH (&(hash)->bins[_##iter##_i], iter)
/**
* NIH_HASH_FOREACH_SAFE:
* @hash: hash table to iterate,
* @iter: name of iterator variable.
*
* Expans to nested for statements that iterate over each entry in each
* bin of @hash, except for the bin head pointer, setting @iter to each
* entry for the block within the loop. A variable named _@iter_i is used
* to iterate the hash bins.
*
* The iteration is performed safely by placing a cursor node after @iter;
* this means that any node including @iter can be removed from the hash,
* added to a different hash or list, or entries added before or after it.
*
* Note that if you add an entry directly after @iter and wish it to be
* visited, you would need to use NIH_HASH_FOREACH() instead, as this
* would be placed before the cursor and thus skipped.
*
* Also since the hash has an extra node during iteration of a different
* type, it is expressly not safe to traverse or iterate the hash while
* iterating - including performing lookups. If you need to perform
* multiple iterations, lookups, or reference the next or previous pointers
* of a node, you must use NIH_HASH_FOREACH().
**/
#define NIH_HASH_FOREACH_SAFE(hash, iter) \
for (size_t _##iter##_i = 0; _##iter##_i < (hash)->size; \
_##iter##_i++) \
NIH_LIST_FOREACH_SAFE (&(hash)->bins[_##iter##_i], iter)
/**
* nih_hash_string_new:
* @parent: parent of new hash,
* @entries: rough number of entries expected,
*
* Allocates a new hash table, the number of buckets selected is a prime
* number that is no larger than @entries; this should be set to a rough
* number of expected entries to ensure optimum distribution.
*
* Individual members of the hash table are NihList member which have
* a constant string as the first member that can be used as the hash key,
* these will be compared case sensitively.
*
* The structure is allocated using nih_alloc() so it can be used as a
* context to other allocations; there is no non-allocated version of this
* function because the hash must be usable as a parent context to its bins.
*
* If @parent is not NULL, it should be a pointer to another object which
* will be used as a parent for the returned hash table. When all parents
* of the returned hash table are freed, the returned hash table will also be
* freed.
*
* Returns: the new hash table or NULL if the allocation failed.
**/
#define nih_hash_string_new(parent, entries) \
nih_hash_new (parent, entries, \
(NihKeyFunction)nih_hash_string_key, \
(NihHashFunction)nih_hash_string_hash, \
(NihCmpFunction)nih_hash_string_cmp)
NIH_BEGIN_EXTERN
NihHash * nih_hash_new (const void *parent, size_t entries,
NihKeyFunction key_function,
NihHashFunction hash_function,
NihCmpFunction cmp_function)
__attribute__ ((warn_unused_result, malloc));
NihList * nih_hash_add (NihHash *hash, NihList *entry);
NihList * nih_hash_add_unique (NihHash *hash, NihList *entry);
NihList * nih_hash_replace (NihHash *hash, NihList *entry);
NihList * nih_hash_search (NihHash *hash, const void *key,
NihList *entry);
NihList * nih_hash_lookup (NihHash *hash, const void *key);
const char *nih_hash_string_key (NihList *entry);
uint32_t nih_hash_string_hash (const char *key);
int nih_hash_string_cmp (const char *key1, const char *key2);
NIH_END_EXTERN
#endif /* NIH_HASH_H */