From fc89e57e698a662d82d5d34ae77366c9752c355d Mon Sep 17 00:00:00 2001 From: Uri Tauber Date: Thu, 25 Jun 2026 09:01:50 +0300 Subject: [PATCH] perf: optimise `normalisePath` (#2162) --- lib/FsHelpers/FsHelpers.cpp | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/lib/FsHelpers/FsHelpers.cpp b/lib/FsHelpers/FsHelpers.cpp index 1e3c68a6..6b315633 100644 --- a/lib/FsHelpers/FsHelpers.cpp +++ b/lib/FsHelpers/FsHelpers.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include namespace FsHelpers { @@ -36,12 +37,14 @@ std::string decodeUriEscapes(const std::string& path) { } std::string normalisePath(const std::string& path) { - std::vector components; - std::string component; + std::vector components; + components.reserve(8); // Eight nested folders is more than we might expect - for (const auto c : path) { - if (c == '/') { - if (!component.empty()) { + size_t start = 0; + for (size_t i = 0; i <= path.length(); ++i) { + if (i == path.length() || path[i] == '/') { + if (i > start) { + std::string_view component(path.data() + start, i - start); if (component == "..") { if (!components.empty()) { components.pop_back(); @@ -49,23 +52,28 @@ std::string normalisePath(const std::string& path) { } else { components.push_back(component); } - component.clear(); } - } else { - component += c; + start = i + 1; } } - if (!component.empty()) { - components.push_back(component); + if (components.empty()) { + return ""; + } + + size_t total_len = 0; + for (const auto& c : components) { + total_len += c.length() + 1; } std::string result; - for (const auto& c : components) { - if (!result.empty()) { - result += "/"; + result.reserve(total_len - 1); + + for (size_t i = 0; i < components.size(); ++i) { + if (i > 0) { + result += '/'; } - result += c; + result.append(components[i].data(), components[i].length()); } return result;