ltk

Socket-based GUI for X11 (WIP)
git clone git://lumidify.org/ltk.git (fast, but not encrypted)
git clone https://lumidify.org/git/ltk.git (encrypted, but very slow)
Log | Files | Refs | README | LICENSE

array.h (7752B)


      1 /*
      2  * This file is part of the Lumidify ToolKit (LTK)
      3  * Copyright (c) 2020, 2023 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 #include "util.h"
     31 #include "memory.h"
     32 
     33 /* FIXME: make this work on more compilers? */
     34 #if (defined(__GNUC__) || defined(__clang__))
     35 #define LTK_UNUSED_FUNC __attribute__((unused))
     36 #else
     37 #define LTK_UNUSED_FUNC
     38 #endif
     39 
     40 #define LTK_ARRAY_INIT_DECL_BASE(name, type, storage)									\
     41 typedef struct {													\
     42 	type *buf;													\
     43 	size_t buf_size;												\
     44 	size_t len;													\
     45 } ltk_array_##name;													\
     46 															\
     47 LTK_UNUSED_FUNC storage ltk_array_##name *ltk_array_create_##name(size_t initial_len);					\
     48 LTK_UNUSED_FUNC storage type ltk_array_pop_##name(ltk_array_##name *ar);						\
     49 LTK_UNUSED_FUNC storage void ltk_array_prepare_gap_##name(ltk_array_##name *ar, size_t index, size_t len);		\
     50 LTK_UNUSED_FUNC storage void ltk_array_insert_##name(ltk_array_##name *ar, size_t index, type *elem, size_t len);	\
     51 LTK_UNUSED_FUNC storage void ltk_array_resize_##name(ltk_array_##name *ar, size_t size);				\
     52 LTK_UNUSED_FUNC storage void ltk_array_destroy_##name(ltk_array_##name *ar);						\
     53 LTK_UNUSED_FUNC storage void ltk_array_clear_##name(ltk_array_##name *ar);						\
     54 LTK_UNUSED_FUNC storage void ltk_array_append_##name(ltk_array_##name *ar, type elem);					\
     55 LTK_UNUSED_FUNC storage void ltk_array_destroy_deep_##name(ltk_array_##name *ar, void (*destroy_func)(type));		\
     56 LTK_UNUSED_FUNC storage type ltk_array_get_safe_##name(ltk_array_##name *ar, size_t index);				\
     57 LTK_UNUSED_FUNC storage void ltk_array_set_safe_##name(ltk_array_##name *ar, size_t index, type e);
     58 
     59 #define LTK_ARRAY_INIT_IMPL_BASE(name, type, storage)							\
     60 LTK_UNUSED_FUNC storage ltk_array_##name *								\
     61 ltk_array_create_##name(size_t initial_len) {								\
     62 	if (initial_len == 0)										\
     63 		ltk_fatal("Array length is zero\n");							\
     64 	ltk_array_##name *ar = ltk_malloc(sizeof(ltk_array_##name));					\
     65 	ar->buf = ltk_reallocarray(NULL, initial_len, sizeof(type));					\
     66 	ar->buf_size = initial_len;									\
     67 	ar->len = 0;											\
     68 	return ar;											\
     69 }													\
     70 													\
     71 LTK_UNUSED_FUNC storage type										\
     72 ltk_array_pop_##name(ltk_array_##name *ar) {								\
     73 	if (ar->len == 0) 										\
     74 		ltk_fatal("Array empty; cannot pop.\n");						\
     75 	ar->len--;											\
     76 	return ar->buf[ar->len];									\
     77 }													\
     78 													\
     79 /* FIXME: having this function in the public interface is ugly */					\
     80 LTK_UNUSED_FUNC storage void										\
     81 ltk_array_prepare_gap_##name(ltk_array_##name *ar, size_t index, size_t len) {				\
     82 	if (index > ar->len) 										\
     83 		ltk_fatal("Array index out of bounds\n");						\
     84 	ltk_array_resize_##name(ar, ar->len + len);							\
     85 	ar->len += len;											\
     86 	if (ar->len - len == index)									\
     87 		return;											\
     88 	memmove(ar->buf + index + len, ar->buf + index,							\
     89 	    (ar->len - len - index) * sizeof(type));							\
     90 }													\
     91 													\
     92 LTK_UNUSED_FUNC storage void										\
     93 ltk_array_insert_##name(ltk_array_##name *ar, size_t index, type *elem, size_t len) {			\
     94 	ltk_array_prepare_gap_##name(ar, index, len);							\
     95 	for (size_t i = 0; i < len; i++) {								\
     96 		ar->buf[index + i] = elem[i];								\
     97 	}												\
     98 }													\
     99 													\
    100 LTK_UNUSED_FUNC storage void										\
    101 ltk_array_append_##name(ltk_array_##name *ar, type elem) {						\
    102 	if (ar->len == ar->buf_size)									\
    103 		ltk_array_resize_##name(ar, ar->len + 1);						\
    104 	ar->buf[ar->len++] = elem;									\
    105 }													\
    106 													\
    107 LTK_UNUSED_FUNC storage void										\
    108 ltk_array_clear_##name(ltk_array_##name *ar) {								\
    109 	ar->len = 0;											\
    110 	ltk_array_resize_##name(ar, 1);									\
    111 }													\
    112 													\
    113 LTK_UNUSED_FUNC storage void										\
    114 ltk_array_resize_##name(ltk_array_##name *ar, size_t len) {						\
    115 	size_t new_size = ideal_array_size(ar->buf_size, len);						\
    116 	if (new_size != ar->buf_size) {									\
    117 		ar->buf = ltk_reallocarray(ar->buf, new_size, sizeof(type));				\
    118 		ar->buf_size = new_size;								\
    119 		ar->len = ar->len < new_size ? ar->len : new_size;					\
    120 	}                                                                               		\
    121 }													\
    122 													\
    123 LTK_UNUSED_FUNC storage void										\
    124 ltk_array_destroy_##name(ltk_array_##name *ar) {							\
    125 	if (!ar)											\
    126 		return;											\
    127 	ltk_free(ar->buf);										\
    128 	ltk_free(ar);											\
    129 }													\
    130 													\
    131 LTK_UNUSED_FUNC storage void										\
    132 ltk_array_destroy_deep_##name(ltk_array_##name *ar, void (*destroy_func)(type)) {			\
    133 	if (!ar)											\
    134 		return;											\
    135 	for (size_t i = 0; i < ar->len; i++) {								\
    136 		destroy_func(ar->buf[i]);								\
    137 	}												\
    138 	ltk_array_destroy_##name(ar);									\
    139 }													\
    140 													\
    141 LTK_UNUSED_FUNC storage type										\
    142 ltk_array_get_safe_##name(ltk_array_##name *ar, size_t index) {						\
    143 	if (index >= ar->len)										\
    144 		ltk_fatal("Index out of bounds.\n");							\
    145 	return ar->buf[index];										\
    146 }													\
    147 													\
    148 LTK_UNUSED_FUNC storage void										\
    149 ltk_array_set_safe_##name(ltk_array_##name *ar, size_t index, type e) {					\
    150 	if (index >= ar->len)										\
    151 		ltk_fatal("Index out of bounds.\n");							\
    152 	ar->buf[index] = e;										\
    153 }
    154 
    155 #define ltk_array(name) ltk_array_##name
    156 #define ltk_array_create(name, initial_len) ltk_array_create_##name(initial_len)
    157 #define ltk_array_pop(name, ar) ltk_array_pop_##name(ar)
    158 #define ltk_array_insert(name, ar, index, elem, len) ltk_array_insert_##name(ar, index, elem, len)
    159 #define ltk_array_resize(name, ar, size) ltk_array_resize_##name(ar, size)
    160 #define ltk_array_destroy(name, ar) ltk_array_destroy_##name(ar)
    161 #define ltk_array_clear(name, ar) ltk_array_clear_##name(ar)
    162 #define ltk_array_append(name, ar, elem) ltk_array_append_##name(ar, elem)
    163 #define ltk_array_destroy_deep(name, ar, destroy_func) ltk_array_destroy_deep_##name(ar, destroy_func)
    164 #define ltk_array_length(ar) ((ar)->len)
    165 #define ltk_array_get(ar, index) ((ar)->buf[index])
    166 #define ltk_array_get_safe(name, ar, index) ltk_array_get_safe_##name(ar, index)
    167 #define ltk_array_set_safe(name, ar, index, e) ltk_array_set_safe_##name(ar, index, e)
    168 
    169 #define LTK_ARRAY_INIT_DECL(name, type) LTK_ARRAY_INIT_DECL_BASE(name, type,)
    170 #define LTK_ARRAY_INIT_IMPL(name, type) LTK_ARRAY_INIT_IMPL_BASE(name, type,)
    171 #define LTK_ARRAY_INIT_DECL_STATIC(name, type) LTK_ARRAY_INIT_DECL_BASE(name, type, static)
    172 #define LTK_ARRAY_INIT_IMPL_STATIC(name, type) LTK_ARRAY_INIT_IMPL_BASE(name, type, static)
    173 
    174 #endif /* _LTK_ARRAY_H_ */