1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
|
/*
* To be able to use cmap 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.
* When 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.
* In order to use Viking as a map key, it is smart to define a plain-old-data "view"
* of the Viking struct, to simplfy insert and lookup in the map.
*/
#include <stc/cmap.h>
#include <stc/cstr.h>
// Viking data struct -----------------------
typedef struct Viking {
cstr_t name;
cstr_t country;
} Viking;
void viking_del(Viking* vk) {
cstr_del(&vk->name);
cstr_del(&vk->country);
}
// Viking view struct -----------------------
typedef struct VikingVw {
const char* name;
const char* country;
} VikingVw;
uint32_t vikingvw_hash(const VikingVw* vw, size_t ignore) {
uint32_t hash = c_string_hash(vw->name) ^ c_string_hash(vw->country);
return hash;
}
int vikingvw_equals(const VikingVw* x, const VikingVw* y) {
if (strcmp(x->name, y->name) != 0) return false;
return strcmp(x->country, y->country) == 0;
}
VikingVw viking_toVw(Viking* vk) {
VikingVw vw = {vk->name.str, vk->country.str}; return vw;
}
Viking viking_fromVw(VikingVw vw) {
Viking vk = {cstr_from(vw.name), cstr_from(vw.country)}; return vk;
}
// Using the full using_cmap() macro to define [Viking -> int] hash map type:
using_cmap(vk, Viking, int, c_default_del, vikingvw_equals, vikingvw_hash,
viking_del, VikingVw, viking_toVw, viking_fromVw);
// cmap_vk uses vikingvw_hash() for hash value calculations, and vikingvw_equals() for equality test.
// cmap_vk_del() will free all memory allocated for Viking keys and the hash table values.
// Main ----------------------------
int main()
{
cmap_vk vikings = cmap_vk_init();
c_push_items(&vikings, cmap_vk, {
{{"Einar", "Norway"}, 20},
{{"Olaf", "Denmark"}, 24},
{{"Harald", "Iceland"}, 12},
});
VikingVw einar = {"Einar", "Norway"};
cmap_vk_entry_t *e = cmap_vk_find(&vikings, einar);
e->second += 5; // update
cmap_vk_emplace(&vikings, einar, 0).first->second += 5; // again
c_foreach (k, cmap_vk, vikings) {
printf("%s of %s has %d HP\n", k.ref->first.name.str, k.ref->first.country.str, k.ref->second);
}
cmap_vk_del(&vikings);
}
|