Memory allocation functions (untested)

This commit is contained in:
bumbread 2022-06-03 20:31:16 +11:00
parent 4b8d8692e5
commit 04555ac1db
9 changed files with 314 additions and 27 deletions

View File

@ -1,9 +1,15 @@
@echo off
setlocal enabledelayedexpansion
set PLATFORM=win32
set CIABATTA_OPTIONS=-Iinc -g -gcodeview -nodefaultlibs -D_CRT_SECURE_NO_WARNINGS
for /R %%F in (*.c) do (
for /R code %%F in (*.c) do (
echo %%F
clang -c -o build\%%~nF.obj %%F %CIABATTA_OPTIONS%
)
for /R platform\%PLATFORM% %%F in (*.c) do (
echo %%F
clang -c -o build\%%~nF.obj %%F %CIABATTA_OPTIONS%
)
llvm-ar rc ciabatta.lib build\*.obj

160
code/stdlib/conv.c Normal file
View File

@ -0,0 +1,160 @@
#include <stdlib.h>
#include <ctype.h>
#include <stdbool.h>
#include <limits.h>
#include <errno.h>
// TODO: strto*: locale-based parsing for integers
// TODO: i made a function that parses longs and i'm fucken
// tired. someone make float parsing :kekw:
#define inrange(start, c, end) ((start) <= (c) && (c) <= (end))
static bool isbase(int c, int base) {
int val;
if(isdigit(c)) {
val = c-'0';
}
else if(islower(c)) {
val = c-'a'+10;
}
else if(isupper(c)) {
val = c-'A'+10;
}
else {
return false;
}
return val < base;
}
// Called only when isbase(c, base) for some base in range
static long todigitl(int c) {
int val;
if(isdigit(c)) {
val = c-'0';
}
else if(islower(c)) {
val = c-'a'+10;
}
else if(isupper(c)) {
val = c-'A'+10;
}
return val;
}
long
strtol(const char *restrict nptr, char **restrict endptr, int inbase) {
if(!inrange(0, inbase, 36)) {
*endptr = NULL;
return 0;
}
// Skip space on the beginning
while(isspace(*nptr)) {
++nptr;
}
// Parse sign
long coef = 1;
if(*nptr == '-') {
coef = -1;
++nptr;
}
if(*nptr == '+') {
++nptr;
}
unsigned long base = (unsigned long)inbase;
unsigned long value = 0;
// See if we need to parse base in C-like format
if(*nptr == '0' && *(nptr+1) == 'x') {
++nptr;
if(base == 16 || base == 0) {
++nptr;
base = 16;
}
else {
value = 0;
goto end;
}
}
else if(*nptr == '0') {
++nptr;
if(base == 8 || base == 0) {
base = 8;
}
}
while(isbase(*nptr, (int)base)) {
unsigned long digit = (unsigned long)todigitl(*nptr);
if(value > (ULONG_MAX - digit)/base) {
errno = ERANGE;
value = 0;
goto end;
}
value = base*value + digit;
++nptr;
}
unsigned long max_modulo = (unsigned long)LONG_MAX+1;
if(value > max_modulo) {
errno = ERANGE;
value = 0;
goto end;
}
if(value == max_modulo) {
if(coef == 1) {
errno = ERANGE;
value = 0;
goto end;
}
else {
value = LONG_MIN;
coef = 1;
}
}
end:
if(endptr != NULL) {
*endptr = (char *)nptr;
}
return coef*(long)value;
}
long long
strtoll(const char *restrict nptr, char **restrict endptr, int base) {
return 0;
}
unsigned long
strtoul(const char *restrict nptr, char **restrict endptr, int base) {
return 0;
}
unsigned long long
strtoull(const char *restrict nptr, char **restrict endptr, int base) {
return 0;
}
double atof(const char *nptr) {
return strtod(nptr, (char **)NULL);
}
int atoi(const char *nptr) {
return (int)strtol(nptr, (char **)NULL, 10);
}
long int atol(const char *nptr) {
return strtol(nptr, (char **)NULL, 10);
}
long long int atoll(const char *nptr) {
return strtoll(nptr, (char **)NULL, 10);
}
double strtod(const char *restrict nptr, char **restrict endptr) {
return 0;
}
float strtof(const char *restrict nptr, char **restrict endptr) {
return 0;
}
long double strtold(const char *restrict nptr, char **restrict endptr) {
return 0;
}

18
code/stdlib/rand.c Normal file
View File

@ -0,0 +1,18 @@
#include <stddef.h>
#include <stdlib.h>
// TODO: the code for rand/srand was shamelessly copied
// from C11 standard's example and is a simple LCG.
// gotta implement a better random function, or no idc
static int last_random_number;
int rand(void) {
last_random_number = last_random_number * 1103515245 + 12345;
return (unsigned int)(last_random_number/65536) % RAND_MAX;
}
void srand(unsigned int seed) {
last_random_number = seed;
}

View File

@ -51,3 +51,4 @@
typedef int errno_t;
typedef size_t rsize_t;
#endif

View File

@ -4,5 +4,5 @@
#define EILSEQ 2
#define ERANGE 3
// TODO:
//_Thread_local int errno;
// TODO: make it thread-local
int errno;

View File

@ -1,4 +1,9 @@
#include "_platform.h"
#pragma once
#if !defined(NULL)
#define NULL ((void *)0)
#endif
// typedef struct div_t {
// int quot;
@ -18,27 +23,31 @@
// #define EXIT_FAILURE 1
// #define EXIT_SUCCESS 0
// #define RAND_MAX 65536
#define RAND_MAX 65536
// #define MB_CUR_MAX 5
// double atof(const char *nptr);
// int atoi(const char *nptr);
// long int atol(const char *nptr);
// long long int atoll(const char *nptr);
// double strtod(const char * restrict nptr, char ** restrict endptr);
// float strtof(const char * restrict nptr, char ** restrict endptr);
// long double strtold(const char * restrict nptr, char ** restrict endptr);
// long int strtol(const char * restrict nptr, char ** restrict endptr, int base);
// long long int strtoll(const char * restrict nptr, char ** restrict endptr, int base);
// unsigned long int strtoul(const char * restrict nptr, char ** restrict endptr, int base);
// unsigned long long int strtoull(const char * restrict nptr, char ** restrict endptr, int base);
// int rand(void);
// void srand(unsigned int seed);
// void *aligned_alloc(size_t alignment, size_t size);
// void *calloc(size_t nmemb, size_t size);
// void free(void *ptr);
// void *malloc(size_t size);
// void *realloc(void *ptr, size_t size);
double atof(const char *nptr);
int atoi(const char *nptr);
long int atol(const char *nptr);
long long int atoll(const char *nptr);
double strtod(const char * restrict nptr, char ** restrict endptr);
float strtof(const char * restrict nptr, char ** restrict endptr);
long double strtold(const char * restrict nptr, char ** restrict endptr);
long int strtol(const char *restrict nptr, char **restrict endptr, int base);
long long int strtoll(const char *restrict nptr, char **restrict endptr, int base);
unsigned long int strtoul(const char *restrict nptr, char **restrict endptr, int base);
unsigned long long int strtoull(const char *restrict nptr, char **restrict endptr, int base);
int rand(void);
void srand(unsigned int seed);
typedef struct _os_heap _os_heap;
void _heap_setup(_os_heap *heap);
void *aligned_alloc(size_t alignment, size_t size);
void *calloc(size_t nmemb, size_t size);
void free(void *ptr);
void *malloc(size_t size);
void *realloc(void *ptr, size_t size);
// _Noreturn void abort(void);
// int atexit(void (*func)(void));
// int at_quick_exit(void (*func)(void));

View File

@ -1,9 +1,9 @@
#include <_platform.h>
#include <locale.h>
#include <stdbool.h>
#include <stdlib.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "win32.h"
extern int main(int argc, char** argv);
@ -58,8 +58,18 @@ void mainCRTStartup() {
convert_wide_chars_to_ansi(args[i], args_wide[i], wide_len);
}
_os_heap heap_data = {
.handle = heap,
};
_heap_setup(&heap_data);
srand(0);
setlocale(LC_ALL, "C");
int exit_code = main(arg_count, args);
ExitProcess(exit_code);
}
// This symbol is required to be present if we're using floating-point
// numbers
int _fltused=0;

74
platform/win32/memory.c Normal file
View File

@ -0,0 +1,74 @@
#include <stdlib.h>
#include <limits.h>
#include <stdbool.h>
#include "win32.h"
// TODO: lock the heap before allocation (?)
HANDLE _heap;
static bool is_power_of_two(size_t s) {
return (s & (s-1)) == 0;
}
static intptr_t align_forward(intptr_t p, size_t a) {
return (p+a-1)&~(a-1);
}
void _heap_setup(_os_heap *heap) {
_heap = heap->handle;
}
void *aligned_alloc(size_t alignment, size_t size) {
if(size == 0) {
return NULL;
}
if(alignment == 0) {
alignment = 8;
}
if(!is_power_of_two(alignment)) {
return NULL;
}
// HeapAlloc is guaranteed to return 8-byte aligned pointer,
// so if our alignment is 8 or less we don't have to overallocate.
// otherwise we'll reserve extra `alignment` bytes to later adjust our
// memory buffer according to required alignment.
size_t min_req_size = size;
if(alignment > 8) {
min_req_size += alignment;
}
void *block_start = HeapAlloc(_heap, HEAP_ZERO_MEMORY, size+alignment);
intptr_t block_start_i = (intptr_t)block_start;
intptr_t aligned_block_start_i = align_forward(block_start_i, alignment);
void *aligned_block_start = (void *)aligned_block_start_i;
return aligned_block_start;
}
void *calloc(size_t nmemb, size_t size) {
if(nmemb == 0 || size == 0) {
return NULL;
}
if(nmemb > SIZE_MAX/size) {
return NULL;
}
void *block_start = HeapAlloc(_heap, HEAP_ZERO_MEMORY, size*nmemb);
return block_start;
}
void free(void *ptr) {
if(ptr == NULL) {
return;
}
HeapFree(_heap, 0, ptr);
}
void *malloc(size_t size) {
return aligned_alloc(8, size);
}
void *realloc(void *ptr, size_t size) {
void *buffer = HeapReAlloc(_heap, 0, ptr, size);
return buffer;
}

9
platform/win32/win32.h Normal file
View File

@ -0,0 +1,9 @@
#pragma once
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
struct _os_heap {
HANDLE handle;
};