From 048d0b67817a903b9fb4fe89139853eae57b7858 Mon Sep 17 00:00:00 2001 From: Kamil Monicz Date: Thu, 18 Dec 2025 03:26:35 +0000 Subject: [PATCH] libexpr: avoid regex engine in getDerivations attr filtering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - getDerivations() filters attribute names with std::regex_match, which runs the regex engine for every attribute visited during nixpkgs scanning. - BM_GetDerivationsAttrScan/10000_mean: 3.338 ms → 1.506 ms (≈ -54.9%) --- src/libexpr/get-drvs.cc | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/libexpr/get-drvs.cc b/src/libexpr/get-drvs.cc index c4a2b00af..a15f1085d 100644 --- a/src/libexpr/get-drvs.cc +++ b/src/libexpr/get-drvs.cc @@ -367,7 +367,26 @@ static std::string addToPath(const std::string & s1, std::string_view s2) return s1.empty() ? std::string(s2) : s1 + "." + s2; } -static std::regex attrRegex("[A-Za-z_][A-Za-z0-9-_+]*"); +static bool isAttrPathComponent(std::string_view symbol) +{ + if (symbol.empty()) + return false; + + /* [A-Za-z_] */ + unsigned char first = symbol[0]; + if (!((first >= 'A' && first <= 'Z') || (first >= 'a' && first <= 'z') || first == '_')) + return false; + + /* [A-Za-z0-9-_+]* */ + for (unsigned char c : symbol.substr(1)) { + if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '-' || c == '_' + || c == '+') + continue; + return false; + } + + return true; +} static void getDerivations( EvalState & state, @@ -400,7 +419,7 @@ static void getDerivations( std::string_view symbol{state.symbols[i->name]}; try { debug("evaluating attribute '%1%'", symbol); - if (!std::regex_match(symbol.begin(), symbol.end(), attrRegex)) + if (!isAttrPathComponent(symbol)) continue; std::string pathPrefix2 = addToPath(pathPrefix, symbol); if (combineChannels)