# HG changeset patch # User Paper # Date 1701888234 18000 # Node ID 9613d72b097ec76ce0fceee3fdc8ebb0d6206271 # Parent 6ef31dbb90cafb5379fc694370265024a711efc8 *: 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 diff -r 6ef31dbb90ca -r 9613d72b097e include/core/date.h --- 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 -#include +#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 year; - std::shared_ptr month; - std::shared_ptr day; + template + 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 year; + OptionalNumber month; + OptionalNumber day; }; #endif // __core__date_h diff -r 6ef31dbb90ca -r 9613d72b097e src/core/anime_db.cc --- 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 + #include #include diff -r 6ef31dbb90ca -r 9613d72b097e src/core/date.cc --- 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 #include + #include -#include -#include /* An implementation of AniList's "fuzzy date" */ -#define CLAMP(x, low, high) (std::max(low, std::min(high, x))) +template +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()); @@ -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; } diff -r 6ef31dbb90ca -r 9613d72b097e src/core/strings.cc --- 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 #include #include #include + #include #include #include @@ -20,12 +23,15 @@ std::string Implode(const std::vector& 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, wchar_t> converter; + static std::wstring_convert, wchar_t> converter; return converter.from_bytes(string); } @@ -137,12 +138,12 @@ } std::string ToUtf8String(const std::wstring& wstring) { - std::wstring_convert, wchar_t> converter; + static std::wstring_convert, 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 bytes_map = { + static const std::unordered_map 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; } diff -r 6ef31dbb90ca -r 9613d72b097e src/gui/dialog/settings/application.cc --- 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::of(&QComboBox::currentIndexChanged), this, + [this](int index) { theme = static_cast(index); }); + theme_combo_box->setCurrentIndex(static_cast(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); diff -r 6ef31dbb90ca -r 9613d72b097e src/gui/locale.cc --- 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; } diff -r 6ef31dbb90ca -r 9613d72b097e src/gui/pages/anime_list.cc --- 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 #include #include #include diff -r 6ef31dbb90ca -r 9613d72b097e src/gui/pages/statistics.cc --- 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)); diff -r 6ef31dbb90ca -r 9613d72b097e src/gui/translate/anilist.cc --- 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 namespace Translate { namespace AniList { Anime::SeriesStatus ToSeriesStatus(std::string status) { - const std::unordered_map map = { + static const std::unordered_map 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 map = { + static const std::unordered_map 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 map = { + static const std::unordered_map map = { {"TV", Anime::SeriesFormat::TV }, {"TV_SHORT", Anime::SeriesFormat::TV_SHORT}, {"MOVIE", Anime::SeriesFormat::MOVIE }, diff -r 6ef31dbb90ca -r 9613d72b097e src/gui/translate/anime.cc --- 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 map = { + static const std::unordered_map 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 map = { + static const std::unordered_map 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 map = { + static const std::unordered_map 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 map = { + static const std::unordered_map 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 map = { + static const std::unordered_map map = { {"AniList", Anime::Services::ANILIST} }; @@ -150,7 +150,7 @@ } Anime::TitleLanguage ToLanguage(const std::string& str) { - const std::unordered_map map = { + static const std::unordered_map 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 map = { + static const std::unordered_map 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 diff -r 6ef31dbb90ca -r 9613d72b097e src/gui/widgets/anime_info.cc --- 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" diff -r 6ef31dbb90ca -r 9613d72b097e src/gui/widgets/poster.cc --- 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)); diff -r 6ef31dbb90ca -r 9613d72b097e src/services/anilist.cc --- 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 #include #include #include #include #include #include + #include #include @@ -72,7 +75,7 @@ } void ParseListStatus(std::string status, Anime::Anime& anime) { - std::unordered_map map = { + static const std::unordered_map 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) {