← index
tree.c
Source: C2x.Examples/src/tree.c
/* Binary Search Tree in C23
 * https://lostsidedead.biz
 *
 */

#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct node {
    char *data;
    size_t bytes;
    struct node *left, *right;
} Node;

typedef int cmp(const char *, const char *);

int compare(const char *a, const char *b) {
    if (a == nullptr && b == nullptr)
        return 0;
    if (a == nullptr)
        return -1;
    if (b == nullptr)
        return 1;
    return strcmp(a, b);
}

[[nodiscard]] Node *createNode(const char *restrict data, const size_t bytes) {
    if (data == nullptr)
        return nullptr;
    if (bytes > SIZE_MAX - sizeof(Node))
        return nullptr;

    Node *n = malloc(sizeof(Node) + bytes);
    if (!n) {
        fprintf(stderr, "Error on allocation\n");
        return nullptr;
    }
    n->left = n->right = nullptr;
    n->data = (char *)n + sizeof(*n);
    memcpy(n->data, data, bytes);
    n->bytes = bytes;
    return n;
}

void freeNodes(Node *n) {
    Node *current = n;
    while (current != nullptr) {
        if (current->left != nullptr) {
            Node *left_ = current->left;
            current->left = left_->right;
            left_->right = current;
            current = left_;
        } else {
            Node *next = current->right;
            free(current);
            current = next;
        }
    }
}

void printNodes(const Node *root) {
    if (root == nullptr)
        return;
    size_t cap_size = 128;
    size_t top = 0;
    const Node **stack = malloc(cap_size * sizeof(const Node *));
    if (!stack) {
        fprintf(stderr, "Error on allocation.\n");
        return;
    }
    const Node *curr = root;
    while (curr != nullptr || top > 0) {
        while (curr != nullptr) {
            if (top >= cap_size) {
                cap_size *= 2;
                const Node **temp = realloc(stack, cap_size * sizeof(const Node *));
                if (!temp) {
                    fprintf(stderr, "Fatal out of memory\n");
                    free(stack);
                    return;
                }
                stack = temp;
            }
            stack[top++] = curr;
            curr = curr->left;
        }
        curr = stack[--top];
        printf("Data: %s\n", curr->data);
        curr = curr->right;
    }
    free(stack);
}

bool insertNode(Node **root, const char *data, size_t bytes, cmp c) {
    Node **current = root;
    while (*current != nullptr) {
        int res = c(data, (*current)->data);
        if (res < 0) {
            current = &(*current)->left;
        } else if (res > 0) {
            current = &(*current)->right;
        } else {
            return true;
        }
    }
    Node *temp = createNode(data, bytes);
    if (temp == nullptr) {
        return false;
    }
    *current = temp;
    return true;
}

[[nodiscard]] Node *findNode(Node *root, const char *data, cmp c) {
    Node *current = root;
    while (current != nullptr) {
        int res = c(data, current->data);
        if (res < 0) {
            current = current->left;
        } else if (res > 0) {
            current = current->right;
        } else {
            return current;
        }
    }
    return nullptr;
}

int main(void) {
    Node *root = nullptr;
    static constexpr unsigned int BUFFER_SIZE = 4096;
    while (true) {
        char buffer[BUFFER_SIZE];
        printf("Enter text (exit to quit): ");
        if (fgets(buffer, BUFFER_SIZE, stdin) == nullptr)
            break;

        buffer[strcspn(buffer, "\n")] = 0;
        if (strcmp(buffer, "exit") == 0)
            break;
        if (!insertNode(&root, buffer, strlen(buffer) + 1, compare)) {
            fprintf(stderr, "Node insertion failed.\n");
            freeNodes(root);
            return EXIT_FAILURE;
        }
    }
    Node *f = findNode(root, "Hello", compare);
    if (f != nullptr) {
        printf("%s World!\n", f->data);
    }
    printNodes(root);
    freeNodes(root);
    return 0;
}