/* linked-list-test.c - singly linked list on the C64, built with cc65 * * Build: * cl65 -t c64 -O -o linked-list-test.prg linked-list-test.c * * Exercises malloc()/free()-backed linked list operations (append, * count, sum, search, delete, reverse, free) at sizes from 1000 to * 2000 nodes, then runs an allocator capacity test to show how many * 4-byte nodes actually fit in real C64 RAM under this cc65 memory * config (program loads at $0801, heap tops out at $D000). */ #include #include #include typedef struct Node { int value; struct Node *next; } Node; /* ---- basic list operations ------------------------------------- */ /* Appends 1..count to a new list. Returns NULL (and frees any partial list) if malloc() runs out of memory partway through. */ static Node *build_list(unsigned int count) { Node *head = NULL, *tail = NULL, *n; unsigned int i; for (i = 0; i < count; i++) { n = malloc(sizeof(Node)); if (!n) { while (head) { n = head; head = head->next; free(n); } return NULL; } n->value = (int)(i + 1); n->next = NULL; if (head) tail->next = n; else head = n; tail = n; } return head; } static unsigned int count_list(Node *head) { unsigned int c = 0; while (head) { c++; head = head->next; } return c; } static long sum_list(Node *head) { long s = 0; while (head) { s += head->value; head = head->next; } return s; } static Node *list_find(Node *head, int value) { while (head) { if (head->value == value) return head; head = head->next; } return NULL; } /* Removes the first node matching value. Returns 1 if removed. */ static unsigned char list_delete(Node **headp, int value) { Node *prev = NULL, *cur = *headp; while (cur) { if (cur->value == value) { if (prev) prev->next = cur->next; else *headp = cur->next; free(cur); return 1; } prev = cur; cur = cur->next; } return 0; } static void list_reverse(Node **headp) { Node *prev = NULL, *cur = *headp, *next; while (cur) { next = cur->next; cur->next = prev; prev = cur; cur = next; } *headp = prev; } static void free_list(Node *head) { Node *n; while (head) { n = head; head = head->next; free(n); } } /* ---- one pass of tests at a given size --------------------------- */ static unsigned char test_size(unsigned int n) { Node *head; unsigned int c; long s, expected; int mid; unsigned char ok = 1; head = build_list(n); if (!head) { textcolor(COLOR_RED); cprintf("N=%4u ALLOC FAIL\n\r", n); return 0; } c = count_list(head); s = sum_list(head); expected = ((long)n * (n + 1)) / 2; if (c != n || s != expected) ok = 0; mid = (int)(n / 2); if (!list_find(head, mid)) ok = 0; if (list_find(head, (int)(n + 500))) ok = 0; if (!list_delete(&head, mid)) ok = 0; if (list_find(head, mid)) ok = 0; if (count_list(head) != n - 1) ok = 0; list_reverse(&head); if (!head || head->value != (int)n) ok = 0; free_list(head); textcolor(ok ? COLOR_GREEN : COLOR_RED); cprintf("N=%4u %s\n\r", n, ok ? "PASS" : "FAIL"); return ok; } /* ---- how many nodes really fit in RAM? --------------------------- */ static void capacity_test(void) { Node *head = NULL, *tail = NULL, *n; unsigned int count = 0; textcolor(COLOR_WHITE); cprintf("\n\rCAPACITY TEST (malloc until NULL)...\n\r"); for (;;) { n = malloc(sizeof(Node)); if (!n) break; n->value = (int)count; n->next = NULL; if (head) tail->next = n; else head = n; tail = n; count++; } textcolor(COLOR_YELLOW); cprintf("MAX NODES ALLOCATED: %u\n\r", count); free_list(head); } /* ---- driver -------------------------------------------------------- */ int main(void) { static const unsigned int sizes[5] = { 1000, 1250, 1500, 1750, 2000 }; unsigned char i, passed = 0; clrscr(); bgcolor(COLOR_BLACK); bordercolor(COLOR_BLACK); textcolor(COLOR_CYAN); cprintf("C64 LINKED LIST TEST (cc65)\n\r"); cprintf("===========================\n\r"); textcolor(COLOR_WHITE); cprintf("append/count/sum/find/delete/reverse\n\r\n\r"); for (i = 0; i < 5; i++) { passed += test_size(sizes[i]); } textcolor(COLOR_WHITE); cprintf("\n\r%u/5 SIZE TESTS PASSED\n\r", passed); capacity_test(); textcolor(COLOR_CYAN); cprintf("\n\rDONE - PRESS ANY KEY\n\r"); cgetc(); bgcolor(COLOR_BLUE); bordercolor(COLOR_LIGHTBLUE); return 0; }