← index
set/set.c
Source: C2x.Examples/src/set/set.c
#include "set.h"
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

SetNode *set_node_create(const void *data, size_t bytes) {
    SetNode *s = malloc(sizeof(SetNode));
    if (s == nullptr)
        return nullptr;
    s->data = malloc(bytes);
    if (s->data == nullptr) {
        free(s);
        return nullptr;
    }
    memcpy(s->data, data, bytes);
    s->bytes = bytes;
    s->next = nullptr;
    s->count = 1;
    return s;
}

bool set_init(Set **set_value, void (*destroy)(void *), int (*compare)(const void *, const void *)) {
    if (set_value == nullptr || compare == nullptr)
        return false;
    Set *s = malloc(sizeof(*s));
    if (s == nullptr)
        return false;
    s->count = 0;
    s->top = nullptr;
    s->destroy = destroy;
    s->compare = compare;
    *set_value = s;
    return true;
}

bool set_contains(const Set *set, const void *data) {
    if (set == nullptr || data == nullptr)
        return false;
    const SetNode *n = set->top;
    while (n != nullptr) {
        if (set->compare(n->data, data) == 0)
            return true;
        n = n->next;
    }
    return false;
}

bool _set_insert_no_check(Set *set, const void *data, size_t bytes) {
    if (set == nullptr || data == nullptr || bytes == 0)
        return false;
    SetNode *n = set_node_create(data, bytes);
    if (n == nullptr)
        return false;
    n->next = set->top;
    set->top = n;
    set->count++;
    return true;
}

bool _multiset_insert_no_check(Set *set, const void *data, size_t bytes, size_t count) {
    if (set == nullptr || data == nullptr || bytes == 0)
        return false;
    SetNode *n = set_node_create(data, bytes);
    if (n == nullptr)
        return false;
    n->count = count;
    n->next = set->top;
    set->top = n;
    set->count++;
    return true;
}

bool set_insert(Set *set, const void *data, size_t bytes) {
    if (set == nullptr || data == nullptr || bytes == 0)
        return false;
    if (set_contains(set, data))
        return true;
    SetNode *n = set_node_create(data, bytes);
    if (n == nullptr)
        return false;
    n->next = set->top;
    set->top = n;
    set->count++;
    return true;
}

bool multiset_insert(Set *set, const void *data, size_t bytes) {
    if (set == nullptr || data == nullptr || bytes == 0)
        return false;
    SetNode *n = set->top;
    while (n != nullptr) {
        if (set->compare(n->data, data) == 0) {
            ++n->count;
            return true;
        }
        n = n->next;
    }
    SetNode *node = set_node_create(data, bytes);
    if (node == nullptr)
        return false;

    node->next = set->top;
    set->top = node;
    set->count++;
    return true;
}

bool _multiset_insert(Set *set, const void *data, size_t bytes, size_t count) {
    if (set == nullptr || data == nullptr || bytes == 0)
        return false;
    SetNode *n = set->top;
    while (n != nullptr) {
        if (set->compare(n->data, data) == 0) {
            n->count += count;
            return true;
        }
        n = n->next;
    }
    SetNode *node = set_node_create(data, bytes);
    if (node == nullptr)
        return false;

    node->count = count;
    node->next = set->top;
    set->top = node;
    set->count++;
    return true;
}

size_t multiset_count(const Set *set, const void *data) {
    if (set == nullptr || data == nullptr)
        return 0;
    const SetNode *n = set->top;
    while (n != nullptr) {
        if (set->compare(n->data, data) == 0) {
            return n->count;
        }
        n = n->next;
    }
    return 0;
}

void multiset_print(const Set *set, void (*echo)(const void *, size_t)) {
    if (set == nullptr || echo == nullptr)
        return;
    const SetNode *n = set->top;
    while (n != nullptr) {
        echo(n->data, n->count);
        n = n->next;
    }
}

bool set_concat(Set *set, const Set *set_from) {
    if (set == nullptr || set_from == nullptr)
        return false;

    if (set_from->count == 0)
        return true;
    const SetNode *n = set_from->top;
    while (n != nullptr) {
        if (!set_insert(set, n->data, n->bytes)) {
            return false;
        }
        n = n->next;
    }
    return true;
}

bool multiset_concat(Set *set, const Set *set_from) {
    if (set == nullptr || set_from == nullptr)
        return false;
    if (set_from->count == 0)
        return true;
    const SetNode *n = set_from->top;
    while (n != nullptr) {
        if (!_multiset_insert(set, n->data, n->bytes, n->count)) {
            return false;
        }
        n = n->next;
    }
    return true;
}

bool set_remove(Set *set, const void *data) {
    if (set == nullptr || data == nullptr || set->count == 0)
        return false;
    SetNode *n = set->top;
    SetNode *prev = nullptr;
    while (n != nullptr) {
        if (set->compare(n->data, data) == 0) {
            if (prev == nullptr)
                set->top = n->next;
            else
                prev->next = n->next;
            if (set->destroy != nullptr) {
                set->destroy(n->data);
            } else {
                free(n->data);
            }
            free(n);
            set->count--;
            return true;
        }
        prev = n;
        n = n->next;
    }
    return false;
}

bool set_union(Set **setu, const Set *set1, const Set *set2, void (*destroy)(void *), int (*compare)(const void *, const void *)) {
    if (setu == nullptr || set1 == nullptr || set2 == nullptr || compare == nullptr)
        return false;

    if (!set_init(setu, destroy, compare))
        return false;
    const SetNode *n = set1->top;
    while (n != nullptr) {
        if (!_set_insert_no_check(*setu, n->data, n->bytes)) {
            fprintf(stderr, "set insert failed.\n");
            set_free(*setu);
            return false;
        }
        n = n->next;
    }
    n = set2->top;
    while (n != nullptr) {
        if (!set_insert(*setu, n->data, n->bytes)) {
            fprintf(stderr, "set insert failed.\n");
            set_free(*setu);
            return false;
        }
        n = n->next;
    }
    return true;
}

bool set_intersection(Set **setu, const Set *set1, const Set *set2, void (*destroy)(void *), int (*compare)(const void *, const void *)) {
    if (setu == nullptr || set1 == nullptr || set2 == nullptr || compare == nullptr)
        return false;

    if (!set_init(setu, destroy, compare)) {
        return false;
    }

    if (set2->count == 0)
        return true;

    const SetNode *n = set1->top;
    while (n != nullptr) {
        if (set_contains(set2, n->data)) {
            if (!_set_insert_no_check(*setu, n->data, n->bytes)) {
                fprintf(stderr, "Error on insertion..\n");
                set_free(*setu);
                return false;
            }
        }
        n = n->next;
    }
    return true;
}

bool set_difference(Set **setu, const Set *set1, const Set *set2, void (*destroy)(void *), int (*compare)(const void *, const void *)) {
    if (setu == nullptr || set1 == nullptr || set2 == nullptr || compare == nullptr)
        return false;

    if (!set_init(setu, destroy, compare)) {
        fprintf(stderr, "Error on init of set\n");
        return false;
    }
    const SetNode *n = set1->top;
    while (n != nullptr) {
        if (!set_contains(set2, n->data)) {
            if (!_set_insert_no_check(*setu, n->data, n->bytes)) {
                fprintf(stderr, "Error on insertion.\n");
                set_free(*setu);
                return false;
            }
        }
        n = n->next;
    }
    return true;
}

bool set_is_subset(const Set *set1, const Set *set2) {

    if (set1 == nullptr || set2 == nullptr)
        return false;

    if (set1->count == 0)
        return true;

    if (set1->count > set2->count)
        return false;

    const SetNode *n = set1->top;

    while (n != nullptr) {
        if (!set_contains(set2, n->data))
            return false;

        n = n->next;
    }
    return true;
}

bool set_is_equal(const Set *set1, const Set *set2) {

    if (set1 == nullptr || set2 == nullptr)
        return false;

    if (set1->count == 0 && set2->count == 0)
        return true;

    if (set1->top == nullptr || set2->top == nullptr)
        return false;

    if (set1->count != set2->count)
        return false;

    if (set_is_subset(set1, set2))
        return true;

    return false;
}

void set_print(const Set *set, void (*echo)(const void *ptr)) {
    if (set == nullptr || echo == nullptr)
        return;

    const SetNode *n = set->top;
    while (n != nullptr) {
        if (n->data != nullptr)
            echo(n->data);
        n = n->next;
    }
}

void set_free(Set *set) {
    if (set == nullptr)
        return;
    SetNode *sn = set->top;
    while (sn != nullptr) {
        SetNode *temp = sn->next;
        if (set->destroy != nullptr)
            set->destroy(sn->data);
        else
            free(sn->data);
        free(sn);
        sn = temp;
    }
    free(set);
}

size_t set_count(const Set *set) {
    if (set == nullptr)
        return 0;
    return set->count;
}