array.h (5528B)
1 /* 2 * This file is part of the Lumidify ToolKit (LTK) 3 * Copyright (c) 2020 lumidify <nobody@lumidify.org> 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a copy 6 * of this software and associated documentation files (the "Software"), to deal 7 * in the Software without restriction, including without limitation the rights 8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 * copies of the Software, and to permit persons to whom the Software is 10 * furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be included in all 13 * copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 * SOFTWARE. 22 */ 23 24 #ifndef _LTK_ARRAY_H_ 25 #define _LTK_ARRAY_H_ 26 27 #include <stdio.h> 28 #include <stdlib.h> 29 30 #define LTK_ARRAY_INIT_DECL(name, type) \ 31 struct ltk_array_##name { \ 32 type *buf; \ 33 size_t buf_size; \ 34 size_t len; \ 35 }; \ 36 \ 37 struct ltk_array_##name *ltk_array_create_##name(size_t initial_len); \ 38 type ltk_array_pop_##name(struct ltk_array_##name *ar); \ 39 void ltk_array_prepare_gap_##name( \ 40 struct ltk_array_##name *ar, size_t index, size_t len); \ 41 void ltk_array_insert_##name(struct ltk_array_##name *ar, size_t index, \ 42 type *elem, size_t len); \ 43 void ltk_array_resize_##name(struct ltk_array_##name *ar, size_t size); \ 44 void ltk_array_destroy_##name(struct ltk_array_##name *ar); \ 45 void ltk_array_clear_##name(struct ltk_array_##name *ar); \ 46 void ltk_array_append_##name(struct ltk_array_##name *ar, type elem); \ 47 void ltk_array_destroy_deep_##name(struct ltk_array_##name *ar, \ 48 void (*destroy_func)(type)); 49 50 #define LTK_ARRAY_INIT_IMPL(name, type) \ 51 struct ltk_array_##name * \ 52 ltk_array_create_##name(size_t initial_len) { \ 53 if (initial_len == 0) { \ 54 (void)fprintf(stderr, "Array length is zero\n"); \ 55 exit(1); \ 56 } \ 57 struct ltk_array_##name *ar = malloc(sizeof(struct ltk_array_##name)); \ 58 if (!ar) goto error; \ 59 ar->buf = malloc(initial_len * sizeof(type)); \ 60 if (!ar->buf) goto error; \ 61 ar->buf_size = initial_len; \ 62 ar->len = 0; \ 63 return ar; \ 64 error: \ 65 (void)fprintf(stderr, "Out of memory while trying to allocate array\n"); \ 66 exit(1); \ 67 } \ 68 \ 69 type \ 70 ltk_array_pop_##name(struct ltk_array_##name *ar) { \ 71 if (ar->len == 0) { \ 72 (void)fprintf(stderr, "Array empty; cannot pop.\n"); \ 73 exit(1); \ 74 } \ 75 ar->len--; \ 76 return ar->buf[ar->len]; \ 77 } \ 78 \ 79 void \ 80 ltk_array_prepare_gap_##name(struct ltk_array_##name *ar, size_t index, size_t len) { \ 81 if (index > ar->len) { \ 82 (void)fprintf(stderr, "Array index out of bounds\n"); \ 83 exit(1); \ 84 } \ 85 ltk_array_resize_##name(ar, ar->len + len); \ 86 ar->len += len; \ 87 if (ar->len - len == index) \ 88 return; \ 89 memmove(ar->buf + index + len, ar->buf + index, \ 90 (ar->len - len - index) * sizeof(type)); \ 91 } \ 92 \ 93 void \ 94 ltk_array_insert_##name(struct ltk_array_##name *ar, size_t index, \ 95 type *elem, size_t len) { \ 96 ltk_array_prepare_gap_##name(ar, index, len); \ 97 /*ltk_array_resize_##name(ar, ar->len + len);*/ \ 98 for (int i = 0; i < len; i++) { \ 99 ar->buf[index + i] = elem[i]; \ 100 } \ 101 } \ 102 \ 103 void \ 104 ltk_array_append_##name(struct ltk_array_##name *ar, type elem) { \ 105 if (ar->len == ar->buf_size) \ 106 ltk_array_resize_##name(ar, ar->len + 1); \ 107 ar->buf[ar->len] = elem; \ 108 ar->len++; \ 109 } \ 110 \ 111 void \ 112 ltk_array_clear_##name(struct ltk_array_##name *ar) { \ 113 ar->len = 0; \ 114 ltk_array_resize_##name(ar, 1); \ 115 } \ 116 \ 117 void \ 118 ltk_array_resize_##name(struct ltk_array_##name *ar, size_t len) { \ 119 size_t new_size; \ 120 if (4 * len <= ar->buf_size) { \ 121 new_size = 2 * len; \ 122 } else if (len > ar->buf_size) { \ 123 new_size = 2 * len; \ 124 } else { \ 125 return; \ 126 } \ 127 type *new = realloc(ar->buf, new_size * sizeof(type)); \ 128 if (!new) { \ 129 (void)fprintf(stderr, "Cannot realloc array\n"); \ 130 exit(1); \ 131 } \ 132 ar->buf = new; \ 133 ar->buf_size = new_size; \ 134 ar->len = ar->len < new_size ? ar->len : new_size; \ 135 } \ 136 \ 137 void \ 138 ltk_array_destroy_##name(struct ltk_array_##name *ar) { \ 139 free(ar->buf); \ 140 ar->buf = NULL; \ 141 free(ar); \ 142 } \ 143 \ 144 void \ 145 ltk_array_destroy_deep_##name(struct ltk_array_##name *ar, \ 146 void (*destroy_func)(type)) { \ 147 for (int i = 0; i < ar->len; i++) { \ 148 destroy_func(ar->buf[i]); \ 149 } \ 150 ltk_array_destroy_##name(ar); \ 151 } 152 153 #endif /* _LTK_ARRAY_H_ */