module patch.utils;

import core.stdc.stdlib : realloc;
import core.stdc.string : memcpy;
import patches;

// Dynamic memory-chunk, with (1) datatype size, (2/3) initialized / allocated chunk, (4) content
struct DynamicArray {
    ubyte elSize;
    uint initialized;  // renamed from 'init' to avoid conflict with D's .init property
    uint alloc;
    char* content;
}

// UTF8_ARRAY macro equivalent  
DynamicArray createUTF8Array() {
    return DynamicArray(4, 0, 0, null);
}

// Helper function for max
T max(T)(T a, T b) {
    return a > b ? a : b;
}

// Function implementations
int p_alloc(DynamicArray* s, uint amount) {
    uint target = s.initialized + cast(uint)s.elSize * amount;
    if (s.alloc < target) {
        uint diff = target - s.alloc;
        uint nas = s.alloc + max(diff, 15U) * s.elSize;
        char* tmp = cast(char*)realloc(s.content, nas);
        if (!tmp) return 0;
        s.alloc = nas;
        s.content = tmp;
    }
    return 1;
}

char* view(DynamicArray* s, uint i) {
    return s.content + i * s.elSize;
}

char* end(DynamicArray* s, uint i) {
    return s.content + s.initialized - (i + 1) * s.elSize;
}

uint getU32(DynamicArray* s, uint i, int b) {
    return *cast(uint*)(b ? view(s, i) : end(s, i));
}

char* expand(DynamicArray* s) {
    if (!p_alloc(s, 1)) return null;
    s.initialized += s.elSize;
    return end(s, 0);
}

void pop(DynamicArray* s) {
    if (s.initialized >= s.elSize) {
        s.initialized -= s.elSize;
    }
}

void empty(DynamicArray* s) {
    s.initialized = 0;
}

int size(const(DynamicArray)* s) {
    return cast(int)(s.initialized / s.elSize);
}

void assign(DynamicArray* s, const(DynamicArray)* o) {
    if (p_alloc(s, size(o))) {
        memcpy(s.content, o.content, cast(size_t)o.initialized);
        s.initialized = o.initialized;
    }
}