#include #include #include "vm/Arrays.h" #define MAX_ALLOCATED_BYTES (1024LL * 1024LL * 1024LL * 4LL) static long long allocatedBytes = 0; void asInit(SnuviArrays* as) { as->capacity = 0; as->usedStart = -1; as->freeStart = -1; as->data = NULL; } void asDelete(SnuviArrays* as) { for(int i = 0; i < as->capacity; i++) { allocatedBytes -= as->data[i].size; free(as->data[i].data); } allocatedBytes -= as->capacity * sizeof(SnuviArray); free(as->data); } static void aInitArray(SnuviArray* a, int previous, int next) { a->size = 0; a->length = -1; a->next = next; a->previous = previous; a->data = NULL; } static void asInitArrays(SnuviArrays* as, int start) { int end = as->capacity - 1; aInitArray(as->data + start, -1, start + 1); for(int i = start + 1; i < end; i++) { aInitArray(as->data + i, i - 1, i + 1); } aInitArray(as->data + end, end - 1, -1); as->freeStart = start; } static bool asEnsureCapacity(SnuviArrays* as) { if(as->freeStart != -1) { return false; } int oldCapacity = as->capacity; int capacity = (as->data == NULL) ? 4 : as->capacity * 2; int oldBytes = sizeof(SnuviArray) * oldCapacity; int bytes = sizeof(SnuviArray) * capacity; if(bytes < 0 || allocatedBytes - oldBytes + bytes > MAX_ALLOCATED_BYTES) { return true; } allocatedBytes += bytes - oldBytes; as->data = realloc(as->data, bytes); as->capacity = capacity; asInitArrays(as, oldCapacity); return false; } static void asPrintDebug(SnuviArrays* as) { printf("Free: %d, Used: %d\n", as->freeStart, as->usedStart); for(int i = 0; i < as->capacity; i++) { SnuviArray* a = as->data + i; printf("%d: %s, size: %d, next: %d, previous: %d\n", i, a->data == NULL ? "null" : "valid", a->size, a->next, a->previous); } } int asAllocate(SnuviArrays* as, int typeSize, int length) { (void)asPrintDebug; if(asEnsureCapacity(as)) { return -1; } int bytes = typeSize * length; if(bytes < 0) { return -2; } else if(allocatedBytes + bytes > MAX_ALLOCATED_BYTES) { return -1; } allocatedBytes += bytes; int index = as->freeStart; SnuviArray* array = as->data + index; as->freeStart = array->next; if(array->next != -1) { as->data[array->next].previous = -1; } array->next = as->usedStart; if(as->usedStart != -1) { as->data[as->usedStart].previous = index; } as->usedStart = index; array->size = bytes; array->length = length; array->data = malloc(bytes); return index; } SnuviArray* asGet(SnuviArrays* as, int p) { if(p < 0 || p >= as->capacity || as->data[p].length == -1) { return NULL; } return as->data + p; } void asDeleteArray(SnuviArrays* as, SnuviArray* a, int p) { if(a->previous != -1) { as->data[a->previous].next = a->next; } else { as->usedStart = a->next; } if(a->next != -1) { as->data[a->next].previous = a->previous; } if(as->freeStart != -1) { a->next = as->freeStart; as->data[as->freeStart].previous = p; } else { a->next = -1; } as->freeStart = p; allocatedBytes -= a->size; a->previous = -1; a->size = 0; a->length = -1; free(a->data); a->data = NULL; }