perf: prefer small containers (#6542)

* perf: make pref_is_savable() constexpr

* refactor: use std::vector in tr_torrents::removedSince()

* chore: remove unused typedef in OptionsDialog

* perf: use std::vector in tr_num_parse_range()

* perf: use small::max_size_set in FileTreeItem::update()

* perf: use small:set in Wishlist::next()

* perf: use small:map in FilterBar

* perf: use small::map for counts in tr_logAddMessage()

* perf: use small::max_size_map in FileTreeModel::twiddleWanted()

perf: use small::max_size_map in FileTreeModel::twiddlePriority()

* perf: use a std::array instead of std::map in TorrentFilter::update()

* perf: use a std::array instead of std::map in TorrentSorter::set_mode()

* perf: use a std::array instead of std::map in TorrentSorter::update()

* perf: use small::set in Application::Impl::on_rpc_changed_idle()

* perf: use std::array for MessageLogColumnsModel::level_names_

* fixup! perf: use std::array for MessageLogColumnsModel::level_names_

* fixup! perf: use small::map for counts in tr_logAddMessage()
This commit is contained in:
Charles Kerr 2024-01-27 09:33:12 -06:00 committed by GitHub
parent 9f77ef9c7a
commit a51f08e532
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 97 additions and 66 deletions

View File

@ -11,7 +11,7 @@ IncludeCategories:
SortPriority: 4
- Regex: '^<(cairo|gdk|gio|glib|gtk|pango)mm([-./]|config)'
Priority: 5
- Regex: '^<(fmt)/'
- Regex: '^<(fmt|small)/'
Priority: 6
- Regex: '^<(cairo|gdk|gio|glib|gtk|pango)[-./]'
Priority: 8

View File

@ -52,6 +52,8 @@
#include <gtkmm/stylecontext.h>
#include <gtkmm/window.h>
#include <small/set.hpp>
#if GTKMM_CHECK_VERSION(4, 0, 0)
#include <gtkmm/droptarget.h>
#include <gtkmm/eventcontrollerfocus.h>
@ -70,7 +72,6 @@
#include <iterator> // std::back_inserter
#include <map>
#include <memory>
#include <set>
#include <sstream>
#include <string>
#include <thread>
@ -478,11 +479,13 @@ bool Application::Impl::on_rpc_changed_idle(tr_rpc_callback_type type, tr_torren
auto const newvals = tr_sessionGetSettings(session);
// determine which settings changed
auto changed_keys = std::set<tr_quark>{};
auto changed_keys = small::set<tr_quark>{};
auto& oldvals = gtr_pref_get_all();
auto const serde = tr_variant_serde::benc();
if (auto const* const newvals_map = newvals.get_if<tr_variant::Map>(); newvals_map != nullptr)
{
changed_keys.reserve(std::size(*newvals_map));
for (auto const& [key, newval] : *newvals_map)
{
bool changed = true;

View File

@ -36,9 +36,10 @@
#include <fmt/core.h>
#include <fmt/ostream.h>
#include <array>
#include <fstream>
#include <map>
#include <memory>
#include <utility>
class MessageLogColumnsModel : public Gtk::TreeModelColumnRecord
{
@ -95,7 +96,14 @@ private:
tr_log_level maxLevel_ = TR_LOG_INFO;
bool isPaused_ = false;
sigc::connection refresh_tag_;
std::map<tr_log_level, char const*> const level_names_;
static auto const inline level_names_ = std::array<std::pair<tr_log_level, char const*>, 5U>{ {
{ TR_LOG_CRITICAL, C_("Logging level", "Critical") },
{ TR_LOG_ERROR, C_("Logging level", "Error") },
{ TR_LOG_WARN, C_("Logging level", "Warning") },
{ TR_LOG_INFO, C_("Logging level", "Information") },
{ TR_LOG_DEBUG, C_("Logging level", "Debug") },
} };
};
namespace
@ -163,6 +171,7 @@ void MessageLogWindow::Impl::level_combo_init(Gtk::ComboBox* level_combo) const
auto has_pref_level = false;
auto items = std::vector<std::pair<Glib::ustring, int>>{};
items.reserve(std::size(level_names_));
for (auto const& [level, name] : level_names_)
{
items.emplace_back(name, level);
@ -213,8 +222,11 @@ void MessageLogWindow::Impl::doSave(std::string const& filename)
auto const* const node = row.get_value(message_log_cols.tr_msg);
auto const date = gtr_asctime(node->when);
auto const it = level_names_.find(node->level);
auto const* const level_str = it != std::end(level_names_) ? it->second : "???";
auto const iter = std::find_if(
std::begin(level_names_),
std::end(level_names_),
[key = node->level](auto const& item) { return item.first == key; });
auto const* const level_str = iter != std::end(level_names_) ? iter->second : "???";
fmt::print(stream, "{}\t{}\t{}\t{}\n", date, level_str, node->name, node->message);
}
@ -477,13 +489,6 @@ MessageLogWindow::Impl::Impl(
, refresh_tag_(Glib::signal_timeout().connect_seconds(
sigc::mem_fun(*this, &Impl::onRefresh),
SECONDARY_WINDOW_REFRESH_INTERVAL_SECONDS))
, level_names_{ {
{ TR_LOG_CRITICAL, C_("Logging level", "Critical") },
{ TR_LOG_ERROR, C_("Logging level", "Error") },
{ TR_LOG_WARN, C_("Logging level", "Warning") },
{ TR_LOG_INFO, C_("Logging level", "Information") },
{ TR_LOG_DEBUG, C_("Logging level", "Debug") },
} }
{
/**
*** toolbar

View File

@ -10,6 +10,9 @@
#include <libtransmission/transmission.h>
#include <array>
#include <utility>
TorrentFilter::TorrentFilter()
: Glib::ObjectBase(typeid(TorrentFilter))
{
@ -127,7 +130,7 @@ void TorrentFilter::update(Torrent::ChangeFlags changes)
if (activity_type_ != Activity::ALL)
{
static auto const activity_flags = std::map<Activity, Torrent::ChangeFlags>({
static constexpr auto ActivityFlags = std::array<std::pair<Activity, Torrent::ChangeFlags>, 7U>{ {
{ Activity::DOWNLOADING, Flag::ACTIVITY },
{ Activity::SEEDING, Flag::ACTIVITY },
{ Activity::ACTIVE, Flag::ACTIVE_PEER_COUNT | Flag::ACTIVITY },
@ -135,10 +138,13 @@ void TorrentFilter::update(Torrent::ChangeFlags changes)
{ Activity::FINISHED, Flag::FINISHED },
{ Activity::VERIFYING, Flag::ACTIVITY },
{ Activity::ERROR, Flag::ERROR_CODE },
});
} };
auto const activity_flags_it = activity_flags.find(activity_type_);
refilter_needed = activity_flags_it != activity_flags.end() && changes.test(activity_flags_it->second);
auto const iter = std::find_if(
std::begin(ActivityFlags),
std::end(ActivityFlags),
[key = activity_type_](auto const& row) { return row.first == key; });
refilter_needed = iter != std::end(ActivityFlags) && changes.test(iter->second);
}
if (!refilter_needed)

View File

@ -13,6 +13,8 @@
#include <libtransmission/utils.h>
#include <algorithm>
#include <array>
#include <utility>
using namespace std::string_view_literals;
@ -178,7 +180,8 @@ TorrentSorter::TorrentSorter()
void TorrentSorter::set_mode(std::string_view mode)
{
static auto const compare_funcs = std::map<std::string_view, CompareFunc>({
static auto constexpr DefaultCompareFunc = &compare_by_name;
static auto constexpr CompareFuncs = std::array<std::pair<std::string_view, CompareFunc>, 9U>{ {
{ "sort-by-activity"sv, &compare_by_activity },
{ "sort-by-age"sv, &compare_by_age },
{ "sort-by-name"sv, &compare_by_name },
@ -188,14 +191,13 @@ void TorrentSorter::set_mode(std::string_view mode)
{ "sort-by-size"sv, &compare_by_size },
{ "sort-by-state"sv, &compare_by_state },
{ "sort-by-time-left"sv, &compare_by_eta },
});
auto compare_func = &compare_by_name;
if (auto const compare_func_it = compare_funcs.find(mode); compare_func_it != compare_funcs.end())
{
compare_func = compare_func_it->second;
}
} };
auto const iter = std::find_if(
std::begin(CompareFuncs),
std::end(CompareFuncs),
[key = mode](auto const& row) { return row.first == key; });
auto const compare_func = iter != std::end(CompareFuncs) ? iter->second : DefaultCompareFunc;
if (compare_func_ == compare_func)
{
return;
@ -224,8 +226,7 @@ int TorrentSorter::compare(Torrent const& lhs, Torrent const& rhs) const
void TorrentSorter::update(Torrent::ChangeFlags changes)
{
using Flag = Torrent::ChangeFlag;
static auto const compare_flags = std::map<CompareFunc, Torrent::ChangeFlags>({
static auto constexpr CompareFlags = std::array<std::pair<CompareFunc, Torrent::ChangeFlags>, 9U>{ {
{ &compare_by_activity, Flag::ACTIVE_PEER_COUNT | Flag::QUEUE_POSITION | Flag::SPEED_DOWN | Flag::SPEED_UP },
{ &compare_by_age, Flag::ADDED_DATE | Flag::NAME },
{ &compare_by_eta, Flag::ETA | Flag::NAME },
@ -235,10 +236,13 @@ void TorrentSorter::update(Torrent::ChangeFlags changes)
{ &compare_by_ratio, Flag::QUEUE_POSITION | Flag::RATIO },
{ &compare_by_size, Flag::NAME | Flag::TOTAL_SIZE },
{ &compare_by_state, Flag::ACTIVITY | Flag::QUEUE_POSITION },
});
} };
if (auto const compare_flags_it = compare_flags.find(compare_func_);
compare_flags_it != compare_flags.end() && changes.test(compare_flags_it->second))
if (auto const iter = std::find_if(
std::begin(CompareFlags),
std::end(CompareFlags),
[key = compare_func_](auto const& row) { return row.first == key; });
iter != std::end(CompareFlags) && changes.test(iter->second))
{
changed(Change::DIFFERENT);
}

View File

@ -8,7 +8,7 @@
#include <chrono>
#include <cstddef> // size_t
#include <iterator> // back_insert_iterator, empty
#include <map>
#include <memory>
#include <mutex>
#include <optional>
#include <string>
@ -22,6 +22,8 @@
#include <fmt/chrono.h>
#include <fmt/core.h>
#include <small/map.hpp>
#include "libtransmission/file.h"
#include "libtransmission/log.h"
#include "libtransmission/tr-assert.h"
@ -246,12 +248,12 @@ void tr_logAddMessage(char const* file, long line, tr_log_level level, std::stri
auto const lock = log_state.unique_lock();
// don't log the same warning ad infinitum.
// it's not useful after some point.
// at some point, it stops being useful.
bool last_one = false;
if (level == TR_LOG_CRITICAL || level == TR_LOG_ERROR || level == TR_LOG_WARN)
{
static auto constexpr MaxRepeat = size_t{ 30 };
static auto counts = new std::map<std::pair<std::string_view, int>, size_t>{};
static auto* const counts = new small::map<std::pair<std::string_view, long>, size_t>{};
auto& count = (*counts)[std::make_pair(filename, line)];
++count;
@ -267,12 +269,8 @@ void tr_logAddMessage(char const* file, long line, tr_log_level level, std::stri
logAddImpl(filename, line, level, std::move(msg), name);
if (last_one)
{
logAddImpl(
filename,
line,
level,
_("Too many messages like this! I won't log this message anymore this session."),
name);
char const* final_msg = _("Too many messages like this! I won't log this message anymore this session.");
logAddImpl(filename, line, level, final_msg, name);
}
errno = err;

View File

@ -5,10 +5,11 @@
#include <algorithm> // std::min, std::partial_sort
#include <cstddef>
#include <set>
#include <utility>
#include <vector>
#include <small/set.hpp>
#define LIBTRANSMISSION_PEER_MODULE
#include "libtransmission/transmission.h"
@ -136,11 +137,12 @@ std::vector<tr_block_span_t> Wishlist::next(size_t n_wanted_blocks)
// We usually won't need all the candidates to be sorted until endgame, so don't
// waste cycles sorting all of them here. partial sort is enough.
static auto constexpr MaxSortedPieces = size_t{ 30 };
static auto constexpr MaxSortedPieces = size_t{ 30U };
auto const middle = std::min(std::size(candidates), MaxSortedPieces);
std::partial_sort(std::begin(candidates), std::begin(candidates) + middle, std::end(candidates));
auto blocks = std::set<tr_block_index_t>{};
auto blocks = small::set<tr_block_index_t, 4096U>{};
blocks.reserve(n_wanted_blocks);
for (auto const& candidate : candidates)
{
// do we have enough?

View File

@ -5,7 +5,6 @@
#include <algorithm>
#include <ctime>
#include <set>
#include <string_view>
#include <vector>
@ -91,15 +90,18 @@ void tr_torrents::remove(tr_torrent const* tor, time_t current_time)
std::vector<tr_torrent_id_t> tr_torrents::removedSince(time_t timestamp) const
{
auto ids = std::set<tr_torrent_id_t>{};
auto ids = std::vector<tr_torrent_id_t>{};
ids.reserve(std::size(removed_));
for (auto const& [id, removed_at] : removed_)
{
if (removed_at >= timestamp)
{
ids.insert(id);
ids.emplace_back(id);
}
}
return { std::begin(ids), std::end(ids) };
std::sort(std::begin(ids), std::end(ids));
ids.erase(std::unique(std::begin(ids), std::end(ids)), std::end(ids));
return ids;
}

View File

@ -493,18 +493,20 @@ std::vector<int> tr_num_parse_range(std::string_view str)
{
using namespace tr_num_parse_range_impl;
auto values = std::set<int>{};
auto values = std::vector<int>{};
auto token = std::string_view{};
auto range = number_range{};
while (tr_strv_sep(&str, &token, ',') && parseNumberSection(token, range))
{
for (auto i = range.low; i <= range.high; ++i)
{
values.insert(i);
values.emplace_back(i);
}
}
return { std::begin(values), std::end(values) };
std::sort(std::begin(values), std::end(values));
values.erase(std::unique(std::begin(values), std::end(values)), std::end(values));
return values;
}
// ---

View File

@ -5,9 +5,10 @@
#include <algorithm>
#include <cassert>
#include <set>
#include <utility>
#include <small/set.hpp>
#include <QApplication>
#include <QStyle>
@ -223,7 +224,7 @@ uint64_t FileTreeItem::size() const
std::pair<int, int> FileTreeItem::update(QString const& name, bool wanted, int priority, uint64_t have_size, bool update_fields)
{
auto changed_columns = std::set<int>{};
auto changed_columns = small::max_size_set<int, FileTreeModel::NUM_COLUMNS>{};
if (name_ != name)
{

View File

@ -7,10 +7,11 @@
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <map>
#include <memory>
#include <set>
#include <small/map.hpp>
#include <libtransmission/transmission.h> // priorities
#include <QAbstractItemModel>
@ -470,7 +471,7 @@ void FileTreeModel::emitSubtreeChanged(QModelIndex const& idx, int first_column,
void FileTreeModel::twiddleWanted(QModelIndexList const& indices)
{
std::map<bool, QModelIndexList> wanted_indices;
auto wanted_indices = small::max_size_map<bool, QModelIndexList, 2U>{};
for (QModelIndex const& i : getOrphanIndices(indices))
{
@ -489,7 +490,7 @@ void FileTreeModel::twiddleWanted(QModelIndexList const& indices)
void FileTreeModel::twiddlePriority(QModelIndexList const& indices)
{
std::map<int, QModelIndexList> priority_indices;
auto priority_indices = small::max_size_map<int, QModelIndexList, 8U>{};
for (QModelIndex const& i : getOrphanIndices(indices))
{

View File

@ -155,7 +155,7 @@ void FilterBar::refreshTrackers()
return i;
};
auto new_trackers = std::map<QString, int>(torrents_per_sitename.begin(), torrents_per_sitename.end());
auto new_trackers = small::map<QString, int>{ torrents_per_sitename.begin(), torrents_per_sitename.end() };
auto old_it = sitename_counts_.cbegin();
auto new_it = new_trackers.cbegin();
auto const old_end = sitename_counts_.cend();

View File

@ -6,7 +6,8 @@
#pragma once
#include <bitset>
#include <map>
#include <small/map.hpp>
#include <QLineEdit>
#include <QStandardItemModel>
@ -63,7 +64,7 @@ private:
FilterBarComboBox* const tracker_combo_ = createTrackerCombo(tracker_model_);
QLineEdit* const line_edit_ = new QLineEdit{ this };
std::map<QString, int> sitename_counts_;
small::map<QString, int> sitename_counts_;
QTimer recount_timer_;
Pending pending_ = {};
bool is_bootstrapping_ = {};

View File

@ -54,8 +54,6 @@ private slots:
void onSessionUpdated();
private:
using mybins_t = std::map<uint32_t, int32_t>;
void reload();
void updateWidgetsLocality();
void clearInfo();

View File

@ -201,6 +201,19 @@ bool isValidUtf8(QByteArray const& byteArray)
#endif
}
[[nodiscard]] constexpr auto pref_is_savable(int pref)
{
switch (pref)
{
// these are the prefs that don't get saved to settings.json
// when the application exits.
case Prefs::FILTER_TEXT:
return false;
default:
return true;
}
}
} // namespace
/***
@ -220,10 +233,6 @@ Prefs::Prefs(QString config_dir)
#endif
// these are the prefs that don't get saved to settings.json
// when the application exits.
temporary_prefs_.insert(FILTER_TEXT);
auto const app_defaults = get_default_app_settings();
auto settings = tr_sessionLoadSettings(&app_defaults, config_dir_.toUtf8().constData(), nullptr);
ensureSoundCommandIsAList(&settings);
@ -323,7 +332,7 @@ Prefs::~Prefs()
for (int i = 0; i < PREFS_COUNT; ++i)
{
if (temporary_prefs_.count(i) != 0U)
if (!pref_is_savable(i))
{
continue;
}

View File

@ -204,7 +204,6 @@ private:
QString const config_dir_;
std::set<int> temporary_prefs_;
std::array<QVariant, PREFS_COUNT> mutable values_;
static std::array<PrefItem, PREFS_COUNT> const Items;