Mercurial > minori
changeset 187:9613d72b097e
*: multiple performance improvements
like marking `static const` when it makes sense...
date: change old stupid heap-based method to a structure which should
make copying the thing actually make a copy.
also many performance-based changes, like removing the std::tie
dependency and forward-declaring nlohmann json
*: replace every instance of QString::fromUtf8 to Strings::ToQString.
the main difference is that our function will always convert exactly
what is in the string, while some other times it would only convert
up to the nearest NUL byte
| author | Paper <mrpapersonic@gmail.com> |
|---|---|
| date | Wed, 06 Dec 2023 13:43:54 -0500 |
| parents | 6ef31dbb90ca |
| children | 168382a89b21 |
| files | include/core/date.h src/core/anime_db.cc src/core/date.cc src/core/strings.cc src/gui/dialog/settings/application.cc src/gui/locale.cc src/gui/pages/anime_list.cc src/gui/pages/statistics.cc src/gui/translate/anilist.cc src/gui/translate/anime.cc src/gui/widgets/anime_info.cc src/gui/widgets/poster.cc src/services/anilist.cc |
| diffstat | 13 files changed, 126 insertions(+), 72 deletions(-) [+] |
line wrap: on
line diff
--- a/include/core/date.h Wed Dec 06 11:47:59 2023 -0500 +++ b/include/core/date.h Wed Dec 06 13:43:54 2023 -0500 @@ -1,9 +1,9 @@ #ifndef __core__date_h #define __core__date_h -#include "core/json.h" -#include <QDate> -#include <cstdint> +#include "json/json_fwd.hpp" + +class QDate; class Date { public: @@ -31,9 +31,22 @@ private: /* this implementation sucks and we should really use a struct instead */ - std::shared_ptr<unsigned int> year; - std::shared_ptr<unsigned int> month; - std::shared_ptr<unsigned int> day; + template<typename T> + struct OptionalNumber { + public: + T Get() const { return enabled ? num : 0; } + bool Enabled() const { return enabled; } + void Set(T n) { num = n; enabled = true; } + void Void() { num = 0; enabled = false; } + + protected: + T num = 0; + bool enabled = false; + }; + + OptionalNumber<unsigned int> year; + OptionalNumber<unsigned int> month; + OptionalNumber<unsigned int> day; }; #endif // __core__date_h
--- a/src/core/anime_db.cc Wed Dec 06 11:47:59 2023 -0500 +++ b/src/core/anime_db.cc Wed Dec 06 13:43:54 2023 -0500 @@ -7,6 +7,8 @@ #include "gui/translate/anime.h" #include "gui/translate/anilist.h" +#include <QDate> + #include <fstream> #include <iostream>
--- a/src/core/date.cc Wed Dec 06 11:47:59 2023 -0500 +++ b/src/core/date.cc Wed Dec 06 13:43:54 2023 -0500 @@ -1,14 +1,17 @@ #include "core/date.h" #include "core/json.h" + #include <QDate> #include <QDebug> + #include <algorithm> -#include <cstdint> -#include <tuple> /* An implementation of AniList's "fuzzy date" */ -#define CLAMP(x, low, high) (std::max(low, std::min(high, x))) +template<typename T> +bool CLAMP(T x, T low, T high) { + return std::max(low, std::min(high, x)); +} Date::Date() { } @@ -31,7 +34,7 @@ Date::Date(const nlohmann::json& json) { /* NOTE: this constructor is made for use with - AniList FussyDate-style JSON. In the future, some other + AniList FuzzyDate-style JSON. In the future, some other methods may be parsed and whatnot if necessary. */ if (json.contains("year") && json.at("year").is_number()) SetYear(json.at("year").get<unsigned int>()); @@ -42,58 +45,50 @@ } void Date::VoidYear() { - year.reset(); + year.Void(); } void Date::VoidMonth() { - month.reset(); + month.Void(); } void Date::VoidDay() { - day.reset(); + day.Void(); } void Date::SetYear(unsigned int y) { - year.reset(new unsigned int(y)); + year.Set(y); } void Date::SetMonth(unsigned int m) { - month.reset(new unsigned int(CLAMP(m, 1U, 12U))); + month.Set(CLAMP(m, 1U, 12U)); } void Date::SetDay(unsigned int d) { - day.reset(new unsigned int(CLAMP(d, 1U, 31U))); + day.Set(CLAMP(d, 1U, 31U)); } unsigned int Date::GetYear() const { - unsigned int* ptr = year.get(); - if (ptr != nullptr) - return *year; - return -1; + return year.Get(); } unsigned int Date::GetMonth() const { - unsigned int* ptr = month.get(); - if (ptr != nullptr) - return *month; - return -1; + return month.Get(); } unsigned int Date::GetDay() const { - unsigned int* ptr = day.get(); - if (ptr != nullptr) - return *day; - return -1; + return day.Get(); } bool Date::IsValid() const { - return year.get() && month.get() && day.get(); + return year.Enabled() && month.Enabled() && day.Enabled(); } bool Date::operator<(const Date& other) const { - unsigned int y = GetYear(), m = GetMonth(), d = GetDay(); - unsigned int o_y = other.GetYear(), o_m = other.GetMonth(), o_d = other.GetDay(); - return std::tie(y, m, d) < std::tie(o_y, o_m, o_d); + const unsigned int y = GetYear(), m = GetMonth(), d = GetDay(); + const unsigned int o_y = other.GetYear(), o_m = other.GetMonth(), o_d = other.GetDay(); + + return (y < o_y && m < o_m && d < o_d); } bool Date::operator>(const Date& other) const { @@ -109,26 +104,30 @@ } QDate Date::GetAsQDate() const { - /* QDates don't support "missing" values, for good reason. */ - if (IsValid()) - return QDate(*year, *month, *day); - else - return QDate(); + /* QDate doesn't support "missing" values (for good reason), + * so we do our best and return what we can. + */ + + return QDate(year.Enabled() ? year.Get() : 2000, month.Enabled() ? month.Get() : 1, day.Enabled() ? day.Get() : 1); } nlohmann::json Date::GetAsAniListJson() const { nlohmann::json result = {}; - if (year.get()) - result["year"] = *year; + + if (year.Enabled()) + result["year"] = year.Get(); else result["year"] = nullptr; - if (month.get()) - result["month"] = *month; + + if (month.Enabled()) + result["month"] = month.Get(); else result["month"] = nullptr; - if (day.get()) - result["day"] = *day; + + if (day.Enabled()) + result["day"] = day.Get(); else result["day"] = nullptr; + return result; }
--- a/src/core/strings.cc Wed Dec 06 11:47:59 2023 -0500 +++ b/src/core/strings.cc Wed Dec 06 13:43:54 2023 -0500 @@ -2,10 +2,13 @@ * strings.cpp: Useful functions for manipulating strings **/ #include "core/strings.h" +#include "core/session.h" // locale + #include <QByteArray> #include <QDebug> #include <QString> #include <QLocale> + #include <algorithm> #include <cctype> #include <codecvt> @@ -20,12 +23,15 @@ std::string Implode(const std::vector<std::string>& vector, const std::string& delimiter) { if (vector.size() < 1) return "-"; + std::string out = ""; + for (unsigned long long i = 0; i < vector.size(); i++) { out.append(vector.at(i)); if (i < vector.size() - 1) out.append(delimiter); } + return out; } @@ -113,20 +119,15 @@ /* let Qt handle the heavy lifting of locale shit I don't want to deal with */ std::string ToUpper(const std::string& string) { - /* todo: this "locale" will have to be moved to session.h - it also defaults to en-US, which sucks very much for - anyone who doesn't speak american english... */ - QLocale locale; - return ToUtf8String(locale.toUpper(ToQString(string))); + return ToUtf8String(session.config.locale.GetLocale().toUpper(ToQString(string))); } std::string ToLower(const std::string& string) { - QLocale locale; - return ToUtf8String(locale.toLower(ToQString(string))); + return ToUtf8String(session.config.locale.GetLocale().toLower(ToQString(string))); } std::wstring ToWstring(const std::string& string) { - std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter; + static std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter; return converter.from_bytes(string); } @@ -137,12 +138,12 @@ } std::string ToUtf8String(const std::wstring& wstring) { - std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter; + static std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter; return converter.to_bytes(wstring); } std::string ToUtf8String(const QString& string) { - QByteArray ba = string.toUtf8(); + const QByteArray ba = string.toUtf8(); return std::string(ba.constData(), ba.size()); } @@ -173,7 +174,7 @@ bool ToBool(const std::string& s, const bool def) { if (s.length() < 4) return def; - std::string l = Strings::ToLower(s); + const std::string l = Strings::ToLower(s); if (Strings::BeginningMatchesSubstring(l, "true")) return true; else if (Strings::BeginningMatchesSubstring(l, "false")) @@ -186,7 +187,7 @@ } uint64_t HumanReadableSizeToBytes(const std::string& str) { - const std::unordered_map<std::string, uint64_t> bytes_map = { + static const std::unordered_map<std::string, uint64_t> bytes_map = { {"KB", 1ull << 10}, {"MB", 1ull << 20}, {"GB", 1ull << 30}, @@ -222,6 +223,7 @@ for (unsigned long long i = 0; i < str.length() && i < sub.length(); i++) if (str[i] != sub[i]) return false; + return true; }
--- a/src/gui/dialog/settings/application.cc Wed Dec 06 11:47:59 2023 -0500 +++ b/src/gui/dialog/settings/application.cc Wed Dec 06 13:43:54 2023 -0500 @@ -128,6 +128,25 @@ } { + /* Application theme */ + { + QLabel* theme_combo_box_label = new QLabel(tr("Application theme:"), appearance_group_box); + appearance_layout->addWidget(theme_combo_box_label); + } + + { + QComboBox* theme_combo_box = new QComboBox(appearance_group_box); + theme_combo_box->addItem(tr("Default")); + theme_combo_box->addItem(tr("Light")); + theme_combo_box->addItem(tr("Dark")); + connect(theme_combo_box, QOverload<int>::of(&QComboBox::currentIndexChanged), this, + [this](int index) { theme = static_cast<Themes>(index); }); + theme_combo_box->setCurrentIndex(static_cast<int>(theme)); + appearance_layout->addWidget(theme_combo_box); + } + } + + { /* Hopefully I made this easy to parse... */ QCheckBox* hl_above_anime_box = new QCheckBox(tr("Display highlighted anime above others"), appearance_group_box); hl_above_anime_box->setCheckState(highlighted_anime_above_others ? Qt::Checked : Qt::Unchecked);
--- a/src/gui/locale.cc Wed Dec 06 11:47:59 2023 -0500 +++ b/src/gui/locale.cc Wed Dec 06 13:43:54 2023 -0500 @@ -101,6 +101,7 @@ if (!translator.load(path)) return false; + qApp->installTranslator(&translator); return true; }
--- a/src/gui/pages/anime_list.cc Wed Dec 06 11:47:59 2023 -0500 +++ b/src/gui/pages/anime_list.cc Wed Dec 06 13:43:54 2023 -0500 @@ -18,6 +18,7 @@ #include "gui/translate/anime.h" #include "services/services.h" +#include <QDate> #include <QDebug> #include <QHBoxLayout> #include <QHeaderView>
--- a/src/gui/pages/statistics.cc Wed Dec 06 11:47:59 2023 -0500 +++ b/src/gui/pages/statistics.cc Wed Dec 06 13:43:54 2023 -0500 @@ -1,5 +1,6 @@ #include "gui/pages/statistics.h" #include "core/anime_db.h" +#include "core/strings.h" #include "core/session.h" #include "gui/pages/anime_list.h" #include "gui/widgets/text.h" @@ -140,7 +141,7 @@ _score_distribution_graph->AddItem(i, GetTotalWithScore(i)); string = ""; - ts << QString::fromUtf8(SecondsToDateString(session.uptime() / 1000).c_str()) << '\n'; + ts << Strings::ToQString(SecondsToDateString(session.uptime() / 1000)) << '\n'; ts << session.GetRequests(); /* Application */ // UiUtils::SetPlainTextEditData(application_data, QString::number(session.uptime() / 1000));
--- a/src/gui/translate/anilist.cc Wed Dec 06 11:47:59 2023 -0500 +++ b/src/gui/translate/anilist.cc Wed Dec 06 13:43:54 2023 -0500 @@ -1,10 +1,11 @@ #include "gui/translate/anilist.h" +#include <unordered_map> namespace Translate { namespace AniList { Anime::SeriesStatus ToSeriesStatus(std::string status) { - const std::unordered_map<std::string, Anime::SeriesStatus> map = { + static const std::unordered_map<std::string, Anime::SeriesStatus> map = { {"FINISHED", Anime::SeriesStatus::FINISHED }, {"RELEASING", Anime::SeriesStatus::RELEASING }, {"NOT_YET_RELEASED", Anime::SeriesStatus::NOT_YET_RELEASED}, @@ -18,7 +19,7 @@ } Anime::SeriesSeason ToSeriesSeason(std::string season) { - const std::unordered_map<std::string, Anime::SeriesSeason> map = { + static const std::unordered_map<std::string, Anime::SeriesSeason> map = { {"WINTER", Anime::SeriesSeason::WINTER}, {"SPRING", Anime::SeriesSeason::SPRING}, {"SUMMER", Anime::SeriesSeason::SUMMER}, @@ -31,7 +32,7 @@ } Anime::SeriesFormat ToSeriesFormat(std::string format) { - const std::unordered_map<std::string, enum Anime::SeriesFormat> map = { + static const std::unordered_map<std::string, enum Anime::SeriesFormat> map = { {"TV", Anime::SeriesFormat::TV }, {"TV_SHORT", Anime::SeriesFormat::TV_SHORT}, {"MOVIE", Anime::SeriesFormat::MOVIE },
--- a/src/gui/translate/anime.cc Wed Dec 06 11:47:59 2023 -0500 +++ b/src/gui/translate/anime.cc Wed Dec 06 13:43:54 2023 -0500 @@ -83,7 +83,7 @@ } Anime::ListStatus ToListStatus(const std::string& str) { - const std::unordered_map<std::string, Anime::ListStatus> map = { + static const std::unordered_map<std::string, Anime::ListStatus> map = { {"Currently watching", Anime::ListStatus::CURRENT}, {"Plan to watch", Anime::ListStatus::PLANNING}, {"Completed", Anime::ListStatus::COMPLETED}, @@ -97,7 +97,7 @@ } Anime::SeriesStatus ToSeriesStatus(const std::string& str) { - const std::unordered_map<std::string, Anime::SeriesStatus> map = { + static const std::unordered_map<std::string, Anime::SeriesStatus> map = { {"Currently airing", Anime::SeriesStatus::RELEASING}, {"Finished airing", Anime::SeriesStatus::FINISHED}, {"Not yet aired", Anime::SeriesStatus::NOT_YET_RELEASED}, @@ -111,7 +111,7 @@ } Anime::SeriesSeason ToSeriesSeason(const std::string& str) { - const std::unordered_map<std::string, Anime::SeriesSeason> map = { + static const std::unordered_map<std::string, Anime::SeriesSeason> map = { {"Winter", Anime::SeriesSeason::WINTER}, {"Summer", Anime::SeriesSeason::SUMMER}, {"Fall", Anime::SeriesSeason::FALL}, @@ -124,7 +124,7 @@ } Anime::SeriesFormat ToSeriesFormat(const std::string& str) { - const std::unordered_map<std::string, Anime::SeriesFormat> map = { + static const std::unordered_map<std::string, Anime::SeriesFormat> map = { {"TV", Anime::SeriesFormat::TV}, {"TV short", Anime::SeriesFormat::TV_SHORT}, {"OVA", Anime::SeriesFormat::OVA}, @@ -140,7 +140,7 @@ } Anime::Services ToService(const std::string& str) { - const std::unordered_map<std::string, Anime::Services> map = { + static const std::unordered_map<std::string, Anime::Services> map = { {"AniList", Anime::Services::ANILIST} }; @@ -150,7 +150,7 @@ } Anime::TitleLanguage ToLanguage(const std::string& str) { - const std::unordered_map<std::string, Anime::TitleLanguage> map = { + static const std::unordered_map<std::string, Anime::TitleLanguage> map = { {"Romaji", Anime::TitleLanguage::ROMAJI}, {"Native", Anime::TitleLanguage::NATIVE}, {"English", Anime::TitleLanguage::ENGLISH} @@ -162,7 +162,7 @@ } Anime::ScoreFormat ToScoreFormat(const std::string& str) { - const std::unordered_map<std::string, Anime::ScoreFormat> map = { + static const std::unordered_map<std::string, Anime::ScoreFormat> map = { {"POINT_3", Anime::ScoreFormat::POINT_3}, {"POINT_5", Anime::ScoreFormat::POINT_5}, {"POINT_10", Anime::ScoreFormat::POINT_10}, @@ -175,7 +175,7 @@ return map.at(str); } -/* Localized versions of ToString() functions */ +/* Localized versions of ToString() functions. Meant for display to the user. */ std::string ToLocalString(const Anime::ListStatus status) { switch (status) { @@ -243,4 +243,15 @@ } } +std::string ToLocalString(const Anime::ScoreFormat format) { + switch (format) { + case Anime::ScoreFormat::POINT_3: return Strings::ToUtf8String(QCoreApplication::tr("3-point")); + case Anime::ScoreFormat::POINT_5: return Strings::ToUtf8String(QCoreApplication::tr("5-point")); + case Anime::ScoreFormat::POINT_10: return Strings::ToUtf8String(QCoreApplication::tr("10-point")); + case Anime::ScoreFormat::POINT_10_DECIMAL: return Strings::ToUtf8String(QCoreApplication::tr("10-point (Decimal)")); + default: + case Anime::ScoreFormat::POINT_100: return Strings::ToUtf8String(QCoreApplication::tr("100-point")); + } +} + } // namespace Translate
--- a/src/gui/widgets/anime_info.cc Wed Dec 06 11:47:59 2023 -0500 +++ b/src/gui/widgets/anime_info.cc Wed Dec 06 13:43:54 2023 -0500 @@ -32,8 +32,9 @@ QString details_data; QTextStream details_data_s(&details_data); /* we have to convert ALL of these strings to - QString because QTextStream sucks and assumes - Latin1 (on Windows?) */ + * QString because QTextStream sucks and assumes + * Latin1 (on Windows?) + */ details_data_s << Strings::ToQString(Translate::ToString(anime.GetFormat())) << "\n" << anime.GetEpisodes() << "\n" << Strings::ToQString(Translate::ToString(anime.GetUserStatus())) << "\n"
--- a/src/gui/widgets/poster.cc Wed Dec 06 11:47:59 2023 -0500 +++ b/src/gui/widgets/poster.cc Wed Dec 06 13:43:54 2023 -0500 @@ -51,7 +51,7 @@ } void Poster::RenderToLabel() { - QPixmap pixmap = QPixmap::fromImage(img); + const QPixmap pixmap = QPixmap::fromImage(img); if (pixmap.isNull()) return; label->setPixmap(pixmap.scaled(label->size(), Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation));
--- a/src/services/anilist.cc Wed Dec 06 11:47:59 2023 -0500 +++ b/src/services/anilist.cc Wed Dec 06 13:43:54 2023 -0500 @@ -7,12 +7,15 @@ #include "core/session.h" #include "core/strings.h" #include "gui/translate/anilist.h" + +#include <QDate> #include <QByteArray> #include <QDesktopServices> #include <QInputDialog> #include <QLineEdit> #include <QMessageBox> #include <QUrl> + #include <chrono> #include <exception> @@ -72,7 +75,7 @@ } void ParseListStatus(std::string status, Anime::Anime& anime) { - std::unordered_map<std::string, Anime::ListStatus> map = { + static const std::unordered_map<std::string, Anime::ListStatus> map = { {"CURRENT", Anime::ListStatus::CURRENT }, {"PLANNING", Anime::ListStatus::PLANNING }, {"COMPLETED", Anime::ListStatus::COMPLETED}, @@ -91,7 +94,7 @@ return; } - anime.SetUserStatus(map[status]); + anime.SetUserStatus(map.at(status)); } std::string ListStatusToString(const Anime::Anime& anime) {
