diff --git a/CPU.cpp b/CPU.cpp index 4618648..57ec8f6 100644 --- a/CPU.cpp +++ b/CPU.cpp @@ -15,3 +15,11 @@ int key_to_index(const CPU &key, int size) { sum += k[i]; return sum % size; } + +std::string to_string(const CPU &cpu) { + return cpu.cpuId + "; " + + std::to_string(cpu.releaseYear) + "; " + + std::to_string(cpu.coreCount) + "; " + + cpu.architecture + "; " + + std::to_string(cpu.baseClock) + ";"; +} diff --git a/CPU.h b/CPU.h index 3324cdc..e5410f3 100644 --- a/CPU.h +++ b/CPU.h @@ -57,7 +57,7 @@ public: // Friend function declarations friend void display(const CPU &cpu); - friend void iDisplay(const CPU& cpu, int level) { + friend void iDisplay(const CPU &cpu, int level) { for (int i = 1; i < level; i++) std::cout << ".."; std::cout << level << "). " << cpu.cpuId << std::endl; @@ -65,7 +65,10 @@ public: friend std::ostream &operator<<(std::ostream &os, const CPU &cpu); - friend int key_to_index(const CPU &key, int size) ; + friend int key_to_index(const CPU &key, int size); + + friend std::string to_string(const CPU &cpu); + }; std::ostream &operator<<(std::ostream &os, const CPU &cpu); @@ -75,4 +78,6 @@ std::ostream &operator<<(std::ostream &os, const CPU &cpu); *~**/ int key_to_index(const CPU &key, int size); +std::string to_string(const CPU &cpu); + #endif // INC_08_TEAM_PROJECT_CPU_H diff --git a/HashTable.h b/HashTable.h index 4be395d..70ea525 100644 --- a/HashTable.h +++ b/HashTable.h @@ -1,57 +1,65 @@ #ifndef INC_08_TEAM_PROJECT_HASHTABLE_H #define INC_08_TEAM_PROJECT_HASHTABLE_H -#include +#include #include "HashNode.h" +#include "CPU.h" -template -class HashTable -{ +using std::string, std::ofstream, std::cout, std::endl; + +template +class HashTable { private: HashNode *hashAry; int hashSize; int count; public: - HashTable() - { + HashTable() { count = 0; hashSize = 97; hashAry = new HashNode[hashSize]; } - HashTable(int n) - { + + HashTable(int n) { count = 0; hashSize = n; hashAry = new HashNode[hashSize]; } + ~HashTable() { delete[] hashAry; } int getCount() const { return count; } + int getHashSize() const { return hashSize; } + double getLoadFactor() const { return 100.0 * count / hashSize; } + bool isEmpty() const { return count == 0; } + bool isFull() const { return count == hashSize; } int getTotalCollisions() const; + int getMaxCollisions() const; bool insert(const T &itemIn, int h(const T &key, int size)); + bool remove(T &itemOut, const T &key, int h(const T &key, int size)); + int search(T &itemOut, const T &key, int h(const T &key, int size)) const; + + void outputFile(const string &filename, string visit(const T &)); }; /*~*~*~* Get total number of collisions throughout hash table *~**/ -template -int HashTable::getTotalCollisions() const -{ +template +int HashTable::getTotalCollisions() const { int total = 0; - for (int i = 0; i < hashSize; i++) - { - if (hashAry[i].getOccupied() == 1) - { + for (int i = 0; i < hashSize; i++) { + if (hashAry[i].getOccupied() == 1) { total += hashAry[i].getNumCollisions(); } } @@ -61,14 +69,11 @@ int HashTable::getTotalCollisions() const /*~*~*~* Get longest collision length in hash table *~**/ -template -int HashTable::getMaxCollisions() const -{ +template +int HashTable::getMaxCollisions() const { int high = 0; - for (int i = 0; i < hashSize; i++) - { - if (hashAry[i].getOccupied() == 1 && hashAry[i].getNumCollisions() > high) - { + for (int i = 0; i < hashSize; i++) { + if (hashAry[i].getOccupied() == 1 && hashAry[i].getNumCollisions() > high) { high = hashAry[i].getNumCollisions(); } } @@ -79,17 +84,14 @@ int HashTable::getMaxCollisions() const Insert an item into the hash table It does not reject duplicates *~**/ -template -bool HashTable::insert(const T &itemIn, int h(const T &key, int size)) -{ +template +bool HashTable::insert(const T &itemIn, int h(const T &key, int size)) { if (count == hashSize) return false; int ind = h(itemIn, hashSize); - for (int i = 0; i < hashSize; i++) - { - if (hashAry[(ind + i) % hashSize].getOccupied() != 1) - { + for (int i = 0; i < hashSize; i++) { + if (hashAry[(ind + i) % hashSize].getOccupied() != 1) { hashAry[(ind + i) % hashSize].setOccupied(1); hashAry[(ind + i) % hashSize].setItem(itemIn); hashAry[(ind + i) % hashSize].setNumCollisions(i); @@ -110,25 +112,19 @@ bool HashTable::insert(const T &itemIn, int h(const T &key, int size)) if not found: - returns false *~**/ -template -bool HashTable::remove(T &itemOut, const T &key, int h(const T &key, int size)) -{ +template +bool HashTable::remove(T &itemOut, const T &key, int h(const T &key, int size)) { int ind = h(key, hashSize); - for (int i = 0; i < hashSize; i++) - { - if (hashAry[(ind + i) % hashSize].getOccupied() == 1) - { - if (hashAry[(ind + i) % hashSize].getItem() == key) - { + for (int i = 0; i < hashSize; i++) { + if (hashAry[(ind + i) % hashSize].getOccupied() == 1) { + if (hashAry[(ind + i) % hashSize].getItem() == key) { itemOut = hashAry[(ind + i) % hashSize].getItem(); hashAry[(ind + i) % hashSize].setOccupied(-1); // Do not access a node with occupied of -1 count--; return true; } - } - else if (hashAry[(ind + 1) % hashSize].getOccupied() == 0) - { + } else if (hashAry[(ind + 1) % hashSize].getOccupied() == 0) { // If using linear probing and we come across a spot that has been empty since start, the item is not in the table break; } @@ -144,22 +140,16 @@ bool HashTable::remove(T &itemOut, const T &key, int h(const T &key, int size - returns the number of collisions for this key if not found, returns -1 *~**/ -template -int HashTable::search(T &itemOut, const T &key, int h(const T &key, int size)) const -{ +template +int HashTable::search(T &itemOut, const T &key, int h(const T &key, int size)) const { int ind = h(key, hashSize); - for (int i = 0; i < hashSize; i++) - { - if (hashAry[(ind + i) % hashSize].getOccupied() == 1) - { - if (hashAry[(ind + i) % hashSize].getItem() == key) - { + for (int i = 0; i < hashSize; i++) { + if (hashAry[(ind + i) % hashSize].getOccupied() == 1) { + if (hashAry[(ind + i) % hashSize].getItem() == key) { itemOut = hashAry[(ind + i) % hashSize].getItem(); return hashAry[(ind + i) % hashSize].getNumCollisions(); } - } - else if (hashAry[(ind + 1) % hashSize].getOccupied() == 0) - { + } else if (hashAry[(ind + 1) % hashSize].getOccupied() == 0) { // If using linear probing and we come across a spot that has been empty since start, the item is not in the table break; } @@ -168,4 +158,31 @@ int HashTable::search(T &itemOut, const T &key, int h(const T &key, int size) return -1; } +template +void HashTable::outputFile(const string &filename, string visit(const T &)) { + ofstream outputFile(filename); + cout << "Outputting data to \"" << filename << "\"" << endl; + + if (!outputFile.good()) { + cout << "Error opening the output file: \"" << filename << "\"" << endl; + exit(EXIT_FAILURE); + } + + T aT; + + if (hashAry[0].getOccupied() == 1) { + aT = hashAry[0].getItem(); + outputFile << visit(aT); + } + + for (int i = 1; i < hashSize; i++) { + if (hashAry[i].getOccupied() == 1) { + aT = hashAry[i].getItem(); + outputFile << endl << visit(aT); + } + } + + outputFile.close(); +} + #endif // INC_08_TEAM_PROJECT_HASHTABLE_H diff --git a/Stack.cpp b/Stack.cpp deleted file mode 100644 index d33c862..0000000 --- a/Stack.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include "Stack.h" - -// Destructor -template -Stack::~Stack() { - while (!isEmpty()) { - pop(); - } -} - -// Push an element onto the stack -template -void Stack::push(const T &data) { - auto *newNode = new StackNode(data); - newNode->next = top; - top = newNode; - count++; -} - -// Pop the top element from the stack -template -T Stack::pop() { - if (isEmpty()) { - throw std::out_of_range("Stack is empty. Cannot pop."); - } - T data = top->data; - StackNode *temp = top; - top = top->next; - delete temp; - count--; - return data; -} - -// Get the top element of the stack without removing it -template -T Stack::peek() { - if (isEmpty()) { - throw std::out_of_range("Stack is empty. Cannot peek."); - } - return top->data; -} - -// Get the number of elements in the stack -template -int Stack::getCount() const { - return count; -} - -// Check if the stack is empty -template -bool Stack::isEmpty() const { - return count == 0; -} - -// Explicit instantiation of the template class for the desired type(s) -template class Stack; \ No newline at end of file diff --git a/Stack.h b/Stack.h index c02b59a..589f6c3 100644 --- a/Stack.h +++ b/Stack.h @@ -13,17 +13,59 @@ private: public: Stack() : top(nullptr), count(0) {}; - ~Stack() { throw std::logic_error("Not implemented: ~Stack()"); }; + // Destructor + ~Stack(); + // Check if the stack is empty [[nodiscard]] bool isEmpty() const { return count == 0; }; + // Get the number of elements in the stack [[nodiscard]] int getCount() const { return count; }; - void push(const T &data) { throw std::logic_error("Not implemented: Stack.push()"); }; + // Push an element onto the stack + void push(const T &data); - T pop() { throw std::logic_error("Not implemented: Stack.pop()"); }; + // Pop the top element from the stack + T pop(); - T peek() { throw std::logic_error("Not implemented: Stack.peek()"); }; + // Get the top element of the stack without removing it + T peek(); }; +template +Stack::~Stack() { + while (!isEmpty()) { + pop(); + } +} + +template +void Stack::push(const T &data) { + auto *newNode = new StackNode(data); + newNode->next = top; + top = newNode; + count++; +} + +template +T Stack::pop() { + if (isEmpty()) { + throw std::out_of_range("Stack is empty. Cannot pop."); + } + T data = top->data; + StackNode *temp = top; + top = top->next; + delete temp; + count--; + return data; +} + +template +T Stack::peek() { + if (isEmpty()) { + throw std::out_of_range("Stack is empty. Cannot peek."); + } + return top->data; +} + #endif //INC_08_TEAM_PROJECT_STACK_H diff --git a/StackNode.h b/StackNode.h index 7a24bf2..50ac216 100644 --- a/StackNode.h +++ b/StackNode.h @@ -3,11 +3,11 @@ template class StackNode { +public: T data; StackNode *next; StackNode(const T &data) : data(data), next(nullptr) {} }; - #endif //INC_08_TEAM_PROJECT_STACKNODE_H diff --git a/main.cpp b/main.cpp index 308c2e4..5b432e7 100644 --- a/main.cpp +++ b/main.cpp @@ -65,11 +65,11 @@ int main() { processInput(command, cpuTable, cpuTree, undoManager, displayManager, searchManager); } catch (std::logic_error &e) { - cout << e.what() << '\n'; + cout << "Error: " << e.what() << '\n'; } } // Quit command received - // TODO: Write data to a file + cpuTable.outputFile("output.txt", to_string); cout << "Exiting program...\n"; return 0; @@ -81,7 +81,7 @@ void handleFileInput(HashTable &hashTable, BinarySearchTree &tree); void deleteCPU(HashTable &hashTable, BinarySearchTree &tree, UndoManager &undoManager); -// void undoDelete(HashTable &hashTable, BinarySearchTree &tree, UndoManager &undoManager); +void handleFileOutput(HashTable &hashTable, UndoManager &undoManager); void processInput(char command, HashTable &cpuTable, BinarySearchTree &cpuTree, UndoManager &undoManager, DisplayManager &displayManager, @@ -110,7 +110,7 @@ void processInput(char command, HashTable &cpuTable, BinarySearchTree &hashTable, BinarySearchTree &tree) cin >> filename; int hashSize = findHashSize(filename); hashTable = HashTable(hashSize); - tree = BinarySearchTree(); + tree.clear(); insertFile(filename, tree, hashTable); cout << "Data from file \"" << filename << "\" added.\n"; @@ -163,3 +163,12 @@ void deleteCPU(HashTable &hashTable, BinarySearchTree &tree, UndoMa cout << "CPU ID \"" << cpuId << "\" deleted.\n"; } + +void handleFileOutput(HashTable &hashTable, UndoManager &undoManager) { + string filename; + cout << "Enter filename: "; + cin >> filename; + hashTable.outputFile(filename, to_string); + undoManager.clearUndoStack(); + cout << "Data written to file \"" << filename << "\".\n"; +}