diff options
| author | Tyge Løvset <[email protected]> | 2020-03-14 13:12:23 +0100 |
|---|---|---|
| committer | GitHub <[email protected]> | 2020-03-14 13:12:23 +0100 |
| commit | bb68c510122a749cec47d5c6ed49f2df71163d9e (patch) | |
| tree | f5acf4e097c8f9c1872f1c45bad9353c2ebce9e2 | |
| parent | 2052a78c985b176a107e43e304689c841e3a635e (diff) | |
| download | STC-modified-bb68c510122a749cec47d5c6ed49f2df71163d9e.tar.gz STC-modified-bb68c510122a749cec47d5c6ed49f2df71163d9e.zip | |
Add files via upload
| -rw-r--r-- | EXAMPLE.md | 150 |
1 files changed, 75 insertions, 75 deletions
@@ -1,75 +1,75 @@ -This example is based on https://stackoverflow.com/questions/17016175/c-unordered-map-using-a-custom-class-type-as-the-key/17017281#17017281, adapted to use CMap and CString instead of std::unordered_map and std::string. - -To be able to use CMap (or one of the other unordered associative containers) with a user-defined key-type, you need to define two things: - -1. A hash function; this must be a function that calculates the hash value given an object of the key-type. - -2. A comparison function for equality; this is required because the hash cannot rely on the fact that the hash function will always provide a unique hash value for every distinct key (i.e., it needs to be able to deal with collisions), so it needs a way to compare two given keys for an exact match. - -The difficulty with the hash function is that if your key type consists of several members, you will usually have the hash function calculate hash values for the individual members, and then somehow combine them into one hash value for the entire object. For good performance (i.e., few collisions) you should think carefully about how to combine the individual hash values to ensure you avoid getting the same output for different objects too often. - -Assuming a key-type like this, and want string as value, we define the functions key_make(), key_destroy() and key_compare(): -``` -#include <clib/cstring.h> - -struct Key -{ - CString first; - CString second; - int third; -}; - -struct Key key_make(const char* first, const char* second, int third) { - struct Key k = {cstring_make(first), cstring_make(second), third}; - return k; -} - -void key_destroy(struct Key* key) { - cstring_destroy(&key->first); - cstring_destroy(&key->second); -} - -int key_compare(const struct Key* x, const struct Key *y, size_t ignore) { - int c; - c = strcmp(x->first.str, y->first.str); if (c != 0) return c; - c = strcmp(x->second.str, y->second.str); if (c != 0) return c; - return memcmp(&x->third, &y->third, sizeof(x->third)); -} -``` -Here is a simple hash function that combines the three member's hashes: -``` -size_t key_hash(const struct Key* k, size_t ignore) { - // Compute individual hash values for first, second and third - // http://stackoverflow.com/a/1646913/126995 - - size_t res = 17; - res = res * 31 + c_murmurHash(k->first.str, cstring_size(k->first)); - res = res * 31 + c_murmurHash(k->second.str, cstring_size(k->second)); - res = res * 31 + c_murmurHash(&k->third, sizeof(k->third)); - return res; -} -``` -With this in place, you can instantiate a CMap with Key => CString: -``` -#include <clib/CMap.h> -declare_CMap(ex, struct Key, CString, cstring_destroy, key_compare, key_hash, key_destroy); - -int main() -{ - CMap_ex m6 = cmap_initializer; - cmap_ex_put(&m6, key_make("John", "Doe", 12), cstring_make("example")); - cmap_ex_put(&m6, key_make("Mary", "Sue", 21), cstring_make("another")); - - // ... - c_foreach (it, cmap_ex, m6) { - if (cstring_equals(it.item->key.first, "John")) - printf("%s %s %d -> %s\n", it.item->key.first.str, it.item->key.second.str, it.item->key.third, - it.item->value.str); - } - - cmap_ex_destroy(&m6); -} -``` -It will automatically use key_hash() as defined above for the hash value calculations, and the key_compare() for equality checks. -The cmap_ex_destroy() function will free all first, second CString's, and the CString value for each item in the map, in addition to the CMap hash table itself. - +This example is based on https://stackoverflow.com/questions/17016175/c-unordered-map-using-a-custom-class-type-as-the-key/17017281#17017281, adapted to use CMap and CString instead of std::unordered_map and std::string.
+
+To be able to use CMap (or one of the other unordered associative containers) with a user-defined key-type, you need to define two things:
+
+1. A hash function; this must be a function that calculates the hash value given an object of the key-type.
+
+2. A comparison function for equality; this is required because the hash cannot rely on the fact that the hash function will always provide a unique hash value for every distinct key (i.e., it needs to be able to deal with collisions), so it needs a way to compare two given keys for an exact match.
+
+The difficulty with the hash function is that if your key type consists of several members, you will usually have the hash function calculate hash values for the individual members, and then somehow combine them into one hash value for the entire object. For good performance (i.e., few collisions) you should think carefully about how to combine the individual hash values to ensure you avoid getting the same output for different objects too often.
+
+Assuming a key-type like this, and want string as value, we define the functions person_make(), person_destroy() and person_compare():
+```
+#include <clib/cstring.h>
+
+struct Person
+{
+ CString name;
+ CString surname;
+ int age;
+};
+
+struct Person person_make(const char* name, const char* surname, int age) {
+ struct Person person = {cstring_make(name), cstring_make(surname), age};
+ return person;
+}
+
+void person_destroy(struct Person* p) {
+ cstring_destroy(&p->name);
+ cstring_destroy(&p->surname);
+}
+
+int person_compare(const struct Person* x, const struct Person *y, size_t ignore) {
+ int c;
+ c = strcmp(x->name.str, y->name.str); if (c != 0) return c;
+ c = strcmp(x->surname.str, y->surname.str); if (c != 0) return c;
+ return memcmp(&x->age, &y->age, sizeof(x->age));
+}
+```
+Here is a simple hash function that combines the three member's hashes:
+```
+size_t person_hash(const struct Person* p, size_t ignore) {
+ // Compute individual hash values for name, surname and age
+ // http://stackoverflow.com/a/1646913/126995
+
+ size_t res = 17;
+ res = res * 31 + c_murmurHash(p->name.str, cstring_size(p->name));
+ res = res * 31 + c_murmurHash(p->surname.str, cstring_size(p->surname));
+ res = res * 31 + c_murmurHash(&p->age, sizeof(p->age));
+ return res;
+}
+```
+With this in place, you can instantiate a CMap with Person => CString:
+```
+#include <clib/CMap.h>
+declare_CMap(ex, struct Person, CString, cstring_destroy, person_compare, person_hash, person_destroy);
+
+int main()
+{
+ CMap_ex m6 = cmap_initializer;
+ cmap_ex_put(&m6, person_make("John", "Doe", 12), cstring_make("example"));
+ cmap_ex_put(&m6, person_make("Mary", "Sue", 21), cstring_make("another"));
+
+ // ...
+ c_foreach (it, cmap_ex, m6) {
+ if (cstring_equals(it.item->key.name, "John"))
+ printf("%s %s %d -> %s\n", it.item->key.name.str, it.item->key.surname.str, it.item->key.age,
+ it.item->value.str);
+ }
+
+ cmap_ex_destroy(&m6);
+}
+```
+It will automatically use person_hash() as defined above for the hash value calculations, and the person_compare() for equality checks.
+The cmap_ex_destroy() function will free CStrings name, surname and the value for each item in the map, in addition to the CMap hash table itself.
+
|
