From 6565364bc9384eb519b6de78ae87502cc6c2bc22 Mon Sep 17 00:00:00 2001 From: william Date: Wed, 1 May 2024 11:45:39 -0400 Subject: [PATCH] Use linked list to navigate through interactive debugger windows --- cpu/cpu.c | 6 +-- cpu/cpu.h | 8 +++- cpu/op.c | 98 ++++++++++++++++++++--------------------- debugger/cpu_view.c | 33 ++++++++++++++ debugger/cpu_view.h | 24 ++++++++++ debugger/debugger.c | 55 +++++++++++++++++------ debugger/program_view.c | 2 +- utils/linked_list.c | 53 +++++++++++++++++++--- utils/linked_list.h | 30 ++++++++++++- 9 files changed, 233 insertions(+), 76 deletions(-) diff --git a/cpu/cpu.c b/cpu/cpu.c index 8a307ef..e044309 100644 --- a/cpu/cpu.c +++ b/cpu/cpu.c @@ -83,11 +83,11 @@ void cpu_add_cycles(System *system, unsigned int cycle_count) { } // === Registers === -bool cpu_get_flag(System *system, byte mask) { - return system->cpu.status & mask; +bool system_get_flag(System *system, byte mask) { + return cpu_get_flag(&system->cpu, mask); } -void cpu_set_flag(System *system, byte mask, bool set) { +void system_set_flag(System *system, byte mask, bool set) { if (set) { system->cpu.status |= mask; } else { diff --git a/cpu/cpu.h b/cpu/cpu.h index a7a14cb..977f6ee 100644 --- a/cpu/cpu.h +++ b/cpu/cpu.h @@ -26,7 +26,11 @@ * @param mask The flag mask * @return The value of the flag. */ -bool cpu_get_flag(System *system, byte mask); +bool system_get_flag(System *system, byte mask); + +static inline bool cpu_get_flag(CPU *cpu, byte mask) { + return cpu->status & mask; +} /** * Sets a flag in the CPU registers. @@ -35,7 +39,7 @@ bool cpu_get_flag(System *system, byte mask); * @param mask The flag mask * @param set If the flag is set or not */ -void cpu_set_flag(System *system, byte mask, bool set); +void system_set_flag(System *system, byte mask, bool set); /** * Gets the next byte in the program. diff --git a/cpu/op.c b/cpu/op.c index 312db48..6290673 100644 --- a/cpu/op.c +++ b/cpu/op.c @@ -122,8 +122,8 @@ byte get_shift_cycle_count(AddressingMode addr_mode) { } void set_acl_flags(System *system, byte result) { - cpu_set_flag(system, CPU_STATUS_ZERO_MASK, result == 0); - cpu_set_flag(system, CPU_STATUS_NEGATIVE_MASK, result & 0x80); + system_set_flag(system, CPU_STATUS_ZERO_MASK, result == 0); + system_set_flag(system, CPU_STATUS_NEGATIVE_MASK, result & 0x80); } byte get_branch_cycle_count(System *system, bool branching, char offset) { @@ -166,15 +166,15 @@ void add_with_carry(System *system, byte value) { } // Add carry flag and check for overflow again - byte result = addition + cpu_get_flag(system, CPU_STATUS_CARRY_MASK); + byte result = addition + system_get_flag(system, CPU_STATUS_CARRY_MASK); if (result < addition) { overflow = true; } system->cpu.accumulator = result; - cpu_set_flag(system, CPU_STATUS_CARRY_MASK, overflow); - cpu_set_flag(system, CPU_STATUS_OVERFLOW_MASK, is_sign_overflow(acc, value, result)); + system_set_flag(system, CPU_STATUS_CARRY_MASK, overflow); + system_set_flag(system, CPU_STATUS_OVERFLOW_MASK, is_sign_overflow(acc, value, result)); set_acl_flags(system, result); } @@ -230,7 +230,7 @@ void op_ASL(System *system, AddressingMode addr_mode) { byte result = value << 1; write_operand(system, operand, result); - cpu_set_flag(system, CPU_STATUS_CARRY_MASK, value & 0x80); + system_set_flag(system, CPU_STATUS_CARRY_MASK, value & 0x80); set_acl_flags(system, result); cpu_add_cycles(system, get_shift_cycle_count(addr_mode)); } @@ -242,17 +242,17 @@ void op_AXS(System *system, AddressingMode addr_mode) { __attribute__((unused)) void op_BCC(System *system, AddressingMode addr_mode) { - op_branch(system, !cpu_get_flag(system, CPU_STATUS_CARRY_MASK)); + op_branch(system, !system_get_flag(system, CPU_STATUS_CARRY_MASK)); } __attribute__((unused)) void op_BCS(System *system, AddressingMode addr_mode) { - op_branch(system, cpu_get_flag(system, CPU_STATUS_CARRY_MASK)); + op_branch(system, system_get_flag(system, CPU_STATUS_CARRY_MASK)); } __attribute__((unused)) void op_BEQ(System *system, AddressingMode addr_mode) { - op_branch(system, cpu_get_flag(system, CPU_STATUS_ZERO_MASK)); + op_branch(system, system_get_flag(system, CPU_STATUS_ZERO_MASK)); } __attribute__((unused)) @@ -263,24 +263,24 @@ void op_BIT(System *system, AddressingMode addr_mode) { byte result = value & acc; - cpu_set_flag(system, CPU_STATUS_ZERO_MASK, result == 0); - cpu_set_flag(system, CPU_STATUS_OVERFLOW_MASK, value & 0x40); - cpu_set_flag(system, CPU_STATUS_NEGATIVE_MASK, value & 0x80); + system_set_flag(system, CPU_STATUS_ZERO_MASK, result == 0); + system_set_flag(system, CPU_STATUS_OVERFLOW_MASK, value & 0x40); + system_set_flag(system, CPU_STATUS_NEGATIVE_MASK, value & 0x80); } __attribute__((unused)) void op_BMI(System *system, AddressingMode addr_mode) { - op_branch(system, cpu_get_flag(system, CPU_STATUS_NEGATIVE_MASK)); + op_branch(system, system_get_flag(system, CPU_STATUS_NEGATIVE_MASK)); } __attribute__((unused)) void op_BNE(System *system, AddressingMode addr_mode) { - op_branch(system, !cpu_get_flag(system, CPU_STATUS_ZERO_MASK)); + op_branch(system, !system_get_flag(system, CPU_STATUS_ZERO_MASK)); } __attribute__((unused)) void op_BPL(System *system, AddressingMode addr_mode) { - op_branch(system, !cpu_get_flag(system, CPU_STATUS_NEGATIVE_MASK)); + op_branch(system, !system_get_flag(system, CPU_STATUS_NEGATIVE_MASK)); } // Stops program execution, useful for debugging @@ -292,41 +292,41 @@ void op_BRK(System *system, AddressingMode addr_mode) { assert(false); - cpu_set_flag(system, CPU_STATUS_B_MASK, true); + system_set_flag(system, CPU_STATUS_B_MASK, true); cpu_add_cycles(system, 7); } __attribute__((unused)) void op_BVC(System *system, AddressingMode addr_mode) { - op_branch(system, !cpu_get_flag(system, CPU_STATUS_OVERFLOW_MASK)); + op_branch(system, !system_get_flag(system, CPU_STATUS_OVERFLOW_MASK)); } __attribute__((unused)) void op_BVS(System *system, AddressingMode addr_mode) { - op_branch(system, cpu_get_flag(system, CPU_STATUS_OVERFLOW_MASK)); + op_branch(system, system_get_flag(system, CPU_STATUS_OVERFLOW_MASK)); } __attribute__((unused)) void op_CLC(System *system, AddressingMode addr_mode) { - cpu_set_flag(system, CPU_STATUS_CARRY_MASK, false); + system_set_flag(system, CPU_STATUS_CARRY_MASK, false); cpu_add_cycles(system, 2); } __attribute__((unused)) void op_CLD(System *system, AddressingMode addr_mode) { - cpu_set_flag(system, CPU_STATUS_DECIMAL_MASK, false); + system_set_flag(system, CPU_STATUS_DECIMAL_MASK, false); cpu_add_cycles(system, 2); } __attribute__((unused)) void op_CLI(System *system, AddressingMode addr_mode) { - cpu_set_flag(system, CPU_STATUS_INTERRUPT_DISABLE_MASK, false); + system_set_flag(system, CPU_STATUS_INTERRUPT_DISABLE_MASK, false); cpu_add_cycles(system, 2); } __attribute__((unused)) void op_CLV(System *system, AddressingMode addr_mode) { - cpu_set_flag(system, CPU_STATUS_OVERFLOW_MASK, false); + system_set_flag(system, CPU_STATUS_OVERFLOW_MASK, false); cpu_add_cycles(system, 2); } @@ -338,9 +338,9 @@ void op_CMP(System *system, AddressingMode addr_mode) { byte result = acc - value; - cpu_set_flag(system, CPU_STATUS_CARRY_MASK, acc >= value); - cpu_set_flag(system, CPU_STATUS_ZERO_MASK, result == 0); - cpu_set_flag(system, CPU_STATUS_NEGATIVE_MASK, result & 0x80); + system_set_flag(system, CPU_STATUS_CARRY_MASK, acc >= value); + system_set_flag(system, CPU_STATUS_ZERO_MASK, result == 0); + system_set_flag(system, CPU_STATUS_NEGATIVE_MASK, result & 0x80); cpu_add_cycles(system, get_cycle_count(operand, addr_mode)); } @@ -353,9 +353,9 @@ void op_CPX(System *system, AddressingMode addr_mode) { byte result = x - value; - cpu_set_flag(system, CPU_STATUS_CARRY_MASK, x >= value); - cpu_set_flag(system, CPU_STATUS_ZERO_MASK, result == 0); - cpu_set_flag(system, CPU_STATUS_NEGATIVE_MASK, result & 0x80); + system_set_flag(system, CPU_STATUS_CARRY_MASK, x >= value); + system_set_flag(system, CPU_STATUS_ZERO_MASK, result == 0); + system_set_flag(system, CPU_STATUS_NEGATIVE_MASK, result & 0x80); cpu_add_cycles(system, get_cycle_count(operand, addr_mode)); } @@ -368,9 +368,9 @@ void op_CPY(System *system, AddressingMode addr_mode) { byte result = y - value; - cpu_set_flag(system, CPU_STATUS_CARRY_MASK, y >= value); - cpu_set_flag(system, CPU_STATUS_ZERO_MASK, result == 0); - cpu_set_flag(system, CPU_STATUS_NEGATIVE_MASK, result & 0x80); + system_set_flag(system, CPU_STATUS_CARRY_MASK, y >= value); + system_set_flag(system, CPU_STATUS_ZERO_MASK, result == 0); + system_set_flag(system, CPU_STATUS_NEGATIVE_MASK, result & 0x80); cpu_add_cycles(system, get_cycle_count(operand, addr_mode)); } @@ -384,9 +384,9 @@ void op_DCP(System *system, AddressingMode addr_mode) { byte result = value - 1; byte cmp_result = acc - result; - cpu_set_flag(system, CPU_STATUS_CARRY_MASK, acc >= value); - cpu_set_flag(system, CPU_STATUS_ZERO_MASK, cmp_result == 0); - cpu_set_flag(system, CPU_STATUS_NEGATIVE_MASK, cmp_result & 0x80); + system_set_flag(system, CPU_STATUS_CARRY_MASK, acc >= value); + system_set_flag(system, CPU_STATUS_ZERO_MASK, cmp_result == 0); + system_set_flag(system, CPU_STATUS_NEGATIVE_MASK, cmp_result & 0x80); write_operand(system, operand, result); @@ -595,7 +595,7 @@ void op_LSR(System *system, AddressingMode addr_mode) { byte value = read_operand(system, operand); // Put bit 0 in the carry flag - cpu_set_flag(system, CPU_STATUS_CARRY_MASK, value & 0x01); + system_set_flag(system, CPU_STATUS_CARRY_MASK, value & 0x01); value >>= 1; write_operand(system, operand, value); @@ -640,7 +640,7 @@ void op_PHP(System *system, AddressingMode addr_mode) { byte status = system->cpu.status; cpu_stack_push(system, status); -// cpu_set_flag(system, CPU_STATUS_B_MASK, true); +// system_set_flag(system, CPU_STATUS_B_MASK, true); cpu_add_cycles(system, 3); } @@ -671,10 +671,10 @@ __attribute__((unused)) void op_RLA(System *system, AddressingMode addr_mode) { Operand operand = decode_operand(system, addr_mode); byte value = read_operand(system, operand); - byte carry = cpu_get_flag(system, CPU_STATUS_CARRY_MASK); + byte carry = system_get_flag(system, CPU_STATUS_CARRY_MASK); byte acc = system->cpu.accumulator; - cpu_set_flag(system, CPU_STATUS_CARRY_MASK, value & 0x80); + system_set_flag(system, CPU_STATUS_CARRY_MASK, value & 0x80); value = (value << 1) | carry; byte and_result = acc & value; @@ -690,9 +690,9 @@ __attribute__((unused)) void op_ROL(System *system, AddressingMode addr_mode) { Operand operand = decode_operand(system, addr_mode); byte value = read_operand(system, operand); - byte carry = cpu_get_flag(system, CPU_STATUS_CARRY_MASK); + byte carry = system_get_flag(system, CPU_STATUS_CARRY_MASK); - cpu_set_flag(system, CPU_STATUS_CARRY_MASK, value & 0x80); + system_set_flag(system, CPU_STATUS_CARRY_MASK, value & 0x80); value = (value << 1) | carry; write_operand(system, operand, value); @@ -704,9 +704,9 @@ __attribute__((unused)) void op_ROR(System *system, AddressingMode addr_mode) { Operand operand = decode_operand(system, addr_mode); byte value = read_operand(system, operand); - byte carry = cpu_get_flag(system, CPU_STATUS_CARRY_MASK); + byte carry = system_get_flag(system, CPU_STATUS_CARRY_MASK); - cpu_set_flag(system, CPU_STATUS_CARRY_MASK, value & 0x01); + system_set_flag(system, CPU_STATUS_CARRY_MASK, value & 0x01); value = (value >> 1) | (carry << 7); write_operand(system, operand, value); @@ -718,9 +718,9 @@ __attribute__((unused)) void op_RRA(System *system, AddressingMode addr_mode) { Operand operand = decode_operand(system, addr_mode); byte value = read_operand(system, operand); - byte carry = cpu_get_flag(system, CPU_STATUS_CARRY_MASK); + byte carry = system_get_flag(system, CPU_STATUS_CARRY_MASK); - cpu_set_flag(system, CPU_STATUS_CARRY_MASK, value & 0x01); + system_set_flag(system, CPU_STATUS_CARRY_MASK, value & 0x01); value = (value >> 1) | (carry << 7); add_with_carry(system, value); write_operand(system, operand, value); @@ -770,19 +770,19 @@ void op_SBC(System *system, AddressingMode addr_mode) { __attribute__((unused)) void op_SEC(System *system, AddressingMode addr_mode) { - cpu_set_flag(system, CPU_STATUS_CARRY_MASK, true); + system_set_flag(system, CPU_STATUS_CARRY_MASK, true); cpu_add_cycles(system, 2); } __attribute__((unused)) void op_SED(System *system, AddressingMode addr_mode) { - cpu_set_flag(system, CPU_STATUS_DECIMAL_MASK, true); + system_set_flag(system, CPU_STATUS_DECIMAL_MASK, true); cpu_add_cycles(system, 2); } __attribute__((unused)) void op_SEI(System *system, AddressingMode addr_mode) { - cpu_set_flag(system, CPU_STATUS_INTERRUPT_DISABLE_MASK, true); + system_set_flag(system, CPU_STATUS_INTERRUPT_DISABLE_MASK, true); cpu_add_cycles(system, 2); } @@ -808,7 +808,7 @@ void op_SLO(System *system, AddressingMode addr_mode) { write_operand(system, operand, result); - cpu_set_flag(system, CPU_STATUS_CARRY_MASK, value & 0x80); + system_set_flag(system, CPU_STATUS_CARRY_MASK, value & 0x80); set_acl_flags(system, acc); cpu_add_cycles(system, get_shift_cycle_count(addr_mode)); } @@ -820,7 +820,7 @@ void op_SRE(System *system, AddressingMode addr_mode) { byte acc = system->cpu.accumulator; // Put bit 0 in the carry flag - cpu_set_flag(system, CPU_STATUS_CARRY_MASK, value & 0x01); + system_set_flag(system, CPU_STATUS_CARRY_MASK, value & 0x01); value >>= 1; acc ^= value; diff --git a/debugger/cpu_view.c b/debugger/cpu_view.c index e110c11..d5a14cc 100644 --- a/debugger/cpu_view.c +++ b/debugger/cpu_view.c @@ -2,4 +2,37 @@ // Created by william on 4/30/24. // +#include #include "cpu_view.h" +#include "../cpu/cpu.h" + +void cv_print(CpuView *view) { + window_print(view->window, 0, 0, "PC: $%04x", view->cpu->program_counter); + window_print(view->window, 0, 1, "SP: %02x", view->cpu->stack_pointer); + window_print(view->window, 0, 2, "A: %02x", view->cpu->accumulator); + window_print(view->window, 0, 3, "X: %02x", view->cpu->x); + window_print(view->window, 0, 4, "Y: %02x", view->cpu->y); + window_print(view->window, 0, 5, "C: %01x", cpu_get_flag(view->cpu, CPU_STATUS_CARRY_MASK)); + window_print(view->window, 0, 6, "Z: %01x", cpu_get_flag(view->cpu, CPU_STATUS_ZERO_MASK)); + window_print(view->window, 0, 7, "I: %01x", cpu_get_flag(view->cpu, CPU_STATUS_INTERRUPT_DISABLE_MASK)); + window_print(view->window, 0, 8, "D: %01x", cpu_get_flag(view->cpu, CPU_STATUS_DECIMAL_MASK)); + window_print(view->window, 0, 9, "B: %01x", cpu_get_flag(view->cpu, CPU_STATUS_B_MASK)); + window_print(view->window, 0, 10, "O: %01x", cpu_get_flag(view->cpu, CPU_STATUS_OVERFLOW_MASK)); + window_print(view->window, 0, 11, "N: %01x", cpu_get_flag(view->cpu, CPU_STATUS_NEGATIVE_MASK)); +} + +CpuView *cv_init(CPU *cpu, int x, int y) { + CpuView *view = malloc(sizeof(CpuView)); + view->window = malloc(sizeof(Window)); + view->cpu = cpu; + + window_init(view->window, x, y, CPU_VIEW_WIDTH, CPU_VIEW_HEIGHT, "CPU VIEW"); + cv_print(view); + + return view; +} + +void cv_uninit(CpuView *view) { + free(view->window); + free(view); +} \ No newline at end of file diff --git a/debugger/cpu_view.h b/debugger/cpu_view.h index d727595..6d0d699 100644 --- a/debugger/cpu_view.h +++ b/debugger/cpu_view.h @@ -5,4 +5,28 @@ #ifndef NESEMULATOR_CPU_VIEW_H #define NESEMULATOR_CPU_VIEW_H +#include "window.h" +#include "../include/types.h" +#include "../include/cpu.h" + +#define CPU_VIEW_HEIGHT 14 +#define CPU_VIEW_WIDTH 12 + +typedef struct cpu_view { + Window *window; + CPU *cpu; +} CpuView; + +/** + * Initializes a CPU view for a system RAM. + * + * @param interact + * @param ram + * @param x + * @param y + */ +CpuView *cv_init(CPU *cpu, int x, int y); + +void cv_uninit(CpuView *cpu_view); + #endif //NESEMULATOR_CPU_VIEW_H diff --git a/debugger/debugger.c b/debugger/debugger.c index ae4b3fc..ecab5fb 100644 --- a/debugger/debugger.c +++ b/debugger/debugger.c @@ -9,8 +9,9 @@ #include "memory_view.h" #include "program_view.h" #include "keys.h" +#include "cpu_view.h" -void create_window() { +void debugger_create_window() { setenv("TERMINFO", "/usr/share/terminfo", 1); setenv("TERM", "xterm", 1); @@ -21,15 +22,45 @@ void create_window() { keypad(stdscr, true); } +LinkedList debugger_create_interactive_windows(System *system) { + LinkedList interactive_windows; + InteractWindow *window; + + interactive_windows = linked_list_init(true); + + window = malloc(sizeof(InteractWindow)); + mv_init(window, system->ram, 0, 0); + linked_list_add(&interactive_windows, window); + + window = malloc(sizeof(InteractWindow)); + pv_init(window, system, MEMORY_VIEW_WIDTH, 0); + linked_list_add(&interactive_windows, window); + + return interactive_windows; +} + +void debugger_uninit_interactive_windows(LinkedList *windows) { + linked_list_cursor_reset(windows); + InteractWindow *window = windows->current->data; + + for (int i = 0; i < windows->size; i++) { + window_inter_deinit(window); + window = linked_list_next(windows)->data; + } + + linked_list_uninit(windows); +} + void start_debugger(System *system) { - InteractWindow windows[2]; - size_t window_index = 0; - InteractWindow *current_window = &windows[window_index]; + CpuView *cpu_view; + LinkedList interactive_windows; + InteractWindow *current_window; - create_window(); + debugger_create_window(); - mv_init(&windows[0], system->ram, 0, 0); - pv_init(&windows[1], system, MEMORY_VIEW_WIDTH, 0); + interactive_windows = debugger_create_interactive_windows(system); + current_window = interactive_windows.current->data; + cpu_view = cv_init(&system->cpu, MEMORY_VIEW_WIDTH + PROGRAM_VIEW_WIDTH, 0); cursor_enable(¤t_window->cursor); @@ -39,13 +70,9 @@ void start_debugger(System *system) { int keycode; while ((keycode = getch()) != KEY_EXIT_DEBUGGER) { if (keycode == KEY_NEXT_VIEW) { - window_index++; - if (window_index > 1) { - window_index = 0; - } cursor_disable(¤t_window->cursor); - current_window = &windows[window_index]; + current_window = linked_list_next(&interactive_windows)->data; cursor_enable(¤t_window->cursor); } else if (keycode == KEY_VIEW_UP) { current_window->handle_cursor_move(current_window, 0, CURSOR_OFFSET_UP); @@ -63,8 +90,8 @@ void start_debugger(System *system) { doupdate(); } - window_inter_deinit(&windows[0]); - window_inter_deinit(&windows[1]); + debugger_uninit_interactive_windows(&interactive_windows); + cv_uninit(cpu_view); endwin(); } \ No newline at end of file diff --git a/debugger/program_view.c b/debugger/program_view.c index 9a0b1d9..3b0fe76 100644 --- a/debugger/program_view.c +++ b/debugger/program_view.c @@ -188,7 +188,7 @@ void pv_init(InteractWindow *interact, System *system, int x, int y) { view->window = interact; view->ram = system->ram; view->pc = &system->cpu.program_counter; - view->operands = linked_list_init(); + view->operands = linked_list_init(false); interact->view = view; interact->handle_cursor_move = &pv_handle_cursor_move; diff --git a/utils/linked_list.c b/utils/linked_list.c index 9a0d152..897c71c 100644 --- a/utils/linked_list.c +++ b/utils/linked_list.c @@ -8,14 +8,21 @@ #include #include "linked_list.h" -LinkedList linked_list_init() { +LinkedList linked_list_init(bool circular) { LinkedList list; + + list.circular = circular; + list.size = 0; list.head = NULL; list.end = NULL; + list.current = NULL; + return list; } void linked_list_add(LinkedList *list, void *data) { + assert(list != NULL); + LinkedListNode *node = malloc(sizeof(LinkedListNode)); if (node == NULL) { perror("Failed to allocate memory for linked list node"); @@ -24,20 +31,48 @@ void linked_list_add(LinkedList *list, void *data) { node->data = data; node->previous = list->end; - node->next = NULL; if (list->head == NULL) { list->head = node; + list->current = node; } if (list->end != NULL) { list->end->next = node; } + if (list->circular) { + node->next = list->head; + } else { + node->next = NULL; + } + list->end = node; + list->size++; +} + +LinkedListNode *linked_list_next(LinkedList* list) { + assert(list != NULL); + + if (list->head == NULL) { + return NULL; + } + + LinkedListNode *next = list->current->next; + list->current = next; + return next; +} + +void linked_list_cursor_reset(LinkedList *list) { + assert(list != NULL); + + list->current = list->head; } LinkedListNode *linked_list_get_if(LinkedList *list, bool(*predicate)(void *, void *), void *userdata) { + assert(list != NULL); + assert(predicate != NULL); + LinkedListNode *node = list->head; while (node != NULL) { @@ -51,10 +86,13 @@ LinkedListNode *linked_list_get_if(LinkedList *list, bool(*predicate)(void *, vo return NULL; } -LinkedListNode *linked_list_get_near(LinkedList *list, int(*predicate)(void *, void *), void *userdata) { +LinkedListNode *linked_list_get_near(LinkedList *list, int(*compute_distance)(void *, void *), void *userdata) { + assert(list != NULL); + assert(compute_distance != NULL); + LinkedListNode *near_node = list->head; - int current_distance = predicate(near_node->data, userdata); + int current_distance = compute_distance(near_node->data, userdata); if (current_distance == 0) { return near_node; } @@ -65,7 +103,7 @@ LinkedListNode *linked_list_get_near(LinkedList *list, int(*predicate)(void *, v while (current_distance < last_distance && near_node->next != NULL) { node = near_node->next; last_distance = current_distance; - current_distance = predicate(node->data, userdata); + current_distance = compute_distance(node->data, userdata); } // After the loop, we have found the nearest node in the list, assuming there is only one point of convergence @@ -82,5 +120,10 @@ void linked_list_uninit(LinkedList *list) { free(current_node->data); free(current_node); + + if (node == list->head) { + // The list may be circular, we don't want an infinite free loop + break; + } } } \ No newline at end of file diff --git a/utils/linked_list.h b/utils/linked_list.h index b3c9ca8..6e293d3 100644 --- a/utils/linked_list.h +++ b/utils/linked_list.h @@ -14,16 +14,20 @@ typedef struct linked_list_node { } LinkedListNode; typedef struct linked_list { + bool circular; + unsigned int size; LinkedListNode *head; LinkedListNode *end; + LinkedListNode *current; } LinkedList; /** * Initializes a new linked list. * + * @param circular If the list is circular, meaning that the last node is linked to the first node. * @return The linked list instance */ -LinkedList linked_list_init(); +LinkedList linked_list_init(bool circular); /** * Adds data to a linked list. @@ -33,6 +37,19 @@ LinkedList linked_list_init(); */ void linked_list_add(LinkedList *list, void *data); +/** + * Gets the next node in the list. + * + * @param list The linked list + * @return The next node in the list. Can be NULL if the list is empty or depleted. + */ +LinkedListNode *linked_list_next(LinkedList *list); + +/** + * Resets the position of the cursor to the head of the list. + */ +void linked_list_cursor_reset(LinkedList *list); + /** * Searches for data corresponding to a predicate. * The search will stop after reaching the first node matching the given predicate. @@ -44,7 +61,16 @@ void linked_list_add(LinkedList *list, void *data); */ LinkedListNode *linked_list_get_if(LinkedList *list, bool(*predicate)(void *, void *), void *userdata); -LinkedListNode *linked_list_get_near(LinkedList *list, int(*predicate)(void *, void *), void *userdata); +/** + * Searches for data with the smallest distance computed from a function. + * The search will stop when a node increasing the distance is found. For this reason, the distance computing function should have a single minimum. + * + * @param list The list to search in + * @param compute_distance The function to compute the distance of a node's data + * @param userdata Parameter to pass to the function + * @return The node with the smallest distance + */ +LinkedListNode *linked_list_get_near(LinkedList *list, int(*compute_distance)(void *, void *), void *userdata); /** * Deinitializes a linked list.