# HG changeset patch # User Olaf Wintermann # Date 1607165698 -3600 # Node ID 18892c0a9adc58ede295044dbd0300205f9f540e # Parent b1eac0878ce7e2111b0e6ee708fb1460d3131b07 ucx update diff -r b1eac0878ce7 -r 18892c0a9adc application/main.c --- a/application/main.c Sat Dec 05 10:34:10 2020 +0100 +++ b/application/main.c Sat Dec 05 11:54:58 2020 +0100 @@ -33,164 +33,14 @@ #include #include -typedef struct Document { - UiText *text; - UiString *t1; - UiString *t2; - UiString *t3; - UiInteger *i; - UiDouble *d; - UiRange *r; - UiList *list; - UiDouble *progress; -} Document; - -typedef struct Entry { - char *name; - char *desc; -} Entry; - -Document *d1; -Document *d2; -int n = 1; - -UiImage *img; - -Document* create_doc(char *str); - -Document* next_doc(void) { - Document *doc = d1; - if(n == 1) { - doc = d2; - printf("doc2\n"); - } else { - printf("doc1\n"); - } - n++; - n = n%2; - return doc; -} - -void action_menu(UiEvent *event, void *data) { - printf("action_menu\n"); - - Document *doc = event->document; - char *s = doc->text->get(doc->text); - printf("text: {\n%s\n}\n", s); - //int i = doc->i->get(doc->i); - //printf("i: %d\n", i); +void action_menu(UiEvent *event, void *userdata) { - fflush(stdout); -} - -void list_data_get(UiEvent *event, UiSelection *selection, UiList *l, int i) { - ui_selection_settext(selection, "Hello World!", -1); -} - -void list_drop(UiEvent *event, UiSelection *selection, UiList *l, int i) { - char *text = ui_selection_gettext(selection); - printf("dnd drop: {%s}\n", text); - free(text); -} - -Document* create_doc(char *str) { - Document *doc = ui_document_new(sizeof(Document)); - UiContext *ctx = ui_document_context(doc); - - doc->text = ui_text_new(ctx, "text"); - doc->t1 = ui_string_new(ctx, "t1"); - doc->t2 = ui_string_new(ctx, "t2"); - doc->t3 = ui_string_new(ctx, "t3"); - - doc->i = ui_int_new(ctx, "int"); - doc->d = ui_double_new(ctx, "d"); - doc->r = ui_range_new(ctx, "r"); - - doc->progress = ui_double_new(ctx, "progress"); - - doc->list = ui_list_new(ctx, "list"); - Entry *e1 = calloc(1, sizeof(Entry)); - e1->name = "test"; - e1->desc = "test file"; - Entry *e2 = calloc(1, sizeof(Entry)); - e2->name = str; - e2->desc = "important document"; - ui_list_append(doc->list, e1); - ui_list_append(doc->list, e2); - - return doc; -} - -void* model_get(Entry *e, int col) { - if(col == 0) { - return img; - } else if(col == 1) { - return e->name; - } else if(col == 2) { - return e->desc; - } - return NULL; -} - -void action_newdoc(UiEvent *event, void *data) { - printf("new doc;\n "); - - Document *newd = next_doc(); - ui_set_document(event->obj, newd); -} - -void observ(UiEvent *event, void *data) { - printf("observ: %s\n", (char*)data); -} - -void doublechanged(UiEvent *event, void *data) { - UiDouble *d = event->eventdata; - printf("d: %f\n", (float)d->get(d)); } void application_startup(UiEvent *event, void *data) { - UiIcon *icon = ui_icon("folder", 16); - img = ui_icon_image(icon); - if(!img) { - fprintf(stderr, "Cannot load folder icon\n"); - } - - //Document *doc = create_doc(); - d1 = create_doc("doc1"); - d2 = create_doc("doc2"); UiObject *obj = ui_window("Test", NULL); - ui_set_document(obj, d1); - ui_textarea_nv(obj, "text"); - //ui_radiobutton_nv(obj, "1", "int"); - //ui_radiobutton_nv(obj, "2", "int"); - //ui_radiobutton_nv(obj, "3", "int"); - - ui_textfield_nv(obj, "t1"); - //ui_textarea_nv(obj, "text"); - //d1->t1->observers = ui_add_observer(d1->t1->observers, observ, "t1"); - //d1->text->observers = ui_add_observer(d1->text->observers, observ, "text"); - - UiModel *model = ui_model(obj->ctx, UI_ICON_TEXT, "name", UI_STRING, "desc", -1); - model->getvalue = (ui_getvaluefunc)model_get; - model->drop = list_drop; - model->data_get = list_data_get; - UiListCallbacks cb = {NULL, NULL, NULL}; - //UIWIDGET table = ui_table_nv(obj, "list", model, cb); - //ui_table_dragsource(table, 0, "text/plain", NULL); - - //ui_spinner_setrange(ui_spinnerf_nv(obj, 1, 0, "d"), 0, 1000); - //ui_spinnerr_nv(obj, "r"); - //d1->r->setrange(d1->r, 0, 10); - //d1->r->setextent(d1->r, 1); - //d1->d->observers = ui_add_observer(d1->d->observers, doublechanged, NULL); - - //ui_progressbar_nv(obj, "progress"); - - ui_textfield(obj, NULL); - - ui_button(obj, "Switch Document", action_newdoc, NULL); ui_show(obj); } diff -r b1eac0878ce7 -r 18892c0a9adc ucx/Makefile --- a/ucx/Makefile Sat Dec 05 10:34:10 2020 +0100 +++ b/ucx/Makefile Sat Dec 05 11:54:58 2020 +0100 @@ -42,6 +42,8 @@ SRC += logging.c SRC += buffer.c SRC += stack.c +SRC += ucx.c +SRC += array.c OBJ = $(SRC:%.c=../build/ucx/%.$(OBJ_EXT)) diff -r b1eac0878ce7 -r 18892c0a9adc ucx/array.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ucx/array.c Sat Dec 05 11:54:58 2020 +0100 @@ -0,0 +1,467 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2019 Mike Becker, Olaf Wintermann All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#define _GNU_SOURCE /* we want to use qsort_r(), if available */ +#define __STDC_WANT_LIB_EXT1__ 1 /* use qsort_s, if available */ + + +#include "ucx/array.h" +#include "ucx/utils.h" + +#include +#include +#include + +#ifndef UCX_ARRAY_DISABLE_QSORT +#ifdef __GLIBC__ +#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8) +#define ucx_array_sort_impl qsort_r +#endif /* glibc version >= 2.8 */ +#elif /* not __GLIBC__ */ defined(__APPLE__) || defined(__FreeBSD__) +#define ucx_array_sort_impl ucx_qsort_r +#define USE_UCX_QSORT_R +#elif /* not (__APPLE || __FreeBSD__) */ defined(__sun) +#if __STDC_VERSION__ >= 201112L +#define ucx_array_sort_impl qsort_s +#endif +#endif /* __GLIBC__, __APLE__, __FreeBSD__, __sun */ +#endif /* UCX_ARRAY_DISABLE_QSORT */ + +#ifndef ucx_array_sort_impl +#define ucx_array_sort_impl ucx_mergesort +#endif + +static int ucx_array_ensurecap(UcxArray *array, size_t reqcap) { + size_t required_capacity = array->capacity; + while (reqcap > required_capacity) { + if (required_capacity * 2 < required_capacity) + return 1; + required_capacity <<= 1; + } + if (ucx_array_reserve(array, required_capacity)) { + return 1; + } + return 0; +} + +int ucx_array_util_set_a(UcxAllocator* alloc, void** array, size_t* capacity, + size_t elmsize, size_t index, void* data) { + + if(!alloc || !capacity || !array) { + errno = EINVAL; + return 1; + } + + size_t newcapacity = *capacity; + while(index >= newcapacity) { + if(ucx_szmul(newcapacity, 2, &newcapacity)) { + errno = EOVERFLOW; + return 1; + } + } + + size_t memlen, offset; + if(ucx_szmul(newcapacity, elmsize, &memlen)) { + errno = EOVERFLOW; + return 1; + } + /* we don't need to check index*elmsize - it is smaller than memlen */ + + + void* newptr = alrealloc(alloc, *array, memlen); + if(newptr == NULL) { + errno = ENOMEM; /* we cannot assume that every allocator sets this */ + return 1; + } + *array = newptr; + *capacity = newcapacity; + + + char* dest = *array; + dest += elmsize*index; + memcpy(dest, data, elmsize); + + return 0; +} + +int ucx_array_util_setptr_a(UcxAllocator* alloc, void** array, size_t* capacity, + size_t index, void* data) { + + return ucx_array_util_set_a(alloc, array, capacity, sizeof(void*), + index, &data); +} + +UcxArray* ucx_array_new(size_t capacity, size_t elemsize) { + return ucx_array_new_a(capacity, elemsize, ucx_default_allocator()); +} + +UcxArray* ucx_array_new_a(size_t capacity, size_t elemsize, + UcxAllocator* allocator) { + UcxArray* array = almalloc(allocator, sizeof(UcxArray)); + if(array) { + ucx_array_init_a(array, capacity, elemsize, allocator); + } + return array; +} + +void ucx_array_init(UcxArray* array, size_t capacity, size_t elemsize) { + ucx_array_init_a(array, capacity, elemsize, ucx_default_allocator()); +} + +void ucx_array_init_a(UcxArray* array, size_t capacity, size_t elemsize, + UcxAllocator* allocator) { + + array->allocator = allocator; + array->elemsize = elemsize; + array->size = 0; + array->data = alcalloc(allocator, capacity, elemsize); + + if (array->data) { + array->capacity = capacity; + } else { + array->capacity = 0; + } +} + +int ucx_array_clone(UcxArray* dest, UcxArray const* src) { + if (ucx_array_ensurecap(dest, src->capacity)) { + return 1; + } + + dest->elemsize = src->elemsize; + dest->size = src->size; + + if (dest->data) { + memcpy(dest->data, src->data, src->size*src->elemsize); + } + + return 0; +} + +int ucx_array_equals(UcxArray const *array1, UcxArray const *array2, + cmp_func cmpfnc, void* data) { + + if (array1->size != array2->size || array1->elemsize != array2->elemsize) { + return 0; + } else { + if (array1->size == 0) + return 1; + + size_t elemsize; + if (cmpfnc == NULL) { + cmpfnc = ucx_cmp_mem; + elemsize = array1->elemsize; + data = &elemsize; + } + + for (size_t i = 0 ; i < array1->size ; i++) { + int r = cmpfnc( + ucx_array_at(array1, i), + ucx_array_at(array2, i), + data); + if (r != 0) + return 0; + } + return 1; + } +} + +void ucx_array_destroy(UcxArray *array) { + if(array->data) + alfree(array->allocator, array->data); + array->data = NULL; + array->capacity = array->size = 0; +} + +void ucx_array_free(UcxArray *array) { + ucx_array_destroy(array); + alfree(array->allocator, array); +} + +int ucx_array_append_from(UcxArray *array, void *data, size_t count) { + if (ucx_array_ensurecap(array, array->size + count)) + return 1; + + void* dest = ucx_array_at(array, array->size); + if (data) { + memcpy(dest, data, array->elemsize*count); + } else { + memset(dest, 0, array->elemsize*count); + } + array->size += count; + + return 0; +} + +int ucx_array_prepend_from(UcxArray *array, void *data, size_t count) { + if (ucx_array_ensurecap(array, array->size + count)) + return 1; + + if (array->size > 0) { + void *dest = ucx_array_at(array, count); + memmove(dest, array->data, array->elemsize*array->size); + } + + if (data) { + memcpy(array->data, data, array->elemsize*count); + } else { + memset(array->data, 0, array->elemsize*count); + } + array->size += count; + + return 0; +} + +int ucx_array_set_from(UcxArray *array, size_t index, + void *data, size_t count) { + if (ucx_array_ensurecap(array, index + count)) + return 1; + + if (index+count > array->size) { + array->size = index+count; + } + + void *dest = ucx_array_at(array, index); + if (data) { + memcpy(dest, data, array->elemsize*count); + } else { + memset(dest, 0, array->elemsize*count); + } + + return 0; +} + +int ucx_array_concat(UcxArray *array1, const UcxArray *array2) { + + if (array1->elemsize != array2->elemsize) + return 1; + + size_t capacity = array1->capacity+array2->capacity; + + if (array1->capacity < capacity) { + if (ucx_array_reserve(array1, capacity)) { + return 1; + } + } + + void* dest = ucx_array_at(array1, array1->size); + memcpy(dest, array2->data, array2->size*array2->elemsize); + + array1->size += array2->size; + + return 0; +} + +void *ucx_array_at(UcxArray const *array, size_t index) { + char* memory = array->data; + char* loc = memory + index*array->elemsize; + return loc; +} + +size_t ucx_array_find(UcxArray const *array, void *elem, + cmp_func cmpfnc, void *data) { + + size_t elemsize; + if (cmpfnc == NULL) { + cmpfnc = ucx_cmp_mem; + elemsize = array->elemsize; + data = &elemsize; + } + + if (array->size > 0) { + for (size_t i = 0 ; i < array->size ; i++) { + void* ptr = ucx_array_at(array, i); + if (cmpfnc(ptr, elem, data) == 0) { + return i; + } + } + return array->size; + } else { + return 0; + } +} + +int ucx_array_contains(UcxArray const *array, void *elem, + cmp_func cmpfnc, void *data) { + return ucx_array_find(array, elem, cmpfnc, data) != array->size; +} + +static void ucx_mergesort_merge(void *arrdata,size_t elemsize, + cmp_func cmpfnc, void *data, + size_t start, size_t mid, size_t end) { + + char* array = arrdata; + + size_t rightstart = mid + 1; + + if (cmpfnc(array + mid*elemsize, + array + rightstart*elemsize, data) <= 0) { + /* already sorted */ + return; + } + + /* we need memory for one element */ + void *value = malloc(elemsize); + + while (start <= mid && rightstart <= end) { + if (cmpfnc(array + start*elemsize, + array + rightstart*elemsize, data) <= 0) { + start++; + } else { + /* save the value from the right */ + memcpy(value, array + rightstart*elemsize, elemsize); + + /* shift all left elements one element to the right */ + size_t shiftcount = rightstart-start; + void *startptr = array + start*elemsize; + void *dest = array + (start+1)*elemsize; + memmove(dest, startptr, shiftcount*elemsize); + + /* bring the first value from the right to the left */ + memcpy(startptr, value, elemsize); + + start++; + mid++; + rightstart++; + } + } + + /* free the temporary memory */ + free(value); +} + +static void ucx_mergesort_impl(void *arrdata, size_t elemsize, + cmp_func cmpfnc, void *data, size_t l, size_t r) { + if (l < r) { + size_t m = l + (r - l) / 2; + + ucx_mergesort_impl(arrdata, elemsize, cmpfnc, data, l, m); + ucx_mergesort_impl(arrdata, elemsize, cmpfnc, data, m + 1, r); + ucx_mergesort_merge(arrdata, elemsize, cmpfnc, data, l, m, r); + } +} + +static void ucx_mergesort(void *arrdata, size_t count, size_t elemsize, + cmp_func cmpfnc, void *data) { + + ucx_mergesort_impl(arrdata, elemsize, cmpfnc, data, 0, count-1); +} + +#ifdef USE_UCX_QSORT_R +struct cmpfnc_swapargs_info { + cmp_func func; + void *data; +}; + +static int cmp_func_swap_args(void *data, const void *x, const void *y) { + struct cmpfnc_swapargs_info* info = data; + return info->func(x, y, info->data); +} + +static void ucx_qsort_r(void *array, size_t count, size_t elemsize, + cmp_func cmpfnc, void *data) { + struct cmpfnc_swapargs_info info; + info.func = cmpfnc; + info.data = data; + qsort_r(array, count, elemsize, &info, cmp_func_swap_args); +} +#endif /* USE_UCX_QSORT_R */ + +void ucx_array_sort(UcxArray* array, cmp_func cmpfnc, void *data) { + ucx_array_sort_impl(array->data, array->size, array->elemsize, + cmpfnc, data); +} + +void ucx_array_remove(UcxArray *array, size_t index) { + array->size--; + if (index < array->size) { + void* dest = ucx_array_at(array, index); + void* src = ucx_array_at(array, index+1); + memmove(dest, src, (array->size - index)*array->elemsize); + } +} + +void ucx_array_remove_fast(UcxArray *array, size_t index) { + array->size--; + if (index < array->size) { + void* dest = ucx_array_at(array, index); + void* src = ucx_array_at(array, array->size); + memcpy(dest, src, array->elemsize); + } +} + +int ucx_array_shrink(UcxArray* array) { + void* newptr = alrealloc(array->allocator, array->data, + array->size*array->elemsize); + if (newptr) { + array->data = newptr; + array->capacity = array->size; + return 0; + } else { + return 1; + } +} + +int ucx_array_resize(UcxArray* array, size_t capacity) { + if (array->capacity >= capacity) { + void* newptr = alrealloc(array->allocator, array->data, + capacity*array->elemsize); + if (newptr) { + array->data = newptr; + array->capacity = capacity; + if (array->size > array->capacity) { + array->size = array->capacity; + } + return 0; + } else { + return 1; + } + } else { + return ucx_array_reserve(array, capacity); + } +} + +int ucx_array_reserve(UcxArray* array, size_t capacity) { + if (array->capacity > capacity) { + return 0; + } else { + void* newptr = alrealloc(array->allocator, array->data, + capacity*array->elemsize); + if (newptr) { + array->data = newptr; + array->capacity = capacity; + return 0; + } else { + return 1; + } + } +} + +int ucx_array_grow(UcxArray* array, size_t count) { + return ucx_array_reserve(array, array->size+count); +} diff -r b1eac0878ce7 -r 18892c0a9adc ucx/list.c --- a/ucx/list.c Sat Dec 05 10:34:10 2020 +0100 +++ b/ucx/list.c Sat Dec 05 11:54:58 2020 +0100 @@ -28,11 +28,11 @@ #include "ucx/list.h" -UcxList *ucx_list_clone(UcxList *l, copy_func fnc, void *data) { +UcxList *ucx_list_clone(const UcxList *l, copy_func fnc, void *data) { return ucx_list_clone_a(ucx_default_allocator(), l, fnc, data); } -UcxList *ucx_list_clone_a(UcxAllocator *alloc, UcxList *l, +UcxList *ucx_list_clone_a(UcxAllocator *alloc, const UcxList *l, copy_func fnc, void *data) { UcxList *ret = NULL; while (l) { @@ -172,7 +172,8 @@ return (UcxList*)(index == 0 ? e : NULL); } -ssize_t ucx_list_find(UcxList *l, void *elem, cmp_func fnc, void *cmpdata) { +ssize_t ucx_list_find(const UcxList *l, void *elem, + cmp_func fnc, void *cmpdata) { ssize_t index = 0; UCX_FOREACH(e, l) { if (fnc) { @@ -189,7 +190,8 @@ return -1; } -int ucx_list_contains(UcxList *l, void *elem, cmp_func fnc, void *cmpdata) { +int ucx_list_contains(const UcxList *l, void *elem, + cmp_func fnc, void *cmpdata) { return ucx_list_find(l, elem, fnc, cmpdata) > -1; } @@ -206,7 +208,7 @@ return s; } -static UcxList *ucx_list_sort_merge(int length, +static UcxList *ucx_list_sort_merge(size_t length, UcxList* ls, UcxList* le, UcxList* re, cmp_func fnc, void* data) { @@ -214,7 +216,7 @@ UcxList *rc, *lc; lc = ls; rc = le; - int n = 0; + size_t n = 0; while (lc && lc != le && rc != re) { if (fnc(lc->data, rc->data, data) <= 0) { sorted[n] = lc; @@ -255,7 +257,7 @@ } UcxList *lc; - int ln = 1; + size_t ln = 1; UcxList *ls = l, *le, *re; @@ -271,7 +273,7 @@ return l; // this list is already sorted :) } else { UcxList *rc; - int rn = 1; + size_t rn = 1; rc = le; // skip already sorted elements while (rc->next != NULL && fnc(rc->next->data, rc->data, data) > 0) { @@ -334,3 +336,93 @@ alfree(alloc, e); return l; } + + +static UcxList* ucx_list_setoperation_a(UcxAllocator *allocator, + UcxList const *left, UcxList const *right, + cmp_func cmpfnc, void* cmpdata, + copy_func cpfnc, void* cpdata, + int op) { + + UcxList *res = NULL; + UcxList *cur = NULL; + const UcxList *src = left; + + do { + UCX_FOREACH(node, src) { + void* elem = node->data; + if ( + (op == 0 && !ucx_list_contains(res, elem, cmpfnc, cmpdata)) || + (op == 1 && ucx_list_contains(right, elem, cmpfnc, cmpdata)) || + (op == 2 && !ucx_list_contains(right, elem, cmpfnc, cmpdata))) { + UcxList *nl = almalloc(allocator, sizeof(UcxList)); + nl->prev = cur; + nl->next = NULL; + if (cpfnc) { + nl->data = cpfnc(elem, cpdata); + } else { + nl->data = elem; + } + if (cur != NULL) + cur->next = nl; + cur = nl; + if (res == NULL) + res = cur; + } + } + if (op == 0 && src == left) + src = right; + else + src = NULL; + } while (src != NULL); + + return res; +} + +UcxList* ucx_list_union(UcxList const *left, UcxList const *right, + cmp_func cmpfnc, void* cmpdata, + copy_func cpfnc, void* cpdata) { + return ucx_list_union_a(ucx_default_allocator(), + left, right, cmpfnc, cmpdata, cpfnc, cpdata); +} + +UcxList* ucx_list_union_a(UcxAllocator *allocator, + UcxList const *left, UcxList const *right, + cmp_func cmpfnc, void* cmpdata, + copy_func cpfnc, void* cpdata) { + + return ucx_list_setoperation_a(allocator, left, right, + cmpfnc, cmpdata, cpfnc, cpdata, 0); +} + +UcxList* ucx_list_intersection(UcxList const *left, UcxList const *right, + cmp_func cmpfnc, void* cmpdata, + copy_func cpfnc, void* cpdata) { + return ucx_list_intersection_a(ucx_default_allocator(), left, right, + cmpfnc, cmpdata, cpfnc, cpdata); +} + +UcxList* ucx_list_intersection_a(UcxAllocator *allocator, + UcxList const *left, UcxList const *right, + cmp_func cmpfnc, void* cmpdata, + copy_func cpfnc, void* cpdata) { + + return ucx_list_setoperation_a(allocator, left, right, + cmpfnc, cmpdata, cpfnc, cpdata, 1); +} + +UcxList* ucx_list_difference(UcxList const *left, UcxList const *right, + cmp_func cmpfnc, void* cmpdata, + copy_func cpfnc, void* cpdata) { + return ucx_list_difference_a(ucx_default_allocator(), left, right, + cmpfnc, cmpdata, cpfnc, cpdata); +} + +UcxList* ucx_list_difference_a(UcxAllocator *allocator, + UcxList const *left, UcxList const *right, + cmp_func cmpfnc, void* cmpdata, + copy_func cpfnc, void* cpdata) { + + return ucx_list_setoperation_a(allocator, left, right, + cmpfnc, cmpdata, cpfnc, cpdata, 2); +} diff -r b1eac0878ce7 -r 18892c0a9adc ucx/logging.c --- a/ucx/logging.c Sat Dec 05 10:34:10 2020 +0100 +++ b/ucx/logging.c Sat Dec 05 11:54:58 2020 +0100 @@ -91,6 +91,10 @@ k += strftime(msg+k, 128, logger->dateformat, localtime(&now)); } if ((logger->mask & UCX_LOGGER_SOURCE) > 0) { + char *fpart = strrchr(file, '/'); + if (fpart) file = fpart+1; + fpart = strrchr(file, '\\'); + if (fpart) file = fpart+1; n = strlen(file); memcpy(msg+k, file, n); k += n; diff -r b1eac0878ce7 -r 18892c0a9adc ucx/map.c --- a/ucx/map.c Sat Dec 05 10:34:10 2020 +0100 +++ b/ucx/map.c Sat Dec 05 11:54:58 2020 +0100 @@ -103,7 +103,7 @@ map->count = 0; } -int ucx_map_copy(UcxMap *from, UcxMap *to, copy_func fnc, void *data) { +int ucx_map_copy(UcxMap const *from, UcxMap *to, copy_func fnc, void *data) { UcxMapIterator i = ucx_map_iterator(from); void *value; UCX_MAP_FOREACH(key, value, i) { @@ -114,9 +114,14 @@ return 0; } -UcxMap *ucx_map_clone(UcxMap *map, copy_func fnc, void *data) { +UcxMap *ucx_map_clone(UcxMap const *map, copy_func fnc, void *data) { + return ucx_map_clone_a(ucx_default_allocator(), map, fnc, data); +} + +UcxMap *ucx_map_clone_a(UcxAllocator *allocator, + UcxMap const *map, copy_func fnc, void *data) { size_t bs = (map->count * 5) >> 1; - UcxMap *newmap = ucx_map_new(bs > map->size ? bs : map->size); + UcxMap *newmap = ucx_map_new_a(allocator, bs > map->size ? bs : map->size); if (!newmap) { return NULL; } @@ -235,8 +240,8 @@ return NULL; } -void *ucx_map_get(UcxMap *map, UcxKey key) { - return ucx_map_get_and_remove(map, key, 0); +void *ucx_map_get(UcxMap const *map, UcxKey key) { + return ucx_map_get_and_remove((UcxMap *)map, key, 0); } void *ucx_map_remove(UcxMap *map, UcxKey key) { @@ -294,7 +299,7 @@ return h; } -UcxMapIterator ucx_map_iterator(UcxMap *map) { +UcxMapIterator ucx_map_iterator(UcxMap const *map) { UcxMapIterator i; i.map = map; i.cur = NULL; @@ -335,3 +340,63 @@ return 0; } +UcxMap* ucx_map_union(const UcxMap *first, const UcxMap *second, + copy_func cpfnc, void* cpdata) { + return ucx_map_union_a(ucx_default_allocator(), + first, second, cpfnc, cpdata); +} + +UcxMap* ucx_map_union_a(UcxAllocator *allocator, + const UcxMap *first, const UcxMap *second, + copy_func cpfnc, void* cpdata) { + UcxMap* result = ucx_map_clone_a(allocator, first, cpfnc, cpdata); + ucx_map_copy(second, result, cpfnc, cpdata); + return result; +} + +UcxMap* ucx_map_intersection(const UcxMap *first, const UcxMap *second, + copy_func cpfnc, void* cpdata) { + return ucx_map_intersection_a(ucx_default_allocator(), + first, second, cpfnc, cpdata); +} + +UcxMap* ucx_map_intersection_a(UcxAllocator *allocator, + const UcxMap *first, const UcxMap *second, + copy_func cpfnc, void* cpdata) { + UcxMap *result = ucx_map_new_a(allocator, first->size < second->size ? + first->size : second->size); + + UcxMapIterator iter = ucx_map_iterator(first); + void* value; + UCX_MAP_FOREACH(key, value, iter) { + if (ucx_map_get(second, key)) { + ucx_map_put(result, key, cpfnc ? cpfnc(value, cpdata) : value); + } + } + + return result; +} + +UcxMap* ucx_map_difference(const UcxMap *first, const UcxMap *second, + copy_func cpfnc, void* cpdata) { + return ucx_map_difference_a(ucx_default_allocator(), + first, second, cpfnc, cpdata); +} + +UcxMap* ucx_map_difference_a(UcxAllocator *allocator, + const UcxMap *first, const UcxMap *second, + copy_func cpfnc, void* cpdata) { + + UcxMap *result = ucx_map_new_a(allocator, first->size - second->count); + + UcxMapIterator iter = ucx_map_iterator(first); + void* value; + UCX_MAP_FOREACH(key, value, iter) { + if (!ucx_map_get(second, key)) { + ucx_map_put(result, key, cpfnc ? cpfnc(value, cpdata) : value); + } + } + + ucx_map_rehash(result); + return result; +} \ No newline at end of file diff -r b1eac0878ce7 -r 18892c0a9adc ucx/string.c --- a/ucx/string.c Sat Dec 05 10:34:10 2020 +0100 +++ b/ucx/string.c Sat Dec 05 11:54:58 2020 +0100 @@ -36,6 +36,10 @@ #include #include +#ifndef _WIN32 +#include /* for strncasecmp() */ +#endif /* _WIN32 */ + sstr_t sstr(char *cstring) { sstr_t string; string.ptr = cstring; @@ -66,6 +70,8 @@ size_t scstrnlen(size_t n, ...) { + if (n == 0) return 0; + va_list ap; va_start(ap, n); @@ -592,6 +598,38 @@ } } +int scstrcaseprefix(scstr_t string, scstr_t prefix) { + if (string.length == 0) { + return prefix.length == 0; + } + if (prefix.length == 0) { + return 1; + } + + if (prefix.length > string.length) { + return 0; + } else { + scstr_t subs = scstrsubsl(string, 0, prefix.length); + return scstrcasecmp(subs, prefix) == 0; + } +} + +int scstrcasesuffix(scstr_t string, scstr_t suffix) { + if (string.length == 0) { + return suffix.length == 0; + } + if (suffix.length == 0) { + return 1; + } + + if (suffix.length > string.length) { + return 0; + } else { + scstr_t subs = scstrsubs(string, string.length-suffix.length); + return scstrcasecmp(subs, suffix) == 0; + } +} + sstr_t scstrlower(scstr_t string) { sstr_t ret = sstrdup(string); for (size_t i = 0; i < ret.length ; i++) { @@ -624,6 +662,136 @@ return ret; } +#define REPLACE_INDEX_BUFFER_MAX 100 + +struct scstrreplace_ibuf { + size_t* buf; + unsigned int len; /* small indices */ + struct scstrreplace_ibuf* next; +}; + +static void scstrrepl_free_ibuf(struct scstrreplace_ibuf *buf) { + while (buf) { + struct scstrreplace_ibuf *next = buf->next; + free(buf->buf); + free(buf); + buf = next; + } +} + +sstr_t scstrreplacen_a(UcxAllocator *allocator, scstr_t str, + scstr_t pattern, scstr_t replacement, size_t replmax) { + + if (pattern.length == 0 || pattern.length > str.length || replmax == 0) + return sstrdup(str); + + /* Compute expected buffer length */ + size_t ibufmax = str.length / pattern.length; + size_t ibuflen = replmax < ibufmax ? replmax : ibufmax; + if (ibuflen > REPLACE_INDEX_BUFFER_MAX) { + ibuflen = REPLACE_INDEX_BUFFER_MAX; + } + + /* Allocate first index buffer */ + struct scstrreplace_ibuf *firstbuf, *curbuf; + firstbuf = curbuf = calloc(1, sizeof(struct scstrreplace_ibuf)); + if (!firstbuf) return sstrn(NULL, 0); + firstbuf->buf = calloc(ibuflen, sizeof(size_t)); + if (!firstbuf->buf) { + free(firstbuf); + return sstrn(NULL, 0); + } + + /* Search occurrences */ + scstr_t searchstr = str; + size_t found = 0; + do { + scstr_t match = scstrscstr(searchstr, pattern); + if (match.length > 0) { + /* Allocate next buffer in chain, if required */ + if (curbuf->len == ibuflen) { + struct scstrreplace_ibuf *nextbuf = + calloc(1, sizeof(struct scstrreplace_ibuf)); + if (!nextbuf) { + scstrrepl_free_ibuf(firstbuf); + return sstrn(NULL, 0); + } + nextbuf->buf = calloc(ibuflen, sizeof(size_t)); + if (!nextbuf->buf) { + free(nextbuf); + scstrrepl_free_ibuf(firstbuf); + return sstrn(NULL, 0); + } + curbuf->next = nextbuf; + curbuf = nextbuf; + } + + /* Record match index */ + found++; + size_t idx = match.ptr - str.ptr; + curbuf->buf[curbuf->len++] = idx; + searchstr.ptr = match.ptr + pattern.length; + searchstr.length = str.length - idx - pattern.length; + } else { + break; + } + } while (searchstr.length > 0 && found < replmax); + + /* Allocate result string */ + sstr_t result; + { + ssize_t adjlen = (ssize_t) replacement.length - (ssize_t) pattern.length; + size_t rcount = 0; + curbuf = firstbuf; + do { + rcount += curbuf->len; + curbuf = curbuf->next; + } while (curbuf); + result.length = str.length + rcount * adjlen; + result.ptr = almalloc(allocator, result.length); + if (!result.ptr) { + scstrrepl_free_ibuf(firstbuf); + return sstrn(NULL, 0); + } + } + + /* Build result string */ + curbuf = firstbuf; + size_t srcidx = 0; + char* destptr = result.ptr; + do { + for (size_t i = 0; i < curbuf->len; i++) { + /* Copy source part up to next match*/ + size_t idx = curbuf->buf[i]; + size_t srclen = idx - srcidx; + if (srclen > 0) { + memcpy(destptr, str.ptr+srcidx, srclen); + destptr += srclen; + srcidx += srclen; + } + + /* Copy the replacement and skip the source pattern */ + srcidx += pattern.length; + memcpy(destptr, replacement.ptr, replacement.length); + destptr += replacement.length; + } + curbuf = curbuf->next; + } while (curbuf); + memcpy(destptr, str.ptr+srcidx, str.length-srcidx); + + /* Free index buffer */ + scstrrepl_free_ibuf(firstbuf); + + return result; +} + +sstr_t scstrreplacen(scstr_t str, scstr_t pattern, + scstr_t replacement, size_t replmax) { + return scstrreplacen_a(ucx_default_allocator(), + str, pattern, replacement, replmax); +} + + // type adjustment functions scstr_t ucx_sc2sc(scstr_t str) { return str; diff -r b1eac0878ce7 -r 18892c0a9adc ucx/ucx/array.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ucx/ucx/array.h Sat Dec 05 11:54:58 2020 +0100 @@ -0,0 +1,460 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2019 Mike Becker, Olaf Wintermann All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +/** + * Dynamically allocated array implementation. + * + * @file array.h + * @author Mike Becker + * @author Olaf Wintermann + */ + +#ifndef UCX_ARRAY_H +#define UCX_ARRAY_H + +#include "ucx.h" +#include "allocator.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * UCX array type. + */ +typedef struct { + /** + * The current capacity of the array. + */ + size_t capacity; + /** + * The actual number of elements in the array. + */ + size_t size; + /** + * The size of an individual element in bytes. + */ + size_t elemsize; + /** + * A pointer to the data. + */ + void* data; + /** + * The allocator used for the data. + */ + UcxAllocator* allocator; +} UcxArray; + +/** + * Sets an element in an arbitrary user defined array. + * The data is copied from the specified data location. + * + * If the capacity is insufficient, the array is automatically reallocated and + * the possibly new pointer is stored in the array argument. + * + * On reallocation the capacity of the array is doubled until it is sufficient. + * The new capacity is stored back to capacity. + * + * @param array a pointer to location of the array pointer + * @param capacity a pointer to the capacity + * @param elmsize the size of each element + * @param idx the index of the element to set + * @param data a pointer to the element data + * @return zero on success or non-zero on error (errno will be set) + */ +#define ucx_array_util_set(array, capacity, elmsize, idx, data) \ + ucx_array_util_set_a(ucx_default_allocator(), (void**)(array), capacity, \ + elmsize, idx, data) + +/** + * Sets an element in an arbitrary user defined array. + * The data is copied from the specified data location. + * + * If the capacity is insufficient, the array is automatically reallocated + * using the specified allocator and the possibly new pointer is stored in + * the array argument. + * + * On reallocation the capacity of the array is doubled until it is sufficient. + * The new capacity is stored back to capacity. + * + * @param alloc the allocator that shall be used to reallocate the array + * @param array a pointer to location of the array pointer + * @param capacity a pointer to the capacity + * @param elmsize the size of each element + * @param idx the index of the element to set + * @param data a pointer to the element data + * @return zero on success or non-zero on error (errno will be set) + */ +int ucx_array_util_set_a(UcxAllocator* alloc, void** array, size_t* capacity, + size_t elmsize, size_t idx, void* data); + +/** + * Stores a pointer in an arbitrary user defined array. + * The element size of the array must be sizeof(void*). + * + * If the capacity is insufficient, the array is automatically reallocated and + * the possibly new pointer is stored in the array argument. + * + * On reallocation the capacity of the array is doubled until it is sufficient. + * The new capacity is stored back to capacity. + * + * @param array a pointer to location of the array pointer + * @param capacity a pointer to the capacity + * @param idx the index of the element to set + * @param ptr the pointer to store + * @return zero on success or non-zero on error (errno will be set) + */ +#define ucx_array_util_setptr(array, capacity, idx, ptr) \ + ucx_array_util_setptr_a(ucx_default_allocator(), (void**)(array), \ + capacity, idx, ptr) + +/** + * Stores a pointer in an arbitrary user defined array. + * The element size of the array must be sizeof(void*). + * + * If the capacity is insufficient, the array is automatically reallocated + * using the specified allocator and the possibly new pointer is stored in + * the array argument. + * + * On reallocation the capacity of the array is doubled until it is sufficient. + * The new capacity is stored back to capacity. + * + * @param alloc the allocator that shall be used to reallocate the array + * @param array a pointer to location of the array pointer + * @param capacity a pointer to the capacity + * @param idx the index of the element to set + * @param ptr the pointer to store + * @return zero on success or non-zero on error (errno will be set) + */ +int ucx_array_util_setptr_a(UcxAllocator* alloc, void** array, size_t* capacity, + size_t idx, void* ptr); + + +/** + * Creates a new UCX array with the given capacity and element size. + * @param capacity the initial capacity + * @param elemsize the element size + * @return a pointer to a new UCX array structure + */ +UcxArray* ucx_array_new(size_t capacity, size_t elemsize); + +/** + * Creates a new UCX array using the specified allocator. + * + * @param capacity the initial capacity + * @param elemsize the element size + * @param allocator the allocator to use + * @return a pointer to new UCX array structure + */ +UcxArray* ucx_array_new_a(size_t capacity, size_t elemsize, + UcxAllocator* allocator); + +/** + * Initializes a UCX array structure with the given capacity and element size. + * The structure must be uninitialized as the data pointer will be overwritten. + * + * @param array the structure to initialize + * @param capacity the initial capacity + * @param elemsize the element size + */ +void ucx_array_init(UcxArray* array, size_t capacity, size_t elemsize); + +/** + * Initializes a UCX array structure using the specified allocator. + * The structure must be uninitialized as the data pointer will be overwritten. + * + * @param array the structure to initialize + * @param capacity the initial capacity + * @param elemsize the element size + * @param allocator the allocator to use + */ +void ucx_array_init_a(UcxArray* array, size_t capacity, size_t elemsize, + UcxAllocator* allocator); + +/** + * Creates an shallow copy of an array. + * + * This function clones the specified array by using memcpy(). + * If the destination capacity is insufficient, an automatic reallocation is + * attempted. + * + * Note: if the destination array is uninitialized, the behavior is undefined. + * + * @param dest the array to copy to + * @param src the array to copy from + * @return zero on success, non-zero on reallocation failure. + */ +int ucx_array_clone(UcxArray* dest, UcxArray const* src); + + +/** + * Compares two UCX arrays element-wise by using a compare function. + * + * Elements of the two specified arrays are compared by using the specified + * compare function and the additional data. The type and content of this + * additional data depends on the cmp_func() used. + * + * This function always returns zero, if the element sizes of the arrays do + * not match and performs no comparisons in this case. + * + * @param array1 the first array + * @param array2 the second array + * @param cmpfnc the compare function + * @param data additional data for the compare function + * @return 1, if and only if the two arrays equal element-wise, 0 otherwise + */ +int ucx_array_equals(UcxArray const *array1, UcxArray const *array2, + cmp_func cmpfnc, void* data); + +/** + * Destroys the array. + * + * The data is freed and both capacity and count are reset to zero. + * If the array structure itself has been dynamically allocated, it has to be + * freed separately. + * + * @param array the array to destroy + */ +void ucx_array_destroy(UcxArray *array); + +/** + * Destroys and frees the array. + * + * @param array the array to free + */ +void ucx_array_free(UcxArray *array); + +/** + * Inserts elements at the end of the array. + * + * This is an O(1) operation. + * The array will automatically grow, if the capacity is exceeded. + * If a pointer to data is provided, the data is copied into the array with + * memcpy(). Otherwise the new elements are completely zeroed. + * + * @param array a pointer the array where to append the data + * @param data a pointer to the data to insert (may be NULL) + * @param count number of elements to copy from data (if data is + * NULL, zeroed elements are appended) + * @return zero on success, non-zero if a reallocation was necessary but failed + * @see ucx_array_set_from() + * @see ucx_array_append() + */ +int ucx_array_append_from(UcxArray *array, void *data, size_t count); + + +/** + * Inserts elements at the beginning of the array. + * + * This is an expensive operation, because the contents must be moved. + * If there is no particular reason to prepend data, you should use + * ucx_array_append_from() instead. + * + * @param array a pointer the array where to prepend the data + * @param data a pointer to the data to insert (may be NULL) + * @param count number of elements to copy from data (if data is + * NULL, zeroed elements are inserted) + * @return zero on success, non-zero if a reallocation was necessary but failed + * @see ucx_array_append_from() + * @see ucx_array_set_from() + * @see ucx_array_prepend() + */ +int ucx_array_prepend_from(UcxArray *array, void *data, size_t count); + + +/** + * Sets elements starting at the specified index. + * + * If the any index is out of bounds, the array automatically grows. + * The pointer to the data may be NULL, in which case the elements are zeroed. + * + * @param array a pointer the array where to set the data + * @param index the index of the element to set + * @param data a pointer to the data to insert (may be NULL) + * @param count number of elements to copy from data (if data is + * NULL, the memory in the array is zeroed) + * @return zero on success, non-zero if a reallocation was necessary but failed + * @see ucx_array_append_from() + * @see ucx_array_set() + */ +int ucx_array_set_from(UcxArray *array, size_t index, void *data, size_t count); + +/** + * Concatenates two arrays. + * + * The contents of the second array are appended to the first array in one + * single operation. The second array is otherwise left untouched. + * + * The first array may grow automatically. If this fails, both arrays remain + * unmodified. + * + * @param array1 first array + * @param array2 second array + * @return zero on success, non-zero if reallocation was necessary but failed + * or the element size does not match + */ +int ucx_array_concat(UcxArray *array1, const UcxArray *array2); + +/** + * Returns a pointer to the array element at the specified index. + * + * @param array the array to retrieve the element from + * @param index index of the element to return + * @return a pointer to the element at the specified index or NULL, + * if the index is greater than the array size + */ +void *ucx_array_at(UcxArray const* array, size_t index); + +/** + * Returns the index of an element containing the specified data. + * + * This function uses a cmp_func() to compare the data of each list element + * with the specified data. If no cmp_func is provided, memcmp() is used. + * + * If the array contains the data more than once, the index of the first + * occurrence is returned. + * If the array does not contain the data, the size of array is returned. + * + * @param array the array where to search for the data + * @param elem the element data + * @param cmpfnc the compare function + * @param data additional data for the compare function + * @return the index of the element containing the specified data or the size of + * the array, if the data is not found in this array + */ +size_t ucx_array_find(UcxArray const *array, void *elem, + cmp_func cmpfnc, void *data); + +/** + * Checks, if an array contains a specific element. + * + * An element is found, if ucx_array_find() returns a value less than the size. + * + * @param array the array where to search for the data + * @param elem the element data + * @param cmpfnc the compare function + * @param data additional data for the compare function + * @return 1, if and only if the array contains the specified element data + * @see ucx_array_find() + */ +int ucx_array_contains(UcxArray const *array, void *elem, + cmp_func cmpfnc, void *data); + +/** + * Sorts a UcxArray with the best available sort algorithm. + * + * The qsort_r() function is used, if available (glibc, FreeBSD or MacOS). + * The order of arguments is automatically adjusted for the FreeBSD and MacOS + * version of qsort_r(). + * + * If qsort_r() is not available, a merge sort algorithm is used, which is + * guaranteed to use no more additional memory than for exactly one element. + * + * @param array the array to sort + * @param cmpfnc the function that shall be used to compare the element data + * @param data additional data for the cmp_func() or NULL + */ +void ucx_array_sort(UcxArray* array, cmp_func cmpfnc, void *data); + +/** + * Removes an element from the array. + * + * This is in general an expensive operation, because several elements may + * be moved. If the order of the elements is not relevant, use + * ucx_array_remove_fast() instead. + * + * @param array pointer to the array from which the element shall be removed + * @param index the index of the element to remove + */ +void ucx_array_remove(UcxArray *array, size_t index); + +/** + * Removes an element from the array. + * + * This is an O(1) operation, but does not maintain the order of the elements. + * The last element in the array is moved to the location of the removed + * element. + * + * @param array pointer to the array from which the element shall be removed + * @param index the index of the element to remove + */ +void ucx_array_remove_fast(UcxArray *array, size_t index); + +/** + * Shrinks the memory to exactly fit the contents. + * + * After this operation, the capacity equals the size. + * + * @param array a pointer to the array + * @return zero on success, non-zero if reallocation failed + */ +int ucx_array_shrink(UcxArray* array); + +/** + * Sets the capacity of the array. + * + * If the new capacity is smaller than the size of the array, the elements + * are removed and the size is adjusted accordingly. + * + * @param array a pointer to the array + * @param capacity the new capacity + * @return zero on success, non-zero if reallocation failed + */ +int ucx_array_resize(UcxArray* array, size_t capacity); + +/** + * Resizes the array only, if the capacity is insufficient. + * + * If the requested capacity is smaller than the current capacity, this + * function does nothing. + * + * @param array a pointer to the array + * @param capacity the guaranteed capacity + * @return zero on success, non-zero if reallocation failed + */ +int ucx_array_reserve(UcxArray* array, size_t capacity); + +/** + * Resizes the capacity, if the specified number of elements would not fit. + * + * A call to ucx_array_grow(array, count) is effectively the same as + * ucx_array_reserve(array, array->size+count). + * + * @param array a pointer to the array + * @param count the number of elements that should additionally fit + * into the array + * @return zero on success, non-zero if reallocation failed + */ +int ucx_array_grow(UcxArray* array, size_t count); + + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_ARRAY_H */ + diff -r b1eac0878ce7 -r 18892c0a9adc ucx/ucx/list.h --- a/ucx/ucx/list.h Sat Dec 05 10:34:10 2020 +0100 +++ b/ucx/ucx/list.h Sat Dec 05 11:54:58 2020 +0100 @@ -57,7 +57,7 @@ * @param elem The variable name of the element */ #define UCX_FOREACH(elem,list) \ - for (UcxList* elem = list ; elem != NULL ; elem = elem->next) + for (UcxList* elem = (UcxList*) list ; elem != NULL ; elem = elem->next) /** * UCX list type. @@ -99,7 +99,7 @@ * @param data additional data for the copy_func() * @return a pointer to the copy */ -UcxList *ucx_list_clone(UcxList *list, copy_func cpyfnc, void* data); +UcxList *ucx_list_clone(const UcxList *list, copy_func cpyfnc, void* data); /** * Creates an element-wise copy of a list using a UcxAllocator. @@ -117,7 +117,7 @@ * @return a pointer to the copy * @see ucx_list_clone() */ -UcxList *ucx_list_clone_a(UcxAllocator *allocator, UcxList *list, +UcxList *ucx_list_clone_a(UcxAllocator *allocator, const UcxList *list, copy_func cpyfnc, void* data); /** @@ -328,7 +328,8 @@ * @return the index of the element containing the specified data or -1 if the * data is not found in this list */ -ssize_t ucx_list_find(UcxList *list, void *elem, cmp_func cmpfnc, void *data); +ssize_t ucx_list_find(const UcxList *list, void *elem, + cmp_func cmpfnc, void *data); /** * Checks, if a list contains a specific element. @@ -342,7 +343,8 @@ * @return 1, if and only if the list contains the specified element data * @see ucx_list_find() */ -int ucx_list_contains(UcxList *list, void *elem, cmp_func cmpfnc, void *data); +int ucx_list_contains(const UcxList *list, void *elem, + cmp_func cmpfnc, void *data); /** * Sorts a UcxList with natural merge sort. @@ -388,6 +390,120 @@ UcxList *ucx_list_remove_a(UcxAllocator *allocator, UcxList *list, UcxList *element); +/** + * Returns the union of two lists. + * + * The union is a list of unique elements regarding cmpfnc obtained from + * both source lists. + * + * @param left the left source list + * @param right the right source list + * @param cmpfnc a function to compare elements + * @param cmpdata additional data for the compare function + * @param cpfnc a function to copy the elements + * @param cpdata additional data for the copy function + * @return a new list containing the union + */ +UcxList* ucx_list_union(const UcxList *left, const UcxList *right, + cmp_func cmpfnc, void* cmpdata, + copy_func cpfnc, void* cpdata); + +/** + * Returns the union of two lists. + * + * The union is a list of unique elements regarding cmpfnc obtained from + * both source lists. + * + * @param allocator allocates the new list elements + * @param left the left source list + * @param right the right source list + * @param cmpfnc a function to compare elements + * @param cmpdata additional data for the compare function + * @param cpfnc a function to copy the elements + * @param cpdata additional data for the copy function + * @return a new list containing the union + */ +UcxList* ucx_list_union_a(UcxAllocator *allocator, + const UcxList *left, const UcxList *right, + cmp_func cmpfnc, void* cmpdata, + copy_func cpfnc, void* cpdata); + +/** + * Returns the intersection of two lists. + * + * The intersection contains all elements of the left list + * (including duplicates) that can be found in the right list. + * + * @param left the left source list + * @param right the right source list + * @param cmpfnc a function to compare elements + * @param cmpdata additional data for the compare function + * @param cpfnc a function to copy the elements + * @param cpdata additional data for the copy function + * @return a new list containing the intersection + */ +UcxList* ucx_list_intersection(const UcxList *left, const UcxList *right, + cmp_func cmpfnc, void* cmpdata, + copy_func cpfnc, void* cpdata); + +/** + * Returns the intersection of two lists. + * + * The intersection contains all elements of the left list + * (including duplicates) that can be found in the right list. + * + * @param allocator allocates the new list elements + * @param left the left source list + * @param right the right source list + * @param cmpfnc a function to compare elements + * @param cmpdata additional data for the compare function + * @param cpfnc a function to copy the elements + * @param cpdata additional data for the copy function + * @return a new list containing the intersection + */ +UcxList* ucx_list_intersection_a(UcxAllocator *allocator, + const UcxList *left, const UcxList *right, + cmp_func cmpfnc, void* cmpdata, + copy_func cpfnc, void* cpdata); + +/** + * Returns the difference of two lists. + * + * The difference contains all elements of the left list + * (including duplicates) that are not equal to any element of the right list. + * + * @param left the left source list + * @param right the right source list + * @param cmpfnc a function to compare elements + * @param cmpdata additional data for the compare function + * @param cpfnc a function to copy the elements + * @param cpdata additional data for the copy function + * @return a new list containing the difference + */ +UcxList* ucx_list_difference(const UcxList *left, const UcxList *right, + cmp_func cmpfnc, void* cmpdata, + copy_func cpfnc, void* cpdata); + +/** + * Returns the difference of two lists. + * + * The difference contains all elements of the left list + * (including duplicates) that are not equal to any element of the right list. + * + * @param allocator allocates the new list elements + * @param left the left source list + * @param right the right source list + * @param cmpfnc a function to compare elements + * @param cmpdata additional data for the compare function + * @param cpfnc a function to copy the elements + * @param cpdata additional data for the copy function + * @return a new list containing the difference + */ +UcxList* ucx_list_difference_a(UcxAllocator *allocator, + const UcxList *left, const UcxList *right, + cmp_func cmpfnc, void* cmpdata, + copy_func cpfnc, void* cpdata); + #ifdef __cplusplus } #endif diff -r b1eac0878ce7 -r 18892c0a9adc ucx/ucx/logging.h --- a/ucx/ucx/logging.h Sat Dec 05 10:34:10 2020 +0100 +++ b/ucx/ucx/logging.h Sat Dec 05 11:54:58 2020 +0100 @@ -160,7 +160,10 @@ * format is: * * [LEVEL] [TIMESTAMP] [SOURCEFILE]:[LINENO] message - * + * + * The source file name is reduced to the actual file name. This is necessary to + * get consistent behavior over different definitions of the __FILE__ macro. + * * Attention: the message (including automatically generated information) * is limited to 4096 characters. The level description is limited to * 256 characters and the timestamp string is limited to 128 characters. diff -r b1eac0878ce7 -r 18892c0a9adc ucx/ucx/map.h --- a/ucx/ucx/map.h Sat Dec 05 10:34:10 2020 +0100 +++ b/ucx/ucx/map.h Sat Dec 05 11:54:58 2020 +0100 @@ -124,7 +124,7 @@ /** Structure for an iterator over a UcxMap. */ struct UcxMapIterator { /** The map to iterate over. */ - UcxMap *map; + UcxMap const *map; /** The current map element. */ UcxMapElement *cur; @@ -211,7 +211,7 @@ * @param data additional data for the copy function * @return 0 on success or a non-zero value on memory allocation errors */ -int ucx_map_copy(UcxMap *from, UcxMap *to, copy_func fnc, void *data); +int ucx_map_copy(UcxMap const *from, UcxMap *to, copy_func fnc, void *data); /** * Clones the map and rehashes if necessary. @@ -227,7 +227,25 @@ * @return the cloned map * @see ucx_map_copy() */ -UcxMap *ucx_map_clone(UcxMap *map, copy_func fnc, void *data); +UcxMap *ucx_map_clone(UcxMap const *map, copy_func fnc, void *data); + +/** + * Clones the map and rehashes if necessary. + * + * Note: In contrast to ucx_map_rehash() the load factor is irrelevant. + * This function always ensures a new UcxMap.size of at least + * 2.5*UcxMap.count. + * + * @param allocator the allocator to use for the cloned map + * @param map the map to clone + * @param fnc the copy function to use or NULL if the new and + * the old map shall share the data pointers + * @param data additional data for the copy function + * @return the cloned map + * @see ucx_map_copy() + */ +UcxMap *ucx_map_clone_a(UcxAllocator *allocator, + UcxMap const *map, copy_func fnc, void *data); /** * Increases size of the hash map, if necessary. @@ -264,7 +282,7 @@ * @param key the key * @return the value */ -void* ucx_map_get(UcxMap *map, UcxKey key); +void* ucx_map_get(UcxMap const *map, UcxKey key); /** * Removes a key/value-pair from the map by using the key. @@ -406,7 +424,7 @@ * first element list * @see ucx_map_iter_next() */ -UcxMapIterator ucx_map_iterator(UcxMap *map); +UcxMapIterator ucx_map_iterator(UcxMap const *map); /** * Proceeds to the next element of the map (if any). @@ -426,6 +444,102 @@ */ int ucx_map_iter_next(UcxMapIterator *iterator, UcxKey *key, void **value); +/** + * Returns the union of two maps. + * + * The union is a fresh map which is filled by two successive calls of + * ucx_map_copy() on the two input maps. + * + * @param first the first source map + * @param second the second source map + * @param cpfnc a function to copy the elements + * @param cpdata additional data for the copy function + * @return a new map containing the union + */ +UcxMap* ucx_map_union(const UcxMap *first, const UcxMap *second, + copy_func cpfnc, void* cpdata); + +/** + * Returns the union of two maps. + * + * The union is a fresh map which is filled by two successive calls of + * ucx_map_copy() on the two input maps. + * + * @param allocator the allocator that shall be used by the new map + * @param first the first source map + * @param second the second source map + * @param cpfnc a function to copy the elements + * @param cpdata additional data for the copy function + * @return a new map containing the union + */ +UcxMap* ucx_map_union_a(UcxAllocator *allocator, + const UcxMap *first, const UcxMap *second, + copy_func cpfnc, void* cpdata); + +/** + * Returns the intersection of two maps. + * + * The intersection is defined as a copy of the first map with every element + * removed that has no valid key in the second map. + * + * @param first the first source map + * @param second the second source map + * @param cpfnc a function to copy the elements + * @param cpdata additional data for the copy function + * @return a new map containing the intersection + */ +UcxMap* ucx_map_intersection(const UcxMap *first, const UcxMap *second, + copy_func cpfnc, void* cpdata); + +/** + * Returns the intersection of two maps. + * + * The intersection is defined as a copy of the first map with every element + * removed that has no valid key in the second map. + * + * @param allocator the allocator that shall be used by the new map + * @param first the first source map + * @param second the second source map + * @param cpfnc a function to copy the elements + * @param cpdata additional data for the copy function + * @return a new map containing the intersection + */ +UcxMap* ucx_map_intersection_a(UcxAllocator *allocator, + const UcxMap *first, const UcxMap *second, + copy_func cpfnc, void* cpdata); + +/** + * Returns the difference of two maps. + * + * The difference contains a copy of all elements of the first map + * for which the corresponding keys cannot be found in the second map. + * + * @param first the first source map + * @param second the second source map + * @param cpfnc a function to copy the elements + * @param cpdata additional data for the copy function + * @return a new list containing the difference + */ +UcxMap* ucx_map_difference(const UcxMap *first, const UcxMap *second, + copy_func cpfnc, void* cpdata); + +/** + * Returns the difference of two maps. + * + * The difference contains a copy of all elements of the first map + * for which the corresponding keys cannot be found in the second map. + * + * @param allocator the allocator that shall be used by the new map + * @param first the first source map + * @param second the second source map + * @param cpfnc a function to copy the elements + * @param cpdata additional data for the copy function + * @return a new list containing the difference + */ +UcxMap* ucx_map_difference_a(UcxAllocator *allocator, + const UcxMap *first, const UcxMap *second, + copy_func cpfnc, void* cpdata); + #ifdef __cplusplus } diff -r b1eac0878ce7 -r 18892c0a9adc ucx/ucx/string.h --- a/ucx/ucx/string.h Sat Dec 05 10:34:10 2020 +0100 +++ b/ucx/ucx/string.h Sat Dec 05 11:54:58 2020 +0100 @@ -83,6 +83,7 @@ #ifdef __cplusplus extern "C" { #endif + /** * The UCX string structure. */ @@ -112,7 +113,7 @@ #ifdef __cplusplus /** - * One of two type adjustment functions that return a scstr_t. + * One of two type adjustment functions that return an scstr_t. * * Used internally to convert a UCX string to an immutable UCX string. * @@ -129,7 +130,7 @@ } /** - * One of two type adjustment functions that return a scstr_t. + * One of two type adjustment functions that return an scstr_t. * * Used internally to convert a UCX string to an immutable UCX string. * This variant is used, when the string is already immutable and no operation @@ -147,13 +148,13 @@ /** * Converts a UCX string to an immutable UCX string (scstr_t). * @param str some UCX string - * @return the an immutable version of the provided string + * @return an immutable version of the provided string */ #define SCSTR(s) s2scstr(s) #else /** - * One of two type adjustment functions that return a scstr_t. + * One of two type adjustment functions that return an scstr_t. * * Used internally to convert a UCX string to an immutable UCX string. * This variant is used, when the string is already immutable and no operation @@ -167,7 +168,7 @@ scstr_t ucx_sc2sc(scstr_t str); /** - * One of two type adjustment functions that return a scstr_t. + * One of two type adjustment functions that return an scstr_t. * * Used internally to convert a UCX string to an immutable UCX string. * @@ -182,7 +183,7 @@ /** * Converts a UCX string to an immutable UCX string (scstr_t). * @param str some UCX string - * @return the an immutable version of the provided string + * @return an immutable version of the provided string */ #define SCSTR(str) _Generic(str, sstr_t: ucx_ss2sc, scstr_t: ucx_sc2sc)(str) @@ -191,7 +192,7 @@ /** * Converts a UCX string to an immutable UCX string (scstr_t). * @param str some UCX string - * @return the an immutable version of the provided string + * @return an immutable version of the provided string */ #define SCSTR(str) __builtin_choose_expr( \ __builtin_types_compatible_p(typeof(str), sstr_t), \ @@ -244,8 +245,8 @@ * * The length is implicitly inferred by using a call to strlen(). * - * Note: the sstr_t will hold a reference to the C string. If you - * do want a copy, use sstrdup() on the return value of this function. + * Note: the sstr_t will share the specified pointer to the C string. + * If you do want a copy, use sstrdup() on the return value of this function. * * If you need to wrap a constant string, use scstr(). * @@ -259,8 +260,8 @@ /** * Creates a new sstr_t of the specified length based on a C string. * - * Note: the sstr_t will hold a reference to the C string. If you - * do want a copy, use sstrdup() on the return value of this function. + * Note: the sstr_t will share the specified pointer to the C string. + * If you do want a copy, use sstrdup() on the return value of this function. * * If you need to wrap a constant string, use scstrn(). * @@ -278,8 +279,8 @@ * * The length is implicitly inferred by using a call to strlen(). * - * Note: the scstr_t will hold a reference to the C string. If you - * do want a copy, use scstrdup() on the return value of this function. + * Note: the scstr_t will share the specified pointer to the C string. + * If you do want a copy, use scstrdup() on the return value of this function. * * @param cstring the C string to wrap * @return a new scstr_t containing the C string @@ -292,9 +293,8 @@ /** * Creates a new scstr_t of the specified length based on a constant C string. * - * Note: the scstr_t will hold a reference to the C string. If you - * do want a copy, use scstrdup() on the return value of this function. - * + * Note: the scstr_t will share the specified pointer to the C string. + * If you do want a copy, use scstrdup() on the return value of this function. * * * @param cstring the C string to wrap * @param length the length of the string @@ -305,21 +305,24 @@ scstr_t scstrn(const char *cstring, size_t length); /** - * Returns the cumulated length of all specified strings. + * Returns the accumulated length of all specified strings. * - * Attention: if the count argument does not match the count of the + * Attention: if the count argument is larger than the count of the * specified strings, the behavior is undefined. * - * @param count the total number of specified strings (so at least 1) + * @param count the total number of specified strings * @param ... all strings - * @return the cumulated length of all strings + * @return the accumulated length of all strings */ size_t scstrnlen(size_t count, ...); /** - * Alias for scstrnlen() which automatically converts the arguments. + * Returns the accumulated length of all specified strings. * - * @param count the total number of specified strings (so at least 1) + * Attention: if the count argument is larger than the count of the + * specified strings, the behavior is undefined. + * + * @param count the total number of specified strings * @param ... all strings * @return the cumulated length of all strings */ @@ -342,7 +345,13 @@ sstr_t scstrcat(size_t count, scstr_t s1, ...); /** - * Alias for scstrcat() which automatically converts the arguments. + * Concatenates two or more strings. + * + * The resulting string will be allocated by standard malloc(). + * So developers MUST pass the sstr_t.ptr to free(). + * + * The sstr_t.ptr of the return value will always be NULL- + * terminated. * * @param count the total number of strings to concatenate * @param s1 first string @@ -354,35 +363,47 @@ /** * Concatenates two or more strings using a UcxAllocator. * - * See scstrcat() for details. + * The resulting string must be freed by the allocators free() + * implementation. + * + * The sstr_t.ptr of the return value will always be NULL- + * terminated. * - * @param a the allocator to use + * @param alloc the allocator to use * @param count the total number of strings to concatenate * @param s1 first string * @param ... all remaining strings * @return the concatenated string + * + * @see scstrcat() */ -sstr_t scstrcat_a(UcxAllocator *a, size_t count, scstr_t s1, ...); +sstr_t scstrcat_a(UcxAllocator *alloc, size_t count, scstr_t s1, ...); /** - * Alias for scstrcat_a() which automatically converts the arguments. + * Concatenates two or more strings using a UcxAllocator. + * + * The resulting string must be freed by the allocators free() + * implementation. * - * See sstrcat() for details. + * The sstr_t.ptr of the return value will always be NULL- + * terminated. * - * @param a the allocator to use + * @param alloc the allocator to use * @param count the total number of strings to concatenate * @param s1 first string * @param ... all remaining strings * @return the concatenated string + * + * @see sstrcat() */ -#define sstrcat_a(a, count, s1, ...) \ - scstrcat_a(a, count, SCSTR(s1), __VA_ARGS__) +#define sstrcat_a(alloc, count, s1, ...) \ + scstrcat_a(alloc, count, SCSTR(s1), __VA_ARGS__) /** * Returns a substring starting at the specified location. * * Attention: the new string references the same memory area as the - * input string and will NOT be NULL-terminated. + * input string and is NOT required to be NULL-terminated. * Use sstrdup() to get a copy. * * @param string input string @@ -395,10 +416,10 @@ sstr_t sstrsubs(sstr_t string, size_t start); /** - * Returns a substring with a maximum length starting at the specified location. + * Returns a substring with the given length starting at the specified location. * * Attention: the new string references the same memory area as the - * input string and will NOT be NULL-terminated. + * input string and is NOT required to be NULL-terminated. * Use sstrdup() to get a copy. * * @param string input string @@ -417,7 +438,7 @@ * location. * * Attention: the new string references the same memory area as the - * input string and will NOT be NULL-terminated. +* input string and is NOT required to be NULL-terminated. * Use scstrdup() to get a copy. * * @param string input string @@ -434,7 +455,7 @@ * at the specified location. * * Attention: the new string references the same memory area as the - * input string and will NOT be NULL-terminated. + * input string and is NOT required to be NULL-terminated. * Use scstrdup() to get a copy. * * @param string input string @@ -522,7 +543,13 @@ sstr_t scstrsstr(sstr_t string, scstr_t match); /** - * Alias for scstrsstr() which automatically converts the match string. + * Returns a substring starting at the location of the first occurrence of the + * specified string. + * + * If the string does not contain the other string, an empty string is returned. + * + * If match is an empty string, the complete string is + * returned. * * @param string the string to be scanned * @param match string containing the sequence of characters to match @@ -550,7 +577,13 @@ scstr_t scstrscstr(scstr_t string, scstr_t match); /** - * Alias for scstrscstr() which automatically converts the match string. + * Returns an immutable substring starting at the location of the + * first occurrence of the specified immutable string. + * + * If the string does not contain the other string, an empty string is returned. + * + * If match is an empty string, the complete string is + * returned. * * @param string the string to be scanned * @param match string containing the sequence of characters to match @@ -595,6 +628,55 @@ * delimiter. * * Attention: The array pointer AND all sstr_t.ptr of the array + * items must be manually passed to free(). Use scstrsplit_a() with + * an allocator to managed memory, to avoid this. + * + * @param string the string to split + * @param delim the delimiter string + * @param count IN: the maximum size of the resulting array (0 = no limit), + * OUT: the actual size of the array + * @return a sstr_t array containing the split strings or + * NULL on error + * + * @see scstrsplit_a() + */ +sstr_t* scstrsplit(scstr_t string, scstr_t delim, ssize_t *count); + +/** + * Splits a string into parts by using a delimiter string. + * + * This function will return NULL, if one of the following happens: + *
    + *
  • the string length is zero
  • + *
  • the delimeter length is zero
  • + *
  • the string equals the delimeter
  • + *
  • memory allocation fails
  • + *
+ * + * The integer referenced by count is used as input and determines + * the maximum size of the resulting array, i.e. the maximum count of splits to + * perform + 1. + * + * The integer referenced by count is also used as output and is + * set to + *
    + *
  • -2, on memory allocation errors
  • + *
  • -1, if either the string or the delimiter is an empty string
  • + *
  • 0, if the string equals the delimiter
  • + *
  • 1, if the string does not contain the delimiter
  • + *
  • the count of array items, otherwise
  • + *
+ * + * If the string starts with the delimiter, the first item of the resulting + * array will be an empty string. + * + * If the string ends with the delimiter and the maximum list size is not + * exceeded, the last array item will be an empty string. + * In case the list size would be exceeded, the last array item will be the + * remaining string after the last split, including the terminating + * delimiter. + * + * Attention: The array pointer AND all sstr_t.ptr of the array * items must be manually passed to free(). Use sstrsplit_a() with * an allocator to managed memory, to avoid this. * @@ -605,20 +687,6 @@ * @return a sstr_t array containing the split strings or * NULL on error * - * @see scstrsplit_a() - */ -sstr_t* scstrsplit(scstr_t string, scstr_t delim, ssize_t *count); - -/** - * Alias for scstrsplit() which automatically converts the arguments. - * - * @param string the string to split - * @param delim the delimiter string - * @param count IN: the maximum size of the resulting array (0 = no limit), - * OUT: the actual size of the array - * @return a sstr_t array containing the split strings or - * NULL on error - * * @see sstrsplit_a() */ #define sstrsplit(string, delim, count) \ @@ -633,9 +701,6 @@ * the sstr_t array itself are allocated by using the UcxAllocator.malloc() * function. * - * Note: the allocator is not used for memory that is freed within the - * same call of this function (locally scoped variables). - * * @param allocator the UcxAllocator used for allocating memory * @param string the string to split * @param delim the delimiter string @@ -650,7 +715,13 @@ ssize_t *count); /** - * Alias for scstrsplit_a() which automatically converts the arguments. + * Performing sstrsplit() using a UcxAllocator. + * + * Read the description of sstrsplit() for details. + * + * The memory for the sstr_t.ptr pointers of the array items and the memory for + * the sstr_t array itself are allocated by using the UcxAllocator.malloc() + * function. * * @param allocator the UcxAllocator used for allocating memory * @param string the string to split @@ -680,7 +751,10 @@ int scstrcmp(scstr_t s1, scstr_t s2); /** - * Alias for scstrcmp() which automatically converts its arguments. + * Compares two UCX strings with standard memcmp(). + * + * At first it compares the sstr_t.length attribute of the two strings. The + * memcmp() function is called, if and only if the lengths match. * * @param s1 the first string * @param s2 the second string @@ -706,7 +780,11 @@ int scstrcasecmp(scstr_t s1, scstr_t s2); /** - * Alias for scstrcasecmp() which automatically converts the arguments. + * Compares two UCX strings ignoring the case. + * + * At first it compares the sstr_t.length attribute of the two strings. If and + * only if the lengths match, both strings are compared char by char ignoring + * the case. * * @param s1 the first string * @param s2 the second string @@ -733,7 +811,14 @@ sstr_t scstrdup(scstr_t string); /** - * Alias for scstrdup() which automatically converts the argument. + * Creates a duplicate of the specified string. + * + * The new sstr_t will contain a copy allocated by standard + * malloc(). So developers MUST pass the sstr_t.ptr to + * free(). + * + * The sstr_t.ptr of the return value will always be NULL- + * terminated, regardless of the argument. * * @param string the string to duplicate * @return a duplicate of the string @@ -760,7 +845,15 @@ sstr_t scstrdup_a(UcxAllocator *allocator, scstr_t string); /** - * Alias for scstrdup_a() which automatically converts the argument. + * Creates a duplicate of the specified string using a UcxAllocator. + * + * The new sstr_t will contain a copy allocated by the allocators + * UcxAllocator.malloc() function. So it is implementation depended, whether the + * returned sstr_t.ptr pointer must be passed to the allocators + * UcxAllocator.free() function manually. + * + * The sstr_t.ptr of the return value will always be NULL- + * terminated, regardless of the argument. * * @param allocator a valid instance of a UcxAllocator * @param string the string to duplicate @@ -810,6 +903,7 @@ /** * Checks, if a string has a specific prefix. + * * @param string the string to check * @param prefix the prefix the string should have * @return 1, if and only if the string has the specified prefix, 0 otherwise @@ -817,7 +911,7 @@ int scstrprefix(scstr_t string, scstr_t prefix); /** - * Alias for scstrprefix() which automatically converts the arguments. + * Checks, if a string has a specific prefix. * * @param string the string to check * @param prefix the prefix the string should have @@ -827,6 +921,7 @@ /** * Checks, if a string has a specific suffix. + * * @param string the string to check * @param suffix the suffix the string should have * @return 1, if and only if the string has the specified suffix, 0 otherwise @@ -834,7 +929,7 @@ int scstrsuffix(scstr_t string, scstr_t suffix); /** - * Alias for scstrsuffix() which automatically converts the arguments. + * Checks, if a string has a specific suffix. * * @param string the string to check * @param suffix the suffix the string should have @@ -843,10 +938,48 @@ #define sstrsuffix(string, suffix) scstrsuffix(SCSTR(string), SCSTR(suffix)) /** + * Checks, if a string has a specific prefix, ignoring the case. + * + * @param string the string to check + * @param prefix the prefix the string should have + * @return 1, if and only if the string has the specified prefix, 0 otherwise + */ +int scstrcaseprefix(scstr_t string, scstr_t prefix); + +/** + * Checks, if a string has a specific prefix, ignoring the case. + * + * @param string the string to check + * @param prefix the prefix the string should have + * @return 1, if and only if the string has the specified prefix, 0 otherwise + */ +#define sstrcaseprefix(string, prefix) \ + scstrcaseprefix(SCSTR(string), SCSTR(prefix)) + +/** + * Checks, if a string has a specific suffix, ignoring the case. + * + * @param string the string to check + * @param suffix the suffix the string should have + * @return 1, if and only if the string has the specified suffix, 0 otherwise + */ +int scstrcasesuffix(scstr_t string, scstr_t suffix); + +/** + * Checks, if a string has a specific suffix, ignoring the case. + * + * @param string the string to check + * @param suffix the suffix the string should have + * @return 1, if and only if the string has the specified suffix, 0 otherwise + */ +#define sstrcasesuffix(string, suffix) \ + scstrcasesuffix(SCSTR(string), SCSTR(suffix)) + +/** * Returns a lower case version of a string. * - * This function creates a duplicate of the input string, first. See the - * documentation of scstrdup() for the implications. + * This function creates a duplicate of the input string, first + * (see scstrdup()). * * @param string the input string * @return the resulting lower case string @@ -855,7 +988,10 @@ sstr_t scstrlower(scstr_t string); /** - * Alias for scstrlower() which automatically converts the argument. + * Returns a lower case version of a string. + * + * This function creates a duplicate of the input string, first + * (see sstrdup()). * * @param string the input string * @return the resulting lower case string @@ -865,8 +1001,8 @@ /** * Returns a lower case version of a string. * - * This function creates a duplicate of the input string, first. See the - * documentation of scstrdup_a() for the implications. + * This function creates a duplicate of the input string, first + * (see scstrdup_a()). * * @param allocator the allocator used for duplicating the string * @param string the input string @@ -877,7 +1013,10 @@ /** - * Alias for scstrlower_a() which automatically converts the argument. + * Returns a lower case version of a string. + * + * This function creates a duplicate of the input string, first + * (see sstrdup_a()). * * @param allocator the allocator used for duplicating the string * @param string the input string @@ -888,8 +1027,8 @@ /** * Returns a upper case version of a string. * - * This function creates a duplicate of the input string, first. See the - * documentation of scstrdup() for the implications. + * This function creates a duplicate of the input string, first + * (see scstrdup()). * * @param string the input string * @return the resulting upper case string @@ -898,7 +1037,10 @@ sstr_t scstrupper(scstr_t string); /** - * Alias for scstrupper() which automatically converts the argument. + * Returns a upper case version of a string. + * + * This function creates a duplicate of the input string, first + * (see sstrdup()). * * @param string the input string * @return the resulting upper case string @@ -908,8 +1050,8 @@ /** * Returns a upper case version of a string. * - * This function creates a duplicate of the input string, first. See the - * documentation of scstrdup_a() for the implications. + * This function creates a duplicate of the input string, first + * (see scstrdup_a()). * * @param allocator the allocator used for duplicating the string * @param string the input string @@ -919,7 +1061,10 @@ sstr_t scstrupper_a(UcxAllocator *allocator, scstr_t string); /** - * Alias for scstrupper_a() which automatically converts the argument. + * Returns a upper case version of a string. + * + * This function creates a duplicate of the input string, first + * (see sstrdup_a()). * * @param allocator the allocator used for duplicating the string * @param string the input string @@ -927,6 +1072,128 @@ */ #define sstrupper_a(allocator, string) scstrupper_a(allocator, string) + +/** + * Replaces a pattern in a string with another string. + * + * The pattern is taken literally and is no regular expression. + * Replaces at most replmax occurrences. + * + * The resulting string is allocated by the specified allocator. I.e. it + * depends on the used allocator, whether the sstr_t.ptr must be freed + * manually. + * + * If allocation fails, the sstr_t.ptr of the return value is NULL. + * + * @param allocator the allocator to use + * @param str the string where replacements should be applied + * @param pattern the pattern to search for + * @param replacement the replacement string + * @param replmax maximum number of replacements + * @return the resulting string after applying the replacements + */ +sstr_t scstrreplacen_a(UcxAllocator *allocator, scstr_t str, + scstr_t pattern, scstr_t replacement, size_t replmax); + +/** + * Replaces a pattern in a string with another string. + * + * The pattern is taken literally and is no regular expression. + * Replaces at most replmax occurrences. + * + * The sstr_t.ptr of the resulting string must be freed manually. + * + * If allocation fails, the sstr_t.ptr of the return value is NULL. + * + * @param str the string where replacements should be applied + * @param pattern the pattern to search for + * @param replacement the replacement string + * @param replmax maximum number of replacements + * @return the resulting string after applying the replacements + */ +sstr_t scstrreplacen(scstr_t str, scstr_t pattern, + scstr_t replacement, size_t replmax); + +/** + * Replaces a pattern in a string with another string. + * + * The pattern is taken literally and is no regular expression. + * Replaces at most replmax occurrences. + * + * The resulting string is allocated by the specified allocator. I.e. it + * depends on the used allocator, whether the sstr_t.ptr must be freed + * manually. + * + * @param allocator the allocator to use + * @param str the string where replacements should be applied + * @param pattern the pattern to search for + * @param replacement the replacement string + * @param replmax maximum number of replacements + * @return the resulting string after applying the replacements + */ +#define sstrreplacen_a(allocator, str, pattern, replacement, replmax) \ + scstrreplacen_a(allocator, SCSTR(str), SCSTR(pattern), \ + SCSTR(replacement), replmax) + +/** + * Replaces a pattern in a string with another string. + * + * The pattern is taken literally and is no regular expression. + * Replaces at most replmax occurrences. + * + * The sstr_t.ptr of the resulting string must be freed manually. + * + * If allocation fails, the sstr_t.ptr of the return value is NULL. + * + * @param str the string where replacements should be applied + * @param pattern the pattern to search for + * @param replacement the replacement string + * @param replmax maximum number of replacements + * @return the resulting string after applying the replacements + */ +#define sstrreplacen(str, pattern, replacement, replmax) \ + scstrreplacen(SCSTR(str), SCSTR(pattern), SCSTR(replacement), replmax) + +/** + * Replaces a pattern in a string with another string. + * + * The pattern is taken literally and is no regular expression. + * Replaces at most replmax occurrences. + * + * The resulting string is allocated by the specified allocator. I.e. it + * depends on the used allocator, whether the sstr_t.ptr must be freed + * manually. + * + * If allocation fails, the sstr_t.ptr of the return value is NULL. + * + * @param allocator the allocator to use + * @param str the string where replacements should be applied + * @param pattern the pattern to search for + * @param replacement the replacement string + * @return the resulting string after applying the replacements + */ +#define sstrreplace_a(allocator, str, pattern, replacement) \ + scstrreplacen_a(allocator, SCSTR(str), SCSTR(pattern), \ + SCSTR(replacement), SIZE_MAX) + +/** + * Replaces a pattern in a string with another string. + * + * The pattern is taken literally and is no regular expression. + * Replaces at most replmax occurrences. + * + * The sstr_t.ptr of the resulting string must be freed manually. + * + * If allocation fails, the sstr_t.ptr of the return value is NULL. + * + * @param str the string where replacements should be applied + * @param pattern the pattern to search for + * @param replacement the replacement string + * @return the resulting string after applying the replacements + */ +#define sstrreplace(str, pattern, replacement) \ + scstrreplacen(SCSTR(str), SCSTR(pattern), SCSTR(replacement), SIZE_MAX) + #ifdef __cplusplus } #endif diff -r b1eac0878ce7 -r 18892c0a9adc ucx/ucx/ucx.h --- a/ucx/ucx/ucx.h Sat Dec 05 10:34:10 2020 +0100 +++ b/ucx/ucx/ucx.h Sat Dec 05 11:54:58 2020 +0100 @@ -40,7 +40,7 @@ #define UCX_VERSION_MAJOR 2 /** Minor UCX version as integer constant. */ -#define UCX_VERSION_MINOR 0 +#define UCX_VERSION_MINOR 1 /** Version constant which ensures to increase monotonically. */ #define UCX_VERSION (((UCX_VERSION_MAJOR)<<16)|UCX_VERSION_MINOR) @@ -170,10 +170,7 @@ /** * Performs a multiplication of size_t values and checks for overflow. - * - * This is a custom implementation in case there is no compiler builtin - * available. - * + * * @param a first operand * @param b second operand * @param result a pointer to a size_t, where the result should @@ -183,6 +180,18 @@ */ #define ucx_szmul(a, b, result) ucx_szmul_impl(a, b, result) +/** + * Performs a multiplication of size_t values and checks for overflow. + * + * This is a custom implementation in case there is no compiler builtin + * available. + * + * @param a first operand + * @param b second operand + * @param result a pointer to a size_t where the result should be stored + * @return zero, if no overflow occurred and the result is correct, non-zero + * otherwise + */ int ucx_szmul_impl(size_t a, size_t b, size_t *result); #endif diff -r b1eac0878ce7 -r 18892c0a9adc ucx/ucx/utils.h --- a/ucx/ucx/utils.h Sat Dec 05 10:34:10 2020 +0100 +++ b/ucx/ucx/utils.h Sat Dec 05 11:54:58 2020 +0100 @@ -184,6 +184,105 @@ */ int ucx_cmp_longint(const void *i1, const void *i2, void *data); +/** + * Compares two integers of type long long. + * @param i1 pointer to long long one + * @param i2 pointer to long long two + * @param data omitted + * @return -1, if *i1 is less than *i2, 0 if both are equal, + * 1 if *i1 is greater than *i2 + */ +int ucx_cmp_longlong(const void *i1, const void *i2, void *data); + +/** + * Compares two integers of type int16_t. + * @param i1 pointer to int16_t one + * @param i2 pointer to int16_t two + * @param data omitted + * @return -1, if *i1 is less than *i2, 0 if both are equal, + * 1 if *i1 is greater than *i2 + */ +int ucx_cmp_int16(const void *i1, const void *i2, void *data); + +/** + * Compares two integers of type int32_t. + * @param i1 pointer to int32_t one + * @param i2 pointer to int32_t two + * @param data omitted + * @return -1, if *i1 is less than *i2, 0 if both are equal, + * 1 if *i1 is greater than *i2 + */ +int ucx_cmp_int32(const void *i1, const void *i2, void *data); + +/** + * Compares two integers of type int64_t. + * @param i1 pointer to int64_t one + * @param i2 pointer to int64_t two + * @param data omitted + * @return -1, if *i1 is less than *i2, 0 if both are equal, + * 1 if *i1 is greater than *i2 + */ +int ucx_cmp_int64(const void *i1, const void *i2, void *data); + +/** + * Compares two integers of type unsigned int. + * @param i1 pointer to unsigned integer one + * @param i2 pointer to unsigned integer two + * @param data omitted + * @return -1, if *i1 is less than *i2, 0 if both are equal, + * 1 if *i1 is greater than *i2 + */ +int ucx_cmp_uint(const void *i1, const void *i2, void *data); + +/** + * Compares two integers of type unsigned long int. + * @param i1 pointer to unsigned long integer one + * @param i2 pointer to unsigned long integer two + * @param data omitted + * @return -1, if *i1 is less than *i2, 0 if both are equal, + * 1 if *i1 is greater than *i2 + */ +int ucx_cmp_ulongint(const void *i1, const void *i2, void *data); + +/** + * Compares two integers of type unsigned long long. + * @param i1 pointer to unsigned long long one + * @param i2 pointer to unsigned long long two + * @param data omitted + * @return -1, if *i1 is less than *i2, 0 if both are equal, + * 1 if *i1 is greater than *i2 + */ +int ucx_cmp_ulonglong(const void *i1, const void *i2, void *data); + +/** + * Compares two integers of type uint16_t. + * @param i1 pointer to uint16_t one + * @param i2 pointer to uint16_t two + * @param data omitted + * @return -1, if *i1 is less than *i2, 0 if both are equal, + * 1 if *i1 is greater than *i2 + */ +int ucx_cmp_uint16(const void *i1, const void *i2, void *data); + +/** + * Compares two integers of type uint32_t. + * @param i1 pointer to uint32_t one + * @param i2 pointer to uint32_t two + * @param data omitted + * @return -1, if *i1 is less than *i2, 0 if both are equal, + * 1 if *i1 is greater than *i2 + */ +int ucx_cmp_uint32(const void *i1, const void *i2, void *data); + +/** + * Compares two integers of type uint64_t. + * @param i1 pointer to uint64_t one + * @param i2 pointer to uint64_t two + * @param data omitted + * @return -1, if *i1 is less than *i2, 0 if both are equal, + * 1 if *i1 is greater than *i2 + */ +int ucx_cmp_uint64(const void *i1, const void *i2, void *data); /** * Distance function for integers of type int. @@ -204,6 +303,96 @@ intmax_t ucx_dist_longint(const void *i1, const void *i2, void *data); /** + * Distance function for integers of type long long. + * @param i1 pointer to long long one + * @param i2 pointer to long long two + * @param data omitted + * @return i1 minus i2 + */ +intmax_t ucx_dist_longlong(const void *i1, const void *i2, void *data); + +/** + * Distance function for integers of type int16_t. + * @param i1 pointer to int16_t one + * @param i2 pointer to int16_t two + * @param data omitted + * @return i1 minus i2 + */ +intmax_t ucx_dist_int16(const void *i1, const void *i2, void *data); + +/** + * Distance function for integers of type int32_t. + * @param i1 pointer to int32_t one + * @param i2 pointer to int32_t two + * @param data omitted + * @return i1 minus i2 + */ +intmax_t ucx_dist_int32(const void *i1, const void *i2, void *data); + +/** + * Distance function for integers of type int64_t. + * @param i1 pointer to int64_t one + * @param i2 pointer to int64_t two + * @param data omitted + * @return i1 minus i2 + */ +intmax_t ucx_dist_int64(const void *i1, const void *i2, void *data); + +/** + * Distance function for integers of type unsigned int. + * @param i1 pointer to unsigned integer one + * @param i2 pointer to unsigned integer two + * @param data omitted + * @return i1 minus i2 + */ +intmax_t ucx_dist_uint(const void *i1, const void *i2, void *data); + +/** + * Distance function for integers of type unsigned long int. + * @param i1 pointer to unsigned long integer one + * @param i2 pointer to unsigned long integer two + * @param data omitted + * @return i1 minus i2 + */ +intmax_t ucx_dist_ulongint(const void *i1, const void *i2, void *data); + +/** + * Distance function for integers of type unsigned long long. + * @param i1 pointer to unsigned long long one + * @param i2 pointer to unsigned long long two + * @param data omitted + * @return i1 minus i2 + */ +intmax_t ucx_dist_ulonglong(const void *i1, const void *i2, void *data); + +/** + * Distance function for integers of type uint16_t. + * @param i1 pointer to uint16_t one + * @param i2 pointer to uint16_t two + * @param data omitted + * @return i1 minus i2 + */ +intmax_t ucx_dist_uint16(const void *i1, const void *i2, void *data); + +/** + * Distance function for integers of type uint32_t. + * @param i1 pointer to uint32_t one + * @param i2 pointer to uint32_t two + * @param data omitted + * @return i1 minus i2 + */ +intmax_t ucx_dist_uint32(const void *i1, const void *i2, void *data); + +/** + * Distance function for integers of type uint64_t. + * @param i1 pointer to uint64_t one + * @param i2 pointer to uint64_t two + * @param data omitted + * @return i1 minus i2 + */ +intmax_t ucx_dist_uint64(const void *i1, const void *i2, void *data); + +/** * Compares two real numbers of type float. * @param f1 pointer to float one * @param f2 pointer to float two diff -r b1eac0878ce7 -r 18892c0a9adc ucx/utils.c --- a/ucx/utils.c Sat Dec 05 10:34:10 2020 +0100 +++ b/ucx/utils.c Sat Dec 05 11:54:58 2020 +0100 @@ -113,8 +113,108 @@ } int ucx_cmp_longint(const void *i1, const void *i2, void *data) { - int a = *((const long int*) i1); - int b = *((const long int*) i2); + long int a = *((const long int*) i1); + long int b = *((const long int*) i2); + if (a == b) { + return 0; + } else { + return a < b ? -1 : 1; + } +} + +int ucx_cmp_longlong(const void *i1, const void *i2, void *data) { + long long a = *((const long long*) i1); + long long b = *((const long long*) i2); + if (a == b) { + return 0; + } else { + return a < b ? -1 : 1; + } +} + +int ucx_cmp_int16(const void *i1, const void *i2, void *data) { + int16_t a = *((const int16_t*) i1); + int16_t b = *((const int16_t*) i2); + if (a == b) { + return 0; + } else { + return a < b ? -1 : 1; + } +} + +int ucx_cmp_int32(const void *i1, const void *i2, void *data) { + int32_t a = *((const int32_t*) i1); + int32_t b = *((const int32_t*) i2); + if (a == b) { + return 0; + } else { + return a < b ? -1 : 1; + } +} + +int ucx_cmp_int64(const void *i1, const void *i2, void *data) { + int64_t a = *((const int64_t*) i1); + int64_t b = *((const int64_t*) i2); + if (a == b) { + return 0; + } else { + return a < b ? -1 : 1; + } +} + +int ucx_cmp_uint(const void *i1, const void *i2, void *data) { + unsigned int a = *((const unsigned int*) i1); + unsigned int b = *((const unsigned int*) i2); + if (a == b) { + return 0; + } else { + return a < b ? -1 : 1; + } +} + +int ucx_cmp_ulongint(const void *i1, const void *i2, void *data) { + unsigned long int a = *((const unsigned long int*) i1); + unsigned long int b = *((const unsigned long int*) i2); + if (a == b) { + return 0; + } else { + return a < b ? -1 : 1; + } +} + +int ucx_cmp_ulonglong(const void *i1, const void *i2, void *data) { + unsigned long long a = *((const unsigned long long*) i1); + unsigned long long b = *((const unsigned long long*) i2); + if (a == b) { + return 0; + } else { + return a < b ? -1 : 1; + } +} + +int ucx_cmp_uint16(const void *i1, const void *i2, void *data) { + uint16_t a = *((const uint16_t*) i1); + uint16_t b = *((const uint16_t*) i2); + if (a == b) { + return 0; + } else { + return a < b ? -1 : 1; + } +} + +int ucx_cmp_uint32(const void *i1, const void *i2, void *data) { + uint32_t a = *((const uint32_t*) i1); + uint32_t b = *((const uint32_t*) i2); + if (a == b) { + return 0; + } else { + return a < b ? -1 : 1; + } +} + +int ucx_cmp_uint64(const void *i1, const void *i2, void *data) { + uint64_t a = *((const uint64_t*) i1); + uint64_t b = *((const uint64_t*) i2); if (a == b) { return 0; } else { @@ -134,6 +234,66 @@ return a - b; } +intmax_t ucx_dist_longlong(const void *i1, const void *i2, void *data) { + intmax_t a = *((const long long*) i1); + intmax_t b = *((const long long*) i2); + return a - b; +} + +intmax_t ucx_dist_int16(const void *i1, const void *i2, void *data) { + intmax_t a = *((const int16_t*) i1); + intmax_t b = *((const int16_t*) i2); + return a - b; +} + +intmax_t ucx_dist_int32(const void *i1, const void *i2, void *data) { + intmax_t a = *((const int32_t*) i1); + intmax_t b = *((const int32_t*) i2); + return a - b; +} + +intmax_t ucx_dist_int64(const void *i1, const void *i2, void *data) { + intmax_t a = *((const int64_t*) i1); + intmax_t b = *((const int64_t*) i2); + return a - b; +} + +intmax_t ucx_dist_uint(const void *i1, const void *i2, void *data) { + uintmax_t a = *((const unsigned int*) i1); + uintmax_t b = *((const unsigned int*) i2); + return a > b ? (intmax_t)(a - b) : -(intmax_t)(b - a); +} + +intmax_t ucx_dist_ulongint(const void *i1, const void *i2, void *data) { + uintmax_t a = *((const unsigned long int*) i1); + uintmax_t b = *((const unsigned long int*) i2); + return a > b ? (intmax_t)(a - b) : -(intmax_t)(b - a); +} + +intmax_t ucx_dist_ulonglong(const void *i1, const void *i2, void *data) { + uintmax_t a = *((const unsigned long long*) i1); + uintmax_t b = *((const unsigned long long*) i2); + return a > b ? (intmax_t)(a - b) : -(intmax_t)(b - a); +} + +intmax_t ucx_dist_uint16(const void *i1, const void *i2, void *data) { + uintmax_t a = *((const uint16_t*) i1); + uintmax_t b = *((const uint16_t*) i2); + return a > b ? (intmax_t)(a - b) : -(intmax_t)(b - a); +} + +intmax_t ucx_dist_uint32(const void *i1, const void *i2, void *data) { + uintmax_t a = *((const uint32_t*) i1); + uintmax_t b = *((const uint32_t*) i2); + return a > b ? (intmax_t)(a - b) : -(intmax_t)(b - a); +} + +intmax_t ucx_dist_uint64(const void *i1, const void *i2, void *data) { + uintmax_t a = *((const uint64_t*) i1); + uintmax_t b = *((const uint64_t*) i2); + return a > b ? (intmax_t)(a - b) : -(intmax_t)(b - a); +} + int ucx_cmp_float(const void *f1, const void *f2, void *epsilon) { float a = *((const float*) f1); float b = *((const float*) f2); diff -r b1eac0878ce7 -r 18892c0a9adc ui/common/context.h --- a/ui/common/context.h Sat Dec 05 10:34:10 2020 +0100 +++ b/ui/common/context.h Sat Dec 05 11:54:58 2020 +0100 @@ -59,14 +59,19 @@ UiContext *parent; UiObject *obj; UcxMempool *mempool; - UcxMap *bound; // key: char* value: UiVar* - UcxMap *vars; // key: char* value: UiVar* - void *document; + + UcxMap *bound; // key: char* value: UiVar* deprecated + UcxMap *vars; // key: char* value: UiVar* deprecated + void *document; // deprecated + + UcxMap *vars2; // manually created context vars + UcxMap *vars_unbound; // unbound vars created by widgets + UcxList *groups; // int list UcxList *group_widgets; // UiGroupWidget* list - void (*set_document)(UiContext *ctx, void *document); - void (*detach_document)(UiContext *ctx); + void (*set_document)(UiContext *ctx, void *document); // deprecated + void (*detach_document)(UiContext *ctx); // deprecated char *title; @@ -78,6 +83,7 @@ void *close_data; }; +// deprecated struct UiVar { void *value; void *orig_val; @@ -85,6 +91,13 @@ UiVar *from; }; +// UiVar replacement, rename it to UiVar when finished +struct UiVar2 { + void *value; + UiVarType type; + UiContext *bound_from; /* bound by this context or NULL if unbound */ +}; + struct UiGroupWidget { UIWIDGET widget; int *groups; @@ -94,8 +107,8 @@ UiContext* uic_context(UiObject *toplevel, UcxMempool *mp); UiContext* uic_root_context(UiContext *ctx); -void uic_context_set_document(UiContext *ctx, void *document); -void uic_context_detach_document(UiContext *ctx); +void uic_context_set_document(UiContext *ctx, void *document); // deprecated +void uic_context_detach_document(UiContext *ctx); // deprecated //UiVar* uic_get_var(UiContext *ctx, char *name); UiVar* uic_create_var(UiContext *ctx, char *name, UiVarType type);