Implemented garbage collection

As a whole, this is still tentative.
This commit is contained in:
2026-05-08 16:28:12 +10:00
parent be84a8dfe2
commit 6c055a0435
15 changed files with 267 additions and 80 deletions
+158 -6
View File
@@ -31,7 +31,7 @@ int test_buckets(void) {
Toy_partitionBucket(&bucket, sizeof(int));
//check
if (bucket == NULL || bucket->count != 4 * sizeof(int)) {
if (bucket == NULL || bucket->count != 4 * (sizeof(int) +4)) { //+4 take the metadata into account
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to partition 'Toy_Bucket' correctly: count is %d, expected %d\n" TOY_CC_RESET, (int)(bucket->count), (int)(4*sizeof(int)));
return -1;
}
@@ -43,7 +43,7 @@ int test_buckets(void) {
//test partitioning a bucket, several times, with an internal expansion
{
//init
Toy_Bucket* bucket = Toy_allocateBucket(sizeof(int) * 4);
Toy_Bucket* bucket = Toy_allocateBucket((sizeof(int)+4) * 4); //+4 take the metadata into account
//grab some memory
Toy_partitionBucket(&bucket, sizeof(int));
@@ -55,11 +55,11 @@ int test_buckets(void) {
//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->capacity != 4 * (sizeof(int)+4) ||
bucket->count != 2 * (sizeof(int)+4) ||
bucket->next == NULL ||
bucket->next->capacity != 4 * sizeof(int) ||
bucket->next->count != 4 * sizeof(int))
bucket->next->capacity != 4 * (sizeof(int)+4) ||
bucket->next->count != 4 * (sizeof(int)+4))
{
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to expand 'Toy_Bucket' correctly\n" TOY_CC_RESET);
return -1;
@@ -72,6 +72,149 @@ int test_buckets(void) {
return 0;
}
int test_garbage_collection(void) {
//release one element in one bucket link
{
//init
Toy_Bucket* bucket = Toy_allocateBucket(sizeof(int) * 32);
//dummy data, producing 4 entries
unsigned char* ptr1 = Toy_partitionBucket(&bucket, sizeof(int));
unsigned char* ptr2 = Toy_partitionBucket(&bucket, sizeof(int));
unsigned char* ptr3 = Toy_partitionBucket(&bucket, sizeof(int));
unsigned char* ptr4 = Toy_partitionBucket(&bucket, sizeof(int));
//release exactly one chunk of data
(void)ptr1;
(void)ptr2;
Toy_releaseBucketPartition(ptr3);
(void)ptr4;
//check the state of the bucket's data
if (
bucket->capacity != 32 * sizeof(int) ||
bucket->count != 4 * (sizeof(int)+4) ||
bucket->next != NULL ||
((unsigned int*)(bucket->data))[0] != 4 ||
((unsigned int*)(bucket->data))[1] != 0 ||
((unsigned int*)(bucket->data))[2] != 4 ||
((unsigned int*)(bucket->data))[3] != 0 ||
((unsigned int*)(bucket->data))[4] != 5 || //nth bit is altered here
((unsigned int*)(bucket->data))[5] != 0 ||
((unsigned int*)(bucket->data))[6] != 4 ||
((unsigned int*)(bucket->data))[7] != 0
)
{
fprintf(stderr, TOY_CC_ERROR "ERROR: failed simple memory partition release in 'Toy_Bucket'\n" TOY_CC_RESET);
Toy_freeBucket(&bucket);
return -1;
}
//cleanup
Toy_freeBucket(&bucket);
}
//release one element in many bucket links
{
//init
Toy_Bucket* bucket = Toy_allocateBucket(sizeof(int) * 32);
//partition the bucket 100 times, for dummy data
for (int i = 0; i < 50; i++) {
Toy_partitionBucket(&bucket, sizeof(int));
}
unsigned char* ptr = Toy_partitionBucket(&bucket, sizeof(int)); //grab the 51st element
for (int i = 0; i < 49; i++) {
Toy_partitionBucket(&bucket, sizeof(int));
}
//16 integers to a link, check for 7 links
if (
bucket->next == NULL ||
bucket->next->next == NULL ||
bucket->next->next->next == NULL ||
bucket->next->next->next->next == NULL ||
bucket->next->next->next->next->next == NULL ||
bucket->next->next->next->next->next->next == NULL ||
bucket->next->next->next->next->next->next->next != NULL) //there is no 8th link
{
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to set up 'Toy_Bucket' to 'release one element in many bucket links'\n" TOY_CC_RESET);
Toy_freeBucket(&bucket);
return -1;
}
Toy_releaseBucketPartition(ptr);
//check the 3rd element in the 4th link
if (
((int*)(bucket->next->next->next->data + 2 * (sizeof(int)+4) ))[0] != 5 ||
((int*)(bucket->next->next->next->data + 2 * (sizeof(int)+4) ))[1] != 0
)
{
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to release one element in many bucket links\n" TOY_CC_RESET);
Toy_freeBucket(&bucket);
return -1;
}
//cleanup
Toy_freeBucket(&bucket);
}
//garbage collection on a chain
{
//init
Toy_Bucket* bucket = Toy_allocateBucket(sizeof(int) * 32);
//partition the bucket 100 times, for dummy data
for (int i = 0; i < 100; i++) {
Toy_partitionBucket(&bucket, sizeof(int));
}
//16 integers to a link, check for 7 links
if (
bucket->next == NULL ||
bucket->next->next == NULL ||
bucket->next->next->next == NULL ||
bucket->next->next->next->next == NULL ||
bucket->next->next->next->next->next == NULL ||
bucket->next->next->next->next->next->next == NULL ||
bucket->next->next->next->next->next->next->next != NULL) //there is no 8th link
{
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to set up 'Toy_Bucket' to test garbage collection on a link\n" TOY_CC_RESET);
Toy_freeBucket(&bucket);
return -1;
}
//grab link pointers
Toy_Bucket* third = bucket->next->next;
Toy_Bucket* fourth = bucket->next->next->next;
Toy_Bucket* fifth = bucket->next->next->next->next;
//free all elements in this link
for (int i = 0; i < 16; i++) {
Toy_releaseBucketPartition((fourth->data + i*8 + 4));
}
//run the GC
Toy_collectBucketGarbage(&bucket);
//check
if (third->next != fifth) {
fprintf(stderr, TOY_CC_ERROR "ERROR: failed to remove a chain link from 'Toy_Bucket' correctly\n" TOY_CC_RESET);
Toy_freeBucket(&bucket);
return -1;
}
//cleanup
Toy_freeBucket(&bucket);
}
return 0;
}
int main(void) {
//run each test set, returning the total errors given
int total = 0, res = 0;
@@ -85,5 +228,14 @@ int main(void) {
}
}
{
res = test_garbage_collection();
total += res;
if (res == 0) {
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
}
}
return total;
}
+1 -1
View File
@@ -56,7 +56,7 @@ int test_string_allocation(void) {
//inspect the bucket
if (bucket->capacity != 1024 ||
bucket->count != sizeof(Toy_String) + 12 ||
bucket->count != sizeof(Toy_String) + 12 + 4 || //+4 for bucket metadata
bucket->next != NULL)
{
fprintf(stderr, TOY_CC_ERROR "ERROR: Unexpected bucket state after 'Toy_createStringLength'\n" TOY_CC_RESET);