An emulator, assembler, and disassembler for the Sega Game Gear
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

hash_table.c 3.9 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. /* Copyright (C) 2014-2015 Ben Kurtovic <ben.kurtovic@gmail.com>
  2. Released under the terms of the MIT License. See LICENSE for details. */
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include "hash_table.h"
  6. #include "../logging.h"
  7. #define INITIAL_BUCKETS 127
  8. #define GET_FIELD_(obj, offset, type) (*((type*) (((char*) obj) + offset)))
  9. #define NODE_KEY(tab, node) GET_FIELD_(node, tab->key_offset, char*)
  10. #define NEXT_NODE(tab, node) GET_FIELD_(node, tab->next_offset, HashNode*)
  11. /* Internal structs */
  12. struct HashNode {
  13. char *key;
  14. HashNode *next;
  15. };
  16. /*
  17. Hash a string key into a hash table bucket index.
  18. This uses the djb2 algorithm: http://www.cse.yorku.ca/~oz/hash.html
  19. */
  20. static inline size_t hash_key(const HashTable *table, const char *key)
  21. {
  22. size_t hash = 5381;
  23. while (*key)
  24. hash = ((hash << 5) + hash) + *(key++);
  25. return hash % table->buckets;
  26. }
  27. /*
  28. Create and return a new HashTable.
  29. These HashTables are designed to be generic, a sort of poor-man's C++
  30. template. They can store any kind of node data as long as they are structs
  31. with a char* field (for the node key), and a pointer to its own type (to
  32. implement separate chaining).
  33. key_offset is the (byte) offset of the key field, and next_offset is the
  34. offset of the self-pointer. The callback function is called on a node when
  35. it is removed from the table. Typically, it should free() the node's
  36. members and then free() the node itself.
  37. The hash_table_NEW macro can be used to call this function more easily.
  38. */
  39. HashTable* hash_table_new(
  40. size_t key_offset, size_t next_offset, HashFreeCallback callback)
  41. {
  42. HashTable *table;
  43. if (!(table = malloc(sizeof(HashTable))))
  44. OUT_OF_MEMORY()
  45. if (!(table->nodes = calloc(INITIAL_BUCKETS, sizeof(HashNode*))))
  46. OUT_OF_MEMORY()
  47. table->buckets = INITIAL_BUCKETS;
  48. table->key_offset = key_offset;
  49. table->next_offset = next_offset;
  50. table->free = callback;
  51. return table;
  52. }
  53. /*
  54. Deallocate a HashTable. This function does nothing if the table is NULL.
  55. */
  56. void hash_table_free(HashTable *table)
  57. {
  58. if (!table)
  59. return;
  60. for (size_t bucket = 0; bucket < table->buckets; bucket++) {
  61. HashNode *node = table->nodes[bucket];
  62. while (node) {
  63. HashNode *temp = NEXT_NODE(table, node);
  64. table->free(node);
  65. node = temp;
  66. }
  67. }
  68. free(table);
  69. }
  70. /*
  71. Search for a key in the hash table.
  72. Return the corresponding node on success and NULL on failure.
  73. */
  74. const HashNode* hash_table_find(const HashTable *table, const char *key)
  75. {
  76. HashNode *node = table->nodes[hash_key(table, key)];
  77. while (node) {
  78. if (!strcmp(key, NODE_KEY(table, node)))
  79. return node;
  80. node = NEXT_NODE(table, node);
  81. }
  82. return NULL;
  83. }
  84. /*
  85. Insert a node into the table.
  86. This doesn't prevent inserting duplicate keys. If a duplicate key is
  87. inserted, the table acts like a stack; the new one will shadow the old one,
  88. and hash_table_remove() will remove the most-recently inserted key to
  89. reveal the second-most recent.
  90. */
  91. void hash_table_insert(HashTable *table, HashNode *node)
  92. {
  93. size_t index = hash_key(table, NODE_KEY(table, node));
  94. NEXT_NODE(table, node) = table->nodes[index];
  95. table->nodes[index] = node;
  96. }
  97. /*
  98. (Try to) remove a node with the given key from the table.
  99. Return true if the node was removed, or false if it was not found.
  100. */
  101. bool hash_table_remove(HashTable *table, const char *key)
  102. {
  103. size_t index = hash_key(table, key);
  104. HashNode *node = table->nodes[index], *prev = NULL, *next;
  105. while (node) {
  106. next = NEXT_NODE(table, node);
  107. if (!strcmp(key, NODE_KEY(table, node))) {
  108. if (prev)
  109. NEXT_NODE(table, prev) = next;
  110. else
  111. table->nodes[index] = next;
  112. table->free(node);
  113. return true;
  114. }
  115. prev = node;
  116. node = next;
  117. }
  118. return false;
  119. }