hashmap.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. /* vim: tabstop=4 shiftwidth=4 noexpandtab
  2. * This file is part of ToaruOS and is released under the terms
  3. * of the NCSA / University of Illinois License - see LICENSE.md
  4. * Copyright (C) 2013-2018 K. Lange
  5. */
  6. #include <toaru/list.h>
  7. #include <toaru/hashmap.h>
  8. unsigned int hashmap_string_hash(void * _key) {
  9. unsigned int hash = 0;
  10. char * key = (char *)_key;
  11. int c;
  12. /* This is the so-called "sdbm" hash. It comes from a piece of
  13. * public domain code from a clone of ndbm. */
  14. while ((c = *key++)) {
  15. hash = c + (hash << 6) + (hash << 16) - hash;
  16. }
  17. return hash;
  18. }
  19. int hashmap_string_comp(void * a, void * b) {
  20. return !strcmp(a,b);
  21. }
  22. void * hashmap_string_dupe(void * key) {
  23. return strdup(key);
  24. }
  25. unsigned int hashmap_int_hash(void * key) {
  26. return (unsigned int)key;
  27. }
  28. int hashmap_int_comp(void * a, void * b) {
  29. return (int)a == (int)b;
  30. }
  31. void * hashmap_int_dupe(void * key) {
  32. return key;
  33. }
  34. static void hashmap_int_free(void * ptr) {
  35. (void)ptr;
  36. return;
  37. }
  38. hashmap_t * hashmap_create(int size) {
  39. hashmap_t * map = malloc(sizeof(hashmap_t));
  40. map->hash_func = &hashmap_string_hash;
  41. map->hash_comp = &hashmap_string_comp;
  42. map->hash_key_dup = &hashmap_string_dupe;
  43. map->hash_key_free = &free;
  44. map->hash_val_free = &free;
  45. map->size = size;
  46. map->entries = malloc(sizeof(hashmap_entry_t *) * size);
  47. memset(map->entries, 0x00, sizeof(hashmap_entry_t *) * size);
  48. return map;
  49. }
  50. hashmap_t * hashmap_create_int(int size) {
  51. hashmap_t * map = malloc(sizeof(hashmap_t));
  52. map->hash_func = &hashmap_int_hash;
  53. map->hash_comp = &hashmap_int_comp;
  54. map->hash_key_dup = &hashmap_int_dupe;
  55. map->hash_key_free = &hashmap_int_free;
  56. map->hash_val_free = &free;
  57. map->size = size;
  58. map->entries = malloc(sizeof(hashmap_entry_t *) * size);
  59. memset(map->entries, 0x00, sizeof(hashmap_entry_t *) * size);
  60. return map;
  61. }
  62. void * hashmap_set(hashmap_t * map, void * key, void * value) {
  63. unsigned int hash = map->hash_func(key) % map->size;
  64. hashmap_entry_t * x = map->entries[hash];
  65. if (!x) {
  66. hashmap_entry_t * e = malloc(sizeof(hashmap_entry_t));
  67. e->key = map->hash_key_dup(key);
  68. e->value = value;
  69. e->next = NULL;
  70. map->entries[hash] = e;
  71. return NULL;
  72. } else {
  73. hashmap_entry_t * p = NULL;
  74. do {
  75. if (map->hash_comp(x->key, key)) {
  76. void * out = x->value;
  77. x->value = value;
  78. return out;
  79. } else {
  80. p = x;
  81. x = x->next;
  82. }
  83. } while (x);
  84. hashmap_entry_t * e = malloc(sizeof(hashmap_entry_t));
  85. e->key = map->hash_key_dup(key);
  86. e->value = value;
  87. e->next = NULL;
  88. p->next = e;
  89. return NULL;
  90. }
  91. }
  92. void * hashmap_get(hashmap_t * map, void * key) {
  93. unsigned int hash = map->hash_func(key) % map->size;
  94. hashmap_entry_t * x = map->entries[hash];
  95. if (!x) {
  96. return NULL;
  97. } else {
  98. do {
  99. if (map->hash_comp(x->key, key)) {
  100. return x->value;
  101. }
  102. x = x->next;
  103. } while (x);
  104. return NULL;
  105. }
  106. }
  107. void * hashmap_remove(hashmap_t * map, void * key) {
  108. unsigned int hash = map->hash_func(key) % map->size;
  109. hashmap_entry_t * x = map->entries[hash];
  110. if (!x) {
  111. return NULL;
  112. } else {
  113. if (map->hash_comp(x->key, key)) {
  114. void * out = x->value;
  115. map->entries[hash] = x->next;
  116. map->hash_key_free(x->key);
  117. map->hash_val_free(x);
  118. return out;
  119. } else {
  120. hashmap_entry_t * p = x;
  121. x = x->next;
  122. do {
  123. if (map->hash_comp(x->key, key)) {
  124. void * out = x->value;
  125. p->next = x->next;
  126. map->hash_key_free(x->key);
  127. map->hash_val_free(x);
  128. return out;
  129. }
  130. p = x;
  131. x = x->next;
  132. } while (x);
  133. }
  134. return NULL;
  135. }
  136. }
  137. int hashmap_has(hashmap_t * map, void * key) {
  138. unsigned int hash = map->hash_func(key) % map->size;
  139. hashmap_entry_t * x = map->entries[hash];
  140. if (!x) {
  141. return 0;
  142. } else {
  143. do {
  144. if (map->hash_comp(x->key, key)) {
  145. return 1;
  146. }
  147. x = x->next;
  148. } while (x);
  149. return 0;
  150. }
  151. }
  152. list_t * hashmap_keys(hashmap_t * map) {
  153. list_t * l = list_create();
  154. for (unsigned int i = 0; i < map->size; ++i) {
  155. hashmap_entry_t * x = map->entries[i];
  156. while (x) {
  157. list_insert(l, x->key);
  158. x = x->next;
  159. }
  160. }
  161. return l;
  162. }
  163. list_t * hashmap_values(hashmap_t * map) {
  164. list_t * l = list_create();
  165. for (unsigned int i = 0; i < map->size; ++i) {
  166. hashmap_entry_t * x = map->entries[i];
  167. while (x) {
  168. list_insert(l, x->value);
  169. x = x->next;
  170. }
  171. }
  172. return l;
  173. }
  174. void hashmap_free(hashmap_t * map) {
  175. for (unsigned int i = 0; i < map->size; ++i) {
  176. hashmap_entry_t * x = map->entries[i], * p;
  177. while (x) {
  178. p = x;
  179. x = x->next;
  180. map->hash_key_free(p->key);
  181. map->hash_val_free(p);
  182. }
  183. }
  184. free(map->entries);
  185. }
  186. int hashmap_is_empty(hashmap_t * map) {
  187. for (unsigned int i = 0; i < map->size; ++i) {
  188. if (map->entries[i]) return 0;
  189. }
  190. return 1;
  191. }