updated filestructure and gitignore. uploading exam progress

This commit is contained in:
Christopher Sanden
2025-11-05 20:09:06 +01:00
parent 729d69a399
commit 1ec6da4771
106 changed files with 12960 additions and 7 deletions

View File

@@ -0,0 +1,40 @@
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# "ON" = build Option 1, "OFF" = build Option 2.
option(BUILD_ASSIGNMENT_01_OPTION_1 "Build Assignment Option 1 (Standard)" ON)
add_executable(Assignment-01
main.cpp
)
# Conditionally add the correct source file
if(BUILD_ASSIGNMENT_01_OPTION_1)
# If ON, add option1.cpp and define 'ASSIGNMENT_OPTION=1' for C++
target_sources(Assignment-01
PRIVATE
option1.cpp
option1.h
)
target_compile_definitions(Assignment-01 PRIVATE "ASSIGNMENT_01_OPTION=1")
else()
# If OFF, add option2.cpp and define 'ASSIGNMENT_OPTION=2' for C++
target_sources(Assignment-01
PRIVATE
option2.cpp
option2.h
)
target_compile_definitions(Assignment-01 PRIVATE "ASSIGNMENT_01_OPTION=2")
endif()
target_link_libraries(Assignment-01
PRIVATE
SharedLib
)
add_custom_command(TARGET Assignment-01 POST_BUILD
# Add a custom command here if needed
COMMAND ${CMAKE_COMMAND} -E echo "Assignment-01 post-build step"
)

View File

@@ -0,0 +1,60 @@
// Mandatory-02.cpp : Defines the entry point for the application.
//
/*
Dear Student,
Remember to follow the coding standards and best practices discussed
in the portfolio assignment document.
Good luck with your portfolio!
NB: Do not delete the code below that prints the assignment and option info!
---------------------------------------------------------------------
*** HOW TO SWITCH BETWEEN OPTION 1 AND OPTION 2 ***
---------------------------------------------------------------------
You CANNOT switch options by changing this file.
1. Go to the 'CMakeLists.txt' file for this assignment.
2. Find the line:
option(BUILD_ASSIGNMENT_OPTION_1 "..." ON)
3. Change 'ON' (for Option 1) to 'OFF' (for Option 2).
*** VERY IMPORTANT: After changing the option ***
Your project will NOT update until you re-run the CMake configuration.
To force an update (e.g., in Visual Studio):
- Right-click the 'CMakeLists.txt' file and select 'Configure Cache'.
- OR, simply delete the 'out' / 'build' folder and rebuild the project.
---------------------------------------------------------------------
*/
#include <iostream>
#include <string_view>
static constexpr std::string_view AssignmentName = "Category 1: Lists, Stacks, & Queues";
#if ASSIGNMENT_01_OPTION == 1
#include "option1.h"
static constexpr std::string_view AssignmentOption = "Option 1 (Standard): Console Text Editor.";
#elif ASSIGNMENT_01_OPTION == 2
#include "option2.h"
static constexpr std::string_view AssignmentOption = "Option 2 (Advanced): Console Music Player.";
#endif
int main(int argc, char* argv[])
{
int appStatus = 0;
std::cout << AssignmentName << std::endl;
std::cout << AssignmentOption << std::endl;
// Create only core or common code in main.cpp
// Use the option header files to implement the specific assignment option logic
appStatus = RunApp();
return appStatus;
}

View File

@@ -0,0 +1,109 @@
// Option 1 (Standard): Console Text Editor.
//
#include "option1.h"
#include <iostream>
#include "TDoublyLinkedList.h"
#include "TQueue.h"
#include "TStack.h"
#include "Utils.h"
TDoublyLinkedList document;
TQueue printQueue;
TStack undoStack, redoStack;
bool running = true;
int lastIndex = 0;
std::string deletedLine;
void Undo()
{
if (!undoStack.IsEmpty()) {
const auto action = undoStack.Pop();
if (action.action == INSERT){
document.Remove(action.index);
}
else{
document.InsertAtIndex(action.index, action.text);
}
redoStack.Push(action);
}
}
void Redo()
{
if (!redoStack.IsEmpty()) {
const auto action = redoStack.Pop();
if (action.action == INSERT) {
document.InsertAtIndex(action.index, action.text);
}
else {
document.Remove(action.index);
}
undoStack.Push(action);
}
}
int RunApp()
{
// Implement the Console Text Editor application logic here
while (running) {
switch (Utils::Choice()) {
case 1: {
std::cout << "----------Add line----------" << std::endl;
lastIndex = Utils::Insert(document, undoStack, redoStack, lastIndex);
break;
}
case 2: {
std::cout << "----------Remove line----------" << std::endl;
Utils::PrintList(document);
lastIndex = Utils::RemoveLine(document, undoStack, redoStack, lastIndex);
break;
}
case 3: {
std::cout << "----------Current document----------" << std::endl;
for (int i = 0; i < document.GetSize(); i++)
std::cout << i + 1 << ". " << document.GetAtIndex(i) << std::endl;
std::cout << "------------------------------------\n\n";
break;
}
case 4: {
for (int i = 0; i < document.GetSize(); ++i)
printQueue.Enqueue(document.GetAtIndex(i));
std::cout << "----------Printing queue-----------" << std::endl;
while (!printQueue.IsEmpty())
std::cout << printQueue.Dequeue() << std::endl;
std::cout << "------------------------------------\n\n";
break;
}
case 5: {
std::cout << "----------UNDO----------" <<std::endl;
Undo();
break;
}
case 6: {
std::cout << "----------REDO----------" <<std::endl;
Redo();
break;
}
case 0: {
std::cout << "----------Exiting...----------" << std::endl;
running = false;
break;
}
default: {
std::cout << "Invalid input, please pick a number..." << std::endl;
break;
}
}
}
return 0;
}

View File

@@ -0,0 +1,11 @@
// option1.h : Option 1 (Standard): Console Text Editor.
#pragma once
#ifndef OPTION1_H
#define OPTION1_H
int RunApp();
#endif // OPTION1_H

View File

@@ -0,0 +1,19 @@
// Option 2 (Advanced): Console Music Player.
#include <iostream>
#include "option2.h"
static bool SongReadCallback(const int aIndex, const int aTotalCount, const std::string& aArtist, const std::string& aTitle, const std::string& aYear, const std::string& aGenre, const std::string& aSource) {
// Implement the logic to process each song read from the file
// For example, print the song details to the console
std::cout << "Song " << (aIndex + 1) << " of " << aTotalCount << ":\n";
std::cout << " Artist: " << aArtist << "\n";
std::cout << " Title: " << aTitle << "\n";
std::cout << " Year: " << aYear << "\n";
std::cout << " Genre: " << aGenre << "\n";
std::cout << " Source: " << aSource << "\n\n";
// Return true to continue reading more songs
return true;
}

View File

@@ -0,0 +1,10 @@
// option1.h : Option 2 (Advanced): Console Music Player.
#pragma once
#ifndef OPTION2_H
#define OPTION2_H
int RunApp();
#endif // OPTION2_H

View File

@@ -0,0 +1,40 @@
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# "ON" = build Option 1, "OFF" = build Option 2.
option(BUILD_ASSIGNMENT_02_OPTION_1 "Build Assignment Option 1 (Standard)" ON)
add_executable(Assignment-02
main.cpp
)
# Conditionally add the correct source file
if(BUILD_ASSIGNMENT_02_OPTION_1)
# If ON, add option1.cpp and define 'ASSIGNMENT_OPTION=1' for C++
target_sources(Assignment-02
PRIVATE
option1.cpp
option1.h
)
target_compile_definitions(Assignment-02 PRIVATE "ASSIGNMENT_02_OPTION=1")
else()
# If OFF, add option2.cpp and define 'ASSIGNMENT_OPTION=2' for C++
target_sources(Assignment-02
PRIVATE
option2.cpp
option2.h
)
target_compile_definitions(Assignment-02 PRIVATE "ASSIGNMENT_02_OPTION=2")
endif()
target_link_libraries(Assignment-02
PRIVATE
SharedLib
)
add_custom_command(TARGET Assignment-02 POST_BUILD
# Add a custom command here if needed
COMMAND ${CMAKE_COMMAND} -E echo "Assignment-02 post-build step"
)

View File

@@ -0,0 +1,57 @@
// Mandatory-02.cpp : Defines the entry point for the application.
//
/*
Dear Student,
Remember to follow the coding standards and best practices discussed
in the portfolio assignment document.
Good luck with your portfolio!
NB: Do not delete the code below that prints the assignment and option info!
---------------------------------------------------------------------
*** HOW TO SWITCH BETWEEN OPTION 1 AND OPTION 2 ***
---------------------------------------------------------------------
You CANNOT switch options by changing this file.
1. Go to the 'CMakeLists.txt' file for this assignment.
2. Find the line:
option(BUILD_ASSIGNMENT_OPTION_1 "..." ON)
3. Change 'ON' (for Option 1) to 'OFF' (for Option 2).
*** VERY IMPORTANT: After changing the option ***
Your project will NOT update until you re-run the CMake configuration.
To force an update (e.g., in Visual Studio):
- Right-click the 'CMakeLists.txt' file and select 'Configure Cache'.
- OR, simply delete the 'out' / 'build' folder and rebuild the project.
---------------------------------------------------------------------
*/
#include <iostream>
#include <string_view>
static constexpr std::string_view AssignmentName = "Category 2: Sorting & Searching";
#if ASSIGNMENT_02_OPTION == 1
#include "option1.h"
static constexpr std::string_view AssignmentOption = "Option 1 (Standard): Cruise Ship Manifest.";
#elif ASSIGNMENT_02_OPTION == 2
#include "option2.h"
static constexpr std::string_view AssignmentOption = "Option 2 (Advanced): Combined Corporate Directory.";
#endif
int main(int argc, char* argv[])
{
int appStatus = 0;
std::cout << AssignmentName << std::endl;
std::cout << AssignmentOption << std::endl;
// Create only core or common code in main.cpp
// Use the option header files to implement the specific assignment option logic
appStatus = RunApp();
return appStatus;
}

View File

@@ -0,0 +1,36 @@
// Option 1 (Standard): Console Text Editor.
//
#include <iostream>
#include <string>
#include "option1.h"
#include "SharedLib.h"
/**
* @brief Callback function to process one name.
*/
static bool NameReadCallback(const int aIndex, const int aTotalCount, const std::string& aFirstName, const std::string& aLastName)
{
std::cout << "Reading Name " << (aIndex + 1) << " of " << aTotalCount << ": "
<< aFirstName << " " << aLastName << "\n";
// We only want to read 10 names (index 0 through 9)
// Return false when aIndex is 9 to stop the loop after this one.
return (aIndex < 9);
}
int RunApp()
{
// Path to the names data file
std::string filename = "F:\\IKT203\\VisualStudio\\DATA\\random_names.txt";
std::cout << "Reading first 10 names from file: " << filename << "\n\n";
// Call the utility function with the name callback
readNamesFromFile(filename, NameReadCallback);
std::cout << "\nFinished reading names." << std::endl;
return 0;
}

View File

@@ -0,0 +1,11 @@
// option1.h : Option 1 (Standard): Console Text Editor.
#pragma once
#ifndef OPTION1_H
#define OPTION1_H
int RunApp();
#endif // OPTION1_H

View File

@@ -0,0 +1,8 @@
// Option 2 (Advanced): Console Music Player.
#include "option2.h"
int RunApp() {
// Implement the Console Music Player application logic here
return 0;
}

View File

@@ -0,0 +1,10 @@
// option1.h : Option 2 (Advanced): Console Music Player.
#pragma once
#ifndef OPTION2_H
#define OPTION2_H
int RunApp();
#endif // OPTION2_H

View File

@@ -0,0 +1,39 @@
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# "ON" = build Option 1, "OFF" = build Option 2.
option(BUILD_ASSIGNMENT_03_OPTION_1 "Build Assignment Option 1 (Standard)" ON)
add_executable(Assignment-03
main.cpp
)
# Conditionally add the correct source file
if(BUILD_ASSIGNMENT_03_OPTION_1)
# If ON, add option1.cpp and define 'ASSIGNMENT_OPTION=1' for C++
target_sources(Assignment-03
PRIVATE
option1.cpp
option1.h
)
target_compile_definitions(Assignment-03 PRIVATE "ASSIGNMENT_03_OPTION=1")
else()
# If OFF, add option2.cpp and define 'ASSIGNMENT_OPTION=2' for C++
target_sources(Assignment-03
PRIVATE
option2.cpp
option2.h
)
target_compile_definitions(Assignment-03 PRIVATE "ASSIGNMENT_03_OPTION=2")
endif()
target_link_libraries(Assignment-03
PRIVATE
SharedLib
)
add_custom_command(TARGET Assignment-03 POST_BUILD
# Add a custom command here if needed
COMMAND ${CMAKE_COMMAND} -E echo "Assignment-03 post-build step"
)

View File

@@ -0,0 +1,54 @@
/*
Dear Student,
Remember to follow the coding standards and best practices discussed
in the portfolio assignment document.
Good luck with your portfolio!
NB: Do not delete the code below that prints the assignment and option info!
---------------------------------------------------------------------
*** HOW TO SWITCH BETWEEN OPTION 1 AND OPTION 2 ***
---------------------------------------------------------------------
You CANNOT switch options by changing this file.
1. Go to the 'CMakeLists.txt' file for this assignment.
2. Find the line:
option(BUILD_ASSIGNMENT_OPTION_1 "..." ON)
3. Change 'ON' (for Option 1) to 'OFF' (for Option 2).
*** VERY IMPORTANT: After changing the option ***
Your project will NOT update until you re-run the CMake configuration.
To force an update (e.g., in Visual Studio):
- Right-click the 'CMakeLists.txt' file and select 'Configure Cache'.
- OR, simply delete the 'out' / 'build' folder and rebuild the project.
---------------------------------------------------------------------
*/
#include <iostream>
#include <string_view>
static constexpr std::string_view AssignmentName = "Category 3: Trees (BST, AVL & RBT)";
#if ASSIGNMENT_03_OPTION == 1
#include "option1.h"
static constexpr std::string_view AssignmentOption = "Option 1 (Standard): Employee Directory (BST vs. AVL).";
#elif ASSIGNMENT_03_OPTION == 2
#include "option2.h"
static constexpr std::string_view AssignmentOption = "Option 2 (Advanced): Interpreted Calculator.";
#endif
int main(int argc, char* argv[])
{
int appStatus = 0;
std::cout << AssignmentName << std::endl;
std::cout << AssignmentOption << std::endl;
// Create only core or common code in main.cpp
// Use the option header files to implement the specific assignment option logic
appStatus = RunApp();
return appStatus;
}

View File

@@ -0,0 +1,6 @@
#include "option1.h"
int RunApp() {
// Implement the Console Text Editor application logic here
return 0;
}

View File

@@ -0,0 +1,9 @@
#pragma once
#ifndef OPTION1_H
#define OPTION1_H
int RunApp();
#endif // OPTION1_H

View File

@@ -0,0 +1,6 @@
#include "option2.h"
int RunApp() {
// Implement the Console Music Player application logic here
return 0;
}

View File

@@ -0,0 +1,9 @@
#pragma once
#ifndef OPTION2_H
#define OPTION2_H
int RunApp();
#endif // OPTION2_H

View File

@@ -0,0 +1,37 @@
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
# "ON" = build Option 1, "OFF" = build Option 2.
option(BUILD_ASSIGNMENT_04_OPTION_1 "Build Assignment Option 1 (Standard)" OFF)
add_executable(Assignment-04
main.cpp
)
if(BUILD_ASSIGNMENT_04_OPTION_1)
target_sources(Assignment-04
PRIVATE
option1.cpp
option1.h
)
target_compile_definitions(Assignment-04 PRIVATE "ASSIGNMENT_04_OPTION=1")
else()
target_sources(Assignment-04
PRIVATE
option2.cpp
option2.h
)
target_compile_definitions(Assignment-04 PRIVATE "ASSIGNMENT_04_OPTION=2")
endif()
target_link_libraries(Assignment-04
PRIVATE
SharedLib
)
add_custom_command(TARGET Assignment-04 POST_BUILD
# Add a custom command here if needed
COMMAND ${CMAKE_COMMAND} -E echo "Assignment-04 post-build step"
)

View File

@@ -0,0 +1,53 @@
/*
Dear Student,
Remember to follow the coding standards and best practices discussed
in the portfolio assignment document.
Good luck with your portfolio!
NB: Do not delete the code below that prints the assignment and option info!
---------------------------------------------------------------------
*** HOW TO SWITCH BETWEEN OPTION 1 AND OPTION 2 ***
---------------------------------------------------------------------
You CANNOT switch options by changing this file.
1. Go to the 'CMakeLists.txt' file for this assignment.
2. Find the line:
option(BUILD_ASSIGNMENT_OPTION_1 "..." ON)
3. Change 'ON' (for Option 1) to 'OFF' (for Option 2).
*** VERY IMPORTANT: After changing the option ***
Your project will NOT update until you re-run the CMake configuration.
To force an update (e.g., in Visual Studio):
- Right-click the 'CMakeLists.txt' file and select 'Configure Cache'.
- OR, simply delete the 'out' / 'build' folder and rebuild the project.
---------------------------------------------------------------------
*/
#include <iostream>
#include <string_view>
static constexpr std::string_view AssignmentName = "Category 4: Graphs & Dijkstra's Algorithm";
#if ASSIGNMENT_04_OPTION == 1
static constexpr std::string_view AssignmentOption = "Option 1 (Standard): Data Center Network Monitor.";
#include "option1.h"
#elif ASSIGNMENT_04_OPTION == 2
static constexpr std::string_view AssignmentOption = "Option 2 (Advanced): Inter-city Logistics Router.";
#include "option2.h"
#endif
int main(int argc, char* argv[])
{
int appStatus = 0;
std::cout << AssignmentName << std::endl;
std::cout << AssignmentOption << std::endl;
// Create only core or common code in main.cpp
// Use the option header files to implement the specific assignment option logic
appStatus = RunApp();
return appStatus;
}

View File

@@ -0,0 +1,6 @@
#include "option1.h"
#include <iostream>
int RunApp() {
return 0;
}

View File

@@ -0,0 +1,9 @@
#pragma once
#ifndef OPTION1_H
#define OPTION1_H
int RunApp();
#endif // OPTION1_H

View File

@@ -0,0 +1,47 @@
#include <iostream>
#include "option1.h"
#include "SharedLib.h"
static constexpr std::string_view AssignmentOption = "Option 1 (Standard): Data Center Network Monitor.";
/**
* @brief Callback function to process one node.
*/
static bool NodeReadCallback(const int aIndex, const int aTotalCount, const std::string& aNode)
{
std::cout << "Loading Node " << (aIndex + 1) << " of " << aTotalCount << ": " << aNode << "\n";
// Return true to continue reading
return true;
}
/**
* @brief Callback function to process one edge.
*/
static bool EdgeReadCallback(const int aIndex, const int aTotalCount, const std::string& aFromNode, const std::string& aToNode, float aWeight)
{
std::cout << " Loading Edge " << (aIndex + 1) << " of " << aTotalCount << ": "
<< aFromNode << " -> " << aToNode << " (Weight: " << aWeight << ")\n";
// Return true to continue reading
return true;
}
int RunApp()
{
std::cout << AssignmentOption << std::endl;
// Path to the graph data file
std::string filename = "F:\\IKT203\\VisualStudio\\DATA\\city_graph.txt";
std::cout << "Reading graph from file: " << filename << "\n\n";
// Call the utility function with both callbacks
readGraphFromFile(filename, NodeReadCallback, EdgeReadCallback);
std::cout << "\nFinished reading graph." << std::endl;
return 0;
}

View File

@@ -0,0 +1,9 @@
#pragma once
#ifndef OPTION2_H
#define OPTION2_H
int RunApp();
#endif // OPTION2_H

View File

@@ -0,0 +1,20 @@
# CMakeList.txt : Top-level CMake project file, do global configuration
# and include sub-projects here.
#
cmake_minimum_required (VERSION 3.20)
project ("Portfolio")
# Enable Hot Reload for MSVC compilers if supported.
if (POLICY CMP0141)
cmake_policy(SET CMP0141 NEW)
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<IF:$<AND:$<C_COMPILER_ID:MSVC>,$<CXX_COMPILER_ID:MSVC>>,$<$<CONFIG:Debug,RelWithDebInfo>:EditAndContinue>,$<$<CONFIG:Debug,RelWithDebInfo>:ProgramDatabase>>")
endif()
# Include sub-projects.
add_subdirectory(SharedLib)
# Tell CMake to find and include the first exercise project.
add_subdirectory(Assignment-01)
add_subdirectory(Assignment-02)
add_subdirectory(Assignment-03)
add_subdirectory(Assignment-04)

View File

@@ -0,0 +1,39 @@
# --- Step 1: Create the Library ---
# Define a library target named "SharedLib".
# We use STATIC because we are using cpp and header files.
add_library(SharedLib STATIC)
# --- Step 2: Add Header Files to the Library ---
# This command explicitly lists the header files that belong to the library.
# This helps Visual Studio display them nicely in the Solution Explorer.
target_sources(SharedLib
PUBLIC
# You can add more functionalty to SharedLib.h just by adding more definitions in SharedLib.h.
SharedLib.h
TDoublyLinkedList.h
TStack.h
TQueue.h
Utils.h
# Or add other shared files here
PRIVATE
ReadNames.cpp
ReadGraph.cpp
ReadSongs.cpp
FileReaderUtils.cpp
TDoublyLinkedList.cpp
TStack.cpp
TQueue.cpp
Utils.cpp
)
# --- Step 3: Make Headers "Findable" ---
# This is the most important command here.
# It tells any other project that links to "SharedLib" to add this
# directory (CMAKE_CURRENT_SOURCE_DIR) to its list of include paths.
# This is what allows you to write #include "list.hpp" in your main.cpp.
# Note: CMAKE_CURRENT_SOURCE_DIR is a built-in variable that points to the directory
target_include_directories(SharedLib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})

View File

@@ -0,0 +1,32 @@
#include "FileReaderUtils.h"
#include "FileReaderUtils.h"
int GetRecordCount(const std::string& aHeaderLine)
{
size_t recordPos = aHeaderLine.find("records:=");
if (recordPos == std::string::npos)
{
return 0; // No record count found
}
size_t countStart = recordPos + 9; // Length of "records:="
// Find the end bracket ']' or a potential semicolon ';'
size_t countEnd = aHeaderLine.find_first_of("];", countStart);
if (countEnd == std::string::npos)
{
return 0; // Malformed header
}
std::string countStr = aHeaderLine.substr(countStart, countEnd - countStart);
try
{
// stoi = string to integer
return std::stoi(countStr);
}
catch (const std::exception&)
{
return 0; // Malformed number
}
}

View File

@@ -0,0 +1,13 @@
// FileReaderUtils.h
#pragma once
#if !defined(FILEREADERUTILS_H)
#define FILEREADERUTILS_H
#include <string>
/**
* @brief [Internal] Safely parses the "records:=N" part of a header line.
* @param aHeaderLine The line, e.g., "[NODES;records:=11]"
* @return The number of records, or 0 if not found.
*/
int GetRecordCount(const std::string& aHeaderLine);
#endif // FILEREADERUTILS_H

View File

@@ -0,0 +1,109 @@
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include "SharedLib.h"
#include "FileReaderUtils.h"
// --- Enum for the parser's state ---
enum class EParseState
{
NONE,
NODES,
EDGES
};
void readGraphFromFile(const std::string& aFilename, FNodeRead aOnNodeRead, FEdgeRead aOnEdgeRead)
{
if (aFilename.empty()) return;
std::ifstream file(aFilename);
if (!file.is_open())
{
// Optional: print an error
// std::cerr << "Error: Could not open file " << aFilename << std::endl;
return;
}
std::string line;
EParseState currentState = EParseState::NONE;
int totalCount = 0;
int currentIndex = 0;
bool keepReading = true;
while (keepReading && std::getline(file, line))
{
if (line.empty()) continue;
if (line[0] == '[')
{
// --- 2. USE THE SHARED FUNCTION ---
totalCount = GetRecordCount(line);
currentIndex = 0;
if (line.find("[NODES") != std::string::npos)
{
currentState = EParseState::NODES;
continue;
}
else if (line.find("[EDGES") != std::string::npos)
{
currentState = EParseState::EDGES;
continue;
}
// If it's a comment or other header, reset state and count
currentState = EParseState::NONE;
totalCount = 0;
continue;
}
// Process data based on the current state
switch (currentState)
{
case EParseState::NODES:
if (aOnNodeRead)
{
if (!aOnNodeRead(currentIndex, totalCount, line))
{
keepReading = false;
}
currentIndex++;
}
break;
case EParseState::EDGES:
{
std::istringstream edgeStream(line);
std::string fromNode, toNode, weightStr;
if (std::getline(edgeStream, fromNode, ';') &&
std::getline(edgeStream, toNode, ';') &&
std::getline(edgeStream, weightStr))
{
try
{
// Use std::stof (string to float) for weight
float weight = std::stof(weightStr);
if (aOnEdgeRead)
{
if (!aOnEdgeRead(currentIndex, totalCount, fromNode, toNode, weight))
{
keepReading = false;
}
currentIndex++;
}
}
catch (const std::exception&)
{
// Failed to parse float, skip this line
}
}
break;
}
case EParseState::NONE:
default:
break;
}
}
file.close();
}

View File

@@ -0,0 +1,55 @@
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include "SharedLib.h"
#include "FileReaderUtils.h"
void readNamesFromFile(const std::string& aFilename, FNameRead aOnNameRead)
{
if (aFilename.empty()) return;
std::ifstream file(aFilename);
if (!file.is_open())
{
std::cerr << "Error: Could not open file " << aFilename << std::endl;
return;
}
std::string line;
int totalCount = 0;
int currentIndex = 0;
bool keepReading = true;
// --- 1. Read the header line ---
if (std::getline(file, line))
{
// Use our shared helper to get the count
totalCount = GetRecordCount(line);
}
// --- 2. Loop through the rest of the file ---
while (keepReading && std::getline(file, line))
{
if (line.empty()) continue;
std::istringstream nameStream(line);
std::string firstName, lastName;
// Parse "FirstName LastName"
if (nameStream >> firstName >> lastName)
{
if (aOnNameRead)
{
// Call the callback with all parameters
if (!aOnNameRead(currentIndex, totalCount, firstName, lastName))
{
keepReading = false;
}
currentIndex++;
}
}
}
file.close();
}

View File

@@ -0,0 +1,60 @@
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include "SharedLib.h"
#include "FileReaderUtils.h" // Include the shared utility
void ReadSongsFromFile(const std::string& aFilename, FSongRead aOnSongRead)
{
if (aFilename.empty()) return;
std::ifstream file(aFilename);
if (!file.is_open())
{
// std::cerr << "Error: Could not open file " << aFilename << std::endl;
return;
}
std::string line;
int totalCount = 0;
int currentIndex = 0;
bool keepReading = true;
// --- 1. Read the header line ---
if (std::getline(file, line))
{
// Use our shared helper to get the count
totalCount = GetRecordCount(line);
}
// --- 2. Loop through the rest of the file (the data lines) ---
while (keepReading && std::getline(file, line))
{
if (line.empty()) continue; // Skip empty lines
std::istringstream lineStream(line);
std::string artist, title, year, genre, source;
// Parse the five semicolon-separated fields
// Artist;Title;Year;Genre;Source
if (std::getline(lineStream, artist, ';') &&
std::getline(lineStream, title, ';') &&
std::getline(lineStream, year, ';') &&
std::getline(lineStream, genre, ';') &&
std::getline(lineStream, source)) // Last one reads to end of line
{
if (aOnSongRead)
{
// Call the callback with all parameters
if (!aOnSongRead(currentIndex, totalCount, artist, title, year, genre, source))
{
keepReading = false;
}
currentIndex++;
}
}
}
file.close();
}

View File

@@ -0,0 +1,100 @@
#pragma once
#ifndef SHARED_LIB_H
#define SHARED_LIB_H
#include <string>
#include <functional>
/// <summary>
/// Delegate type for processing a name read from a file.
/// </summary>
/// <param name="aIndex">The index of the name (0-based).</param>
/// <param name="aTotalCount">The total number of names.</param>
/// <param name="aFirstName">The first name read from the file.</param>
/// <param name="aLastName">The last name read from the file.</param>
/// <returns>Returns true to continue reading, false to stop.</returns>
typedef bool (*FNameRead)(
const int aIndex,
const int aTotalCount,
const std::string& aFirstName,
const std::string& aLastName
);
/// <summary>
/// Use this function to read names from a specified file and process them using a callback function.
/// </summary>
/// <function>readNamesFromFile</function>
/// <description>Reads names from a specified file and invokes a callback for each name read.</description>
/// <param name="aFilename">The path to the file containing names.</param>
/// <param name="aOnNameRead">A callback function that is called for each name read. It takes two parameters: firstName and lastName. If the callback returns false, the reading process stops.</param>
/// <param name="firstName">The first name read from the file.</param>
/// <param name="lastName">The last name read from the file.</param>
/// <returns>None.</returns>
void readNamesFromFile(const std::string& aFilename, FNameRead aOnNameRead);
/// <summary>
/// Delegate type for processing a node read from the file.
/// </summary>
/// <description>Function pointer type for a callback that processes nodes read from a file.</description>
/// <param name="aIndex">The index of the node (0-based).</param>
/// <param name="aTotalCount">The total number of nodes.</param>
/// <param name="aNode">The node std::string.</param>
/// <returns>Returns true to continue reading, false to stop.</returns>
typedef bool (*FNodeRead)(const int aIndex, const int aTotalCount, const std::string& aNode);
/// <summary>
/// Delegate type for processing an edge read from the file.
/// </summary>
/// <description>Function pointer type for a callback that processes edges read from a file.</description>
/// <param name="aIndex">The index of the edge (0-based).</param>
/// <param name="aTotalCount">The total number of edges.</param>
/// <param name="aFromNode">The from node std::string.</param>
/// <param name="aToNode">The to node std::string.</param>
/// <param name="aWeight">The weight of the edge.</param>
/// <returns>Returns true to continue reading, false to stop.</returns>
typedef bool (*FEdgeRead)(const int aIndex, const int aTotalCount, const std::string& aFromNode, const std::string& aToNode, float aWeight);
/// </summary>
/// Use this function to read a graph from a specified file and process its nodes and edges using callback functions.
/// </summary>
/// <function>readGraphFromFile</function>
/// <description>
/// Reads a graph from a specified file and invokes callbacks for each node and edge read.
/// All nodes are read first, followed by edges.
/// </description>
/// <param name="aFilename">The path to the file containing the graph data.</param>
/// <param name="aOnNodeRead">A callback function that is called for each node read. It takes one parameter: the node std::string. If the callback returns false, the reading process stops.</param>
/// <param name="aOnEdgeRead">A callback function that is called for each edge read. It takes three parameters: the fromNode std::string, the toNode std::string, and the weight float. If the callback returns false, the reading process stops.</param>
void readGraphFromFile(const std::string& aFilename, FNodeRead aOnNodeRead, FEdgeRead aOnEdgeRead);
/// <summary>
/// Delegate type for processing a song read from the file.
/// </summary>
/// <param name="aIndex">The index of the song (0-based).</param>
/// <param name="aTotalCount">The total number of songs.</param>
/// <param name="aArtist">The artist.</param>
/// <param name="aTitle">The title.</param>
/// <param name="aYear">The release year (as a std::string).</param>
/// <param name="aGenre">The genre.</param>
/// <param name="aSource">The source.</param>
/// <returns>Returns true to continue reading, false to stop.</returns>
typedef bool (*FSongRead)(
const int aIndex,
const int aTotalCount,
const std::string& aArtist,
const std::string& aTitle,
const std::string& aYear,
const std::string& aGenre,
const std::string& aSource
);
/// <summary>
/// Reads song data from a file and processes them using a callback.
/// This function automatically skips the "records:=" header.
/// </summary>
/// <param name="aFilename">The path to the file (e.g., "songs.txt").</param>
/// <param name="aOnSongRead">The callback function called for each song.</param>
void ReadSongsFromFile(const std::string& aFilename, FSongRead aOnSongRead);
#endif // SHARED_LIB_H

View File

@@ -0,0 +1,114 @@
#include "TDoublyLinkedList.h"
#include <iostream>
#include "SharedLib.h"
void TDoublyLinkedList::Append(const std::string& line)
{
auto* newNode = new Node(line);
if (size == 0)
head = tail = newNode;
else {
newNode->SetPrev(tail);
tail->SetNext(newNode);
tail = newNode;
}
size++;
}
void TDoublyLinkedList::Prepend(const std::string& line)
{
auto* newNode = new Node(line);
if (size == 0)
head = tail = newNode;
else {
newNode->SetNext(head);
head->SetPrev(newNode);
head = newNode;
}
size++;
}
TDoublyLinkedList::Node* TDoublyLinkedList::NavigateToNode(const int index) const
{
if (index < 0 || index >= size)
return nullptr;
auto* node = head;
for (int i = 0; i < index; i++)
node = node->GetNext();
return node;
}
void TDoublyLinkedList::Remove(const int index)
{
auto* node = NavigateToNode(index);
if (!node)
return;
if (node->GetPrev())
node->GetPrev()->SetNext(node->GetNext());
else
head = node->GetNext();
if (node->GetNext())
node->GetNext()->SetPrev(node->GetPrev());
else
tail = node->GetPrev();
delete node;
size--;
}
std::string TDoublyLinkedList::GetAtIndex(const int index) const
{
const auto* node = NavigateToNode(index);
return node ? node->GetLine() : "Error, line does not exist\n";
}
void TDoublyLinkedList::InsertAtIndex(const int index, const std::string &line)
{
if (index < 0 || index > size) {
std::cout << "========\nIndex doesn't exist\n========\n" << std::endl;
return;
}
if (index == 0)
{
Prepend(line);
return;
}
if (index == size)
{
Append(line);
return;
}
Node* cur = head;
for (int i = 0; i < index; i++)
cur = cur->GetNext();
Node* newNode = new Node(line);
Node* prev = cur->GetPrev();
newNode->SetPrev(prev);
newNode->SetNext(cur);
prev->SetNext(newNode);
cur->SetPrev(newNode);
size++;
}
int TDoublyLinkedList::GetSize() const
{
return size;
}

View File

@@ -0,0 +1,60 @@
#ifndef TDOUBLYLINKEDLIST_H
#define TDOUBLYLINKEDLIST_H
#include <string>
#include <utility>
#include "SharedLib.h"
class TDoublyLinkedList {
private:
struct Node {
std::string line;
Node* next;
Node* prev;
explicit Node(std::string text) : line(std::move(text)), next(nullptr), prev(nullptr) {}
void SetNext(Node* node)
{
this->next = node;
}
void SetPrev(Node* node)
{
this->prev = node;
}
[[nodiscard]] Node* GetPrev() const
{
return this->prev;
}
[[nodiscard]] Node* GetNext() const
{
return this->next;
}
[[nodiscard]] std::string GetLine() const
{
return line;
}
};
Node* head;
Node* tail;
int size;
public:
TDoublyLinkedList() : head(nullptr), tail(nullptr), size(0) {}
~TDoublyLinkedList() = default;
void Append(const std::string &line);
void Prepend(const std::string& line);
[[nodiscard]] Node* NavigateToNode(int index) const;
void Remove(int index);
[[nodiscard]] std::string GetAtIndex(int index) const;
void InsertAtIndex(int index, const std::string &line);
[[nodiscard]] int GetSize() const;
};
#endif //TDOUBLYLINKEDLIST_H

View File

@@ -0,0 +1,47 @@
#include "TQueue.h"
#include <stdexcept>
void TQueue::Enqueue(const std::string& text)
{
if (IsFull())
throw std::overflow_error("Queue Overflow");
queue[tail] = text;
tail = (tail + 1) % MAX_SIZE;
count++;
}
std::string TQueue::Dequeue()
{
if (IsEmpty())
throw std::underflow_error("Empty Queue");
const std::string item = queue[head];
head = (head + 1) % MAX_SIZE;
count--;
return item;
}
std::string TQueue::Peek() const
{
if (IsEmpty())
throw std::underflow_error("Empty Queue");
return queue[head];
}
bool TQueue::IsEmpty() const
{
return count == 0;
}
bool TQueue::IsFull() const
{
return count == MAX_SIZE;
}
int TQueue::GetTail() const
{
if (IsEmpty())
throw std::underflow_error("Empty Queue");
return tail;
}

View File

@@ -0,0 +1,28 @@
#ifndef TQUEUE_H
#define TQUEUE_H
#define MAX_SIZE 100
#include "TDoublyLinkedList.h"
class TQueue {
private:
std::string queue[MAX_SIZE];
int head = 0;
int tail = 0;
int count = 0;
public:
TQueue() = default;
~TQueue() = default;
void Enqueue(const std::string& text);
std::string Dequeue();
[[nodiscard]] int GetTail() const;
[[nodiscard]] std::string Peek() const;
[[nodiscard]] bool IsEmpty() const;
[[nodiscard]] bool IsFull() const;
};
#endif //TQUEUE_H

View File

@@ -0,0 +1,36 @@
#include "TStack.h"
#include <stdexcept>
void TStack::Push(const TAction& action)
{
if (top >= STACK_MAX_SIZE)
throw std::overflow_error("Stack overflow");
event[top++] = action;
}
TStack::TAction TStack::Pop()
{
if (top == 0)
throw std::underflow_error("Stack empty");
return event[--top];
}
TStack::TAction TStack::Peek() const
{
if (top == 0)
throw std::underflow_error("Stack empty");
return event[top - 1];
}
bool TStack::IsEmpty() const
{
return top == 0;
}
void TStack::Clear()
{
for (int i = 0; i < top; i++) {
this->Pop();
}
}

View File

@@ -0,0 +1,37 @@
#ifndef TSTACK_H
#define TSTACK_H
#define STACK_MAX_SIZE 100
#include <string>
enum EnumActionType {
INSERT,
DELETE
};
class TStack {
private:
struct TAction {
EnumActionType action;
std::string text;
int index;
};
TAction event[STACK_MAX_SIZE]{};
int top = 0;
public:
TStack() = default;
~TStack() = default;
void Push(const TAction& action);
TAction Pop();
[[nodiscard]] TAction Peek() const;
[[nodiscard]] bool IsEmpty() const;
void Clear();
};
#endif //TSTACK_H

View File

@@ -0,0 +1,78 @@
#include "Utils.h"
#include <iostream>
#include <limits>
#include "TDoublyLinkedList.h"
#include "TStack.h"
int Utils::Choice()
{
std::cout << "========\n1. Add line\n2. Remove line\n3. Print current document\n4. Print queue\n5. Undo\n6. Redo\n0. Exit"
"\n\nChoice: ";
int choice;
std::cin >> choice;
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
//std::cout << "\n=====================\n";
return choice;
}
int Utils::Insert(TDoublyLinkedList &document, TStack &undoStack, TStack &redoStack, int index)
{
for (int i = 0; i < document.GetSize(); i++) {
std::cout << i + 1 << ". " << document.GetAtIndex(i) << std::endl;
}
if (document.GetSize() > 0)
{
std::cout << "Enter the line number where you want to insert the line" <<std::endl;
if (!(std::cin >> index)) {
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << "========\nIndex must be a number\n========\n\n" << std::endl;
return index;
}
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
if (document.GetSize() < 1)
index = 1;
std::cout << "Enter the text" <<std::endl;
std::string line;
std::getline(std::cin, line);
document.InsertAtIndex(index - 1, line);
undoStack.Push({INSERT, line, index - 1});
if (!redoStack.IsEmpty()) {
redoStack.Clear();
}
return index;
}
void Utils::PrintList(const TDoublyLinkedList &document)
{
for (int i = 0; i < document.GetSize(); i++) {
std::cout << i + 1 << ". " << document.GetAtIndex(i) << std::endl;
}
std::cout << "\n\n";
}
int Utils::RemoveLine(TDoublyLinkedList &document, TStack &undoStack, TStack &redoStack, int index)
{
std::cout << "Enter the number of the line you want to remove" <<std::endl;
if (!(std::cin >> index)) {
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
std::cout << "========\nIndex must be a number\n========\n\n" << std::endl;
return index;
} std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
const std::string deletedLine = document.GetAtIndex(index-1);
document.Remove(index-1);
undoStack.Push({DELETE, deletedLine, index-1});
if (!redoStack.IsEmpty()) {
redoStack.Clear();
}
return index;
}

View File

@@ -0,0 +1,26 @@
#ifndef UTILS_H
#define UTILS_H
#include "TDoublyLinkedList.h"
#include "TStack.h"
class Utils {
public:
static int Choice();
static int Insert(TDoublyLinkedList &document, TStack &undoStack, TStack &redoStack, int index);
static void PrintList(const TDoublyLinkedList &document);
static int RemoveLine(TDoublyLinkedList &document, TStack &undoStack, TStack &redoStack, int index);
};
#endif //PART1_UTILS_H