fix: ChangeFlag bitwise operations (#7613)

* unbreak ChangeFlag bitwise operations (Fix #7572)

8 bits is not enough to do bitwise comparisons on more than 8 independent
values: use std:bitset to ensure proper bitwise operations inside
ChangeFlags().

* refactor: use bitset methods and specify TR_CONSTEXPR23

---------

Co-authored-by: Yat Ho <lagoho7@gmail.com>
Co-authored-by: Charles Kerr <charles@charleskerr.com>
This commit is contained in:
niol
2025-10-15 02:38:52 +02:00
committed by GitHub
parent bf461a0f72
commit a7a5bc38ad
6 changed files with 52 additions and 46 deletions

View File

@@ -13,6 +13,8 @@
#include "TorrentFilter.h"
#include "Utils.h"
#include <libtransmission/tr-macros.h>
#include <gdkmm/pixbuf.h>
#include <glibmm/i18n.h>
#include <glibmm/main.h>
@@ -604,7 +606,7 @@ void FilterBar::Impl::update_count_label_idle()
void FilterBar::Impl::update_filter_models(Torrent::ChangeFlags changes)
{
static auto constexpr activity_flags = Torrent::ChangeFlag::ACTIVE_PEERS_DOWN | Torrent::ChangeFlag::ACTIVE_PEERS_UP |
static auto TR_CONSTEXPR23 activity_flags = Torrent::ChangeFlag::ACTIVE_PEERS_DOWN | Torrent::ChangeFlag::ACTIVE_PEERS_UP |
Torrent::ChangeFlag::ACTIVE | Torrent::ChangeFlag::ACTIVITY | Torrent::ChangeFlag::ERROR_CODE |
Torrent::ChangeFlag::FINISHED;
static auto constexpr tracker_flags = Torrent::ChangeFlag::TRACKERS;

View File

@@ -5,13 +5,16 @@
#pragma once
#include <libtransmission/tr-macros.h>
#include <bitset>
#include <initializer_list>
#include <type_traits>
// NOLINTBEGIN(bugprone-macro-parentheses, cppcoreguidelines-macro-usage)
#define DEFINE_FLAGS_OPERATORS(FlagType) \
constexpr inline Flags<FlagType> operator|(FlagType lhs, FlagType rhs) noexcept \
TR_CONSTEXPR23 inline Flags<FlagType> operator|(FlagType lhs, FlagType rhs) noexcept \
{ \
return { lhs, rhs }; \
}
@@ -23,20 +26,21 @@ class Flags
{
public:
using FlagType = T;
using ValueType = std::make_unsigned_t<std::underlying_type_t<FlagType>>;
using EnumValueType = std::make_unsigned_t<std::underlying_type_t<FlagType>>;
using BitsetType = std::bitset<static_cast<EnumValueType>(FlagType::N_FLAGS)>;
static_assert(std::is_enum_v<FlagType> && !std::is_convertible_v<FlagType, ValueType>);
static_assert(std::is_enum_v<FlagType> && !std::is_convertible_v<FlagType, BitsetType>);
public:
constexpr Flags() noexcept = default;
// NOLINTNEXTLINE(hicpp-explicit-conversions)
constexpr Flags(FlagType flag) noexcept
TR_CONSTEXPR23 Flags(FlagType flag) noexcept
{
set(flag);
}
constexpr Flags(std::initializer_list<FlagType> flags) noexcept
TR_CONSTEXPR23 Flags(std::initializer_list<FlagType> flags) noexcept
{
for (auto const flag : flags)
{
@@ -44,58 +48,53 @@ public:
}
}
[[nodiscard]] constexpr bool none() const noexcept
[[nodiscard]] TR_CONSTEXPR23 bool none() const noexcept
{
return value_ == 0;
return value_.none();
}
[[nodiscard]] constexpr bool any() const noexcept
[[nodiscard]] TR_CONSTEXPR23 bool any() const noexcept
{
return !none();
return value_.any();
}
[[nodiscard]] constexpr bool test(FlagType flag) const noexcept
[[nodiscard]] TR_CONSTEXPR23 bool test(FlagType flag) const noexcept
{
return (value_ & get_mask(flag)) != 0;
return value_.test(static_cast<EnumValueType>(flag));
}
[[nodiscard]] constexpr bool test(Flags rhs) const noexcept
[[nodiscard]] TR_CONSTEXPR23 bool test(Flags rhs) const noexcept
{
return (value_ & rhs.value_) != 0;
return (value_ & rhs.value_).any();
}
constexpr void set(FlagType flag) noexcept
TR_CONSTEXPR23 void set(FlagType flag) noexcept
{
value_ |= get_mask(flag);
value_.set(static_cast<EnumValueType>(flag));
}
[[nodiscard]] constexpr Flags operator|(Flags rhs) const noexcept
[[nodiscard]] TR_CONSTEXPR23 Flags operator|(Flags rhs) const noexcept
{
return Flags(value_ | rhs.value_);
}
constexpr Flags& operator|=(Flags rhs) noexcept
TR_CONSTEXPR23 Flags& operator|=(Flags rhs) noexcept
{
value_ |= rhs.value_;
return *this;
}
[[nodiscard]] constexpr Flags operator~() const noexcept
[[nodiscard]] TR_CONSTEXPR23 Flags operator~() const noexcept
{
return Flags(~value_);
}
private:
constexpr explicit Flags(ValueType value) noexcept
: value_(value)
constexpr explicit Flags(BitsetType value) noexcept
: value_(std::move(value))
{
}
[[nodiscard]] static constexpr ValueType get_mask(FlagType flag) noexcept
{
return ValueType{ 1 } << static_cast<ValueType>(flag);
}
private:
ValueType value_ = {};
BitsetType value_ = {};
};

View File

@@ -11,6 +11,7 @@
#include "Utils.h"
#include <libtransmission/transmission.h>
#include <libtransmission/tr-macros.h>
#include <libtransmission/utils.h>
#include <libtransmission/values.h>
@@ -362,23 +363,24 @@ void Torrent::Impl::notify_property_changes(ChangeFlags changes) const
#if GTKMM_CHECK_VERSION(4, 0, 0)
static auto constexpr properties_flags = std::array<std::pair<Property, ChangeFlags>, PropertyStore::PropertyCount - 1>({ {
{ Property::ICON, ChangeFlag::MIME_TYPE },
{ Property::NAME, ChangeFlag::NAME },
{ Property::PERCENT_DONE, ChangeFlag::PERCENT_DONE },
{ Property::SHORT_STATUS,
ChangeFlag::ACTIVE_PEERS_DOWN | ChangeFlag::ACTIVE_PEERS_UP | ChangeFlag::ACTIVITY | ChangeFlag::FINISHED |
ChangeFlag::RATIO | ChangeFlag::RECHECK_PROGRESS | ChangeFlag::SPEED_DOWN | ChangeFlag::SPEED_UP },
{ Property::LONG_PROGRESS,
ChangeFlag::ACTIVITY | ChangeFlag::ETA | ChangeFlag::LONG_PROGRESS | ChangeFlag::PERCENT_COMPLETE |
ChangeFlag::PERCENT_DONE | ChangeFlag::RATIO | ChangeFlag::TOTAL_SIZE },
{ Property::LONG_STATUS,
ChangeFlag::ACTIVE_PEERS_DOWN | ChangeFlag::ACTIVE_PEERS_UP | ChangeFlag::ACTIVITY | ChangeFlag::ERROR_CODE |
ChangeFlag::ERROR_MESSAGE | ChangeFlag::HAS_METADATA | ChangeFlag::LONG_STATUS | ChangeFlag::SPEED_DOWN |
ChangeFlag::SPEED_UP | ChangeFlag::STALLED },
{ Property::SENSITIVE, ChangeFlag::ACTIVITY },
{ Property::CSS_CLASSES, ChangeFlag::ACTIVITY | ChangeFlag::ERROR_CODE },
} });
static auto TR_CONSTEXPR23
properties_flags = std::array<std::pair<Property, ChangeFlags>, PropertyStore::PropertyCount - 1>({ {
{ Property::ICON, ChangeFlag::MIME_TYPE },
{ Property::NAME, ChangeFlag::NAME },
{ Property::PERCENT_DONE, ChangeFlag::PERCENT_DONE },
{ Property::SHORT_STATUS,
ChangeFlag::ACTIVE_PEERS_DOWN | ChangeFlag::ACTIVE_PEERS_UP | ChangeFlag::ACTIVITY | ChangeFlag::FINISHED |
ChangeFlag::RATIO | ChangeFlag::RECHECK_PROGRESS | ChangeFlag::SPEED_DOWN | ChangeFlag::SPEED_UP },
{ Property::LONG_PROGRESS,
ChangeFlag::ACTIVITY | ChangeFlag::ETA | ChangeFlag::LONG_PROGRESS | ChangeFlag::PERCENT_COMPLETE |
ChangeFlag::PERCENT_DONE | ChangeFlag::RATIO | ChangeFlag::TOTAL_SIZE },
{ Property::LONG_STATUS,
ChangeFlag::ACTIVE_PEERS_DOWN | ChangeFlag::ACTIVE_PEERS_UP | ChangeFlag::ACTIVITY | ChangeFlag::ERROR_CODE |
ChangeFlag::ERROR_MESSAGE | ChangeFlag::HAS_METADATA | ChangeFlag::LONG_STATUS | ChangeFlag::SPEED_DOWN |
ChangeFlag::SPEED_UP | ChangeFlag::STALLED },
{ Property::SENSITIVE, ChangeFlag::ACTIVITY },
{ Property::CSS_CLASSES, ChangeFlag::ACTIVITY | ChangeFlag::ERROR_CODE },
} });
auto& properties = PropertyStore::get();

View File

@@ -68,6 +68,7 @@ public:
STALLED,
TOTAL_SIZE,
TRACKERS,
N_FLAGS,
};
using ChangeFlags = Flags<ChangeFlag>;

View File

@@ -9,6 +9,7 @@
#include "Utils.h"
#include <libtransmission/transmission.h>
#include <libtransmission/tr-macros.h>
#include <array>
#include <utility>
@@ -130,7 +131,7 @@ void TorrentFilter::update(Torrent::ChangeFlags changes)
if (activity_type_ != Activity::ALL)
{
static constexpr auto ActivityFlags = std::array<std::pair<Activity, Torrent::ChangeFlags>, 7U>{ {
static auto TR_CONSTEXPR23 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 },

View File

@@ -10,6 +10,7 @@
#include "Utils.h"
#include <libtransmission/transmission.h>
#include <libtransmission/tr-macros.h>
#include <libtransmission/utils.h>
#include <algorithm>
@@ -226,7 +227,7 @@ int TorrentSorter::compare(Torrent const& lhs, Torrent const& rhs) const
void TorrentSorter::update(Torrent::ChangeFlags changes)
{
using Flag = Torrent::ChangeFlag;
static auto constexpr CompareFlags = std::array<std::pair<CompareFunc, Torrent::ChangeFlags>, 9U>{ {
static auto TR_CONSTEXPR23 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 },