mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 14:54: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"
|
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
|
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
|
.PHONY: tests
|
||||||
tests:
|
tests:
|
||||||
$(MAKE) -C tests
|
$(MAKE) -C tests -k
|
||||||
|
|
||||||
#util targets
|
#util targets
|
||||||
$(TOY_OUTDIR):
|
$(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_ASSERT, "assert"},
|
||||||
{TOY_TOKEN_KEYWORD_BREAK, "break"},
|
{TOY_TOKEN_KEYWORD_BREAK, "break"},
|
||||||
{TOY_TOKEN_KEYWORD_CLASS, "class"},
|
{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_CONTINUE, "continue"},
|
||||||
{TOY_TOKEN_KEYWORD_DO, "do"},
|
{TOY_TOKEN_KEYWORD_DO, "do"},
|
||||||
{TOY_TOKEN_KEYWORD_ELSE, "else"},
|
{TOY_TOKEN_KEYWORD_ELSE, "else"},
|
||||||
|
|||||||
@@ -19,4 +19,69 @@ void* Toy_reallocate(void* pointer, size_t oldSize, size_t newSize) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
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"
|
#include "toy_common.h"
|
||||||
|
|
||||||
|
//standard movable array for general use
|
||||||
#define TOY_GROW_CAPACITY(capacity) \
|
#define TOY_GROW_CAPACITY(capacity) \
|
||||||
((capacity) < 8 ? 8 : (capacity) * 2)
|
((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) \
|
#define TOY_GROW_ARRAY(type, pointer, oldSize, newSize) \
|
||||||
(type*)Toy_reallocate(pointer, sizeof(type)*oldSize, sizeof(type)*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) \
|
#define TOY_FREE_ARRAY(type, pointer, oldSize) \
|
||||||
(type*)Toy_reallocate(pointer, sizeof(type)*oldSize, 0)
|
(type*)Toy_reallocate(pointer, sizeof(type)*oldSize, 0)
|
||||||
|
|
||||||
TOY_API void* Toy_reallocate(void* pointer, size_t oldSize, size_t newSize);
|
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
|
#pragma once
|
||||||
|
|
||||||
typedef enum Toy_OpcodeType {
|
typedef enum Toy_OpcodeType {
|
||||||
TOY_OPCODE_RETURN,
|
TOY_OPCODE_PASS,
|
||||||
|
TOY_OPCODE_ERROR,
|
||||||
|
TOY_OPCODE_EOF,
|
||||||
} Toy_OpcodeType;
|
} Toy_OpcodeType;
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ typedef enum Toy_ValueType {
|
|||||||
TOY_VALUE_OPAQUE,
|
TOY_VALUE_OPAQUE,
|
||||||
} Toy_ValueType;
|
} Toy_ValueType;
|
||||||
|
|
||||||
|
//4 bytes in size
|
||||||
typedef struct Toy_Value {
|
typedef struct Toy_Value {
|
||||||
union {
|
union {
|
||||||
bool boolean; //1
|
bool boolean; //1
|
||||||
@@ -26,7 +27,7 @@ typedef struct Toy_Value {
|
|||||||
//TODO: opaque
|
//TODO: opaque
|
||||||
} as; //4
|
} as; //4
|
||||||
|
|
||||||
Toy_ValueType type; //4 bytes
|
Toy_ValueType type; //4
|
||||||
} Toy_Value;
|
} Toy_Value;
|
||||||
|
|
||||||
#define TOY_VALUE_IS_NULL(value) ((value).type == TOY_VALUE_NULL)
|
#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_value.h"
|
||||||
#include "toy_console_colors.h"
|
#include "toy_console_colors.h"
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
|
|||||||
Reference in New Issue
Block a user