pm.c92 lines · 2.5 KB · raw
1#include "pm.h"
2#include <stdlib.h>
3#include <stdbool.h>
4
5struct pm {
6    size_t values_count;
7    size_t values_capacity;
8    size_t refs_count;
9    size_t refs_capacity;
10    struct pm_kv {
11        uintptr_t key;
12        union {
13            void * value;       // for values
14            void ** value_p;    // for refs
15        };
16    } * values;
17    struct pm_kv * refs;
18};
19
20struct pm * pm_create() {
21    struct pm * pm = calloc(1, sizeof *pm);
22    if (pm == NULL) return NULL;
23
24    *pm = (struct pm) {
25        .values_capacity = 0,
26        .refs_capacity = 0,
27        .values_count = 0,
28        .refs_count = 0,
29        .values = NULL,
30        .refs = NULL,
31    };
32    return pm;
33}
34
35static int pm_kv_cmp(const void * _a, const void * _b) {
36    const struct pm_kv * a = _a;
37    const struct pm_kv * b = _b;
38    if (a->key < b->key) return -1;
39    if (a->key > b->key) return 1;
40    return 0;
41}
42
43size_t pm_destroy(struct pm * pm) {
44    qsort(pm->values, pm->values_count, sizeof *pm->values, &pm_kv_cmp);
45    size_t unmatched = 0;
46    for (size_t i = 0; i < pm->refs_count; i++) {
47        struct pm_kv * ref = &pm->refs[i];
48        struct pm_kv * value = bsearch(ref, pm->values, pm->values_count, sizeof *pm->values, &pm_kv_cmp);
49        if (value == NULL) {
50            unmatched++;
51            continue;
52        }
53        *ref->value_p = value->value;
54    }
55
56    free(pm->values);
57    free(pm->refs);
58    free(pm);
59    return unmatched;
60}
61
62int pm_set(struct pm * pm, uintptr_t key, void * value) {
63    if (pm->values_count >= pm->values_capacity) {
64        size_t new_capacity = pm->values_capacity * 2;
65        if (new_capacity < 16) new_capacity = 16;
66        void * new_values = realloc(pm->values, new_capacity * sizeof(*pm->values));
67        if (new_values == NULL) return -1;
68        pm->values_capacity = new_capacity;
69        pm->values = new_values;
70    }
71    pm->values[pm->values_count++] = (struct pm_kv) {
72        .key = key,
73        .value = value,
74    };
75    return 0;
76}
77
78int pm_get(struct pm * pm, uintptr_t key, void ** value_p) {
79    if (pm->refs_count >= pm->refs_capacity) {
80        size_t new_capacity = pm->refs_capacity * 2;
81        if (new_capacity < 16) new_capacity = 16;
82        void * new_refs = realloc(pm->refs, new_capacity * sizeof(*pm->refs));
83        if (new_refs == NULL) return -1;
84        pm->refs_capacity = new_capacity;
85        pm->refs = new_refs;
86    }
87    pm->refs[pm->refs_count++] = (struct pm_kv) {
88        .key = key,
89        .value_p = value_p,
90    };
91    return 0;
92}