Initial Commit

This commit is contained in:
Marc
2025-09-13 14:40:16 +02:00
commit ded01301c2
383 changed files with 71046 additions and 0 deletions

542
OU4/src/int_list/int_list.c Normal file
View File

@@ -0,0 +1,542 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <int_list.h>
/*
* Implementation of a typed, undirected list of integers for the
* "Datastructures and algorithms" courses at the Department of
* Computing Science, Umea University. The implementation uses linked
* 2-cells.
*
* Authors: Niclas Borlin (niclas@cs.umu.se)
*
* Version information:
* v1.0 2018-01-28: First public version.
* v1.01 2018-03-26: Bugfix: Corrected const declaration in remove.
* v1.1 2023-01-19: Added list_pos_equal and list_pos_is_valid functions.
* v1.2 2023-01-20: Renamed list_pos_equal to list_pos_are_equal.
* v1.3 2023-03-23: Renamed list_pos_are_equal to list_pos_is_equal.
* v2.0 2024-05-10: Added print_internal.
*/
// ===========INTERNAL DATA TYPES============
/*
* The list elements are implemented as two-cells with forward and
* backward links and place to store one integer. The list uses two
* border cells at the start and end of the list.
*/
typedef struct cell {
struct cell *next;
struct cell *prev;
int val;
} cell;
struct list {
cell *head;
cell *tail;
};
// ===========INTERNAL FUNCTION IMPLEMENTATIONS============
/**
* list_empty() - Create an empty list.
*
* Returns: A pointer to the new list.
*/
list *list_empty(void)
{
// Allocate memory for the list head.
list *l = calloc(1, sizeof(list));
// Allocate memory for the border cells.
l->head = calloc(1, sizeof(cell));
l->tail = calloc(1, sizeof(cell));
// Set consistent links between border elements.
l->head->next = l->tail;
l->tail->prev = l->head;
return l;
}
/**
* list_is_empty() - Check if a list is empty.
* @l: List to check.
*
* Returns: True if the list is empty, otherwise false.
*/
bool list_is_empty(const list * l)
{
// List is empty if there are no cells between head and tail.
return (l->head->next == l->tail);
}
/**
* list_first() - Return the first position of a list, i.e. the
* position of the first element in the list.
* @l: List to inspect.
*
* Returns: The first position in the given list.
*/
list_pos list_first(const list * l)
{
// First position is position of first element.
return l->head->next;
}
/**
* list_end() - Return the last position of a list, i.e. the position
* after the last element in the list.
* @l: List to inspect.
*
* Returns: The last position in the given list.
*/
list_pos list_end(const list * l)
{
// Last position is position *after* last element.
return l->tail;
}
/**
* list_next() - Return the next position in a list.
* @l: List to inspect.
* @p: Any valid position except the last in the list.
*
* Returns: The position in the list after the given position.
* NOTE: The return value is undefined for the last position.
*/
list_pos list_next(const list * l, const list_pos p)
{
if (list_pos_is_equal(l, p, list_end(l))) {
// This should really throw an error.
fprintf(stderr,"list_next: Warning: Trying to navigate past end of list!");
}
return p->next;
}
/**
* list_prev() - Return the previous position in a list.
* @l: List to inspect.
* @p: Any valid position except the first in the list.
*
* Returns: The position in the list before the given position.
* NOTE: The return value is undefined for the first position.
*/
list_pos list_prev(const list * l, const list_pos p)
{
if (list_pos_is_equal(l, p, list_first(l))) {
// This should really throw an error.
fprintf(stderr,"list_prev: Warning: Trying to navigate "
"past beginning of list!\n");
}
return p->prev;
}
/**
* list_inspect() - Return the value of the element at a given
* position in a list.
* @l: List to inspect.
* @p: Any valid position in the list, except the last.
*
* Returns: The integer value stored in the element at postiion pos.
* NOTE: The return value is undefined for the last position.
*/
int list_inspect(const list * l, const list_pos p)
{
if (list_pos_is_equal(l, p, list_end(l))) {
// This should really throw an error.
fprintf(stderr,"list_inspect: Warning: Trying to inspect "
"position at end of list!\n");
}
return p->val;
}
/**
* list_insert() - Insert a new element with a given value into a list.
* @l: List to manipulate.
* @v: Integer value to be inserted into the list.
* @p: Position in the list before which the value should be inserted.
*
* Creates a new element and inserts it into the list before p.
* Stores data in the new element.
*
* Returns: The position of the newly created element.
*/
list_pos list_insert(list * l, int v, const list_pos p)
{
// Allocate memory for a new cell.
list_pos e = malloc(sizeof(cell));
// Store the value.
e->val = v;
// Add links to/from the new cell.
e->next = p;
e->prev = p->prev;
p->prev = e;
e->prev->next = e;
// Return the position of the new cell.
return e;
}
/**
* list_remove() - Remove an element from a list.
* @l: List to manipulate.
* @p: Position in the list of the element to remove.
*
* Removes the element at position p from the list.
*
* Returns: The position after the removed element.
*/
list_pos list_remove(list *l, const list_pos p)
{
// Remember return position.
list_pos next_pos = p->next;
// Link past this element.
p->prev->next = p->next;
p->next->prev = p->prev;
// Free the memory allocated to the cell itself.
free(p);
// Return the position of the next element.
return next_pos;
}
/**
* list_kill() - Destroy a given list.
* @l: List to destroy.
*
* Returns all dynamic memory used by the list and its elements.
*
* Returns: Nothing.
*/
void list_kill(list * l)
{
// Use public functions to traverse the list.
// Start with the first element (will be defined even for an
// empty list).
list_pos p = list_first(l);
// Remove first element until list is empty.
while (!list_is_empty(l)) {
p = list_remove(l, p);
}
// Free border elements and the list head.
free(l->head);
free(l->tail);
free(l);
}
/**
* list_print() - Iterate over the list element and print their values.
* @l: List to inspect.
*
* Iterates over the list and print each stored integer.
*
* Returns: Nothing.
*/
void list_print(const list * l)
{
// Start at the beginning of the list.
list_pos p = list_first(l);
while (!list_pos_is_equal(l, p, list_end(l))) {
// Call print_func with the element value at the
// current position.
printf("[%d]\n", list_inspect(l, p));
p = list_next(l, p);
}
}
/**
* list_pos_is_equal() - Return true if two positions in a list are equal.
* @l: List to inspect.
* @p1: First position to compare.
* @p2: Second position to compare.
*
* Returns: True if p1 and p2 refer to the same position in l, otherwise False.
* NOTE: The result is defined only if p1 and p2 are valid positions in l.
*/
bool list_pos_is_equal(const list *l, const list_pos p1, const list_pos p2)
{
// Since we don't need to check whether p1 or p2 are valid, we
// only need to compare them directly.
return p1 == p2;
}
/**
* list_pos_is_valid() - Return true for a valid position in a list
* @l: List to inspect.
* @p: Any position.
*
* Returns: True if p is a valid position in the list, otherwise false.
*/
bool list_pos_is_valid(const list *l, const list_pos p)
{
// Iterate over all positions in l.
list_pos q = list_first(l);
while (!list_pos_is_equal(l, q, list_end(l))) {
if (list_pos_is_equal(l, p, q)) {
// We found the position in the list.
return true;
}
// Advance to the next valid position,
q = list_next(l, q);
}
// p was not among valid positions in l.
return false;
}
// ===========INTERNAL FUNCTIONS USED BY int_list_print_internal ============
// The functions below output code in the dot language, used by
// GraphViz. For documention of the dot language, see graphviz.org.
/**
* indent() - Output indentation string.
* @n: Indentation level.
*
* Print n tab characters.
*
* Returns: Nothing.
*/
static void indent(int n)
{
for (int i=0; i<n; i++) {
printf("\t");
}
}
/**
* iprintf(...) - Indent and print.
* @n: Indentation level
* @...: printf arguments
*
* Print n tab characters and calls printf.
*
* Returns: Nothing.
*/
static void iprintf(int n, const char *fmt, ...)
{
// Indent...
indent(n);
// ...and call printf
va_list args;
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
}
/**
* print_edge() - Print a edge between two addresses.
* @from: The address of the start of the edge. Should be non-NULL.
* @to: The address of the destination for the edge, including NULL.
* @port: The name of the port on the source node, or NULL.
* @label: The label for the edge, or NULL.
* @options: A string with other edge options, or NULL.
*
* Print an edge from port PORT on node FROM to TO with label
* LABEL. If to is NULL, the destination is the NULL node, otherwise a
* memory node. If the port is NULL, the edge starts at the node, not
* a specific port on it. If label is NULL, no label is used. The
* options string, if non-NULL, is printed before the label.
*
* Returns: Nothing.
*/
static void print_edge(int indent_level, const void *from, const void *to, const char *port,
const char *label, const char *options)
{
indent(indent_level);
if (port) {
printf("m%04lx:%s -> ", PTR2ADDR(from), port);
} else {
printf("m%04lx -> ", PTR2ADDR(from));
}
if (to == NULL) {
printf("NULL");
} else {
printf("m%04lx", PTR2ADDR(to));
}
printf(" [");
if (options != NULL) {
printf("%s", options);
}
if (label != NULL) {
printf(" label=\"%s\"",label);
}
printf("]\n");
}
/**
* print_head_node() - Print a node corresponding to the list head struct.
* @indent_level: Indentation level.
* @l: List to inspect.
*
* Returns: Nothing.
*/
static void print_head_node(int indent_level, const list *l)
{
iprintf(indent_level, "m%04lx [shape=record "
"label=\"<h>head\\n%04lx|<t>tail\\n%04lx\" xlabel=\"%04lx\"]\n",
PTR2ADDR(l), PTR2ADDR(l->head), PTR2ADDR(l->tail), PTR2ADDR(l));
}
// Print edges from the list head to the head and tail cells.
static void print_head_edges(int indent_level, const list *l)
{
print_edge(indent_level, l, l->head, "h", "head", NULL);
print_edge(indent_level, l, l->tail, "t", "tail", NULL);
}
// Print a node corresponding to the cell at position p.
static void print_elem_node(int indent_level, const list_pos p)
{
iprintf(indent_level, "m%04lx [shape=record "
"label=\"<v>val\\n%d|<n>next\\n%04lx|<p>prev\\n%04lx\" xlabel=\"%04lx\"]\n",
PTR2ADDR(p), p->val, PTR2ADDR(p->next), PTR2ADDR(p->prev), PTR2ADDR(p));
}
// Print edges from the cell at position p to the next and previous
// cells and the value. The value pointer is red, the others are
// black. If the list owns the memory, the edge is solid, otherwise
// dashed.
static void print_elem_edges(int indent_level, const list *l, const list_pos p)
{
print_edge(indent_level, p, p->next, "n", "next", NULL);
print_edge(indent_level, p, p->prev, "p", "prev", NULL);
}
// Create an escaped version of the input string. The most common
// control characters - newline, horizontal tab, backslash, and double
// quote - are replaced by their escape sequence. The returned pointer
// must be deallocated by the caller.
static char *escape_chars(const char *s)
{
int i, j;
int escaped = 0; // The number of chars that must be escaped.
// Count how many chars need to be escaped, i.e. how much longer
// the output string will be.
for (i = escaped = 0; s[i] != '\0'; i++) {
if (s[i] == '\n' || s[i] == '\t' || s[i] == '\\' || s[i] == '\"') {
escaped++;
}
}
// Allocate space for the escaped string. The variable i holds the input
// length, escaped how much the string will grow.
char *t = malloc(i + escaped + 1);
// Copy-and-escape loop
for (i = j = 0; s[i] != '\0'; i++) {
// Convert each control character by its escape sequence.
// Non-control characters are copied as-is.
switch (s[i]) {
case '\n': t[i+j] = '\\'; t[i+j+1] = 'n'; j++; break;
case '\t': t[i+j] = '\\'; t[i+j+1] = 't'; j++; break;
case '\\': t[i+j] = '\\'; t[i+j+1] = '\\'; j++; break;
case '\"': t[i+j] = '\\'; t[i+j+1] = '\"'; j++; break;
default: t[i+j] = s[i]; break;
}
}
// Terminal the output string
t[i+j] = '\0';
return t;
}
/**
* list_print_internal() - Print the lists internal structure in dot format.
* @l: List to inspect.
* @desc: String with a description/state of the list, or NULL for no description.
* @indent_level: Indentation level, 0 for outermost
*
* Iterates over the list and outputs dot code that shows the internal
* structure of the list. The dot code can be visualized by
* Graphviz.
*
* On linux system, the output can be parsed by the dot program, e.g.
*
* <list_program> | dot -Tsvg > /tmp/dot.svg; firefox /tmp/dot.svg
*
* where <list_program> is the name of the executable
*
* The output may also be possible to visualize online on
* https://dreampuf.github.io/GraphvizOnline/ or google "graphviz
* online".
*
* For documention of the dot language, see graphviz.org.
*
* Returns: Nothing.
*/
void list_print_internal(const list *l, const char *desc, int indent_level)
{
static int graph_number = 0;
graph_number++;
int il = indent_level;
if (indent_level == 0) {
// If this is the outermost datatype, start a graph...
printf("digraph LIST_%d {\n", graph_number);
// Specify default shape and fontname
il++;
iprintf(il, "node [shape=rectangle fontname=\"Courier New\"]\n");
iprintf(il, "ranksep=0.01\n");
}
if (desc != NULL) {
// Escape the string before printout
char *escaped = escape_chars(desc);
// Use different names on inner description nodes
if (indent_level == 0) {
iprintf(il, "description [label=\"%s\"]\n", escaped);
} else {
iprintf(il, "\tcluster_int_list_%d_description [label=\"%s\"]\n", graph_number, escaped);
}
// Return the memory used by the escaped string
free(escaped);
}
if (indent_level == 0) {
// Use a single "pointer" edge as a starting point for the
// outermost datatype
iprintf(il, "l [label=\"%04lx\" xlabel=\"l\"]\n", PTR2ADDR(l));
iprintf(il, "l -> m%04lx\n", PTR2ADDR(l));
}
// Print the subgraph to surround the DList content
iprintf(il, "subgraph cluster_int_list_%d { label=\"List\"\n", graph_number);
il++;
// Output the head node
print_head_node(il, l);
// Output the element nodes
list_pos p = l->head;
while (p != NULL) {
print_elem_node(il, p);
p = p->next;
}
// Close the subgraph
il--;
iprintf(il, "}\n");
// Output the edges from the head
print_head_edges(il, l);
// Output the edges from each element
p = l->head;
while (p != NULL) {
print_elem_edges(il, l, p);
p = p->next;
}
if (indent_level == 0) {
// Termination of graph
printf("}\n");
}
}