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}