blob: f9894631df28638117e1ce7a288ff5e98f82c601 [file] [log] [blame]
/* Copyright (C) 2002, 2004 Christopher Clark <firstname.lastname@cl.cam.ac.uk>
*
* Modified 2009 by Barret Rhoden <brho@cs.berkeley.edu>
* Changes include:
* - No longer frees keys or values. It's up to the client to do that.
* - Provides common hash and equality functions (meant for longs)
* - Uses the slab allocator for hash entry allocation.
* - Merges the iterator code with the main hash table code, mostly to avoid
* externing the hentry cache.
* - hash for each */
#pragma once
#include <ros/common.h>
/*****************************************************************************/
typedef struct hash_entry
{
void *k, *v;
size_t h;
struct hash_entry *next;
} hash_entry_t;
typedef struct hashtable {
size_t tablelength;
hash_entry_t **table;
size_t entrycount;
size_t loadlimit;
size_t primeindex;
size_t (*hashfn) (void *k);
ssize_t (*eqfn) (void *k1, void *k2);
} hashtable_t;
static inline size_t indexFor(unsigned int tablelength, unsigned int hashvalue)
{
return (hashvalue % tablelength);
};
/*****************************************************************************/
/* Example of use:
* hashtable_init(); // Do this once during kernel initialization
*
* struct hashtable *h;
* struct some_key *k;
* struct some_value *v;
*
* static size_t hash_from_key_fn( void *k );
* static ssize_t keys_equal_fn ( void *key1, void *key2 );
*
* h = create_hashtable(16, hash_from_key_fn, keys_equal_fn);
* k = (struct some_key *) kmalloc(sizeof(struct some_key));
* v = (struct some_value *) kmalloc(sizeof(struct some_value));
*
* (initialise k and v to suitable values)
*
* if (! hashtable_insert(h,k,v) )
* { panic("Hashtable broken...\n"); }
*
* if (NULL == (found = hashtable_search(h,k) ))
* { printk("not found!"); }
*
* if (NULL == (found = hashtable_remove(h,k) ))
* { printk("Not found\n"); }
*
*/
/* Macros may be used to define type-safe(r) hashtable access functions, with
* methods specialized to take known key and value types as parameters.
*
* Example:
*
* Insert this at the start of your file:
*
* DEFINE_HASHTABLE_INSERT(insert_some, struct some_key, struct some_value);
* DEFINE_HASHTABLE_SEARCH(search_some, struct some_key, struct some_value);
* DEFINE_HASHTABLE_REMOVE(remove_some, struct some_key, struct some_value);
*
* This defines the functions 'insert_some', 'search_some' and 'remove_some'.
* These operate just like hashtable_insert etc., with the same parameters,
* but their function signatures have 'struct some_key *' rather than
* 'void *', and hence can generate compile time errors if your program is
* supplying incorrect data as a key (and similarly for value).
*
* Note that the hash and key equality functions passed to create_hashtable
* still take 'void *' parameters instead of 'some key *'. This shouldn't be
* a difficult issue as they're only defined and passed once, and the other
* functions will ensure that only valid keys are supplied to them.
*
* The cost for this checking is increased code size and runtime overhead
* - if performance is important, it may be worth switching back to the
* unsafe methods once your program has been debugged with the safe methods.
* This just requires switching to some simple alternative defines - eg:
* #define insert_some hashtable_insert
*
*/
/* Call this once on bootup, after initializing the slab allocator. */
void hashtable_init(void);
/* Common hash/equals functions. Don't call these directly. */
size_t __generic_hash(void *k);
ssize_t __generic_eq(void *k1, void *k2);
/*****************************************************************************
* create_hashtable
* @name create_hashtable
* @param minsize minimum initial size of hashtable
* @param hashfunction function for hashing keys
* @param key_eq_fn function for determining key equality
* @return newly created hashtable or NULL on failure
*/
hashtable_t *
create_hashtable(size_t minsize,
size_t (*hashfunction) (void*),
ssize_t (*key_eq_fn) (void*,void*));
/*****************************************************************************
* hashtable_insert
* @name hashtable_insert
* @param h the hashtable to insert into
* @param k the key
* @param v the value
* @return non-zero for successful insertion
*
* This function will cause the table to expand if the insertion would take
* the ratio of entries to table size over the maximum load factor.
*
* This function does not check for repeated insertions with a duplicate key.
* The value returned when using a duplicate key is undefined -- when
* the hashtable changes size, the order of retrieval of duplicate key
* entries is reversed.
* If in doubt, remove before insert.
*/
ssize_t
hashtable_insert(hashtable_t *h, void *k, void *v);
#define DEFINE_HASHTABLE_INSERT(fnname, keytype, valuetype) \
ssize_t fnname (hashtable_t *h, keytype *k, valuetype *v) \
{ \
return hashtable_insert(h,k,v); \
}
/*****************************************************************************
* hashtable_search
* @name hashtable_search
* @param h the hashtable to search
* @param k the key to search for
* @return the value associated with the key, or NULL if none found
*/
void *
hashtable_search(hashtable_t *h, void *k);
#define DEFINE_HASHTABLE_SEARCH(fnname, keytype, valuetype) \
valuetype * fnname (hashtable_t *h, keytype *k) \
{ \
return (valuetype *) (hashtable_search(h,k)); \
}
/*****************************************************************************
* hashtable_remove
* @name hashtable_remove
* @param h the hashtable to remove the item from
* @param k the key to search for
* @return the value associated with the key, or NULL if none found
*
* Caller ought to free the key, if appropriate.
*/
void * /* returns value */
hashtable_remove(hashtable_t *h, void *k);
#define DEFINE_HASHTABLE_REMOVE(fnname, keytype, valuetype) \
valuetype * fnname (hashtable_t *h, keytype *k) \
{ \
return (valuetype *) (hashtable_remove(h,k)); \
}
/*****************************************************************************
* hashtable_count
* @name hashtable_count
* @param h the hashtable
* @return the number of items stored in the hashtable
*/
size_t
hashtable_count(hashtable_t *h);
/*****************************************************************************
* hashtable_destroy
* @name hashtable_destroy
* @param h the hashtable
*
* This will not free the values or the keys. Each user of the hashtable may
* have a different way of freeing (such as the slab allocator, kfree, or
* nothing (key is just an integer)).
*
* If the htable isn't empty, you ought to iterate through and destroy manually.
* This will warn if you try to destroy an non-empty htable.
*/
void
hashtable_destroy(hashtable_t *h);
/***************************** Hashtable Iterator ****************************/
/*****************************************************************************/
/* This struct is only concrete here to allow the inlining of two of the
* accessor functions. */
typedef struct hashtable_itr {
hashtable_t *h;
hash_entry_t *e;
hash_entry_t *parent;
size_t index;
} hashtable_itr_t;
/*****************************************************************************/
/* hashtable_iterator. Be sure to kfree this when you are done.
*/
hashtable_itr_t *
hashtable_iterator(hashtable_t *h);
/*****************************************************************************/
/* hashtable_iterator_key
* - return the key of the (key,value) pair at the current position
*
* Keep this in sync with the non-externed version in the .c */
extern inline void *
hashtable_iterator_key(hashtable_itr_t *i)
{
return i->e->k;
}
/*****************************************************************************/
/* value - return the value of the (key,value) pair at the current position
*
* Keep this in sync with the non-externed version in the .c */
extern inline void *
hashtable_iterator_value(hashtable_itr_t *i)
{
return i->e->v;
}
/*****************************************************************************/
/* advance - advance the iterator to the next element
* returns zero if advanced to end of table */
ssize_t
hashtable_iterator_advance(hashtable_itr_t *itr);
/*****************************************************************************/
/* remove - remove current element and advance the iterator to the next element
* NB: if you need the key or value to free it, read it before
* removing. ie: beware memory leaks! this will not remove the key.
* returns zero if advanced to end of table */
ssize_t
hashtable_iterator_remove(hashtable_itr_t *itr);
/*****************************************************************************/
/* search - overwrite the supplied iterator, to point to the entry
* matching the supplied key.
* h points to the hashtable to be searched.
* returns zero if not found. */
ssize_t
hashtable_iterator_search(hashtable_itr_t *itr,
hashtable_t *h, void *k);
#define DEFINE_HASHTABLE_ITERATOR_SEARCH(fnname, keytype) \
ssize_t fnname (hashtable_itr_t *i, hashtable_t *h, keytype *k) \
{ \
return (hashtable_iterator_search(i,h,k)); \
}
/* Runs func on each member of the hash table */
void hash_for_each(struct hashtable *hash, void func(void *, void *),
void *opaque);
/* Same, but removes the item too */
void hash_for_each_remove(struct hashtable *hash, void func(void *, void *),
void *opaque);
/*
* Copyright (c) 2002, 2004, Christopher Clark
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of the original author; nor the names of any contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/