aboutsummaryrefslogtreecommitdiffstats
path: root/src/darray.h
blob: fa4e2932ac471c402789937457aa003dab82cb00 (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
81
#ifndef BDL_DARRAY_H
#define BDL_DARRAY_H

#include <string.h>

typedef struct ArrayHeader {
    size_t size;
    size_t cap;
} ArrayHeader;

// Header/Size/capacity accessors.
#define array_head(ARR) ((ArrayHeader *)((char *)(ARR) - sizeof(ArrayHeader)))
#define array_size(ARR) ((ARR) ? array_head(ARR)->size : 0)
#define array_cap(ARR)  ((ARR) ? array_head(ARR)->cap : 0)

// Initialize a dynamic array ARR with N elements. The initialization doesn't
// zero out the data, so thread carefully..
#define array_init(ARR,N) ((ARR) = _array_reserve(N, sizeof(*(ARR))))

// Push a given element T to the dynamic array ARR.
#define array_push(ARR, T) \
    ((ARR) = _array_maybe_grow(ARR, sizeof(T)),  \
     (ARR)[array_head(ARR)->size++] = (T))

// Return the last element of the array. Can be used to build stacks.
#define array_pop(ARR) (ARR)[--array_head(ARR)->size]

// Return the value stored at the OFFSET position from the tail of the array.
#define array_peek(ARR, OFFSET) (ARR)[array_head(ARR)->size - 1 - (OFFSET)]

// Insert N bytes from the SRC array into the ARR dynamic array.
#define array_insert(ARR, SRC, N) \
    ((ARR) = _array_insert(ARR, SRC, N, sizeof(*(ARR))))

// Free the memory from the original allocated position.
#define array_free(ARR)   ((ARR) ? free(array_head(ARR)), (ARR) = NULL : 0)

static inline void *
_array_reserve(size_t num_elem, size_t type_size) {
    char *p = malloc(num_elem * type_size + sizeof(ArrayHeader));
    p += sizeof(ArrayHeader);
    array_head(p)->size = 0;
    array_head(p)->cap = num_elem;
    return p;
}

static inline void *
_array_maybe_grow(void *arr, size_t type_size) {
    ArrayHeader *head = array_head(arr);
    if (head->cap == head->size) {
        if (head->cap == 0) {
            head->cap++;
        } else {
            head->cap *= 2;
        }
        head = realloc(head, head->cap * type_size + sizeof(ArrayHeader));
    }
    arr = (char *)head + sizeof(ArrayHeader);
    return arr;
}

static inline
char * _array_insert(char *arr, const char *src, size_t n_bytes, size_t type_size) {
    ArrayHeader *head = array_head(arr);
    size_t new_size = n_bytes + head->size;
    if (new_size > head->cap * type_size) {
        if (head->cap == 0) {
            head->cap = 1;
        }
        while (new_size >= head->cap * type_size) {
            head->cap *= 2;
        }
        head = realloc(head, head->cap * type_size + sizeof(ArrayHeader));
    }
    arr = (char *)head + sizeof(ArrayHeader);
    memcpy((arr + head->size), src, n_bytes);
    head->size = new_size;
    return arr;
}

#endif // BDL_DARRAY_H