hash.h 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. #ifndef __EACSMB_HASH_H__
  2. #define __EACSMB_HASH_H__
  3. #include <stdint.h>
  4. struct hash_bucket {
  5. uint64_t hash;
  6. char* key;
  7. void* value;
  8. };
  9. typedef struct hash_table {
  10. size_t alloc_size;
  11. size_t fill;
  12. float grow_ratio; // default 0.75
  13. float shrink_ratio; // set greater than 1.0 to entirely disable, default 99.0
  14. struct hash_bucket* buckets;
  15. } HashTable;
  16. #define HashTable(x) struct hash_table
  17. // NOTE: if you pass in garbage pointers you deserve the segfault
  18. HashTable* HT_create(int allocPOT);
  19. int HT_init(HashTable* obj, int allocPOT);
  20. void HT_destroy(HashTable* obj, int free_values_too);
  21. int HT_resize(HashTable* obj, int newSize);
  22. // returns 0 if val is set to the value
  23. // *val == NULL && return > 0 means the key was not found;
  24. int HT_get(HashTable* obj, char* key, void* val);
  25. int HT_getInt(HashTable* obj, char* key, int64_t* val);
  26. // zero for success
  27. // key's memory is not managed internally. strdup it yourself
  28. int HT_set(HashTable* obj, char* key, void* val);
  29. int HT_setInt(HashTable* obj, char* key, int64_t val);
  30. int HT_delete(HashTable* obj, char* key);
  31. // iteration. no order. results undefined if modified while iterating
  32. // returns 0 when there is none left
  33. // set iter to NULL to start
  34. int HT_next(HashTable* obj, void* iter, char** key, void* value);
  35. /*
  36. Loop macro magic
  37. https://www.chiark.greenend.org.uk/~sgtatham/mp/
  38. HashTable obj;
  39. HT_LOOP(&obj, key, char*, val) {
  40. printf("loop: %s, %s", key, val);
  41. }
  42. effective source:
  43. #define HT_LOOP(obj, keyname, valtype, valname)
  44. if(0)
  45. finished: ;
  46. else
  47. for(char* keyname;;) // internal declarations, multiple loops to avoid comma op funny business
  48. for(valtype valname;;)
  49. for(void* iter = NULL ;;)
  50. if(HT_next(obj, iter, &keyname, &valname))
  51. goto main_loop;
  52. else
  53. while(1)
  54. if(1) {
  55. // when the user uses break
  56. goto finished;
  57. }
  58. else
  59. while(1)
  60. if(!HT_next(obj, iter, &keyname, &valname)) {
  61. // normal termination
  62. goto finished;
  63. }
  64. else
  65. main_loop:
  66. // { user block; not in macro }
  67. */
  68. #define HASH__PASTEINNER(a, b) a ## b
  69. #define HASH__PASTE(a, b) HASH__PASTEINNER(a, b)
  70. #define HASH__ITER(key, val) HASH__PASTE(hashtable_iter_ ## key ## __ ## val ## __, __LINE__)
  71. #define HASH__FINISHED(key, val) HASH__PASTE(hashtable_finished__ ## key ## __ ## val ## __, __LINE__)
  72. #define HASH__MAINLOOP(key, val) HASH__PASTE(hashtable_main_loop__ ## key ## __ ## val ## __, __LINE__)
  73. #define HT_LOOP(obj, keyname, valtype, valname) \
  74. if(0) \
  75. HASH__FINISHED(key, val): ; \
  76. else \
  77. for(char* keyname ;;) \
  78. for(valtype valname ;;) \
  79. for(void* HASH__ITER(key, val) = NULL ;;) \
  80. if(HT_next(obj, & (HASH__ITER(key, val)), &keyname, (void*)&valname)) \
  81. goto HASH__MAINLOOP(key, val); \
  82. else \
  83. while(1) \
  84. if(1) { \
  85. goto HASH__FINISHED(key, val); \
  86. } \
  87. else \
  88. while(1) \
  89. if(!HT_next(obj, & (HASH__ITER(key, val)), &keyname, (void*)&valname)) { \
  90. goto HASH__FINISHED(key, val); \
  91. } \
  92. else \
  93. HASH__MAINLOOP(key, val) :
  94. // { user block; not in macro }
  95. // special faster version for storing just integer sets
  96. struct int_hash_bucket {
  97. uint64_t key;
  98. uint64_t value;
  99. };
  100. typedef struct int_hash_table {
  101. size_t alloc_size;
  102. size_t fill;
  103. float grow_ratio;
  104. float shrink_ratio;
  105. struct int_hash_bucket* buckets;
  106. } IntHash;
  107. #define HT_TYPE(x) _Generic( (x), \
  108. default: 'std', \
  109. struct hash_table: HT_STD, \
  110. struct int_hash_table: HT_INT, \
  111. )
  112. #endif //__EACSMB_HASH_H__