Compare commits

...

10 Commits

17 changed files with 510 additions and 77 deletions

View File

@ -1,3 +1,23 @@
/* Unit 2: BST
*
* - Written in template format for flexibility
*
* - In project, BST holds primary key of CPU IDs
*
* - Sorted based off string comparison
*
* - Has insert, search, and remove functionality
*
* - Has multiple transversal functions (inorder, preorder, postorder)
*
* - Has printTree function that prints all nodes in function
*
* - In project, function pointer is used to print in indented format
*
* Written By: Tuhin Mondal
*/
#ifndef INC_08_TEAM_PROJECT_BINARYSEARCHTREE_H
#define INC_08_TEAM_PROJECT_BINARYSEARCHTREE_H
@ -20,6 +40,7 @@ public:
bool search(const T& target, T& returnedItem) const;
};
// Caller function for private _insert() method
template<typename T>
void BinarySearchTree<T>::insert(const T& newEntry)
{
@ -28,6 +49,7 @@ void BinarySearchTree<T>::insert(const T& newEntry)
this->size++;
}
// Inserts and sorts a new node into BST
template<typename T>
BinaryTreeNode<T>* BinarySearchTree<T>::_insert(BinaryTreeNode<T>* nodePtr, BinaryTreeNode<T>* newNodePtr) {
BinaryTreeNode<T>* pWalk = nodePtr, * parent = nullptr;
@ -54,6 +76,7 @@ BinaryTreeNode<T>* BinarySearchTree<T>::_insert(BinaryTreeNode<T>* nodePtr, Bina
return nodePtr;
}
// Caller function for private _remove() function
template<typename T>
bool BinarySearchTree<T>::remove(const T& item) {
BinaryTreeNode<T>* removed = _remove(this->root, item);
@ -64,6 +87,7 @@ bool BinarySearchTree<T>::remove(const T& item) {
return false;
}
// Removes a node from BST
template<typename T>
BinaryTreeNode<T>* BinarySearchTree<T>::_remove(BinaryTreeNode<T>* nodePtr, const T& target) {
BinaryTreeNode<T>* parNode = nullptr;
@ -108,6 +132,7 @@ BinaryTreeNode<T>* BinarySearchTree<T>::_remove(BinaryTreeNode<T>* nodePtr, cons
return nullptr;
}
// Caller function for private _search() function
template<typename T>
bool BinarySearchTree<T>::search(const T& target, T& returnedItem) const
{
@ -122,6 +147,7 @@ bool BinarySearchTree<T>::search(const T& target, T& returnedItem) const
return false;
}
// Searches for a node and returns it if found.
template<typename T>
BinaryTreeNode<T>* BinarySearchTree<T>::_search(BinaryTreeNode<T>* nodePtr, const T& target) const
{

View File

@ -1,3 +1,23 @@
/* Unit 2: BST
*
* - Written in template format for flexibility
*
* - In project, BST holds primary key of CPU IDs
*
* - Sorted based off string comparison
*
* - Has insert, search, and remove functionality
*
* - Has multiple transversal functions (inorder, preorder, postorder)
*
* - Has printTree function that prints all nodes in function
*
* - In project, function pointer is used to print in indented format
*
* Written By: Tuhin Mondal
*/
#ifndef INC_08_TEAM_PROJECT_BINARYTREE_H
#define INC_08_TEAM_PROJECT_BINARYTREE_H
@ -20,15 +40,20 @@ public:
[[nodiscard]] int getSize() const { return size; };
// Caller function for private destroyTree() method
void clear() { destroyTree(root); root = 0; size = 0; }
// Caller function for private _preorder() method
void preOrder(void visit(const T&)) const { _preorder(visit, root); }
// Caller function for private _inorder() method
void inOrder(std::function<void(const T&)> visit) const { _inorder(visit, root); }
// Caller function for private _postorder() method
void postOrder(void visit(const T&)) const { _postorder(visit, root); }
void printIndented(void visit(const T&)) const { _printindented(visit, root, 0); }
// Caller function for private _printTree() method
void printTree(void visit(const T&, int)) const { _printTree(visit, root, 1); }
// abstract functions to be implemented by derived class
virtual void insert(const T& newData) = 0;
@ -46,10 +71,11 @@ private:
void _postorder(void visit(const T&), BinaryTreeNode<T>* nodePtr) const;
void _printindented(void visit(const T&, int), BinaryTreeNode<T>* nodePtr) const;
void _printTree(void visit(const T&, int), BinaryTreeNode<T>* nodePtr, int level) const;
};
// Recursively deletes every node in the tree
template<class T>
void BinaryTree<T>::destroyTree(BinaryTreeNode<T>* nodePtr)
{
@ -61,6 +87,7 @@ void BinaryTree<T>::destroyTree(BinaryTreeNode<T>* nodePtr)
}
}
// Traverses through tree in preorder
template<typename T>
void BinaryTree<T>::_preorder(void visit(const T&), BinaryTreeNode<T>* nodePtr) const
{
@ -72,6 +99,7 @@ void BinaryTree<T>::_preorder(void visit(const T&), BinaryTreeNode<T>* nodePtr)
}
}
// Traverses through tree in inorder
template<typename T>
void BinaryTree<T>::_inorder(std::function<void(const T&)> visit, BinaryTreeNode<T>* nodePtr) const
{
@ -84,6 +112,7 @@ void BinaryTree<T>::_inorder(std::function<void(const T&)> visit, BinaryTreeNode
}
}
// Traverses through tree in postorder
template<typename T>
void BinaryTree<T>::_postorder(void visit(const T&), BinaryTreeNode<T>* nodePtr) const
{
@ -95,13 +124,15 @@ void BinaryTree<T>::_postorder(void visit(const T&), BinaryTreeNode<T>* nodePtr)
}
}
template<typename T>
void BinaryTree<T>::_printindented(void visit(const T&, int), BinaryTreeNode<T>* nodePtr) const {
// Prints tree using function pointer
template<class T>
void BinaryTree<T>::_printTree(void visit(const T&, int), BinaryTreeNode<T>* nodePtr, int level) const
{
if (nodePtr) {
T item = nodePtr->getItem();
_printInnerNodes(visit, nodePtr->getLeftPtr());
if (nodePtr->getLeftPtr() || nodePtr->getRightPtr()) visit(item);
_printInnerNodes(visit, nodePtr->getRightPtr());
visit(item, level);
_printTree(visit, nodePtr->getRightPtr(), level + 1);
_printTree(visit, nodePtr->getLeftPtr(), level + 1);
}
}

View File

@ -1,8 +1,26 @@
/* Unit 2: BST
*
* - Written in template format for flexibility
*
* - In project, BST holds primary key of CPU IDs
*
* - Sorted based off string comparison
*
* - Has insert, search, and remove functionality
*
* - Has multiple transversal functions (inorder, preorder, postorder)
*
* - Has printTree function that prints all nodes in function
*
* - In project, function pointer is used to print in indented format
*
* Written By: Tuhin Mondal
*/
#ifndef INC_08_TEAM_PROJECT_BINARYTREENODE_H
#define INC_08_TEAM_PROJECT_BINARYTREENODE_H
#include <stdexcept>
template<typename T>
class BinaryTreeNode {
private:

15
CPU.cpp
View File

@ -6,11 +6,14 @@ using namespace std;
void display(const CPU &cpu) {
const int minTotalWidth = max((size_t) 38, cpu.cpuId.length() + 2);
// Calculate total width, make sure architecture fits
const vector<int> widths = {18, max(minTotalWidth - 19, (int) cpu.architecture.length() + 2)};
const int totalWidth = widths[0] + widths[1];
// CPU ID
// width is different because bold characters are counted but invisible
string boldCenteredCpuId = centeredStr(boldStr(cpu.cpuId), 46);
printTableHeader({39}, {boldCenteredCpuId});
static const vector<int> widths = {18, 20};
string boldCenteredCpuId = centeredStr(boldStr(cpu.cpuId), totalWidth + 8);
printTableHeader({totalWidth + 1}, {boldCenteredCpuId});
// Release Year
cout << "| ";
@ -52,10 +55,10 @@ void display(const CPU &cpu) {
printTableFooter(widths);
}
void iDisplay(const CPU &cpu, int level) {
void iDisplay(const string &cpuId, int level) {
for (int i = 0; i < level; i++)
cout << " ";
cout << cpu.cpuId << endl;
cout << "..";
cout << level << ")." << cpuId << endl;
}
void rowDisplay(const CPU &cpu, const vector<int> &widths) {

36
CPU.h
View File

@ -1,3 +1,8 @@
// CPU class
//
// Written by: Kevin Galvan Serrano
// Modified by: Iurii Tatishchev
#ifndef INC_08_TEAM_PROJECT_CPU_H
#define INC_08_TEAM_PROJECT_CPU_H
@ -72,19 +77,46 @@ public:
};
/*
* Display the CPU object as a table.
*
* Written by: Iurii Tatishchev
*/
void display(const CPU &cpu);
void iDisplay(const CPU &cpu, int level);
/*
* Display the CPU object as part of an indented tree.
*
* Written by: Tuhin Mondal
*/
void iDisplay(const std::string &cpuId, int level);
/*
* Display the CPU object as a table row.
*
* Written by: Iurii Tatishchev
*/
void rowDisplay(const CPU &cpu, const std::vector<int> &widths);
/*
* Overload the << operator to display the CPU object.
*
* Written by: Iurii Tatishchev
*/
std::ostream &operator<<(std::ostream &os, const CPU &cpu);
/*~*~*~*
Hash function: takes the key and returns the index in the hash table
Hash function: takes the key and returns the index in the hash table.
Written by: Joshiro Lawrence
*~**/
int key_to_index(const CPU &key, int size);
/*~*~*~*
Converts the CPU object to a string.
Written by: Iurii Tatishchev
*~**/
std::string to_string(const CPU &cpu);
#endif // INC_08_TEAM_PROJECT_CPU_H

View File

@ -1,3 +1,33 @@
/*
Name: DisplayManager
Written By: Kevin Galvan Serrano
Modified By:
Purpose: Manage the display of CPU information and the binary search tree
Input: HashTable and BinarySearchTree objects
Output: Displayed CPU information and tree structure
Procedure: Uses the HashTable and BinarySearchTree to retrieve and display information
*/
/*
Name: displayAll
Written By: Kevin Galvan Serrano
Modified By:
Purpose: Display all CPUs in the database
Input: None
Output: List of all CPUs sorted by their ID
Procedure: Iterates through the HashTable and displays each CPU's information
*/
/*
Name: displayTree
Written By: Kevin Galvan Serrano
Modified By:
Purpose: Display the BST as an indented tree
Input: None
Output: Indented representation of the binary search tree
Procedure: Performs an inorder traversal of the BST, displaying each node with appropriate indentation
*/
#ifndef DISPLAY_MANAGER_H
#define DISPLAY_MANAGER_H
@ -55,11 +85,20 @@ void DisplayManager<T>::displayTree() const {
"Architecture",
"Base Clock (GHz)"
};
static const std::vector<int> widths = {20, 14, 12, 20, 18};
printTableHeader(widths, headers);
std::vector<int> widths = {20, 14, 12, 20, 18};
// Call the BST's inorder traversal method to calculate the column widths
bst->inOrder([this, &widths](const string &cpuId) {
CPU cpu;
cpu.setCpuId(cpuId);
this->hashTable->search(cpu, cpu, key_to_index);
widths[0] = max(cpu.getCpuId().length() + 2, (size_t) widths[0]);
widths[3] = max(cpu.getArchitecture().length() + 2, (size_t) widths[3]);
});
printTableHeader(widths, headers);
// Call the BST's inorder traversal method to display the tree
bst->inOrder([this](const string &cpuId) {
bst->inOrder([this, &widths](const string &cpuId) {
CPU cpu;
cpu.setCpuId(cpuId);
this->hashTable->search(cpu, cpu, key_to_index);

View File

@ -1,9 +1,13 @@
/*
Joshiro Lawrence - Unit 3 (Hash Table)
Wrote all functions in this file.
*/
#ifndef INC_08_TEAM_PROJECT_HASHNODE_H
#define INC_08_TEAM_PROJECT_HASHNODE_H
template<typename T>
class HashNode
{
class HashNode {
private:
T item;
int occupied; // 1 -> occupied, 0 -> empty from start, -1 -> empty after removal
@ -11,31 +15,35 @@ private:
public:
// constructors
HashNode()
{
HashNode() {
occupied = 0;
numCollisions = 0;
}
HashNode(T anItem)
{
HashNode(T anItem) {
item = anItem;
occupied = 1;
numCollisions = 0;
}
HashNode(T anItem, int ocp, int nCol)
{
HashNode(T anItem, int ocp, int nCol) {
item = anItem;
occupied = ocp;
numCollisions = nCol;
}
// setters
void setItem(const T &anItem) { item = anItem; }
void setOccupied(int ocp) { occupied = ocp; }
void setNumCollisions(int nCol) { numCollisions = nCol; }
// getters
T getItem() const { return item; }
int getOccupied() const { return occupied; }
int getNumCollisions() const { return numCollisions; }
};

View File

@ -1,3 +1,10 @@
/*
Joshiro Lawrence - Unit 3 (Hash Table)
Wrote all functions in this file except for _reHash, writeToFile, and the code block of insert that deals with rehashing
The purpose of the hash table in this project is to store the CPU objects. This allows for quick insertion, search, and removal into the hash table. Specifically, the hash table allows for quick searching in this program, to tell if a CPU object exists in the database already.
*/
#ifndef INC_08_TEAM_PROJECT_HASHTABLE_H
#define INC_08_TEAM_PROJECT_HASHTABLE_H
@ -24,10 +31,12 @@ private:
int hashSize;
int count;
void _reHash(int h(const T &key, int size));
public:
HashTable() {
count = 0;
hashSize = 3;
hashSize = 7;
hashAry = new HashNode<T>[hashSize];
}
@ -59,8 +68,6 @@ public:
int search(T &itemOut, const T &key, int h(const T &key, int size)) const;
void reHash(int h(const T &key, int size));
friend void writeToFile<T>(const HashTable<T> &hashTable, const string &filename, string visit(const T &));
};
@ -98,8 +105,11 @@ int HashTable<T>::getMaxCollisions() const {
*~**/
template<typename T>
bool HashTable<T>::insert(const T &itemIn, int h(const T &key, int size)) {
if (count == hashSize)
return false;
if (getLoadFactor() >= 75) {
cout << "Load factor is " << getLoadFactor() << ". Rehashing...\n";
_reHash(key_to_index);
}
int ind = h(itemIn, hashSize);
for (int i = 0; i < hashSize; i++) {
@ -170,8 +180,17 @@ int HashTable<T>::search(T &itemOut, const T &key, int h(const T &key, int size)
return -1;
}
/*
* Name: reHash
* Written By: Kevin Cremin
* Modified By:
* Purpose: Increases the size of the Hash Table's array
* Input: Hash function
* Output: N/A
* Procedure: Creates a larger array, and then traverses the old array, rehashing each item into the new one.
*/
template<class T>
void HashTable<T>::reHash(int h(const T &key, int size)) {
void HashTable<T>::_reHash(int h(const T &key, int size)) {
int nHashSize = hashSize * 2;
@ -187,11 +206,11 @@ void HashTable<T>::reHash(int h(const T &key, int size)) {
int nIndex = h(aT, nHashSize);
for (int j = 0; j < hashSize; j++) {
for (int j = 0; j < nHashSize; j++) {
if (nHashAry[nIndex].getOccupied() != 1) {
nHashAry[nIndex].setItem(aT);
nHashAry[nIndex].setOccupied(1);
nHashAry[nIndex].setNumCollisions(i);
nHashAry[nIndex].setNumCollisions(j);
break;
}
@ -204,13 +223,22 @@ void HashTable<T>::reHash(int h(const T &key, int size)) {
hashSize = nHashSize;
}
/*
* Name: writeToFile
* Written By: Kevin Cremin
* Modified By:
* Purpose: Outputs each item in the hash table into a file.
* Input: Name of the file, function
* Output: N/A
* Procedure: Checks if a bucket is in use, and outputs it into the file.
*/
template<typename T>
void writeToFile(const HashTable<T> &hashTable, const string &filename, string visit(const T &)) {
ofstream outputFile(filename);
if (!outputFile.good()) {
cout << "Error opening the output file: \"" << filename << "\"" << endl;
exit(EXIT_FAILURE);
return;
}
outputFile.flush();
@ -224,6 +252,7 @@ void writeToFile(const HashTable<T> &hashTable, const string &filename, string v
}
}
cout << "Data written to file \"" << filename << "\".\n";
outputFile.close();
}

View File

@ -1,3 +1,24 @@
/*
Name: SearchManager
Written By: Kevin Galvan Serrano
Modified By:
Purpose: Manage the search functionality for CPUs
Input: HashTable object
Output: Search results or error messages
Procedure: Prompts user for search criteria, uses the HashTable to find matching CPUs, and displays results
*/
/*
Name: searchCPU
Written By: Kevin Galvan Serrano
Modified By:
Purpose: Search for a CPU by its ID
Input: CPU ID (string)
Output: CPU information if found, or a "not found" message
Procedure: Uses the HashTable's search function to find the CPU, then displays its information
*/
#ifndef SEARCH_MANAGER_H
#define SEARCH_MANAGER_H

60
Stack.h
View File

@ -1,3 +1,63 @@
/*
Name: Stack
Written By: Kevin Galvan Serrano
Modified By:
Purpose: Implement a generic stack data structure
Input: Template parameter T for the type of elements stored in the stack
Output: N/A
Procedure: Uses a linked list of StackNodes to store elements in a Last-In-First-Out (LIFO) order
*/
/*
Name: push
Written By: Kevin Galvan Serrano
Modified By:
Purpose: Add an element to the top of the stack
Input: Element of type T to be added
Output: None
Procedure: Creates a new StackNode with the input data and adds it to the top of the stack
*/
/*
Name: pop
Written By: Kevin Galvan Serrano
Modified By:
Purpose: Remove and return the top element from the stack
Input: None
Output: Element of type T that was at the top of the stack
Procedure: Removes the top StackNode, returns its data, and updates the stack accordingly
*/
/*
Name: peek
Written By: Kevin Galvan Serrano
Modified By:
Purpose: Return the top element of the stack without removing it
Input: None
Output: Element of type T that is at the top of the stack
Procedure: Returns the data of the top StackNode without modifying the stack
*/
/*
Name: isEmpty
Written By: Kevin Galvan Serrano
Modified By:
Purpose: Check if the stack is empty
Input: None
Output: Boolean indicating whether the stack is empty
Procedure: Returns true if the stack contains no elements, false otherwise
*/
/*
Name: getCount
Written By: Kevin Galvan Serrano
Modified By:
Purpose: Get the number of elements in the stack
Input: None
Output: Integer representing the number of elements in the stack
Procedure: Returns the count of elements currently in the stack
*/
#ifndef INC_08_TEAM_PROJECT_STACK_H
#define INC_08_TEAM_PROJECT_STACK_H

View File

@ -1,3 +1,13 @@
/*
Name: StackNode
Written By: Kevin Galvan Serrano
Modified By:
Purpose: Represent a single node in the Stack data structure
Input: Template parameter T for the type of data stored in the node
Output: N/A
Procedure: Stores an element of data and a pointer to the next StackNode in the stack
*/
#ifndef INC_08_TEAM_PROJECT_STACKNODE_H
#define INC_08_TEAM_PROJECT_STACKNODE_H

View File

@ -1,3 +1,33 @@
/*
Name: UndoManager
Written By: Kevin Galvan Serrano
Modified By:
Purpose: Manage the undo delete functionality
Input: HashTable, BinarySearchTree, and Stack objects
Output: Messages confirming undo operations
Procedure: Uses a Stack to keep track of deleted CPUs and reinserts them when undoing a deletion
*/
/*
Name: addToUndoStack
Written By: Kevin Galvan Serrano
Modified By:
Purpose: Add a deleted CPU to the undo stack
Input: CPU object
Output: None
Procedure: Pushes the deleted CPU onto the undo stack
*/
/*
Name: undoDelete
Written By: Kevin Galvan Serrano
Modified By:
Purpose: Undo the most recent CPU deletion
Input: None
Output: Message confirming the undo operation
Procedure: Pops a CPU from the undo stack and reinserts it into the HashTable and BinarySearchTree
*/
#ifndef UNDO_MANAGER_H
#define UNDO_MANAGER_H

42
fio.cpp
View File

@ -1,3 +1,10 @@
// Unit 5: File I/O
// - Determine hash size based on the number of records in the file
// - Read data from the input file and insert them into the hash table and BST
//
// Written by: Kevin Cremin
// Modified by: Iurii Tatishchev
#include <sstream>
#include "fio.h"
@ -10,8 +17,8 @@ using namespace std;
int findHashSize(const string &filename) {
ifstream inputFile(filename);
if (!inputFile) {
cout << "Error opening the input file: \"" << filename << "\"" << endl;
if (!inputFile.good()) {
// cout << "Error opening the input file: \"" << filename << "\"" << endl;
return -1;
}
// cout << "Reading data from \"" << filename << "\"" << endl;
@ -32,9 +39,9 @@ void insertFile(const string &filename, BinarySearchTree<string> &bst, HashTable
ifstream inputFile(filename);
// cout << "Reading data from \"" << filename << "\"" << endl;
if (!inputFile) {
cout << "Error opening the input file: \"" << filename << "\"" << endl;
exit(EXIT_FAILURE);
if (!inputFile.good()) {
cout << "Error opening the input file: \"" << filename << "\". Skipping...\n";
return;
}
string line;
@ -47,6 +54,12 @@ void insertFile(const string &filename, BinarySearchTree<string> &bst, HashTable
getline(temp, name, ';');
// check if the CPU is already in the hash table
CPU key(name, -1, -1, "", -1);
if (hash.search(key, key, key_to_index) != -1) {
cout << "Duplicate CPU \"" << name << "\" found in file. Skipping...\n";
continue;
}
temp.ignore();
getline(temp, strToNum, ';');
releaseYear = stoi(strToNum);
@ -71,6 +84,7 @@ void insertFile(const string &filename, BinarySearchTree<string> &bst, HashTable
}
inputFile.close();
cout << "Data from file \"" << filename << "\" added.\n";
}
@ -136,6 +150,15 @@ void insertCPU(BinarySearchTree<string> &bst, HashTable<CPU> &hash) {
hash.insert(aCPU, key_to_index);
}
/*
* Name: isInteger
* Written By: Kevin Cremin
* Modified By:
* Purpose: Determine if input is an integer
* Input: String to test
* Output: Bool of whether input was an integer
* Procedure: Checks that all characters are digits.
*/
bool isInteger(const string &str) {
for (int i = 0; i < str.length(); i++) {
if (!(isdigit(str[i]))) {
@ -146,6 +169,15 @@ bool isInteger(const string &str) {
return true;
}
/*
* Name: isDouble
* Written By: Kevin Cremin
* Modified By:
* Purpose: Determine if input is a double
* Input: String to test
* Output: Bool of whether input was an double
* Procedure: Checks that all characters are digits and that there is at most one period.
*/
bool isDouble(const string &str) {
int chance = 0;

33
fio.h
View File

@ -1,8 +1,8 @@
// Unit 5: File I/O
// - Determine hash size based on the number of records in the file
// - Read data from the input file and insert them into the hash table and BST
// - Save to file (in hash table sequence)
// - Re-hashing
// - Save to file (in hash table sequence) (in HashTable.h)
// - Re-hashing (in HashTable.h)
//
// Written by: Kevin Cremin
@ -18,10 +18,39 @@
using std::string;
/*
* Name: findHashSize
* Written By: Kevin Cremin
* Modified By: Iurii Tatishchev
* Purpose: Find the the necessary initial size of the hash table
* Input: Name of file
* Output: Appropriate size of hash array based on how many items are in the fileName
* Procedure: Multiplies number of items in file by two, then finds next prime number
*/
int findHashSize(const string &filename);
/*
* Name: insertFile
* Written By: Kevin Cremin
* Modified By: Iurii Tatishchev
* Purpose: Input all items in the file into the program.
* Input: Name of file, the Binary Search Tree, and the Hash Table
* Output: N/A
* Procedure: Goes through each item in the file and inputs them into the table and tree,
* verifying that there are no duplicate keys.
*/
void insertFile(const string &filename, BinarySearchTree<string> &bst, HashTable<CPU> &hash);
/*
* Name: insertCPU
* Written By: Kevin Cremin
* Modified By:
* Purpose: Input an individual CPU from the user
* Input: The Binary Search Tree and the Hash Table
* Output: N/A
* Procedure: Requests information from the user, making sure that it is not a duplicate,
* and that all inputs are the correct data type.
*/
void insertCPU(BinarySearchTree<string> &bst, HashTable<CPU> &hash);
#endif //INC_08_TEAM_PROJECT_FIO_H

View File

@ -24,6 +24,11 @@
// The output file name does not have to be the same as the input file name,
// but the file format must be the same so that it can be read back into the program.
// Unit 1: Main
// - Menu and input processing
//
// Written by: Iurii Tatishchev
#include <iostream>
#include <string>
#include "utils.h"
@ -40,6 +45,9 @@ using namespace std;
const string DEFAULT_FILE = "out.txt";
/*
* Takes a command character and calls the appropriate function to process the command.
*/
void processInput(char command, HashTable<CPU> &table, BinarySearchTree<string> &tree,
UndoManager<CPU> &undoManager, DisplayManager<CPU> &displayManager,
SearchManager<CPU> &searchManager);
@ -49,11 +57,15 @@ int main() {
printHelp();
int hashSize = findHashSize(DEFAULT_FILE);
HashTable<CPU> cpuTable = HashTable<CPU>(hashSize);
HashTable<CPU> cpuTable = HashTable<CPU>(hashSize == -1 ? 7 : hashSize);
BinarySearchTree<string> cpuTree;
// Read initial data from output file
// Read initial data from output file if it exists
if (hashSize != -1) {
insertFile(DEFAULT_FILE, cpuTree, cpuTable);
} else {
cout << "Could not open default file \"" << DEFAULT_FILE << "\". Starting with an empty database.\n";
}
DisplayManager<CPU> displayManager(&cpuTable, &cpuTree);
SearchManager<CPU> searchManager(&cpuTable);
@ -64,7 +76,9 @@ int main() {
cout << "Enter an option (H - for help): ";
cin >> command;
command = toupper(command, std::locale());
// Temporary try catch block to handle unimplemented commands
// Temporary try catch block to handle unimplemented commands.
// Actually, this catches exceptions like stoi (integer input too large)
// so I think leaving it is a good idea.
try {
processInput(command, cpuTable, cpuTree, undoManager, displayManager, searchManager);
}
@ -73,18 +87,31 @@ int main() {
}
}
// Quit command received
writeToFile(cpuTable, DEFAULT_FILE, to_string);
cout << "Exiting program...\n";
return 0;
}
/*
* Input a new record into the table and tree.
*/
void handleInsert(HashTable<CPU> &hashTable, BinarySearchTree<string> &tree);
/*
* Input data from a file into the table and tree.
*/
void handleFileInput(HashTable<CPU> &hashTable, BinarySearchTree<string> &tree);
/*
* Delete a record from the table and tree.
* Also adds the deleted record to the undo stack.
*/
void deleteCPU(HashTable<CPU> &hashTable, BinarySearchTree<string> &tree, UndoManager<CPU> &undoManager);
/*
* Write data to a file.
* Also clears the undo stack.
*/
void handleFileOutput(HashTable<CPU> &hashTable, UndoManager<CPU> &undoManager);
void processInput(char command, HashTable<CPU> &cpuTable, BinarySearchTree<string> &cpuTree,
@ -117,17 +144,18 @@ void processInput(char command, HashTable<CPU> &cpuTable, BinarySearchTree<strin
handleFileOutput(cpuTable, undoManager);
break;
case 'T': // Hashtable statistics
cout << "Load factor: " << cpuTable.getLoadFactor() << std::endl;
cout << "Total number of collisions: " << cpuTable.getTotalCollisions() << std::endl;
cout << "Longest collision path: " << cpuTable.getMaxCollisions() << std::endl;
cout << "Load factor: " << cpuTable.getLoadFactor() << '\n';
cout << "Total number of collisions: " << cpuTable.getTotalCollisions() << '\n';
cout << "Longest collision path: " << cpuTable.getMaxCollisions() << '\n';
break;
case 'P': // Print indented tree
throw std::logic_error("Not yet implemented: Print indented tree");
cpuTree.printTree(iDisplay);
break;
case 'Z': // Display names of team members
printTeam();
break;
case 'Q': // Quit
writeToFile(cpuTable, DEFAULT_FILE, to_string);
break;
default:
cout << "Invalid command. Press 'H' to view available commands.\n";
@ -135,10 +163,6 @@ void processInput(char command, HashTable<CPU> &cpuTable, BinarySearchTree<strin
}
void handleInsert(HashTable<CPU> &hashTable, BinarySearchTree<string> &tree) {
if (hashTable.getLoadFactor() >= 75) {
cout << "Load factor is " << hashTable.getLoadFactor() << ". Rehashing...\n";
hashTable.reHash(key_to_index);
}
insertCPU(tree, hashTable);
}
@ -148,19 +172,19 @@ void handleFileInput(HashTable<CPU> &hashTable, BinarySearchTree<string> &tree)
cin >> filename;
insertFile(filename, tree, hashTable);
cout << "Data from file \"" << filename << "\" added.\n";
}
void deleteCPU(HashTable<CPU> &hashTable, BinarySearchTree<string> &tree, UndoManager<CPU> &undoManager) {
string cpuId;
cout << "Enter CPU ID to delete: ";
cin >> cpuId;
cin.ignore();
getline(cin, cpuId);
CPU cpu(cpuId, 0, 0, "", 0.0);
CPU cpuFound;
while (hashTable.search(cpuFound, cpu, key_to_index) == -1) {
cout << "CPU ID not found. Enter a valid CPU ID: ";
cin >> cpuId;
cpu = CPU(cpuId, 0, 0, "", 0.0);
if (hashTable.search(cpuFound, cpu, key_to_index) == -1) {
cout << "CPU ID \"" << cpuId << "\" not found.\n";
return;
}
hashTable.remove(cpuFound, cpu, key_to_index);
undoManager.addToUndoStack(cpuFound);
@ -175,5 +199,4 @@ void handleFileOutput(HashTable<CPU> &hashTable, UndoManager<CPU> &undoManager)
cin >> filename;
writeToFile(hashTable, filename, to_string);
undoManager.clearUndoStack();
cout << "Data written to file \"" << filename << "\".\n";
}

View File

@ -58,16 +58,6 @@ void printTableFooter(const vector<int> &widths) {
cout << "\b\n";
}
/*
* Print ascii/unicode table with given column widths and data. For example:
*
* | Col1 | Col2 | Col3 | Numeric Column |
* +========================================+==========+========================+================+
* | Value 1 | Value 2 | 123 | 10.0 |
* | Separate | cols | with a tab or 4 spaces | -2,027.1 |
* | This is a row with only one cell | | | |
*
*/
void printTable(const vector<int> &widths, const vector<vector<string>> &data) {
printTableHeader(widths, data[0]);
for (int i = 1; i < data.size(); i++) {

52
utils.h
View File

@ -1,3 +1,6 @@
// Contains utility functions mostly for printing tables and formatting.
// Written by: Iurii Tatishchev
#ifndef INC_08_TEAM_PROJECT_UTILS_H
#define INC_08_TEAM_PROJECT_UTILS_H
@ -6,22 +9,71 @@
using namespace std;
/*
* Print a single row of a table, given the widths of each column and the data for the row.
*
* Example output:
* | Value 1 | Value 2 | 123 | 10.0 |
*/
void printRow(const vector<int> &widths, const vector<string> &row);
/*
* Print the header of a table, given the widths of each column and the headers for each column.
* Unicode characters are used to draw the table.
*
* Example output:
*
* | Col1 | Col2 | Col3 | Numeric Column |
* +========================================+==========+========================+================+
*/
void printTableHeader(const vector<int> &widths, const vector<string> &headers);
/*
* Print the footer of a table, given the widths of each column.
*
* Example output:
*
*/
void printTableFooter(const vector<int> &widths);
/*
* Print ascii/unicode table with given column widths and data. For example:
*
* | Col1 | Col2 | Col3 | Numeric Column |
* +========================================+==========+========================+================+
* | Value 1 | Value 2 | 123 | 10.0 |
* | Separate | cols | with a tab or 4 spaces | -2,027.1 |
* | This is a row with only one cell | | | |
*
*/
void printTable(const vector<int> &widths, const vector<vector<string>> &data);
/*
* Print a help table with all available commands and their descriptions.
*/
void printHelp();
/*
* Print a table with the team members and their roles.
*/
void printTeam();
/*
* Find the next prime number after n.
*
* Written by: Kevin Cremin
* Modified by: Iurii Tatishchev
*/
int findNextPrime(int n);
/*
* Add bold control characters around a string for terminal output.
*/
string boldStr(const string &str);
/*
* Pad a string with spaces on both sides to center it in a string of a given width.
*/
string centeredStr(const string &str, int width);
#endif //INC_08_TEAM_PROJECT_UTILS_H