Implemented garbage collection
As a whole, this is still tentative.
This commit is contained in:
+158
-6
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user