build: bump to C++20 (#7191)

* build: bump to C++20

Co-authored-by: Cœur <coeur@gmx.fr>

* refactor: use designated initializers

* refactor: remove redundant SFINAE

* fix: clang-tidy warnings

* chore: comments about min compiler versions for C++20 features

* build: clang objc++ modules build errors

Co-authored-by: Dzmitry Neviadomski <nevack.d@gmail.com>

* refactor: add `TR_CONSTEXPR_VEC` and `TR_CONSTEXPR_STR`

* fix: don't use `std::rel_ops`

* chore: housekeeping

* fix: possible fix for macOS linker error

---------

Co-authored-by: Cœur <coeur@gmx.fr>
Co-authored-by: Dzmitry Neviadomski <nevack.d@gmail.com>
Co-authored-by: Charles Kerr <charles@charleskerr.com>
This commit is contained in:
Yat Ho
2026-01-21 06:27:34 +08:00
committed by GitHub
parent a3202cbe47
commit cbc5388440
48 changed files with 321 additions and 196 deletions

View File

@@ -43,7 +43,7 @@ TabWidth: 4
UseTab: Never
---
Language: Cpp
Standard: c++17
Standard: c++20
AccessModifierOffset: -4
PackConstructorInitializers: Never

View File

@@ -174,7 +174,7 @@ if(NOT CMAKE_C_STANDARD)
set(CMAKE_C_STANDARD_REQUIRED ON)
endif()
if(NOT CMAKE_CXX_STANDARD)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
endif()

View File

@@ -483,6 +483,7 @@
EDC37BCD2EE9C2AD001E2612 /* api-compat.cc in Sources */ = {isa = PBXBuildFile; fileRef = EDC37BCC2EE9C2AD001E2612 /* api-compat.cc */; };
EDC37BCE2EE9C2AD001E2612 /* api-compat.h in Headers */ = {isa = PBXBuildFile; fileRef = EDC37BCB2EE9C2AD001E2612 /* api-compat.h */; };
EDC749F92D98AE3000A12D0F /* PowerManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = EDC749F82D98AE2900A12D0F /* PowerManager.mm */; };
EDD735D62D83087400852628 /* UniformTypeIdentifiers.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EDD735D52D83087400852628 /* UniformTypeIdentifiers.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
F11545ACA7C4D7A464F703AB /* block-info.h in Headers */ = {isa = PBXBuildFile; fileRef = 6A044CBD8C049AFCBD4DB411 /* block-info.h */; settings = {ATTRIBUTES = (Project, ); }; };
F63480631E1D7274005B9E09 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F63480621E1D7274005B9E09 /* Images.xcassets */; };
/* End PBXBuildFile section */
@@ -1478,6 +1479,7 @@
EDC37BCC2EE9C2AD001E2612 /* api-compat.cc */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = "api-compat.cc"; sourceTree = "<group>"; };
EDC749F72D98ADE200A12D0F /* PowerManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PowerManager.h; sourceTree = "<group>"; };
EDC749F82D98AE2900A12D0F /* PowerManager.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = PowerManager.mm; sourceTree = "<group>"; };
EDD735D52D83087400852628 /* UniformTypeIdentifiers.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UniformTypeIdentifiers.framework; path = System/Library/Frameworks/UniformTypeIdentifiers.framework; sourceTree = SDKROOT; };
F63480621E1D7274005B9E09 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Images.xcassets; path = Images/Images.xcassets; sourceTree = "<group>"; };
/* End PBXFileReference section */
@@ -1505,6 +1507,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
EDD735D62D83087400852628 /* UniformTypeIdentifiers.framework in Frameworks */,
C87369652809984200573C90 /* UserNotifications.framework in Frameworks */,
8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */,
4D1838DD09DEC0E80047D688 /* libtransmission.a in Frameworks */,
@@ -2185,6 +2188,7 @@
A2F35BBA15C5A0A100EBF632 /* Frameworks */ = {
isa = PBXGroup;
children = (
EDD735D52D83087400852628 /* UniformTypeIdentifiers.framework */,
C87369642809984200573C90 /* UserNotifications.framework */,
55869925257074EC00F77A43 /* libcurl.tbd */,
C88771AB2803EE53005C7523 /* libiconv.tbd */,
@@ -4381,8 +4385,9 @@
LD_RUNPATH_SEARCH_PATHS = "@executable_path/../Frameworks";
OTHER_CPLUSPLUSFLAGS = (
"$(inherited)",
"-fmodules",
"-fcxx-modules",
"-fno-modules",
"-Xclang",
"-fno-cxx-modules",
);
PRODUCT_NAME = Transmission;
SYSTEM_HEADER_SEARCH_PATHS = (
@@ -4457,7 +4462,7 @@
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
CLANG_CXX_LANGUAGE_STANDARD = "c++20";
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
@@ -4644,8 +4649,9 @@
LD_RUNPATH_SEARCH_PATHS = "@executable_path/../Frameworks";
OTHER_CPLUSPLUSFLAGS = (
"$(inherited)",
"-fmodules",
"-fcxx-modules",
"-fno-modules",
"-Xclang",
"-fno-cxx-modules",
);
PRODUCT_NAME = Transmission;
SYSTEM_HEADER_SEARCH_PATHS = (
@@ -4662,7 +4668,7 @@
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
CLANG_CXX_LANGUAGE_STANDARD = "c++20";
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
@@ -4765,7 +4771,7 @@
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_CXX_LANGUAGE_STANDARD = "c++17";
CLANG_CXX_LANGUAGE_STANDARD = "c++20";
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
@@ -4849,8 +4855,9 @@
LD_RUNPATH_SEARCH_PATHS = "@executable_path/../Frameworks";
OTHER_CPLUSPLUSFLAGS = (
"$(inherited)",
"-fmodules",
"-fcxx-modules",
"-fno-modules",
"-Xclang",
"-fno-cxx-modules",
);
PRODUCT_NAME = Transmission;
SYSTEM_HEADER_SEARCH_PATHS = (
@@ -5034,8 +5041,9 @@
INSTALL_PATH = /Library/QuickLook;
OTHER_CPLUSPLUSFLAGS = (
"$(inherited)",
"-fmodules",
"-fcxx-modules",
"-fno-modules",
"-Xclang",
"-fno-cxx-modules",
);
PRODUCT_BUNDLE_IDENTIFIER = "org.m0k.transmission.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -5061,8 +5069,9 @@
INSTALL_PATH = /Library/QuickLook;
OTHER_CPLUSPLUSFLAGS = (
"$(inherited)",
"-fmodules",
"-fcxx-modules",
"-fno-modules",
"-Xclang",
"-fno-cxx-modules",
);
PRODUCT_BUNDLE_IDENTIFIER = "org.m0k.transmission.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -5088,8 +5097,9 @@
INSTALL_PATH = /Library/QuickLook;
OTHER_CPLUSPLUSFLAGS = (
"$(inherited)",
"-fmodules",
"-fcxx-modules",
"-fno-modules",
"-Xclang",
"-fno-cxx-modules",
);
PRODUCT_BUNDLE_IDENTIFIER = "org.m0k.transmission.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";

View File

@@ -53,6 +53,7 @@ template<typename... Ts>
Glib::VariantContainerBase make_variant_tuple(Ts&&... args)
{
return Glib::VariantContainerBase::create_tuple(
// TODO(c++20): use std::remove_cvref_t (P0550R2) when GCC >= 9.1
{ Glib::Variant<std::remove_cv_t<std::remove_reference_t<Ts>>>::create(std::forward<Ts>(args))... });
}

View File

@@ -40,8 +40,6 @@ Glib::Value<T>& column_value_cast(Glib::ValueBase& value, Gtk::TreeModelColumn<T
template<typename T, typename U, typename = std::enable_if_t<!std::is_floating_point_v<T>>>
void update_cache_value(T& value, U&& new_value, Torrent::ChangeFlags& changes, Torrent::ChangeFlag flag)
{
using std::rel_ops::operator!=;
if (value != new_value)
{
value = std::forward<U>(new_value);

View File

@@ -3,7 +3,15 @@ HeaderFilterRegex: .*/libtransmission/.*
# TODO: Enable `portability-template-virtual-member-function` after https://github.com/llvm/llvm-project/issues/139031 is fixed
# TODO: Enable `cppcoreguidelines-pro-bounds-pointer-arithmetic` after converting all pointers to std::span
# TODO: Enable `modernize-use-constraints` after GCC >= 10, clang 10
# TODO: Enable `modernize-use-integer-sign-comparison` (P0586R2) after GCC >= 10.1, clang >= 13
# PRs welcome to fix & re-enable any of these explicitly-disabled checks
#
# -modernize-use-ranges: GCC 10.1, clang 15
# -modernize-loop-convert (P0896R4): GCC 10.1, clang 15
# -readability-container-contains (P0458R2): GCC 9.1, clang 13
# Ref: https://gcc.gnu.org/onlinedocs/libstdc++/manual/status.html
# Ref: https://libcxx.llvm.org/Status/Cxx20.html
Checks: >
bugprone-*,
-bugprone-branch-clone,
@@ -36,12 +44,18 @@ Checks: >
-misc-no-recursion,
-misc-non-private-member-variables-in-classes,
modernize-*,
-modernize-loop-convert,
-modernize-use-constraints,
-modernize-use-designated-initializers,
-modernize-use-integer-sign-comparison,
-modernize-use-ranges,
-modernize-use-trailing-return-type,
performance-*,
-performance-move-const-arg,
portability-*,
-portability-template-virtual-member-function,
readability-*,
-readability-container-contains,
-readability-enum-initial-value,
-readability-function-cognitive-complexity,
-readability-identifier-length,

View File

@@ -82,19 +82,19 @@ public:
return std::size(trackers_);
}
[[nodiscard]] TR_CONSTEXPR20 tracker_info const& at(size_t i) const
[[nodiscard]] TR_CONSTEXPR_VEC tracker_info const& at(size_t i) const
{
return trackers_.at(i);
}
[[nodiscard]] tr_tracker_tier_t nextTier() const;
[[nodiscard]] TR_CONSTEXPR20 bool operator==(tr_announce_list const& that) const
[[nodiscard]] TR_CONSTEXPR_VEC bool operator==(tr_announce_list const& that) const
{
return trackers_ == that.trackers_;
}
[[nodiscard]] bool operator!=(tr_announce_list const& that) const
[[nodiscard]] TR_CONSTEXPR_VEC bool operator!=(tr_announce_list const& that) const
{
return trackers_ != that.trackers_;
}
@@ -113,7 +113,7 @@ public:
bool replace(tr_tracker_id_t id, std::string_view announce_url_sv);
size_t set(char const* const* announce_urls, tr_tracker_tier_t const* tiers, size_t n);
TR_CONSTEXPR20 void clear()
TR_CONSTEXPR_VEC void clear()
{
trackers_.clear();
}

View File

@@ -926,22 +926,22 @@ void on_announce_error(tr_tier* tier, char const* err, tr_announce_event e, time
auto const* const current_tracker = tier->currentTracker();
TR_ASSERT(current_tracker != nullptr);
auto req = tr_announce_request{};
req.port = announcer->session->advertisedPeerPort();
req.announce_url = current_tracker->announce_url;
req.tracker_id = current_tracker->tracker_id;
req.info_hash = tor->info_hash();
req.peer_id = tor->peer_id();
req.up = tier->byteCounts[TR_ANN_UP];
req.down = tier->byteCounts[TR_ANN_DOWN];
req.corrupt = tier->byteCounts[TR_ANN_CORRUPT];
req.leftUntilComplete = tor->has_metainfo() ? tor->total_size() - tor->has_total() : INT64_MAX;
req.event = event;
req.numwant = event == TR_ANNOUNCE_EVENT_STOPPED ? 0 : Numwant;
req.key = tor->announce_key();
req.partial_seed = tor->is_partial_seed();
req.log_name = tier->buildLogName();
return req;
return {
.event = event,
.partial_seed = tor->is_partial_seed(),
.port = announcer->session->advertisedPeerPort(),
.key = tor->announce_key(),
.numwant = event == TR_ANNOUNCE_EVENT_STOPPED ? 0 : Numwant,
.up = tier->byteCounts[TR_ANN_UP],
.down = tier->byteCounts[TR_ANN_DOWN],
.corrupt = tier->byteCounts[TR_ANN_CORRUPT],
.leftUntilComplete = tor->has_metainfo() ? tor->total_size() - tor->has_total() : INT64_MAX,
.announce_url = current_tracker->announce_url,
.tracker_id = current_tracker->tracker_id,
.peer_id = tor->peer_id(),
.info_hash = tor->info_hash(),
.log_name = tier->buildLogName(),
};
}
[[nodiscard]] tr_tier* getTier(tr_announcer_impl* announcer, tr_sha1_digest_t const& info_hash, size_t tier_id)

View File

@@ -653,6 +653,7 @@ void convert_keys(tr_variant& var, State& state)
var.visit(
[&state](auto& val)
{
// TODO(c++20): use std::remove_cvref_t (P0550R2) when GCC >= 9.1
using ValueType = std::decay_t<decltype(val)>;
if constexpr (std::is_same_v<ValueType, std::string> || std::is_same_v<ValueType, std::string_view>)

View File

@@ -14,9 +14,9 @@
struct tr_error
{
public:
tr_error() = default;
TR_CONSTEXPR_STR tr_error() = default;
tr_error(int code, std::string message)
TR_CONSTEXPR_STR tr_error(int code, std::string message)
: message_{ std::move(message) }
, code_{ code }
{
@@ -27,7 +27,7 @@ public:
return code_;
}
[[nodiscard]] TR_CONSTEXPR20 auto message() const noexcept
[[nodiscard]] TR_CONSTEXPR_STR auto message() const noexcept
{
return std::string_view{ message_ };
}
@@ -42,24 +42,24 @@ public:
return has_value();
}
void set(int code, std::string&& message)
TR_CONSTEXPR_STR void set(int code, std::string&& message)
{
code_ = code;
message_ = std::move(message);
}
void set(int code, std::string_view message)
TR_CONSTEXPR_STR void set(int code, std::string_view message)
{
code_ = code;
message_.assign(message);
}
void set(int code, char const* const message)
TR_CONSTEXPR_STR void set(int code, char const* const message)
{
set(code, std::string_view{ message != nullptr ? message : "" });
}
void prefix_message(std::string_view prefix)
TR_CONSTEXPR_STR void prefix_message(std::string_view prefix)
{
message_.insert(std::begin(message_), std::begin(prefix), std::end(prefix));
}

View File

@@ -45,7 +45,7 @@ public:
explicit tr_file_piece_map(tr_torrent_metainfo const& tm);
tr_file_piece_map(tr_block_info const& block_info, uint64_t const* file_sizes, size_t n_files);
[[nodiscard]] TR_CONSTEXPR20 piece_span_t piece_span_for_file(tr_file_index_t const file) const noexcept
[[nodiscard]] TR_CONSTEXPR_VEC piece_span_t piece_span_for_file(tr_file_index_t const file) const noexcept
{
return file_pieces_[file];
}
@@ -59,7 +59,7 @@ public:
return std::size(file_pieces_);
}
[[nodiscard]] TR_CONSTEXPR20 auto byte_span_for_file(tr_file_index_t const file) const
[[nodiscard]] TR_CONSTEXPR_VEC auto byte_span_for_file(tr_file_index_t const file) const
{
auto const& span = file_bytes_[file];
return tr_byte_span_t{ span.begin, span.end };
@@ -84,7 +84,7 @@ private:
class tr_file_priorities
{
public:
TR_CONSTEXPR20 explicit tr_file_priorities(tr_file_piece_map const* fpm) noexcept
TR_CONSTEXPR_VEC explicit tr_file_priorities(tr_file_piece_map const* fpm) noexcept
: fpm_{ fpm }
{
}

View File

@@ -40,7 +40,7 @@ public:
return std::size(webseed_urls_);
}
[[nodiscard]] TR_CONSTEXPR20 auto const& webseed(size_t i) const
[[nodiscard]] TR_CONSTEXPR_VEC auto const& webseed(size_t i) const
{
return webseed_urls_.at(i);
}

View File

@@ -127,7 +127,7 @@ public:
return files_.file_count();
}
[[nodiscard]] TR_CONSTEXPR20 auto file_size(tr_file_index_t i) const noexcept
[[nodiscard]] TR_CONSTEXPR_VEC auto file_size(tr_file_index_t i) const noexcept
{
return files_.file_size(i);
}
@@ -142,7 +142,7 @@ public:
return tr_sys_path_basename(top_);
}
[[nodiscard]] auto const& path(tr_file_index_t i) const noexcept
[[nodiscard]] TR_CONSTEXPR_VEC auto const& path(tr_file_index_t i) const noexcept
{
return files_.path(i);
}

View File

@@ -665,7 +665,7 @@ std::optional<tr_address> tr_address::from_ipv4_mapped() const noexcept
// --- tr_socket_addrses
std::string tr_socket_address::display_name(tr_address const& address, tr_port port) noexcept
std::string tr_socket_address::display_name(tr_address const& address, tr_port port)
{
return fmt::format(fmt::runtime(address.is_ipv6() ? "[{:s}]:{:d}" : "{:s}:{:d}"), address.display_name(), port.host());
}

View File

@@ -427,9 +427,9 @@ struct tr_address
switch (type)
{
case TR_AF_INET:
return tr_address{ TR_AF_INET, { { { { INADDR_ANY } } } } };
return tr_address{ TR_AF_INET, { .addr4 = { INADDR_ANY } } };
case TR_AF_INET6:
return tr_address{ TR_AF_INET6, { IN6ADDR_ANY_INIT } };
return tr_address{ TR_AF_INET6, { .addr6 = IN6ADDR_ANY_INIT } };
default:
TR_ASSERT_MSG(false, "invalid type");
return tr_address{};
@@ -472,8 +472,8 @@ struct tr_socket_address
return port_;
}
[[nodiscard]] static std::string display_name(tr_address const& address, tr_port port) noexcept;
[[nodiscard]] auto display_name() const noexcept
[[nodiscard]] static std::string display_name(tr_address const& address, tr_port port);
[[nodiscard]] auto display_name() const
{
return display_name(address_, port_);
}

View File

@@ -23,7 +23,7 @@
namespace
{
[[nodiscard]] std::vector<tr_block_span_t> make_spans(small::vector<tr_block_index_t> const& blocks)
[[nodiscard]] TR_CONSTEXPR_VEC std::vector<tr_block_span_t> make_spans(small::vector<tr_block_index_t> const& blocks)
{
if (std::empty(blocks))
{
@@ -34,7 +34,7 @@ namespace
spans.reserve(std::size(blocks));
for (auto span_begin = std::begin(blocks), end = std::end(blocks); span_begin != end;)
{
static auto constexpr NotAdjacent = [](tr_block_index_t const lhs, tr_block_index_t const rhs)
auto constexpr NotAdjacent = [](tr_block_index_t const lhs, tr_block_index_t const rhs)
{
return lhs + 1U != rhs;
};
@@ -218,7 +218,7 @@ private:
}
}
TR_CONSTEXPR20 void reset_blocks_bitfield(tr_bitfield const& requests)
TR_CONSTEXPR_VEC void reset_blocks_bitfield(tr_bitfield const& requests)
{
for (auto& candidate : candidates_)
{
@@ -253,7 +253,7 @@ private:
// ---
TR_CONSTEXPR20 void peer_disconnect(tr_bitfield const& have, tr_bitfield const& requests)
TR_CONSTEXPR_VEC void peer_disconnect(tr_bitfield const& have, tr_bitfield const& requests)
{
dec_replication_bitfield(have);
reset_blocks_bitfield(requests);

View File

@@ -15,7 +15,6 @@
#include <memory>
#include <optional>
#include <tuple> // std::tie
#include <type_traits>
#include <unordered_map>
#include <utility>
#include <vector>
@@ -76,11 +75,11 @@ private:
}
return TorrentInfo{
tor->info_hash(), // info_hash
tor->peer_id(), // client_peer_id
tor->id(), // id
tor->is_done(), // is_done
tor->is_running() // is_running
.info_hash = tor->info_hash(),
.client_peer_id = tor->peer_id(),
.id = tor->id(),
.is_done = tor->is_done(),
.is_running = tor->is_running(),
};
}
@@ -308,8 +307,8 @@ void tr_peer_info::update_canonical_priority()
// FFFF:FFFF:FFFF:FFFF:5555:5555:5555:5555, etc...
static auto constexpr MaskStartBaseOffset = std::array{ 2U, 6U };
auto const base_idx = MaskStartBaseOffset[type];
auto const mismatch_idx = std::mismatch(first, second, second).first - first;
for (auto i = mismatch_idx >= base_idx ? mismatch_idx + 1 : base_idx; i < address_size; ++i)
auto const mismatch_idx = static_cast<size_t>(std::mismatch(first, second, second).first - first);
for (auto i = mismatch_idx >= base_idx ? mismatch_idx + 1U : base_idx; i < address_size; ++i)
{
first[i] &= std::byte{ 0x55 };
second[i] &= std::byte{ 0x55 };
@@ -354,8 +353,7 @@ constexpr struct
}
template<typename T>
[[nodiscard]] constexpr std::enable_if_t<std::is_same_v<std::decay_t<decltype(*std::declval<T>())>, tr_peer_info>, bool>
operator()(T const& a, T const& b) const noexcept
[[nodiscard]] constexpr bool operator()(T const& a, T const& b) const noexcept
{
return compare(*a, *b) < 0;
}
@@ -2460,9 +2458,7 @@ struct ComparePeerInfo
}
template<typename T>
[[nodiscard]] std::enable_if_t<std::is_same_v<std::decay_t<decltype(*std::declval<T>())>, tr_peer_info>, bool> operator()(
T const& a,
T const& b) const noexcept
[[nodiscard]] bool operator()(T const& a, T const& b) const noexcept
{
return compare(*a, *b) < 0;
}

View File

@@ -2606,6 +2606,9 @@ using SessionAccessors = std::pair<SessionGetter, SessionSetter>;
[](tr_session const& /*src*/) -> tr_variant { return tr_variant::unmanaged_string(LONG_VERSION_STRING); },
nullptr);
// `row` could have been replaced by structured bindings,
// but it's not available until clang 16
// https://github.com/llvm/llvm-project/commit/44f2baa3804a62ca793f0ff3e43aa71cea91a795
for (auto const& row : tr_session::Scripts)
{
auto const script = row.script;

View File

@@ -31,6 +31,7 @@ namespace detail
// NOLINTBEGIN(readability-identifier-naming)
// use std-style naming for these traits
// TODO(c++20): use std::remove_cvref_t (P0550R2) when GCC >= 9.1
template<typename T>
using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>;

View File

@@ -77,7 +77,7 @@ void tr_session_alt_speeds::set_active(bool active, ChangeReason reason, bool fo
}
}
[[nodiscard]] bool tr_session_alt_speeds::is_active_minute(time_t time) const noexcept
[[nodiscard]] bool tr_session_alt_speeds::is_active_minute(time_t time) const
{
auto const tm = *std::localtime(&time);

View File

@@ -189,7 +189,7 @@ private:
void set_active(bool active, ChangeReason reason, bool force);
// whether `time` hits in one of the `minutes_` that is true
[[nodiscard]] bool is_active_minute(time_t time) const noexcept;
[[nodiscard]] bool is_active_minute(time_t time) const;
static int constexpr MinutesPerHour = 60;
static int constexpr MinutesPerDay = MinutesPerHour * 24;

View File

@@ -110,13 +110,14 @@ tr_session_id::session_id_t tr_session_id::make_session_id()
return session_id;
}
// NOLINTNEXTLINE(bugprone-exception-escape)
tr_session_id::~tr_session_id()
{
destroy_lockfile(current_lock_file_, std::data(current_value_));
destroy_lockfile(previous_lock_file_, std::data(previous_value_));
}
bool tr_session_id::is_local(std::string_view session_id) noexcept
bool tr_session_id::is_local(std::string_view session_id)
{
if (std::empty(session_id))
{
@@ -158,7 +159,7 @@ bool tr_session_id::is_local(std::string_view session_id) noexcept
return is_local;
}
std::string_view tr_session_id::sv() const noexcept
std::string_view tr_session_id::sv() const
{
if (auto const now = get_current_time_(); now >= expires_at_)
{
@@ -174,7 +175,7 @@ std::string_view tr_session_id::sv() const noexcept
return std::string_view{ std::data(current_value_), std::size(current_value_) - 1 };
}
char const* tr_session_id::c_str() const noexcept
char const* tr_session_id::c_str() const
{
return std::data(sv()); // current_value_ is zero-terminated
}

View File

@@ -36,11 +36,11 @@ public:
* relative paths to absolute before passing through RPC, or presenting
* different UI for local and remote sessions.
*/
[[nodiscard]] static bool is_local(std::string_view session_id) noexcept;
[[nodiscard]] static bool is_local(std::string_view session_id);
// current session identifier
[[nodiscard]] std::string_view sv() const noexcept;
[[nodiscard]] char const* c_str() const noexcept;
[[nodiscard]] std::string_view sv() const;
[[nodiscard]] char const* c_str() const;
private:
static auto constexpr SessionIdSize = size_t{ 48 };

View File

@@ -555,7 +555,7 @@ public:
explicit tr_session(std::string_view config_dir, tr_variant const& settings_dict);
[[nodiscard]] std::string_view sessionId() const noexcept
[[nodiscard]] std::string_view sessionId() const
{
return session_id_.sv();
}

View File

@@ -40,7 +40,7 @@ public:
return std::size(files_);
}
[[nodiscard]] TR_CONSTEXPR20 uint64_t file_size(tr_file_index_t file_index) const
[[nodiscard]] TR_CONSTEXPR_VEC uint64_t file_size(tr_file_index_t file_index) const
{
return files_.at(file_index).size_;
}
@@ -50,7 +50,7 @@ public:
return total_size_;
}
[[nodiscard]] TR_CONSTEXPR20 std::string const& path(tr_file_index_t file_index) const
[[nodiscard]] TR_CONSTEXPR_VEC std::string const& path(tr_file_index_t file_index) const
{
return files_.at(file_index).path_;
}
@@ -71,17 +71,17 @@ public:
}
}
void reserve(size_t n_files)
TR_CONSTEXPR_VEC void reserve(size_t n_files)
{
files_.reserve(n_files);
}
void shrink_to_fit()
TR_CONSTEXPR_VEC void shrink_to_fit()
{
files_.shrink_to_fit();
}
TR_CONSTEXPR20 void clear() noexcept
TR_CONSTEXPR_VEC void clear() noexcept
{
files_.clear();
total_size_ = uint64_t{};
@@ -102,7 +102,7 @@ public:
return ret;
}
tr_file_index_t add(std::string_view path, uint64_t file_size)
TR_CONSTEXPR_VEC tr_file_index_t add(std::string_view path, uint64_t file_size)
{
auto const ret = static_cast<tr_file_index_t>(std::size(files_));
files_.emplace_back(path, file_size);
@@ -176,7 +176,7 @@ private:
struct file_t
{
public:
void set_path(std::string_view subpath)
TR_CONSTEXPR_STR void set_path(std::string_view subpath)
{
if (path_ != subpath)
{
@@ -185,7 +185,7 @@ private:
}
}
file_t(std::string_view path, uint64_t size)
TR_CONSTEXPR_STR file_t(std::string_view path, uint64_t size)
: path_{ path }
, size_{ size }
{

View File

@@ -48,7 +48,7 @@ public:
return metadata_;
}
[[nodiscard]] TR_CONSTEXPR20 std::string_view log_name() const noexcept
[[nodiscard]] TR_CONSTEXPR_STR std::string_view log_name() const noexcept
{
return log_name_;
}

View File

@@ -46,11 +46,11 @@ public:
{
return files().file_count();
}
[[nodiscard]] TR_CONSTEXPR20 auto file_size(tr_file_index_t i) const
[[nodiscard]] TR_CONSTEXPR_VEC auto file_size(tr_file_index_t i) const
{
return files().file_size(i);
}
[[nodiscard]] TR_CONSTEXPR20 auto const& file_subpath(tr_file_index_t i) const
[[nodiscard]] TR_CONSTEXPR_VEC auto const& file_subpath(tr_file_index_t i) const
{
return files().path(i);
}
@@ -132,7 +132,7 @@ public:
return is_private_;
}
[[nodiscard]] TR_CONSTEXPR20 tr_sha1_digest_t const& piece_hash(tr_piece_index_t piece) const
[[nodiscard]] TR_CONSTEXPR_VEC tr_sha1_digest_t const& piece_hash(tr_piece_index_t piece) const
{
return pieces_[piece];
}

View File

@@ -1434,11 +1434,29 @@ tr_file_view tr_torrentFile(tr_torrent const* tor, tr_file_index_t file)
if (tor->is_seed() || length == 0)
{
return { subpath.c_str(), length, length, 1.0, begin, end, priority, wanted };
return {
.name = subpath.c_str(),
.have = length,
.length = length,
.progress = 1.0,
.beginPiece = begin,
.endPiece = end,
.priority = priority,
.wanted = wanted,
};
}
auto const have = tor->completion_.count_has_bytes_in_span(tor->byte_span_for_file(file));
return { subpath.c_str(), have, length, have >= length ? 1.0 : have / double(length), begin, end, priority, wanted };
return {
.name = subpath.c_str(),
.have = have,
.length = length,
.progress = have >= length ? 1.0 : have / double(length),
.beginPiece = begin,
.endPiece = end,
.priority = priority,
.wanted = wanted,
};
}
size_t tr_torrentFileCount(tr_torrent const* torrent)
@@ -1473,21 +1491,19 @@ size_t tr_torrentTrackerCount(tr_torrent const* tor)
tr_torrent_view tr_torrentView(tr_torrent const* tor)
{
TR_ASSERT(tr_isTorrent(tor));
auto ret = tr_torrent_view{};
ret.name = tor->name().c_str();
ret.hash_string = tor->info_hash_string().c_str();
ret.comment = tor->comment().c_str();
ret.creator = tor->creator().c_str();
ret.source = tor->source().c_str();
ret.total_size = tor->total_size();
ret.date_created = tor->date_created();
ret.piece_size = tor->piece_size();
ret.n_pieces = tor->piece_count();
ret.is_private = tor->is_private();
ret.is_folder = tor->file_count() > 1 || (tor->file_count() == 1 && tr_strv_contains(tor->file_subpath(0), '/'));
return ret;
return {
.name = tor->name().c_str(),
.hash_string = tor->info_hash_string().c_str(),
.comment = tor->comment().c_str(),
.creator = tor->creator().c_str(),
.source = tor->source().c_str(),
.total_size = tor->total_size(),
.date_created = tor->date_created(),
.piece_size = tor->piece_size(),
.n_pieces = tor->piece_count(),
.is_private = tor->is_private(),
.is_folder = tor->file_count() > 1 || (tor->file_count() == 1 && tr_strv_contains(tor->file_subpath(0), '/')),
};
}
std::string tr_torrentFilename(tr_torrent const* tor)

View File

@@ -480,12 +480,12 @@ struct tr_torrent
return metainfo_.file_count();
}
[[nodiscard]] TR_CONSTEXPR20 auto const& file_subpath(tr_file_index_t i) const
[[nodiscard]] TR_CONSTEXPR_VEC auto const& file_subpath(tr_file_index_t i) const
{
return metainfo_.file_subpath(i);
}
[[nodiscard]] TR_CONSTEXPR20 auto file_size(tr_file_index_t i) const
[[nodiscard]] TR_CONSTEXPR_VEC auto file_size(tr_file_index_t i) const
{
return metainfo_.file_size(i);
}
@@ -517,7 +517,7 @@ struct tr_torrent
return metainfo_.webseed_count();
}
[[nodiscard]] TR_CONSTEXPR20 auto const& webseed(size_t i) const
[[nodiscard]] TR_CONSTEXPR_VEC auto const& webseed(size_t i) const
{
return metainfo_.webseed(i);
}
@@ -1272,7 +1272,7 @@ private:
// must be called after the torrent's announce list changes.
void on_announce_list_changed();
[[nodiscard]] TR_CONSTEXPR20 tr_byte_span_t byte_span_for_file(tr_file_index_t file) const
[[nodiscard]] TR_CONSTEXPR_VEC tr_byte_span_t byte_span_for_file(tr_file_index_t file) const
{
return fpm_.byte_span_for_file(file);
}

View File

@@ -111,7 +111,7 @@ public:
return {};
}
if (auto const n_sent = send(sockfd, reinterpret_cast<char const*>(data()), n_bytes, 0); n_sent >= 0U)
if (auto const n_sent = send(sockfd, reinterpret_cast<char const*>(data()), n_bytes, 0); n_sent >= 0)
{
drain(n_sent);
return n_sent;

View File

@@ -17,6 +17,18 @@
#define TR_CONSTEXPR20
#endif
#if __cpp_lib_constexpr_vector >= 201907L
#define TR_CONSTEXPR_VEC constexpr
#else
#define TR_CONSTEXPR_VEC
#endif
#if __cpp_lib_constexpr_string >= 201907L
#define TR_CONSTEXPR_STR constexpr
#else
#define TR_CONSTEXPR_STR
#endif
#if __cplusplus >= 202302L // _MSVC_LANG value for C++23 not available yet
#define TR_CONSTEXPR23 constexpr
#else

View File

@@ -114,33 +114,41 @@ template<typename T>
*/
[[nodiscard]] bool tr_wildmat(char const* text, char const* pattern);
// c++23 (P1679R3), GCC 11.1, clang 12
template<typename T>
[[nodiscard]] constexpr bool tr_strv_contains(std::string_view sv, T key) noexcept // c++23
[[nodiscard]] constexpr bool tr_strv_contains(std::string_view sv, T key) noexcept
{
return sv.find(key) != std::string_view::npos;
}
[[nodiscard]] constexpr bool tr_strv_starts_with(std::string_view sv, char key) // c++20
// c++20 (P0457R2), GCC 9.1, clang 6
[[nodiscard]] constexpr bool tr_strv_starts_with(std::string_view sv, char key)
{
return !std::empty(sv) && sv.front() == key;
}
[[nodiscard]] constexpr bool tr_strv_starts_with(std::string_view sv, std::string_view key) // c++20
// c++20 (P0457R2), GCC 9.1, clang 6
[[nodiscard]] constexpr bool tr_strv_starts_with(std::string_view sv, std::string_view key)
{
return std::size(key) <= std::size(sv) && sv.substr(0, std::size(key)) == key;
}
[[nodiscard]] constexpr bool tr_strv_starts_with(std::wstring_view sv, std::wstring_view key) // c++20
// c++20 (P0457R2), GCC 9.1, clang 6
[[nodiscard]] constexpr bool tr_strv_starts_with(
std::wstring_view sv,
std::wstring_view key) // c++20 (P0457R2), GCC 9.1, clang 6
{
return std::size(key) <= std::size(sv) && sv.substr(0, std::size(key)) == key;
}
[[nodiscard]] constexpr bool tr_strv_ends_with(std::string_view sv, std::string_view key) // c++20
// c++20 (P0457R2), GCC 9.1, clang 6
[[nodiscard]] constexpr bool tr_strv_ends_with(std::string_view sv, std::string_view key)
{
return std::size(key) <= std::size(sv) && sv.substr(std::size(sv) - std::size(key)) == key;
}
[[nodiscard]] constexpr bool tr_strv_ends_with(std::string_view sv, char key) // c++20
// c++20 (P0457R2), GCC 9.1, clang 6
[[nodiscard]] constexpr bool tr_strv_ends_with(std::string_view sv, char key)
{
return !std::empty(sv) && sv.back() == key;
}

View File

@@ -48,7 +48,7 @@ struct Config
struct Units
{
template<typename... Names> // NOLINTNEXTLINE(google-explicit-constructor, cppcoreguidelines-pro-type-member-init)
Units(Base base, Names... names) noexcept
Units(Base base, Names... names)
{
set_base(base);
@@ -204,7 +204,7 @@ public:
return compare(that) >= 0;
}
std::string_view to_string(char* buf, size_t buflen) const noexcept
std::string_view to_string(char* buf, size_t buflen) const
{
auto idx = size_t{ 0 };
auto val = 1.0 * base_quantity_;

View File

@@ -192,6 +192,7 @@ tr_variant& tr_variant::merge(tr_variant const& that)
that.visit(
[this](auto const& value)
{
// TODO(c++20): use std::remove_cvref_t (P0550R2) when GCC >= 9.1
using ValueType = std::decay_t<decltype(value)>;
if constexpr (

View File

@@ -100,9 +100,9 @@ public:
return Vector::const_iterator{ const_cast<Map*>(this)->find(key) };
}
[[nodiscard]] auto contains(tr_quark const key) const noexcept
[[nodiscard]] TR_CONSTEXPR20 auto contains(tr_quark const key) const noexcept
{
return find(key) != end(); // NOLINT(readability-container-contains)
return find(key) != end();
}
[[nodiscard]] TR_CONSTEXPR20 auto size() const noexcept
@@ -131,7 +131,7 @@ public:
return 0U;
}
bool replace_key(tr_quark const old_key, tr_quark const new_key)
TR_CONSTEXPR20 bool replace_key(tr_quark const old_key, tr_quark const new_key)
{
if (contains(new_key))
{
@@ -309,6 +309,7 @@ public:
template<typename Val>
[[nodiscard]] constexpr auto* get_if() noexcept
{
// TODO(c++20): use std::remove_cvref_t (P0550R2) when GCC >= 9.1
static_assert(
!std::is_same_v<std::decay_t<Val>, std::string> && !std::is_same_v<std::decay_t<Val>, std::string_view>,
"not supported -- use value_if<std::string_view>() instead.");
@@ -318,6 +319,7 @@ public:
template<typename Val>
[[nodiscard]] constexpr auto const* get_if() const noexcept
{
// TODO(c++20): use std::remove_cvref_t (P0550R2) when GCC >= 9.1
static_assert(
!std::is_same_v<std::decay_t<Val>, std::string> && !std::is_same_v<std::decay_t<Val>, std::string_view>,
"not supported -- use value_if<std::string_view>() instead.");

View File

@@ -9,8 +9,10 @@ find_program(CODESIGN_EXECUTABLE codesign REQUIRED)
set(MAC_BUNDLE_NAME Transmission)
add_compile_options(
$<$<COMPILE_LANGUAGE:C,CXX>:-fmodules>
$<$<COMPILE_LANGUAGE:C,CXX>:-fcxx-modules>
$<$<COMPILE_LANGUAGE:C>:-fmodules>
# https://github.com/llvm/llvm-project/issues/57432
"$<$<COMPILE_LANG_AND_ID:CXX,AppleClang,Clang>:-fno-modules;-Xclang;-fno-cxx-modules>"
# equivalent of XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC YES for this directory
$<$<COMPILE_LANGUAGE:C,CXX>:-fobjc-arc>
@@ -415,6 +417,7 @@ target_link_libraries(${TR_NAME}-mac
"-framework Quartz"
"-framework Security"
"-weak_framework Sparkle"
"-weak_framework UniformTypeIdentifiers"
"-weak_framework UserNotifications")
if(NOT CMAKE_GENERATOR STREQUAL Xcode)

View File

@@ -2,10 +2,17 @@
// It may be used under the MIT (SPDX: MIT) license.
// License text can be found in the licenses/ folder.
#if __has_feature(modules)
@import Carbon;
@import UserNotifications;
@import Sparkle;
#else
#import <Carbon/Carbon.h>
#import <UserNotifications/UserNotifications.h>
#import <Sparkle/Sparkle.h>
#endif
#include <atomic> /* atomic, atomic_fetch_add_explicit, memory_order_relaxed */

View File

@@ -2,7 +2,11 @@
// It may be used under the MIT (SPDX: MIT) license.
// License text can be found in the licenses/ folder.
#if __has_feature(modules)
@import AppKit;
#else
#import <AppKit/AppKit.h>
#endif
#import "ExpandedPathToIconTransformer.h"

View File

@@ -2,7 +2,11 @@
// It may be used under the MIT (SPDX: MIT) license.
// License text can be found in the licenses/ folder.
#if __has_feature(modules)
@import AppKit;
#else
#import <AppKit/AppKit.h>
#endif
#import "FileListNode.h"

View File

@@ -99,9 +99,11 @@ target_link_libraries(${TR_NAME}-mac-qlappex
PRIVATE
${TR_NAME}
"-framework Foundation"
"-framework AppKit"
"-framework CoreFoundation"
"-framework CoreServices"
"-framework Quartz"
"-framework UniformTypeIdentifiers"
"-framework QuickLook")
install(

View File

@@ -1,6 +1,12 @@
#if __has_feature(modules)
@import AppKit;
@import CoreFoundation;
@import QuickLook;
#else
#import <AppKit/AppKit.h>
#import <CoreFoundation/CFPlugInCOM.h>
#import <QuickLook/QuickLook.h>
#endif
#include <string>
#include <unordered_map>

View File

@@ -1,5 +1,11 @@
#if __has_feature(modules)
@import CoreFoundation;
@import QuickLook;
#else
#import <CoreFoundation/CoreFoundation.h>
#import <CoreFoundation/CFPlugInCOM.h>
#import <QuickLook/QuickLook.h>
#endif
QL_EXTERN_C_BEGIN
OSStatus GenerateThumbnailForURL(void* thisInterface, QLThumbnailRequestRef thumbnail, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options, CGSize maxSize);

View File

@@ -2,8 +2,13 @@
// It may be used under the MIT (SPDX: MIT) license.
// License text can be found in the licenses/ folder.
#if __has_feature(modules)
@import ObjectiveC;
@import AppKit;
#else
#import <objc/runtime.h>
#import <AppKit/AppKit.h>
#endif
#import "NSStringAdditions.h"
// Development-only proxy when app is not signed for running Sparkle

View File

@@ -2,7 +2,11 @@
// It may be used under the MIT (SPDX: MIT) license.
// License text can be found in the licenses/ folder.
#if __has_feature(modules)
@import AppKit;
#else
#import <AppKit/AppKit.h>
#endif
#include <libtransmission/transmission.h>

View File

@@ -3,6 +3,11 @@ HeaderFilterRegex: .*/tests/libtransmission/.*
# Many of these checks are disabled only because the code hasn't been
# cleaned up yet. Pull requests welcomed.
#
# -modernize-loop-convert (P0896R4): GCC 10.1, clang 15
# -readability-container-contains (P0458R2): GCC 9.1, clang 13
# Ref: https://gcc.gnu.org/onlinedocs/libstdc++/manual/status.html
# Ref: https://libcxx.llvm.org/Status/Cxx20.html
Checks: >
bugprone-*,
-bugprone-easily-swappable-parameters,
@@ -30,9 +35,13 @@ Checks: >
-misc-no-recursion,
-misc-non-private-member-variables-in-classes,
modernize-*,
-modernize-loop-convert,
-modernize-use-designated-initializers,
-modernize-use-ranges,
-modernize-use-trailing-return-type,
performance-*,
readability-*,
-readability-container-contains,
-readability-enum-initial-value,
-readability-function-cognitive-complexity,
-readability-identifier-length,

View File

@@ -635,35 +635,38 @@ TEST_F(AnnouncerUdpTest, canAnnounceIPv4)
{ tr_address::from_string("192.168.1.3"sv).value_or(tr_address{}), tr_port::from_host(2022) },
} };
auto request = tr_announce_request{};
request.event = TR_ANNOUNCE_EVENT_STARTED;
request.port = tr_port::from_host(80);
request.key = 0xCAFE;
request.numwant = 20;
request.up = 1;
request.down = 2;
request.corrupt = 3;
request.leftUntilComplete = 100;
request.announce_url = "https://127.0.0.1/announce"sv;
request.tracker_id = "fnord"s;
request.peer_id = tr_peerIdInit();
request.info_hash = tr_rand_obj<tr_sha1_digest_t>();
auto const request = tr_announce_request{
.event = TR_ANNOUNCE_EVENT_STARTED,
.port = tr_port::from_host(80),
.key = 0xCAFE,
.numwant = 20,
.up = 1,
.down = 2,
.corrupt = 3,
.leftUntilComplete = 100,
.announce_url = tr_interned_string{ "https://127.0.0.1/announce"sv },
.tracker_id = "fnord"s,
.peer_id = tr_peerIdInit(),
.info_hash = tr_rand_obj<tr_sha1_digest_t>(),
.log_name = {},
};
auto expected_response = tr_announce_response{};
expected_response.info_hash = request.info_hash;
expected_response.did_connect = true;
expected_response.did_timeout = false;
expected_response.interval = Interval;
expected_response.min_interval = 0; // not specified in UDP announce
expected_response.seeders = Seeders;
expected_response.leechers = Leechers;
expected_response.downloads = std::nullopt; // not specified in UDP announce
expected_response.pex = std::vector<tr_pex>{ tr_pex{ addresses[0] }, tr_pex{ addresses[1] }, tr_pex{ addresses[2] } };
expected_response.pex6 = {};
expected_response.errmsg = {};
expected_response.warning = {};
expected_response.tracker_id = {}; // not specified in UDP announce
expected_response.external_ip = {};
auto const expected_response = tr_announce_response{
.info_hash = request.info_hash,
.did_connect = true,
.did_timeout = false,
.interval = Interval,
.min_interval = 0, // not specified in UDP announce
.seeders = Seeders,
.leechers = Leechers,
.downloads = std::nullopt, // not specified in UDP announce
.pex = std::vector{ tr_pex{ addresses[0] }, tr_pex{ addresses[1] }, tr_pex{ addresses[2] } },
.pex6 = {},
.errmsg = {},
.warning = {},
.tracker_id = {}, // not specified in UDP announce
.external_ip = {},
};
// build the announcer
auto mediator = MockMediator{};
@@ -718,35 +721,38 @@ TEST_F(AnnouncerUdpTest, canAnnounceIPv6)
{ tr_address::from_string("fd12:3456:789a:1::3"sv).value_or(tr_address{}), tr_port::from_host(2022) },
} };
auto request = tr_announce_request{};
request.event = TR_ANNOUNCE_EVENT_STARTED;
request.port = tr_port::from_host(80);
request.key = 0xCAFE;
request.numwant = 20;
request.up = 1;
request.down = 2;
request.corrupt = 3;
request.leftUntilComplete = 100;
request.announce_url = "https://[::1]/announce"sv;
request.tracker_id = "fnord"s;
request.peer_id = tr_peerIdInit();
request.info_hash = tr_rand_obj<tr_sha1_digest_t>();
auto const request = tr_announce_request{
.event = TR_ANNOUNCE_EVENT_STARTED,
.port = tr_port::from_host(80),
.key = 0xCAFE,
.numwant = 20,
.up = 1,
.down = 2,
.corrupt = 3,
.leftUntilComplete = 100,
.announce_url = tr_interned_string{ "https://[::1]/announce"sv },
.tracker_id = "fnord"s,
.peer_id = tr_peerIdInit(),
.info_hash = tr_rand_obj<tr_sha1_digest_t>(),
.log_name = {},
};
auto expected_response = tr_announce_response{};
expected_response.info_hash = request.info_hash;
expected_response.did_connect = true;
expected_response.did_timeout = false;
expected_response.interval = Interval;
expected_response.min_interval = 0; // not specified in UDP announce
expected_response.seeders = Seeders;
expected_response.leechers = Leechers;
expected_response.downloads = std::nullopt; // not specified in UDP announce
expected_response.pex = {};
expected_response.pex6 = std::vector<tr_pex>{ tr_pex{ addresses[0] }, tr_pex{ addresses[1] }, tr_pex{ addresses[2] } };
expected_response.errmsg = {};
expected_response.warning = {};
expected_response.tracker_id = {}; // not specified in UDP announce
expected_response.external_ip = {};
auto const expected_response = tr_announce_response{
.info_hash = request.info_hash,
.did_connect = true,
.did_timeout = false,
.interval = Interval,
.min_interval = 0, // not specified in UDP announce
.seeders = Seeders,
.leechers = Leechers,
.downloads = std::nullopt, // not specified in UDP announce
.pex = {},
.pex6 = std::vector{ tr_pex{ addresses[0] }, tr_pex{ addresses[1] }, tr_pex{ addresses[2] } },
.errmsg = {},
.warning = {},
.tracker_id = {}, // not specified in UDP announce
.external_ip = {},
};
// build the announcer
auto mediator = MockMediator{};

View File

@@ -147,16 +147,20 @@ public:
static auto constexpr PlaintextProtocolName = "\023BitTorrent protocol"sv;
tr_socket_address const DefaultPeerSockAddr{ *tr_address::from_string("127.0.0.1"sv), tr_port::from_host(8080) };
tr_handshake::Mediator::TorrentInfo const TorrentWeAreSeeding{ tr_sha1::digest("abcde"sv),
tr_peerIdInit(),
tr_torrent_id_t{ 100 },
true /*is_done*/,
true /*is_running*/ };
tr_handshake::Mediator::TorrentInfo const UbuntuTorrent{ *tr_sha1_from_string("2c6b6858d61da9543d4231a71db4b1c9264b0685"sv),
tr_peerIdInit(),
tr_torrent_id_t{ 101 },
false /*is_done*/,
true /*is_running*/ };
tr_handshake::Mediator::TorrentInfo const TorrentWeAreSeeding{
.info_hash = tr_sha1::digest("abcde"sv),
.client_peer_id = tr_peerIdInit(),
.id = tr_torrent_id_t{ 100 },
.is_done = true,
.is_running = true,
};
tr_handshake::Mediator::TorrentInfo const UbuntuTorrent{
.info_hash = *tr_sha1_from_string("2c6b6858d61da9543d4231a71db4b1c9264b0685"sv),
.client_peer_id = tr_peerIdInit(),
.id = tr_torrent_id_t{ 101 },
.is_done = false,
.is_running = true,
};
auto createIncomingIo(tr_session* session)
{

View File

@@ -735,6 +735,7 @@ TEST_F(VariantTest, visitsNodesDepthFirst)
node.visit(
[&](auto const& val)
{
// TODO(c++20): use std::remove_cvref_t (P0550R2) when GCC >= 9.1
using ValueType = std::decay_t<decltype(val)>;
if constexpr (