diff --git a/CMakeLists.txt b/CMakeLists.txt index 65fb34e..0707ed3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,10 +27,14 @@ endif(DOXYGEN_FOUND) # Project build add_executable(AED2324_PRJ1_G23 main.cpp - src/appClasses.cpp src/appClasses.hpp - src/appClassesPerUC.cpp src/appClassesPerUC.hpp - src/appStudentsClasses.cpp src/appStudentsClasses.hpp - src/classes.cpp src/classes.hpp - src/classesPerUC.cpp src/classesPerUC.hpp - src/studentsClasses.cpp src/studentsClasses.hpp - src/Utils.cpp src/Utils.hpp) + src/CSVClasses.cpp src/CSVClasses.hpp + src/CSVClassesPerUC.cpp src/CSVClassesPerUC.hpp + src/CSVStudentsClasses.cpp src/CSVStudentsClasses.hpp + src/Lesson.cpp src/Lesson.hpp + src/ClassesPerUC.cpp src/ClassesPerUC.hpp + src/StudentsClasses.cpp src/StudentsClasses.hpp + src/Utils.cpp src/Utils.hpp + src/Runtime.cpp src/Runtime.hpp + src/ClassSchedule.cpp src/ClassSchedule.hpp + src/Student.cpp src/Student.hpp + src/Process.cpp src/Process.hpp) diff --git a/docs/Doxyfile b/docs/Doxyfile index 5c3e9d3..29d81e6 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -871,7 +871,7 @@ WARN_LOGFILE = # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. -INPUT = ../src ../main.cpp ../docs/docs.md +INPUT = @PROJECT_SOURCE_DIR@/src @PROJECT_SOURCE_DIR@/main.cpp @PROJECT_SOURCE_DIR@/docs/docs.md # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses diff --git a/main.cpp b/main.cpp index 34dd1f0..65a1c69 100644 --- a/main.cpp +++ b/main.cpp @@ -2,27 +2,30 @@ * @file main.cpp * @brief Point of entry of the program. */ - -#include "src/appClasses.hpp" -#include "src/appClassesPerUC.hpp" -#include "src/appStudentsClasses.hpp" -#include "src/classes.hpp" -#include "src/classesPerUC.hpp" -#include "src/studentsClasses.hpp" -#include -#include -#include -#include +#include "src/CSVClasses.hpp" +#include "src/CSVClassesPerUC.hpp" +#include "src/CSVStudentsClasses.hpp" +#include "src/ClassesPerUC.hpp" +#include "src/StudentsClasses.hpp" +#include "src/Lesson.hpp" +#include "src/ClassSchedule.hpp" +#include "src/Student.hpp" +#include "src/Runtime.hpp" +#include "src/Utils.hpp" int main(int argc, char** argv) { - AppClassPerUC cpu = AppClassPerUC("schedule/classes_per_uc.csv"); - cpu.display(); + CSVClassPerUC cpu("schedule/classes_per_uc.csv"); + //cpu.display(); + + CSVStudentsClasses sc("schedule/students_classes.csv"); + //sc.display(); - AppStudentsClasses sc("schedule/students_classes.csv"); - sc.display(); + CSVClasses ac("schedule/classes.csv"); + //ac.display(); - AppClass ac("schedule/classes.csv"); - ac.display(); + Runtime rt(sc, cpu, ac); + + rt.run(); return 0; } diff --git a/src/appClasses.cpp b/src/CSVClasses.cpp similarity index 63% rename from src/appClasses.cpp rename to src/CSVClasses.cpp index 3d6ae83..8b5bb2d 100644 --- a/src/appClasses.cpp +++ b/src/CSVClasses.cpp @@ -1,20 +1,20 @@ -#include "appClasses.hpp" +/** + * @file CSVClasses.cpp + */ +#include "CSVClasses.hpp" #include "Utils.hpp" -#include "classes.hpp" +#include "Lesson.hpp" #include #include #include #include -/** - * @file appClasses.cpp - */ /** - * This constructor receives a string containing all the lines of a csv file and creates the AppClass from it. + * @brief This constructor receives a string containing all the lines of a csv file and creates the AppClass from it. * @param csv */ -AppClass::AppClass(const std::string& csv) { +CSVClasses::CSVClasses(const std::string& csv) { // CSV file into memory std::ifstream file = std::ifstream(csv); std::string contents; @@ -25,7 +25,7 @@ AppClass::AppClass(const std::string& csv) { // Parse string std::stringstream s(contents); std::string line; - this->entries = std::vector(); + this->entries = std::vector(); getline(s, line, '\n'); std::vector bufs; parse_csv_line(line, bufs); @@ -37,19 +37,19 @@ AppClass::AppClass(const std::string& csv) { this->type_cath_name = bufs[5]; line.clear(); while (std::getline(s, line, '\n')) { - this->entries.push_back(Class(line)); + this->entries.push_back(Lesson(line)); } } /** - * Erases the contents of classes.csv and saves there the updated values. + * @brief Erases the contents of classes.csv and saves there the updated values. */ -AppClass::~AppClass() { +CSVClasses::~CSVClasses() { std::ofstream ofs; ofs.open("../schedule/classes.csv", std::ofstream::out | std::ofstream::trunc); ofs << class_cath_name << ',' << uc_cath_name << ',' << weekday_cath_name << ',' << start_hour_cath_name << ',' << duration_cath_name << ',' << type_cath_name << '\n'; - for (Class entry: entries) { + for (Lesson entry: entries) { std::string value; entry.class_to_str(value); ofs << value << ','; @@ -65,7 +65,10 @@ AppClass::~AppClass() { ofs.close(); } -void AppClass::display() { +/** + * @brief Displays the contents of the class. + */ +void CSVClasses::display() { std::cout << this->uc_cath_name << ',' << this->class_cath_name << ',' << this->weekday_cath_name << ',' << this->start_hour_cath_name << ',' << this->duration_cath_name << ',' << this->type_cath_name @@ -75,10 +78,16 @@ void AppClass::display() { } } -void AppClass::sort_by(std::string category) { +/** + * @brief Sorts the entries by the category passed as parameter. + * @details Available categories: id, ClassCode, UcCode, Weekday, StartHour, Duration, Type. + * Theoretical Complexity: O(n log n), n being the number of lines in the csv file. + * @param category + */ +void CSVClasses::sort_by(std::string category) { if (category == uc_cath_name) { std::stable_sort(this->entries.begin(), this->entries.end(), - [](const Class &first, const Class &second) { + [](const Lesson &first, const Lesson &second) { std::string first_uc, second_uc; first.uc_to_str(first_uc); second.uc_to_str(second_uc); @@ -86,28 +95,33 @@ void AppClass::sort_by(std::string category) { }); } else if (category == class_cath_name) { std::stable_sort(this->entries.begin(), this->entries.end(), - [](const Class &first, const Class &second) { + [](const Lesson &first, const Lesson &second) { return first.get_class_code() < second.get_class_code(); }); } else if (category == weekday_cath_name) { std::stable_sort(this->entries.begin(), this->entries.end(), - [](const Class &first, const Class &second) { + [](const Lesson &first, const Lesson &second) { return first.get_day() < second.get_day(); }); } else if (category == start_hour_cath_name) { std::stable_sort(this->entries.begin(), this->entries.end(), - [](const Class &first, const Class &second) { + [](const Lesson &first, const Lesson &second) { return first.get_start_hour() < second.get_start_hour(); }); } else if (category == duration_cath_name) { std::stable_sort(this->entries.begin(), this->entries.end(), - [](const Class &first, const Class &second) { + [](const Lesson &first, const Lesson &second) { return first.get_duration() < second.get_duration(); }); } else if (category == type_cath_name) { std::stable_sort(this->entries.begin(), this->entries.end(), - [](const Class &first, const Class &second) { - return first.get_type() < second.get_type(); + [](const Lesson &first, const Lesson &second) { + return first.get_type() < second.get_type(); + }); + } else if (category == "id") { + std::stable_sort(this->entries.begin(), this->entries.end(), + [](const Lesson &first, const Lesson &second) { + return first.get_id() < second.get_id(); }); } else { std::cerr << "Error: invalid category" << '\n'; @@ -115,12 +129,18 @@ void AppClass::sort_by(std::string category) { } } -std::vector::iterator AppClass::search_by_uc( +/** + * @deprecated + * @brief Search the lines for the first class with the given uc_code. + * @param uc_code + * @return Iterator to the first class with the given uc_code. If not found, returns a past-the-end pointer. + */ +std::vector::iterator CSVClasses::search_by_uc( uint16_t uc_code) { // Sorts the entries by UC and returns the iterator of the // first found. If not found, returns a past-the-end pointer sort_by(uc_cath_name); - std::vector::iterator ret = entries.end(); + std::vector::iterator ret = entries.end(); size_t mid = entries.size() / 2; while (true) { // Binary search if (mid == entries.size()) { @@ -145,14 +165,21 @@ std::vector::iterator AppClass::search_by_uc( return ret; } -std::vector::iterator AppClass::search_by_class(uint16_t class_code) { +/** + * @deprecated + * @brief Search the lines for the first class with the given class_code. + * @param uc_code + * @param class_code + * @return Iterator to the first class with the given class_code. If not found, returns a past-the-end pointer. + */ +std::vector::iterator CSVClasses::search_by_class(uint16_t uc_code, uint16_t class_code) { sort_by(class_cath_name); - std::vector::iterator ret = entries.end(); + std::vector::iterator 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) { + } else if (entries[mid].get_uc_code() == uc_code && entries[mid].get_class_code() == class_code) { ret = entries.begin() + mid; break; } else if (entries[mid].get_class_code() > class_code) { @@ -171,3 +198,9 @@ std::vector::iterator AppClass::search_by_class(uint16_t class_code) { } return ret; } + +/** + * @brief Getter for the vector of Lessons + * @return Pointer to lessons. + */ +std::vector *CSVClasses::get_lessons() {return &this->entries;} diff --git a/src/CSVClasses.hpp b/src/CSVClasses.hpp new file mode 100644 index 0000000..392a2ae --- /dev/null +++ b/src/CSVClasses.hpp @@ -0,0 +1,35 @@ +/** + * @file CSVClasses.hpp + */ +#ifndef APPCLASSES_H +#define APPCLASSES_H +#include "Lesson.hpp" +#include +#include + +/** + * @brief Class representation of the file classes.csv + */ +class CSVClasses { +private: + std::string class_cath_name; + std::string uc_cath_name; + std::string weekday_cath_name; + std::string start_hour_cath_name; + std::string duration_cath_name; + std::string type_cath_name; + /// Vector with every line of the file + std::vector entries; + +public: + CSVClasses(const std::string& csv); + ~CSVClasses(); + std::vector* get_lessons(); + void display(); + void sort_by(std::string category); + std::vector::iterator search_by_uc(uint16_t uc_code); + std::vector::iterator search_by_class(uint16_t uc_code, uint16_t class_code); +}; + + +#endif // APPCLASSES_H diff --git a/src/appClassesPerUC.cpp b/src/CSVClassesPerUC.cpp similarity index 51% rename from src/appClassesPerUC.cpp rename to src/CSVClassesPerUC.cpp index 46d7183..eec6ddc 100644 --- a/src/appClassesPerUC.cpp +++ b/src/CSVClassesPerUC.cpp @@ -1,21 +1,22 @@ -#include "appClassesPerUC.hpp" -#include "classesPerUC.hpp" +/** + * @file CSVClassesPerUC.cpp + */ +#include "CSVClassesPerUC.hpp" +#include "ClassesPerUC.hpp" #include #include #include #include -/** - * @file appClassesPerUC.cpp - */ /** - * This constructor receives a string containing all the lines of a csv file and creates the AppClassPerUC from it. - * The cap parameter is the capacity of each class. + * @brief This constructor receives a string containing all the lines of a csv file and creates the AppClassPerUC from it. + * @details The cap parameter is the capacity of each class (30 by default). + * Theoretical complexity: O(n), where n is the number of lines in the csv file. * @param csv * @param cap */ -AppClassPerUC::AppClassPerUC(const std::string& csv, uint8_t cap) { +CSVClassPerUC::CSVClassPerUC(const std::string& csv, uint8_t cap) { this->cap = cap; // CSV file into memory @@ -41,9 +42,9 @@ AppClassPerUC::AppClassPerUC(const std::string& csv, uint8_t cap) { } /** - * Erases the contents of classes_per_uc.csv and saves there the updated values. + * @brief Erases the contents of classes_per_uc.csv and saves there the updated values. */ -AppClassPerUC::~AppClassPerUC() { +CSVClassPerUC::~CSVClassPerUC() { std::ofstream ofs; ofs.open("../schedule/classes_per_uc.csv", std::ofstream::out | std::ofstream::trunc); ofs << uc_cath_name << ',' << class_cath_name << '\n'; @@ -57,14 +58,23 @@ AppClassPerUC::~AppClassPerUC() { ofs.close(); } -void AppClassPerUC::display() { +/** + * @brief This method prints the csv file. + */ +void CSVClassPerUC::display() { std::cout << this->uc_cath_name << ',' << this->class_cath_name << '\n'; for (auto e : this->entries) { e.display(); } } -void AppClassPerUC::sort_by(std::string category) { +/** + * @brief Sort the entries vector by the category parameter. + * @details Available categories: UcCode, ClassCode, id. + * Theoretical complexity: O(n log n), where n is the number of entries in the vector. + * @param category + */ +void CSVClassPerUC::sort_by(std::string category) { if (category == uc_cath_name) { std::stable_sort(this->entries.begin(), this->entries.end(), [](const ClassPerUC &first, const ClassPerUC &second) { @@ -74,12 +84,29 @@ void AppClassPerUC::sort_by(std::string category) { return first_uc < second_uc; }); } else if (category == class_cath_name) { - std::stable_sort(this->entries.begin(), this->entries.end(), - [](const ClassPerUC &first, const ClassPerUC &second) { - return first.get_class_code() < second.get_class_code(); - }); + std::stable_sort(this->entries.begin(), this->entries.end(), + [](const ClassPerUC &first, const ClassPerUC &second) { + return first.get_class_code() < second.get_class_code(); + }); + } else if (category == "id") { + std::stable_sort(this->entries.begin(), this->entries.end(), + [](const ClassPerUC &first, const ClassPerUC &second) { + return first.get_id() < second.get_id(); + }); } else { std::cerr << "Error: invalid category" << '\n'; std::exit(1); } } + +/** + * @brief Getter for the vector of ClassPerUC. + * @return Pointer to entries. + */ +std::vector *CSVClassPerUC::get_classes() {return &this->entries;} + +/** + * @brief Getter for the capacity of every class. + * @return cap + */ +uint8_t CSVClassPerUC::get_cap() const {return cap;} diff --git a/src/CSVClassesPerUC.hpp b/src/CSVClassesPerUC.hpp new file mode 100644 index 0000000..eee9675 --- /dev/null +++ b/src/CSVClassesPerUC.hpp @@ -0,0 +1,32 @@ +/** + * @file CSVClassesPerUC.hpp + */ +#ifndef CSVCLASSESPERUC_HPP +#define CSVCLASSESPERUC_HPP +#include "ClassesPerUC.hpp" +#include +#include + +/** + * @brief Representation of the file classes_per_uc.csv + */ +class CSVClassPerUC { +private: + std::string uc_cath_name; + std::string class_cath_name; + /// Vector with every line of the csv file + std::vector entries; + /// Capacity on any class + uint8_t cap; + +public: + CSVClassPerUC(const std::string& csv, uint8_t cap = 30); + ~CSVClassPerUC(); + void display(); + void sort_by(std::string category); + std::vector* get_classes(); + uint8_t get_cap() const; +}; + + +#endif // CSVCLASSESPERUC_HPP diff --git a/src/appStudentsClasses.cpp b/src/CSVStudentsClasses.cpp similarity index 86% rename from src/appStudentsClasses.cpp rename to src/CSVStudentsClasses.cpp index 150b560..a39c8fc 100644 --- a/src/appStudentsClasses.cpp +++ b/src/CSVStudentsClasses.cpp @@ -1,5 +1,8 @@ -#include "appStudentsClasses.hpp" -#include "studentsClasses.hpp" +/** + * @file CSVStudentsClasses.cpp + */ +#include "CSVStudentsClasses.hpp" +#include "StudentsClasses.hpp" #include "Utils.hpp" #include #include @@ -8,16 +11,12 @@ #include #include -/** - * @file appStudentsClasses.cpp - */ -// Constructor /** * This constructor receives a string containing all the lines of a csv file and creates the AppSudentClass from it. * @param csv */ -AppStudentsClasses::AppStudentsClasses(const std::string& csv) { +CSVStudentsClasses::CSVStudentsClasses(const std::string& csv) { // CSV file into memory std::ifstream file = std::ifstream(csv); std::string contents; @@ -42,11 +41,10 @@ AppStudentsClasses::AppStudentsClasses(const std::string& csv) { } } -//Destructor /** * Erases the contents of students_classes.csv and saves there the updated values. */ -AppStudentsClasses::~AppStudentsClasses() { +CSVStudentsClasses::~CSVStudentsClasses() { std::ofstream ofs; ofs.open("../schedule/students_classes.csv", std::ofstream::out | std::ofstream::trunc); ofs << student_code_cath_name << ',' << student_name_cath_name << ',' @@ -65,16 +63,16 @@ AppStudentsClasses::~AppStudentsClasses() { } // Methods -void AppStudentsClasses::sort_by(const std::string& category) { - if (category == this->student_code_cath_name) { +void CSVStudentsClasses::sort_by(const std::string& category) { + if (category == "StudentCode") { 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) { + } else if (category == "StudentName") { 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_cath_name) { + } else if (category == "UcCode") { std::stable_sort(this->entries.begin(), this->entries.end(), [](const ClassPerUC &first, const ClassPerUC &second) { std::string first_uc, second_uc; @@ -82,7 +80,7 @@ void AppStudentsClasses::sort_by(const std::string& category) { second.uc_to_str(second_uc); return first_uc < second_uc; }); - } else if (category == this->class_cath_name) { + } else if (category == "ClassCode") { std::stable_sort(this->entries.begin(), this->entries.end(), [](const ClassPerUC &first, const ClassPerUC &second) { return first.get_class_code() < second.get_class_code(); @@ -94,7 +92,7 @@ void AppStudentsClasses::sort_by(const std::string& category) { } } -std::vector::iterator AppStudentsClasses::search_by_uc(uint16_t uc_code) { +std::vector::iterator CSVStudentsClasses::search_by_uc(uint16_t uc_code) { sort_by(uc_cath_name); auto ret = entries.end(); size_t mid = entries.size() / 2; @@ -119,7 +117,7 @@ std::vector::iterator AppStudentsClasses::search_by_uc(uint16_t } } -std::vector::iterator AppStudentsClasses::search_by_student(uint32_t student_code) { +std::vector::iterator CSVStudentsClasses::search_by_student(uint32_t student_code) { sort_by(student_code_cath_name); auto ret = entries.end(); size_t mid = entries.size() / 2; @@ -145,7 +143,7 @@ std::vector::iterator AppStudentsClasses::search_by_student(uin } -std::vector::iterator AppStudentsClasses::search_by_class(uint16_t class_code) { +std::vector::iterator CSVStudentsClasses::search_by_class(uint16_t class_code) { sort_by(class_cath_name); auto ret = entries.end(); size_t mid = entries.size() / 2; @@ -171,7 +169,7 @@ std::vector::iterator AppStudentsClasses::search_by_class(uint1 } // Debug -void AppStudentsClasses::display() const { +void CSVStudentsClasses::display() const { std::cout << this->student_code_cath_name << ',' << this->student_name_cath_name << ',' << this->uc_cath_name << ',' @@ -180,3 +178,5 @@ void AppStudentsClasses::display() const { e.display(); } } + +std::vector *CSVStudentsClasses::get_students() {return &this->entries;} diff --git a/src/appStudentsClasses.hpp b/src/CSVStudentsClasses.hpp similarity index 66% rename from src/appStudentsClasses.hpp rename to src/CSVStudentsClasses.hpp index 04793bf..bf0905b 100644 --- a/src/appStudentsClasses.hpp +++ b/src/CSVStudentsClasses.hpp @@ -1,12 +1,14 @@ -#include "studentsClasses.hpp" +/** + * @file CSVStudentsClasses.hpp + */ +#ifndef CSVSTUDENTCLASSES_H +#define CSVSTUDENTCLASSES_H +#include "StudentsClasses.hpp" #include #include -/** - * @file appStudentsClasses.hpp - */ -class AppStudentsClasses { +class CSVStudentsClasses { private: std::string student_code_cath_name; std::string student_name_cath_name; @@ -16,17 +18,21 @@ class AppStudentsClasses { public: // Constructor - AppStudentsClasses(const std::string& csv); + CSVStudentsClasses(const std::string& csv); //Destructor - virtual ~AppStudentsClasses(); + virtual ~CSVStudentsClasses(); // 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); + std::vector* get_students(); // Debug void display() const; -}; \ No newline at end of file +}; + + +#endif // CSVSTUDENTCLASSES_H diff --git a/src/ClassSchedule.cpp b/src/ClassSchedule.cpp new file mode 100644 index 0000000..02cd563 --- /dev/null +++ b/src/ClassSchedule.cpp @@ -0,0 +1,91 @@ +/** + * @file ClassSchedule.cpp + */ +#include "ClassSchedule.hpp" +#include +#include +#include + +/** + * @brief Constructor of the class. + * @param uc_code + * @param class_code + */ +ClassSchedule::ClassSchedule(uint16_t uc_code, uint16_t class_code) { + this->uc_code_ = uc_code; + this->class_code_ = class_code; + this->classes = std::vector(); + this->n_students = 0; +} + +/** + * @brief Add one student to the counter. + */ +void ClassSchedule::add_student() {n_students += 1;} +/** + * @brief Remove one student of the counter. + */ +void ClassSchedule::remove_student() {n_students -= 1;} + +/** + * @brief Add a Lesson to the vector of this class. + * @param c + * @return bool (If the action is valid or not.) + */ +bool ClassSchedule::add_entry(Lesson* c) { + if (c->get_id() != this->get_id()) { + fprintf(stdout, "Error: Operation Invalid: Can't add a lesson to a schedule of a different class!"); + return false; + } + this->classes.push_back(c); + return true; +} + +/** + * @deprecated + * @brief Remove a Lesson to the vector of this class. + * @param c + * @return bool (If the action is valid or not.) + */ +bool ClassSchedule::remove_entry(Lesson* c) { + // Probably unecessary + for (std::vector::iterator itr = this->classes.begin(); itr != this->classes.end(); ++itr) { + if (*itr == c) { + this->classes.erase(itr); + return true; + } + } + return false; +} + +/** + * @brief Getter for student_count. + * @return student_count + */ +uint64_t ClassSchedule::get_student_count() const { + return this->n_students; +} + +/** + * @brief Getter for class_schedule. + * @return class_schedule + */ +std::vector* ClassSchedule::get_class_schedule() { + return &this->classes; +} + +/** + * @brief Prints to the screen the contents of this class. + */ +void ClassSchedule::display() const { + std::string uc_,class_; + this->uc_to_str(uc_); + this->class_to_str(class_); + std::cout << "Uc: " << uc_ << "\nClass: " << class_ << "\n"; + for (auto i : this->classes) { + std::cout << " "; + i->display(); + } + std::cout << std::endl; +} + diff --git a/src/ClassSchedule.hpp b/src/ClassSchedule.hpp new file mode 100644 index 0000000..c16ccf7 --- /dev/null +++ b/src/ClassSchedule.hpp @@ -0,0 +1,33 @@ +/** + * @file ClassSchedule.hpp + */ +#ifndef CLASSSCHEDULE_H +#define CLASSSCHEDULE_H +#include +#include +#include "ClassesPerUC.hpp" +#include "Lesson.hpp" + +/** + * @brief Representation of a class and their respective lessons. + */ +class ClassSchedule : public ClassPerUC { +private: + /// Derivative attribute that indicates the number of students enrolled in this class. + uint64_t n_students = 0; + /// Pointers to all of the lessons associated to this class. + std::vector classes; + +public: + ClassSchedule(uint16_t uc_code, uint16_t class_code); + bool add_entry(Lesson* entry); + bool remove_entry(Lesson* entry); + void add_student(); + void remove_student(); + uint64_t get_student_count() const; + std::vector* get_class_schedule(); + void display() const; +}; + + +#endif // CLASSSCHEDULE_H diff --git a/src/classesPerUC.cpp b/src/ClassesPerUC.cpp similarity index 59% rename from src/classesPerUC.cpp rename to src/ClassesPerUC.cpp index 224b964..0e31e83 100644 --- a/src/classesPerUC.cpp +++ b/src/ClassesPerUC.cpp @@ -1,4 +1,7 @@ -#include "classesPerUC.hpp" +/** + * @file ClassesPerUC.cpp + */ +#include "ClassesPerUC.hpp" #include "Utils.hpp" #include #include @@ -10,17 +13,13 @@ #include #include -/** - * @file classPerUC.cpp - */ -// Constructor: /** - * The constructor reads the line and assigns each string value to its attribute. - * We opted to transform the sting values of uc_code and class_code_ into hashes for sakes of performance, + * @brief The constructor reads the line and assigns each string value to its attribute. + * @details It was opted to transform the sting values of uc_code and class_code_ into hashes for sakes of performance, * since it is quicker to compare integers than strings. + * Theoretical Complexity: O(n), n being the number of characters in a csv line. * @param line - * @tparam */ ClassPerUC::ClassPerUC(std::string line) { std::vector linebuf; @@ -29,44 +28,56 @@ ClassPerUC::ClassPerUC(std::string line) { class_code_ = parse_class(linebuf[1]); } +/** + * @brief The constructor implicitly used for subclasses. Not used standalone. + */ ClassPerUC::ClassPerUC() { uc_code_ = 0; class_code_ = 0; } +/** + * @brief Getter for uc_code. + * @return uc_code + */ uint16_t ClassPerUC::get_uc_code() const { return uc_code_; } +/** + * @brief Getter for class_code. + * @return class_code + */ uint16_t ClassPerUC::get_class_code() const { return class_code_; } +/** + * @brief Getter for uc_code and class_code as a single uint32_t. + * @return id + */ +uint32_t ClassPerUC::get_id() const { + return ((uint32_t)uc_code_ << 16) + class_code_; +} + +/** + * @brief Parse uc_code from a std::string to an uint16_t. + * @details Useful to save memory and to make comparisons faster. + * Theoretical Complexity: O(n), n being the number of characters of the std::string. + * @param uc_code + * @return uc_code as a uint16_t + */ uint16_t ClassPerUC::parse_uc(std::string uc_code) { - uint64_t hash = 5381; - std::string num_part; - for (char c : uc_code) { - if (!isnum(c)) { - // DEBUG : printf("%c",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); - } - // DEBUG : printf(" -> code : %d\n", (uint8_t)hash); - 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); - } + return parse_uc_gen(uc_code); } +/** + * @brief Parse class_code from a std::string to an uint16_t. + * @details Useful to save memory and to make comparisons faster. + * Theoretical Complexity: O(n), n being the number of characters of the std::string. + * @param class_code + * @return class_code as uint16_t + */ uint16_t ClassPerUC::parse_class(std::string class_code) { uint8_t year = class_code[0] - '0'; std::string classnum; @@ -88,7 +99,7 @@ uint16_t ClassPerUC::parse_class(std::string class_code) { } /** - * This method converts the attribute uc_code_ into a string and assigns the parameter out with its string value. + * @brief This method converts the attribute uc_code_ into a string and assigns the parameter out with its string value. * @param out * @tparam std::string */ @@ -107,7 +118,7 @@ void ClassPerUC::uc_to_str(std::string &out) const { } /** - * This method converts the attribute class_code_ into a string and assigns the parameter out with its string value. + * @brief This method converts the attribute class_code_ into a string and assigns the parameter out with its string value. * @param out * @tparam std::string */ @@ -124,7 +135,7 @@ void ClassPerUC::class_to_str(std::string &out) const { } /** - * This method prints the csv line of the current state of the object. + * @brief This method prints the csv line of the current state of the object. */ void ClassPerUC::display() const { // std::cout << "UcCode,ClassCode\n"; diff --git a/src/classesPerUC.hpp b/src/ClassesPerUC.hpp similarity index 77% rename from src/classesPerUC.hpp rename to src/ClassesPerUC.hpp index c26bead..2e2f264 100644 --- a/src/classesPerUC.hpp +++ b/src/ClassesPerUC.hpp @@ -1,31 +1,42 @@ +/** + * @file ClassesPerUC.hpp + */ +#ifndef CLASSPERUC_H +#define CLASSPERUC_H #include #include #include #include #include -#ifndef CLASSPERUC_H -#define CLASSPERUC_H + +void parse_csv_line(std::string s, std::vector &res); /** - * @file classesPerUC.hpp + * @brief Class representation of one line inside the file classes_per_uc. */ - -void parse_csv_line(std::string s, std::vector &res); class ClassPerUC { protected: + /// Code of curricular unit. See parse_uc() for more info about the hash. uint16_t uc_code_; + /// Code of class. See parse_class() for more info about the hash. uint16_t class_code_; - // constexpr const static char *types_of_uc[256] = { - // ,[0] = "IR" - // ,[14] = "SEESTE"}; - // ,[16] = "L.EIC" - // ,[64] = "DDS" - // ,[67] = "IAPD" - // ,[138] = "UP" - // ,[184] = "IADE" - // ,[237] = "CSR" - // ,[249] = "MPSAC" + + /** + * @brief Lookup table for the names of the UCs. Used in uc_to_str(); + * @details constexpr const static char *types_of_uc[256] = { + * [0] = "IR" + * ,[14] = "SEESTE" + * ,[16] = "L.EIC" + * ,[64] = "DDS" + * ,[67] = "IAPD" + * ,[138] = "UP" + * ,[184] = "IADE" + * ,[237] = "CSR" + * ,[249] = "MPSAC" + * }; + */ + constexpr const static char *types_of_uc[256] = { "IR", "", "", "", "", "", "", "", "", "", "", "", "", "", "SEESTE", "", "L.EIC", "", "", "", "", "", "", "", "", "", @@ -54,6 +65,7 @@ class ClassPerUC { ClassPerUC(); uint16_t get_uc_code() const; uint16_t get_class_code() const; + uint32_t get_id() const; uint16_t parse_uc(std::string uc_code); uint16_t parse_class(std::string class_code); void class_to_str(std::string &out) const; @@ -63,4 +75,5 @@ class ClassPerUC { virtual void display() const; }; + #endif // !CLASSPERUC_H diff --git a/src/classes.cpp b/src/Lesson.cpp similarity index 83% rename from src/classes.cpp rename to src/Lesson.cpp index e3a8f5d..a229dce 100644 --- a/src/classes.cpp +++ b/src/Lesson.cpp @@ -1,20 +1,18 @@ -#include "classes.hpp" +/** + * @file Lesson.cpp + */ +#include "Lesson.hpp" #include "Utils.hpp" #include - using namespace std; -/** - * @file classes.cpp - */ -// Constructor: /** * The constructor reads the line and assigns each string value to its attribute. * @param line * @tparam std::string */ -Class::Class(std::string line) { +Lesson::Lesson(std::string line) { std::vector linebuf; parse_csv_line(line, linebuf); class_code_ = parse_class(linebuf[0]); @@ -27,18 +25,17 @@ Class::Class(std::string line) { //______________________________________________________________________________________________________________________ // Getters: -WeekDay Class::get_day() const { return day; } +WeekDay Lesson::get_day() const { return day; } -double Class::get_start_hour() const { return start_hour; } +double Lesson::get_start_hour() const { return start_hour; } -double Class::get_duration() const { return duration; } +double Lesson::get_duration() const { return duration; } -Type Class::get_type() const { return type; } +Type Lesson::get_type() const { return type; } //______________________________________________________________________________________________________________________ // Parsers: - -WeekDay Class::parse_day(std::string day) { +WeekDay Lesson::parse_day(std::string day) { if (day == "Monday") { return WeekDay::MONDAY; } else if (day == "Tuesday") { @@ -56,7 +53,7 @@ WeekDay Class::parse_day(std::string day) { } } -Type Class::parse_type(std::string type) { +Type Lesson::parse_type(std::string type) { if (type == "T") { return Type::T; } else if (type == "TP") { @@ -71,7 +68,7 @@ Type Class::parse_type(std::string type) { * @param out * @tparam std::string */ -void Class::day_to_str(std::string &out) const { +void Lesson::day_to_str(std::string &out) const { if (day == WeekDay::MONDAY) { out = "Monday"; } else if (day == WeekDay::TUESDAY) { @@ -94,7 +91,7 @@ void Class::day_to_str(std::string &out) const { * @param out * @tparam std::string */ -void Class::type_to_str(std::string &out) const { +void Lesson::type_to_str(std::string &out) const { if (type == Type::T) { out = "T"; } else if (type == Type::TP) { @@ -109,7 +106,7 @@ void Class::type_to_str(std::string &out) const { /** * This method prints the csv line of the current state of the object. */ -void Class::display() const { +void Lesson::display() const { string uc; string cc; string dia; diff --git a/src/classes.hpp b/src/Lesson.hpp similarity index 85% rename from src/classes.hpp rename to src/Lesson.hpp index 6b98a44..a0338de 100644 --- a/src/classes.hpp +++ b/src/Lesson.hpp @@ -1,15 +1,14 @@ +/** + * @file Lesson.hpp + */ +#ifndef LESSON_HPP +#define LESSON_HPP #include #include #include #include -#include "classesPerUC.hpp" - -#ifndef CLASS_HPP -#define CLASS_HPP +#include "ClassesPerUC.hpp" -/** - * @file classes.hpp - */ /** * Since it is quicker to compare numbers instead of strings and there are only 7 days in a week, we decided to store @@ -37,7 +36,7 @@ enum class Type { PL, }; -class Class : public ClassPerUC { +class Lesson : public ClassPerUC { private: WeekDay day; float start_hour; @@ -45,7 +44,7 @@ class Class : public ClassPerUC { Type type; public: - Class(std::string line); // Constructor + Lesson(std::string line); // Constructor // Getters: WeekDay get_day() const; @@ -68,7 +67,7 @@ class Class : public ClassPerUC { // Other Methods: void display() const override; - //void display(); }; -#endif // CLASS_HPP + +#endif // LESSON_HPP diff --git a/src/Process.cpp b/src/Process.cpp new file mode 100644 index 0000000..54ff62b --- /dev/null +++ b/src/Process.cpp @@ -0,0 +1,21 @@ +#include "Process.hpp" +#include +#include + + +Process::Process(TypeOfRequest t) { + type = t; + operands = std::vector(); +} + +void Process::add_operand(std::string op) { + operands.push_back(op); +} + +TypeOfRequest Process::get_type() { + return type; +} + +std::vector& Process::get_ops() { + return operands; +} diff --git a/src/Process.hpp b/src/Process.hpp new file mode 100644 index 0000000..e7ddcb5 --- /dev/null +++ b/src/Process.hpp @@ -0,0 +1,23 @@ +#include +#include + + +enum class TypeOfRequest { + Add, + Remove, + Switch, + Print, + Batch, +}; + + +class Process { + private: + TypeOfRequest type; + std::vector operands; + public: + Process(TypeOfRequest t); + void add_operand(std::string s); + TypeOfRequest get_type(); + std::vector& get_ops(); +}; diff --git a/src/Runtime.cpp b/src/Runtime.cpp new file mode 100644 index 0000000..8410bb2 --- /dev/null +++ b/src/Runtime.cpp @@ -0,0 +1,266 @@ +/** + * @file Runtime.cpp + */ +#include "Runtime.hpp" +#include "ClassSchedule.hpp" +#include "Student.hpp" +#include "Utils.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +Runtime::Runtime(CSVStudentsClasses &sc, CSVClassPerUC &cpu, CSVClasses &c) { + cap = cpu.get_cap(); + is_batching = false; + procs = std::queue(); + + // 1. Populate lessons + auto lessons = c.get_lessons(); + c.sort_by("id"); + + // 2. Populate classSchedules + cpu.sort_by("id"); + int idx = 0; + for (ClassPerUC &entry : *cpu.get_classes()) { + ClassSchedule cs(entry.get_uc_code(), entry.get_class_code()); + while (idx < lessons->size()) { + if ((*lessons)[idx].get_id() == cs.get_id()) { + cs.add_entry(&lessons->at(idx)); + ++idx; + continue; + } + break; + } + classes.push_back(cs); + } + + // 3. Populate students + sc.sort_by(std::string("StudentCode")); + auto sc_vector = sc.get_students(); + Student s(sc_vector->at(0).get_student_code(), + sc_vector->at(0).get_student_name()); + + for (const auto &i : *sc_vector) { + if (i.get_student_code() == s.get_code()) { + s.add_to_class(find_class(i.get_id())); + } else { + students.insert(s); + s = Student(i.get_student_code(), i.get_student_name()); + s.add_to_class(find_class(i.get_id())); + } + } +} + +/** + * Using Binary Search, find the ClassSchedule inside of the vector classes with + * the same uc_code ans class_code. Theoretical Complexity: O(log n) + * @param id + * @return Pointer to the found ClassSchedule + */ +ClassSchedule *Runtime::find_class(uint32_t id) { + size_t high = classes.size(); + size_t low = 0; + + while (low <= high) { + size_t mid = low + (high - low) / 2; + if (classes[mid].get_id() == id) + return &classes.at(mid); + if (classes[mid].get_id() < id) { + low = mid + 1; + } else { + high = mid - 1; + } + } + return nullptr; +} + +void Runtime::run() { + std::string in; + std::istringstream stream; + std::string buf; + bool exit = false; + std::vector line; + std::cout << "Welcome to SchedulEd. Type 'help' to learn more." << std::endl; + while (!exit) { + if (is_batching) { + std::cout << "Batching> "; + } else { + std::cout << "> "; + } + getline(std::cin, in); + stream = std::istringstream(in); + while (std::getline(stream, buf, ' ')) { + line.push_back(buf); + buf.clear(); + } + if (line.size() == 0) { + in.clear(); + continue; + } + if (!is_batching) { + process_args(line); + in.clear(); + line.clear(); + while (procs.size() != 0) { + Process p = procs.front(); + procs.pop(); + handle_process(p); + } + } + in.clear(); + } +} + +void Runtime::process_args(std::vector args) { + if (args[0] == "quit") { + std::cout << "Quitting..." << std::endl; + // TODO: Call saving functions + std::exit(1); + } + if (args[0] == "remove") { + if (args.size() != 3) { + std::cerr << "ERROR: USAGE: remove takes two arguments: remove " + << " " << std::endl; + return; + } else { + Process t(TypeOfRequest::Remove); + t.add_operand(args[1]); + t.add_operand(args[2]); + procs.push(t); + return; + } + } + if (args[0] == "add") { + if (args.size() != 4) { + std::cerr << "ERROR: USAGE: add takes three arguments: add " + << " " << std::endl; + return; + } else { + Process t(TypeOfRequest::Add); + t.add_operand(args[1]); + t.add_operand(args[2]); + t.add_operand(args[3]); + procs.push(t); + return; + } + } + if (args[0] == "switch") { + if (args.size() != 4) { + std::cerr << "ERROR: USAGE: switch takes three arguments: switch " + << " " << std::endl; + return; + } else { + Process t(TypeOfRequest::Switch); + t.add_operand(args[1]); + t.add_operand(args[2]); + t.add_operand(args[3]); + procs.push(t); + return; + } + } + if (args[0] == "print") { + if (args.size() != 2) { + std::cerr << "ERROR: USAGE: print takes 1 argument: print " + << std::endl; + return; + } else { + Process t(TypeOfRequest::Print); + t.add_operand(args[1]); + procs.push(t); + return; + } + } + + if (args[0] == "help") { + std::cout << "The available commands are:\n\n" << + " print: takes 1 argument: print \n" << + " Prints the student name, the student code and the student schedule.\n\n" << + " add: takes 3 arguments: add \n" << + " Adds a student to a class if possible.\n\n" << + " remove: takes 2 arguments: remove \n" << + " Removes a student from a class if possible.\n\n" << + " switch: takes 3 arguments: switch \n" << + " Switches the class of two students.\n\n" << + " quit: takes 0 arguments: quit\n" << + " Quits the program.\n\n" << + " help: takes 0 arguments: help\n" << + " Prints this help." << + std::endl; + return; + } + + std::cerr << "ERROR: No such command " << args[0] + << ". Try typing 'help' to know the available commands." + << std::endl; +} + +void Runtime::handle_process(Process p) { + std::vector ops = p.get_ops(); + // handle remove + if (p.get_type() == TypeOfRequest::Remove) { + uint32_t student_code; + try { + student_code = std::stoi(ops[0]); + } catch (std::exception e) { + std::cerr << "ERROR: The string " << ops[0] << " is not a student_code." + << std::endl; + return; + } + uint16_t uc_code = parse_uc_gen(ops[1]); + if (auto itr = students.find(Student(student_code, "")); + itr != students.end()) { + Student s = *itr; + std::vector sched = s.get_schedule(); + for (ClassSchedule *a : sched) { + if (a->get_uc_code() == uc_code) { + // std::cout << "Lookup: " << uc_code << "\nFound: " << + // a->get_uc_code() << std::endl; + s.remove_from_class(a); + students.erase(s); + students.insert(s); + history.push(p); + return; + } + } + } else { + std::cerr << "ERROR: There is no such student with code: " << student_code + << std::endl; + } + return; + } + // End Remove + + if (p.get_type() == TypeOfRequest::Print) { + uint32_t student_code; + try { + student_code = std::stoi(ops[0]); + } catch (std::exception e) { + std::cerr << "ERROR: The string " << ops[0] << " is not a student_code." + << std::endl; + return; + } + if (auto itr = students.find(Student(student_code, "")); + itr != students.end()) { + Student s = *itr; + std::cout << "Name: " << s.get_name() << "\nCode: " << s.get_code() + << std::endl; + std::vector sched = s.get_schedule(); + for (auto i : sched) { + i->display(); + } + } else { + std::cerr << "ERROR: There is no such student with code: " << student_code + << std::endl; + } + return; + } +} diff --git a/src/Runtime.hpp b/src/Runtime.hpp new file mode 100644 index 0000000..d64a814 --- /dev/null +++ b/src/Runtime.hpp @@ -0,0 +1,46 @@ +/** + * @file Runtime.hpp + */ +#ifndef RUNTIME_H +#define RUNTIME_H +#include "Student.hpp" +#include "ClassSchedule.hpp" +#include "Lesson.hpp" +#include "CSVClasses.hpp" +#include "CSVClassesPerUC.hpp" +#include "CSVStudentsClasses.hpp" +#include "Process.hpp" +#include +#include +#include +#include +#include + + +class Runtime { +private: + std::set students; + std::vector classes; + std::queue procs; + std::stack history; + + //std::vector* lessons; + uint8_t cap; + bool is_batching; + +public: + Runtime(CSVStudentsClasses &sc, CSVClassPerUC &cpu, CSVClasses &c); + + // Sorting + + // Searching + ClassSchedule* find_class(uint32_t id); + // TODO + void run(); + void process_args(std::vector args); + void handle_process(Process p); + void execute_queue(); +}; + + +#endif //RUNTIME_H diff --git a/src/Student.cpp b/src/Student.cpp new file mode 100644 index 0000000..cc1a98d --- /dev/null +++ b/src/Student.cpp @@ -0,0 +1,210 @@ +/** + * @file Student.cpp + */ +#include "Student.hpp" +#include "Utils.hpp" +#include +#include +#include +#include +#include + +Student::Student(uint32_t code, std::string name) { + this->code = code; + this->name = name; + this->classes = std::vector(); +} + +std::vector &Student::get_schedule() { return this->classes; } + +/** + * @brief Verifies if adding this class is legal or not. + * @details The following rules need to be followed: + * Number of UCs must be 7 or lower; + * The class must have a vacancy; + * No time conflicts; + * Only one class per UC; + * All classes must be balanced (Difference lower than 4). + * + * @param c + * @return Error, Conflicts or Success + */ +OperationResult Student::verify_add(ClassSchedule *c) { + // Number of UCs + if (this->classes.size() >= 7) + return OperationResult::Error; + + // Class vacancy + if (c->get_student_count() >= 30) + return OperationResult::Error; + + // One class per UC + for (auto clas : this->get_schedule()) { + if (clas->get_uc_code() == c->get_uc_code()) + return OperationResult::Error; + } + + // No time conflits + OperationResult highest = OperationResult::Success; + std::vector *new_lessons = c->get_class_schedule(); + for (ClassSchedule *a : this->classes) { + std::vector *lessons = a->get_class_schedule(); + for (Lesson *lesson : *lessons) { + for (Lesson *new_lesson : *new_lessons) { + if (lesson->get_day() == new_lesson->get_day()) { + // if new_lesson starts in the middle of lesson: + if (lesson->get_start_hour() < new_lesson->get_start_hour() && + new_lesson->get_start_hour() < + (lesson->get_start_hour() + lesson->get_duration())) { + if (lesson->get_type() == Type::T || + new_lesson->get_type() == Type::T) { + highest = highest > OperationResult::Conflicts + ? highest + : OperationResult::Conflicts; + // We return conflicts so that + // the handler function can ask + // the user whether or not they + // want to proceed. + } + highest = highest > OperationResult::Error + ? highest + : OperationResult::Error; + } + // if lesson starts in the middle of new_lesson: + if (new_lesson->get_start_hour() < lesson->get_start_hour() && + lesson->get_start_hour() < + (new_lesson->get_start_hour() + new_lesson->get_duration())) { + if (lesson->get_type() == Type::T || + new_lesson->get_type() == Type::T) { + highest = highest > OperationResult::Conflicts + ? highest + : OperationResult::Conflicts; + } + highest = highest > OperationResult::Error + ? highest + : OperationResult::Error; + } + } + } + } + } + return highest; +} + +/** + * @brief Verifies if switching classes is legal or not. + * @details No time conflits are allowed for both students. + */ +OperationResult Student::verify_switch(Student other, uint16_t uc_code) { + // TODO + return OperationResult::Success; +} + +/** + * @brief Add this Student to a particular class. + * @param c + */ +void Student::add_to_class(ClassSchedule *c) { + c->add_student(); + this->classes.push_back(c); +} + +/** + * @brief Remove this Student from a given class. + * @param c + */ +void Student::remove_from_class(ClassSchedule *c) { + c->remove_student(); + int i = 0; + for (i = 0; i < classes.size(); ++i) { + if (classes[i] == c) { + break; + } + } + classes.erase(classes.begin() + i); +} + +/** + * Switch the classes of Student and other Student with a given uc_code + * @param Student + */ +void Student::switch_class_with(Student other, uint16_t uc_code) { + ClassSchedule* this_class = this->find_class(uc_code); + ClassSchedule* other_class = other.find_class(uc_code); + + if (this_class == nullptr or other_class == nullptr) { + std::cerr << "ERROR: uc_code " << uc_code << " not found inside student'\n"; + } + + this->remove_from_class(this_class); + this->add_to_class(other_class); + other.remove_from_class(other_class); + other.add_to_class(this_class); +} + +bool Student::operator<(const Student &other) const { + return this->code < other.code; +} + +// SmolKey::SmolKey(uint32_t a): uc_code_(a) {} +// uint32_t SmolKey::get_key() const {return uc_code_;} + +// bool operator<(const Student& s,const SmolKey &other) { +// return s.get_code() < other.get_key(); +// } +// bool operator<(const SmolKey& s,const Student &other) { +// return other.get_code() < s.get_key(); +// } + +uint32_t Student::get_code() const { return code; } + + + +bool Student::verify_remove(ClassSchedule* c) { + for (std::vector::iterator itr = this->classes.begin(); + itr != this->classes.end(); ++itr) { + if (c == *itr) { + return true; + } + } + return false; +} + +ClassSchedule* Student::find_class(uint16_t uc_code) { + size_t high = classes.size(); + size_t low = 0; + + while (low <= high) { + size_t mid = low + (high - low) / 2; + if (classes[mid]->get_uc_code() == uc_code) return classes.at(mid); + if (classes[mid]->get_uc_code() < uc_code) { + low = mid + 1; + } else { + high = mid - 1; + } + } + return nullptr; +} + + +const std::string& Student::get_name() const {return name;} + + + + + + + + + + + + + + + + + + + + diff --git a/src/Student.hpp b/src/Student.hpp new file mode 100644 index 0000000..5cdc5ef --- /dev/null +++ b/src/Student.hpp @@ -0,0 +1,47 @@ +/** + * @file Student.hpp + */ +#ifndef STUDENT_H +#define STUDENT_H +#include +#include "ClassSchedule.hpp" +#include "Utils.hpp" +#include + +// class SmolKey { +// uint32_t uc_code_; +// public: +// SmolKey(uint32_t a); +// uint32_t get_key() const; + +// }; + + +class Student { +private: + uint32_t code; + std::string name; + std::vector classes; + + ClassSchedule* find_class(uint16_t uc_code); + +public: + Student(uint32_t code, std::string name); + uint32_t get_code() const; + const std::string& get_name() const; + + bool operator<(const Student& other) const; + std::vector& get_schedule(); + void add_to_class(ClassSchedule* c); + OperationResult verify_add(ClassSchedule* c); + OperationResult verify_switch(Student other, uint16_t uc_code); + bool verify_remove(ClassSchedule* c); + void remove_from_class(ClassSchedule* c); + void switch_class_with(Student other, uint16_t uc_code); + + + +}; + + +#endif // STUDENT_H diff --git a/src/studentsClasses.cpp b/src/StudentsClasses.cpp similarity index 95% rename from src/studentsClasses.cpp rename to src/StudentsClasses.cpp index 2cf8289..d5092dc 100644 --- a/src/studentsClasses.cpp +++ b/src/StudentsClasses.cpp @@ -1,4 +1,7 @@ -#include "studentsClasses.hpp" +/** + * @file StudentsClasses.cpp + */ +#include "StudentsClasses.hpp" #include "Utils.hpp" #include #include @@ -7,11 +10,7 @@ #include #include -/** - * @file studentsClasses.cpp - */ -// Constructor /** * The constructor reads the line and assigns each string value to its attribute. * @param line diff --git a/src/studentsClasses.hpp b/src/StudentsClasses.hpp similarity index 92% rename from src/studentsClasses.hpp rename to src/StudentsClasses.hpp index 0243565..e90dbd7 100644 --- a/src/studentsClasses.hpp +++ b/src/StudentsClasses.hpp @@ -1,12 +1,12 @@ -#include -#include -#include "classesPerUC.hpp" +/** + * @file StudentsClasses.hpp + */ #ifndef STUDENTSCLASSES_H #define STUDENTSCLASSES_H +#include +#include +#include "ClassesPerUC.hpp" -/** - * @file studentsClasses.hpp - */ class StudentsClasses : public ClassPerUC { private: @@ -31,4 +31,5 @@ class StudentsClasses : public ClassPerUC { void display() const override; }; + #endif // STUDENTSCLASSES_H diff --git a/src/Utils.cpp b/src/Utils.cpp index 5b817ad..73a059d 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -1,10 +1,9 @@ -#include "Utils.hpp" - /** * @file Utils.cpp * This file defines some functions that are gonna be useful in other classes */ - +#include "Utils.hpp" +#include /** * This function converts a string to a 8 bit hash. @@ -21,6 +20,31 @@ uint8_t hash_str(std::string s) { return (uint8_t)(hash % 256); } +uint16_t parse_uc_gen(std::string uc_code) { + uint64_t hash = 5381; + std::string num_part; + for (char c : uc_code) { + if (!isnum(c)) { + // DEBUG : printf("%c",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); + } + // DEBUG : printf(" -> code : %d\n", (uint8_t)hash); + 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); + } +} + /** * This function checks if a given character in a number. * @param c @@ -43,4 +67,3 @@ void parse_csv_line(std::string s, std::vector &res) { while (getline(line, buf, ',')) res.push_back(buf); } - diff --git a/src/Utils.hpp b/src/Utils.hpp index f7aebec..1dd8777 100644 --- a/src/Utils.hpp +++ b/src/Utils.hpp @@ -1,16 +1,29 @@ +/** + * @file Utils.hpp + */ #ifndef UTILS_HPP #define UTILS_HPP #include +#include #include #include #include -/** - * @file Utils.hpp - */ // djb2 hash : https://theartincode.stanis.me/008-djb2/ -uint8_t hash_str(std::string s); -bool isnum(uint32_t c); +uint8_t hash_str(std::string s); + +uint16_t parse_uc_gen(std::string s); + +bool isnum(uint32_t c); + void parse_csv_line(std::string s, std::vector &res); + +enum class OperationResult { + Success = 0, + Conflicts = 1, + Error = 2, +}; + + #endif // !UTILS_HPP diff --git a/src/appClasses.hpp b/src/appClasses.hpp deleted file mode 100644 index 8dc8dfd..0000000 --- a/src/appClasses.hpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "classes.hpp" -#include -#include - -#ifndef APPCLASSES_H -#define APPCLASSES_H - -/** - * @file appClasses.hpp - */ - -class AppClass{ -private: - std::string class_cath_name; - std::string uc_cath_name; - std::string weekday_cath_name; - std::string start_hour_cath_name; - std::string duration_cath_name; - std::string type_cath_name; - std::vector entries; - -public: - AppClass(const std::string& csv); - ~AppClass(); - void display(); - void sort_by(std::string category); - std::vector::iterator search_by_uc(uint16_t uc_code); - std::vector::iterator search_by_class(uint16_t class_code); -}; - -#endif // APPCLASSES_H \ No newline at end of file diff --git a/src/appClassesPerUC.hpp b/src/appClassesPerUC.hpp deleted file mode 100644 index 3b3b167..0000000 --- a/src/appClassesPerUC.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#include "classesPerUC.hpp" -#include -#include - -/** - * @file appClassesPerUC.hpp - */ - -class AppClassPerUC { -private: - std::string uc_cath_name; - std::string class_cath_name; - std::vector entries; - uint8_t cap; // Capacity on any class - -public: - AppClassPerUC(const std::string& csv, uint8_t cap = 30); - ~AppClassPerUC(); - void display(); - void sort_by(std::string category); -};