perf: tr_sys_path_basename() returns a std::string_view (#4176)
This commit is contained in:
parent
134363d83d
commit
d0639b5f0c
|
@ -240,17 +240,32 @@ std::string tr_sys_path_resolve(std::string_view path, tr_error** error)
|
|||
return {};
|
||||
}
|
||||
|
||||
std::string tr_sys_path_basename(std::string_view path, tr_error** error)
|
||||
std::string_view tr_sys_path_basename(std::string_view path, tr_error** /*error*/)
|
||||
{
|
||||
auto tmp = tr_pathbuf{ path };
|
||||
|
||||
if (char const* const ret = basename(std::data(tmp)); ret != nullptr)
|
||||
// As per the basename() manpage:
|
||||
// If path [is] an empty string, then basename() return[s] the string "."
|
||||
if (std::empty(path))
|
||||
{
|
||||
return ret;
|
||||
return "."sv;
|
||||
}
|
||||
|
||||
set_system_error(error, errno);
|
||||
return {};
|
||||
// Remove all trailing slashes.
|
||||
// If nothing is left, return "/"
|
||||
if (auto pos = path.find_last_not_of('/'); pos != std::string_view::npos)
|
||||
{
|
||||
path = path.substr(0, pos + 1);
|
||||
}
|
||||
else // all slashes
|
||||
{
|
||||
return "/"sv;
|
||||
}
|
||||
|
||||
if (auto pos = path.find_last_of('/'); pos != std::string_view::npos)
|
||||
{
|
||||
path.remove_prefix(pos + 1);
|
||||
}
|
||||
|
||||
return std::empty(path) ? "/"sv : path;
|
||||
}
|
||||
|
||||
// This function is adapted from Node.js's path.posix.dirname() function,
|
||||
|
|
|
@ -109,9 +109,11 @@ static constexpr auto stat_to_sys_path_info(DWORD attributes, DWORD size_low, DW
|
|||
return info;
|
||||
}
|
||||
|
||||
static auto constexpr Slashes = "\\/"sv;
|
||||
|
||||
static constexpr bool is_slash(char c)
|
||||
{
|
||||
return c == '\\' || c == '/';
|
||||
return tr_strvContains(Slashes, c);
|
||||
}
|
||||
|
||||
static constexpr bool is_unc_path(std::string_view path)
|
||||
|
@ -547,11 +549,11 @@ std::string tr_sys_path_resolve(std::string_view path, tr_error** error)
|
|||
return {};
|
||||
}
|
||||
|
||||
std::string tr_sys_path_basename(std::string_view path, tr_error** error)
|
||||
std::string_view tr_sys_path_basename(std::string_view path, tr_error** error)
|
||||
{
|
||||
if (std::empty(path))
|
||||
{
|
||||
return ".";
|
||||
return "."sv;
|
||||
}
|
||||
|
||||
if (!is_valid_path(path))
|
||||
|
@ -560,32 +562,23 @@ std::string tr_sys_path_basename(std::string_view path, tr_error** error)
|
|||
return {};
|
||||
}
|
||||
|
||||
char const* const begin = std::data(path);
|
||||
char const* end = begin + std::size(path);
|
||||
|
||||
while (end > begin && is_slash(*(end - 1)))
|
||||
// Remove all trailing slashes.
|
||||
// If nothing is left, return "/"
|
||||
if (auto const pos = path.find_last_not_of(Slashes); pos != std::string_view::npos)
|
||||
{
|
||||
--end;
|
||||
path = path.substr(0, pos + 1);
|
||||
}
|
||||
else // all slashes
|
||||
{
|
||||
return "/"sv;
|
||||
}
|
||||
|
||||
if (end == begin)
|
||||
if (auto pos = path.find_last_of("\\/:"); pos != std::string_view::npos)
|
||||
{
|
||||
return "/";
|
||||
path.remove_prefix(pos + 1);
|
||||
}
|
||||
|
||||
char const* name = end;
|
||||
|
||||
while (name > begin && *(name - 1) != ':' && !is_slash(*(name - 1)))
|
||||
{
|
||||
--name;
|
||||
}
|
||||
|
||||
if (name == end)
|
||||
{
|
||||
return "/";
|
||||
}
|
||||
|
||||
return { name, size_t(end - name) };
|
||||
return !std::empty(path) ? path : "/"sv;
|
||||
}
|
||||
|
||||
[[nodiscard]] static bool isWindowsDeviceRoot(char ch) noexcept
|
||||
|
|
|
@ -237,7 +237,7 @@ std::string tr_sys_path_resolve(std::string_view path, struct tr_error** error =
|
|||
* @return base name (last path component; parent path removed) on success,
|
||||
* or empty string otherwise (with `error` set accordingly).
|
||||
*/
|
||||
std::string tr_sys_path_basename(std::string_view path, struct tr_error** error = nullptr);
|
||||
std::string_view tr_sys_path_basename(std::string_view path, struct tr_error** error = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Portability wrapper for `dirname()`.
|
||||
|
|
|
@ -140,26 +140,30 @@ protected:
|
|||
|
||||
struct XnameTestData
|
||||
{
|
||||
char const* input;
|
||||
char const* output;
|
||||
std::string_view input;
|
||||
std::string_view output;
|
||||
};
|
||||
|
||||
static void testPathXname(XnameTestData const* data, size_t data_size, std::string (*func)(std::string_view, tr_error**))
|
||||
static void testPathXname(
|
||||
XnameTestData const* data,
|
||||
size_t data_size,
|
||||
std::string_view (*func)(std::string_view, tr_error**))
|
||||
{
|
||||
for (size_t i = 0; i < data_size; ++i)
|
||||
{
|
||||
tr_error* err = nullptr;
|
||||
auto const name = func(data[i].input, &err);
|
||||
auto const& [input, output] = data[i];
|
||||
auto const name = func(input, &err);
|
||||
|
||||
if (data[i].output != nullptr)
|
||||
if (!std::empty(data[i].output))
|
||||
{
|
||||
EXPECT_NE(""sv, name);
|
||||
EXPECT_EQ(nullptr, err) << *err;
|
||||
EXPECT_EQ(data[i].output, name);
|
||||
EXPECT_EQ(output, name) << " in [" << input << ']';
|
||||
}
|
||||
else
|
||||
{
|
||||
EXPECT_EQ(""sv, name);
|
||||
EXPECT_EQ(""sv, name) << " in [" << input << ']';
|
||||
EXPECT_NE(nullptr, err);
|
||||
tr_error_clear(&err);
|
||||
}
|
||||
|
@ -720,30 +724,30 @@ TEST_F(FileTest, pathBasename)
|
|||
#ifdef _WIN32
|
||||
{ "\\", "/" },
|
||||
/* Invalid paths */
|
||||
{ "\\\\\\", nullptr },
|
||||
{ "123:", nullptr },
|
||||
{ "\\\\\\", "" },
|
||||
{ "123:", "" },
|
||||
/* Reserved characters */
|
||||
{ "<", nullptr },
|
||||
{ ">", nullptr },
|
||||
{ ":", nullptr },
|
||||
{ "\"", nullptr },
|
||||
{ "|", nullptr },
|
||||
{ "?", nullptr },
|
||||
{ "*", nullptr },
|
||||
{ "a\\<", nullptr },
|
||||
{ "a\\>", nullptr },
|
||||
{ "a\\:", nullptr },
|
||||
{ "a\\\"", nullptr },
|
||||
{ "a\\|", nullptr },
|
||||
{ "a\\?", nullptr },
|
||||
{ "a\\*", nullptr },
|
||||
{ "c:\\a\\b<c\\d", nullptr },
|
||||
{ "c:\\a\\b>c\\d", nullptr },
|
||||
{ "c:\\a\\b:c\\d", nullptr },
|
||||
{ "c:\\a\\b\"c\\d", nullptr },
|
||||
{ "c:\\a\\b|c\\d", nullptr },
|
||||
{ "c:\\a\\b?c\\d", nullptr },
|
||||
{ "c:\\a\\b*c\\d", nullptr },
|
||||
{ "<", "" },
|
||||
{ ">", "" },
|
||||
{ ":", "" },
|
||||
{ "\"", "" },
|
||||
{ "|", "" },
|
||||
{ "?", "" },
|
||||
{ "*", "" },
|
||||
{ "a\\<", "" },
|
||||
{ "a\\>", "" },
|
||||
{ "a\\:", "" },
|
||||
{ "a\\\"", "" },
|
||||
{ "a\\|", "" },
|
||||
{ "a\\?", "" },
|
||||
{ "a\\*", "" },
|
||||
{ "c:\\a\\b<c\\d", "" },
|
||||
{ "c:\\a\\b>c\\d", "" },
|
||||
{ "c:\\a\\b:c\\d", "" },
|
||||
{ "c:\\a\\b\"c\\d", "" },
|
||||
{ "c:\\a\\b|c\\d", "" },
|
||||
{ "c:\\a\\b?c\\d", "" },
|
||||
{ "c:\\a\\b*c\\d", "" },
|
||||
#else
|
||||
{ "////", "/" },
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue