nostrdb

an unfairly fast embedded nostr database backed by lmdb
git clone git://jb55.com/nostrdb
Log | Files | Refs | Submodules | README | LICENSE

htable_type.h (6681B)


      1 /* Licensed under LGPLv2+ - see LICENSE file for details */
      2 #ifndef CCAN_HTABLE_TYPE_H
      3 #define CCAN_HTABLE_TYPE_H
      4 #include <ccan/htable/htable.h>
      5 #include <ccan/compiler/compiler.h>
      6 #include "config.h"
      7 
      8 /**
      9  * HTABLE_DEFINE_TYPE - create a set of htable ops for a type
     10  * @type: a type whose pointers will be values in the hash.
     11  * @keyof: a function/macro to extract a key: <keytype> @keyof(const type *elem)
     12  * @hashfn: a hash function for a @key: size_t @hashfn(const <keytype> *)
     13  * @eqfn: an equality function keys: bool @eqfn(const type *, const <keytype> *)
     14  * @prefix: a prefix for all the functions to define (of form <name>_*)
     15  *
     16  * NULL values may not be placed into the hash table.
     17  *
     18  * This defines the type hashtable type and an iterator type:
     19  *	struct <name>;
     20  *	struct <name>_iter;
     21  *
     22  * It also defines initialization and freeing functions:
     23  *	void <name>_init(struct <name> *);
     24  *	bool <name>_init_sized(struct <name> *, size_t);
     25  *	void <name>_clear(struct <name> *);
     26  *	bool <name>_copy(struct <name> *dst, const struct <name> *src);
     27  *
     28  * Count entries:
     29  *	size_t <name>_count(const struct <name> *ht);
     30  *
     31  * Add function only fails if we run out of memory:
     32  *	bool <name>_add(struct <name> *ht, const <type> *e);
     33  *
     34  * Delete and delete-by key return true if it was in the set:
     35  *	bool <name>_del(struct <name> *ht, const <type> *e);
     36  *	bool <name>_delkey(struct <name> *ht, const <keytype> *k);
     37  *
     38  * Delete by iterator:
     39  *	bool <name>_delval(struct <name> *ht, struct <name>_iter *i);
     40  *
     41  * Find and return the (first) matching element, or NULL:
     42  *	type *<name>_get(const struct @name *ht, const <keytype> *k);
     43  *
     44  * Find and return all matching elements, or NULL:
     45  *	type *<name>_getfirst(const struct @name *ht, const <keytype> *k,
     46  *			      struct <name>_iter *i);
     47  *	type *<name>_getnext(const struct @name *ht, const <keytype> *k,
     48  *			     struct <name>_iter *i);
     49  *
     50  * Iteration over hashtable is also supported:
     51  *	type *<name>_first(const struct <name> *ht, struct <name>_iter *i);
     52  *	type *<name>_next(const struct <name> *ht, struct <name>_iter *i);
     53  *	type *<name>_prev(const struct <name> *ht, struct <name>_iter *i);
     54  *      type *<name>_pick(const struct <name> *ht, size_t seed,
     55  *                        struct <name>_iter *i);
     56  * It's currently safe to iterate over a changing hashtable, but you might
     57  * miss an element.  Iteration isn't very efficient, either.
     58  *
     59  * You can use HTABLE_INITIALIZER like so:
     60  *	struct <name> ht = { HTABLE_INITIALIZER(ht.raw, <name>_hash, NULL) };
     61  */
     62 #define HTABLE_DEFINE_TYPE(type, keyof, hashfn, eqfn, name)		\
     63 	struct name { struct htable raw; };				\
     64 	struct name##_iter { struct htable_iter i; };			\
     65 	static inline size_t name##_hash(const void *elem, void *priv)	\
     66 	{								\
     67 		(void)priv;						\
     68 		return hashfn(keyof((const type *)elem));		\
     69 	}								\
     70 	static inline UNNEEDED void name##_init(struct name *ht)	\
     71 	{								\
     72 		htable_init(&ht->raw, name##_hash, NULL);		\
     73 	}								\
     74 	static inline UNNEEDED bool name##_init_sized(struct name *ht,	\
     75 						      size_t s)		\
     76 	{								\
     77 		return htable_init_sized(&ht->raw, name##_hash, NULL, s); \
     78 	}								\
     79 	static inline UNNEEDED size_t name##_count(const struct name *ht) \
     80 	{								\
     81 		return htable_count(&ht->raw);				\
     82 	}								\
     83 	static inline UNNEEDED void name##_clear(struct name *ht)	\
     84 	{								\
     85 		htable_clear(&ht->raw);					\
     86 	}								\
     87 	static inline UNNEEDED bool name##_copy(struct name *dst,	\
     88 						const struct name *src)	\
     89 	{								\
     90 		return htable_copy(&dst->raw, &src->raw);		\
     91 	}								\
     92 	static inline bool name##_add(struct name *ht, const type *elem) \
     93 	{								\
     94 		return htable_add(&ht->raw, hashfn(keyof(elem)), elem);	\
     95 	}								\
     96 	static inline UNNEEDED bool name##_del(struct name *ht,		\
     97 					       const type *elem)	\
     98 	{								\
     99 		return htable_del(&ht->raw, hashfn(keyof(elem)), elem);	\
    100 	}								\
    101 	static inline UNNEEDED type *name##_get(const struct name *ht,	\
    102 				       const HTABLE_KTYPE(keyof, type) k) \
    103 	{								\
    104 		struct htable_iter i;					\
    105 		size_t h = hashfn(k);					\
    106 		void *c;						\
    107 									\
    108 		for (c = htable_firstval(&ht->raw,&i,h);		\
    109 		     c;							\
    110 		     c = htable_nextval(&ht->raw,&i,h)) {		\
    111 			if (eqfn(c, k))					\
    112 				return c;				\
    113 		}							\
    114 		return NULL;						\
    115 	}								\
    116 	static inline UNNEEDED type *name##_getmatch_(const struct name *ht, \
    117 				         const HTABLE_KTYPE(keyof, type) k, \
    118 				         size_t h,			\
    119 				         type *v,			\
    120 					 struct name##_iter *iter)	\
    121 	{								\
    122 		while (v) {						\
    123 			if (eqfn(v, k))					\
    124 				break;					\
    125 			v = htable_nextval(&ht->raw, &iter->i, h);	\
    126 		}							\
    127 		return v;						\
    128 	}								\
    129 	static inline UNNEEDED type *name##_getfirst(const struct name *ht, \
    130 				         const HTABLE_KTYPE(keyof, type) k, \
    131 					 struct name##_iter *iter)	\
    132 	{								\
    133 		size_t h = hashfn(k);					\
    134 		type *v = htable_firstval(&ht->raw, &iter->i, h);	\
    135 		return name##_getmatch_(ht, k, h, v, iter);			\
    136 	}								\
    137 	static inline UNNEEDED type *name##_getnext(const struct name *ht, \
    138 				         const HTABLE_KTYPE(keyof, type) k, \
    139 					 struct name##_iter *iter)	\
    140 	{								\
    141 		size_t h = hashfn(k);					\
    142 		type *v = htable_nextval(&ht->raw, &iter->i, h);	\
    143 		return name##_getmatch_(ht, k, h, v, iter);		\
    144 	}								\
    145 	static inline UNNEEDED bool name##_delkey(struct name *ht,	\
    146 					 const HTABLE_KTYPE(keyof, type) k) \
    147 	{								\
    148 		type *elem = name##_get(ht, k);				\
    149 		if (elem)						\
    150 			return name##_del(ht, elem);			\
    151 		return false;						\
    152 	}								\
    153 	static inline UNNEEDED void name##_delval(struct name *ht,	\
    154 						  struct name##_iter *iter) \
    155 	{								\
    156 		htable_delval(&ht->raw, &iter->i);			\
    157 	}								\
    158 	static inline UNNEEDED type *name##_pick(const struct name *ht,	\
    159 						size_t seed,		\
    160 						struct name##_iter *iter) \
    161 	{								\
    162 		return htable_pick(&ht->raw, seed, iter ? &iter->i : NULL); \
    163 	}								\
    164 	static inline UNNEEDED type *name##_first(const struct name *ht, \
    165 					 struct name##_iter *iter)	\
    166 	{								\
    167 		return htable_first(&ht->raw, &iter->i);		\
    168 	}								\
    169 	static inline UNNEEDED type *name##_next(const struct name *ht,	\
    170 					struct name##_iter *iter)	\
    171 	{								\
    172 		return htable_next(&ht->raw, &iter->i);			\
    173 	}								\
    174 	static inline UNNEEDED type *name##_prev(const struct name *ht,	\
    175 					struct name##_iter *iter)	\
    176 	{								\
    177 		return htable_prev(&ht->raw, &iter->i);			\
    178 	}
    179 
    180 #if HAVE_TYPEOF
    181 #define HTABLE_KTYPE(keyof, type) typeof(keyof((const type *)NULL))
    182 #else
    183 /* Assumes keys are a pointer: if not, override. */
    184 #ifndef HTABLE_KTYPE
    185 #define HTABLE_KTYPE(keyof, type) void *
    186 #endif
    187 #endif
    188 #endif /* CCAN_HTABLE_TYPE_H */