diff --git a/src/imports/import_base.hpp b/src/imports/import_base.hpp index 3656e09..c69d751 100644 --- a/src/imports/import_base.hpp +++ b/src/imports/import_base.hpp @@ -7,27 +7,65 @@ #include "system/parts.hpp" #include "system/signals.hpp" +/** + * @brief Base class for importing data from a file. + * + * This class provides a foundation for parsing files and managing + * system parts and signals. Derived classes must implement the `parse` method. + */ class ImportBase { protected: - Parts *prts; - Signals *sigs; - std::fstream file_lines; + Parts *prts; ///< Pointer to the Parts object. + Signals *sigs; ///< Pointer to the Signals object. + std::fstream file_lines; ///< File stream for reading the input file. + public: + /** + * @brief Constructor for ImportBase. + * + * Initializes the file stream and creates new Parts and Signals objects. + * + * @param file_name Name of the file to be imported. + */ ImportBase(std::string file_name) : file_lines(std::fstream(file_name)) { prts = new Parts(); sigs = new Signals(); }; - virtual void parse() = 0; + + /** + * @brief Pure virtual method for parsing the file. + * + * Derived classes must implement this method to define how the file is parsed. + * + * @param signals Pointer to the signals object to be completed. + */ + virtual void parse(Signals * signals) = 0; + + /** + * @brief Retrieves the Parts object. + * @return Pointer to the Parts object. + */ Parts * parts() { return prts; } + + /** + * @brief Retrieves the Signals object. + * @return Pointer to the Signals object. + */ Signals * signals() { return sigs; } + + /** + * @brief Virtual destructor for ImportBase. + * + * Ensures proper cleanup of derived classes. + */ virtual ~ImportBase() = default; }; diff --git a/src/imports/import_mentor.cpp b/src/imports/import_mentor.cpp index 416e827..90c46d5 100644 --- a/src/imports/import_mentor.cpp +++ b/src/imports/import_mentor.cpp @@ -1,4 +1,3 @@ - #include "import_mentor.hpp" #include "system/pins.hpp" #include "system/parts.hpp" @@ -9,83 +8,112 @@ using namespace std; +/** + * @brief Enum representing the parsing state. + * + * - NO_PART: No part is currently being processed. + * - IS_PART: A part is currently being processed. + */ enum class State { NO_PART, IS_PART, }; +/** + * @brief Constructor for ImportMentor. + * + * Initializes the base class with the provided filename. + * + * @param filename Name of the file to be imported. + */ ImportMentor::ImportMentor(string filename) : ImportBase(filename) {} +/** + * @brief Destructor for ImportMentor. + * + * Ensures proper cleanup by calling the base class destructor. + */ ImportMentor::~ImportMentor() { ImportBase::~ImportBase(); } -void ImportMentor::parse() +/** + * @brief Parses the file to extract parts, pins, and signals. + * + * This method reads the file line by line, identifies parts and pins using + * regular expressions, and associates them with signals. + * + * @param signals Pointer to the Signals object used for managing signal connections. + */ +void ImportMentor::parse(Signals *signals) { string line; - auto state = State::NO_PART; - const regex name_regex("'([^'\\s][^']*)'"); - const regex part_regex("^COMP:"); - const regex pin_regex("^\\s*Explicit Pin:"); + auto state = State::NO_PART; // Initial parsing state. + const regex name_regex("'([^'\\s][^']*)'"); // Regex to extract names enclosed in single quotes. + const regex part_regex("^COMP:"); // Regex to identify part definitions. + const regex pin_regex("^\\s*Explicit Pin:"); // Regex to identify pin definitions. bool is_name_match = false; bool is_part_match = false; bool is_pin_match = false; - Part *prt = nullptr; + Part *prt = nullptr; // Pointer to the current part being processed. + + // Read the file line by line. while (getline(file_lines, line)) { vector names; + // Extract all names matching the name_regex. for (sregex_iterator it(line.begin(), line.end(), name_regex), end; it != end; ++it) { names.push_back((*it)[1]); } - is_name_match = (names.size() > 0); - is_part_match = regex_search(line, part_regex); - is_pin_match = regex_search(line, pin_regex); + is_name_match = (names.size() > 0); // Check if any names were found. + is_part_match = regex_search(line, part_regex); // Check if the line matches a part definition. + is_pin_match = regex_search(line, pin_regex); // Check if the line matches a pin definition. + + // Handle the current state. switch (state) { case State::NO_PART: + // If no part is being processed and a part definition is found. if (is_part_match) { if (is_name_match) { - prt = new Part(names[1]); - state = State::IS_PART; + prt = new Part(names[1]); // Create a new part with the second name. + state = State::IS_PART; // Transition to IS_PART state. } } break; default: + // If a part is being processed and another part definition is found. if (is_part_match) { if (is_name_match) { - prts->add(prt); - prt = new Part(names[1]); + prts->add(prt); // Add the current part to the container. + prt = new Part(names[1]); // Create a new part with the second name. } } else if (is_pin_match) { + // If a pin definition is found. if (is_name_match) { - auto pin = new Pin(names[0]); + auto pin = new Pin(names[0]); // Create a new pin with the first name. Signal *s = nullptr; - prt->add(pin); - if (!sigs->exists(names[2])) - { - s = new Signal(names[2]); - sigs->add(s); - } else { - s = sigs->get(names[2]); - }; - pin->connect(s); + prt->add(pin); // Add the pin to the current part. + pin->connect(signals->merge(names[2])); // Connect the pin to a signal. } } break; } } + + // Add the last part to the container if still in IS_PART state. if (state == State::IS_PART) { prts->add(prt); diff --git a/src/imports/import_mentor.hpp b/src/imports/import_mentor.hpp index f3d6886..0b0f143 100644 --- a/src/imports/import_mentor.hpp +++ b/src/imports/import_mentor.hpp @@ -9,7 +9,7 @@ class ImportMentor : public ImportBase { public: ImportMentor(std::string filename); - void parse() override; + void parse(Signals *signals) override; ~ImportMentor(); }; diff --git a/src/system/signals.cpp b/src/system/signals.cpp index 5b15cd5..80071c9 100644 --- a/src/system/signals.cpp +++ b/src/system/signals.cpp @@ -7,3 +7,5 @@ Signals::Signals(void): SystemElementContainer("signals") {} Signals::Signals(std::vector signals): SystemElementContainer("signals", signals) {} +Signals::~Signals() {} + diff --git a/src/system/signals.hpp b/src/system/signals.hpp index c9493c6..2daeb11 100644 --- a/src/system/signals.hpp +++ b/src/system/signals.hpp @@ -17,6 +17,7 @@ class Signals : public SystemElementContainer public: Signals(void); Signals(std::vector signals); + ~Signals(); }; #endif // _SIGNALS_HPP_ \ No newline at end of file diff --git a/src/system/syselmts.hpp b/src/system/syselmts.hpp index ea259fe..92a7259 100644 --- a/src/system/syselmts.hpp +++ b/src/system/syselmts.hpp @@ -8,22 +8,43 @@ using namespace std; +/** + * @brief Represents a basic system element with a name. + */ class SystemElement { public: - string name; + string name; // Name of the system element. + + /** + * @brief Constructor for SystemElement. + * @param name Name of the element. + */ SystemElement(string name) : name(name) {}; }; +/** + * @brief A container for managing system elements of type T. + * + * @tparam T Type of elements, must inherit from SystemElement. + */ template class SystemElementContainer : public SystemElement { -private: - //static_assert(is_base_of::value, "T shall be a system element descendant !"); - unsigned int iter_count; - unordered_map content; +public: + using MapType = unordered_map; // Map to store elements by name. + using iterator = typename MapType::iterator; // Iterator for the map. + using const_iterator = typename MapType::const_iterator; // Const iterator for the map. - void add(unordered_map el_content) +private: + unsigned int iter_count; // Counter for iterations (currently unused). + MapType content; // Container for storing elements. + + /** + * @brief Adds elements from a map to the container. + * @param el_content Map of elements to add. + */ + void add(MapType el_content) { for (const auto &[key, value] : el_content) { @@ -32,11 +53,27 @@ private: } public: + /** + * @brief Constructor for an empty container. + * @param name Name of the container. + */ SystemElementContainer(string name) : SystemElement(name) {}; + + /** + * @brief Constructor with initial elements. + * @param name Name of the container. + * @param elements Vector of elements to add. + */ SystemElementContainer(string name, vector elements) : SystemElement(name) { add(elements); } + + /** + * @brief Checks if an element exists in the container. + * @param name Name of the element to check. + * @return True if the element exists, false otherwise. + */ bool exists(string name) { try @@ -49,7 +86,13 @@ public: return false; } } - void add(T* element) + + /** + * @brief Adds a single element to the container. + * @param element Pointer to the element to add. + * @throws runtime_error If the element's name is empty or already exists. + */ + void add(T *element) { if ("" == element->name) { @@ -61,17 +104,34 @@ public: } content.insert({element->name, element}); } + + /** + * @brief Adds elements from another container. + * @param elements Pointer to another container. + */ void add(SystemElementContainer *elements) { add(elements->content); } - void add(vector elements) + + /** + * @brief Adds multiple elements from a vector. + * @param elements Vector of elements to add. + */ + void add(vector elements) { for (auto &element : elements) { add(element); } } + + /** + * @brief Retrieves an element by its name. + * @param name Name of the element to retrieve. + * @return Pointer to the element. + * @throws runtime_error If the element is not found. + */ T *get(string name) { auto it = content.find(name); @@ -84,6 +144,48 @@ public: throw runtime_error("System elements not found"); } } + + /** + * @brief Merges an element by retrieving it or creating a new one if it doesn't exist. + * @param name Name of the element. + * @return Pointer to the merged or newly created element. + */ + T* merge(string name) + { + if (exists(name)) { + return get(name); + } + else + { + T* ret = new T(name); + add(ret); + return ret; + } + } + + /** + * @brief Returns an iterator to the beginning of the container. + * @return Iterator to the beginning. + */ + iterator begin() { return content.begin(); } + + /** + * @brief Returns an iterator to the end of the container. + * @return Iterator to the end. + */ + iterator end() { return content.end(); } + + /** + * @brief Returns a constant iterator to the beginning of the container. + * @return Constant iterator to the beginning. + */ + const_iterator begin() const { return content.begin(); } + + /** + * @brief Returns a constant iterator to the end of the container. + * @return Constant iterator to the end. + */ + const_iterator end() const { return content.end(); } }; #endif \ No newline at end of file