skip to content
==> src/member_list.c <==
1/* Member lists and masks (see the header). */
2#include "mesh/member_list.h"
3#include "mesh/abi/base.h"
4#include "mesh/parse.h"
5#include "mesh/rust_fmt.h"
6#include "mesh/mt.h"
7
8#include <stdlib.h>
9#include <string.h>
10
11void ml_push(ml_list *l, uint32_t k) {
12    if (l->n == l->cap) {
13        l->cap = l->cap ? l->cap * 2 : 8;
14        l->v = mt_realloc(l->v, l->cap * sizeof *l->v);
15    }
16    l->v[l->n++] = k;
17}
18
19long ml_find(const ml_list *l, uint32_t k) {
20    for (size_t i = 0; i < l->n; i++)
21        if (l->v[i] == k) return (long)i;
22    return -1;
23}
24
25bool ml_has(const ml_list *l, uint32_t k) { return ml_find(l, k) >= 0; }
26
27void ml_remove_at(ml_list *l, size_t i) {
28    memmove(l->v + i, l->v + i + 1, (l->n - i - 1) * sizeof *l->v);
29    l->n--;
30}
31
32void ml_remove_value(ml_list *l, uint32_t k) {
33    size_t j = 0;
34    for (size_t i = 0; i < l->n; i++)
35        if (l->v[i] != k) l->v[j++] = l->v[i];
36    l->n = j;
37}
38
39static int cmp_u32(const void *a, const void *b) {
40    uint32_t x = *(const uint32_t *)a, y = *(const uint32_t *)b;
41    return x < y ? -1 : x > y;
42}
43
44void ml_sort(ml_list *l) {
45    if (l->n > 1) qsort(l->v, l->n, sizeof *l->v, cmp_u32);
46}
47
48bool ml_eq(const ml_list *a, const ml_list *b) {
49    return a->n == b->n && (a->n == 0 || memcmp(a->v, b->v, a->n * sizeof *a->v) == 0);
50}
51
52ml_list ml_of(const uint32_t *v, size_t n) {
53    ml_list l = {0};
54    for (size_t i = 0; i < n; i++) ml_push(&l, v[i]);
55    return l;
56}
57
58ml_list ml_clone(const ml_list *l) { return ml_of(l->v, l->n); }
59
60void ml_free(ml_list *l) {
61    free(l->v);
62    *l = (ml_list){0};
63}
64
65ml_opt ml_none(void) { return (ml_opt){0}; }
66ml_opt ml_some(const uint32_t *v, size_t n) { return (ml_opt){true, ml_of(v, n)}; }
67
68bool ml_opt_eq(const ml_opt *a, const ml_opt *b) {
69    if (a->some != b->some) return false;
70    return !a->some || ml_eq(&a->l, &b->l);
71}
72
73ml_opt ml_opt_clone(const ml_opt *o) { return o->some ? (ml_opt){true, ml_clone(&o->l)} : ml_none(); }
74
75void ml_opt_free(ml_opt *o) {
76    ml_free(&o->l);
77    o->some = false;
78}
79
80bool ml_opt_has_or_all(const ml_opt *o, uint32_t k) { return !o->some || ml_has(&o->l, k); }
81
82char *ml_text(const ml_list *l) {
83    if (l->n == 0) return mt_strdup("-");
84    mt_buf b = {0};
85    for (size_t i = 0; i < l->n; i++) mt_printf(&b, i ? ",%u" : "%u", l->v[i]);
86    return mt_take(&b);
87}
88
89char *ml_at_word(const ml_opt *o) { return o->some ? ml_text(&o->l) : mt_strdup("all"); }
90
91bool ml_parse(const char *s, ml_list *out, char **err) {
92    *out = (ml_list){0};
93    if (strcmp(s, "-") == 0) return true;
94    mt_strs w = mt_split(s, ',');
95    for (size_t i = 0; i < w.n; i++) {
96        uint32_t k;
97        if (!mp_u32(w.v[i], &k)) {
98            char *q = rf_debug_str(s);
99            *err = mt_fmt("bad member list %s", q);
100            free(q);
101            goto fail;
102        }
103        if (k >= MESH_MAX_SYSTEMS) {
104            *err = mt_fmt("member %u >= %u", k, (unsigned)MESH_MAX_SYSTEMS);
105            goto fail;
106        }
107        ml_push(out, k);
108    }
109    mt_strs_free(&w);
110    return true;
111fail:
112    mt_strs_free(&w);
113    ml_free(out);
114    return false;
115}
116
117uint32_t ml_mask(const ml_list *l) {
118    uint32_t m = 0;
119    for (size_t i = 0; i < l->n; i++) m |= 1u << l->v[i];
120    return m;
121}
122
123ml_list ml_members(uint32_t mask) {
124    ml_list l = {0};
125    for (uint32_t k = 0; k < 32; k++)
126        if (mask >> k & 1) ml_push(&l, k);
127    return l;
128}
129
130int ml_popcount(uint32_t x) {
131    int n = 0;
132    for (; x; x &= x - 1) n++;
133    return n;
134}