refactor: add tr_compare_3way() (#5742)
* refactor: add tr_compare_3way() This is a small templated utility function to make libtransmission's sorting / comparison code more consistent and easier to read.
This commit is contained in:
parent
c364abcb6f
commit
fdf042d32c
|
@ -64,35 +64,22 @@ struct StopsCompare
|
|||
// primary key: volume of data transferred
|
||||
auto const ax = one.up + one.down;
|
||||
auto const bx = two.up + two.down;
|
||||
if (ax < bx)
|
||||
if (auto const val = tr_compare_3way(ax, bx); val != 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (ax > bx)
|
||||
{
|
||||
return 1;
|
||||
return val;
|
||||
}
|
||||
|
||||
// secondary key: the torrent's info_hash
|
||||
for (size_t i = 0, n = sizeof(tr_sha1_digest_t); i < n; ++i)
|
||||
{
|
||||
if (one.info_hash[i] != two.info_hash[i])
|
||||
if (auto const val = tr_compare_3way(one.info_hash[i], two.info_hash[i]); val != 0)
|
||||
{
|
||||
return one.info_hash[i] < two.info_hash[i] ? -1 : 1;
|
||||
return val;
|
||||
}
|
||||
}
|
||||
|
||||
// tertiary key: the tracker's announce url
|
||||
if (one.announce_url < two.announce_url)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (one.announce_url > two.announce_url)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return tr_compare_3way(one.announce_url, two.announce_url);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr auto operator()(tr_announce_request const& one, tr_announce_request const& two) const noexcept
|
||||
|
@ -1478,15 +1465,15 @@ namespace upkeep_helpers
|
|||
int compareAnnounceTiers(tr_tier const* a, tr_tier const* b)
|
||||
{
|
||||
/* prefer higher-priority events */
|
||||
if (auto const priority_a = a->announce_event_priority, priority_b = b->announce_event_priority; priority_a != priority_b)
|
||||
if (auto const val = tr_compare_3way(a->announce_event_priority, b->announce_event_priority); val != 0)
|
||||
{
|
||||
return priority_a > priority_b ? -1 : 1;
|
||||
return -val;
|
||||
}
|
||||
|
||||
/* prefer swarms where we might upload */
|
||||
if (auto const leechers_a = a->countDownloaders(), leechers_b = b->countDownloaders(); leechers_a != leechers_b)
|
||||
if (auto const val = tr_compare_3way(a->countDownloaders(), b->countDownloaders()); val != 0)
|
||||
{
|
||||
return leechers_a > leechers_b ? -1 : 1;
|
||||
return -val;
|
||||
}
|
||||
|
||||
/* prefer swarms where we might download */
|
||||
|
@ -1496,17 +1483,18 @@ int compareAnnounceTiers(tr_tier const* a, tr_tier const* b)
|
|||
}
|
||||
|
||||
/* prefer larger stats, to help ensure stats get recorded when stopping on shutdown */
|
||||
if (auto const xa = a->byteCounts[TR_ANN_UP] + a->byteCounts[TR_ANN_DOWN],
|
||||
xb = b->byteCounts[TR_ANN_UP] + b->byteCounts[TR_ANN_DOWN];
|
||||
xa != xb)
|
||||
if (auto const val = tr_compare_3way(
|
||||
a->byteCounts[TR_ANN_UP] + a->byteCounts[TR_ANN_DOWN],
|
||||
b->byteCounts[TR_ANN_UP] + b->byteCounts[TR_ANN_DOWN]);
|
||||
val != 0)
|
||||
{
|
||||
return xa > xb ? -1 : 1;
|
||||
return -val;
|
||||
}
|
||||
|
||||
// announcements that have been waiting longer go first
|
||||
if (a->announceAt != b->announceAt)
|
||||
if (auto const val = tr_compare_3way(a->announceAt, b->announceAt); val != 0)
|
||||
{
|
||||
return a->announceAt < b->announceAt ? -1 : 1;
|
||||
return val;
|
||||
}
|
||||
|
||||
// the tiers are effectively equal priority, but add an arbitrary
|
||||
|
|
|
@ -590,9 +590,9 @@ std::pair<sockaddr_storage, socklen_t> tr_address::to_sockaddr(tr_port port) con
|
|||
int tr_address::compare(tr_address const& that) const noexcept // <=>
|
||||
{
|
||||
// IPv6 addresses are always "greater than" IPv4
|
||||
if (this->type != that.type)
|
||||
if (auto const val = tr_compare_3way(this->type, that.type); val != 0)
|
||||
{
|
||||
return this->is_ipv4() ? 1 : -1;
|
||||
return val;
|
||||
}
|
||||
|
||||
return this->is_ipv4() ? memcmp(&this->addr.addr4, &that.addr.addr4, sizeof(this->addr.addr4)) :
|
||||
|
|
|
@ -34,26 +34,21 @@ struct Candidate
|
|||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] int compare(Candidate const& that) const // <=>
|
||||
[[nodiscard]] constexpr auto compare(Candidate const& that) const noexcept // <=>
|
||||
{
|
||||
// prefer pieces closer to completion
|
||||
if (n_blocks_missing != that.n_blocks_missing)
|
||||
if (auto const val = tr_compare_3way(n_blocks_missing, that.n_blocks_missing); val != 0)
|
||||
{
|
||||
return n_blocks_missing < that.n_blocks_missing ? -1 : 1;
|
||||
return val;
|
||||
}
|
||||
|
||||
// prefer higher priority
|
||||
if (priority != that.priority)
|
||||
if (auto const val = tr_compare_3way(priority, that.priority); val != 0)
|
||||
{
|
||||
return priority > that.priority ? -1 : 1;
|
||||
return -val;
|
||||
}
|
||||
|
||||
if (salt != that.salt)
|
||||
{
|
||||
return salt < that.salt ? -1 : 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return tr_compare_3way(salt, that.salt);
|
||||
}
|
||||
|
||||
bool operator<(Candidate const& that) const // less than
|
||||
|
|
|
@ -1317,22 +1317,17 @@ constexpr struct
|
|||
{
|
||||
[[nodiscard]] constexpr static int compare(peer_atom const& a, peer_atom const& b) noexcept // <=>
|
||||
{
|
||||
if (a.piece_data_time != b.piece_data_time)
|
||||
if (auto const val = tr_compare_3way(a.piece_data_time, b.piece_data_time); val != 0)
|
||||
{
|
||||
return a.piece_data_time > b.piece_data_time ? -1 : 1;
|
||||
return -val;
|
||||
}
|
||||
|
||||
if (a.fromBest != b.fromBest)
|
||||
if (auto const val = tr_compare_3way(a.fromBest, b.fromBest); val != 0)
|
||||
{
|
||||
return a.fromBest < b.fromBest ? -1 : 1;
|
||||
return val;
|
||||
}
|
||||
|
||||
if (a.num_fails != b.num_fails)
|
||||
{
|
||||
return a.num_fails < b.num_fails ? -1 : 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return tr_compare_3way(a.num_fails, b.num_fails);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool operator()(peer_atom const& a, peer_atom const& b) const noexcept
|
||||
|
@ -1775,9 +1770,10 @@ struct ChokeData
|
|||
|
||||
[[nodiscard]] constexpr auto compare(ChokeData const& that) const noexcept // <=>
|
||||
{
|
||||
if (this->rate != that.rate) // prefer higher overall speeds
|
||||
// prefer higher overall speeds
|
||||
if (auto const val = tr_compare_3way(this->rate, that.rate); val != 0)
|
||||
{
|
||||
return this->rate > that.rate ? -1 : 1;
|
||||
return -val;
|
||||
}
|
||||
|
||||
if (this->was_choked != that.was_choked) // prefer unchoked
|
||||
|
@ -1785,12 +1781,7 @@ struct ChokeData
|
|||
return this->was_choked ? 1 : -1;
|
||||
}
|
||||
|
||||
if (this->salt != that.salt) // random order
|
||||
{
|
||||
return this->salt < that.salt ? -1 : 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return tr_compare_3way(this->salt, that.salt);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr auto operator<(ChokeData const& that) const noexcept
|
||||
|
@ -2058,18 +2049,13 @@ constexpr struct
|
|||
}
|
||||
|
||||
/* the one to give us data more recently goes first */
|
||||
if (a->atom->piece_data_time != b->atom->piece_data_time)
|
||||
if (auto const val = tr_compare_3way(a->atom->piece_data_time, b->atom->piece_data_time); val != 0)
|
||||
{
|
||||
return a->atom->piece_data_time > b->atom->piece_data_time ? -1 : 1;
|
||||
return -val;
|
||||
}
|
||||
|
||||
/* the one we connected to most recently goes first */
|
||||
if (a->atom->time != b->atom->time)
|
||||
{
|
||||
return a->atom->time > b->atom->time ? -1 : 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return -tr_compare_3way(a->atom->time, b->atom->time);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool operator()(tr_peer const* a, tr_peer const* b) const // less than
|
||||
|
|
|
@ -166,6 +166,22 @@ template<typename T>
|
|||
return !std::empty(sv) && sv.back() == key;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] constexpr int tr_compare_3way(T const& left, T const& right)
|
||||
{
|
||||
if (left < right)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (right < left)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
constexpr std::string_view tr_strv_sep(std::string_view* sv, char delim)
|
||||
{
|
||||
auto pos = sv->find(delim);
|
||||
|
|
|
@ -37,24 +37,19 @@ int tr_verify_worker::Node::compare(tr_verify_worker::Node const& that) const
|
|||
// higher priority comes before lower priority
|
||||
auto const pa = tr_torrentGetPriority(torrent);
|
||||
auto const pb = tr_torrentGetPriority(that.torrent);
|
||||
if (pa != pb)
|
||||
if (auto const val = tr_compare_3way(pa, pb); val != 0)
|
||||
{
|
||||
return pa > pb ? -1 : 1;
|
||||
return -val;
|
||||
}
|
||||
|
||||
// smaller torrents come before larger ones because they verify faster
|
||||
if (current_size != that.current_size)
|
||||
if (auto const val = tr_compare_3way(current_size, that.current_size); val != 0)
|
||||
{
|
||||
return current_size < that.current_size ? -1 : 1;
|
||||
return val;
|
||||
}
|
||||
|
||||
// tertiary compare just to ensure they don't compare equal
|
||||
if (torrent->id() != that.torrent->id())
|
||||
{
|
||||
return torrent->id() < that.torrent->id() ? -1 : 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return tr_compare_3way(torrent->id(), that.torrent->id());
|
||||
}
|
||||
|
||||
bool tr_verify_worker::verify_torrent(tr_torrent* tor, std::atomic<bool> const& stop_flag)
|
||||
|
|
|
@ -183,25 +183,23 @@ TEST_F(NetTest, isGlobalUnicastAddress)
|
|||
|
||||
TEST_F(NetTest, ipCompare)
|
||||
{
|
||||
static auto constexpr IpPairs = std::array{ std::tuple{ "223.18.245.229"sv, "8.8.8.8"sv, 1 },
|
||||
static constexpr auto IpPairs = std::array{ std::tuple{ "223.18.245.229"sv, "8.8.8.8"sv, 1 },
|
||||
std::tuple{ "0.0.0.0"sv, "255.255.255.255"sv, -1 },
|
||||
std::tuple{ "8.8.8.8"sv, "8.8.8.8"sv, 0 },
|
||||
std::tuple{ "8.8.8.8"sv, "2001:0:0eab:dead::a0:abcd:4e"sv, 1 },
|
||||
std::tuple{ "8.8.8.8"sv, "2001:0:0eab:dead::a0:abcd:4e"sv, -1 },
|
||||
std::tuple{ "2001:1890:1112:1::20"sv, "2001:0:0eab:dead::a0:abcd:4e"sv, 1 },
|
||||
std::tuple{ "2001:1890:1112:1::20"sv, "2001:1890:1112:1::20"sv, 0 } };
|
||||
|
||||
for (auto const& [ip_str1, ip_str2, res] : IpPairs)
|
||||
for (auto const& [sv1, sv2, res] : IpPairs)
|
||||
{
|
||||
auto const ip1 = *tr_address::from_string(ip_str1);
|
||||
auto const ip2 = *tr_address::from_string(ip_str2);
|
||||
auto const ip1 = *tr_address::from_string(sv1);
|
||||
auto const ip2 = *tr_address::from_string(sv2);
|
||||
|
||||
std::cerr << ip_str1 << " Vs " << ip_str2 << std::endl;
|
||||
|
||||
EXPECT_EQ(ip1.compare(ip2) < 0, res < 0);
|
||||
EXPECT_EQ(ip1.compare(ip2) > 0, res > 0);
|
||||
EXPECT_EQ(ip1.compare(ip2) == 0, res == 0);
|
||||
EXPECT_EQ(ip1 < ip2, res < 0);
|
||||
EXPECT_EQ(ip1 > ip2, res > 0);
|
||||
EXPECT_EQ(ip1 == ip2, res == 0);
|
||||
EXPECT_EQ(ip1.compare(ip2) < 0, res < 0) << sv1 << ' ' << sv2;
|
||||
EXPECT_EQ(ip1.compare(ip2) > 0, res > 0) << sv1 << ' ' << sv2;
|
||||
EXPECT_EQ(ip1.compare(ip2) == 0, res == 0) << sv1 << ' ' << sv2;
|
||||
EXPECT_EQ(ip1 < ip2, res < 0) << sv1 << ' ' << sv2;
|
||||
EXPECT_EQ(ip1 > ip2, res > 0) << sv1 << ' ' << sv2;
|
||||
EXPECT_EQ(ip1 == ip2, res == 0) << sv1 << ' ' << sv2;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue