Files
j-lang/src/memory/allocator.h

328 lines
8.8 KiB
C
Raw Normal View History

#ifndef JLANG_ALLOCATOR_H
#define JLANG_ALLOCATOR_H
2026-02-15 20:57:19 +01:00
#include <stdio.h>
2026-02-15 22:12:19 +01:00
#include <stdlib.h>
2026-02-15 20:57:19 +01:00
#include <string.h>
/*
Custom Memory Allocator
2026-02-15 22:12:19 +01:00
Implementacion custom de un memory allocator que opera sobre un array de
bytes usandolo como "heap"
2026-02-15 20:57:19 +01:00
*/
#define JLANG_OK 0
#define JLANG_ERR 1
#define JLANG_FREE 0
#define JLANG_HEADER 1
#define JLANG_PAYLOAD 2
#define JLANG_NOT_USE 3
2026-02-15 20:57:19 +01:00
/*
2026-02-15 22:12:19 +01:00
La estructura de Metadata se encarga de almacenar el tamaño del bloque y si
está en uso. Se añadirá al principio de cada bloque [BLOCK_METADATA] +
[BLOCK_BYTES]
2026-02-15 20:57:19 +01:00
*/
2026-02-15 22:12:19 +01:00
typedef struct {
size_t size; // 8 bytes
int in_use; // 4 bytes
int marked; // 4 bytes
2026-02-15 20:57:19 +01:00
} JLANG_metadata;
/*
2026-02-15 22:12:19 +01:00
La estructura de Memory Allocator se encarga de almancenar el array de
memoria y el tamaño de esta.
2026-02-15 20:57:19 +01:00
*/
2026-02-15 22:12:19 +01:00
typedef struct {
char *memory; // 8 bytes
size_t size; // 8 bytes
2026-02-15 20:57:19 +01:00
} JLANG_memory_allocator;
2026-02-15 22:12:19 +01:00
void *JLANG_CreateAllocator() {
// Allocate memory in heap for JLANG_memory_allocator
JLANG_memory_allocator *allocator =
(JLANG_memory_allocator *)malloc(sizeof(JLANG_memory_allocator));
2026-02-15 20:57:19 +01:00
2026-02-15 22:12:19 +01:00
// Assign default free bytes
allocator->memory = (char *)malloc(1 * 1024);
allocator->size = 1 * 1024;
2026-02-15 20:57:19 +01:00
2026-02-15 22:12:19 +01:00
// ensure all memory is zero
for (int i = 0; i < 1 * 1024; i++) {
allocator->memory[i] = 0;
}
2026-02-15 20:57:19 +01:00
2026-02-15 22:12:19 +01:00
return allocator;
2026-02-15 20:57:19 +01:00
}
2026-02-15 22:12:19 +01:00
size_t JLANG_used(void *ptr) {
JLANG_memory_allocator *allocPtr = (JLANG_memory_allocator *)ptr;
2026-02-15 20:57:19 +01:00
2026-02-15 22:12:19 +01:00
// Iterate memory parsing only metadata
JLANG_metadata *currentHeader = (JLANG_metadata *)allocPtr->memory;
size_t used = 0;
while (currentHeader->size != 0 && used < allocPtr->size) {
2026-02-15 22:12:19 +01:00
used += sizeof(JLANG_metadata) + currentHeader->size;
2026-02-15 20:57:19 +01:00
2026-02-15 22:12:19 +01:00
// Current block is in_use, jump to next block
currentHeader =
(JLANG_metadata *)((char *)currentHeader + sizeof(JLANG_metadata) +
currentHeader->size);
}
2026-02-15 20:57:19 +01:00
2026-02-15 22:12:19 +01:00
return used;
2026-02-15 20:57:19 +01:00
}
2026-02-15 22:12:19 +01:00
void *JLANG_last_free(void *ptr) {
JLANG_memory_allocator *allocPtr = (JLANG_memory_allocator *)ptr;
2026-02-15 20:57:19 +01:00
2026-02-15 22:12:19 +01:00
// Iterate memory parsing only metadata
JLANG_metadata *currentHeader = (JLANG_metadata *)allocPtr->memory;
size_t used = 0;
while (currentHeader->size != 0 && used < allocPtr->size) {
2026-02-15 22:12:19 +01:00
used += sizeof(JLANG_metadata) + currentHeader->size;
2026-02-15 20:57:19 +01:00
2026-02-15 22:12:19 +01:00
// Current block is in_use, jump to next block
currentHeader =
(JLANG_metadata *)((char *)currentHeader + sizeof(JLANG_metadata) +
currentHeader->size);
}
2026-02-15 20:57:19 +01:00
2026-02-15 22:12:19 +01:00
return currentHeader;
2026-02-15 20:57:19 +01:00
}
// JLANG_malloc devuelve un offset a la memoria del heap. No un absoluto a la
// memoria del proceso
size_t JLANG_malloc(void *ptr, size_t size) {
2026-02-15 22:12:19 +01:00
JLANG_memory_allocator *allocPtr = (JLANG_memory_allocator *)ptr;
2026-02-15 20:57:19 +01:00
// Recorrer memoria hasta encontrar un hueco libre
JLANG_metadata *currentHead = (JLANG_metadata *)allocPtr->memory;
size_t used = 0;
while (1) {
used += currentHead->size;
2026-02-15 20:57:19 +01:00
if (currentHead->in_use == 0 && currentHead->size >= size) {
break;
}
2026-02-15 20:57:19 +01:00
if (currentHead->size == 0) {
size_t offset = (char *)currentHead - allocPtr->memory;
if (offset + sizeof(JLANG_metadata) + size > allocPtr->size) {
// No cabe, grow
size_t newSize = allocPtr->size * 2;
// asegurar que quepa la peticion
while (newSize < offset + sizeof(JLANG_metadata) + size) {
newSize *= 2;
}
char *newBuffer = (char *)malloc(newSize); // pedir newSize bytes
if (newBuffer == NULL) {
printf("ERROR: out of memory\n");
exit(1);
}
memset(newBuffer, 0, newSize);
memcpy(newBuffer, allocPtr->memory,
allocPtr->size); // Copiamos al nuevo buffer
allocPtr->size = newSize;
free(allocPtr->memory); // Liberamos el buffer antiguo
allocPtr->memory = newBuffer; // Seteamos el nuevo buffer
JLANG_metadata *freeHeader =
(JLANG_metadata *)(allocPtr->memory + offset);
freeHeader->size = size;
freeHeader->in_use = 1;
void *payloadPtr = (char *)freeHeader + sizeof(JLANG_metadata);
return (char *)payloadPtr - allocPtr->memory;
}
// Fin del heap, asignar aqui
currentHead->size = size;
currentHead->in_use = 1;
return (char *)currentHead - allocPtr->memory + sizeof(JLANG_metadata);
}
// Go next
currentHead =
(JLANG_metadata *)((char *)currentHead + sizeof(JLANG_metadata) +
currentHead->size);
2026-02-15 22:12:19 +01:00
}
2026-02-15 20:57:19 +01:00
// currentHead tiene sitio para nosotros, particionamos y usamos
currentHead->in_use = 1;
size_t oldSize = currentHead->size;
currentHead->size = size;
if (oldSize > size + sizeof(JLANG_metadata)) {
// creamos un bloque vacio con los bytes que sobran
JLANG_metadata *emptyBlock =
(JLANG_metadata *)((char *)currentHead + sizeof(JLANG_metadata) + size);
emptyBlock->size = oldSize - size - sizeof(JLANG_metadata);
}
return (char *)currentHead - allocPtr->memory + sizeof(JLANG_metadata);
/*
// 1. Hay bloques disponibles??
size_t used = JLANG_used(ptr);
size_t available = allocPtr->size - used;
// chequear si hay suficiente espacio libre
if (available > size + sizeof(JLANG_metadata)) {
JLANG_metadata *freeHeader = (JLANG_metadata *)JLANG_last_free(ptr);
freeHeader->size = size;
freeHeader->in_use = 1;
void *payloadPtr = (char *)freeHeader + sizeof(JLANG_metadata);
return (char *)payloadPtr - allocPtr->memory;
}
// Se necesita más espacio..
int newSize = allocPtr->size + 1024;
char *newBuffer = (char *)malloc(newSize); // Otro 1KB
memset(newBuffer, 0, newSize);
memcpy(newBuffer, allocPtr->memory,
allocPtr->size); // Copiamos al nuevo buffer
allocPtr->size = newSize;
free(allocPtr->memory); // Liberamos el buffer antiguo
allocPtr->memory = newBuffer; // Seteamos el nuevo buffer
JLANG_metadata *freeHeader = (JLANG_metadata *)JLANG_last_free(ptr);
freeHeader->size = size;
freeHeader->in_use = 1;
void *payloadPtr = (char *)freeHeader + sizeof(JLANG_metadata);
return (char *)payloadPtr - allocPtr->memory;
*/
2026-02-15 22:12:19 +01:00
}
void JLANG_free(void *ptr, size_t blockOffset) {
2026-02-15 22:12:19 +01:00
JLANG_memory_allocator *allocPtr = (JLANG_memory_allocator *)ptr;
// Get block header
void *blockPtr = allocPtr->memory + blockOffset;
2026-02-15 22:12:19 +01:00
JLANG_metadata *blockHeader =
(JLANG_metadata *)((char *)blockPtr - sizeof(JLANG_metadata));
// Set block as not_used
blockHeader->in_use = 0;
// Set to 0 payload
memset(blockPtr, 0, blockHeader->size);
2026-02-15 20:57:19 +01:00
}
/*
Debug Visualization
[FF FF FF FF FF FF FF ]
*/
2026-02-15 22:12:19 +01:00
int _ceil(float v) {
int n = (int)v;
float r = v - n;
2026-02-15 20:57:19 +01:00
2026-02-15 22:12:19 +01:00
if (r > 0) {
return n + 1;
}
return n;
2026-02-15 20:57:19 +01:00
}
2026-02-15 22:12:19 +01:00
void JLANG_visualize(void *ptr) {
JLANG_memory_allocator *allocPtr = (JLANG_memory_allocator *)ptr;
// Step 1. Get byte type
char *byteMapPtr = (char *)malloc(allocPtr->size);
memset(byteMapPtr, 0, allocPtr->size);
JLANG_metadata *currentHeader = (JLANG_metadata *)allocPtr->memory;
long used = 0;
while (used < allocPtr->size) {
long blockIndex = (char *)currentHeader - (char *)allocPtr->memory;
used += sizeof(JLANG_metadata) + currentHeader->size;
/*
HEADER
blockIndex + sizeof(JLANG_metadata)
*/
if (currentHeader->size > 0) {
if (currentHeader->in_use == 1) {
byteMapPtr[blockIndex] = JLANG_HEADER;
for (int i = 0; i < sizeof(JLANG_metadata); i++) {
byteMapPtr[blockIndex + i] = JLANG_HEADER;
}
/*
PAYLOAD
*/
for (int i = 0; i < currentHeader->size; i++) {
byteMapPtr[blockIndex + sizeof(JLANG_metadata) + i] = JLANG_PAYLOAD;
}
} else {
// Mark all block as JLANG_NOT_USE
memset(byteMapPtr + blockIndex, JLANG_NOT_USE,
sizeof(JLANG_metadata) + currentHeader->size);
2026-02-15 22:12:19 +01:00
}
} else {
break;
2026-02-15 20:57:19 +01:00
}
2026-02-15 22:12:19 +01:00
// Jump to next block
currentHeader =
(JLANG_metadata *)((char *)currentHeader + sizeof(JLANG_metadata) +
currentHeader->size);
}
2026-02-15 20:57:19 +01:00
2026-02-15 22:12:19 +01:00
// Step 2. Draw
2026-02-15 20:57:19 +01:00
2026-02-15 22:12:19 +01:00
int bytePerRow = 40;
int totalRows = _ceil(allocPtr->size / bytePerRow);
2026-02-15 20:57:19 +01:00
2026-02-15 22:12:19 +01:00
char *currentMemPtr = allocPtr->memory;
2026-02-15 20:57:19 +01:00
2026-02-15 22:12:19 +01:00
for (int i = 0; i < totalRows; i++) {
printf("[");
for (int n = 0; n < bytePerRow; n++) {
2026-02-15 20:57:19 +01:00
2026-02-15 22:12:19 +01:00
int index = n + i * bytePerRow;
2026-02-15 20:57:19 +01:00
2026-02-15 22:12:19 +01:00
switch (byteMapPtr[index]) {
case JLANG_HEADER:
printf("\033[46m");
break;
case JLANG_FREE:
printf("\033[32m");
break;
case JLANG_NOT_USE:
printf("\033[47;5;224m");
break;
2026-02-15 22:12:19 +01:00
default:
printf("\033[41m");
break;
}
2026-02-15 20:57:19 +01:00
2026-02-15 22:12:19 +01:00
printf("%.2x", (unsigned char)*(currentMemPtr + (n + i * bytePerRow)));
2026-02-15 20:57:19 +01:00
/*
if (n < bytePerRow - 1) {
printf(" ");
}
*/
2026-02-15 20:57:19 +01:00
2026-02-15 22:12:19 +01:00
printf("\033[0m");
2026-02-15 20:57:19 +01:00
}
2026-02-15 22:12:19 +01:00
printf("]\n");
}
2026-02-15 20:57:19 +01:00
}
#endif