aboutsummaryrefslogtreecommitdiff
path: root/ls_vec.h
blob: 5fcb4545b69b5b01fde84c2fff1e9781c5c3f883 (plain) (blame)
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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#pragma once

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

/*
 * Lion's Standard (LS) ANSI C vector library.
 *
 * This is a vector library, i.e. a dynamically sized array.
 * To get started, you have to declare your type:
 *
 *      VEC(int)
 *
 * which creates a struct and the associated functions for a vec_int,
 * meaning a vector of type `int`. The resulting struct is named `vec_int`
 * and all associated functions are prefixed with that same name, for
 * example `vec_int_init`, `vec_int_push`, etc.
 *
 * You can choose a name for long or complex types like this:
 *
 *      VEC_NAMED(int*, intp)
 *
 * which results in vec_intp, vec_intp_push, etc. or
 *
 *      VEC_NAMED(struct Car, car)
 *
 * which results in vec_car, vec_car_push, etc.
 *
 * The VEC and VEC_NAMED macros create both the declaration and implementation.
 * If you'd like to split that, call
 *
 *      VEC_DECL(int)
 *
 * to generate the declarations, and somewhere else
 *
 *      VEC_IMPL(int)
 *
 * to generate the implementation. The same with VEC_NAMED_DECL
 * and VEC_NAMED_IMPL.
 *
 * Full example:
 *
 *      VEC(int)
 *
 *      int main(void) {
 *          vec_int vec;
 *          vec_int_init(&vec);
 *          for (int i = 0; i < 10; ++i) {
 *              vec_int_push(&vec, i);
 *          }
 *          vec_int_clear(&vec);
 *      }
 *
 */

#define LS_VEC_DECL(T, name)                                                   \
    typedef struct name {                                                      \
        size_t size;                                                           \
        size_t capacity;                                                       \
        T* data;                                                               \
    } name;                                                                    \
    void name##_init(name* vec);                                               \
    void name##_clear(name* vec);                                              \
    int name##_reserve(name* vec, size_t count);                               \
    int name##_push(name* vec, T value);
#define LS_VEC_IMPL(T, name) _ls_VEC_IMPL_DETAIL(T, name, )

#define LS_VEC_INLINE(T, name)                                                 \
    typedef struct name {                                                      \
        size_t size;                                                           \
        size_t capacity;                                                       \
        T* data;                                                               \
    } name;                                                                    \
    _ls_VEC_IMPL_DETAIL(T, name, static)

#define _ls_VEC_IMPL_DETAIL(T, name, specifier)                                \
    specifier void name##_init(name* vec) { memset(vec, 0, sizeof(*vec)); }    \
    specifier void name##_clear(name* vec) {                                   \
        if (vec->data) {                                                       \
            free(vec->data);                                                   \
            vec->data = NULL;                                                  \
        }                                                                      \
        vec->size = 0;                                                         \
        vec->capacity = 0;                                                     \
    }                                                                          \
    specifier int name##_reserve(name* vec, size_t count) {                    \
        if (vec->capacity < count) {                                           \
            T* new_data;                                                       \
            size_t total;                                                      \
            if (count == 0) {                                                  \
                vec->capacity = 5;                                             \
            } else {                                                           \
                size_t new_cap = (size_t)((float)vec->capacity * 1.6f + 1.0f); \
                vec->capacity = new_cap > count ? new_cap : count;             \
            }                                                                  \
            total = vec->capacity * sizeof(T);                                 \
            if (vec->capacity != 0 && total / vec->capacity != sizeof(T))      \
                return 0; /* integer overflow */                               \
            new_data = (T*)realloc(vec->data, total);                          \
            if (!new_data)                                                     \
                return 0;                                                      \
            vec->data = new_data;                                              \
        }                                                                      \
        return 1;                                                              \
    }                                                                          \
    specifier int name##_push(name* vec, T value) {                            \
        if (!name##_reserve(vec, vec->size + 1)) {                             \
            return 0;                                                          \
        }                                                                      \
        vec->data[vec->size++] = value;                                        \
        return 1;                                                              \
    }