hashmap.h 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. /* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
  2. /*
  3. * Generic non-thread safe hash map implementation.
  4. *
  5. * Copyright (c) 2019 Facebook
  6. */
  7. #ifndef __LIBBPF_HASHMAP_H
  8. #define __LIBBPF_HASHMAP_H
  9. #include <stdbool.h>
  10. #include <stddef.h>
  11. #include <limits.h>
  12. static inline size_t hash_bits(size_t h, int bits)
  13. {
  14. /* shuffle bits and return requested number of upper bits */
  15. if (bits == 0)
  16. return 0;
  17. #if (__SIZEOF_SIZE_T__ == __SIZEOF_LONG_LONG__)
  18. /* LP64 case */
  19. return (h * 11400714819323198485llu) >> (__SIZEOF_LONG_LONG__ * 8 - bits);
  20. #elif (__SIZEOF_SIZE_T__ <= __SIZEOF_LONG__)
  21. return (h * 2654435769lu) >> (__SIZEOF_LONG__ * 8 - bits);
  22. #else
  23. # error "Unsupported size_t size"
  24. #endif
  25. }
  26. /* generic C-string hashing function */
  27. static inline size_t str_hash(const char *s)
  28. {
  29. size_t h = 0;
  30. while (*s) {
  31. h = h * 31 + *s;
  32. s++;
  33. }
  34. return h;
  35. }
  36. typedef size_t (*hashmap_hash_fn)(long key, void *ctx);
  37. typedef bool (*hashmap_equal_fn)(long key1, long key2, void *ctx);
  38. /*
  39. * Hashmap interface is polymorphic, keys and values could be either
  40. * long-sized integers or pointers, this is achieved as follows:
  41. * - interface functions that operate on keys and values are hidden
  42. * behind auxiliary macros, e.g. hashmap_insert <-> hashmap__insert;
  43. * - these auxiliary macros cast the key and value parameters as
  44. * long or long *, so the user does not have to specify the casts explicitly;
  45. * - for pointer parameters (e.g. old_key) the size of the pointed
  46. * type is verified by hashmap_cast_ptr using _Static_assert;
  47. * - when iterating using hashmap__for_each_* forms
  48. * hasmap_entry->key should be used for integer keys and
  49. * hasmap_entry->pkey should be used for pointer keys,
  50. * same goes for values.
  51. */
  52. struct hashmap_entry {
  53. union {
  54. long key;
  55. const void *pkey;
  56. };
  57. union {
  58. long value;
  59. void *pvalue;
  60. };
  61. struct hashmap_entry *next;
  62. };
  63. struct hashmap {
  64. hashmap_hash_fn hash_fn;
  65. hashmap_equal_fn equal_fn;
  66. void *ctx;
  67. struct hashmap_entry **buckets;
  68. size_t cap;
  69. size_t cap_bits;
  70. size_t sz;
  71. };
  72. void hashmap__init(struct hashmap *map, hashmap_hash_fn hash_fn,
  73. hashmap_equal_fn equal_fn, void *ctx);
  74. struct hashmap *hashmap__new(hashmap_hash_fn hash_fn,
  75. hashmap_equal_fn equal_fn,
  76. void *ctx);
  77. void hashmap__clear(struct hashmap *map);
  78. void hashmap__free(struct hashmap *map);
  79. size_t hashmap__size(const struct hashmap *map);
  80. size_t hashmap__capacity(const struct hashmap *map);
  81. /*
  82. * Hashmap insertion strategy:
  83. * - HASHMAP_ADD - only add key/value if key doesn't exist yet;
  84. * - HASHMAP_SET - add key/value pair if key doesn't exist yet; otherwise,
  85. * update value;
  86. * - HASHMAP_UPDATE - update value, if key already exists; otherwise, do
  87. * nothing and return -ENOENT;
  88. * - HASHMAP_APPEND - always add key/value pair, even if key already exists.
  89. * This turns hashmap into a multimap by allowing multiple values to be
  90. * associated with the same key. Most useful read API for such hashmap is
  91. * hashmap__for_each_key_entry() iteration. If hashmap__find() is still
  92. * used, it will return last inserted key/value entry (first in a bucket
  93. * chain).
  94. */
  95. enum hashmap_insert_strategy {
  96. HASHMAP_ADD,
  97. HASHMAP_SET,
  98. HASHMAP_UPDATE,
  99. HASHMAP_APPEND,
  100. };
  101. #define hashmap_cast_ptr(p) ({ \
  102. _Static_assert((__builtin_constant_p((p)) ? (p) == NULL : 0) || \
  103. sizeof(*(p)) == sizeof(long), \
  104. #p " pointee should be a long-sized integer or a pointer"); \
  105. (long *)(p); \
  106. })
  107. /*
  108. * hashmap__insert() adds key/value entry w/ various semantics, depending on
  109. * provided strategy value. If a given key/value pair replaced already
  110. * existing key/value pair, both old key and old value will be returned
  111. * through old_key and old_value to allow calling code do proper memory
  112. * management.
  113. */
  114. int hashmap_insert(struct hashmap *map, long key, long value,
  115. enum hashmap_insert_strategy strategy,
  116. long *old_key, long *old_value);
  117. #define hashmap__insert(map, key, value, strategy, old_key, old_value) \
  118. hashmap_insert((map), (long)(key), (long)(value), (strategy), \
  119. hashmap_cast_ptr(old_key), \
  120. hashmap_cast_ptr(old_value))
  121. #define hashmap__add(map, key, value) \
  122. hashmap__insert((map), (key), (value), HASHMAP_ADD, NULL, NULL)
  123. #define hashmap__set(map, key, value, old_key, old_value) \
  124. hashmap__insert((map), (key), (value), HASHMAP_SET, (old_key), (old_value))
  125. #define hashmap__update(map, key, value, old_key, old_value) \
  126. hashmap__insert((map), (key), (value), HASHMAP_UPDATE, (old_key), (old_value))
  127. #define hashmap__append(map, key, value) \
  128. hashmap__insert((map), (key), (value), HASHMAP_APPEND, NULL, NULL)
  129. bool hashmap_delete(struct hashmap *map, long key, long *old_key, long *old_value);
  130. #define hashmap__delete(map, key, old_key, old_value) \
  131. hashmap_delete((map), (long)(key), \
  132. hashmap_cast_ptr(old_key), \
  133. hashmap_cast_ptr(old_value))
  134. bool hashmap_find(const struct hashmap *map, long key, long *value);
  135. #define hashmap__find(map, key, value) \
  136. hashmap_find((map), (long)(key), hashmap_cast_ptr(value))
  137. /*
  138. * hashmap__for_each_entry - iterate over all entries in hashmap
  139. * @map: hashmap to iterate
  140. * @cur: struct hashmap_entry * used as a loop cursor
  141. * @bkt: integer used as a bucket loop cursor
  142. */
  143. #define hashmap__for_each_entry(map, cur, bkt) \
  144. for (bkt = 0; bkt < (map)->cap; bkt++) \
  145. for (cur = (map)->buckets[bkt]; cur; cur = cur->next)
  146. /*
  147. * hashmap__for_each_entry_safe - iterate over all entries in hashmap, safe
  148. * against removals
  149. * @map: hashmap to iterate
  150. * @cur: struct hashmap_entry * used as a loop cursor
  151. * @tmp: struct hashmap_entry * used as a temporary next cursor storage
  152. * @bkt: integer used as a bucket loop cursor
  153. */
  154. #define hashmap__for_each_entry_safe(map, cur, tmp, bkt) \
  155. for (bkt = 0; bkt < (map)->cap; bkt++) \
  156. for (cur = (map)->buckets[bkt]; \
  157. cur && ({tmp = cur->next; true; }); \
  158. cur = tmp)
  159. /*
  160. * hashmap__for_each_key_entry - iterate over entries associated with given key
  161. * @map: hashmap to iterate
  162. * @cur: struct hashmap_entry * used as a loop cursor
  163. * @key: key to iterate entries for
  164. */
  165. #define hashmap__for_each_key_entry(map, cur, _key) \
  166. for (cur = (map)->buckets \
  167. ? (map)->buckets[hash_bits((map)->hash_fn((_key), (map)->ctx), (map)->cap_bits)] \
  168. : NULL; \
  169. cur; \
  170. cur = cur->next) \
  171. if ((map)->equal_fn(cur->key, (_key), (map)->ctx))
  172. #define hashmap__for_each_key_entry_safe(map, cur, tmp, _key) \
  173. for (cur = (map)->buckets \
  174. ? (map)->buckets[hash_bits((map)->hash_fn((_key), (map)->ctx), (map)->cap_bits)] \
  175. : NULL; \
  176. cur && ({ tmp = cur->next; true; }); \
  177. cur = tmp) \
  178. if ((map)->equal_fn(cur->key, (_key), (map)->ctx))
  179. #endif /* __LIBBPF_HASHMAP_H */