/* * Copyright © 2020 Benjamin Otte * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . * * Authors: Benjamin Otte */ #include G_BEGIN_DECLS #ifndef GDK_ARRAY_TYPE_NAME #define GDK_ARRAY_TYPE_NAME GdkArray #endif #ifndef GDK_ARRAY_NAME #define GDK_ARRAY_NAME gdk_array #endif #ifndef GDK_ARRAY_ELEMENT_TYPE #define GDK_ARRAY_ELEMENT_TYPE gpointer #endif #ifdef GDK_ARRAY_PREALLOC #if GDK_ARRAY_PREALLOC == 0 #undef GDK_ARRAY_PREALLOC #endif #endif #ifdef GDK_ARRAY_NULL_TERMINATED #define GDK_ARRAY_REAL_SIZE(_size) ((_size) + 1) #else #define GDK_ARRAY_REAL_SIZE(_size) (_size) #endif /* make this readable */ #define _T_ GDK_ARRAY_ELEMENT_TYPE #define GdkArray GDK_ARRAY_TYPE_NAME #define gdk_array_paste_more(GDK_ARRAY_NAME, func_name) GDK_ARRAY_NAME ## _ ## func_name #define gdk_array_paste(GDK_ARRAY_NAME, func_name) gdk_array_paste_more (GDK_ARRAY_NAME, func_name) #define gdk_array(func_name) gdk_array_paste (GDK_ARRAY_NAME, func_name) typedef struct GdkArray GdkArray; struct GdkArray { _T_ *start; _T_ *end; _T_ *end_allocation; #ifdef GDK_ARRAY_PREALLOC _T_ preallocated[GDK_ARRAY_REAL_SIZE(GDK_ARRAY_PREALLOC)]; #endif }; /* no G_GNUC_UNUSED here, if you don't use an array type, remove it. */ static inline void gdk_array(init) (GdkArray *self) { #ifdef GDK_ARRAY_PREALLOC self->start = self->preallocated; self->end = self->start; self->end_allocation = self->start + GDK_ARRAY_PREALLOC; #ifdef GDK_ARRAY_NULL_TERMINATED *self->start = *(_T_[1]) { 0 }; #endif #else self->start = NULL; self->end = NULL; self->end_allocation = NULL; #endif } static inline void gdk_array(free_elements) (_T_ *start, _T_ *end) { #ifdef GDK_ARRAY_FREE_FUNC _T_ *e; for (e = start; e < end; e++) #ifdef GDK_ARRAY_BY_VALUE GDK_ARRAY_FREE_FUNC (e); #else GDK_ARRAY_FREE_FUNC (*e); #endif #endif } /* no G_GNUC_UNUSED here */ static inline void gdk_array(clear) (GdkArray *self) { gdk_array(free_elements) (self->start, self->end); #ifdef GDK_ARRAY_PREALLOC if (self->start != self->preallocated) #endif g_free (self->start); gdk_array(init) (self); } G_GNUC_UNUSED static inline _T_ * gdk_array(get_data) (const GdkArray *self) { return self->start; } G_GNUC_UNUSED static inline _T_ * gdk_array(index) (const GdkArray *self, gsize pos) { return self->start + pos; } G_GNUC_UNUSED static inline gsize gdk_array(get_capacity) (const GdkArray *self) { return self->end_allocation - self->start; } G_GNUC_UNUSED static inline gsize gdk_array(get_size) (const GdkArray *self) { return self->end - self->start; } G_GNUC_UNUSED static inline gboolean gdk_array(is_empty) (const GdkArray *self) { return self->end == self->start; } G_GNUC_UNUSED static inline void gdk_array(reserve) (GdkArray *self, gsize n) { gsize new_size, size; if (n <= gdk_array(get_capacity) (self)) return; size = gdk_array(get_size) (self); new_size = 1 << g_bit_storage (MAX (GDK_ARRAY_REAL_SIZE (n), 16) - 1); #ifdef GDK_ARRAY_PREALLOC if (self->start == self->preallocated) { self->start = g_new (_T_, new_size); memcpy (self->start, self->preallocated, sizeof (_T_) * GDK_ARRAY_REAL_SIZE (size)); } else #endif #ifdef GDK_ARRAY_NULL_TERMINATED if (self->start == NULL) { self->start = g_new (_T_, new_size); *self->start = *(_T_[1]) { 0 }; } else #endif self->start = g_renew (_T_, self->start, new_size); self->end = self->start + size; self->end_allocation = self->start + new_size; #ifdef GDK_ARRAY_NULL_TERMINATED self->end_allocation--; #endif } G_GNUC_UNUSED static inline void gdk_array(splice) (GdkArray *self, gsize pos, gsize removed, _T_ *additions, gsize added) { gsize size; gsize remaining; size = gdk_array(get_size) (self); g_assert (pos + removed <= size); remaining = size - pos - removed; gdk_array(free_elements) (gdk_array(index) (self, pos), gdk_array(index) (self, pos + removed)); gdk_array(reserve) (self, size - removed + added); if (GDK_ARRAY_REAL_SIZE (remaining) && removed != added) memmove (gdk_array(index) (self, pos + added), gdk_array(index) (self, pos + removed), GDK_ARRAY_REAL_SIZE (remaining) * sizeof (_T_)); if (added) { if (additions) memcpy (gdk_array(index) (self, pos), additions, added * sizeof (_T_)); #ifndef GDK_ARRAY_NO_MEMSET else memset (gdk_array(index) (self, pos), 0, added * sizeof (_T_)); #endif } /* might overflow, but does the right thing */ self->end += added - removed; } G_GNUC_UNUSED static void gdk_array(set_size) (GdkArray *self, gsize new_size) { gsize old_size = gdk_array(get_size) (self); if (new_size > old_size) gdk_array(splice) (self, old_size, 0, NULL, new_size - old_size); else gdk_array(splice) (self, new_size, old_size - new_size, NULL, 0); } G_GNUC_UNUSED static void gdk_array(append) (GdkArray *self, #ifdef GDK_ARRAY_BY_VALUE _T_ *value) #else _T_ value) #endif { gdk_array(splice) (self, gdk_array(get_size) (self), 0, #ifdef GDK_ARRAY_BY_VALUE value, #else &value, #endif 1); } #ifdef GDK_ARRAY_BY_VALUE G_GNUC_UNUSED static _T_ * gdk_array(get) (const GdkArray *self, gsize pos) { return gdk_array(index) (self, pos); } #else G_GNUC_UNUSED static _T_ gdk_array(get) (const GdkArray *self, gsize pos) { return *gdk_array(index) (self, pos); } #endif #ifndef GDK_ARRAY_NO_UNDEF #undef _T_ #undef GdkArray #undef gdk_array_paste_more #undef gdk_array_paste #undef gdk_array #undef GDK_ARRAY_REAL_SIZE #undef GDK_ARRAY_BY_VALUE #undef GDK_ARRAY_ELEMENT_TYPE #undef GDK_ARRAY_FREE_FUNC #undef GDK_ARRAY_NAME #undef GDK_ARRAY_NULL_TERMINATED #undef GDK_ARRAY_PREALLOC #undef GDK_ARRAY_TYPE_NAME #undef GDK_ARRAY_NO_MEMSET #endif