From b64df79f6c20b6055f0d756033b0cbc09dd518bf Mon Sep 17 00:00:00 2001 From: Joel Winarske Date: Mon, 18 Nov 2024 10:00:06 -0800 Subject: [PATCH] shared_ptr for Component -cuts runtime RAM ~50% Signed-off-by: Joel Winarske --- AppStreamParser.cpp | 160 ++++++++----------- AppStreamParser.h | 21 ++- Component.cpp | 378 +++++++++++++++++++++----------------------- Component.h | 1 - main.cpp | 52 +++--- 5 files changed, 291 insertions(+), 321 deletions(-) diff --git a/AppStreamParser.cpp b/AppStreamParser.cpp index 1a9d185..b463454 100644 --- a/AppStreamParser.cpp +++ b/AppStreamParser.cpp @@ -33,8 +33,7 @@ constexpr size_t CHUNK_SIZE = 1024; int convertToInt(const std::string &str) { try { - const int result = std::stoi(str); - return result; + return std::stoi(str); } catch (const std::invalid_argument &e) { spdlog::error("Invalid argument: could not convert to int: {}", str); throw; @@ -49,21 +48,10 @@ size_t convertToSizeT(const char *str) { errno = 0; const long long result = std::strtoll(str, &endPtr, 10); - // Check for various possible errors - if ((errno == ERANGE && (result == LLONG_MAX || result == LLONG_MIN)) || - (errno != 0 && result == 0)) { - std::perror("Conversion error"); - return 0; // Or handle the error case more gracefully - } - - if (endPtr == str) { - spdlog::error("Invalid argument: could not convert to size_t: {}", str); - return 0; // Or handle the error case more gracefully - } - - if (result < 0 || static_cast(result) > std::numeric_limits::max()) { - spdlog::error("Value out of range: {}", str); - return 0; // Or handle the error case more gracefully + if (errno == ERANGE || errno != 0 || endPtr == str || result < 0 || static_cast(result) > + std::numeric_limits::max()) { + spdlog::error("Conversion error: {}", str); + return 0; } return result; @@ -71,20 +59,10 @@ size_t convertToSizeT(const char *str) { // Function to parse a const char* as a Unix timestamp and convert to ISO 8601 std::string unixEpochToISO8601(const char *epochStr) { - // Convert the input const char* to a time_t const std::time_t epoch = std::stoll(epochStr); - - // Convert epoch to a time_point - const std::chrono::system_clock::time_point tp = std::chrono::system_clock::from_time_t(epoch); - - // Convert time_point to std::time_t to use std::gmtime - const std::time_t time = std::chrono::system_clock::to_time_t(tp); - const std::tm tm = *std::gmtime(&time); - - // Use stringstream to format the time as ISO 8601 + const std::tm tm = *std::gmtime(&epoch); std::stringstream ss; ss << std::put_time(&tm, "%Y-%m-%dT%H:%M:%S") << 'Z'; - return ss.str(); } @@ -96,7 +74,7 @@ void AppStreamParser::startElementCallback(void *user_data, const xmlChar *name, if (strcmp(tag, "component") == 0) { parser->state_.insideComponent = true; - parser->state_.currentComponent = Component(); + parser->state_.currentComponent = std::make_shared(); return; } @@ -197,12 +175,12 @@ void AppStreamParser::startElementCallback(void *user_data, const xmlChar *name, break; } if (strcmp(tag, "developer") == 0 && strcmp(key, "id") == 0) { - parser->state_.currentComponent.developer.id = value; + parser->state_.currentComponent->developer.id = value; parser->state_.currentDeveloper = true; break; } if (strcmp(tag, "bundle") == 0 && strcmp(key, "type") == 0) { - parser->state_.currentComponent.bundle.type = Component::stringToBundleType({value, value_len}); + parser->state_.currentComponent->bundle.type = Component::stringToBundleType({value, value_len}); break; } if (strcmp(tag, "url") == 0 && strcmp(key, "type") == 0) { @@ -223,69 +201,69 @@ void AppStreamParser::endElementCallback(void *user_data, const xmlChar *name) { if (parser->state_.insideComponent) { if (currentElement == "id") { - parser->state_.currentComponent.id = parser->state_.currentData; + parser->state_.currentComponent->id = parser->state_.currentData; } else if (currentElement == "pkgname") { - parser->state_.currentComponent.pkgname = parser->state_.currentData; + parser->state_.currentComponent->pkgname = parser->state_.currentData; } else if (currentElement == "source_pkgname") { - parser->state_.currentComponent.source_pkgname = parser->state_.currentData; + parser->state_.currentComponent->source_pkgname = parser->state_.currentData; } else if (currentElement == "name") { if (parser->state_.currentDeveloper) { - parser->state_.currentComponent.developer.name = parser->state_.currentData; + parser->state_.currentComponent->developer.name = parser->state_.currentData; } else { - parser->state_.currentComponent.name = parser->state_.currentData; + parser->state_.currentComponent->name = parser->state_.currentData; } } else if (currentElement == "project_license") { - parser->state_.currentComponent.projectLicense = parser->state_.currentData; + parser->state_.currentComponent->projectLicense = parser->state_.currentData; } else if (currentElement == "summary") { - parser->state_.currentComponent.summary = parser->state_.currentData; + parser->state_.currentComponent->summary = parser->state_.currentData; } else if (currentElement == "description") { if (parser->state_.insideReleases) { parser->state_.currentRelease.description = parser->state_.currentData; } else { - parser->state_.currentComponent.description = parser->state_.currentData; + parser->state_.currentComponent->description = parser->state_.currentData; } } else if (currentElement == "url") { if (parser->state_.insideReleases) { parser->state_.currentRelease.url = parser->state_.currentData; } else { if (parser->state_.urlType == Component::UrlType::HELP) { - parser->state_.currentComponent.url.help = parser->state_.currentData; + parser->state_.currentComponent->url.help = parser->state_.currentData; } else if (parser->state_.urlType == Component::UrlType::CONTACT) { - parser->state_.currentComponent.url.contact = parser->state_.currentData; + parser->state_.currentComponent->url.contact = parser->state_.currentData; } else if (parser->state_.urlType == Component::UrlType::DONATION) { - parser->state_.currentComponent.url.donation = parser->state_.currentData; + parser->state_.currentComponent->url.donation = parser->state_.currentData; } else if (parser->state_.urlType == Component::UrlType::HOMEPAGE) { - parser->state_.currentComponent.url.homepage = parser->state_.currentData; + parser->state_.currentComponent->url.homepage = parser->state_.currentData; } else if (parser->state_.urlType == Component::UrlType::TRANSLATE) { - parser->state_.currentComponent.url.translate = parser->state_.currentData; + parser->state_.currentComponent->url.translate = parser->state_.currentData; } else if (parser->state_.urlType == Component::UrlType::FAQ) { - parser->state_.currentComponent.url.faq = parser->state_.currentData; + parser->state_.currentComponent->url.faq = parser->state_.currentData; } else if (parser->state_.urlType == Component::UrlType::BUGTRACKER) { - parser->state_.currentComponent.url.bugtracker = parser->state_.currentData; + parser->state_.currentComponent->url.bugtracker = parser->state_.currentData; } else if (parser->state_.urlType == Component::UrlType::CONTRIBUTE) { - parser->state_.currentComponent.url.contribute = parser->state_.currentData; + parser->state_.currentComponent->url.contribute = parser->state_.currentData; } else if (parser->state_.urlType == Component::UrlType::VCS_BROWSER) { - parser->state_.currentComponent.url.vcs_browser = parser->state_.currentData; + parser->state_.currentComponent->url.vcs_browser = parser->state_.currentData; } else { - parser->state_.currentComponent.url.unknown = parser->state_.currentData; + parser->state_.currentComponent->url.unknown = parser->state_.currentData; } } } else if (currentElement == "project_group") { - parser->state_.currentComponent.project_group = parser->state_.currentData; + parser->state_.currentComponent->project_group = parser->state_.currentData; } else if (currentElement == "compulsory_for_desktop") { - parser->state_.currentComponent.compulsory_for_desktop.push_back( + parser->state_.currentComponent->compulsory_for_desktop.push_back( Component::stringToCompulsoryForDesktop(parser->state_.currentData)); } else if (currentElement == "developer") { parser->state_.currentDeveloper = false; } else if (currentElement == "launchable") { if (parser->state_.launchableType == Component::LaunchableType::URL) { - parser->state_.currentComponent.launchable.url = parser->state_.currentData; + parser->state_.currentComponent->launchable.url = parser->state_.currentData; } else if (parser->state_.launchableType == Component::LaunchableType::SERVICE) { - parser->state_.currentComponent.launchable.service = parser->state_.currentData; + parser->state_.currentComponent->launchable.service = parser->state_.currentData; } else if (parser->state_.launchableType == Component::LaunchableType::DESKTOP_ID) { - parser->state_.currentComponent.launchable.desktop_id = parser->state_.currentData; + parser->state_.currentComponent->launchable.desktop_id = parser->state_.currentData; } else if (parser->state_.launchableType == Component::LaunchableType::COCKPIT_MANIFEST) { - parser->state_.currentComponent.launchable.cockpit_manifest = parser->state_.currentData; + parser->state_.currentComponent->launchable.cockpit_manifest = parser->state_.currentData; } else { spdlog::error("Unknown launchable type: {}", parser->state_.currentData); } @@ -301,41 +279,41 @@ void AppStreamParser::endElementCallback(void *user_data, const xmlChar *name) { parser->state_.currentArtifact.size[parser->state_.currentArtifactSizeKey] = convertToSizeT( parser->state_.currentData.c_str()); } else if (currentElement == "bundle") { - parser->state_.currentComponent.bundle.id = parser->state_.currentData; + parser->state_.currentComponent->bundle.id = parser->state_.currentData; } else if (currentElement == "content_rating") { - parser->state_.currentComponent.content_rating = parser->state_.currentData; + parser->state_.currentComponent->content_rating = parser->state_.currentData; } else if (currentElement == "agreement") { - parser->state_.currentComponent.agreement = parser->state_.currentData; + parser->state_.currentComponent->agreement = parser->state_.currentData; } else if (currentElement == "keyword") { - parser->state_.currentComponent.keywords.push_back(parser->state_.currentData); + parser->state_.currentComponent->keywords.push_back(parser->state_.currentData); } else if (currentElement == "category") { - parser->state_.currentComponent.categories.push_back(parser->state_.currentData); + parser->state_.currentComponent->categories.push_back(parser->state_.currentData); } else if (currentElement == "icon") { parser->state_.currentIcon.value = parser->state_.currentData; - parser->state_.currentComponent.icons.push_back(parser->state_.currentIcon); + parser->state_.currentComponent->icons.push_back(parser->state_.currentIcon); } else if (currentElement == "suggest") { - parser->state_.currentComponent.suggests.push_back(parser->state_.currentData); + parser->state_.currentComponent->suggests.push_back(parser->state_.currentData); } else if (currentElement == "media_baseurl") { - parser->state_.currentComponent.media_baseurl = parser->state_.currentData; + parser->state_.currentComponent->media_baseurl = parser->state_.currentData; } else if (currentElement == "architecture") { - parser->state_.currentComponent.architecture = parser->state_.currentData; + parser->state_.currentComponent->architecture = parser->state_.currentData; } else if (currentElement == "releases") { parser->state_.insideReleases = false; } else if (currentElement == "release") { - parser->state_.currentComponent.releases.push_back(parser->state_.currentRelease); + parser->state_.currentComponent->releases.push_back(parser->state_.currentRelease); } else if (currentElement == "issues") { parser->state_.insideIssues = false; } else if (currentElement == "issue") { parser->state_.currentRelease.issues.push_back(parser->state_.currentIssue); } else if (currentElement == "language") { - parser->state_.currentComponent.addSupportedLanguage(parser->state_.currentData); + parser->state_.currentComponent->addSupportedLanguage(parser->state_.currentData); } else if (currentElement == "component") { parser->state_.insideComponent = false; - assert(!parser->state_.currentComponent.id.empty()); - if (!parser->components_.count(parser->state_.currentComponent.id)) { - parser->components_[parser->state_.currentComponent.id] = parser->state_.currentComponent; + assert(!parser->state_.currentComponent->id.empty()); + if (!parser->components_.count(parser->state_.currentComponent->id)) { + parser->components_[parser->state_.currentComponent->id] = std::move(parser->state_.currentComponent); } else { - SPDLOG_WARN("Duplicate: [{}]", parser->state_.currentComponent.id); + SPDLOG_WARN("Duplicate: [{}]", parser->state_.currentComponent->id); } } } @@ -346,9 +324,7 @@ void AppStreamParser::endElementCallback(void *user_data, const xmlChar *name) { } void AppStreamParser::charactersCallback(void *user_data, const xmlChar *ch, const int len) { - spdlog::debug("{}", std::string_view(reinterpret_cast(ch), len)); - auto *parser = static_cast(user_data); - if (!parser->state_.currentElement.empty()) { + if (auto *parser = static_cast(user_data); !parser->state_.currentElement.empty()) { parser->state_.currentData.append(reinterpret_cast(ch), len); } } @@ -364,7 +340,7 @@ AppStreamParser::~AppStreamParser() { } void AppStreamParser::mmapFile(const std::string &filename) { - int fd = open(filename.c_str(), O_RDONLY); + const int fd = open(filename.c_str(), O_RDONLY); if (fd == -1) { spdlog::error("Failed to open file: {}", filename); exit(EXIT_FAILURE); @@ -436,7 +412,7 @@ std::vector AppStreamParser::getUniqueCategories() { std::unordered_set uniqueCategories; for (const auto &[key, component]: components_) { - uniqueCategories.insert(component.categories.begin(), component.categories.end()); + uniqueCategories.insert(component->categories.begin(), component->categories.end()); } return {uniqueCategories.begin(), uniqueCategories.end()}; @@ -446,15 +422,15 @@ std::vector AppStreamParser::getUniqueKeywords() { std::unordered_set uniqueKeywords; for (const auto &[key, component]: components_) { - uniqueKeywords.insert(component.keywords.begin(), component.keywords.end()); + uniqueKeywords.insert(component->keywords.begin(), component->keywords.end()); } return {uniqueKeywords.begin(), uniqueKeywords.end()}; } -std::vector AppStreamParser::getSortedComponents(const SortOption option) { +std::vector > AppStreamParser::getSortedComponents(const SortOption option) { // Convert unordered_map to vector for sorting - std::vector sortedComponents; + std::vector > sortedComponents; sortedComponents.reserve(components_.size()); for (const auto &[key, component]: components_) { sortedComponents.push_back(component); @@ -463,14 +439,16 @@ std::vector AppStreamParser::getSortedComponents(const SortOption opt // Sort based on the option switch (option) { case SortOption::BY_ID: - std::sort(sortedComponents.begin(), sortedComponents.end(), [](const Component &a, const Component &b) { - return a.id < b.id; - }); + std::sort(sortedComponents.begin(), sortedComponents.end(), + [](const std::shared_ptr &a, const std::shared_ptr &b) { + return a->id < b->id; + }); break; case SortOption::BY_NAME: - std::sort(sortedComponents.begin(), sortedComponents.end(), [](const Component &a, const Component &b) { - return a.name < b.name; - }); + std::sort(sortedComponents.begin(), sortedComponents.end(), + [](const std::shared_ptr &a, const std::shared_ptr &b) { + return a->name < b->name; + }); break; default: throw std::invalid_argument("Invalid sort option"); @@ -479,11 +457,11 @@ std::vector AppStreamParser::getSortedComponents(const SortOption opt return sortedComponents; } -std::vector AppStreamParser::searchByCategory(const std::string &category) { - std::vector result; +std::vector > AppStreamParser::searchByCategory(const std::string &category) { + std::vector > result; for (const auto &[key, component]: components_) { - if (std::find(component.categories.begin(), component.categories.end(), category) != component.categories. + if (std::find(component->categories.begin(), component->categories.end(), category) != component->categories. end()) { result.push_back(component); } @@ -492,11 +470,11 @@ std::vector AppStreamParser::searchByCategory(const std::string &cate return result; } -std::vector AppStreamParser::searchByKeyword(const std::string &keyword) { - std::vector result; +std::vector > AppStreamParser::searchByKeyword(const std::string &keyword) { + std::vector > result; for (const auto &[key, component]: components_) { - if (std::find(component.keywords.begin(), component.keywords.end(), keyword) != component.keywords.end()) { + if (std::find(component->keywords.begin(), component->keywords.end(), keyword) != component->keywords.end()) { result.push_back(component); } } @@ -508,6 +486,6 @@ size_t AppStreamParser::getTotalComponentCount() const { return components_.size(); } -const std::map &AppStreamParser::getComponents() const { +const std::map > &AppStreamParser::getComponents() const { return components_; } diff --git a/AppStreamParser.h b/AppStreamParser.h index 4a39254..3509252 100644 --- a/AppStreamParser.h +++ b/AppStreamParser.h @@ -18,9 +18,12 @@ #define APPSTREAMPARSER_H #include "Component.h" + +#include +#include #include #include -#include + #include @@ -34,17 +37,17 @@ class AppStreamParser { std::vector getUniqueKeywords(); - std::vector searchByCategory(const std::string &category); + std::vector > searchByCategory(const std::string &category); - std::vector searchByKeyword(const std::string &keyword); + std::vector > searchByKeyword(const std::string &keyword); enum class SortOption { BY_ID, BY_NAME }; - std::vector getSortedComponents(SortOption option); + std::vector > getSortedComponents(SortOption option); [[nodiscard]] size_t getTotalComponentCount() const; - [[nodiscard]] const std::map &getComponents() const; + [[nodiscard]] const std::map > &getComponents() const; private: static constexpr char kEmptyString[] = ""; @@ -52,7 +55,7 @@ class AppStreamParser { static constexpr char kReleaseUrgencyMedium[] = "medium"; static constexpr char kIssueTypeGeneric[] = "generic"; - std::map components_; + std::map > components_; std::string language_; struct ParsingState { @@ -62,15 +65,17 @@ class AppStreamParser { bool insideArtifact = true; bool currentDeveloper = false; + std::shared_ptr currentComponent; std::string currentElement; - Component currentComponent; - Component::Icon currentIcon; std::string currentData; + + Component::Icon currentIcon; Component::UrlType urlType; Component::LaunchableType launchableType; Component::Release currentRelease; Component::Issue currentIssue; Component::Artifact currentArtifact; + std::string currentArtifactChecksumKey; std::string currentArtifactSizeKey; std::string language; diff --git a/Component.cpp b/Component.cpp index e39329f..aa6fb0e 100644 --- a/Component.cpp +++ b/Component.cpp @@ -18,73 +18,126 @@ #include "spdlog/spdlog.h" +constexpr char kPackage[] = "package"; +constexpr char kLimba[] = "limba"; +constexpr char kFlatpak[] = "flatpak"; +constexpr char kAppimage[] = "appimage"; +constexpr char kSnap[] = "snap"; +constexpr char kTarball[] = "tarball"; +constexpr char kCabinet[] = "cabinet"; +constexpr char kLinglong[] = "linglong"; +constexpr char kUnknown[] = "unknown"; + +constexpr char kStock[] = "stock"; +constexpr char kCached[] = "cached"; +constexpr char kLocal[] = "local"; +constexpr char kUrl[] = "url"; +constexpr char kRemote[] = "remote"; + +constexpr char kCosmic[] = "COSMIC"; +constexpr char kGnome[] = "GNOME"; +constexpr char kGnomeClassic[] = "GNOME-Classic"; +constexpr char kGnomeFlashback[] = "GNOME-Flashback"; +constexpr char kKde[] = "KDE"; +constexpr char kLxde[] = "LXDE"; +constexpr char kLxqt[] = "LXQt"; +constexpr char kMate[] = "MATE"; +constexpr char kRazor[] = "Razor"; +constexpr char kRox[] = "ROX"; +constexpr char kTde[] = "TDE"; +constexpr char kUnity[] = "Unity"; +constexpr char kXfce[] = "XFCE"; +constexpr char kEde[] = "EDE"; +constexpr char kCinnamon[] = "Cinnamon"; +constexpr char kPantheon[] = "Pantheon"; +constexpr char kDde[] = "DDE"; +constexpr char kEndless[] = "Endless"; +constexpr char kOld[] = "Old"; + +constexpr char kHomepage[] = "homepage"; +constexpr char kBugtracker[] = "bugtracker"; +constexpr char kFaq[] = "faq"; +constexpr char kHelp[] = "help"; +constexpr char kDonation[] = "donation"; +constexpr char kTranslate[] = "translate"; +constexpr char kContact[] = "contact"; +constexpr char kVcsBrowser[] = "vcs-browser"; +constexpr char kContribute[] = "contribute"; + +constexpr char kDesktopId[] = "desktop-id"; +constexpr char kService[] = "service"; +constexpr char kCockpitManifest[] = "cockpit-manifest"; + +constexpr char kStable[] = "stable"; +constexpr char kDevelopment[] = "development"; +constexpr char kSnapshot[] = "snapshot"; + +constexpr char kLow[] = "low"; +constexpr char kMedium[] = "medium"; +constexpr char kHigh[] = "high"; +constexpr char kCritical[] = "critical"; + +constexpr char kGeneric[] = "generic"; +constexpr char kCve[] = "cve"; + Component::BundleType Component::stringToBundleType(const std::string &typeStr) { - if (typeStr == "package") return BundleType::PACKAGE; - if (typeStr == "limba") return BundleType::LIMBA; - if (typeStr == "flatpak") return BundleType::FLATPAK; - if (typeStr == "appimage") return BundleType::APPIMAGE; - if (typeStr == "snap") return BundleType::SNAP; - if (typeStr == "tarball") return BundleType::TARBALL; - if (typeStr == "cabinet") return BundleType::CABINET; - if (typeStr == "linglong") return BundleType::LINGLONG; + if (typeStr == kPackage) return BundleType::PACKAGE; + if (typeStr == kLimba) return BundleType::LIMBA; + if (typeStr == kFlatpak) return BundleType::FLATPAK; + if (typeStr == kAppimage) return BundleType::APPIMAGE; + if (typeStr == kSnap) return BundleType::SNAP; + if (typeStr == kTarball) return BundleType::TARBALL; + if (typeStr == kCabinet) return BundleType::CABINET; + if (typeStr == kLinglong) return BundleType::LINGLONG; return BundleType::UNKNOWN; } std::string Component::bundleTypeToString(const BundleType type) { switch (type) { - case BundleType::PACKAGE: return "package"; - case BundleType::LIMBA: return "limba"; - case BundleType::FLATPAK: return "flatpak"; - case BundleType::APPIMAGE: return "appimage"; - case BundleType::SNAP: return "snap"; - case BundleType::TARBALL: return "tarball"; - case BundleType::CABINET: return "cabinet"; - case BundleType::LINGLONG: return "linglong"; - default: return "unknown"; + case BundleType::PACKAGE: return kPackage; + case BundleType::LIMBA: return kLimba; + case BundleType::FLATPAK: return kFlatpak; + case BundleType::APPIMAGE: return kAppimage; + case BundleType::SNAP: return kSnap; + case BundleType::TARBALL: return kTarball; + case BundleType::CABINET: return kCabinet; + case BundleType::LINGLONG: return kLinglong; + default: return kUnknown; } } Component::IconType Component::stringToIconType(const std::string &typeStr) { - if (typeStr == "stock") return Component::IconType::STOCK; - if (typeStr == "cached") return Component::IconType::CACHED; - if (typeStr == "local") return Component::IconType::LOCAL; - if (typeStr == "url") return Component::IconType::URL; - if (typeStr == "remote") return Component::IconType::REMOTE; + if (typeStr == kStock) return IconType::STOCK; + if (typeStr == kCached) return IconType::CACHED; + if (typeStr == kLocal) return IconType::LOCAL; + if (typeStr == kUrl) return IconType::URL; + if (typeStr == kRemote) return IconType::REMOTE; return IconType::UNKNOWN; } std::string Component::iconTypeToString(const IconType type) { switch (type) { - case IconType::STOCK: return "stock"; - case IconType::CACHED: return "cached"; - case IconType::LOCAL: return "local"; - case IconType::URL: return "url"; - case IconType::REMOTE: return "remote"; - default: return "unknown"; + case IconType::STOCK: return kStock; + case IconType::CACHED: return kCached; + case IconType::LOCAL: return kLocal; + case IconType::URL: return kUrl; + case IconType::REMOTE: return kRemote; + default: return kUnknown; } } Component::CompulsoryForDesktop Component::stringToCompulsoryForDesktop(const std::string &desktopString) { static const std::unordered_map stringToEnumMap = { - {"COSMIC", CompulsoryForDesktop::COSMIC}, - {"GNOME", CompulsoryForDesktop::GNOME}, - {"GNOME-Classic", CompulsoryForDesktop::GNOME_Classic}, - {"GNOME-Flashback", CompulsoryForDesktop::GNOME_Flashback}, - {"KDE", CompulsoryForDesktop::KDE}, - {"LXDE", CompulsoryForDesktop::LXDE}, - {"LXQt", CompulsoryForDesktop::LXQt}, - {"MATE", CompulsoryForDesktop::MATE}, - {"Razor", CompulsoryForDesktop::Razor}, - {"ROX", CompulsoryForDesktop::ROX}, - {"TDE", CompulsoryForDesktop::TDE}, - {"Unity", CompulsoryForDesktop::Unity}, - {"XFCE", CompulsoryForDesktop::XFCE}, - {"EDE", CompulsoryForDesktop::EDE}, - {"Cinnamon", CompulsoryForDesktop::Cinnamon}, - {"Pantheon", CompulsoryForDesktop::Pantheon}, - {"DDE", CompulsoryForDesktop::DDE}, - {"Endless", CompulsoryForDesktop::Endless}, - {"Old", CompulsoryForDesktop::Old} + {kCosmic, CompulsoryForDesktop::COSMIC}, {kGnome, CompulsoryForDesktop::GNOME}, + {kGnomeClassic, CompulsoryForDesktop::GNOME_Classic}, {kGnomeFlashback, CompulsoryForDesktop::GNOME_Flashback}, + {kKde, CompulsoryForDesktop::KDE}, {kLxde, CompulsoryForDesktop::LXDE}, + {kLxqt, CompulsoryForDesktop::LXQt}, {kMate, CompulsoryForDesktop::MATE}, + {kRazor, CompulsoryForDesktop::Razor}, {kRox, CompulsoryForDesktop::ROX}, + {kTde, CompulsoryForDesktop::TDE}, {kUnity, CompulsoryForDesktop::Unity}, + {kXfce, CompulsoryForDesktop::XFCE}, {kEde, CompulsoryForDesktop::EDE}, + {kCinnamon, CompulsoryForDesktop::Cinnamon}, {kPantheon, CompulsoryForDesktop::Pantheon}, + {kDde, CompulsoryForDesktop::DDE}, {kEndless, CompulsoryForDesktop::Endless}, + {kOld, CompulsoryForDesktop::Old} }; if (const auto it = stringToEnumMap.find(desktopString); it != stringToEnumMap.end()) { @@ -95,97 +148,90 @@ Component::CompulsoryForDesktop Component::stringToCompulsoryForDesktop(const st std::string Component::compulsoryForDesktopToString(const CompulsoryForDesktop desktopEnum) { static const std::unordered_map enumToStringMap = { - {CompulsoryForDesktop::COSMIC, "COSMIC"}, - {CompulsoryForDesktop::GNOME, "GNOME"}, - {CompulsoryForDesktop::GNOME_Classic, "GNOME-Classic"}, - {CompulsoryForDesktop::GNOME_Flashback, "GNOME-Flashback"}, - {CompulsoryForDesktop::KDE, "KDE"}, - {CompulsoryForDesktop::LXDE, "LXDE"}, - {CompulsoryForDesktop::LXQt, "LXQt"}, - {CompulsoryForDesktop::MATE, "MATE"}, - {CompulsoryForDesktop::Razor, "Razor"}, - {CompulsoryForDesktop::ROX, "ROX"}, - {CompulsoryForDesktop::TDE, "TDE"}, - {CompulsoryForDesktop::Unity, "Unity"}, - {CompulsoryForDesktop::XFCE, "XFCE"}, - {CompulsoryForDesktop::EDE, "EDE"}, - {CompulsoryForDesktop::Cinnamon, "Cinnamon"}, - {CompulsoryForDesktop::Pantheon, "Pantheon"}, - {CompulsoryForDesktop::DDE, "DDE"}, - {CompulsoryForDesktop::Endless, "Endless"}, - {CompulsoryForDesktop::Old, "Old"} + {CompulsoryForDesktop::COSMIC, kCosmic}, {CompulsoryForDesktop::GNOME, kGnome}, + {CompulsoryForDesktop::GNOME_Classic, kGnomeClassic}, {CompulsoryForDesktop::GNOME_Flashback, kGnomeFlashback}, + {CompulsoryForDesktop::KDE, kKde}, {CompulsoryForDesktop::LXDE, kLxde}, + {CompulsoryForDesktop::LXQt, kLxqt}, {CompulsoryForDesktop::MATE, kMate}, + {CompulsoryForDesktop::Razor, kRazor}, {CompulsoryForDesktop::ROX, kRox}, + {CompulsoryForDesktop::TDE, kTde}, {CompulsoryForDesktop::Unity, kUnity}, + {CompulsoryForDesktop::XFCE, kXfce}, {CompulsoryForDesktop::EDE, kEde}, + {CompulsoryForDesktop::Cinnamon, kCinnamon}, {CompulsoryForDesktop::Pantheon, kPantheon}, + {CompulsoryForDesktop::DDE, kDde}, {CompulsoryForDesktop::Endless, kEndless}, + {CompulsoryForDesktop::Old, kOld} }; if (const auto it = enumToStringMap.find(desktopEnum); it != enumToStringMap.end()) { return it->second; } - return "unknown"; + return kUnknown; } Component::UrlType Component::stringToUrlType(const std::string &typeStr) { - if (typeStr == "homepage") return UrlType::HOMEPAGE; - if (typeStr == "bugtracker") return UrlType::BUGTRACKER; - if (typeStr == "faq") return UrlType::FAQ; - if (typeStr == "help") return UrlType::HELP; - if (typeStr == "donation") return UrlType::DONATION; - if (typeStr == "translate") return UrlType::TRANSLATE; - if (typeStr == "contact") return UrlType::CONTACT; - if (typeStr == "vcs-browser") return UrlType::VCS_BROWSER; - if (typeStr == "contribute") return UrlType::CONTRIBUTE; + if (typeStr == kHomepage) return UrlType::HOMEPAGE; + if (typeStr == kBugtracker) return UrlType::BUGTRACKER; + if (typeStr == kFaq) return UrlType::FAQ; + if (typeStr == kHelp) return UrlType::HELP; + if (typeStr == kDonation) return UrlType::DONATION; + if (typeStr == kTranslate) return UrlType::TRANSLATE; + if (typeStr == kContact) return UrlType::CONTACT; + if (typeStr == kVcsBrowser) return UrlType::VCS_BROWSER; + if (typeStr == kContribute) return UrlType::CONTRIBUTE; return UrlType::UNKNOWN; } Component::LaunchableType Component::stringToLaunchableType(const std::string &typeStr) { - if (typeStr == "desktop-id") return LaunchableType::DESKTOP_ID; - if (typeStr == "service") return LaunchableType::SERVICE; - if (typeStr == "cockpit-manifest") return LaunchableType::COCKPIT_MANIFEST; - if (typeStr == "url") return LaunchableType::URL; + if (typeStr == kDesktopId) return LaunchableType::DESKTOP_ID; + if (typeStr == kService) return LaunchableType::SERVICE; + if (typeStr == kCockpitManifest) return LaunchableType::COCKPIT_MANIFEST; + if (typeStr == kUrl) return LaunchableType::URL; return LaunchableType::UNKNOWN; } Component::ReleaseType Component::stringToReleaseType(const std::string &typeStr) { - if (typeStr == "stable") return ReleaseType::STABLE; - if (typeStr == "development") return ReleaseType::DEVELOPMENT; - if (typeStr == "snapshot") return ReleaseType::SNAPSHOT; + if (typeStr == kStable) return ReleaseType::STABLE; + if (typeStr == kDevelopment) return ReleaseType::DEVELOPMENT; + if (typeStr == kSnapshot) return ReleaseType::SNAPSHOT; return ReleaseType::UNKNOWN; } Component::ReleaseUrgency Component::stringToReleaseUrgency(const std::string &typeStr) { - if (typeStr == "low") return ReleaseUrgency::LOW; - if (typeStr == "medium") return ReleaseUrgency::MEDIUM; - if (typeStr == "high") return ReleaseUrgency::HIGH; - if (typeStr == "critical") return ReleaseUrgency::CRITICAL; + if (typeStr == kLow) return ReleaseUrgency::LOW; + if (typeStr == kMedium) return ReleaseUrgency::MEDIUM; + if (typeStr == kHigh) return ReleaseUrgency::HIGH; + if (typeStr == kCritical) return ReleaseUrgency::CRITICAL; return ReleaseUrgency::UNKNOWN; } std::string Component::releaseUrgencyToString(const ReleaseUrgency type) { - if (type == ReleaseUrgency::LOW) return "low"; - if (type == ReleaseUrgency::MEDIUM) return "medium"; - if (type == ReleaseUrgency::HIGH) return "high"; - if (type == ReleaseUrgency::CRITICAL) return "critical"; - return "unknown"; + switch (type) { + case ReleaseUrgency::LOW: return kLow; + case ReleaseUrgency::MEDIUM: return kMedium; + case ReleaseUrgency::HIGH: return kHigh; + case ReleaseUrgency::CRITICAL: return kCritical; + default: return kUnknown; + } } Component::IssueType Component::stringToIssueType(const std::string &typeStr) { - if (typeStr == "generic") return IssueType::GENERIC; - if (typeStr == "cve") return IssueType::CVE; + if (typeStr == kGeneric) return IssueType::GENERIC; + if (typeStr == kCve) return IssueType::CVE; return IssueType::UNKNOWN; } std::string Component::releaseTypeToString(const ReleaseType type) { switch (type) { - case ReleaseType::STABLE: return "stable"; - case ReleaseType::SNAPSHOT: return "snapshot"; - case ReleaseType::DEVELOPMENT: return "development"; - default: return "unknown"; + case ReleaseType::STABLE: return kStable; + case ReleaseType::SNAPSHOT: return kSnapshot; + case ReleaseType::DEVELOPMENT: return kDevelopment; + default: return kUnknown; } } std::string Component::issueTypeToString(const IssueType type) { switch (type) { - case IssueType::GENERIC: return "generic"; - case IssueType::CVE: return "cve"; - default: return "unknown"; + case IssueType::GENERIC: return kGeneric; + case IssueType::CVE: return kCve; + default: return kUnknown; } } @@ -198,119 +244,59 @@ void Component::Dump() const { spdlog::info("\tname: {}", name); spdlog::info("\tproject_license: {}", projectLicense); spdlog::info("\tsummary: {}", summary); - if (!pkgname.empty()) { - spdlog::info("\tpkgname: {}", pkgname); - } - if (!source_pkgname.empty()) { - spdlog::info("\tsource_pkgname: {}", source_pkgname); - } - if (!description.empty()) { - spdlog::info("\tdescription: {}", description); - } - if (!url.homepage.empty()) { - spdlog::info("\thomepage: {}", url.homepage); - } - if (!url.bugtracker.empty()) { - spdlog::info("\tbugtracker: {}", url.bugtracker); - } - if (!url.faq.empty()) { - spdlog::info("\tfaq: {}", url.faq); - } - if (!url.help.empty()) { - spdlog::info("\thelp: {}", url.help); - } - if (!url.donation.empty()) { - spdlog::info("\tdonation: {}", url.donation); - } - if (!url.translate.empty()) { - spdlog::info("\ttranslate: {}", url.translate); - } - if (!url.contact.empty()) { - spdlog::info("\tcontact: {}", url.contact); - } - if (!url.vcs_browser.empty()) { - spdlog::info("\tvcs_browser: {}", url.vcs_browser); - } - if (!url.contribute.empty()) { - spdlog::info("\tcontribute: {}", url.contribute); - } - if (!url.unknown.empty()) { - spdlog::info("\tunknown: {}", url.unknown); - } - if (!project_group.empty()) { - spdlog::info("\tproject_group: {}", project_group); - } - if (!developer.id.empty()) { - spdlog::info("\tdeveloper id: {}", developer.id); - } - if (!developer.name.empty()) { - spdlog::info("\tdeveloper name: {}", developer.name); - } - if (!launchable.desktop_id.empty()) { - spdlog::info("\tlaunchable desktop_id: {}", launchable.desktop_id); - } - if (!launchable.service.empty()) { - spdlog::info("\tlaunchable service: {}", launchable.service); - } - if (!launchable.cockpit_manifest.empty()) { - spdlog::info("\tlaunchable cockpit_manifest: {}", launchable.cockpit_manifest); - } - if (!launchable.url.empty()) { - spdlog::info("\tlaunchable url: {}", launchable.url); - } + if (!pkgname.empty()) spdlog::info("\tpkgname: {}", pkgname); + if (!source_pkgname.empty()) spdlog::info("\tsource_pkgname: {}", source_pkgname); + if (!description.empty()) spdlog::info("\tdescription: {}", description); + if (!url.homepage.empty()) spdlog::info("\thomepage: {}", url.homepage); + if (!url.bugtracker.empty()) spdlog::info("\tbugtracker: {}", url.bugtracker); + if (!url.faq.empty()) spdlog::info("\tfaq: {}", url.faq); + if (!url.help.empty()) spdlog::info("\thelp: {}", url.help); + if (!url.donation.empty()) spdlog::info("\tdonation: {}", url.donation); + if (!url.translate.empty()) spdlog::info("\ttranslate: {}", url.translate); + if (!url.contact.empty()) spdlog::info("\tcontact: {}", url.contact); + if (!url.vcs_browser.empty()) spdlog::info("\tvcs_browser: {}", url.vcs_browser); + if (!url.contribute.empty()) spdlog::info("\tcontribute: {}", url.contribute); + if (!url.unknown.empty()) spdlog::info("\tunknown: {}", url.unknown); + if (!project_group.empty()) spdlog::info("\tproject_group: {}", project_group); + if (!developer.id.empty()) spdlog::info("\tdeveloper id: {}", developer.id); + if (!developer.name.empty()) spdlog::info("\tdeveloper name: {}", developer.name); + if (!launchable.desktop_id.empty()) spdlog::info("\tlaunchable desktop_id: {}", launchable.desktop_id); + if (!launchable.service.empty()) spdlog::info("\tlaunchable service: {}", launchable.service); + if (!launchable.cockpit_manifest.empty()) + spdlog::info("\tlaunchable cockpit_manifest: {}", + launchable.cockpit_manifest); + if (!launchable.url.empty()) spdlog::info("\tlaunchable url: {}", launchable.url); for (const auto &comp: compulsory_for_desktop) { - spdlog::info("compulsory_for_desktop: {}", Component::compulsoryForDesktopToString(comp)); + spdlog::info("compulsory_for_desktop: {}", compulsoryForDesktopToString(comp)); } for (const auto &[type, value, width, height, scale]: icons) { spdlog::info("\ticon"); - spdlog::info("\t\ttype: {}", Component::iconTypeToString(type)); + spdlog::info("\t\ttype: {}", iconTypeToString(type)); spdlog::info("\t\tvalue: {}", value); - if (width.has_value()) { - spdlog::info("\t\twidth: {}", width.value()); - } - if (height.has_value()) { - spdlog::info("\t\theight: {}", height.value()); - } - if (scale.has_value()) { - spdlog::info("\t\tscale: {}", scale.value()); - } + if (width) spdlog::info("\t\twidth: {}", *width); + if (height) spdlog::info("\t\theight: {}", *height); + if (scale) spdlog::info("\t\tscale: {}", *scale); } for (const auto &[type, version, date, timestamp, date_eol, urgency, description, url, issues, artifacts]: releases) { spdlog::info("\trelease"); spdlog::info("\t\ttype: {}", releaseTypeToString(type)); spdlog::info("\t\tversion: {}", version); - if (!date.empty()) { - spdlog::info("\t\tdate: {}", date); - } - if (!timestamp.empty()) { - spdlog::info("\t\ttimestamp: {}", timestamp); - } - if (!date_eol.empty()) { - spdlog::info("\t\tdate_eol: {}", date_eol); - } + if (!date.empty()) spdlog::info("\t\tdate: {}", date); + if (!timestamp.empty()) spdlog::info("\t\ttimestamp: {}", timestamp); + if (!date_eol.empty()) spdlog::info("\t\tdate_eol: {}", date_eol); spdlog::info("\t\turgency: {}", releaseUrgencyToString(urgency)); - if (!description.empty()) { - spdlog::info("\t\tdescription: {}", description); - } - if (!url.empty()) { - spdlog::info("\t\turl: {}", url); - } + if (!description.empty()) spdlog::info("\t\tdescription: {}", description); + if (!url.empty()) spdlog::info("\t\turl: {}", url); for (const auto &[type, url, value]: issues) { spdlog::info("\t\tissue"); spdlog::info("\t\t\ttype: {}", issueTypeToString(type)); - if (!url.empty()) { - spdlog::info("\t\t\turl: {}", url); - } - if (!value.empty()) { - spdlog::info("\t\t\tvalue: {}", value); - } + if (!url.empty()) spdlog::info("\t\t\turl: {}", url); + if (!value.empty()) spdlog::info("\t\t\tvalue: {}", value); } for (const auto &[location, checksum, size]: artifacts) { spdlog::info("\t\tartifact"); - if (!location.empty()) { - spdlog::info("\t\t\tlocation: {}", location); - } + if (!location.empty()) spdlog::info("\t\t\tlocation: {}", location); if (!checksum.empty()) { for (const auto &[key, value]: checksum) { spdlog::info("\t\t\tchecksum: {} = {}", key, value); diff --git a/Component.h b/Component.h index b200973..81b7a37 100644 --- a/Component.h +++ b/Component.h @@ -17,7 +17,6 @@ #ifndef COMPONENT_H #define COMPONENT_H -#include #include #include #include diff --git a/main.cpp b/main.cpp index 30f53aa..048ba60 100644 --- a/main.cpp +++ b/main.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -25,47 +26,48 @@ #include #include -// Function to get memory usage from /proc/self/stat +/** + * @brief Retrieves the current memory usage of the process. + * + * This function reads the memory usage statistics from the `/proc/self/stat` file, + * which contains various information about the current process. It extracts the + * virtual memory size (vm_usage) and the resident set size (resident_set) from the file. + * + * @param[out] vm_usage The virtual memory usage in kilobytes. + * @param[out] resident_set The resident set size in kilobytes. + */ void getMemoryUsage(double &vm_usage, double &resident_set) { - using std::ios_base; - using std::ifstream; - using std::string; - vm_usage = 0.0; resident_set = 0.0; - // 'file' represents the file "/proc/self/stat" - ifstream file("/proc/self/stat", ios_base::in); - - // Read in the data from the file - string line; + std::ifstream file("/proc/self/stat"); + std::string line; std::getline(file, line); - file.close(); - // Split the line by whitespace std::istringstream iss(line); - std::vector fields; - string value; - while (iss >> value) { - fields.push_back(value); - } - // fields[22] and fields[23] represent virtual memory and resident set size in kB - if (fields.size() >= 24) { + if (std::vector fields((std::istream_iterator(iss)), std::istream_iterator()) + ; fields.size() >= 24) { unsigned long vsize = std::stoul(fields[22]); long rss = std::stol(fields[23]); + long page_size_kb = sysconf(_SC_PAGE_SIZE) / 1024; - long page_size_kb = sysconf(_SC_PAGE_SIZE) / 1024; // in case x86-64 is configured to use 2MB pages vm_usage = vsize / 1024.0; resident_set = rss * page_size_kb; } } -// Function to get the file size in bytes +/** + * @brief Gets the size of a file. + * + * This function retrieves the size of the specified file in bytes. + * + * @param filename The name of the file whose size is to be determined. + * @return The size of the file in bytes, or -1 if the file could not be accessed. + */ long getFileSize(const std::string &filename) { struct stat stat_buf{}; - const int rc = stat(filename.c_str(), &stat_buf); - return rc == 0 ? stat_buf.st_size : -1; + return stat(filename.c_str(), &stat_buf) == 0 ? stat_buf.st_size : -1; } int main(const int argc, char *argv[]) { @@ -135,7 +137,7 @@ int main(const int argc, char *argv[]) { const auto componentsByCategory = parser->searchByCategory(sampleCategory); spdlog::info("Components in category '{}', ({}):", sampleCategory, sampleCategory.size()); for (const auto &component: componentsByCategory) { - component.Dump(); + component->Dump(); } // After searching by category @@ -147,7 +149,7 @@ int main(const int argc, char *argv[]) { const auto componentsByKeyword = parser->searchByKeyword(sampleKeyword); spdlog::info("Components with keyword '{}', ({}):", sampleKeyword, componentsByKeyword.size()); for (const auto &comp: componentsByKeyword) { - comp.Dump(); + comp->Dump(); } const auto components = parser->getComponents();