1
0
Fork 0
mirror of https://github.com/transmission/transmission synced 2025-02-20 13:16:53 +00:00

refactor: tr_parseNumberRange() takes a std::string_view (#1962)

* tr_parseNumberRange() now takes a std::string_view
This commit is contained in:
Charles Kerr 2021-10-15 17:15:33 -05:00 committed by GitHub
parent d11ccf113c
commit 3e7b8eb7bb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 35 additions and 23 deletions

View file

@ -2840,7 +2840,12 @@ void tr_rpc_request_exec_json(
*/
void tr_rpc_parse_list_str(tr_variant* setme, char const* str, size_t len)
{
auto const values = tr_parseNumberRange(str, len);
if (len == TR_BAD_SIZE)
{
len = strlen(str);
}
auto const values = tr_parseNumberRange(std::string_view{ str, len });
auto const valueCount = std::size(values);
if (valueCount == 0)

View file

@ -1371,27 +1371,30 @@ struct number_range
* This should be a single number (ex. "6") or a range (ex. "6-9").
* Anything else is an error and will return failure.
*/
static bool parseNumberSection(char const* str, char const* const end, number_range& range)
static bool parseNumberSection(std::string_view str, number_range& range)
{
bool success;
auto const error = errno;
#if defined(HAVE_CHARCONV)
auto result = std::from_chars(str, end, range.low);
// wants char*, so string_view::iterator don't work. make our own begin/end
auto const* const begin_ch = std::data(str);
auto const* const end_ch = begin_ch + std::size(str);
auto result = std::from_chars(begin_ch, end_ch, range.low);
success = result.ec == std::errc{};
if (success)
{
range.high = range.low;
if (result.ptr != end && *result.ptr == '-')
if (result.ptr < end_ch && *result.ptr == '-')
{
result = std::from_chars(result.ptr + 1, end, range.high);
result = std::from_chars(result.ptr + 1, end_ch, range.high);
success = result.ec == std::errc{};
}
}
#else
try
{
auto tmp = std::string(str, end);
auto tmp = std::string(str);
auto pos = size_t{};
range.low = range.high = std::stoi(tmp, &pos);
if (pos != std::size(tmp) && tmp[pos] == '-')
@ -1418,26 +1421,27 @@ static bool parseNumberSection(char const* str, char const* const end, number_ra
* It's the caller's responsibility to call tr_free () on the returned array.
* If a fragment of the string can't be parsed, nullptr is returned.
*/
std::vector<int> tr_parseNumberRange(char const* str, size_t len) // TODO: string_view
std::vector<int> tr_parseNumberRange(std::string_view str)
{
auto values = std::set<int>{};
auto const* const end = str + (len != TR_BAD_SIZE ? len : strlen(str));
for (auto const* walk = str; walk < end;)
for (;;)
{
auto delim = std::find(walk, end, ',');
auto const delim = str.find(',');
auto range = number_range{};
if (!parseNumberSection(walk, delim, range))
if (!parseNumberSection(str.substr(0, delim), range))
{
break;
}
for (auto i = range.low; i <= range.high; ++i)
{
values.insert(i);
}
walk = delim + 1;
if (delim == std::string_view::npos)
{
break;
}
str.remove_prefix(delim + 1);
}
return { std::begin(values), std::end(values) };

View file

@ -286,7 +286,7 @@ double tr_getRatio(uint64_t numerator, uint64_t denominator);
*
* For example, "5-8" will return [ 5, 6, 7, 8 ] and setmeCount will be 4.
*/
std::vector<int> tr_parseNumberRange(char const* str, size_t str_len) TR_GNUC_NONNULL(1);
std::vector<int> tr_parseNumberRange(std::string_view str);
/**
* @brief truncate a double value at a given number of decimal places.

View file

@ -6,6 +6,9 @@
*
*/
#include <string_view>
#include <typeinfo>
#ifdef _WIN32
#include <windows.h>
#define setenv(key, value, unused) SetEnvironmentVariableA(key, value)
@ -30,8 +33,8 @@
#include <string>
using ::libtransmission::test::makeString;
using UtilsTest = ::testing::Test;
using namespace std::literals;
TEST_F(UtilsTest, trStripPositionalArgs)
{
@ -125,20 +128,20 @@ TEST_F(UtilsTest, numbers)
return ss.str();
};
auto numbers = tr_parseNumberRange("1-10,13,16-19", TR_BAD_SIZE);
auto numbers = tr_parseNumberRange("1-10,13,16-19"sv);
EXPECT_EQ(std::string("1 2 3 4 5 6 7 8 9 10 13 16 17 18 19 "), tostring(numbers));
numbers = tr_parseNumberRange("1-5,3-7,2-6", TR_BAD_SIZE);
numbers = tr_parseNumberRange("1-5,3-7,2-6"sv);
EXPECT_EQ(std::string("1 2 3 4 5 6 7 "), tostring(numbers));
numbers = tr_parseNumberRange("1-Hello", TR_BAD_SIZE);
numbers = tr_parseNumberRange("1-Hello"sv);
auto const empty_string = std::string{};
EXPECT_EQ(empty_string, tostring(numbers));
numbers = tr_parseNumberRange("1-", TR_BAD_SIZE);
numbers = tr_parseNumberRange("1-"sv);
EXPECT_EQ(empty_string, tostring(numbers));
numbers = tr_parseNumberRange("Hello", TR_BAD_SIZE);
numbers = tr_parseNumberRange("Hello"sv);
EXPECT_EQ(empty_string, tostring(numbers));
}

View file

@ -645,7 +645,7 @@ static void addDays(tr_variant* args, tr_quark const key, char const* arg)
if (arg != nullptr)
{
for (int& day : tr_parseNumberRange(arg, TR_BAD_SIZE))
for (int& day : tr_parseNumberRange(arg))
{
if (day < 0 || day > 7)
{
@ -706,7 +706,7 @@ static void addFiles(tr_variant* args, tr_quark const key, char const* arg)
if (strcmp(arg, "all") != 0)
{
for (auto const& idx : tr_parseNumberRange(arg, TR_BAD_SIZE))
for (auto const& idx : tr_parseNumberRange(arg))
{
tr_variantListAddInt(files, idx);
}