/* This software is licensed by the MIT License, see LICENSE file */
/*                                Copyright © 2022 Gregory Lirent */

#include <stdlib.h>
#include "../include/extra/cstring.h"
#include "__internal/include.h"
#undef aligned_alloc
#undef malloc
#undef realloc
#undef calloc

/*#####################################################################################################################*/

void* libcdsb_aalloc(size_t a, size_t n) {
    void* x;

    if ((x = aligned_alloc(a, n)))
        return x;
    abort();
}


void* libcdsb_calloc(size_t n, size_t c) {
    void* x;

    if ((x = calloc(n, c)))
        return x;
    abort();
}


void* libcdsb_malloc(size_t n) {
    void* x;

    if ((x = malloc(n)))
        return x;
    abort();
}


void* libcdsb_realloc(void* x, size_t n) {
    if ((x = realloc(x, n)))
        return x;
    abort();
}


/*#####################################################################################################################*/


void* libcdsb_memndup(const void* m, size_t n) {
    void* x;

    if ((x = malloc(n)))
        return memcpy(x, m, n);
    abort();
}


char* libcdsb_strdup(const char* s) {
    void*  x;
    size_t n;

    if ((x = malloc(n = strlen(s) + 1)))
        return memcpy(x, s, n);
    abort();
}


char* libcdsb_strndup(const char* s, size_t n) {
    void* x;

    if ((x = malloc(n + 1))) {
        ((char*)memcpy(x, s, n))[n] = 0;
        return x;
    }
    abort();
}


/*#####################################################################################################################*/


void libcdsb_stack_init(stack_t* x) {
    memset(x, 0, sizeof(*x));
}


void libcdsb_stack_push(stack_t* x, void* value) {
    stack_t* n;

    if (x->value) {
        if (!(n = malloc(sizeof(*n))))
            abort();

        n->prev  = x->prev;
        n->value = x->value;
        x->prev  = n;
    }

    x->value = value;
}

void* libcdsb_stack_pop(stack_t* x) {

    stack_t* n;
    void*    v;

    v = x->value;

    if (x->prev) {
        n = x->prev;
        x->prev = n->prev;
        x->value = n->value;
        free(n);
    } else x->value = 0;

    return v;
}


void libcdsb_stack_flush(stack_t* stack) {
    stack_t* c;

    while (stack->prev) {
        c = stack->prev;
        stack->prev = c->prev;
        free(c);
    }

    stack->value = 0;
}

/*#####################################################################################################################*/


size_t libcdsb_strlen(const char* s) {
    static const size_t m = (sizeof(size_t) == 8) ? 0x8080808080808080UL : 0x80808080UL;
    static const size_t d = (sizeof(size_t) == 8) ? 0x0101010101010101UL : 0x01010101UL;

    const u8_t* p;
    const size_t* w;

    p = (void*)s;

    while((uintptr_t)p%sizeof(size_t)) {
        if (!*p) return (void*)p - (void*)s;
        ++p;
    }

    w = (void*)p;

    while (!((*w-d)&(~*w&m))) { ++w; }

    p = (void*)w;

    while (*p) { ++p; }

    return (void*)p - (void*)s;
}


size_t libcdsb_strasciilen(const char* s) {
    static const size_t m = (sizeof(size_t) == 8) ? 0x8080808080808080UL : 0x80808080UL;
    static const size_t d = (sizeof(size_t) == 8) ? 0x0101010101010101UL : 0x01010101UL;

    const u8_t* p;
    const size_t* w;

    p = (void*)s;

    while((uintptr_t)p%sizeof(size_t)) {
        if (!*p || (*p&0x80))
            return (void*)p - (void*)s;
        ++p;
    }

    w = (void*)p;

    while (!((*w&m)||((*w-d)&m))) { ++w; }

    p = (void*)w;

    while (*p && !(*p&0x80)) { ++p; }

    return (void*)p - (void*)s;
}