Improve path splitting speed
And create a range closure so the components can be iterated without allocating a container.
This commit is contained in:
parent
b3e2c9f9f1
commit
8626140b73
6 changed files with 45 additions and 27 deletions
|
@ -279,6 +279,7 @@ find_package(LLVM MODULE COMPONENTS Demangle)
|
|||
find_package(lz4 REQUIRED)
|
||||
find_package(nlohmann_json 3.8 REQUIRED)
|
||||
find_package(Opus 1.3 MODULE)
|
||||
find_package(range-v3 REQUIRED)
|
||||
find_package(ZLIB 1.2 REQUIRED)
|
||||
find_package(zstd 1.5 REQUIRED)
|
||||
|
||||
|
|
|
@ -350,17 +350,11 @@ std::string_view RemoveTrailingSlash(std::string_view path) {
|
|||
}
|
||||
|
||||
std::vector<std::string> SplitPathComponents(std::string_view filename) {
|
||||
std::string copy(filename);
|
||||
std::replace(copy.begin(), copy.end(), '\\', '/');
|
||||
std::vector<std::string> out;
|
||||
|
||||
std::stringstream stream(copy);
|
||||
std::string item;
|
||||
while (std::getline(stream, item, '/')) {
|
||||
out.push_back(std::move(item));
|
||||
std::vector<std::string> copied_components;
|
||||
for (std::string_view component : filename | split_path_components_view) {
|
||||
copied_components.emplace_back(component);
|
||||
}
|
||||
|
||||
return out;
|
||||
return copied_components;
|
||||
}
|
||||
|
||||
std::string SanitizePath(std::string_view path_, DirectorySeparator directory_separator) {
|
||||
|
|
|
@ -6,6 +6,10 @@
|
|||
#include <filesystem>
|
||||
#include <vector>
|
||||
|
||||
#include <range/v3/view/remove_if.hpp>
|
||||
#include <range/v3/view/split_when.hpp>
|
||||
#include <range/v3/view/transform.hpp>
|
||||
|
||||
#include "common/fs/fs_util.h"
|
||||
|
||||
namespace Common::FS {
|
||||
|
@ -284,6 +288,23 @@ enum class DirectorySeparator {
|
|||
PlatformDefault,
|
||||
};
|
||||
|
||||
// A range adaptor closure which splits the path on '/' or '\'
|
||||
// i.e. "C:\Users\Yuzu\Documents\save.bin" becomes {"C:", "Users", "Yuzu", "Documents", "save.bin" }
|
||||
constexpr auto split_path_components_view =
|
||||
// Somehow split_when never made it into the standard
|
||||
ranges::views::split_when([](auto cur, auto end) {
|
||||
const char c = *cur;
|
||||
bool do_split = c == '\\' || c == '/';
|
||||
return std::make_pair(do_split, cur + (do_split ? 1 : 0));
|
||||
}) |
|
||||
// Convert from opaque range to std::string_view
|
||||
ranges::views::transform([](auto&& chunk) {
|
||||
return std::string_view{&*ranges::begin(chunk),
|
||||
static_cast<std::size_t>(ranges::distance(chunk))};
|
||||
}) |
|
||||
// Skip any empty segments like at the beginning and end of "/root/directory/"
|
||||
ranges::views::remove_if(&std::string_view::empty);
|
||||
|
||||
// Splits the path on '/' or '\' and put the components into a vector
|
||||
// i.e. "C:\Users\Yuzu\Documents\save.bin" becomes {"C:", "Users", "Yuzu", "Documents", "save.bin" }
|
||||
[[nodiscard]] std::vector<std::string> SplitPathComponents(std::string_view filename);
|
||||
|
|
|
@ -837,7 +837,7 @@ endif()
|
|||
create_target_directory_groups(core)
|
||||
|
||||
target_link_libraries(core PUBLIC common PRIVATE audio_core network video_core)
|
||||
target_link_libraries(core PUBLIC Boost::headers PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls Opus::opus)
|
||||
target_link_libraries(core PUBLIC Boost::headers PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls Opus::opus range-v3)
|
||||
if (MINGW)
|
||||
target_link_libraries(core PRIVATE ${MSWSOCK_LIBRARY})
|
||||
endif()
|
||||
|
|
|
@ -200,31 +200,32 @@ std::string VfsFile::GetFullPath() const {
|
|||
}
|
||||
|
||||
VirtualFile VfsDirectory::GetFileRelative(std::string_view path) const {
|
||||
auto vec = Common::FS::SplitPathComponents(path);
|
||||
vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
|
||||
vec.end());
|
||||
if (vec.empty()) {
|
||||
auto&& component_view = path | Common::FS::split_path_components_view;
|
||||
auto next_component = component_view.begin();
|
||||
if (next_component == component_view.end()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (vec.size() == 1) {
|
||||
return GetFile(vec[0]);
|
||||
}
|
||||
|
||||
auto dir = GetSubdirectory(vec[0]);
|
||||
for (std::size_t component = 1; component < vec.size() - 1; ++component) {
|
||||
if (dir == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
dir = dir->GetSubdirectory(vec[component]);
|
||||
std::string_view component = *next_component;
|
||||
if (++next_component == component_view.end()) {
|
||||
return GetFile(component);
|
||||
}
|
||||
|
||||
auto dir = GetSubdirectory(component);
|
||||
if (dir == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
component = *next_component;
|
||||
|
||||
return dir->GetFile(vec.back());
|
||||
while (++next_component != component_view.end()) {
|
||||
dir = dir->GetSubdirectory(component);
|
||||
if (dir == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
component = *next_component;
|
||||
}
|
||||
|
||||
return dir->GetFile(component);
|
||||
}
|
||||
|
||||
VirtualFile VfsDirectory::GetFileAbsolute(std::string_view path) const {
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
"fmt",
|
||||
"lz4",
|
||||
"nlohmann-json",
|
||||
"range-v3",
|
||||
"zlib",
|
||||
"zstd"
|
||||
],
|
||||
|
|
Loading…
Add table
Reference in a new issue