From 4134a6d4d279f1f0fabd50dd103513528504984f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20V=C3=ADtor=20Ferreira?= Date: Mon, 23 Oct 2023 21:26:03 +0100 Subject: [PATCH 1/6] First implementation of studentsClasses (with SEGFAULT) --- src/studentsClasses.cpp | 115 ++++++++++++++++++++++++++++++++++++++++ src/studentsClasses.hpp | 34 ++++++++++++ 2 files changed, 149 insertions(+) diff --git a/src/studentsClasses.cpp b/src/studentsClasses.cpp index e69de29..06433a0 100644 --- a/src/studentsClasses.cpp +++ b/src/studentsClasses.cpp @@ -0,0 +1,115 @@ +#include "studentsClasses.hpp" +#include "Utils.hpp" +#include +#include +#include +#include +#include + +// Constructor +StudentsClasses::StudentsClasses(std::string line) { + std::vector linebuf; + parse_csv_line(line, linebuf); + student_code_ = parse_student_code(linebuf[0]); + student_name_ = linebuf[1]; + uc_code_ = parse_uc(linebuf[2]); + class_code_ = parse_class(linebuf[3]); +} + + +// Parsers +uint32_t StudentsClasses::parse_student_code(std::string student_code) { + return std::stoi(student_code); +} + +uint16_t StudentsClasses::parse_uc(std::string uc_code) { + uint64_t hash = 5381; + std::string num_part; + for (char c : uc_code) { + if (!isnum(c)) { + hash = (hash << 5) + hash + c; + } + if (isnum(c)) { + num_part.push_back(c); + } + } + try { + uint8_t num = 0; + if (num_part != "") { + num = std::stoi(num_part); + } + return (uint16_t)((hash % 256) << 8) + (uint16_t)(num); + } catch (std::invalid_argument &e) { + std::cerr << e.what() << " uc: failed to parse" << '\n'; + std::exit(1); + } +} + +uint16_t StudentsClasses::parse_class(std::string class_code) { + uint8_t year = class_code[0] - '0'; + std::string classnum; + for (int i = 1; i < class_code.size(); ++i) { + if (isnum(class_code[i])) { + classnum.push_back(class_code[i]); + } + } + try { + uint8_t num = 0; + if (classnum != "") { + num = std::stoi(classnum); + } + return ((uint16_t)year << 8) + num; + } catch (std::invalid_argument &e) { + std::cerr << e.what() << " class: failed to parse" << '\n'; + std::exit(1); + } +} + + +// String format +void StudentsClasses::student_code_to_str(std::string& student_code) { + student_code = std::to_string(student_code_); +} +void StudentsClasses::student_name_to_str(std::string& student_name) { + student_name = student_name_; +} +void StudentsClasses::uc_code_to_str(std::string& uc_code) { + std::stringstream s; + std::string classname; + bool found = false; + uint16_t hash_of_class = uc_code_ >> 8; + for (int i = 0; i <= sizeof(this->types_of_uc) / sizeof(char *); ++i) { + if (hash_of_class == hash_str(std::string(this->types_of_uc[i]))) { + classname = this->types_of_uc[i]; + found = true; + break; + } + } + if (!found) { + std::cerr << "There is no known uc type with hash " << hash_of_class + << "!\n"; + std::exit(1); + } + s << classname << std::setfill('0') << std::setw(3) << (uc_code_ & 255); + uc_code = s.str(); +} +void StudentsClasses::class_code_to_str(std::string& class_code) { + std::stringstream s; + // TODO: use exceptions to handle errors instead of closing. + if ((class_code_ >> 8) == 19) { + class_code = "ClassCode"; + return; + } + s << (class_code_ >> 8) << "LEIC" << std::setfill('0') << std::setw(2) + << (class_code_ & 255); + class_code = s.str(); +} + + +// Debug +void StudentsClasses::display() { + std::cout << student_code_ << "," + << student_name_ << "," + << uc_code_ << "," + << class_code_ << '\n'; +} diff --git a/src/studentsClasses.hpp b/src/studentsClasses.hpp index e69de29..7db509b 100644 --- a/src/studentsClasses.hpp +++ b/src/studentsClasses.hpp @@ -0,0 +1,34 @@ +#include +#include +#ifndef STUDENTSCLASSES_H +#define STUDENTSCLASSES_H + +class StudentsClasses { +private: + uint32_t student_code_; + std::string student_name_; + uint16_t uc_code_; + uint16_t class_code_; + constexpr const static char *types_of_uc[] = { + "L.EIC", "UP", "IAPD", "CSR", "IADE", "IR", "MPSAC", "DDS", "SEESTE"}; + +public: + // Constructor + StudentsClasses(std::string line); + + // Parsers + uint32_t parse_student_code(std::string student_code); + uint16_t parse_uc(std::string uc_code); + uint16_t parse_class(std::string class_code); + + // String format + void student_code_to_str(std::string& student_code); + void student_name_to_str(std::string& student_name); + void uc_code_to_str(std::string& uc_code); + void class_code_to_str(std::string& class_code); + + // Debug + void display(); +}; + +#endif // STUDENTSCLASSES_H \ No newline at end of file From 0386c1daf91789b9ef1f8c5219073e5fbdf8ac86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20V=C3=ADtor=20Ferreira?= Date: Tue, 24 Oct 2023 07:06:44 +0100 Subject: [PATCH 2/6] Correction of StudentsClasses::display() --- src/studentsClasses.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/studentsClasses.cpp b/src/studentsClasses.cpp index 06433a0..5166254 100644 --- a/src/studentsClasses.cpp +++ b/src/studentsClasses.cpp @@ -108,8 +108,16 @@ void StudentsClasses::class_code_to_str(std::string& class_code) { // Debug void StudentsClasses::display() { - std::cout << student_code_ << "," - << student_name_ << "," - << uc_code_ << "," - << class_code_ << '\n'; + std::string student_code; + std::string student_name; + std::string uc_code; + std::string class_code; + student_code_to_str(student_code); + student_name_to_str(student_name); + uc_code_to_str(uc_code); + class_code_to_str(class_code); + std::cout << student_code << "," + << student_name << "," + << uc_code << "," + << class_code << '\n'; } From add925bb1d26fa1219fc87a10ddd3b7602038cee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20V=C3=ADtor=20Ferreira?= Date: Tue, 24 Oct 2023 19:54:39 +0100 Subject: [PATCH 3/6] First implementation of AppSC and some corrections --- src/appStudentsClasses.cpp | 140 +++++++++++++++++++++++++++++++++++++ src/appStudentsClasses.hpp | 25 +++++++ src/studentsClasses.cpp | 31 ++++---- src/studentsClasses.hpp | 24 ++++--- 4 files changed, 198 insertions(+), 22 deletions(-) diff --git a/src/appStudentsClasses.cpp b/src/appStudentsClasses.cpp index e69de29..788a6ab 100644 --- a/src/appStudentsClasses.cpp +++ b/src/appStudentsClasses.cpp @@ -0,0 +1,140 @@ +#include "appStudentsClasses.hpp" +#include "studentsClasses.hpp" +#include "Utils.hpp" +#include +#include +#include +#include +#include + +// Constructor +AppStudentsClasses::AppStudentsClasses(std::string csv) { + std::stringstream s(csv); + std::string line; + this->entries = std::vector(); + getline(s,line,'\n'); + std::vector bufs; + parse_csv_line(line,bufs); + this->student_code_cath_name = bufs[0]; + this->student_name_cath_name = bufs[1]; + this->uc_code_cath_name = bufs[2]; + this->class_code_cath_name = bufs[3]; + line.clear(); + while (std::getline(s,line,'\n')) { + this->entries.push_back(StudentsClasses(line)); + } +} + +// Methods +void AppStudentsClasses::sort_by(const std::string& category) { + if (category == this->student_code_cath_name) { + std::sort(this->entries.begin(), this->entries.end(), + [](const StudentsClasses& a, const StudentsClasses& b) {return a.get_student_code() < b.get_student_code();}); + + } else if (category == this->student_name_cath_name) { + std::sort(this->entries.begin(), this->entries.end(), + [](const StudentsClasses& a, const StudentsClasses& b) {return a.get_student_name() < b.get_student_name();}); + + } else if (category == this->uc_code_cath_name) { + std::sort(this->entries.begin(), this->entries.end(), + [](const StudentsClasses& a, const StudentsClasses& b) {return a.get_uc_code() < b.get_uc_code();}); + + } else if (category == this->class_code_cath_name) { + std::sort(this->entries.begin(), this->entries.end(), + [](const StudentsClasses& a, const StudentsClasses& b) {return a.get_class_code() < b.get_class_code();}); + + } else { + std::cerr << "Error: invalid category" << '\n'; + std::exit(1); + } +} + +std::vector::iterator AppStudentsClasses::search_by_uc(uint16_t uc_code) { + sort_by(uc_code_cath_name); + auto ret = entries.end(); + size_t mid = entries.size() / 2; + + while (true) { // Binary search + if (mid == entries.size()) { + return ret; + } else if (entries[mid].get_uc_code() == uc_code) { + ret = entries.begin() + mid; + break; + } else if (entries[mid].get_uc_code() > uc_code) { + mid = mid / 2; + } else { + mid = mid + mid / 2; + } + } + + while (true) { + if ((ret - 1)->get_uc_code() != uc_code) { + return ret; + } else --ret; + } +} + +std::vector::iterator AppStudentsClasses::search_by_student(uint32_t student_code) { + sort_by(student_code_cath_name); + auto ret = entries.end(); + size_t mid = entries.size() / 2; + + while (true) { // Binary search + if (mid == entries.size()) { + return ret; + } else if (entries[mid].get_student_code() == student_code) { + ret = entries.begin() + mid; + break; + } else if (entries[mid].get_student_code() > student_code) { + mid = mid / 2; + } else { + mid = mid + mid / 2; + } + } + + while (true) { + if ((ret - 1)->get_student_code() != student_code) { + return ret; + } else --ret; + } +} + +std::vector::iterator AppStudentsClasses::search_by_class(uint16_t class_code) { + sort_by(class_code_cath_name); + auto ret = entries.end(); + size_t mid = entries.size() / 2; + + while (true) { // Binary search + if (mid == entries.size()) { + return ret; + } else if (entries[mid].get_class_code() == class_code) { + ret = entries.begin() + mid; + break; + } else if (entries[mid].get_class_code() > class_code) { + mid = mid / 2; + } else { + mid = mid + mid / 2; + } + } + + while (true) { + if ((ret - 1)->get_class_code() != class_code) { + return ret; + } else --ret; + } +} + + +// Degub +void AppStudentsClasses::display() const { + std::cout << this->student_code_cath_name << ',' + << this->student_name_cath_name << ',' + << this->uc_code_cath_name << ',' + << this->class_code_cath_name << '\n'; + for (const auto& e : this->entries) { + e.display(); + } +} + + + diff --git a/src/appStudentsClasses.hpp b/src/appStudentsClasses.hpp index e69de29..c598443 100644 --- a/src/appStudentsClasses.hpp +++ b/src/appStudentsClasses.hpp @@ -0,0 +1,25 @@ +#include "studentsClasses.hpp" +#include +#include + +class AppStudentsClasses { +private: + std::string student_code_cath_name; + std::string student_name_cath_name; + std::string uc_code_cath_name; + std::string class_code_cath_name; + std::vector entries; + +public: + // Constructor + AppStudentsClasses(std::string csv); + + // Methods + void sort_by(const std::string& category); + std::vector::iterator search_by_student(uint32_t student_code); + std::vector::iterator search_by_uc(uint16_t uc_code); + std::vector::iterator search_by_class(uint16_t class_code); + + // Debug + void display() const; +}; \ No newline at end of file diff --git a/src/studentsClasses.cpp b/src/studentsClasses.cpp index 5166254..11760c3 100644 --- a/src/studentsClasses.cpp +++ b/src/studentsClasses.cpp @@ -7,7 +7,7 @@ #include // Constructor -StudentsClasses::StudentsClasses(std::string line) { +StudentsClasses::StudentsClasses(std::string& line) { std::vector linebuf; parse_csv_line(line, linebuf); student_code_ = parse_student_code(linebuf[0]); @@ -17,12 +17,19 @@ StudentsClasses::StudentsClasses(std::string line) { } +// Getters +uint32_t StudentsClasses::get_student_code() const { return student_code_; } +std::string StudentsClasses::get_student_name() const { return student_name_; } +uint16_t StudentsClasses::get_uc_code() const { return uc_code_; } +uint16_t StudentsClasses::get_class_code() const { return class_code_; } + + // Parsers -uint32_t StudentsClasses::parse_student_code(std::string student_code) { +uint32_t StudentsClasses::parse_student_code(const std::string& student_code) const { return std::stoi(student_code); } -uint16_t StudentsClasses::parse_uc(std::string uc_code) { +uint16_t StudentsClasses::parse_uc(const std::string& uc_code) const { uint64_t hash = 5381; std::string num_part; for (char c : uc_code) { @@ -45,7 +52,7 @@ uint16_t StudentsClasses::parse_uc(std::string uc_code) { } } -uint16_t StudentsClasses::parse_class(std::string class_code) { +uint16_t StudentsClasses::parse_class(std::string class_code) const { uint8_t year = class_code[0] - '0'; std::string classnum; for (int i = 1; i < class_code.size(); ++i) { @@ -67,13 +74,11 @@ uint16_t StudentsClasses::parse_class(std::string class_code) { // String format -void StudentsClasses::student_code_to_str(std::string& student_code) { +void StudentsClasses::student_code_to_str(std::string& student_code) const { student_code = std::to_string(student_code_); } -void StudentsClasses::student_name_to_str(std::string& student_name) { - student_name = student_name_; -} -void StudentsClasses::uc_code_to_str(std::string& uc_code) { + +void StudentsClasses::uc_code_to_str(std::string& uc_code) const { std::stringstream s; std::string classname; bool found = false; @@ -93,7 +98,8 @@ void StudentsClasses::uc_code_to_str(std::string& uc_code) { s << classname << std::setfill('0') << std::setw(3) << (uc_code_ & 255); uc_code = s.str(); } -void StudentsClasses::class_code_to_str(std::string& class_code) { + +void StudentsClasses::class_code_to_str(std::string& class_code) const { std::stringstream s; // TODO: use exceptions to handle errors instead of closing. if ((class_code_ >> 8) == 19) { @@ -107,13 +113,12 @@ void StudentsClasses::class_code_to_str(std::string& class_code) { // Debug -void StudentsClasses::display() { +void StudentsClasses::display() const { std::string student_code; - std::string student_name; + std::string student_name = get_student_name(); std::string uc_code; std::string class_code; student_code_to_str(student_code); - student_name_to_str(student_name); uc_code_to_str(uc_code); class_code_to_str(class_code); std::cout << student_code << "," diff --git a/src/studentsClasses.hpp b/src/studentsClasses.hpp index 7db509b..feb49b4 100644 --- a/src/studentsClasses.hpp +++ b/src/studentsClasses.hpp @@ -14,21 +14,27 @@ class StudentsClasses { public: // Constructor - StudentsClasses(std::string line); + StudentsClasses(std::string& line); + + // Getters + uint32_t get_student_code() const; + std::string get_student_name() const; + uint16_t get_uc_code() const; + uint16_t get_class_code() const; // Parsers - uint32_t parse_student_code(std::string student_code); - uint16_t parse_uc(std::string uc_code); - uint16_t parse_class(std::string class_code); + uint32_t parse_student_code(const std::string& student_code) const; + uint16_t parse_uc(const std::string& uc_code) const; + uint16_t parse_class(std::string class_code) const; // String format - void student_code_to_str(std::string& student_code); - void student_name_to_str(std::string& student_name); - void uc_code_to_str(std::string& uc_code); - void class_code_to_str(std::string& class_code); + void student_code_to_str(std::string& student_code) const; + // void student_name_to_str(std::string& student_name) const; (= get_student_name()) + void uc_code_to_str(std::string& uc_code) const; + void class_code_to_str(std::string& class_code) const; // Debug - void display(); + void display() const; }; #endif // STUDENTSCLASSES_H \ No newline at end of file From b3a7805d3ab018250ee9832aef91b2a193de22b1 Mon Sep 17 00:00:00 2001 From: Guilherme Matos Date: Wed, 25 Oct 2023 15:50:36 +0100 Subject: [PATCH 4/6] Change to std::stable_sort --- src/appStudentsClasses.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/appStudentsClasses.cpp b/src/appStudentsClasses.cpp index 788a6ab..e19cab5 100644 --- a/src/appStudentsClasses.cpp +++ b/src/appStudentsClasses.cpp @@ -28,19 +28,19 @@ AppStudentsClasses::AppStudentsClasses(std::string csv) { // Methods void AppStudentsClasses::sort_by(const std::string& category) { if (category == this->student_code_cath_name) { - std::sort(this->entries.begin(), this->entries.end(), + std::stable_sort(this->entries.begin(), this->entries.end(), [](const StudentsClasses& a, const StudentsClasses& b) {return a.get_student_code() < b.get_student_code();}); } else if (category == this->student_name_cath_name) { - std::sort(this->entries.begin(), this->entries.end(), + std::stable_sort(this->entries.begin(), this->entries.end(), [](const StudentsClasses& a, const StudentsClasses& b) {return a.get_student_name() < b.get_student_name();}); } else if (category == this->uc_code_cath_name) { - std::sort(this->entries.begin(), this->entries.end(), + std::stable_sort(this->entries.begin(), this->entries.end(), [](const StudentsClasses& a, const StudentsClasses& b) {return a.get_uc_code() < b.get_uc_code();}); } else if (category == this->class_code_cath_name) { - std::sort(this->entries.begin(), this->entries.end(), + std::stable_sort(this->entries.begin(), this->entries.end(), [](const StudentsClasses& a, const StudentsClasses& b) {return a.get_class_code() < b.get_class_code();}); } else { From fd8350ab39d6c3d3b3851858f20734c66190abbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20V=C3=ADtor=20Ferreira?= Date: Wed, 25 Oct 2023 16:49:06 +0100 Subject: [PATCH 5/6] Added tests for all classes --- .github/workflows/c-cpp.yml | 3 +++ main.cpp | 32 +++++++++++++++++++++++++------- src/studentsClasses.cpp | 6 +++++- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index ab695ca..34de4df 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -37,4 +37,7 @@ jobs: # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail run: ctest -C ${{env.BUILD_TYPE}} + - name: Execute + working-directory: ${{github.workspace}}/build + run: ./AED2324_PRJ1_G23 diff --git a/main.cpp b/main.cpp index 736aeb9..b46fa74 100644 --- a/main.cpp +++ b/main.cpp @@ -10,14 +10,32 @@ #include int main(int argc, char** argv) { - std::ifstream file = std::ifstream("schedule/classes_per_uc.csv"); - std::string contents; - std::ostringstream sstr; - sstr << file.rdbuf(); - contents = sstr.str(); - AppCPU cpu = AppCPU(contents); + // AppClassesPerUC + std::ifstream file1 = std::ifstream("schedule/classes_per_uc.csv"); + std::string contents1; + std::ostringstream sstr1; + sstr1 << file1.rdbuf(); + contents1 = sstr1.str(); + AppCPU cpu = AppCPU(contents1); cpu.display(); - //std::cout << "Hello, World!" << std::endl; + // AppStudentsClasses + std::ifstream file2 = std::ifstream("schedule/students_classes.csv"); + std::string contents2; + std::ostringstream sstr2; + sstr2 << file2.rdbuf(); + contents2 = sstr2.str(); + AppStudentsClasses sc(contents2); + sc.display(); + + // AppClass + std::ifstream file3 = std::ifstream("schedule/classes.csv"); + std::string contents3; + std::ostringstream sstr3; + sstr3 << file3.rdbuf(); + contents3 = sstr3.str(); + AppClass ac(contents3); + ac.display(); + return 0; } diff --git a/src/studentsClasses.cpp b/src/studentsClasses.cpp index 11760c3..9413c41 100644 --- a/src/studentsClasses.cpp +++ b/src/studentsClasses.cpp @@ -5,6 +5,7 @@ #include #include #include +#include // Constructor StudentsClasses::StudentsClasses(std::string& line) { @@ -26,7 +27,10 @@ uint16_t StudentsClasses::get_class_code() const { return class_code_; } // Parsers uint32_t StudentsClasses::parse_student_code(const std::string& student_code) const { - return std::stoi(student_code); + std::istringstream iss(student_code); + uint32_t student_code_int; + iss >> student_code_int; + return student_code_int; } uint16_t StudentsClasses::parse_uc(const std::string& uc_code) const { From 7e67ab2321ceaf93e7a0dd37092a3687bd1a9c93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20V=C3=ADtor=20Ferreira?= Date: Wed, 25 Oct 2023 16:51:10 +0100 Subject: [PATCH 6/6] Revert bot "Execute" --- .github/workflows/c-cpp.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index 34de4df..4f7aae6 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -36,8 +36,3 @@ jobs: # Execute tests defined by the CMake configuration. # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail run: ctest -C ${{env.BUILD_TYPE}} - - - name: Execute - working-directory: ${{github.workspace}}/build - - run: ./AED2324_PRJ1_G23