ucx/list.c

Sun, 17 Dec 2023 14:25:34 +0100

author
Mike Becker <universe@uap-core.de>
date
Sun, 17 Dec 2023 14:25:34 +0100
changeset 797
edbb20b1438d
parent 750
4d7a2238c5ac
child 816
839fefbdedc7
permissions
-rw-r--r--

[Makefile] fix missing rules preventing dry-runs

We have to support dry-runs, because many IDEs are using
dry-runs to collect build information.

Some rules have dependencies that expect certain files or
directories to be just present. We added respective build
rules which invoke the test program. This way, the behavior
when running make normally is exactly the same, but dry-runs
are also not failing now.

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 2021 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.
 */

#include "cx/list.h"

#include <string.h>

// <editor-fold desc="Store Pointers Functionality">

static _Thread_local cx_compare_func cx_pl_cmpfunc_impl;

static int cx_pl_cmpfunc(
        void const *l,
        void const *r
) {
    void *const *lptr = l;
    void *const *rptr = r;
    void const *left = lptr == NULL ? NULL : *lptr;
    void const *right = rptr == NULL ? NULL : *rptr;
    return cx_pl_cmpfunc_impl(left, right);
}

static void cx_pl_hack_cmpfunc(struct cx_list_s const *list) {
    // cast away const - this is the hacky thing
    struct cx_list_s *l = (struct cx_list_s *) list;
    cx_pl_cmpfunc_impl = l->cmpfunc;
    l->cmpfunc = cx_pl_cmpfunc;
}

static void cx_pl_unhack_cmpfunc(struct cx_list_s const *list) {
    // cast away const - this is the hacky thing
    struct cx_list_s *l = (struct cx_list_s *) list;
    l->cmpfunc = cx_pl_cmpfunc_impl;
}

static void cx_pl_destructor(struct cx_list_s *list) {
    list->climpl->destructor(list);
}

static int cx_pl_insert_element(
        struct cx_list_s *list,
        size_t index,
        void const *element
) {
    return list->climpl->insert_element(list, index, &element);
}

static size_t cx_pl_insert_array(
        struct cx_list_s *list,
        size_t index,
        void const *array,
        size_t n
) {
    return list->climpl->insert_array(list, index, array, n);
}

static int cx_pl_insert_iter(
        struct cx_mut_iterator_s *iter,
        void const *elem,
        int prepend
) {
    struct cx_list_s *list = iter->src_handle;
    return list->climpl->insert_iter(iter, &elem, prepend);
}

static int cx_pl_remove(
        struct cx_list_s *list,
        size_t index
) {
    return list->climpl->remove(list, index);
}

static void cx_pl_clear(struct cx_list_s *list) {
    list->climpl->clear(list);
}

static int cx_pl_swap(
        struct cx_list_s *list,
        size_t i,
        size_t j
) {
    return list->climpl->swap(list, i, j);
}

static void *cx_pl_at(
        struct cx_list_s const *list,
        size_t index
) {
    void **ptr = list->climpl->at(list, index);
    return ptr == NULL ? NULL : *ptr;
}

static ssize_t cx_pl_find(
        struct cx_list_s const *list,
        void const *elem
) {
    cx_pl_hack_cmpfunc(list);
    ssize_t ret = list->climpl->find(list, &elem);
    cx_pl_unhack_cmpfunc(list);
    return ret;
}

static void cx_pl_sort(struct cx_list_s *list) {
    cx_pl_hack_cmpfunc(list);
    list->climpl->sort(list);
    cx_pl_unhack_cmpfunc(list);
}

static int cx_pl_compare(
        struct cx_list_s const *list,
        struct cx_list_s const *other
) {
    cx_pl_hack_cmpfunc(list);
    int ret = list->climpl->compare(list, other);
    cx_pl_unhack_cmpfunc(list);
    return ret;
}

static void cx_pl_reverse(struct cx_list_s *list) {
    list->climpl->reverse(list);
}

static void *cx_pl_iter_current(void const *it) {
    struct cx_iterator_s const *iter = it;
    void **ptr = iter->base.current_impl(it);
    return ptr == NULL ? NULL : *ptr;
}

static struct cx_iterator_s cx_pl_iterator(
        struct cx_list_s const *list,
        size_t index,
        bool backwards
) {
    struct cx_iterator_s iter = list->climpl->iterator(list, index, backwards);
    iter.base.current_impl = iter.base.current;
    iter.base.current = cx_pl_iter_current;
    return iter;
}

static cx_list_class cx_pointer_list_class = {
        cx_pl_destructor,
        cx_pl_insert_element,
        cx_pl_insert_array,
        cx_pl_insert_iter,
        cx_pl_remove,
        cx_pl_clear,
        cx_pl_swap,
        cx_pl_at,
        cx_pl_find,
        cx_pl_sort,
        cx_pl_compare,
        cx_pl_reverse,
        cx_pl_iterator,
};

void cxListStoreObjects(CxList *list) {
    list->store_pointer = false;
    if (list->climpl != NULL) {
        list->cl = list->climpl;
        list->climpl = NULL;
    }
}

void cxListStorePointers(CxList *list) {
    list->item_size = sizeof(void *);
    list->store_pointer = true;
    list->climpl = list->cl;
    list->cl = &cx_pointer_list_class;
}

// </editor-fold>

// <editor-fold desc="empty list implementation">

static void cx_emptyl_noop(__attribute__((__unused__)) CxList *list) {
    // this is a noop, but MUST be implemented
}

static void *cx_emptyl_at(
        __attribute__((__unused__)) struct cx_list_s const *list,
        __attribute__((__unused__)) size_t index
) {
    return NULL;
}

static ssize_t cx_emptyl_find(
        __attribute__((__unused__)) struct cx_list_s const *list,
        __attribute__((__unused__)) void const *elem
) {
    return -1;
}

static int cx_emptyl_compare(
        __attribute__((__unused__)) struct cx_list_s const *list,
        struct cx_list_s const *other
) {
    if (other->size == 0) return 0;
    return -1;
}

static bool cx_emptyl_iter_valid(__attribute__((__unused__)) void const *iter) {
    return false;
}

static CxIterator cx_emptyl_iterator(
        struct cx_list_s const *list,
        size_t index,
        __attribute__((__unused__)) bool backwards
) {
    CxIterator iter = {0};
    iter.src_handle = list;
    iter.index = index;
    iter.base.valid = cx_emptyl_iter_valid;
    return iter;
}

static cx_list_class cx_empty_list_class = {
        cx_emptyl_noop,
        NULL,
        NULL,
        NULL,
        NULL,
        cx_emptyl_noop,
        NULL,
        cx_emptyl_at,
        cx_emptyl_find,
        cx_emptyl_noop,
        cx_emptyl_compare,
        cx_emptyl_noop,
        cx_emptyl_iterator,
};

CxList cx_empty_list = {
        NULL,
        NULL,
        0,
        0,
        NULL,
        NULL,
        NULL,
        false,
        &cx_empty_list_class,
        NULL
};

CxList *const cxEmptyList = &cx_empty_list;

// </editor-fold>

void cxListDestroy(CxList *list) {
    list->cl->destructor(list);
}

int cxListCompare(
        CxList const *list,
        CxList const *other
) {
    if (
        // if one is storing pointers but the other is not
        (list->store_pointer ^ other->store_pointer) ||

        // if one class is wrapped but the other is not
        ((list->climpl == NULL) ^ (other->climpl == NULL)) ||

        // if the resolved compare functions are not the same
        ((list->climpl != NULL ? list->climpl->compare : list->cl->compare) !=
         (other->climpl != NULL ? other->climpl->compare : other->cl->compare))
    ) {
        // lists are definitely different - cannot use internal compare function
        if (list->size == other->size) {
            CxIterator left = cxListIterator(list);
            CxIterator right = cxListIterator(other);
            for (size_t i = 0; i < list->size; i++) {
                void *leftValue = cxIteratorCurrent(left);
                void *rightValue = cxIteratorCurrent(right);
                int d = list->cmpfunc(leftValue, rightValue);
                if (d != 0) {
                    return d;
                }
                cxIteratorNext(left);
                cxIteratorNext(right);
            }
            return 0;
        } else {
            return list->size < other->size ? -1 : 1;
        }
    } else {
        // lists are compatible
        return list->cl->compare(list, other);
    }
}

CxMutIterator cxListMutIteratorAt(
        CxList *list,
        size_t index
) {
    CxIterator it = list->cl->iterator(list, index, false);
    it.base.mutating = true;

    // we know the iterators share the same memory layout
    CxMutIterator iter;
    memcpy(&iter, &it, sizeof(CxMutIterator));
    return iter;
}

CxMutIterator cxListMutBackwardsIteratorAt(
        CxList *list,
        size_t index
) {
    CxIterator it = list->cl->iterator(list, index, true);
    it.base.mutating = true;

    // we know the iterators share the same memory layout
    CxMutIterator iter;
    memcpy(&iter, &it, sizeof(CxMutIterator));
    return iter;
}

mercurial