{"id":23719258,"url":"https://github.com/german-one/c-hashmap-and-hashset","last_synced_at":"2025-09-08T14:34:56.681Z","repository":{"id":193141759,"uuid":"652339958","full_name":"german-one/C-Hashmap-and-Hashset","owner":"german-one","description":"C interface of a hash map, incl. an implementation of a hash set.","archived":false,"fork":false,"pushed_at":"2023-06-11T20:51:48.000Z","size":27,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-12-30T21:48:16.289Z","etag":null,"topics":["c","hashmap","hashset","hashtable"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/german-one.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2023-06-11T20:46:48.000Z","updated_at":"2024-12-06T18:57:10.000Z","dependencies_parsed_at":"2023-09-07T00:22:31.629Z","dependency_job_id":null,"html_url":"https://github.com/german-one/C-Hashmap-and-Hashset","commit_stats":null,"previous_names":["german-one/c-hashmap-and-hashset"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/german-one%2FC-Hashmap-and-Hashset","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/german-one%2FC-Hashmap-and-Hashset/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/german-one%2FC-Hashmap-and-Hashset/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/german-one%2FC-Hashmap-and-Hashset/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/german-one","download_url":"https://codeload.github.com/german-one/C-Hashmap-and-Hashset/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239808509,"owners_count":19700455,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c","hashmap","hashset","hashtable"],"created_at":"2024-12-30T21:48:24.011Z","updated_at":"2025-02-20T09:21:33.697Z","avatar_url":"https://github.com/german-one.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# C interface of a hash map, incl. an implementation of a hash set.\r\n\r\nCopyright (c) 2023 Steffen Illhardt  \r\nLicensed under the MIT license ( https://opensource.org/license/mit/ )\r\n\r\nVersion 1.0  \r\n\r\n\u003chr\u003e\r\n\r\n\r\nThe file `hm.h` contains the `C` interface of both a Hash Map and a Hash Set\r\nlibrary, implemented in the `hm.c` source file. \u003cbr\u003e\r\nThe comments in the header are [Doxygen](https://www.doxygen.nl/index.html)\r\ncompliant for the generation of a documentation of the entire library.\r\n\r\nAdding to the container copies both keys and values and automatically\r\nappends null bytes, sufficient to serve as terminators for any string type,\r\nif necessary. Of course, the interfaces can also be used for binary\r\ndata. \u003cbr\u003e\r\nThe length of keys and values is defined at the element level to allow for\r\ndynamically sized strings, arrays, or serialized data. \u003cbr\u003e\r\n\r\n\u003chr\u003e\r\n\r\n- A Hash Map (a.k.a. Hash Table) is an unordered container to store items as\r\nkey-value pairs where the keys are unique. \u003cbr\u003e\r\nThis implementation allows NULL pointer values. \u003cbr\u003e\r\nValues can be detached from the map to possibly avoid copying them once\r\nagain. \u003cbr\u003e\u003cbr\u003e\r\n\r\n- A Hash Set is an unordered container to store unique values. \u003cbr\u003e\r\nSince a Hash Set can be treated as a Hash Map where the key is also the\r\nvalue and with the value field of the map set to null, this implementation\r\nof a Hash Set just wraps the Hash Map interface. \u003cbr\u003e\u003cbr\u003e\r\n\r\n- The Hashing Function Interface defines the pointer type\r\nof a custom hashing function. It's shared with both the Hash Map and the\r\nHash Set interfaces. \u003cbr\u003e\r\nThe aim of the function is to calculate hash values for keys of the Hash Map\r\nor for values of the Hash Set, respectively. If they contain paddings with\r\nundefined content (e.g. members of structures might be padded) you should\r\nuse a suitable algorithm for the calculation. Also, a case-insensitive\r\nequality evaluation can be achieved using custom hashing and comparison\r\nfunctions.\u003cbr\u003e\r\nFurthermore, there are many personal preferences for hashing algorithms.\r\nMost of those should be able to get wrapped in a function with the\r\nspecification defined. \u003cbr\u003e\r\nIf this interface is not used, the calculation of hash values will fall back\r\nto a simple `FNV-1a` algorithm. \u003cbr\u003e\u003cbr\u003e\r\n\r\n- The Comparison Function Interface defines the pointer\r\ntype of a custom equality comparison function. It's shared with both the\r\nHash Map and the Hash Set interfaces. \u003cbr\u003e\r\nThe aim of the function is to compare keys of the Hash Map or values of the\r\nHash Set, respectively. If they contain paddings with undefined content\r\n(e.g. members of structures might be padded) you should use a suitable\r\nalgorithm for the comparison. Also, a case-insensitive equality evaluation\r\ncan be achieved using custom hashing and comparison functions.\u003cbr\u003e\r\nAt the point the function is called, both the hash and length equality have\r\nbeen already checked. \u003cbr\u003e\r\nIf this interface is not used, the comparison will fall back to a binary\r\nequality check using `memcmp()`.\r\n\r\n\u003chr\u003e\r\n\r\n### Hash Map Example:\r\n\r\n```c\r\n#include \u003cstdio.h\u003e\r\n#include \"hm.h\"\r\n\r\nint main(void)\r\n{\r\n  static const char key[] = \"abc\";\r\n  const size_t keyLen = sizeof(key) / sizeof(key[0]) - 1;\r\n\r\n  // create a hash map (with default hashing algorithm and default comparer)\r\n  hm_t hm = hm_create(NULL, 0, NULL);\r\n  if (hm == NULL)\r\n    return 1;\r\n\r\n  // add an element\r\n  hm_add(hm, key, keyLen, (int[]){ 5 }, sizeof(int)); // the array (compound literal) decays into a pointer to int 5\r\n\r\n  // get the data of the element with a certain key\r\n  hm_iter_t item = hm_item(hm, key, keyLen);\r\n  if (item != NULL)\r\n    printf(\"\\\"abc\\\" is associated with %d\\n\", *(int *)(item-\u003eval));\r\n  else\r\n    puts(\"\\\"abc\\\" not found\");\r\n\r\n  // release allocated resources\r\n  hm_destroy(hm);\r\n\r\n  return 0;\r\n}\r\n```\r\n\r\n\u003cbr\u003e\u003chr\u003e\r\n### Hash Set Example:\r\n\r\n```c\r\n#include \u003cstdio.h\u003e\r\n#include \"hm.h\"\r\n\r\nint main(void)\r\n{\r\n  static const char val[] = \"abc\";\r\n  const size_t valLen = sizeof(val) / sizeof(val[0]) - 1;\r\n\r\n  // create a hash set (with default hashing algorithm and default comparer)\r\n  hs_t hs = hs_create(NULL, 0, NULL);\r\n  if (hs == NULL)\r\n    return 1;\r\n\r\n  // add an element\r\n  hs_add(hs, val, valLen);\r\n\r\n  // check whether the element is contained\r\n  if (hs_contains(hs, val, valLen))\r\n    puts(\"\\\"abc\\\" found\");\r\n  else\r\n    puts(\"\\\"abc\\\" not found\");\r\n\r\n  // release allocated resources\r\n  hs_destroy(hs);\r\n\r\n  return 0;\r\n}\r\n```\r\n\r\n\u003cbr\u003e\u003chr\u003e\r\n### Example of a function set for a case-insensitive string hashing/comparison:\r\n```c\r\n#include \u003cctype.h\u003e\r\n#include \"hm.h\"\r\n\r\nuint64_t case_insensitive_hash(const void *key, size_t keyLen, uint64_t hashSeed)\r\n{\r\n  // FNV-1a algorithm with each character converted using `toupper()`\r\n  (void)hashSeed;\r\n  uint64_t hash = UINT64_C(0xCBF29CE484222325);\r\n  for (const uint8_t *byteIt = (const uint8_t *)key, *const end = byteIt + keyLen; byteIt \u003c end; ++byteIt)\r\n    hash = (hash ^ (uint8_t)toupper(*byteIt)) * UINT64_C(0x00000100000001B3);\r\n\r\n  return hash;\r\n}\r\n\r\nbool case_insensitive_commparer(const void *key1, const void *key2, size_t len)\r\n{\r\n  // character-wise comparison with each character converted using `toupper()`\r\n  for (const uint8_t *key1It = (const uint8_t *)key1, *key2It = (const uint8_t *)key2, *const end = key1It + len; key1It \u003c end; ++key1It, ++key2It)\r\n    if (toupper(*key1It) != toupper(*key2It))\r\n      return false;\r\n\r\n  return true;\r\n}\r\n\r\n// to be used like so:\r\n// hm_t hm = hm_create(\u0026case_insensitive_hash, 0, \u0026case_insensitive_commparer);\r\n```\r\n\u003cbr\u003e\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgerman-one%2Fc-hashmap-and-hashset","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgerman-one%2Fc-hashmap-and-hashset","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgerman-one%2Fc-hashmap-and-hashset/lists"}