summaryrefslogtreecommitdiff
path: root/src/util/container.h
blob: 8b89440300014d94b451bf2ee96b889b3ab9b2c1 (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
#ifndef ANIMTOOL_CONTAINER_H_
#define ANIMTOOL_CONTAINER_H_

#include <stdlib.h>
#include <string.h>
#include <stdbit.h>
#include <stddef.h>

#define option(type) struct { bool present; type data; }
#define array(type) struct { size_t len; type *ptr; }
#define arraybuf(type) struct { size_t len, cap; type *ptr; }
#define map(type) arraybuf(struct { str key; type val; })

#define array_typeck(a, b) ((void) ((a).ptr == (b).ptr))

#define array_eq(a, b) (array_typeck(a, b), \
    ((a).len == (b).len && !memcmp((a).ptr, (b).ptr, (a).len * sizeof *(a).ptr)))

#define array_alloc(arr, e_len) (arr)->ptr = malloc(((arr)->len = (e_len)) * sizeof *(arr)->ptr)

#define array_dup(dst, src) do { \
        array_typeck(*(dst), *(src)); \
        array_alloc(dst, (src)->len); \
        memcpy((dst)->ptr, (src)->ptr, (src)->len * sizeof(*(src)->ptr)); \
    } while(0)

#define arraybuf_grow(arr, by) do { \
        if ((arr)->len + by > (arr)->cap) \
            (arr)->ptr = realloc((arr)->ptr, ((arr)->cap = stdc_bit_ceil((arr)->len) + by) * sizeof(*(arr)->ptr)); \
        else if (!(arr)->ptr) \
            (arr)->ptr = malloc((arr)->cap * sizeof(*(arr)->ptr)); \
    } while (0)

#define arraybuf_insert(arr, val) do { \
        arraybuf_grow(arr, 1); \
        (arr)->ptr[(arr)->len++] = (val); \
    } while (0)

#define arraybuf_cast(arr) { .len = (arr).len, .ptr = (arr).ptr }
#define array_assign(a, b) do { (a)->len = (b).len; (a)->ptr = (b).ptr; } while(0)

#define map_find(arr, e_key, p_val) do { \
        for (size_t i = 0; i < (arr)->len; i++) \
            if (array_eq((arr)->ptr[i].key, e_key)) { \
                *(p_val) = &(arr)->ptr[i].val; \
                break; \
            } \
    } while (0)

#define map_insert_end(arr, e_key, e_val) do { \
        arraybuf_grow(arr, 1); \
        (arr)->ptr[(arr)->len].key = (e_key); \
        (arr)->ptr[(arr)->len].val = (e_val); \
        (arr)->len++; \
    } while (0)

#define map_insert(arr, e_key, e_val, p_succ) do { \
        typeof(&(arr)->ptr->val) _val = nullptr; \
        map_find(arr, e_key, &_val); \
        if ((*(p_succ) = !_val)) \
            map_insert_end(arr, e_key, e_val); \
    } while (0)

#endif