1 | #ifndef NVIM_GARRAY_H |
2 | #define NVIM_GARRAY_H |
3 | |
4 | #include <stddef.h> // for size_t |
5 | |
6 | #include "nvim/types.h" // for char_u |
7 | #include "nvim/log.h" |
8 | |
9 | /// Structure used for growing arrays. |
10 | /// This is used to store information that only grows, is deleted all at |
11 | /// once, and needs to be accessed by index. See ga_clear() and ga_grow(). |
12 | typedef struct growarray { |
13 | int ga_len; // current number of items used |
14 | int ga_maxlen; // maximum number of items possible |
15 | int ga_itemsize; // sizeof(item) |
16 | int ga_growsize; // number of items to grow each time |
17 | void *ga_data; // pointer to the first item |
18 | } garray_T; |
19 | |
20 | #define GA_EMPTY_INIT_VALUE { 0, 0, 0, 1, NULL } |
21 | #define GA_INIT(itemsize, growsize) { 0, 0, (itemsize), (growsize), NULL } |
22 | |
23 | #define GA_EMPTY(ga_ptr) ((ga_ptr)->ga_len <= 0) |
24 | |
25 | #define GA_APPEND(item_type, gap, item) \ |
26 | do { \ |
27 | ga_grow(gap, 1); \ |
28 | ((item_type *)(gap)->ga_data)[(gap)->ga_len++] = (item); \ |
29 | } while (0) |
30 | |
31 | #define GA_APPEND_VIA_PTR(item_type, gap) \ |
32 | ga_append_via_ptr(gap, sizeof(item_type)) |
33 | |
34 | #ifdef INCLUDE_GENERATED_DECLARATIONS |
35 | # include "garray.h.generated.h" |
36 | #endif |
37 | |
38 | static inline void *ga_append_via_ptr(garray_T *gap, size_t item_size) |
39 | { |
40 | if ((int)item_size != gap->ga_itemsize) { |
41 | WLOG("wrong item size (%zu), should be %d" , item_size, gap->ga_itemsize); |
42 | } |
43 | ga_grow(gap, 1); |
44 | return ((char *)gap->ga_data) + (item_size * (size_t)gap->ga_len++); |
45 | } |
46 | |
47 | /// Deep free a garray of specific type using a custom free function. |
48 | /// Items in the array as well as the array itself are freed. |
49 | /// |
50 | /// @param gap the garray to be freed |
51 | /// @param item_type type of the item in the garray |
52 | /// @param free_item_fn free function that takes (*item_type) as parameter |
53 | #define GA_DEEP_CLEAR(gap, item_type, free_item_fn) \ |
54 | do { \ |
55 | garray_T *_gap = (gap); \ |
56 | if (_gap->ga_data != NULL) { \ |
57 | for (int i = 0; i < _gap->ga_len; i++) { \ |
58 | item_type *_item = &(((item_type *)_gap->ga_data)[i]); \ |
59 | free_item_fn(_item); \ |
60 | } \ |
61 | } \ |
62 | ga_clear(_gap); \ |
63 | } while (false) |
64 | |
65 | #define FREE_PTR_PTR(ptr) xfree(*(ptr)) |
66 | |
67 | /// Call `free` for every pointer stored in the garray and then frees the |
68 | /// garray. |
69 | /// |
70 | /// @param gap the garray to be freed |
71 | #define GA_DEEP_CLEAR_PTR(gap) GA_DEEP_CLEAR(gap, void*, FREE_PTR_PTR) |
72 | |
73 | #endif // NVIM_GARRAY_H |
74 | |