summaryrefslogtreecommitdiff
path: root/include/al/array_typed.h
blob: 73e77f7ca688301c904c1a0e797b9253a1e5e947 (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
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#ifndef _AL_ARRAY_TYPED_H
#define _AL_ARRAY_TYPED_H

#ifndef AL_HAVE_GNU_EXTENSIONS
#error "missing required GNU C extensions"
#endif

#include "macros.h"

#define AL_EMPTY_DEFAULT_1(FUNC, T, S, ...) FUNC(T, S)
#define AL_EMPTY_DEFAULT(...) AL_EMPTY_DEFAULT_1(__VA_ARGS__, , )

#define _array(N, ...) AL_PASTER(array, AL_PASTER(N, __VA_ARGS__))
#define _al_array_init(N, ...) AL_PASTER(_array_init, AL_PASTER(N, __VA_ARGS__))
#define _al_array_data(N, ...) AL_PASTER(_array_data, AL_PASTER(N, __VA_ARGS__))
#define _al_array_reserve(N, ...) AL_PASTER(_array_reserve, AL_PASTER(N, __VA_ARGS__))
#define __al_array_reserve_internal(N, ...) AL_PASTER(_array_reserve_internal, AL_PASTER(N, __VA_ARGS__))
#define _al_array_at(N, ...) AL_PASTER(_array_at, AL_PASTER(N, __VA_ARGS__))
#define _al_array_last(N, ...) AL_PASTER(_array_last, AL_PASTER(N, __VA_ARGS__))
#define _al_array_push(N, ...) AL_PASTER(_array_push, AL_PASTER(N, __VA_ARGS__))
#define _al_array_pop(N, ...) AL_PASTER(_array_pop, AL_PASTER(N, __VA_ARGS__))
#define _al_array_remove_at(N, ...) AL_PASTER(_array_remove_at, AL_PASTER(N, __VA_ARGS__))
#define _al_array_pop_at(N, ...) AL_PASTER(_array_pop_at, AL_PASTER(N, __VA_ARGS__))
#define _al_array_insert(N, ...) AL_PASTER(_array_insert, AL_PASTER(N, __VA_ARGS__))
#define _al_array_free(N, ...) AL_PASTER(_array_free, AL_PASTER(N, __VA_ARGS__))

#define array(...) AL_EMPTY_DEFAULT(_array, __VA_ARGS__)
#define al_array_init(...) AL_EMPTY_DEFAULT(_al_array_init, __VA_ARGS__)
#define al_array_data(...) AL_EMPTY_DEFAULT(_al_array_data, __VA_ARGS__)
#define _al_array_reserve_internal(...) AL_EMPTY_DEFAULT(__al_array_reserve_internal, __VA_ARGS__)
#define al_array_reserve(...) AL_EMPTY_DEFAULT(_al_array_reserve, __VA_ARGS__)
#define al_array_at(...) AL_EMPTY_DEFAULT(_al_array_at, __VA_ARGS__)
#define al_array_last(...) AL_EMPTY_DEFAULT(_al_array_last, __VA_ARGS__)
#define al_array_push(...) AL_EMPTY_DEFAULT(_al_array_push, __VA_ARGS__)
#define al_array_pop(...) AL_EMPTY_DEFAULT(_al_array_pop, __VA_ARGS__)
#define al_array_remove_at(...) AL_EMPTY_DEFAULT(_al_array_remove_at, __VA_ARGS__)
#define al_array_pop_at(...) AL_EMPTY_DEFAULT(_al_array_pop_at, __VA_ARGS__)
#define al_array_insert(...) AL_EMPTY_DEFAULT(_al_array_insert, __VA_ARGS__)
#define al_array_free(...) AL_EMPTY_DEFAULT(_al_array_free, __VA_ARGS__)

#define AL_ARRAY_DEFINE_FUNCTIONS(N, T, ...) \
    static inline T *al_array_at(N, __VA_ARGS__)(array(N, __VA_ARGS__) *array, u32 i) \
    { \
        return &al_array_data(N, __VA_ARGS__)(array)[i]; \
    } \
    static inline T *al_array_last(N, __VA_ARGS__)(array(N, __VA_ARGS__) *array) \
    { \
        return al_array_at(N, __VA_ARGS__)(array, array->count - 1); \
    } \
    static inline void al_array_reserve(N, __VA_ARGS__)(array(N, __VA_ARGS__) *array, u32 count); \
    static inline void al_array_push(N, __VA_ARGS__)(array(N, __VA_ARGS__) *array, T value) \
    { \
        al_array_reserve(N, __VA_ARGS__)(array, array->count + 1); \
        *al_array_at(N, __VA_ARGS__)(array, array->count++) = value; \
    } \
    static inline void al_array_insert(N, __VA_ARGS__)(array(N, __VA_ARGS__) *array, u32 i, T item) \
    { \
        al_array_reserve(N, __VA_ARGS__)(array, array->count + 1); \
        if (i != array->count - 1) { \
            al_memmove(al_array_at(N, __VA_ARGS__)(array, i + 1), al_array_at(N, __VA_ARGS__)(array, i), \
                (array->count - i) * sizeof(T)); \
        } \
        array->count++; \
        *al_array_at(N, __VA_ARGS__)(array, i) = item; \
    } \
    static inline void al_array_pop(N, __VA_ARGS__)(array(N, __VA_ARGS__) *array, T *ret) \
    { \
        *ret = *al_array_at(N, __VA_ARGS__)(array, --array->count); \
    } \
    static inline void al_array_remove_at(N, __VA_ARGS__)(array(N, __VA_ARGS__) *array, u32 i) \
    { \
        if (UNLIKELY(i == array->count - 1)) { \
            array->count--; \
        } else { \
            al_memmove(al_array_at(N, __VA_ARGS__)(array, i), al_array_at(N, __VA_ARGS__)(array, i + 1), \
                (--array->count - i) * sizeof(T)); \
        } \
    } \
    static inline T al_array_pop_at(N, __VA_ARGS__)(array(N, __VA_ARGS__) *array, u32 i) \
    { \
        T ret = *al_array_at(N, __VA_ARGS__)(array, i); \
        al_array_remove_at(N, __VA_ARGS__)(array, i); \
        return ret; \
    } \
    static inline void _al_array_reserve_internal(N, __VA_ARGS__)(array(N, __VA_ARGS__) *array, u32 size) \
    { \
        array->alloc = al_growing_allocation((void **)&array->data, array->alloc, size, al_realloc); \
    } \
    static inline void al_array_free(N, __VA_ARGS__)(array(N, __VA_ARGS__) *array) \
    { \
        if (array->data) al_free(array->data); \
    }

#define AL_ARRAY_DEFINE(N, T) \
    typedef struct array(N) array(N); \
    struct array(N) { \
        u32 count; \
        u32 alloc; \
        T *data; \
    }; \
    static inline void al_array_init(N)(array(N) *array) \
    { \
        array->count = 0; \
        array->alloc = 0; \
        array->data = NULL; \
    } \
    static inline T *al_array_data(N)(array(N) *array) \
    { \
        return array->data; \
    } \
    AL_ARRAY_DEFINE_FUNCTIONS(N, T,) \
    static inline void al_array_reserve(N)(array(N) *array, u32 count) \
    { \
        _al_array_reserve_internal(N)(array, count * sizeof(T)); \
    }

#define AL_ARRAY_INLINE_STORAGE_DEFINE(N, T, S) \
    typedef struct array(N, S) array(N, S); \
    struct array(N, S) { \
        u32 count; \
        u32 alloc; \
        T *data; \
        T inline_data[S]; \
    }; \
    static inline void al_array_init(N, S)(array(N, S) *array) \
    { \
        array->count = 0; \
        array->alloc = S * sizeof(T); \
        array->data = NULL; \
    } \
    static inline T *al_array_data(N, S)(array(N, S) *array) \
    { \
        if (array->data) return array->data; \
        else return array->inline_data; \
    } \
    AL_ARRAY_DEFINE_FUNCTIONS(N, T, S) \
    static inline void al_array_reserve(N, S)(array(N, S) *array, u32 count) \
    { \
        if (S >= count) { \
            return; \
        } \
        bool copy_inline = array->data == NULL; \
        _al_array_reserve_internal(N, S)(array, count * sizeof(T)); \
        if (UNLIKELY(copy_inline)) { \
            al_memcpy(array->data, array->inline_data, array->count * sizeof(T)); \
        } \
    }

#endif // _AL_ARRAY_TYPED_H