diff --git a/.github/workflows/c-cpp.yml b/.github/workflows/c-cpp.yml index ab695ca..4f7aae6 100644 --- a/.github/workflows/c-cpp.yml +++ b/.github/workflows/c-cpp.yml @@ -36,5 +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}} - - 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/appStudentsClasses.cpp b/src/appStudentsClasses.cpp index e69de29..e19cab5 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::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::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::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::stable_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 e69de29..9413c41 100644 --- a/src/studentsClasses.cpp +++ b/src/studentsClasses.cpp @@ -0,0 +1,132 @@ +#include "studentsClasses.hpp" +#include "Utils.hpp" +#include +#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]); +} + + +// 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(const std::string& student_code) const { + 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 { + 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) const { + 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) const { + student_code = std::to_string(student_code_); +} + +void StudentsClasses::uc_code_to_str(std::string& uc_code) const { + 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) const { + 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() const { + std::string student_code; + std::string student_name = get_student_name(); + std::string uc_code; + std::string class_code; + student_code_to_str(student_code); + uc_code_to_str(uc_code); + class_code_to_str(class_code); + std::cout << student_code << "," + << student_name << "," + << uc_code << "," + << class_code << '\n'; +} diff --git a/src/studentsClasses.hpp b/src/studentsClasses.hpp index e69de29..feb49b4 100644 --- a/src/studentsClasses.hpp +++ b/src/studentsClasses.hpp @@ -0,0 +1,40 @@ +#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); + + // 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(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) 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() const; +}; + +#endif // STUDENTSCLASSES_H \ No newline at end of file