An emulator, assembler, and disassembler for the Sega Game Gear
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

105 lines
2.6 KiB

  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. */
  30. HashTable* hash_table_new(size_t key_offset, size_t next_offset)
  31. {
  32. HashTable *table;
  33. if (!(table = malloc(sizeof(HashTable))))
  34. OUT_OF_MEMORY()
  35. if (!(table->nodes = calloc(INITIAL_BUCKETS, sizeof(HashNode*))))
  36. OUT_OF_MEMORY()
  37. table->buckets = INITIAL_BUCKETS;
  38. table->key_offset = key_offset;
  39. table->next_offset = next_offset;
  40. return table;
  41. }
  42. /*
  43. Deallocate a HashTable. This function does nothing if the table is NULL.
  44. The given callback function is called on each node as it is removed from
  45. the table. Typically, it will free() the node's members and then free()
  46. the node itself.
  47. */
  48. void hash_table_free(HashTable *table, HashFreeCallback callback)
  49. {
  50. if (!table)
  51. return;
  52. for (size_t bucket = 0; bucket < table->buckets; bucket++) {
  53. HashNode *node = table->nodes[bucket];
  54. while (node) {
  55. HashNode *temp = NEXT_NODE(table, node);
  56. callback(node);
  57. node = temp;
  58. }
  59. }
  60. free(table);
  61. }
  62. /*
  63. Search for a key in the hash table.
  64. Return the corresponding node on success and NULL on failure.
  65. */
  66. const HashNode* hash_table_find(const HashTable *table, const char *key)
  67. {
  68. HashNode *node = table->nodes[hash_key(table, key)];
  69. while (node) {
  70. if (!strcmp(key, NODE_KEY(table, node)))
  71. return node;
  72. node = NEXT_NODE(table, node);
  73. }
  74. return NULL;
  75. }
  76. /*
  77. Insert a node into the table.
  78. This doesn't check for duplicate keys, so you must do that beforehand.
  79. */
  80. void hash_table_insert(HashTable *table, HashNode *node)
  81. {
  82. size_t index = hash_key(table, NODE_KEY(table, node));
  83. NEXT_NODE(table, node) = table->nodes[index];
  84. table->nodes[index] = node;
  85. }