URI:
       array.h - ltk - GUI toolkit for X11 (WIP)
  HTML git clone git://lumidify.org/ltk.git (fast, but not encrypted)
  HTML git clone https://lumidify.org/git/ltk.git (encrypted, but very slow)
  HTML git clone git://4kcetb7mo7hj6grozzybxtotsub5bempzo4lirzc3437amof2c2impyd.onion/ltk.git (over tor)
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       array.h (11836B)
       ---
            1 /* FIXME: oops, I guess I left the old MIT license here - not sure if I should just
            2    leave it as is or update it to ISC... */
            3 /*
            4  * Copyright (c) 2020-2026 lumidify <nobody@lumidify.org>
            5  *
            6  * Permission is hereby granted, free of charge, to any person obtaining a copy
            7  * of this software and associated documentation files (the "Software"), to deal
            8  * in the Software without restriction, including without limitation the rights
            9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
           10  * copies of the Software, and to permit persons to whom the Software is
           11  * furnished to do so, subject to the following conditions:
           12  *
           13  * The above copyright notice and this permission notice shall be included in all
           14  * copies or substantial portions of the Software.
           15  *
           16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
           17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
           18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
           19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
           20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
           21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
           22  * SOFTWARE.
           23  */
           24 
           25 #ifndef LTK_ARRAY_H
           26 #define LTK_ARRAY_H
           27 
           28 #include <stdio.h>
           29 #include <stdlib.h>
           30 #include <string.h>
           31 
           32 #include "util.h"
           33 #include "memory.h"
           34 
           35 /* FIXME: make this work on more compilers? */
           36 #if (defined(__GNUC__) || defined(__clang__))
           37 #define LTK_UNUSED_FUNC __attribute__((unused))
           38 #else
           39 #define LTK_UNUSED_FUNC
           40 #endif
           41 
           42 /* FIXME: add accesser macros; also add init function to not allocate array itself but initialize given pointer */
           43 /* FIXME: separate struct definition and forward-declaration for header files */
           44 
           45 #define LTK_ARRAY_INIT_STRUCT_DECL_BASE(name, type, storage)                                                                \
           46 typedef struct {                                                                                                        \
           47         type *buf;                                                                                                        \
           48         size_t buf_size;                                                                                                \
           49         size_t len;                                                                                                        \
           50 } ltk_array_##name;
           51 
           52 #define LTK_ARRAY_INIT_FUNC_DECL_BASE(name, type, storage)                                                                        \
           53 LTK_UNUSED_FUNC storage ltk_array_##name *ltk_array_create_##name(size_t initial_capacity);                                        \
           54 LTK_UNUSED_FUNC storage type ltk_array_pop_##name(ltk_array_##name *ar);                                                        \
           55 LTK_UNUSED_FUNC storage size_t ltk_array_remove_if_##name(                                                                        \
           56         ltk_array_##name *ar, int (*callback)(type *, void *), void *data                                                        \
           57 );                                                                                                                                \
           58 LTK_UNUSED_FUNC storage void ltk_array_prepare_gap_##name(ltk_array_##name *ar, size_t index, size_t len);                        \
           59 LTK_UNUSED_FUNC storage void ltk_array_insert_##name(ltk_array_##name *ar, size_t index, type elem);                                \
           60 LTK_UNUSED_FUNC storage void ltk_array_insert_multiple_##name(ltk_array_##name *ar, size_t index, type *elem, size_t len);        \
           61 LTK_UNUSED_FUNC storage void ltk_array_delete_##name(ltk_array_##name *ar, size_t index, size_t len);                                \
           62 LTK_UNUSED_FUNC storage void ltk_array_resize_##name(ltk_array_##name *ar, size_t size, type default_val);                        \
           63 LTK_UNUSED_FUNC storage void ltk_array_change_capacity_##name(ltk_array_##name *ar, size_t size);                                \
           64 LTK_UNUSED_FUNC storage void ltk_array_len_to_capacity_##name(ltk_array_##name *ar, type default_val);                                \
           65 LTK_UNUSED_FUNC storage void ltk_array_destroy_##name(ltk_array_##name *ar);                                                        \
           66 LTK_UNUSED_FUNC storage void ltk_array_reset_##name(ltk_array_##name *ar);                                                        \
           67 LTK_UNUSED_FUNC storage void ltk_array_append_##name(ltk_array_##name *ar, type elem);                                                \
           68 LTK_UNUSED_FUNC storage void ltk_array_destroy_deep_##name(ltk_array_##name *ar, void (*destroy_func)(type));                        \
           69 LTK_UNUSED_FUNC storage type ltk_array_get_safe_##name(ltk_array_##name *ar, size_t index);                                        \
           70 LTK_UNUSED_FUNC storage void ltk_array_set_safe_##name(ltk_array_##name *ar, size_t index, type e);
           71 
           72 #define LTK_ARRAY_INIT_IMPL_BASE(name, type, storage)                                                        \
           73 LTK_UNUSED_FUNC storage ltk_array_##name *                                                                \
           74 ltk_array_create_##name(size_t initial_capacity) {                                                        \
           75         if (initial_capacity == 0)                                                                        \
           76                 ltk_fatal("Array capacity is zero\n");                                                        \
           77         ltk_array_##name *ar = ltk_malloc(sizeof(ltk_array_##name));                                        \
           78         ar->buf = ltk_reallocarray(NULL, initial_capacity, sizeof(type));                                \
           79         ar->buf_size = initial_capacity;                                                                \
           80         ar->len = 0;                                                                                        \
           81         return ar;                                                                                        \
           82 }                                                                                                        \
           83                                                                                                         \
           84 LTK_UNUSED_FUNC storage type                                                                                \
           85 ltk_array_pop_##name(ltk_array_##name *ar) {                                                                \
           86         if (ar->len == 0)                                                                                 \
           87                 ltk_fatal("Array empty; cannot pop.\n");                                                \
           88         ar->len--;                                                                                        \
           89         return ar->buf[ar->len];                                                                        \
           90 }                                                                                                        \
           91                                                                                                         \
           92 LTK_UNUSED_FUNC storage size_t                                                                                \
           93 ltk_array_remove_if_##name(ltk_array_##name *ar, int (*callback)(type *, void *), void *data) {                \
           94         size_t removed = 0;                                                                                \
           95         for (size_t i = 0; i < ar->len; i++) {                                                                \
           96                 if (callback(&ar->buf[i], data))                                                        \
           97                         removed++;                                                                        \
           98                 else                                                                                        \
           99                         ar->buf[i - removed] = ar->buf[i];                                                \
          100         }                                                                                                \
          101         /* FIXME: maybe release memory */                                                                \
          102         ar->len -= removed;                                                                                \
          103         return removed;                                                                                        \
          104 }                                                                                                        \
          105                                                                                                         \
          106 /* FIXME: having this function in the public interface is ugly */                                        \
          107 LTK_UNUSED_FUNC storage void                                                                                \
          108 ltk_array_prepare_gap_##name(ltk_array_##name *ar, size_t index, size_t len) {                                \
          109         if (index > ar->len)                                                                                 \
          110                 ltk_fatal("Array index out of bounds\n");                                                \
          111         ltk_array_change_capacity_##name(ar, ar->len + len);                                                \
          112         ar->len += len;                                                                                        \
          113         if (ar->len - len == index)                                                                        \
          114                 return;                                                                                        \
          115         memmove(ar->buf + index + len, ar->buf + index,                                                        \
          116             (ar->len - len - index) * sizeof(type));                                                        \
          117 }                                                                                                        \
          118                                                                                                         \
          119 LTK_UNUSED_FUNC storage void                                                                                \
          120 ltk_array_insert_##name(ltk_array_##name *ar, size_t index, type elem) {                                \
          121         ltk_array_prepare_gap_##name(ar, index, 1);                                                        \
          122         ar->buf[index] = elem;                                                                                \
          123 }                                                                                                        \
          124                                                                                                         \
          125 LTK_UNUSED_FUNC storage void                                                                                \
          126 ltk_array_insert_multiple_##name(ltk_array_##name *ar, size_t index, type *elem, size_t len) {                \
          127         ltk_array_prepare_gap_##name(ar, index, len);                                                        \
          128         for (size_t i = 0; i < len; i++) {                                                                \
          129                 ar->buf[index + i] = elem[i];                                                                \
          130         }                                                                                                \
          131 }                                                                                                        \
          132                                                                                                         \
          133 LTK_UNUSED_FUNC storage void                                                                                \
          134 ltk_array_delete_##name(ltk_array_##name *ar, size_t index, size_t len) {                                \
          135         /* FIXME: integer overflow protection everywhere */                                                \
          136         if (index + len > ar->len)                                                                        \
          137                 ltk_fatal("Array index out of bounds\n");                                                \
          138         /* FIXME: maybe release memory at some point? */                                                \
          139         memmove(ar->buf + index, ar->buf + index + len, (ar->len - index - len) * sizeof(type));        \
          140         ar->len -= len;                                                                                        \
          141 }                                                                                                        \
          142                                                                                                         \
          143 LTK_UNUSED_FUNC storage void                                                                                \
          144 ltk_array_append_##name(ltk_array_##name *ar, type elem) {                                                \
          145         if (ar->len == ar->buf_size)                                                                        \
          146                 ltk_array_change_capacity_##name(ar, ar->len + 1);                                        \
          147         ar->buf[ar->len++] = elem;                                                                        \
          148 }                                                                                                        \
          149                                                                                                         \
          150 LTK_UNUSED_FUNC storage void                                                                                \
          151 ltk_array_reset_##name(ltk_array_##name *ar) {                                                                \
          152         ar->len = 0;                                                                                        \
          153         ltk_array_change_capacity_##name(ar, 1);                                                        \
          154 }                                                                                                        \
          155                                                                                                         \
          156 LTK_UNUSED_FUNC storage void                                                                                \
          157 ltk_array_resize_##name(ltk_array_##name *ar, size_t len, type default_val) {                                \
          158         ltk_array_change_capacity_##name(ar, len);                                                        \
          159         for (size_t i = ar->len; i < len; i++) {                                                        \
          160                 ar->buf[i] = default_val;                                                                \
          161         }                                                                                                \
          162         ar->len = len;                                                                                        \
          163 }                                                                                                        \
          164                                                                                                         \
          165 LTK_UNUSED_FUNC storage void                                                                                \
          166 ltk_array_change_capacity_##name(ltk_array_##name *ar, size_t len) {                                        \
          167         size_t new_size = ideal_array_size(ar->buf_size, len);                                                \
          168         if (new_size != ar->buf_size) {                                                                        \
          169                 ar->buf = ltk_reallocarray(ar->buf, new_size, sizeof(type));                                \
          170                 ar->buf_size = new_size;                                                                \
          171                 ar->len = ar->len < new_size ? ar->len : new_size;                                        \
          172         }                                                                                               \
          173 }                                                                                                        \
          174                                                                                                         \
          175 LTK_UNUSED_FUNC storage void                                                                                \
          176 ltk_array_len_to_capacity_##name(ltk_array_##name *ar, type default_val) {                                \
          177         for (size_t i = ar->len; i < ar->buf_size; i++) {                                                \
          178                 ar->buf[i] = default_val;                                                                \
          179         }                                                                                                \
          180         ar->len = ar->buf_size;                                                                                \
          181 }                                                                                                        \
          182                                                                                                         \
          183 LTK_UNUSED_FUNC storage void                                                                                \
          184 ltk_array_destroy_##name(ltk_array_##name *ar) {                                                        \
          185         if (!ar)                                                                                        \
          186                 return;                                                                                        \
          187         ltk_free(ar->buf);                                                                                \
          188         ltk_free(ar);                                                                                        \
          189 }                                                                                                        \
          190                                                                                                         \
          191 LTK_UNUSED_FUNC storage void                                                                                \
          192 ltk_array_destroy_deep_##name(ltk_array_##name *ar, void (*destroy_func)(type)) {                        \
          193         if (!ar)                                                                                        \
          194                 return;                                                                                        \
          195         for (size_t i = 0; i < ar->len; i++) {                                                                \
          196                 destroy_func(ar->buf[i]);                                                                \
          197         }                                                                                                \
          198         ltk_array_destroy_##name(ar);                                                                        \
          199 }                                                                                                        \
          200                                                                                                         \
          201 LTK_UNUSED_FUNC storage type                                                                                \
          202 ltk_array_get_safe_##name(ltk_array_##name *ar, size_t index) {                                                \
          203         if (index >= ar->len)                                                                                \
          204                 ltk_fatal("Index out of bounds.\n");                                                        \
          205         return ar->buf[index];                                                                                \
          206 }                                                                                                        \
          207                                                                                                         \
          208 LTK_UNUSED_FUNC storage void                                                                                \
          209 ltk_array_set_safe_##name(ltk_array_##name *ar, size_t index, type e) {                                        \
          210         if (index >= ar->len)                                                                                \
          211                 ltk_fatal("Index out of bounds.\n");                                                        \
          212         ar->buf[index] = e;                                                                                \
          213 }
          214 
          215 /* FIXME: resize and change_capacity should maybe also take destroy_func optionally if size/capacity is decreased */
          216 #define ltk_array(name) ltk_array_##name
          217 #define ltk_array_create(name, initial_capacity) ltk_array_create_##name(initial_capacity)
          218 #define ltk_array_pop(name, ar) ltk_array_pop_##name(ar)
          219 #define ltk_array_remove_if(name, ar, callback, data) ltk_array_remove_if_##name(ar, callback, data)
          220 #define ltk_array_insert(name, ar, index, elem) ltk_array_insert_##name(ar, index, elem)
          221 #define ltk_array_insert_multiple(name, ar, index, elem, len) ltk_array_insert_multiple_##name(ar, index, elem, len)
          222 #define ltk_array_delete(name, ar, index, len) ltk_array_delete_##name(ar, index, len)
          223 #define ltk_array_resize(name, ar, size, default_val) ltk_array_resize_##name(ar, size, default_val)
          224 #define ltk_array_change_capacity(name, ar, size) ltk_array_change_capacity_##name(ar, size)
          225 #define ltk_array_len_to_capacity(name, ar, default_val) ltk_array_len_to_capacity_##name(ar, default_val)
          226 #define ltk_array_destroy(name, ar) ltk_array_destroy_##name(ar)
          227 #define ltk_array_reset(name, ar) ltk_array_reset_##name(ar)
          228 #define ltk_array_clear(ar) ((ar)->len = 0)
          229 #define ltk_array_append(name, ar, elem) ltk_array_append_##name(ar, elem)
          230 #define ltk_array_destroy_deep(name, ar, destroy_func) ltk_array_destroy_deep_##name(ar, destroy_func)
          231 #define ltk_array_len(ar) ((ar)->len)
          232 #define ltk_array_get_buf(ar) ((ar)->buf)
          233 #define ltk_array_get(ar, index) ((ar)->buf[index])
          234 #define ltk_array_get_safe(name, ar, index) ltk_array_get_safe_##name(ar, index)
          235 #define ltk_array_set_safe(name, ar, index, e) ltk_array_set_safe_##name(ar, index, e)
          236 
          237 #define LTK_ARRAY_INIT_DECL(name, type)                        \
          238 LTK_ARRAY_INIT_STRUCT_DECL_BASE(name, type,)                \
          239 LTK_ARRAY_INIT_FUNC_DECL_BASE(name, type,)
          240 
          241 /* mainly for header files that shouldn't include all the function declarations */
          242 #define LTK_ARRAY_INIT_STRUCT_DECL(name, type)LTK_ARRAY_INIT_STRUCT_DECL_BASE(name, type,)
          243 #define LTK_ARRAY_INIT_FUNC_DECL(name, type)LTK_ARRAY_INIT_FUNC_DECL_BASE(name, type,)
          244 #define LTK_ARRAY_INIT_FUNC_DECL_STATIC(name, type)LTK_ARRAY_INIT_FUNC_DECL_BASE(name, type, static)
          245 
          246 #define LTK_ARRAY_INIT_DECL_STATIC(name, type)                \
          247 LTK_ARRAY_INIT_STRUCT_DECL_BASE(name, type, static)        \
          248 LTK_ARRAY_INIT_FUNC_DECL_BASE(name, type, static)
          249 
          250 #define LTK_ARRAY_INIT_IMPL(name, type) LTK_ARRAY_INIT_IMPL_BASE(name, type,)
          251 #define LTK_ARRAY_INIT_IMPL_STATIC(name, type) LTK_ARRAY_INIT_IMPL_BASE(name, type, static)
          252 
          253 #endif /* LTK_ARRAY_H */