X-Git-Url: http://git.ozlabs.org/?p=ccan;a=blobdiff_plain;f=ccan%2Fhtable%2Fhtable_type.h;h=14011676903807fed252318ef5884b55f14e9556;hp=6fe05e2fd8de9bf837451c1ba745b993e0e1c566;hb=e0b86f0ca416d757684e6d98532e1fadf839b830;hpb=198d85adf5e8d9a44b7436bdd046dbffce66b23a diff --git a/ccan/htable/htable_type.h b/ccan/htable/htable_type.h index 6fe05e2f..14011676 100644 --- a/ccan/htable/htable_type.h +++ b/ccan/htable/htable_type.h @@ -1,97 +1,166 @@ +/* Licensed under LGPLv2+ - see LICENSE file for details */ #ifndef CCAN_HTABLE_TYPE_H #define CCAN_HTABLE_TYPE_H #include +#include #include "config.h" /** * HTABLE_DEFINE_TYPE - create a set of htable ops for a type * @type: a type whose pointers will be values in the hash. - * @keyof: a function/macro to extract a key from a @type element. - * @hashfn: a hash function for a @key - * @cmpfn: a comparison function for two keyof()s. - * @name: a name for all the functions to define (of form htable__*) + * @keyof: a function/macro to extract a key: @keyof(const type *elem) + * @hashfn: a hash function for a @key: size_t @hashfn(const *) + * @eqfn: an equality function keys: bool @eqfn(const type *, const *) + * @prefix: a prefix for all the functions to define (of form _*) * * NULL values may not be placed into the hash table. * - * The following wrapper functions are defined; each one is a - * simplified version of the htable.h equivalent: + * This defines the type hashtable type and an iterator type: + * struct ; + * struct _iter; * - * // Creating and freeing. - * struct htable_@name *htable_@name_new(void); - * void htable_@name_free(const struct htable_@name *ht); + * It also defines initialization and freeing functions: + * void _init(struct *); + * bool _init_sized(struct *, size_t); + * void _clear(struct *); + * bool _copy(struct *dst, const struct *src); * - * // Add, delete and find. - * bool htable_@name_add(struct htable_@name *ht, const type *e); - * bool htable_@name_del(struct htable_@name *ht, const type *e); - * bool htable_@name_delkey(struct htable_@name *ht, const ktype *k); - * type *htable_@name_get(const struct htable_@name *ht, const ktype *k); + * Add function only fails if we run out of memory: + * bool _add(struct *ht, const *e); * - * // Iteration. - * struct htable_@name_iter; - * type *htable_@name_first(const struct htable_@name *ht, - * struct htable_@name_iter *i); - * type *htable_@name_next(const struct htable_@name *ht, - * struct htable_@name_iter *i); + * Delete and delete-by key return true if it was in the set: + * bool _del(struct *ht, const *e); + * bool _delkey(struct *ht, const *k); + * + * Find and return the (first) matching element, or NULL: + * type *_get(const struct @name *ht, const *k); + * + * Find and return all matching elements, or NULL: + * type *_getfirst(const struct @name *ht, const *k, + * struct _iter *i); + * type *_getnext(const struct @name *ht, const *k, + * struct _iter *i); + * + * Iteration over hashtable is also supported: + * type *_first(const struct *ht, struct _iter *i); + * type *_next(const struct *ht, struct _iter *i); + * type *_prev(const struct *ht, struct _iter *i); + * + * It's currently safe to iterate over a changing hashtable, but you might + * miss an element. Iteration isn't very efficient, either. + * + * You can use HTABLE_INITIALIZER like so: + * struct ht = { HTABLE_INITIALIZER(ht.raw, _hash, NULL) }; */ -#define HTABLE_DEFINE_TYPE(type, keyof, hashfn, cmpfn, name) \ -struct htable_##name; \ -struct htable_##name##_iter { struct htable_iter i; }; \ -static inline size_t htable_##name##_hash(const void *elem, void *priv) \ -{ \ - return hashfn(keyof((const type *)elem)); \ -} \ -static inline struct htable_##name *htable_##name##_new(void) \ -{ \ - return (struct htable_##name *)htable_new(htable_##name##_hash, \ - NULL); \ -} \ -static inline void htable_##name##_free(const struct htable_##name *ht) \ -{ \ - htable_free((const struct htable *)ht); \ -} \ -static inline bool htable_##name##_add(struct htable_##name *ht, \ - const type *elem) \ -{ \ - return htable_add((struct htable *)ht, hashfn(keyof(elem)), elem); \ -} \ -static inline bool htable_##name##_del(const struct htable_##name *ht, \ - const type *elem) \ -{ \ - return htable_del((struct htable *)ht, hashfn(keyof(elem)), elem); \ -} \ -static inline type *htable_##name##_get(const struct htable_##name *ht, \ - const HTABLE_KTYPE(keyof) k) \ -{ \ - /* Typecheck for cmpfn */ \ - (void)sizeof(cmpfn(keyof((const type *)NULL), \ - keyof((const type *)NULL))); \ - return (type *)htable_get((const struct htable *)ht, \ - hashfn(k), \ - (bool (*)(const void *, void *))(cmpfn), \ - k); \ -} \ -static inline bool htable_##name##_delkey(struct htable_##name *ht, \ - const HTABLE_KTYPE(keyof) k) \ -{ \ - type *elem = htable_##name##_get(ht, k); \ - if (elem) \ - return htable_##name##_del(ht, elem); \ - return false; \ -} \ -static inline type *htable_##name##_first(const struct htable_##name *ht, \ - struct htable_##name##_iter *iter) \ -{ \ - return htable_first((const struct htable *)ht, &iter->i); \ -} \ -static inline type *htable_##name##_next(const struct htable_##name *ht, \ - struct htable_##name##_iter *iter) \ -{ \ - return htable_next((const struct htable *)ht, &iter->i); \ -} +#define HTABLE_DEFINE_TYPE(type, keyof, hashfn, eqfn, name) \ + struct name { struct htable raw; }; \ + struct name##_iter { struct htable_iter i; }; \ + static inline size_t name##_hash(const void *elem, void *priv) \ + { \ + (void)priv; \ + return hashfn(keyof((const type *)elem)); \ + } \ + static inline UNNEEDED void name##_init(struct name *ht) \ + { \ + htable_init(&ht->raw, name##_hash, NULL); \ + } \ + static inline UNNEEDED bool name##_init_sized(struct name *ht, \ + size_t s) \ + { \ + return htable_init_sized(&ht->raw, name##_hash, NULL, s); \ + } \ + static inline UNNEEDED void name##_clear(struct name *ht) \ + { \ + htable_clear(&ht->raw); \ + } \ + static inline UNNEEDED bool name##_copy(struct name *dst, \ + const struct name *src) \ + { \ + return htable_copy(&dst->raw, &src->raw); \ + } \ + static inline bool name##_add(struct name *ht, const type *elem) \ + { \ + return htable_add(&ht->raw, hashfn(keyof(elem)), elem); \ + } \ + static inline UNNEEDED bool name##_del(struct name *ht, \ + const type *elem) \ + { \ + return htable_del(&ht->raw, hashfn(keyof(elem)), elem); \ + } \ + static inline UNNEEDED type *name##_get(const struct name *ht, \ + const HTABLE_KTYPE(keyof, type) k) \ + { \ + struct htable_iter i; \ + size_t h = hashfn(k); \ + void *c; \ + \ + for (c = htable_firstval(&ht->raw,&i,h); \ + c; \ + c = htable_nextval(&ht->raw,&i,h)) { \ + if (eqfn(c, k)) \ + return c; \ + } \ + return NULL; \ + } \ + static inline UNNEEDED type *name##_getmatch_(const struct name *ht, \ + const HTABLE_KTYPE(keyof, type) k, \ + size_t h, \ + type *v, \ + struct name##_iter *iter) \ + { \ + while (v) { \ + if (eqfn(v, k)) \ + break; \ + v = htable_nextval(&ht->raw, &iter->i, h); \ + } \ + return v; \ + } \ + static inline UNNEEDED type *name##_getfirst(const struct name *ht, \ + const HTABLE_KTYPE(keyof, type) k, \ + struct name##_iter *iter) \ + { \ + size_t h = hashfn(k); \ + type *v = htable_firstval(&ht->raw, &iter->i, h); \ + return name##_getmatch_(ht, k, h, v, iter); \ + } \ + static inline UNNEEDED type *name##_getnext(const struct name *ht, \ + const HTABLE_KTYPE(keyof, type) k, \ + struct name##_iter *iter) \ + { \ + size_t h = hashfn(k); \ + type *v = htable_nextval(&ht->raw, &iter->i, h); \ + return name##_getmatch_(ht, k, h, v, iter); \ + } \ + static inline UNNEEDED bool name##_delkey(struct name *ht, \ + const HTABLE_KTYPE(keyof, type) k) \ + { \ + type *elem = name##_get(ht, k); \ + if (elem) \ + return name##_del(ht, elem); \ + return false; \ + } \ + static inline UNNEEDED type *name##_first(const struct name *ht, \ + struct name##_iter *iter) \ + { \ + return htable_first(&ht->raw, &iter->i); \ + } \ + static inline UNNEEDED type *name##_next(const struct name *ht, \ + struct name##_iter *iter) \ + { \ + return htable_next(&ht->raw, &iter->i); \ + } \ + static inline UNNEEDED type *name##_prev(const struct name *ht, \ + struct name##_iter *iter) \ + { \ + return htable_prev(&ht->raw, &iter->i); \ + } #if HAVE_TYPEOF -#define HTABLE_KTYPE(keyof) typeof(keyof(NULL)) +#define HTABLE_KTYPE(keyof, type) typeof(keyof((const type *)NULL)) #else -#define HTABLE_KTYPE(keyof) void * +/* Assumes keys are a pointer: if not, override. */ +#ifndef HTABLE_KTYPE +#define HTABLE_KTYPE(keyof, type) void * +#endif #endif #endif /* CCAN_HTABLE_TYPE_H */