Use linked list to navigate through interactive debugger windows

This commit is contained in:
william 2024-05-01 11:45:39 -04:00
parent e5e972fc4a
commit 6565364bc9
9 changed files with 233 additions and 76 deletions

View File

@ -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 {

View File

@ -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.

View File

@ -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;

View File

@ -2,4 +2,37 @@
// Created by william on 4/30/24.
//
#include <stdlib.h>
#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);
}

View File

@ -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

View File

@ -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(&current_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(&current_window->cursor);
current_window = &windows[window_index];
current_window = linked_list_next(&interactive_windows)->data;
cursor_enable(&current_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();
}

View File

@ -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;

View File

@ -8,14 +8,21 @@
#include <assert.h>
#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;
}
}
}

View File

@ -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.