mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 06:44:07 +10:00
Implemented bucket memory structure for custom allocators
This commit is contained in:
@@ -13,7 +13,7 @@ Notes:
|
||||
|
||||
unlike version 1, identifiers are not a valid datatype - they're just an index representing a symbol, like "standard::clock"
|
||||
|
||||
placeholder opcodes - EOF, PASS, ERROR,
|
||||
meta opcodes - EOF, PASS, ERROR,
|
||||
|
||||
a "value" can be of any valid datatype, and may point to various parts of memory to define it's value
|
||||
|
||||
|
||||
2
makefile
2
makefile
@@ -17,7 +17,7 @@ all: clean tests
|
||||
|
||||
.PHONY: tests
|
||||
tests:
|
||||
$(MAKE) -C tests
|
||||
$(MAKE) -C tests -k
|
||||
|
||||
#util targets
|
||||
$(TOY_OUTDIR):
|
||||
|
||||
2
source/toy_ast.c
Normal file
2
source/toy_ast.c
Normal file
@@ -0,0 +1,2 @@
|
||||
#include "toy_ast.h"
|
||||
|
||||
9
source/toy_ast.h
Normal file
9
source/toy_ast.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "toy_common.h"
|
||||
|
||||
typedef enum Toy_AstType {
|
||||
TOY_AST_PASS,
|
||||
TOY_AST_ERROR,
|
||||
} Toy_AstType;
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
#include "toy_chunk.h"
|
||||
|
||||
#include "toy_memory.h"
|
||||
|
||||
void Toy_initChunk(Toy_Chunk* chunk) {
|
||||
chunk->count = 0;
|
||||
chunk->capacity = 0;
|
||||
chunk->code = NULL;
|
||||
}
|
||||
|
||||
void Toy_pushChunk(Toy_Chunk* chunk, uint8_t byte) {
|
||||
if (chunk->count +1 > chunk->capacity) {
|
||||
int oldCapacity = chunk->capacity;
|
||||
chunk->capacity = TOY_GROW_CAPACITY(oldCapacity);
|
||||
chunk->code = TOY_GROW_ARRAY(uint8_t, chunk->code, oldCapacity, chunk->capacity);
|
||||
}
|
||||
|
||||
chunk->code[chunk->count++] = byte;
|
||||
}
|
||||
|
||||
void Toy_freeChunk(Toy_Chunk* chunk) {
|
||||
TOY_FREE_ARRAY(uint8_t, chunk->code, chunk->capacity);
|
||||
Toy_initChunk(chunk);
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "toy_common.h"
|
||||
|
||||
typedef struct Toy_Chunk {
|
||||
int count;
|
||||
int capacity;
|
||||
uint8_t* code;
|
||||
} Toy_Chunk;
|
||||
|
||||
TOY_API void Toy_initChunk(Toy_Chunk* chunk);
|
||||
TOY_API void Toy_pushChunk(Toy_Chunk* chunk, uint8_t byte);
|
||||
TOY_API void Toy_freeChunk(Toy_Chunk* chunk);
|
||||
@@ -23,7 +23,7 @@ const Toy_KeywordTypeTuple Toy_private_keywords[] = {
|
||||
{TOY_TOKEN_KEYWORD_ASSERT, "assert"},
|
||||
{TOY_TOKEN_KEYWORD_BREAK, "break"},
|
||||
{TOY_TOKEN_KEYWORD_CLASS, "class"},
|
||||
{TOY_TOKEN_KEYWORD_CONST, "const"}, //TODO: investigate the constness of types
|
||||
{TOY_TOKEN_KEYWORD_CONST, "const"},
|
||||
{TOY_TOKEN_KEYWORD_CONTINUE, "continue"},
|
||||
{TOY_TOKEN_KEYWORD_DO, "do"},
|
||||
{TOY_TOKEN_KEYWORD_ELSE, "else"},
|
||||
|
||||
@@ -19,4 +19,69 @@ void* Toy_reallocate(void* pointer, size_t oldSize, size_t newSize) {
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
//buckets of fun
|
||||
void Toy_initBucket(Toy_Bucket** bucketHandle, size_t capacity) {
|
||||
if (capacity == 0) {
|
||||
fprintf(stderr, TOY_CC_ERROR "[internal] ERROR: Cannot init a bucket with zero capacity\n" TOY_CC_RESET);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
(*bucketHandle) = malloc(sizeof(Toy_Bucket));
|
||||
|
||||
if ((*bucketHandle) == NULL) {
|
||||
fprintf(stderr, TOY_CC_ERROR "[internal] ERROR: Failed to allocate space for a bucket\n" TOY_CC_RESET);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
//initialize the bucket
|
||||
(*bucketHandle)->next = NULL;
|
||||
(*bucketHandle)->contents = NULL; //leave until the first partition
|
||||
(*bucketHandle)->capacity = capacity;
|
||||
(*bucketHandle)->count = 0;
|
||||
}
|
||||
|
||||
void* Toy_partBucket(Toy_Bucket** bucketHandle, size_t space) {
|
||||
if ((*bucketHandle) == NULL) {
|
||||
fprintf(stderr, TOY_CC_ERROR "[internal] ERROR: Expected bucket, received NULL\n" TOY_CC_RESET);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
//if out of space in the current bucket
|
||||
if ((*bucketHandle)->capacity < (*bucketHandle)->count + space) {
|
||||
//move to the next bucket
|
||||
Toy_Bucket* tmp = NULL;
|
||||
Toy_initBucket(&tmp, (*bucketHandle)->capacity);
|
||||
tmp->next = (*bucketHandle);
|
||||
(*bucketHandle) = tmp;
|
||||
}
|
||||
|
||||
//if no space allocated for the current bucket
|
||||
if ((*bucketHandle)->contents == NULL) {
|
||||
//allocate space for the current bucket
|
||||
(*bucketHandle)->contents = malloc((*bucketHandle)->capacity);
|
||||
|
||||
//double check
|
||||
if ((*bucketHandle)->contents == NULL) {
|
||||
fprintf(stderr, TOY_CC_ERROR "[internal] ERROR: Failed to allocate space for bucket contents\n" TOY_CC_RESET);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
//track the new count, and return the specified memory space
|
||||
(*bucketHandle)->count += space;
|
||||
return ((*bucketHandle)->contents + (*bucketHandle)->count - space);
|
||||
}
|
||||
|
||||
void Toy_freeBucket(Toy_Bucket** bucketHandle) {
|
||||
while ((*bucketHandle) != NULL) {
|
||||
//run down the chain
|
||||
Toy_Bucket* ptr = (*bucketHandle);
|
||||
(*bucketHandle) = (*bucketHandle)->next;
|
||||
|
||||
//clear the previous bucket from memory
|
||||
free(ptr->contents);
|
||||
free(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,13 +2,45 @@
|
||||
|
||||
#include "toy_common.h"
|
||||
|
||||
//standard movable array for general use
|
||||
#define TOY_GROW_CAPACITY(capacity) \
|
||||
((capacity) < 8 ? 8 : (capacity) * 2)
|
||||
|
||||
#define TOY_ALLOCATE(type, count) \
|
||||
(type*)Toy_reallocate(NULL, 0, sizeof(type)*(count))
|
||||
|
||||
#define TOY_FREE(type, pointer) \
|
||||
(type*)Toy_reallocate(pointer, sizeof(type), 0)
|
||||
|
||||
#define TOY_GROW_ARRAY(type, pointer, oldSize, newSize) \
|
||||
(type*)Toy_reallocate(pointer, sizeof(type)*oldSize, sizeof(type)*newSize)
|
||||
|
||||
#define TOY_SHRINK_ARRAY(type, pointer, oldCount, count) \
|
||||
(type*)Toy_reallocate((type*)pointer, sizeof(type)*(oldCount), sizeof(type)*(count))
|
||||
|
||||
#define TOY_FREE_ARRAY(type, pointer, oldSize) \
|
||||
(type*)Toy_reallocate(pointer, sizeof(type)*oldSize, 0)
|
||||
|
||||
TOY_API void* Toy_reallocate(void* pointer, size_t oldSize, size_t newSize);
|
||||
|
||||
//immobile "bucket" memory structure for custom allocators
|
||||
typedef struct Toy_Bucket {
|
||||
struct Toy_Bucket* next;
|
||||
void* contents;
|
||||
int capacity;
|
||||
int count;
|
||||
} Toy_Bucket;
|
||||
|
||||
TOY_API void Toy_initBucket(Toy_Bucket** bucketHandle, size_t capacity);
|
||||
TOY_API void* Toy_partBucket(Toy_Bucket** bucketHandle, size_t space);
|
||||
TOY_API void Toy_freeBucket(Toy_Bucket** bucketHandle);
|
||||
|
||||
#define TOY_BUCKET_INIT(type, bucket, capacity) \
|
||||
Toy_initBucket(&(bucket), sizeof(type)*(capacity))
|
||||
|
||||
#define TOY_BUCKET_PART(type, bucket) \
|
||||
Toy_partBucket(&(bucket), sizeof(type))
|
||||
|
||||
#define TOY_BUCKET_FREE(bucket) \
|
||||
Toy_freeBucket(&(bucket))
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
typedef enum Toy_OpcodeType {
|
||||
TOY_OPCODE_RETURN,
|
||||
TOY_OPCODE_PASS,
|
||||
TOY_OPCODE_ERROR,
|
||||
TOY_OPCODE_EOF,
|
||||
} Toy_OpcodeType;
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ typedef enum Toy_ValueType {
|
||||
TOY_VALUE_OPAQUE,
|
||||
} Toy_ValueType;
|
||||
|
||||
//4 bytes in size
|
||||
typedef struct Toy_Value {
|
||||
union {
|
||||
bool boolean; //1
|
||||
@@ -26,7 +27,7 @@ typedef struct Toy_Value {
|
||||
//TODO: opaque
|
||||
} as; //4
|
||||
|
||||
Toy_ValueType type; //4 bytes
|
||||
Toy_ValueType type; //4
|
||||
} Toy_Value;
|
||||
|
||||
#define TOY_VALUE_IS_NULL(value) ((value).type == TOY_VALUE_NULL)
|
||||
|
||||
157
tests/cases/test_memory.c
Normal file
157
tests/cases/test_memory.c
Normal file
@@ -0,0 +1,157 @@
|
||||
#include "toy_memory.h"
|
||||
#include "toy_console_colors.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
int test_reallocate() {
|
||||
//test single pointer
|
||||
{
|
||||
int* integer = TOY_ALLOCATE(int, 1);
|
||||
TOY_FREE(int, integer);
|
||||
}
|
||||
|
||||
//test single pointer array
|
||||
{
|
||||
int* array = TOY_ALLOCATE(int, 10);
|
||||
|
||||
//check you can access the memory
|
||||
array[1] = 42;
|
||||
|
||||
TOY_FREE_ARRAY(int, array, 10);
|
||||
}
|
||||
|
||||
//test multiple pointer arrays
|
||||
{
|
||||
int* array1 = TOY_ALLOCATE(int, 10);
|
||||
int* array2 = TOY_ALLOCATE(int, 10);
|
||||
|
||||
array1[1] = 42; //access the given memory
|
||||
array2[1] = 42; //access the given memory
|
||||
|
||||
TOY_FREE_ARRAY(int, array1, 10);
|
||||
TOY_FREE_ARRAY(int, array2, 10);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_buckets() {
|
||||
//test initializing and freeing a bucket
|
||||
{
|
||||
//init
|
||||
Toy_Bucket* bucket = NULL;
|
||||
TOY_BUCKET_INIT(int, bucket, 32);
|
||||
|
||||
//check
|
||||
if (bucket == NULL || bucket->capacity != 32 * sizeof(int)) {
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to initialize 'Toy_Bucket'\n" TOY_CC_RESET);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//cleanup
|
||||
TOY_BUCKET_FREE(bucket);
|
||||
}
|
||||
|
||||
//test partitioning a bucket, several times
|
||||
{
|
||||
//init
|
||||
Toy_Bucket* bucket = NULL;
|
||||
TOY_BUCKET_INIT(int, bucket, 32);
|
||||
|
||||
//grab some memory
|
||||
int* a = TOY_BUCKET_PART(int, bucket);
|
||||
int* b = TOY_BUCKET_PART(int, bucket);
|
||||
int* c = TOY_BUCKET_PART(int, bucket);
|
||||
int* d = TOY_BUCKET_PART(int, bucket);
|
||||
|
||||
//check
|
||||
if (bucket == NULL || bucket->count != 4 * sizeof(int)) {
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to partition 'Toy_Bucket' correctly: count is %d, expected %d\n" TOY_CC_RESET, bucket->count, (int)(4*sizeof(int)));
|
||||
return -1;
|
||||
}
|
||||
|
||||
//cleanup
|
||||
TOY_BUCKET_FREE(bucket);
|
||||
}
|
||||
|
||||
//test partitioning a bucket, several times, with an internal expansion
|
||||
{
|
||||
//init
|
||||
Toy_Bucket* bucket = NULL;
|
||||
TOY_BUCKET_INIT(int, bucket, 4);
|
||||
|
||||
//grab some memory
|
||||
int* a = TOY_BUCKET_PART(int, bucket);
|
||||
int* b = TOY_BUCKET_PART(int, bucket);
|
||||
int* c = TOY_BUCKET_PART(int, bucket);
|
||||
int* d = TOY_BUCKET_PART(int, bucket);
|
||||
int* e = TOY_BUCKET_PART(int, bucket);
|
||||
int* f = TOY_BUCKET_PART(int, bucket);
|
||||
|
||||
//checks - please note that the top-most bucket is what is being filled - older buckets are further along
|
||||
if (
|
||||
bucket->capacity != 4 * sizeof(int) ||
|
||||
bucket->count != 2 * sizeof(int) ||
|
||||
bucket->next == NULL ||
|
||||
bucket->next->capacity != 4 * sizeof(int) ||
|
||||
bucket->next->count != 4 * sizeof(int))
|
||||
{
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to expand 'Toy_Bucket' correctly\n" TOY_CC_RESET);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//cleanup
|
||||
TOY_BUCKET_FREE(bucket);
|
||||
}
|
||||
|
||||
//test partitioning a bucket, several times, with an internal expansion, and awkward sizes
|
||||
{
|
||||
//init
|
||||
Toy_Bucket* bucket = NULL;
|
||||
Toy_initBucket(&bucket, 32);
|
||||
|
||||
//grab some memory
|
||||
void* a = Toy_partBucket(&bucket, 16);
|
||||
void* b = Toy_partBucket(&bucket, 10);
|
||||
void* c = Toy_partBucket(&bucket, 10);
|
||||
void* d = Toy_partBucket(&bucket, 10);
|
||||
|
||||
//checks - awkward and mismatched sizes is not officially supported, but it should work
|
||||
if (
|
||||
bucket->capacity != 32 ||
|
||||
bucket->count != 20 ||
|
||||
bucket->next == NULL ||
|
||||
bucket->next->capacity != 32 ||
|
||||
bucket->next->count != 26)
|
||||
{
|
||||
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to expand 'Toy_Bucket' with awkward/mismatched sizes correctly\n" TOY_CC_RESET);
|
||||
return -1;
|
||||
}
|
||||
|
||||
//cleanup
|
||||
TOY_BUCKET_FREE(bucket);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main() {
|
||||
//run each test set, returning the total errors given
|
||||
int total = 0, res = 0;
|
||||
|
||||
res = test_reallocate();
|
||||
total += res;
|
||||
|
||||
if (res == 0) {
|
||||
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||
}
|
||||
|
||||
res = test_buckets();
|
||||
total += res;
|
||||
|
||||
if (res == 0) {
|
||||
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "toy_value.h"
|
||||
#include "toy_console_colors.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
|
||||
Reference in New Issue
Block a user