mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-08-16 23:31:24 +00:00
Server::make_matcher() built a std::regex for every pattern that did not contain "/:", even though most route patterns are plain literals with no regular expression syntax in them. Matching those went through std::regex_match on every request, for every registered route the dispatcher scanned before reaching the one that matches. PathParamsMatcher already performs an exact literal comparison when it captures no parameter, so no new matcher class is needed: a pattern with no regex metacharacter can simply use it. Add an early return for the zero parameter case in PathParamsMatcher::match(), and select the matcher by also looking for the 14 ECMAScript metacharacters instead of only for "/:". Path params keep taking precedence, so a pattern that mixes both, such as "/users/:id/(.*)", is unaffected. Measured with clang -O2 on macOS, scanning routes that all miss until the last one: at 100 routes a scan drops from 10.3us to 0.46us, and end to end throughput rises by about 24%. At 1000 routes throughput is roughly 3 times higher. Registering 5000 routes drops from about 3.0ms to about 0.9ms, since no std::regex is built for literal patterns. This also keeps CPPHTTPLIB_REGEX_ROUTE_PATH_MAX_LENGTH confined to the routes it is meant for. That limit rejects overlong paths before calling std::regex_match, but until now every literal route was a RegexMatcher too, so a literal route longer than the limit stopped matching even though no regular expression was involved. Literal routes no longer go through RegexMatcher, so only real regex routes are capped. Patterns containing a metacharacter keep their current behavior, so "/index.html" still matches "/indexXhtml" the way it always has. One visible change: a literal route no longer populates Request::matches, which is now a default constructed std::smatch. Path parameter routes have always behaved that way, and Request::matches only carries useful information for regex routes.