Got everything, just need to change comments and do the menu

This commit is contained in:
2026-03-21 22:13:19 -06:00
commit 96006ff170
8 changed files with 972 additions and 0 deletions

149
.gitignore vendored Normal file
View File

@@ -0,0 +1,149 @@
##Doxygen
docs
Doxyfile
images
# Prerequisites
*.d
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Linker files
*.ilk
# Debugger Files
*.pdb
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
*.so.*
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
# Build directories
build/
Build/
build-*/
out
out/Debug
# CMake generated files
CMakeFiles/
CMakeCache.txt
cmake_install.cmake
Makefile
install_manifest.txt
compile_commands.json
# Temporary files
*.tmp
*.log
*.bak
*.swp
# vcpkg
vcpkg_installed/
# debug information files
*.dwo
# test output & cache
Testing/
.cache/Doxygen
docs
Doxyfile
images
# Prerequisites
*.d
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Linker files
*.ilk
# Debugger Files
*.pdb
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
*.so.*
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
# Build directories
build/
Build/
build-*/
# CMake generated files
CMakeFiles/
CMakeCache.txt
cmake_install.cmake
Makefile
install_manifest.txt
compile_commands.json
# Temporary files
*.tmp
*.log
*.bak
*.swp
# vcpkg
vcpkg_installed/
# debug information files
*.dwo
# test output & cache
Testing/
.cache/

33
CMakeLists.txt Normal file
View File

@@ -0,0 +1,33 @@
cmake_minimum_required(VERSION 3.16)
project(LinkedList
VERSION 1.0
LANGUAGES CXX
)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
add_compile_options(
-Wall
-Wextra
-Wpedantic
)
add_executable(main_exec
src/main.cpp
src/utils.cpp
)
target_include_directories(main_exec
PRIVATE
${PROJECT_SOURCE_DIR}/include
)
enable_testing()
add_subdirectory(test)

352
include/linkedlist.h Normal file
View File

@@ -0,0 +1,352 @@
#ifndef LINKEDLIST_H
#define LINKEDLIST_H
#include <cstdlib>
#include <expected>
#include <new>
#include <print>
/**
* @brief Codigos de error para operaciones de LinkedList
*/
enum class LinkedListErr {
LINKEDLIST_OK, /**< Operacin exitosa */
LINKEDLIST_BAD_ALLOC, /**< Error al asignar memoria */
LINKEDLIST_OUT_OF_BOUNDS, /**< Índice fuera de rango */
LINKESLIST_INVALID_SIZE, /**< Tamaño inválido */
LINKEDLIST_NOT_FOUND, /**< Elemento no encontrado */
LINKEDLIST_EMPTY, /**< La lista está vacia */
};
/**
* @brief Nodo de una lista enlazada
*
* @tparam T Tipo de dato almacenado en el nodo
*/
template<typename T>
class Node {
public:
T data; /**< Dato almacenado en el nodo */
Node<T> *next; /**< Puntero al siguiente nodo */
};
/**
* @brief Implementación de una lista enlazada simple
*
* Estructura de datos dinamica que almacena elementos de tipo T
* utilizando nodos enlazados mediante punteros.
*
* @tparam T Tipo de dato almacenado en la lista
*/
template<typename T>
class LinkedList {
private:
size_t size; /**< Numero de elementos en la lista */
Node<T> *head; /**< Primer nodo de la lista */
Node<T> *tail; /**< Último nodo de la lista */
public:
/**
* @brief Constructor de la lista enlazada
*/
LinkedList();
/**
* @brief Destructor de la lista
*
* Libera toda la memoria de los nodos.
*/
~LinkedList();
/**
* @brief Obtiene el elemento en una posicion específica
*
* @param index indice del elemento
* @return std::expected<T, LinkedListErr> Valor encontrado o error
*/
std::expected<T, LinkedListErr> get(size_t index);
/**
* @brief Inserta un elemento al final de la lista
*
* @param value Valor a insertar
* @return LinkedListErr Cdigo de estado de la operacion
*/
LinkedListErr append(const T& value);
/**
* @brief Inserta un elemento al inicio de la lista
*
* @param value Valor a insertar
* @return LinkedListErr Codigo de estado
*/
LinkedListErr prepend(const T& value);
/**
* @brief Elimina y devuelve el ultimo elemento de la lista
*
* @return std::expected<T, LinkedListErr> Elemento eliminado o error
*/
std::expected<T, LinkedListErr> pop();
/**
* @brief Elimina el elemento en una posicion especifica
*
* @param index Indice del elemento a eliminar
* @return LinkedListErr Codigo de estado
*/
LinkedListErr remove(size_t index);
/**
* @brief Modifica el valor de un elemento en un indice
*
* @param index Índice del elemento
* @param value Nuevo valor
* @return LinkedListErr Código de estado
*/
LinkedListErr set(size_t index, const T& value);
/**
* @brief Busca un valor dentro de la lista
*
* @param value Valor a buscar
* @return std::expected<size_t, LinkedListErr> Índice del elemento o error
*/
std::expected<size_t, LinkedListErr> find(const T& value);
/**
* @brief Imprime los elementos de la lista
*
* @return LinkedListErr Código de estado
*/
LinkedListErr print();
/**
* @brief Verifica si la lista esta vacia
*
* @return true si la lista no contiene elementos
*/
bool is_empty();
/**
* @brief Obtiene el numero de elementos de la lista
*
* @return size_t Tamaño de la lista
*/
size_t len();
};
template <typename T>
LinkedList<T>::LinkedList() {
size = 0;
head = nullptr;
tail = nullptr;
}
template <typename T>
LinkedList<T>::~LinkedList() {
Node<T> *current = this->head;
while (current != nullptr) {
Node<T> *temp = current;
current = current->next;
delete temp;
}
}
template <typename T>
std::expected<T, LinkedListErr> LinkedList<T>::get(size_t index) {
if (index >= this->size) {
return std::unexpected(LinkedListErr::LINKEDLIST_OUT_OF_BOUNDS);
}
if (index == this->size - 1) {
return tail->data;
}
Node<T> *current = this->head;
for (size_t i = 0; i < index ; i++) {
current = current->next;
}
return current->data;
}
template <typename T>
LinkedListErr LinkedList<T>::set(size_t index, const T& val) {
if (index >= this->size) {
return LinkedListErr::LINKEDLIST_OUT_OF_BOUNDS;
}
if (index == this->size - 1) {
this->tail->data = val;
}
Node<T> *current = this->head;
for (size_t i = 0; i < index; i++) {
current = current->next;
}
current->data = val;
return LinkedListErr::LINKEDLIST_OK;
}
template <typename T>
LinkedListErr LinkedList<T>::append(const T& value) {
Node<T> *new_node = nullptr;
try {
new_node = new Node<T>;
} catch(std::bad_alloc&) {
return LinkedListErr::LINKEDLIST_BAD_ALLOC;
}
new_node->data = value;
new_node->next = nullptr;
if (this->head == nullptr && this->tail == nullptr) {
this->head = new_node;
this->tail = this->head;
} else {
this->tail->next = new_node;
this->tail = this->tail->next;
}
this->size += 1;
return LinkedListErr::LINKEDLIST_OK;
}
template <typename T>
LinkedListErr LinkedList<T>::prepend(const T& value) {
Node<T> *new_node = nullptr;
try {
new_node = new Node<T>;
} catch(std::bad_alloc&) {
return LinkedListErr::LINKEDLIST_BAD_ALLOC;
}
new_node->data = value;
new_node->next = nullptr;
if (this->head == nullptr && this->tail == nullptr) {
this->head = new_node;
this->tail = this->head;
} else {
new_node->next = this->head;
this->head = new_node;
}
this->size += 1;
return LinkedListErr::LINKEDLIST_OK;
}
template <typename T>
std::expected<T, LinkedListErr> LinkedList<T>::pop() {
if (this->size == 0) {
return std::unexpected(LinkedListErr::LINKEDLIST_EMPTY);
}
if (this->head->next == nullptr) {
T return_val = this->head->data;
delete this->head;
this->head = nullptr;
this->size--;
return return_val;
}
Node<T>* current = this->head;
while (current->next->next != nullptr) {
current = current->next;
}
T return_val = current->next->data;
delete current->next;
current->next = nullptr;
this->size--;
return return_val;
}
template <typename T>
LinkedListErr LinkedList<T>::remove(size_t index) {
if (index >= this->size) {
return LinkedListErr::LINKEDLIST_OUT_OF_BOUNDS;
}
if (index == 0) {
Node<T>* tmp = this->head;
this->head = this->head->next;
delete tmp;
this->size--;
return LinkedListErr::LINKEDLIST_OK;
}
Node<T>* current = this->head;
for (size_t i = 1; i < index; ++i) {
current = current->next;
}
Node<T>* tmp = current->next;
current->next = tmp->next;
if(tmp == this->tail) {
this->tail = current;
}
delete tmp;
this->size--;
return LinkedListErr::LINKEDLIST_OK;
}
template <typename T>
std::expected<size_t, LinkedListErr> LinkedList<T>::find(const T& value) {
Node<T> *current = this->head;
size_t count = 0;
while (current != nullptr) {
if (current->data == value) {
return count;
}
count++;
current = current->next;
}
return std::unexpected(LinkedListErr::LINKEDLIST_NOT_FOUND);
}
template <typename T>
LinkedListErr LinkedList<T>::print() {
if (this->size == 0) {
return LinkedListErr::LINKEDLIST_OK;
}
std::println("[LL]");
std::println(" |\n v");
Node<T> *current = this->head;
while (current != nullptr) {
std::println("Node({})", current->data);
std::println(" |");
std::println(" v");
current = current->next;
}
std::println("NULL");
return LinkedListErr::LINKEDLIST_OK;
}
template <typename T>
size_t LinkedList<T>::len() {
return this->size;
}
#endif // !

14
include/utils.h Normal file
View File

@@ -0,0 +1,14 @@
#ifndef UTILS_H
#define UTILS_H
#include <stddef.h>
#include <stdio.h>
void clear_screen();
void wait_enter();
void sleep_seconds(size_t s);
void read_string(const char *message, char **dest);
int read_int(const char *message, int *dest);
int read_double(const char *message, double *dest);
#endif // !

8
src/main.cpp Normal file
View File

@@ -0,0 +1,8 @@
#include "linkedlist.h"
#include <cstdlib>
#include <print>
int main(void) {
std::print("hi");
return EXIT_SUCCESS;
}

129
src/utils.cpp Normal file
View File

@@ -0,0 +1,129 @@
#include "utils.h"
#include <limits.h>
#include <stdlib.h>
#include <errno.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
void clear_screen() {
printf("\033[2J\033[H");
fflush(stdout);
}
void wait_enter() {
int c;
printf("Press Enter to continue...");
fflush(stdout);
while ((c = getchar()) != '\n' && c != EOF) {
;
}
}
void sleep_seconds(size_t s) {
#ifdef _WIN32
#include <windows.h>
Sleep(s * 1000);
#else
// #include <unistd.h>
// sleep(s);
#endif /* ifdef _WIN32
*/
}
void read_string(const char *message, char **dest) {
if (!dest) {
return;
}
printf("%s", message);
char buffer[256]; // I mean, should be enough
if (!fgets(buffer, sizeof(buffer), stdin))
return;
buffer[strcspn(buffer, "\n")] = '\0';
char *tmp = static_cast<char *>(malloc(strlen(buffer) + 1));
if (!tmp) {
return;
}
strcpy(tmp, buffer);
free(*dest);
*dest = tmp;
}
int read_int(const char *message, int *dest) {
char buffer[64];
char *end;
long value;
printf("%s", message);
fflush(stdout);
if (!fgets(buffer, sizeof(buffer), stdin)) {
return 0;
}
errno = 0;
value = strtol(buffer, &end, 10);
if (errno != 0) {
return 0;
}
if (end == buffer) {
return 0;
}
if (*end != '\n' && *end != '\0') {
return 0;
}
if (value < INT_MIN || value > INT_MAX) {
return 0;
}
*dest = (int)value;
return 1;
}
int read_double(const char *message, double *dest) {
char buffer[64];
char *end;
double value;
printf("%s", message);
fflush(stdout);
if (!fgets(buffer, sizeof(buffer), stdin)) {
return 0;
}
errno = 0;
value = strtod(buffer, &end);
if (errno != 0) {
return 0;
}
if (end == buffer) {
return 0;
}
if (*end != '\n' && *end != '\0') {
return 0;
}
if (!isfinite(value)) {
return 0;
}
*dest = value;
return 1;
}

38
test/CMakeLists.txt Normal file
View File

@@ -0,0 +1,38 @@
include(FetchContent)
FetchContent_Declare(
Catch2
GIT_REPOSITORY https://github.com/catchorg/Catch2.git
GIT_TAG v3.5.3
)
FetchContent_MakeAvailable(Catch2)
add_executable(test_linkedlist
test_linkedlist.cpp
)
target_include_directories(test_linkedlist
PRIVATE
${PROJECT_SOURCE_DIR}/include
)
target_link_libraries(test_linkedlist
PRIVATE
Catch2::Catch2WithMain
)
target_compile_options(test_linkedlist PRIVATE
-fsanitize=address
-fno-omit-frame-pointer
-g
)
target_link_options(test_linkedlist PRIVATE
-fsanitize=address
)
include(CTest)
include(Catch)
catch_discover_tests(test_linkedlist)

249
test/test_linkedlist.cpp Normal file
View File

@@ -0,0 +1,249 @@
#include "linkedlist.h"
#include <catch2/catch_test_macros.hpp>
TEST_CASE("Append 3 items to linkedlist", "[linkedlist]") {
LinkedList<int> list = {};
REQUIRE(list.len() == 0);
list.append(8);
REQUIRE(list.len() == 1);
REQUIRE(list.get(0) == 8);
list.append(9);
REQUIRE(list.len() == 2);
REQUIRE(list.get(1) == 9);
list.append(10);
REQUIRE(list.len() == 3);
REQUIRE(list.get(2) == 10);
}
TEST_CASE("Prepend 3 items to linkedlist", "[linkedlist]") {
LinkedList<int> list = {};
REQUIRE(list.len() == 0);
list.prepend(8);
REQUIRE(list.len() == 1);
REQUIRE(list.get(0) == 8);
list.prepend(9);
REQUIRE(list.len() == 2);
REQUIRE(list.get(0) == 9);
list.prepend(10);
REQUIRE(list.len() == 3);
REQUIRE(list.get(0) == 10);
}
TEST_CASE("Get out ouf bounds item", "[linkedlist]") {
LinkedList<int> list = {};
REQUIRE(list.len() == 0);
list.append(8);
REQUIRE(list.len() == 1);
REQUIRE(list.get(0) == 8);
list.append(9);
REQUIRE(list.len() == 2);
REQUIRE(list.get(1) == 9);
list.append(10);
REQUIRE(list.len() == 3);
REQUIRE(list.get(2) == 10);
auto result = list.get(50);
REQUIRE(!result.has_value());
REQUIRE(result.error() == LinkedListErr::LINKEDLIST_OUT_OF_BOUNDS);
}
TEST_CASE("Set head to val", "[linkedlist]") {
LinkedList<int> list = {};
REQUIRE(list.len() == 0);
list.append(8);
REQUIRE(list.len() == 1);
REQUIRE(list.get(0) == 8);
list.append(9);
REQUIRE(list.len() == 2);
REQUIRE(list.get(1) == 9);
list.append(10);
REQUIRE(list.len() == 3);
REQUIRE(list.get(2) == 10);
auto result = list.set(0, 90);
REQUIRE(list.len() == 3);
REQUIRE(result == LinkedListErr::LINKEDLIST_OK);
REQUIRE(list.get(0) == 90);
}
TEST_CASE("Set tail to val", "[linkedlist]") {
LinkedList<int> list = {};
REQUIRE(list.len() == 0);
list.append(8);
REQUIRE(list.len() == 1);
REQUIRE(list.get(0) == 8);
list.append(9);
REQUIRE(list.len() == 2);
REQUIRE(list.get(1) == 9);
list.append(10);
REQUIRE(list.len() == 3);
REQUIRE(list.get(2) == 10);
auto result = list.set(2, 90);
REQUIRE(list.len() == 3);
REQUIRE(result == LinkedListErr::LINKEDLIST_OK);
REQUIRE(list.get(2) == 90);
}
TEST_CASE("Set to out of bounds", "[linkedlist]") {
LinkedList<int> list = {};
REQUIRE(list.len() == 0);
list.append(8);
REQUIRE(list.len() == 1);
REQUIRE(list.get(0) == 8);
list.append(9);
REQUIRE(list.len() == 2);
REQUIRE(list.get(1) == 9);
list.append(10);
REQUIRE(list.len() == 3);
REQUIRE(list.get(2) == 10);
auto result = list.set(50, 90);
REQUIRE(list.len() == 3);
REQUIRE(result == LinkedListErr::LINKEDLIST_OUT_OF_BOUNDS);
}
TEST_CASE("Pop element", "[linkedlist]") {
LinkedList<int> list = {};
REQUIRE(list.len() == 0);
list.append(8);
REQUIRE(list.len() == 1);
REQUIRE(list.get(0) == 8);
list.append(9);
REQUIRE(list.len() == 2);
REQUIRE(list.get(1) == 9);
list.append(10);
REQUIRE(list.len() == 3);
REQUIRE(list.get(2) == 10);
REQUIRE(list.pop() == 10);
REQUIRE(list.len() == 2);
}
TEST_CASE("Pop empty", "[linkedlist]") {
LinkedList<int> list = {};
REQUIRE(list.len() == 0);
auto result = list.pop();
REQUIRE(result.error() == LinkedListErr::LINKEDLIST_EMPTY);
REQUIRE(list.len() == 0);
}
TEST_CASE("Remove head", "[linkedlist]") {
LinkedList<int> list = {};
REQUIRE(list.len() == 0);
list.append(8);
REQUIRE(list.len() == 1);
REQUIRE(list.get(0) == 8);
list.append(9);
REQUIRE(list.len() == 2);
REQUIRE(list.get(1) == 9);
list.append(10);
REQUIRE(list.len() == 3);
REQUIRE(list.get(2) == 10);
auto result = list.remove(0);
REQUIRE(result == LinkedListErr::LINKEDLIST_OK);
REQUIRE(list.len() == 2);
REQUIRE(list.get(0) == 9);
}
TEST_CASE("Remove tail", "[linkedlist]") {
LinkedList<int> list = {};
REQUIRE(list.len() == 0);
list.append(8);
REQUIRE(list.len() == 1);
REQUIRE(list.get(0) == 8);
list.append(9);
REQUIRE(list.len() == 2);
REQUIRE(list.get(1) == 9);
list.append(10);
REQUIRE(list.len() == 3);
REQUIRE(list.get(2) == 10);
auto result = list.remove(2);
REQUIRE(result == LinkedListErr::LINKEDLIST_OK);
REQUIRE(list.len() == 2);
REQUIRE(list.get(1) == 9);
}
TEST_CASE("Find 1 value present", "[linkedlist]") {
LinkedList<int> list = {};
REQUIRE(list.len() == 0);
list.append(8);
REQUIRE(list.len() == 1);
REQUIRE(list.get(0) == 8);
list.append(9);
REQUIRE(list.len() == 2);
REQUIRE(list.get(1) == 9);
list.append(10);
REQUIRE(list.len() == 3);
REQUIRE(list.get(2) == 10);
auto result = list.find(9);
REQUIRE(result == 1);
}
TEST_CASE("Find 1 value not present", "[linkedlist]") {
LinkedList<int> list = {};
REQUIRE(list.len() == 0);
list.append(8);
REQUIRE(list.len() == 1);
REQUIRE(list.get(0) == 8);
list.append(9);
REQUIRE(list.len() == 2);
REQUIRE(list.get(1) == 9);
list.append(10);
REQUIRE(list.len() == 3);
REQUIRE(list.get(2) == 10);
auto result = list.find(80);
REQUIRE(result.error() == LinkedListErr::LINKEDLIST_NOT_FOUND);
}