AmendHub

Download:

ftech

/

SList

/

amendments

/

1

First commit


Francois Techene made amendment 1 2 days ago
--- LICENSE Wed Mar 26 11:02:46 2025 +++ LICENSE Wed Mar 26 11:02:46 2025 @@ -0,0 +1,7 @@ +Copyright (c) 2025 Francois Techene <ftechene@yahoo.fr> + +The SList Library for classic Mac is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +<https://www.gnu.org/licenses/gpl-3.0.en.html>. --- README Mon Mar 31 19:08:23 2025 +++ README Mon Mar 31 19:08:23 2025 @@ -0,0 +1,59 @@ +SList: a C library that implements Singly Linked Lists for classic Macintosh programs. + +SList is free software; see the LICENSE file for copyright/licensing +--- + +# Install + +This library has been built and tested using THINK C v5 on a Macintosh SE. + +In order to install it, just import `Slist.Lib` from the `build` folder to your project and include it in your source files. + +You can also add `slist.c` and `slist.h` directly to your project. +--- + +# Usage + +## Creating a new list +``` +// Create a new SList object. +SList* my_list = SList_new(); +``` + +## Adding objects to the list +``` +// Append an object at the end of the list. +slist_append(my_list, (Ptr)my_object); + +// Insert an object at a given 0 based index position in the list. +// (Third position in this case). +slist_insert_at(my_list, (Ptr)my_object, 2); + +// Insert an object after the first occurence of another one. +slist_insert_after(my_list, (Ptr)my_object, (Ptr)other_object); +``` + +## Removing objects from the list +``` +// Remove the first occurence of an object from the list. +slist_remove_value(my_list, (Ptr)my_object); + +// Remove an object at a given 0 based index postion from the list. +// (Third position in this case). +slist_remove_at(my_list, 2); + +// Remove the last object from the list. +slist_remove_last(my_list); + +// Remove all objects from the list. +slist_empty(my_list); +``` + +## Parsing a list +``` +SL_FOREACH(item, list) { + obj = (MyObject*)item->data; +} +``` + +You can customize the SL_FOREACH macro by re-implementing `SList.first()`, `SList.last()` and `SList.next()` for your own needs. --- slist-test.c Mon Mar 31 18:59:30 2025 +++ slist-test.c Mon Mar 31 18:59:30 2025 @@ -0,0 +1,489 @@ +/* slist_test.c + * + * Copyright 2025 Francois Techene + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> + +#include "slist.h" + +#ifndef bool +typedef Boolean bool; +#endif + + +typedef struct _MyObject { + + char* text; + int num; + +} MyObject; + +MyObject* MyObject_new(char* text, int num) +{ + MyObject* self = (MyObject*)malloc(sizeof(MyObject)); + + self->text = text; + self->num = num; + + return self; +} + + +MyObject* obj1 = NULL; +MyObject* obj2 = NULL; +MyObject* obj3 = NULL; + +SList* list = NULL; + +bool found_error = false; + + +////////////////////////////////////////////////////////// +// Assert Functions +// +bool +ut_asser_ptr_equal(void* value_1, void* value_2, char* msg) +{ + if (value_1 != value_2) { + printf(" FAILED: %s - Pointers do not match\n", msg); + found_error = true; + return 0; + } + return 1; +} + +bool +ut_asser_null(void* value, char* msg) +{ + if (value) { + printf(" FAILED: %s - Should be NULL\n", msg); + found_error = true; + return 0; + } + return 1; +} + +bool +ut_asser_not_null(void* value, char* msg) +{ + if (!value) { + printf(" FAILED: %s - Should not be NULL\n", msg); + found_error = true; + return 0; + } + return 1; +} + +bool +ut_asser_true(bool value, char* msg) +{ + if (!value) { + printf(" FAILED: %s - Should be true\n", msg); + found_error = true; + return 0; + } + return 1; +} + +bool +ut_asser_false(bool value, char* msg) +{ + if (value) { + printf(" FAILED: %s - Should be false\n", msg); + found_error = true; + return 0; + } + return 1; +} + +bool +ut_asser_greater_int(int value_1, int value_2, char* msg) +{ + if (value_1 > value_2) { + printf(" FAILED: %s - Should be greater than %d and is %d\n", + msg, + value_2, + value_1); + found_error = true; + return 0; + } + return 1; +} + +bool +ut_asser_not_equal_int(int value_1, int value_2, char* msg) +{ + if (value_1 == value_2) { + printf(" FAILED: %s - Should not equal %d\n", msg, value_2); + found_error = true; + return 0; + } + return 1; +} + +bool +ut_asser_equal_int(int value_1, int value_2, char* msg) +{ + if (value_1 != value_2) { + printf(" FAILED: %s - Value is %d, should be %d\n", + msg, + value_1, + value_2); + found_error = true; + return 0; + } + return 1; +} + +////////////////////////////////////////////////////////// +// Unit Test +// +void +init_tests() +{ + printf("Initializing Objects... \n"); + + obj1 = MyObject_new("Obj1", 1); + obj2 = MyObject_new("Obj2", 2); + obj3 = MyObject_new("Obj3", 3); + + list = SList_new(); + + ut_asser_equal_int(obj1->num, 1, + "init_tests() - obj1->num"); + ut_asser_equal_int(obj2->num, 2, + "init_tests() - obj2->num"); + ut_asser_equal_int(obj3->num, 3, + "init_tests() - obj3->num"); + + ut_asser_null(list->head, + "init_tests() - list->head"); + + ut_asser_equal_int(list->count, 0, + "init_tests() - list->count"); +} + +void +test_append() +{ + MyObject* obj = NULL; + SListItem* item = NULL; + int count = 0; + + printf("Testing append... \n"); + + slist_append(list, obj1); + slist_append(list, obj2); + slist_append(list, obj3); + + SL_FOREACH(item, list) { + count++; + obj = (MyObject*)item->data; + + ut_asser_equal_int(obj->num, count, + "test_append() - obj->num"); + + } + + ut_asser_equal_int(count, 3, + "test_append() - FOREACH count"); +} + +void +test_remove_item() +{ + MyObject* obj = NULL; + SListItem* item = NULL; + int count = 0; + + printf("Testing remove item...\n"); + + slist_remove_value(list, obj2); + + SL_FOREACH(item, list) { + count++; + obj = (MyObject*)item->data; + + if (count == 1) { + ut_asser_equal_int(obj->num, 1, + "test_remove_item() - obj->num"); + } + + if (count == 2) { + ut_asser_equal_int(obj->num, 3, + "test_remove_item() - obj->num"); + } + + } + + ut_asser_equal_int(list->count, 2, + "test_remove_item() - list->count"); + + ut_asser_equal_int(count, 2, + "test_remove_item() - FOREACH count"); +} + +void +test_insert_at() +{ + MyObject* obj = NULL; + SListItem* item = NULL; + int count = 0; + + printf("Testing insert at... \n"); + + slist_insert_at(list, obj2, 1); + + SL_FOREACH(item, list) { + count++; + obj = (MyObject*)item->data; + + if (count == 1) { + ut_asser_equal_int(obj->num, 1, + "test_insert_at() - obj->num"); + } + if (count == 2) { + ut_asser_equal_int(obj->num, 2, + "test_insert_at() - obj->num"); + } + if (count == 3) { + ut_asser_equal_int(obj->num, 3, + "test_insert_at() - obj->num"); + } + + } + + ut_asser_equal_int(list->count, 3, + "test_insert_at() - list->count"); + + ut_asser_equal_int(count, 3, + "test_insert_at() - FOREACH count"); +} + +void +test_remove_at() +{ + MyObject* obj = NULL; + SListItem* item = NULL; + int count = 0; + + printf("Testing remove first...\n"); + + slist_remove_at(list, 1); + + SL_FOREACH(item, list) { + count++; + obj = (MyObject*)item->data; + + if (count == 1) { + ut_asser_equal_int(obj->num, 1, + "test_remove_at() - obj->num"); + } + + if (count == 2) { + ut_asser_equal_int(obj->num, 3, + "test_remove_at() - obj->num"); + } + + } + + ut_asser_equal_int(list->count, 2, + "test_remove_at() - list->count"); + + ut_asser_equal_int(count, 2, + "test_remove_at() - FOREACH count"); +} + +void +test_insert_after() +{ + MyObject* obj = NULL; + SListItem* item = NULL; + int count = 0; + + printf("Testing insert after... \n"); + + slist_insert_after(list, obj2, obj1); + + SL_FOREACH(item, list) { + count++; + obj = (MyObject*)item->data; + + if (count == 1) { + ut_asser_equal_int(obj->num, 1, + "test_insert_after()"); + } + if (count == 2) { + ut_asser_equal_int(obj->num, 2, + "test_insert_after()"); + } + if (count == 3) { + ut_asser_equal_int(obj->num, 3, + "test_insert_after()"); + } + + } + + ut_asser_equal_int(list->count, 3, + "test_insert_after() - list->count"); + + ut_asser_equal_int(count, 3, + "test_insert_after() - FOREACH count"); +} + +void +test_remove_last() +{ + MyObject* obj = NULL; + SListItem* item = NULL; + int count = 0; + + printf("Testing remove last...\n"); + + slist_remove_last(list); + + SL_FOREACH(item, list) { + count++; + obj = (MyObject*)item->data; + + if (count == 1) { + ut_asser_equal_int(obj->num, 1, + "test_remove_last()"); + } + if (count == 2) { + ut_asser_equal_int(obj->num, 2, + "test_remove_last()"); + } + } + + ut_asser_equal_int(list->count, 2, + "test_remove_last() - list->count"); + + ut_asser_equal_int(count, 2, + "test_remove_last() - FOREACH count"); +} + +void +test_empty_list() +{ + MyObject* obj = NULL; + SListItem* item = NULL; + int count = 0; + + printf("Testing empty list...\n"); + + slist_append(list, obj1); + slist_append(list, obj2); + + ut_asser_not_equal_int(list->count, 0, + "test_empty_list() - list->count"); + + slist_empty(list); + + SL_FOREACH(item, list) { + count++; + obj = (MyObject*)item->data; + } + + ut_asser_equal_int(count, 0, + "test_empty_list() - FOREACH count"); + + ut_asser_equal_int(list->count, 0, + "test_empty_list() - list->count"); +} + +void test_memory() +{ + long total_mem; + long mem_1; + long mem_2; + long mem_3; + long mem_4; + long mem_5; + long mem_empty; + + printf("\nTesting memory...\n\n"); + + total_mem = FreeMem(); + + slist_append(list, obj1); + slist_append(list, obj2); + slist_append(list, obj3); + mem_1 = total_mem - FreeMem(); + + slist_remove_at(list, 0); + mem_2 = total_mem - FreeMem(); + + slist_remove_last(list); + mem_3 = total_mem - FreeMem(); + + slist_remove_value(list, obj2); + mem_4 = total_mem - FreeMem(); + + slist_append(list, obj1); + slist_append(list, obj2); + slist_append(list, obj3); + mem_5 = total_mem - FreeMem(); + + slist_empty(list); + mem_empty = total_mem - FreeMem(); + + + printf("After appending 3 items: using %ld bytes\n", mem_1); + printf("After removing first: using %ld bytes\n", mem_2); + printf("After removing last: using %ld bytes\n", mem_3); + printf("After removing item: using %ld bytes\n", mem_4); + printf("After re-appending 3 items: using %ld bytes\n", mem_5); + printf("After emptying: using %ld bytes\n", mem_empty); +} + +int +main(void) +{ + + + MaxApplZone(); + + printf("+-----------------------------------+\n"); + printf("| SList Unit Test |\n"); + printf("+-----------------------------------+\n\n"); + + init_tests(); + + test_append(); + test_remove_item(); + test_insert_at(); + test_remove_at(); + test_insert_after(); + test_remove_last(); + test_empty_list(); + + test_memory(); + + if (!found_error) { + printf("\nSuccessful!\n"); + } + else { + printf("\n** Errors were found **\n"); + } + + return 1; +} --- slist.c Mon Mar 31 18:56:11 2025 +++ slist.c Mon Mar 31 18:56:11 2025 @@ -0,0 +1,258 @@ +/* slist.c + * + * Copyright 2025 Francois Techene + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include "slist.h" + +#include <stdlib.h> + + +SListItem* +SListItem_new(void* data) +{ + SListItem* self = (SListItem*)NewPtr(sizeof(SListItem)); + self->data = data; + self->next = NULL; + + return self; +} + +void +SListItem_delete(SListItem** item) +{ + if (*item) { + DisposPtr(*item); + *item = NULL; + } +} + +SList* +SList_new() +{ + SList* self = (SList*)NewPtr(sizeof(SList)); + + self->first = slist_first; + self->last = slist_last; + self->next = slist_next; + + self->head = NULL; + self->count = 0; + + return self; +} + +void +SList_delete(SList** list) +{ + slist_empty(*list); + + if (*list) { + DisposPtr(*list); + *list = NULL; + } +} + +void* +slist_first(SList* self) +{ + return self->head; +} + +void* +slist_last(SList* self) +{ + return NULL; +} + +void* +slist_next(SList* self, SListItem* item) +{ + return item->next; +} + +void +slist_append(SList* self, void* data) +{ + SListItem* elem = self->head; + SListItem* new_elem = SListItem_new(data); + + if (!elem) { + self->head = new_elem; + self->count++; + return; + } + + while (elem->next) { + elem = elem->next; + } + elem->next = new_elem; + + self->count++; +} + +void +slist_insert_at(SList* self, void* data, int index) +{ + int count = 0; + SListItem* prev_elem = NULL; + SListItem* elem = self->head; + SListItem* new_elem = SListItem_new(data); + + while (elem && count < index) { + prev_elem = elem; + elem = elem->next; + count++; + } + + new_elem->next = elem; + + if (!prev_elem) { + self->head = new_elem; + } + else { + prev_elem->next = new_elem; + } + + self->count++; +} + +void +slist_insert_after(SList* self, void* data, void* value) +{ + SListItem* elem = self->head; + SListItem* new_elem = SListItem_new(data); + + if (!self->head) { + self->head = new_elem; + self->count++; + return; + } + + while (elem->next && elem->data != value) { + elem = elem->next; + } + + new_elem->next = elem->next; + elem->next = new_elem; + + self->count++; +} + + +void slist_empty(SList* self) +{ + while (self->head) { + slist_remove_at(self, 0); + } + self->head = NULL; + self->count = 0; +} + +void +slist_remove_at(SList* self, int index) +{ + int count = 0; + SListItem* prev_elem = NULL; + SListItem* elem = self->head; + + if (!elem) { + return; // List is empty; + } + + while (elem && count < index) { + prev_elem = elem; + elem = elem->next; + count++; + } + + if (!elem) { + return; // No element at that index position. + } + + if (!prev_elem) { + self->head = elem->next; + } + else { + prev_elem->next = elem->next; + } + + SListItem_delete(&elem); + elem = NULL; + + self->count--; +} + +void +slist_remove_last(SList* self) +{ + SListItem* prev_elem = NULL; + SListItem* elem = self->head; + + if (!elem) { + return; // List is empty + } + + while (elem->next) { + prev_elem = elem; + elem = elem->next; + } + + // prev_elem->next is freed and set to NULL by the + // delete method. + // + SListItem_delete(&(prev_elem->next)); + prev_elem->next = NULL; + + self->count--; +} + +// Remove the first occurence of the item having the same value +// as 'value'. +// +void +slist_remove_value(SList* self, void* value) +{ + SListItem* prev_elem = NULL; + SListItem* elem = self->head; + + + while (elem != NULL) { + if (elem->data == value) { + + if (!prev_elem) { + self->head = elem->next; + } + else { + prev_elem->next = elem->next; + } + + // elem is freed and set to NULL by the + // delete method. + // + SListItem_delete(&elem); + elem = NULL; + + self->count--; + } + else { + prev_elem = elem; + elem = elem->next; + } + } +} --- slist.h Mon Mar 31 18:45:57 2025 +++ slist.h Mon Mar 31 18:45:57 2025 @@ -0,0 +1,71 @@ +/* slist.h + * + * Copyright 2025 Francois Techene + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#ifndef SLISTS_H +#define SLISTS_H + +typedef struct _SListItem { + + void* data; + struct _SListItem* next; + +} SListItem; + +typedef struct _SList { + + void* (*first)(struct _SList* self); + void* (*last)(struct _SList* self); + void* (*next)(struct _SList* self, SListItem* item); + + SListItem* head; + int count; + +} SList; + +// SListItem //////////////// +// +SListItem* SListItem_new(); +void SListItem_delete(SListItem** item); + +// SList //////////////////// +// +SList* SList_new(); +void SList_delete(SList** self); + +void* slist_first(SList* self); +void* slist_last(SList* self); +void* slist_next(SList* self, SListItem* item); + +void slist_append(SList* self, void* data); +void slist_insert_at(SList* self, void* data, int index); +void slist_insert_after(SList* self, void* data, void* value); + +void slist_remove_at(SList* self, int index); +void slist_remove_last(SList* self); +void slist_remove_value(SList* self, void* data); +void slist_empty(SList* self); + + +#define SL_FOREACH(item, list) \ + for ((item) = (list)->first(list); \ + (item) != (list)->last(list); \ + (item) = (list)->next(list, item)) + +#endif