#include "array.h"
#include "crash.h"
#include <string.h>
#include <stdlib.h>

#define CRASH_IF_OOB(array, len) {\
    if (len > array.length)\
        crash("Array access out of bounds: %ld > %ld\n", len, array.length);\
}

void* array_at(const array_t array, size_t idx) {
    CRASH_IF_OOB(array, idx);
    return (char*)array.__data + idx*array.elemsz;
}

array_t array_slice(const array_t array, size_t start, size_t length) {
    CRASH_IF_OOB(array, start + length);
    array_t slice = {
        .length = length,
        .__data = (char*)array.__data + start * array.elemsz
    };
    return slice;
}

array_t array_init(void* data, size_t length, size_t elemsz) {
    array_t array = {.length = length, .elemsz = elemsz, .__data = data};
    return array;
}

array_t array_heap_alloc(size_t length, size_t elemsz) {
    void* data_ptr = calloc(length, elemsz);
    if (data_ptr == NULL)
        crash(
            "Out of memory allocating %ld elements of size %ld\n",
            length,
            elemsz);

    array_t container = {
        .length = length,
        .elemsz = elemsz,
        .__data = data_ptr,
    };
    return container;
}

void array_heap_destroy(array_t array) {
    free(array.__data);
}
