refactor: use std::unordered_set for tr_torrent.labels (#1856)
This commit is contained in:
parent
e03bc8e5bc
commit
baafb68bfd
|
@ -106,12 +106,11 @@ static uint64_t loadPeers(tr_variant* dict, tr_torrent* tor)
|
|||
|
||||
static void saveLabels(tr_variant* dict, tr_torrent const* tor)
|
||||
{
|
||||
size_t const n = tr_ptrArraySize(&tor->labels);
|
||||
tr_variant* list = tr_variantDictAddList(dict, TR_KEY_labels, n);
|
||||
char const* const* labels = (char const* const*)tr_ptrArrayBase(&tor->labels);
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
auto const& labels = tor->labels;
|
||||
tr_variant* list = tr_variantDictAddList(dict, TR_KEY_labels, std::size(labels));
|
||||
for (auto const& label : labels)
|
||||
{
|
||||
tr_variantListAddStr(list, labels[i]);
|
||||
tr_variantListAddStr(list, label.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -128,7 +127,7 @@ static uint64_t loadLabels(tr_variant* dict, tr_torrent* tor)
|
|||
{
|
||||
if (tr_variantGetStr(tr_variantListChild(list, i), &str, &str_len) && str != nullptr && str_len != 0)
|
||||
{
|
||||
tr_ptrArrayAppend(&tor->labels, tr_strndup(str, str_len));
|
||||
tor->labels.emplace(str, str_len);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -472,12 +472,10 @@ static char const* torrentVerify(
|
|||
|
||||
static void addLabels(tr_torrent const* tor, tr_variant* list)
|
||||
{
|
||||
int const labelsCount = tr_ptrArraySize(&tor->labels);
|
||||
tr_variantInitList(list, labelsCount);
|
||||
char const* const* labels = (char const* const*)tr_ptrArrayBase(&tor->labels);
|
||||
for (int i = 0; i < labelsCount; ++i)
|
||||
tr_variantInitList(list, std::size(tor->labels));
|
||||
for (auto const& label : tor->labels)
|
||||
{
|
||||
tr_variantListAddStr(list, labels[i]);
|
||||
tr_variantListAddStr(list, label.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1079,8 +1077,7 @@ static char const* setLabels(tr_torrent* tor, tr_variant* list)
|
|||
{
|
||||
size_t const n = tr_variantListSize(list);
|
||||
char const* errmsg = nullptr;
|
||||
auto labels = tr_ptrArray{};
|
||||
int labelcount = 0;
|
||||
auto labels = tr_labels_t{};
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
{
|
||||
char const* str;
|
||||
|
@ -1099,26 +1096,13 @@ static char const* setLabels(tr_torrent* tor, tr_variant* list)
|
|||
errmsg = "labels cannot contain comma (,) character";
|
||||
}
|
||||
|
||||
if (errmsg == nullptr)
|
||||
if (errmsg == nullptr && labels.count(label) != 0)
|
||||
{
|
||||
bool dup = false;
|
||||
for (int j = 0; j < labelcount; j++)
|
||||
{
|
||||
if (tr_strcmp0(label, (char*)tr_ptrArrayNth(&labels, j)) == 0)
|
||||
{
|
||||
dup = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (dup)
|
||||
{
|
||||
errmsg = "labels cannot contain duplicates";
|
||||
}
|
||||
errmsg = "labels cannot contain duplicates";
|
||||
}
|
||||
|
||||
tr_ptrArrayAppend(&labels, label);
|
||||
labelcount++;
|
||||
labels.emplace(label);
|
||||
tr_free(label);
|
||||
|
||||
if (errmsg != nullptr)
|
||||
{
|
||||
|
@ -1129,10 +1113,9 @@ static char const* setLabels(tr_torrent* tor, tr_variant* list)
|
|||
|
||||
if (errmsg == nullptr)
|
||||
{
|
||||
tr_torrentSetLabels(tor, &labels);
|
||||
tr_torrentSetLabels(tor, std::move(labels));
|
||||
}
|
||||
|
||||
tr_ptrArrayDestruct(&labels, tr_free);
|
||||
return errmsg;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <cstdlib> /* qsort */
|
||||
#include <cstring> /* memcmp */
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#ifndef _WIN32
|
||||
|
@ -42,7 +43,6 @@
|
|||
#include "peer-common.h" /* MAX_BLOCK_SIZE */
|
||||
#include "peer-mgr.h"
|
||||
#include "platform.h" /* TR_PATH_DELIMITER_STR */
|
||||
#include "ptrarray.h"
|
||||
#include "resume.h"
|
||||
#include "session.h"
|
||||
#include "subprocess.h"
|
||||
|
@ -867,7 +867,6 @@ static void torrentInit(tr_torrent* tor, tr_ctor const* ctor)
|
|||
tor->uniqueId = nextUniqueId++;
|
||||
tor->magicNumber = TORRENT_MAGIC_NUMBER;
|
||||
tor->queuePosition = tr_sessionCountTorrents(session);
|
||||
tor->labels = {};
|
||||
|
||||
tr_sha1(tor->obfuscatedHash, "req2", 4, tor->info.hash, SHA_DIGEST_LENGTH, nullptr);
|
||||
|
||||
|
@ -1077,7 +1076,7 @@ tr_torrent* tr_torrentNew(tr_ctor const* ctor, int* setme_error, int* setme_dupl
|
|||
|
||||
if (r == TR_PARSE_OK)
|
||||
{
|
||||
tor = tr_new0(tr_torrent, 1);
|
||||
tor = new tr_torrent{};
|
||||
tor->info = tmpInfo;
|
||||
|
||||
if (hasInfo)
|
||||
|
@ -1639,11 +1638,9 @@ static void freeTorrent(tr_torrent* tor)
|
|||
TR_ASSERT(queueIsSequenced(session));
|
||||
|
||||
tr_bandwidthDestruct(&tor->bandwidth);
|
||||
tr_ptrArrayDestruct(&tor->labels, tr_free);
|
||||
|
||||
tr_metainfoFree(inf);
|
||||
memset(tor, ~0, sizeof(tr_torrent));
|
||||
tr_free(tor);
|
||||
delete tor;
|
||||
|
||||
tr_sessionUnlock(session);
|
||||
}
|
||||
|
@ -2109,6 +2106,23 @@ void tr_torrentClearIdleLimitHitCallback(tr_torrent* torrent)
|
|||
tr_torrentSetIdleLimitHitCallback(torrent, nullptr, nullptr);
|
||||
}
|
||||
|
||||
static std::string buildLabelsString(tr_torrent const* tor)
|
||||
{
|
||||
auto buf = std::stringstream{};
|
||||
|
||||
for (auto it = std::begin(tor->labels), end = std::end(tor->labels); it != end;)
|
||||
{
|
||||
buf << *it;
|
||||
|
||||
if (++it != end)
|
||||
{
|
||||
buf << ',';
|
||||
}
|
||||
}
|
||||
|
||||
return buf.str();
|
||||
}
|
||||
|
||||
static void torrentCallScript(tr_torrent const* tor, char const* script)
|
||||
{
|
||||
if (tr_str_is_empty(script))
|
||||
|
@ -2129,8 +2143,6 @@ static void torrentCallScript(tr_torrent const* tor, char const* script)
|
|||
nullptr,
|
||||
};
|
||||
|
||||
char* labels = tr_strjoin((char const* const*)tr_ptrArrayBase(&tor->labels), tr_ptrArraySize(&tor->labels), ",");
|
||||
|
||||
char* const env[] = {
|
||||
tr_strdup_printf("TR_APP_VERSION=%s", SHORT_VERSION_STRING),
|
||||
tr_strdup_printf("TR_TIME_LOCALTIME=%s", ctime_str),
|
||||
|
@ -2138,7 +2150,7 @@ static void torrentCallScript(tr_torrent const* tor, char const* script)
|
|||
tr_strdup_printf("TR_TORRENT_HASH=%s", tor->info.hashString),
|
||||
tr_strdup_printf("TR_TORRENT_ID=%d", tr_torrentId(tor)),
|
||||
tr_strdup_printf("TR_TORRENT_NAME=%s", tr_torrentName(tor)),
|
||||
tr_strdup_printf("TR_TORRENT_LABELS=%s", labels),
|
||||
tr_strdup_printf("TR_TORRENT_LABELS=%s", buildLabelsString(tor).c_str()),
|
||||
nullptr,
|
||||
};
|
||||
|
||||
|
@ -2154,7 +2166,6 @@ static void torrentCallScript(tr_torrent const* tor, char const* script)
|
|||
|
||||
tr_free_ptrv((void* const*)env);
|
||||
tr_free_ptrv((void* const*)cmd);
|
||||
tr_free(labels);
|
||||
tr_free(torrent_dir);
|
||||
}
|
||||
|
||||
|
@ -2412,21 +2423,13 @@ void tr_torrentSetFileDLs(tr_torrent* tor, tr_file_index_t const* files, tr_file
|
|||
****
|
||||
***/
|
||||
|
||||
void tr_torrentSetLabels(tr_torrent* tor, tr_ptrArray* labels)
|
||||
void tr_torrentSetLabels(tr_torrent* tor, tr_labels_t&& labels)
|
||||
{
|
||||
TR_ASSERT(tr_isTorrent(tor));
|
||||
|
||||
tr_torrentLock(tor);
|
||||
|
||||
tr_ptrArrayDestruct(&tor->labels, tr_free);
|
||||
tor->labels = {};
|
||||
char** l = (char**)tr_ptrArrayBase(labels);
|
||||
int const n = tr_ptrArraySize(labels);
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
tr_ptrArrayAppend(&tor->labels, tr_strdup(l[i]));
|
||||
}
|
||||
|
||||
tor->labels = std::move(labels);
|
||||
tr_torrentSetDirty(tor);
|
||||
|
||||
tr_torrentUnlock(tor);
|
||||
|
|
|
@ -12,13 +12,15 @@
|
|||
#error only libtransmission should #include this header.
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "bandwidth.h" /* tr_bandwidth */
|
||||
#include "completion.h" /* tr_completion */
|
||||
#include "session.h" /* tr_sessionLock(), tr_sessionUnlock() */
|
||||
#include "tr-assert.h"
|
||||
#include "tr-macros.h"
|
||||
#include "utils.h" /* TR_GNUC_PRINTF */
|
||||
#include "ptrarray.h"
|
||||
|
||||
struct tr_torrent_tiers;
|
||||
struct tr_magnet_info;
|
||||
|
@ -44,7 +46,9 @@ void tr_ctorInitTorrentWanted(tr_ctor const* ctor, tr_torrent* tor);
|
|||
/* just like tr_torrentSetFileDLs but doesn't trigger a fastresume save */
|
||||
void tr_torrentInitFileDLs(tr_torrent* tor, tr_file_index_t const* files, tr_file_index_t fileCount, bool do_download);
|
||||
|
||||
void tr_torrentSetLabels(tr_torrent* tor, tr_ptrArray* labels);
|
||||
using tr_labels_t = std::unordered_set<std::string>;
|
||||
|
||||
void tr_torrentSetLabels(tr_torrent* tor, tr_labels_t&& labels);
|
||||
|
||||
void tr_torrentRecheckCompleteness(tr_torrent*);
|
||||
|
||||
|
@ -264,7 +268,7 @@ struct tr_torrent
|
|||
tr_idlelimit idleLimitMode;
|
||||
bool finishedSeedingByIdle;
|
||||
|
||||
tr_ptrArray labels;
|
||||
tr_labels_t labels;
|
||||
};
|
||||
|
||||
/* what piece index is this block in? */
|
||||
|
|
|
@ -608,37 +608,6 @@ char* tr_strsep(char** str, char const* delims)
|
|||
#endif
|
||||
}
|
||||
|
||||
char* tr_strjoin(char const* const* arr, size_t len, char const* delim)
|
||||
{
|
||||
size_t total_len = 1;
|
||||
size_t delim_len = strlen(delim);
|
||||
for (size_t i = 0; i < len; ++i)
|
||||
{
|
||||
total_len += strlen(arr[i]);
|
||||
}
|
||||
|
||||
total_len += len > 0 ? (len - 1) * delim_len : 0;
|
||||
|
||||
char* const ret = tr_new(char, total_len);
|
||||
char* p = ret;
|
||||
|
||||
for (size_t i = 0; i < len; ++i)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
memcpy(p, delim, delim_len);
|
||||
p += delim_len;
|
||||
}
|
||||
|
||||
size_t const part_len = strlen(arr[i]);
|
||||
memcpy(p, arr[i], part_len);
|
||||
p += part_len;
|
||||
}
|
||||
|
||||
*p = '\0';
|
||||
return ret;
|
||||
}
|
||||
|
||||
char* tr_strstrip(char* str)
|
||||
{
|
||||
if (str != nullptr)
|
||||
|
|
|
@ -250,9 +250,6 @@ char const* tr_strcasestr(char const* haystack, char const* needle);
|
|||
/** @brief Portability wrapper for strsep() that uses the system implementation if available */
|
||||
char* tr_strsep(char** str, char const* delim);
|
||||
|
||||
/** @brief Concatenates array of strings with delimiter in between elements */
|
||||
char* tr_strjoin(char const* const* arr, size_t len, char const* delim);
|
||||
|
||||
/***
|
||||
****
|
||||
***/
|
||||
|
|
|
@ -68,29 +68,6 @@ TEST_F(UtilsTest, trStrstrip)
|
|||
tr_free(in);
|
||||
}
|
||||
|
||||
TEST_F(UtilsTest, trStrjoin)
|
||||
{
|
||||
auto const in1 = std::array<char const*, 2>{ "one", "two" };
|
||||
auto out = makeString(tr_strjoin(in1.data(), in1.size(), ", "));
|
||||
EXPECT_EQ("one, two", out);
|
||||
|
||||
auto const in2 = std::array<char const*, 1>{ "hello" };
|
||||
out = makeString(tr_strjoin(in2.data(), in2.size(), "###"));
|
||||
EXPECT_EQ("hello", out);
|
||||
|
||||
auto const in3 = std::array<char const*, 5>{ "a", "b", "ccc", "d", "eeeee" };
|
||||
out = makeString(tr_strjoin(in3.data(), in3.size(), " "));
|
||||
EXPECT_EQ("a b ccc d eeeee", out);
|
||||
|
||||
auto const in4 = std::array<char const*, 3>{ "7", "ate", "9" };
|
||||
out = makeString(tr_strjoin(in4.data(), in4.size(), ""));
|
||||
EXPECT_EQ("7ate9", out);
|
||||
|
||||
char const** in5 = nullptr;
|
||||
out = makeString(tr_strjoin(in5, 0, "a"));
|
||||
EXPECT_EQ("", out);
|
||||
}
|
||||
|
||||
TEST_F(UtilsTest, trBuildpath)
|
||||
{
|
||||
auto out = makeString(tr_buildPath("foo", "bar", nullptr));
|
||||
|
|
Loading…
Reference in New Issue