refactor: C++ify tr_torrentStat() (#8257)

* refactor: callers now own the return value of tr_torrentStat()

fix one potential thread issue by simplifying ownership

* refactor: make tr_stat_errtype an enum class; move into tr_stat

* refactor: order tr_stat fields to reduce padding

* chore: fix branch shear

* fix: int-to-enum-class comparison

* fix: namespace regression

* chore: make clang-tidy happy
This commit is contained in:
Charles Kerr
2026-01-29 08:07:11 -06:00
committed by GitHub
parent 7de2aadb41
commit dd008ae1d0
20 changed files with 465 additions and 446 deletions

View File

@@ -20,6 +20,8 @@
#import "TrackerNode.h"
#import "Utils.h"
using tr::Values::Speed;
NSString* const kTorrentDidChangeGroupNotification = @"TorrentDidChangeGroup";
static int const kETAIdleDisplaySec = 2 * 60;
@@ -29,7 +31,7 @@ static dispatch_queue_t timeMachineExcludeQueue;
@interface Torrent ()
@property(nonatomic, readonly) tr_torrent* fHandle;
@property(nonatomic) tr_stat const* fStat;
@property(nonatomic) tr_stat fStat;
@property(nonatomic, readonly) NSUserDefaults* fDefaults;
@@ -274,7 +276,7 @@ bool trashDataFile(std::string_view const filename, tr_error* error)
torrent_objects.emplace_back(torrent);
torrent_handles.emplace_back(torrent.fHandle);
was_transmitting.emplace_back(torrent.fStat != nullptr && torrent.transmitting);
was_transmitting.emplace_back(torrent.transmitting);
}
if (torrent_handles.empty())
@@ -361,7 +363,7 @@ bool trashDataFile(std::string_view const filename, tr_error* error)
- (NSUInteger)queuePosition
{
return self.fStat->queuePosition;
return self.fStat.queue_position;
}
- (void)setQueuePosition:(NSUInteger)index
@@ -392,12 +394,12 @@ bool trashDataFile(std::string_view const filename, tr_error* error)
- (NSString*)magnetLink
{
return @(tr_torrentGetMagnetLink(self.fHandle).c_str());
return tr_strv_to_utf8_nsstring(tr_torrentGetMagnetLink(self.fHandle));
}
- (CGFloat)ratio
{
return self.fStat->ratio;
return self.fStat.upload_ratio;
}
- (tr_ratiolimit)ratioSetting
@@ -424,7 +426,7 @@ bool trashDataFile(std::string_view const filename, tr_error* error)
- (CGFloat)progressStopRatio
{
return self.fStat->seedRatioPercentDone;
return self.fStat.seed_ratio_percent_done;
}
- (tr_idlelimit)idleSetting
@@ -492,7 +494,7 @@ bool trashDataFile(std::string_view const filename, tr_error* error)
}
- (BOOL)waitingToStart
{
return self.fStat->activity == TR_STATUS_DOWNLOAD_WAIT || self.fStat->activity == TR_STATUS_SEED_WAIT;
return self.fStat.activity == TR_STATUS_DOWNLOAD_WAIT || self.fStat.activity == TR_STATUS_SEED_WAIT;
}
- (tr_priority_t)priority
@@ -665,7 +667,7 @@ bool trashDataFile(std::string_view const filename, tr_error* error)
- (uint64_t)sizeLeft
{
return self.fStat->leftUntilDone;
return self.fStat.left_until_done;
}
- (NSMutableArray*)allTrackerStats
@@ -789,7 +791,7 @@ bool trashDataFile(std::string_view const filename, tr_error* error)
- (NSString*)torrentLocation
{
return @(tr_torrentFilename(self.fHandle).c_str());
return tr_strv_to_utf8_nsstring(tr_torrentFilename(self.fHandle));
}
- (NSString*)dataLocation
@@ -813,7 +815,7 @@ bool trashDataFile(std::string_view const filename, tr_error* error)
else
{
auto const location = tr_torrentFindFile(self.fHandle, 0);
return std::empty(location) ? nil : @(location.c_str());
return std::empty(location) ? nil : tr_strv_to_utf8_nsstring(location);
}
}
@@ -853,7 +855,7 @@ bool trashDataFile(std::string_view const filename, tr_error* error)
else
{
auto const location = tr_torrentFindFile(self.fHandle, node.indexes.firstIndex);
return std::empty(location) ? nil : @(location.c_str());
return std::empty(location) ? nil : tr_strv_to_utf8_nsstring(location);
}
}
@@ -883,17 +885,17 @@ bool trashDataFile(std::string_view const filename, tr_error* error)
- (time_t)eta
{
time_t eta = self.fStat->eta;
time_t eta = self.fStat.eta;
if (eta >= 0)
{
return eta;
}
time_t etaIdle = self.fStat->etaIdle;
time_t etaIdle = self.fStat.eta_idle;
if (etaIdle >= 0 && etaIdle < kETAIdleDisplaySec)
{
return etaIdle;
}
if (self.fStat->leftUntilDone <= 0)
if (self.fStat.left_until_done <= 0)
{
// We return smallest amount of time remaining for simplest compliance with sorting.
return 0;
@@ -904,12 +906,12 @@ bool trashDataFile(std::string_view const filename, tr_error* error)
- (CGFloat)progress
{
return self.fStat->percentComplete;
return self.fStat.percent_complete;
}
- (CGFloat)progressDone
{
return self.fStat->percentDone;
return self.fStat.percent_done;
}
- (CGFloat)progressLeft
@@ -924,39 +926,38 @@ bool trashDataFile(std::string_view const filename, tr_error* error)
- (CGFloat)checkingProgress
{
return self.fStat->recheckProgress;
return self.fStat.recheck_progress;
}
- (CGFloat)availableDesired
{
return (CGFloat)self.fStat->desiredAvailable / self.sizeLeft;
return (CGFloat)self.fStat.desired_available / self.sizeLeft;
}
- (BOOL)isActive
{
return self.fStat->activity != TR_STATUS_STOPPED && self.fStat->activity != TR_STATUS_DOWNLOAD_WAIT &&
self.fStat->activity != TR_STATUS_SEED_WAIT;
return self.fStat.activity != TR_STATUS_STOPPED && self.fStat.activity != TR_STATUS_DOWNLOAD_WAIT && self.fStat.activity != TR_STATUS_SEED_WAIT;
}
- (BOOL)isTransmitting
{
return self.fStat->peersGettingFromUs > 0 || self.fStat->peersSendingToUs > 0 || self.fStat->webseedsSendingToUs > 0 ||
self.fStat->activity == TR_STATUS_CHECK;
return self.fStat.peers_getting_from_us > 0 || self.fStat.peers_sending_to_us > 0 ||
self.fStat.webseeds_sending_to_us > 0 || self.fStat.activity == TR_STATUS_CHECK;
}
- (BOOL)isSeeding
{
return self.fStat->activity == TR_STATUS_SEED;
return self.fStat.activity == TR_STATUS_SEED;
}
- (BOOL)isChecking
{
return self.fStat->activity == TR_STATUS_CHECK || self.fStat->activity == TR_STATUS_CHECK_WAIT;
return self.fStat.activity == TR_STATUS_CHECK || self.fStat.activity == TR_STATUS_CHECK_WAIT;
}
- (BOOL)isCheckingWaiting
{
return self.fStat->activity == TR_STATUS_CHECK_WAIT;
return self.fStat.activity == TR_STATUS_CHECK_WAIT;
}
- (BOOL)allDownloaded
@@ -971,17 +972,17 @@ bool trashDataFile(std::string_view const filename, tr_error* error)
- (BOOL)isFinishedSeeding
{
return self.fStat->finished;
return self.fStat.finished;
}
- (BOOL)isError
{
return self.fStat->error == TR_STAT_LOCAL_ERROR;
return self.fStat.error == tr_stat::Error::LocalError;
}
- (BOOL)isAnyErrorOrWarning
{
return self.fStat->error != TR_STAT_OK;
return self.fStat.error != tr_stat::Error::Ok;
}
- (NSString*)errorMessage
@@ -991,9 +992,8 @@ bool trashDataFile(std::string_view const filename, tr_error* error)
return @"";
}
NSString* error;
if (!(error = @(self.fStat->errorString)) &&
!(error = [NSString stringWithCString:self.fStat->errorString encoding:NSISOLatin1StringEncoding]))
NSString* error = tr_strv_to_utf8_nsstring(self.fStat.error_string);
if (!error || [error isEqualToString:@""])
{
error = [NSString stringWithFormat:@"(%@)", NSLocalizedString(@"unreadable error", "Torrent -> error string unreadable")];
}
@@ -1074,9 +1074,9 @@ bool trashDataFile(std::string_view const filename, tr_error* error)
{
if (self.magnet)
{
NSString* progressString = self.fStat->metadataPercentComplete > 0.0 ?
NSString* progressString = self.fStat.metadata_percent_complete > 0.0 ?
[NSString stringWithFormat:NSLocalizedString(@"%@ of torrent metadata retrieved", "Torrent -> progress string"),
[NSString percentString:self.fStat->metadataPercentComplete longDecimals:YES]] :
[NSString percentString:self.fStat.metadata_percent_complete longDecimals:YES]] :
NSLocalizedString(@"torrent metadata needed", "Torrent -> progress string");
return [NSString stringWithFormat:@"%@ — %@", NSLocalizedString(@"Magnetized transfer", "Torrent -> progress string"), progressString];
@@ -1143,15 +1143,15 @@ bool trashDataFile(std::string_view const filename, tr_error* error)
if (self.anyErrorOrWarning)
{
switch (self.fStat->error)
switch (self.fStat.error)
{
case TR_STAT_LOCAL_ERROR:
case tr_stat::Error::LocalError:
string = NSLocalizedString(@"Error", "Torrent -> status string");
break;
case TR_STAT_TRACKER_ERROR:
case tr_stat::Error::TrackerError:
string = NSLocalizedString(@"Tracker returned error", "Torrent -> status string");
break;
case TR_STAT_TRACKER_WARNING:
case tr_stat::Error::TrackerWarning:
string = NSLocalizedString(@"Tracker returned warning", "Torrent -> status string");
break;
default:
@@ -1166,7 +1166,7 @@ bool trashDataFile(std::string_view const filename, tr_error* error)
}
else
{
switch (self.fStat->activity)
switch (self.fStat.activity)
{
case TR_STATUS_STOPPED:
if (self.finishedSeeding)
@@ -1210,7 +1210,7 @@ bool trashDataFile(std::string_view const filename, tr_error* error)
self.peersSendingToUs];
}
if (NSUInteger const webSeedCount = self.fStat->webseedsSendingToUs; webSeedCount > 0)
if (NSUInteger const webSeedCount = self.fStat.webseeds_sending_to_us; webSeedCount > 0)
{
NSString* webSeedString;
if (webSeedCount != 1)
@@ -1255,7 +1255,7 @@ bool trashDataFile(std::string_view const filename, tr_error* error)
//append even if error
if (self.active && !self.checking)
{
if (self.fStat->activity == TR_STATUS_DOWNLOAD)
if (self.fStat.activity == TR_STATUS_DOWNLOAD)
{
string = [string stringByAppendingFormat:@" — %@: %@, %@: %@",
NSLocalizedString(@"DL", "Torrent -> status string"),
@@ -1278,7 +1278,7 @@ bool trashDataFile(std::string_view const filename, tr_error* error)
{
NSString* string;
switch (self.fStat->activity)
switch (self.fStat.activity)
{
case TR_STATUS_STOPPED:
if (self.finishedSeeding)
@@ -1342,7 +1342,7 @@ bool trashDataFile(std::string_view const filename, tr_error* error)
- (NSString*)stateString
{
switch (self.fStat->activity)
switch (self.fStat.activity)
{
case TR_STATUS_STOPPED:
case TR_STATUS_DOWNLOAD_WAIT:
@@ -1353,7 +1353,7 @@ bool trashDataFile(std::string_view const filename, tr_error* error)
NSString* extra = nil;
if (self.waitingToStart)
{
extra = self.fStat->activity == TR_STATUS_DOWNLOAD_WAIT ?
extra = self.fStat.activity == TR_STATUS_DOWNLOAD_WAIT ?
NSLocalizedString(@"Waiting to download", "Torrent -> status string") :
NSLocalizedString(@"Waiting to seed", "Torrent -> status string");
}
@@ -1383,97 +1383,97 @@ bool trashDataFile(std::string_view const filename, tr_error* error)
- (NSUInteger)totalPeersConnected
{
return self.fStat->peersConnected;
return self.fStat.peers_connected;
}
- (NSUInteger)totalPeersTracker
{
return self.fStat->peersFrom[TR_PEER_FROM_TRACKER];
return self.fStat.peers_from[TR_PEER_FROM_TRACKER];
}
- (NSUInteger)totalPeersIncoming
{
return self.fStat->peersFrom[TR_PEER_FROM_INCOMING];
return self.fStat.peers_from[TR_PEER_FROM_INCOMING];
}
- (NSUInteger)totalPeersCache
{
return self.fStat->peersFrom[TR_PEER_FROM_RESUME];
return self.fStat.peers_from[TR_PEER_FROM_RESUME];
}
- (NSUInteger)totalPeersPex
{
return self.fStat->peersFrom[TR_PEER_FROM_PEX];
return self.fStat.peers_from[TR_PEER_FROM_PEX];
}
- (NSUInteger)totalPeersDHT
{
return self.fStat->peersFrom[TR_PEER_FROM_DHT];
return self.fStat.peers_from[TR_PEER_FROM_DHT];
}
- (NSUInteger)totalPeersLocal
{
return self.fStat->peersFrom[TR_PEER_FROM_LPD];
return self.fStat.peers_from[TR_PEER_FROM_LPD];
}
- (NSUInteger)totalPeersLTEP
{
return self.fStat->peersFrom[TR_PEER_FROM_LTEP];
return self.fStat.peers_from[TR_PEER_FROM_LTEP];
}
- (NSUInteger)totalKnownPeersTracker
{
return self.fStat->knownPeersFrom[TR_PEER_FROM_TRACKER];
return self.fStat.known_peers_from[TR_PEER_FROM_TRACKER];
}
- (NSUInteger)totalKnownPeersIncoming
{
return self.fStat->knownPeersFrom[TR_PEER_FROM_INCOMING];
return self.fStat.known_peers_from[TR_PEER_FROM_INCOMING];
}
- (NSUInteger)totalKnownPeersCache
{
return self.fStat->knownPeersFrom[TR_PEER_FROM_RESUME];
return self.fStat.known_peers_from[TR_PEER_FROM_RESUME];
}
- (NSUInteger)totalKnownPeersPex
{
return self.fStat->knownPeersFrom[TR_PEER_FROM_PEX];
return self.fStat.known_peers_from[TR_PEER_FROM_PEX];
}
- (NSUInteger)totalKnownPeersDHT
{
return self.fStat->knownPeersFrom[TR_PEER_FROM_DHT];
return self.fStat.known_peers_from[TR_PEER_FROM_DHT];
}
- (NSUInteger)totalKnownPeersLocal
{
return self.fStat->knownPeersFrom[TR_PEER_FROM_LPD];
return self.fStat.known_peers_from[TR_PEER_FROM_LPD];
}
- (NSUInteger)totalKnownPeersLTEP
{
return self.fStat->knownPeersFrom[TR_PEER_FROM_LTEP];
return self.fStat.known_peers_from[TR_PEER_FROM_LTEP];
}
- (NSUInteger)peersSendingToUs
{
return self.fStat->peersSendingToUs;
return self.fStat.peers_sending_to_us;
}
- (NSUInteger)peersGettingFromUs
{
return self.fStat->peersGettingFromUs;
return self.fStat.peers_getting_from_us;
}
- (CGFloat)downloadRate
{
return self.fStat->pieceDownloadSpeed_KBps;
return self.fStat.piece_download_speed.count(Speed::Units::KByps);
}
- (CGFloat)uploadRate
{
return self.fStat->pieceUploadSpeed_KBps;
return self.fStat.piece_upload_speed.count(Speed::Units::KByps);
}
- (CGFloat)totalRate
@@ -1483,32 +1483,32 @@ bool trashDataFile(std::string_view const filename, tr_error* error)
- (uint64_t)haveVerified
{
return self.fStat->haveValid;
return self.fStat.have_valid;
}
- (uint64_t)haveTotal
{
return self.haveVerified + self.fStat->haveUnchecked;
return self.haveVerified + self.fStat.have_unchecked;
}
- (uint64_t)totalSizeSelected
{
return self.fStat->sizeWhenDone;
return self.fStat.size_when_done;
}
- (uint64_t)downloadedTotal
{
return self.fStat->downloadedEver;
return self.fStat.downloaded_ever;
}
- (uint64_t)uploadedTotal
{
return self.fStat->uploadedEver;
return self.fStat.uploaded_ever;
}
- (uint64_t)failedHash
{
return self.fStat->corruptEver;
return self.fStat.corrupt_ever;
}
- (void)setGroupValue:(NSInteger)groupValue determinationType:(TorrentDeterminationType)determinationType
@@ -1700,19 +1700,19 @@ bool trashDataFile(std::string_view const filename, tr_error* error)
- (NSDate*)dateAdded
{
time_t const date = self.fStat->addedDate;
time_t const date = self.fStat.added_date;
return [NSDate dateWithTimeIntervalSince1970:date];
}
- (NSDate*)dateCompleted
{
time_t const date = self.fStat->doneDate;
time_t const date = self.fStat.done_date;
return date != 0 ? [NSDate dateWithTimeIntervalSince1970:date] : nil;
}
- (NSDate*)dateActivity
{
time_t const date = self.fStat->activityDate;
time_t const date = self.fStat.activity_date;
return date != 0 ? [NSDate dateWithTimeIntervalSince1970:date] : nil;
}
@@ -1724,27 +1724,27 @@ bool trashDataFile(std::string_view const filename, tr_error* error)
- (NSInteger)secondsDownloading
{
return self.fStat->secondsDownloading;
return self.fStat.seconds_downloading;
}
- (NSInteger)secondsSeeding
{
return self.fStat->secondsSeeding;
return self.fStat.seconds_seeding;
}
- (NSInteger)stalledMinutes
{
if (self.fStat->idleSecs == -1)
if (self.fStat.idle_secs == -1)
{
return -1;
}
return self.fStat->idleSecs / 60;
return self.fStat.idle_secs / 60;
}
- (BOOL)isStalled
{
return self.fStat->isStalled;
return self.fStat.is_stalled;
}
- (void)updateTimeMachineExclude
@@ -1822,6 +1822,7 @@ bool trashDataFile(std::string_view const filename, tr_error* error)
}
_fDefaults = NSUserDefaults.standardUserDefaults;
_fStat = tr_stat{};
if (torrentStruct)
{
@@ -2156,7 +2157,7 @@ bool trashDataFile(std::string_view const filename, tr_error* error)
- (BOOL)shouldShowEta
{
if (self.fStat->activity == TR_STATUS_DOWNLOAD)
if (self.fStat.activity == TR_STATUS_DOWNLOAD)
{
return YES;
}
@@ -2169,7 +2170,7 @@ bool trashDataFile(std::string_view const filename, tr_error* error)
}
//idle: show only if remaining time is less than cap
if (self.fStat->etaIdle != TR_ETA_NOT_AVAIL && self.fStat->etaIdle < kETAIdleDisplaySec)
if (self.fStat.eta_idle != TR_ETA_NOT_AVAIL && self.fStat.eta_idle < kETAIdleDisplaySec)
{
return YES;
}
@@ -2180,12 +2181,12 @@ bool trashDataFile(std::string_view const filename, tr_error* error)
- (NSString*)etaString
{
time_t eta = self.fStat->eta;
time_t eta = self.fStat.eta;
// if there's a regular ETA, the torrent isn't idle
BOOL fromIdle = NO;
if (eta < 0)
{
eta = self.fStat->etaIdle;
eta = self.fStat.eta_idle;
fromIdle = YES;
}
// Foundation undocumented behavior: values above INT32_MAX (68 years) are interpreted as negative values by `stringFromTimeInterval` (#3451)