summaryrefslogtreecommitdiffhomepage
path: root/examples/advanced.c
blob: 931efb5785d0b77c67f095b29141bb8b0d3e72a2 (plain)
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);
}