Skip to content

♻️ Refactor: Improve performance analyseConstantPart#3753

Merged
ReneWerner87 merged 4 commits intogofiber:mainfrom
ksw2000:refact-findNextParamPosition
Sep 22, 2025
Merged

♻️ Refactor: Improve performance analyseConstantPart#3753
ReneWerner87 merged 4 commits intogofiber:mainfrom
ksw2000:refact-findNextParamPosition

Conversation

@ksw2000
Copy link
Member

@ksw2000 ksw2000 commented Sep 20, 2025

Description

  • Refactor functions findNextCharsetPosition, findNextCharsetPositionConstraint, and findNextNonEscapedCharsetPosition to reduce time complexity from O(len(search)len(charset)) to O(len(search)) and inline them into the function analyseParameterPart.
  • Improve the performance of findNextParamPosition.
goos: linux
goarch: amd64
pkg: github.com/gofiber/fiber/v3
cpu: AMD EPYC 7763 64-Core Processor                
                                                                              │   old.txt   │               new.txt               │
                                                                              │   sec/op    │   sec/op     vs base                │
_RoutePatternMatch//api/v1/const_|_match_|_/api/v1/const-2                      227.8n ± 2%   207.8n ± 5%   -8.82% (p=0.000 n=20)
_RoutePatternMatch//api/v1/const_|_not_match_|_/api/v1-2                        218.5n ± 5%   202.2n ± 3%   -7.44% (p=0.000 n=20)
_RoutePatternMatch//api/v1/const_|_not_match_|_/api/v1/-2                       219.0n ± 3%   204.3n ± 3%   -6.71% (p=0.000 n=20)
_RoutePatternMatch//api/v1/const_|_not_match_|_/api/v1/something-2              221.8n ± 3%   204.8n ± 6%   -7.66% (p=0.000 n=20)
_RoutePatternMatch//api/:param/fixedEnd_|_match_|_/api/abc/fixedEnd-2           665.9n ± 3%   559.4n ± 4%  -15.99% (p=0.000 n=20)
_RoutePatternMatch//api/:param/fixedEnd_|_not_match_|_/api/abc/def/fixedEnd-2   653.5n ± 3%   566.1n ± 4%  -13.37% (p=0.000 n=20)
_RoutePatternMatch//api/v1/:param/*_|_match_|_/api/v1/entity-2                  752.5n ± 4%   606.9n ± 5%  -19.35% (p=0.000 n=20)
_RoutePatternMatch//api/v1/:param/*_|_match_|_/api/v1/entity/-2                 740.9n ± 3%   598.2n ± 3%  -19.26% (p=0.000 n=20)
_RoutePatternMatch//api/v1/:param/*_|_match_|_/api/v1/entity/1-2                725.4n ± 4%   605.9n ± 4%  -16.47% (p=0.000 n=20)
_RoutePatternMatch//api/v1/:param/*_|_not_match_|_/api/v-2                      701.0n ± 2%   566.0n ± 5%  -19.26% (p=0.000 n=20)
_RoutePatternMatch//api/v1/:param/*_|_not_match_|_/api/v2-2                     698.8n ± 4%   564.9n ± 2%  -19.15% (p=0.000 n=20)
_RoutePatternMatch//api/v1/:param/*_|_not_match_|_/api/v1/-2                    730.6n ± 3%   582.8n ± 4%  -20.24% (p=0.000 n=20)
geomean                                                                         480.7n        410.4n       -14.63%

                                                                              │  old.txt   │               new.txt               │
                                                                              │    B/op    │    B/op     vs base                 │
_RoutePatternMatch//api/v1/const_|_match_|_/api/v1/const-2                      128.0 ± 0%   128.0 ± 0%       ~ (p=1.000 n=20) ¹
_RoutePatternMatch//api/v1/const_|_not_match_|_/api/v1-2                        128.0 ± 0%   128.0 ± 0%       ~ (p=1.000 n=20) ¹
_RoutePatternMatch//api/v1/const_|_not_match_|_/api/v1/-2                       128.0 ± 0%   128.0 ± 0%       ~ (p=1.000 n=20) ¹
_RoutePatternMatch//api/v1/const_|_not_match_|_/api/v1/something-2              128.0 ± 0%   128.0 ± 0%       ~ (p=1.000 n=20) ¹
_RoutePatternMatch//api/:param/fixedEnd_|_match_|_/api/abc/fixedEnd-2           368.0 ± 0%   368.0 ± 0%       ~ (p=1.000 n=20) ¹
_RoutePatternMatch//api/:param/fixedEnd_|_not_match_|_/api/abc/def/fixedEnd-2   368.0 ± 0%   368.0 ± 0%       ~ (p=1.000 n=20) ¹
_RoutePatternMatch//api/v1/:param/*_|_match_|_/api/v1/entity-2                  416.0 ± 0%   416.0 ± 0%       ~ (p=1.000 n=20) ¹
_RoutePatternMatch//api/v1/:param/*_|_match_|_/api/v1/entity/-2                 416.0 ± 0%   416.0 ± 0%       ~ (p=1.000 n=20) ¹
_RoutePatternMatch//api/v1/:param/*_|_match_|_/api/v1/entity/1-2                416.0 ± 0%   416.0 ± 0%       ~ (p=1.000 n=20) ¹
_RoutePatternMatch//api/v1/:param/*_|_not_match_|_/api/v-2                      416.0 ± 0%   416.0 ± 0%       ~ (p=1.000 n=20) ¹
_RoutePatternMatch//api/v1/:param/*_|_not_match_|_/api/v2-2                     416.0 ± 0%   416.0 ± 0%       ~ (p=1.000 n=20) ¹
_RoutePatternMatch//api/v1/:param/*_|_not_match_|_/api/v1/-2                    416.0 ± 0%   416.0 ± 0%       ~ (p=1.000 n=20) ¹
geomean                                                                         275.2        275.2       +0.00%
¹ all samples are equal

                                                                              │  old.txt   │               new.txt               │
                                                                              │ allocs/op  │ allocs/op   vs base                 │
_RoutePatternMatch//api/v1/const_|_match_|_/api/v1/const-2                      3.000 ± 0%   3.000 ± 0%       ~ (p=1.000 n=20) ¹
_RoutePatternMatch//api/v1/const_|_not_match_|_/api/v1-2                        3.000 ± 0%   3.000 ± 0%       ~ (p=1.000 n=20) ¹
_RoutePatternMatch//api/v1/const_|_not_match_|_/api/v1/-2                       3.000 ± 0%   3.000 ± 0%       ~ (p=1.000 n=20) ¹
_RoutePatternMatch//api/v1/const_|_not_match_|_/api/v1/something-2              3.000 ± 0%   3.000 ± 0%       ~ (p=1.000 n=20) ¹
_RoutePatternMatch//api/:param/fixedEnd_|_match_|_/api/abc/fixedEnd-2           9.000 ± 0%   9.000 ± 0%       ~ (p=1.000 n=20) ¹
_RoutePatternMatch//api/:param/fixedEnd_|_not_match_|_/api/abc/def/fixedEnd-2   9.000 ± 0%   9.000 ± 0%       ~ (p=1.000 n=20) ¹
_RoutePatternMatch//api/v1/:param/*_|_match_|_/api/v1/entity-2                  8.000 ± 0%   8.000 ± 0%       ~ (p=1.000 n=20) ¹
_RoutePatternMatch//api/v1/:param/*_|_match_|_/api/v1/entity/-2                 8.000 ± 0%   8.000 ± 0%       ~ (p=1.000 n=20) ¹
_RoutePatternMatch//api/v1/:param/*_|_match_|_/api/v1/entity/1-2                8.000 ± 0%   8.000 ± 0%       ~ (p=1.000 n=20) ¹
_RoutePatternMatch//api/v1/:param/*_|_not_match_|_/api/v-2                      8.000 ± 0%   8.000 ± 0%       ~ (p=1.000 n=20) ¹
_RoutePatternMatch//api/v1/:param/*_|_not_match_|_/api/v2-2                     8.000 ± 0%   8.000 ± 0%       ~ (p=1.000 n=20) ¹
_RoutePatternMatch//api/v1/:param/*_|_not_match_|_/api/v1/-2                    8.000 ± 0%   8.000 ± 0%       ~ (p=1.000 n=20) ¹
geomean                                                                         5.883        5.883       +0.00%
¹ all samples are equal

Changes introduced

List the new features or adjustments introduced in this pull request. Provide details on benchmarks, documentation updates, changelog entries, and if applicable, the migration guide.

  • Benchmarks: Describe any performance benchmarks and improvements related to the changes.
  • Documentation Update: Detail the updates made to the documentation and links to the changed files.
  • Changelog/What's New: Include a summary of the additions for the upcoming release notes.
  • Migration Guide: If necessary, provide a guide or steps for users to migrate their existing code to accommodate these changes.
  • API Alignment with Express: Explain how the changes align with the Express API.
  • API Longevity: Discuss the steps taken to ensure that the new or updated APIs are consistent and not prone to breaking changes.
  • Examples: Provide examples demonstrating the new features or changes in action.

Type of change

Please delete options that are not relevant.

  • Enhancement (improvement to existing features and functionality)

Checklist

Before you submit your pull request, please make sure you meet these requirements:

  • Followed the inspiration of the Express.js framework for new functionalities, making them similar in usage.
  • Conducted a self-review of the code and provided comments for complex or critical parts.
  • Updated the documentation in the /docs/ directory for Fiber's documentation.
  • Added or updated unit tests to validate the effectiveness of the changes or new features.
  • Ensured that new and existing unit tests pass locally with the changes.
  • Verified that any new dependencies are essential and have been agreed upon by the maintainers/community.
  • Aimed for optimal performance with minimal allocations in the new code.
  • Provided benchmarks for the new code to analyze and improve upon.

@ksw2000 ksw2000 requested a review from a team as a code owner September 20, 2025 06:28
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 20, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Refactors parameter parsing in path.go: replaces charset helper scans with 256-entry boolean tables and inlines parameter end/constraint detection inside analyseParameterPart. Several charset-position helper functions were removed. No exported/public signatures changed.

Changes

Cohort / File(s) Summary
Parameter start detection rewrite
path.go
Replaced parameterStartChars slice with a [256]bool table and rewrote findNextParamPosition to perform an unescaped linear scan using that table to detect parameter/wildcard/plus starts.
Parameter end & constraint handling
path.go
Rewrote analyseParameterPart to inline end/constraint detection: introduces paramEndPosition, paramConstraintStartPosition, paramConstraintEndPosition, and uses a parameterEndChars set for boundary detection; updates slicing, constraint extraction, and optional/wildcard/plus handling.
Removed helper position finders
path.go
Removed helper functions (findNextCharsetPosition, findNextCharsetPositionConstraint, findNextNonEscapedCharsetPosition) and migrated their logic into the inlined scans within analyseParameterPart.
Variable & usage adjustments
path.go
Eliminated prior charset helper usage and declarations; introduced local boolean maps and updated all usages to reference paramEndPosition and the new local maps during parsing and route-segment assembly.
Parsing/control-flow consolidation
path.go
Consolidated parsing flow by embedding unescaped scanning and constraint handling directly in the analyzer, simplifying inter-function navigation and removing indirect charset helpers.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Caller
  participant Parser as parseRoute
  participant Analyzer as analyseParameterPart

  Caller->>Parser: parseRoute(pattern)
  Parser->>Analyzer: examine next segment (byte slice)
  Note over Analyzer: build 256-entry boolean table\nscan unescaped bytes for start\ntrack paramEnd/constraintStart/constraintEnd
  Analyzer-->>Parser: segment info (start, end, name, constraint, flags)
  Parser-->>Caller: compiled route segment
Loading
sequenceDiagram
  rect rgba(230,245,255,0.6)
  Note over Parser,Helpers: Old flow used multiple charset helper functions
  participant Parser
  participant Helpers as CharsetHelpers
  Parser->>Helpers: findNextCharsetPosition(...)
  Helpers-->>Parser: index
  Parser->>Helpers: findNextNonEscapedCharsetPosition(...)
  Helpers-->>Parser: index
  Parser->>Analyzer: analyseParameterPart(with indices)
  end

  rect rgba(235,255,235,0.6)
  Note over Parser,Analyzer: New flow inlines scanning and detection
  participant Parser
  participant Analyzer
  Parser->>Analyzer: analyseParameterPart(slice)
  Analyzer->>Analyzer: inline boolean-table + per-byte unescaped checks\ncompute paramEnd/constraint positions
  Analyzer-->>Parser: result
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • sixcolors
  • efectn
  • ReneWerner87
  • gaby

Poem

I hop through bytes with whiskers keen,
A tiny table shows what's seen.
Helpers gone, I sniff the trail,
I scan unescaped without fail.
Routes are tidy — rabbit's grin! 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Title Check ⚠️ Warning The provided title refers to “analyseConstantPart” and promises a performance refactor for that function, but the actual changes focus on parameter parsing functions such as analyseParameterPart and findNextParamPosition, not any “analyseConstantPart” entity. As a result, the title misrepresents the core refactor and may confuse reviewers about the patch’s true scope and intent. It should succinctly reflect the main performance improvements to parameter parsing logic. Please update the title to accurately summarize the primary change—for example, “♻️ Refactor: Improve performance of analyseParameterPart and findNextParamPosition”—removing any reference to non-existent or irrelevant functions and ensuring concise, clear phrasing. Consider dropping emojis if they are not part of the repository’s title conventions.
Description Check ⚠️ Warning The description does open with a technical summary and benchmark data, but it does not follow the repository’s template: it omits a “Fixes #…” issue reference, leaves the “Changes introduced” section entirely unpopulated, and retains checklist placeholders instead of deleting or completing them to reflect actual documentation updates, changelog entries, migration guidance, or examples. Consequently, key contextual details that help reviewers verify completeness are missing. Please add a “Fixes #…” line to link this PR to its related issue, fill in the “Changes introduced” section with actual details such as benchmark summaries, documentation updates, changelog entries, migration steps, and usage examples or remove those checklist items if they do not apply, and delete any unused template placeholders to clearly indicate which sections are complete.
✅ Passed checks (1 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @ksw2000, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request delivers a crucial optimization to the route pattern matching mechanism within the Fiber framework. By streamlining the character search logic and integrating helper functions directly into the core parsing methods, the change dramatically improves the efficiency of route analysis. This enhancement translates to faster request processing and a more performant application overall, without introducing any additional memory overhead.

Highlights

  • Performance Enhancement: The time complexity of parameter parsing functions has been reduced from O(len(search)len(charset)) to O(len(search)), leading to significant speed improvements.
  • Code Refactoring and Inlining: Several helper functions, specifically findNextCharsetPosition, findNextCharsetPositionConstraint, and findNextNonEscapedCharsetPosition, have been inlined directly into analyseParameterPart and findNextParamPosition for better performance and reduced overhead.
  • Benchmark Improvements: Benchmarking results demonstrate notable performance gains, with sec/op reductions ranging from 8.82% to 20.24% across various route pattern matching scenarios, while memory allocations remain unchanged.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@ksw2000 ksw2000 changed the title ♻️ Refactor: Improve performance findNextParamPosition ♻️ Refactor: Improve performance analyseConstantPart Sep 20, 2025
@codecov
Copy link

codecov bot commented Sep 20, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.50%. Comparing base (1471049) to head (a1f4cf7).
⚠️ Report is 3 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3753      +/-   ##
==========================================
- Coverage   91.93%   91.50%   -0.43%     
==========================================
  Files         113      113              
  Lines       11700    11778      +78     
==========================================
+ Hits        10756    10778      +22     
- Misses        684      735      +51     
- Partials      260      265       +5     
Flag Coverage Δ
unittests 91.50% <100.00%> (-0.43%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request successfully refactors the path parsing logic for a significant performance improvement, primarily by replacing character set searches with lookup tables. The benchmarks clearly demonstrate the effectiveness of this optimization. The code is cleaner and more efficient. I've identified one edge-case bug in the new findNextParamPosition function concerning parameter clusters at the end of a string and have provided a suggested fix.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
path.go (2)

279-283: Fix formatting issue detected by gofumpt.

The linter reports that the file is not properly formatted. The indentation on line 279 appears incorrect.

Apply this diff to fix the formatting:

-	var search = [256]bool{
+	search := [256]bool{
 		wildcardParam:    true,
 		plusParam:        true,
 		paramStarterChar: true,
 	}

318-361: Consider extracting constraint parsing logic for better maintainability.

The analyseParameterPart function is complex with deeply nested logic for handling constraints and parameter endings. Consider extracting the constraint boundary detection (lines 339-354) into a separate helper function for improved readability and testability.

Example refactor approach:

func findConstraintBoundaries(search string) (start, end int) {
    start, end = -1, -1
    for i := range search {
        if start == -1 && search[i] == '<' && (i == 0 || search[i-1] != escapeChar) {
            start = i + 1
            continue
        }
        if end == -1 && search[i] == '>' && (i == 0 || search[i-1] != escapeChar) {
            end = i + 1
            break
        }
    }
    return start, end
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1471049 and 364ab7e.

📒 Files selected for processing (1)
  • path.go (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

**/*.go: Format Go code using gofumpt (enforced via make format)
Ensure code passes golangci-lint checks (enforced via make lint)
Optimize struct field alignment using betteralign (enforced via make betteralign)
Modernize Go code using gopls modernize (enforced via make modernize)

Files:

  • path.go
🪛 GitHub Check: lint
path.go

[failure] 279-279:
File is not properly formatted (gofumpt)

🪛 GitHub Actions: golangci-lint
path.go

[error] 279-279: golangci-lint: path.go:279:1 - File is not properly formatted (gofumpt)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: unit (1.25.x, macos-latest)
  • GitHub Check: unit (1.25.x, windows-latest)
  • GitHub Check: unit (1.25.x, macos-13)
  • GitHub Check: repeated
  • GitHub Check: Analyse
  • GitHub Check: Compare
🔇 Additional comments (3)
path.go (3)

276-300: Well-optimized parameter detection using lookup table.

The refactored implementation efficiently reduces time complexity from O(len(search) * len(charset)) to O(len(search)) by using a 256-entry boolean lookup table instead of charset scanning. This is a clean, performant approach that aligns well with the reported benchmark improvements.


327-361: Good performance improvement with inlined end detection.

The refactored implementation successfully inlines the parameter end detection logic, eliminating the need for helper functions and reducing function call overhead. This contributes to the measured latency improvements while maintaining correct functionality.


343-345: Incorrect variable reference in constraint end detection.

Line 343 references paramConstraintEnd (a byte constant defined as '>') but should reference the local variable for comparison.

Apply this diff to fix the variable reference:

-			if parameterConstraintEnd == -1 && search[i] == paramConstraintEnd && (i == 0 || search[i-1] != escapeChar) {
+			if parameterConstraintEnd == -1 && search[i] == '>' && (i == 0 || search[i-1] != escapeChar) {
 				parameterConstraintEnd = i + 1

Likely an incorrect or invalid review comment.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
path.go (2)

284-300: Fix parameter cluster termination logic.

The logic for handling parameter clusters has the same issue identified in the previous reviews. When a cluster of parameter start characters extends to the end of the pattern, the function returns next (the start index) instead of the correct end index.

Apply this fix to handle clusters that extend to the pattern end:

 	if next > 0 && pattern[next] != wildcardParam {
 		// checking the found parameterStartChar is a cluster
 		for i := next + 1; i < len(pattern); i++ {
 			if !search[pattern[i]] {
 				return i - 1
 			}
 		}
-		next = len(pattern) - 1
+		return len(pattern) - 1
 	}
 	return next

340-341: Fix incorrect variable reference in constraint detection.

The condition incorrectly references the byte constant paramConstraintStart instead of the local variable parameterConstraintStart for comparison.

Apply this diff to fix the variable reference:

-		if parameterConstraintStart == -1 && search[i] == paramConstraintStart && (i == 0 || search[i-1] != escapeChar) {
+		if parameterConstraintStart == -1 && search[i] == '<' && (i == 0 || search[i-1] != escapeChar) {
 			parameterConstraintStart = i + 1
🧹 Nitpick comments (1)
path.go (1)

351-351: Consider using explicit boolean logic for clarity.

The XOR operation parameterConstraintStart^parameterConstraintEnd >= 0 is mathematically correct but could be more readable.

Consider this more explicit approach for better readability:

-			if parameterConstraintStart^parameterConstraintEnd >= 0 {
+			if (parameterConstraintStart == -1 && parameterConstraintEnd == -1) ||
+			   (parameterConstraintStart != -1 && parameterConstraintEnd != -1) {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 364ab7e and a5cf250.

📒 Files selected for processing (1)
  • path.go (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

**/*.go: Format Go code using gofumpt (enforced via make format)
Ensure code passes golangci-lint checks (enforced via make lint)
Optimize struct field alignment using betteralign (enforced via make betteralign)
Modernize Go code using gopls modernize (enforced via make modernize)

Files:

  • path.go
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: unit (1.25.x, windows-latest)
  • GitHub Check: repeated
  • GitHub Check: Compare
🔇 Additional comments (4)
path.go (4)

279-283: LGTM: Effective optimization using boolean lookup table.

The use of a 256-entry boolean array for character lookup is well-suited for Go, where booleans are represented as bytes, providing O(1) lookup performance while maintaining simplicity. This table-driven approach effectively replaces the previous charset-based string searches with direct array indexing.


329-336: LGTM: Efficient parameter end detection using boolean table.

The implementation correctly uses a boolean table for quick character classification, properly identifying parameter end characters including delimiters and special characters. This approach maintains the same O(1) character lookup performance as the parameter start detection.


344-346: LGTM: Correct constraint end detection.

The constraint end detection properly references the byte constant paramConstraintEnd and correctly updates the local variable parameterConstraintEnd.


357-362: LGTM: Proper parameter end position handling.

The logic correctly handles different cases for parameter end position determination, including when no end is found and when additional character checking is needed. The boundary conditions are properly managed.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (8)
path.go (8)

279-284: Hoist the lookup table to avoid per-call init cost.

Make the 256-entry search table a package-level var and reuse it. It’s tiny but this function is hot.

Apply:

-	search := [256]bool{
-		wildcardParam:    true,
-		plusParam:        true,
-		paramStarterChar: true,
-	}
+	search := paramStartLookup

Add outside the function:

var paramStartLookup = [256]bool{
	wildcardParam:    true,
	plusParam:        true,
	paramStarterChar: true,
}

285-290: Iterate by byte, not rune.

Use a byte-indexed loop to avoid rune decoding overhead in this hot path.

-	for i := range pattern {
+	for i := 0; i < len(pattern); i++ {

323-361: End-of-parameter scan: boundary conditions look good; small clarity tweak suggested.

Logic is correct. For readability and to prevent future off-by-one regressions, consider storing base := 1 and commenting that indices in this block are relative to pattern[1:].


365-367: Guard against impossible negatives (defensive only).

paramEndPosition can’t be -1 here due to the switch above, but a cheap assert helps future edits.

-	processedPart := pattern[0 : paramEndPosition+1]
+	// paramEndPosition >= 0 guaranteed by switch above
+	processedPart := pattern[0 : paramEndPosition+1]

372-373: Constraint slice indexes are correct; add a fast-path when empty.

If < > are adjacent (empty constraints), skip parsing to avoid allocating an empty slice.

-		constraintString := pattern[paramConstraintStartPosition+1 : paramConstraintEndPosition]
+		constraintString := pattern[paramConstraintStartPosition+1 : paramConstraintEndPosition]
+		if len(constraintString) == 0 {
+			// treat as no constraints: <>
+			goto build_segment
+		}

417-417: Correct name extraction with constraints; add trim for trailing spaces.

If users accidentally put spaces before <, trimming avoids surprising param names.

-		paramName = RemoveEscapeChar(GetTrimmedParam(pattern[0:paramConstraintStartPosition]))
+		paramName = RemoveEscapeChar(GetTrimmedParam(strings.TrimRight(pattern[0:paramConstraintStartPosition], " ")))

432-432: Optional flag detection is right; consider guarding wildcard early.

Minor: short-circuit IsOptional for wildcards to avoid indexing.

-		IsOptional: isWildCard || pattern[paramEndPosition] == optionalParam,
+		IsOptional: isWildCard || (!isWildCard && pattern[paramEndPosition] == optionalParam),

279-299: Add focused tests for escapes, clusters, and constraints.

These fast paths are easy to regress. Please add unit tests covering:

  • Escaped starters: "\:a", "\\:a" (escaped vs. double-escaped)
  • Cluster at EOF: "a::", "a++", "a*:"
  • Constraints with/without data: ":id<min(3)>", ":id<>", nested escaped "<regex(\>)>"
  • Optional marker inclusion: ":id?" and with trailing delimiter ":id?/"

I can draft them if helpful.

Also applies to: 323-361, 365-367, 372-373, 417-417, 432-432

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a5cf250 and 2f40775.

📒 Files selected for processing (1)
  • path.go (4 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

**/*.go: Format Go code using gofumpt (enforced via make format)
Ensure code passes golangci-lint checks (enforced via make lint)
Optimize struct field alignment using betteralign (enforced via make betteralign)
Modernize Go code using gopls modernize (enforced via make modernize)

Files:

  • path.go
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: unit (1.25.x, macos-latest)
  • GitHub Check: unit (1.25.x, windows-latest)
  • GitHub Check: unit (1.25.x, macos-13)
  • GitHub Check: repeated
  • GitHub Check: Compare
🔇 Additional comments (1)
path.go (1)

291-299: Approve — cluster termination fix is correct.
findNextParamPosition handles the fall‑through‑at‑EOF case and returning len(pattern)-1 for clusters that run to the string end is correct (verified in path.go); no changes required.

@ReneWerner87
Copy link
Member

@ksw2000 thx

@gaby gaby moved this to In Progress in v3 Sep 20, 2025
Copy link
Member

@gaby gaby left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
path.go (2)

123-138: Consider moving character maps to package level as suggested.

Per the previous review comment, these boolean maps could be moved outside the functions to the package level for better organization and easier expansion. This change would have minimal performance impact while improving code maintainability.

Consider moving these maps outside the var block to package level:

// Character lookup tables for parameter parsing
var (
	parameterStartChars = [256]bool{
		wildcardParam:    true,
		plusParam:        true,
		paramStarterChar: true,
	}
	parameterEndChars = [256]bool{
		optionalParam:    true,
		paramStarterChar: true,
		escapeChar:       true,
		slashDelimiter:   true,
		'-':              true,
		'.':              true,
	}
)

294-311: Fix handling of parameter clusters extending to pattern end.

The current implementation correctly handles parameter clusters that extend to the end of the pattern by returning len(pattern) - 1 on line 308. However, there's a logical issue with the condition on line 301 - it should check next != -1 instead of next > 0 to properly handle clusters starting at position 0.

Apply this diff to fix the cluster detection logic:

-	if next > 0 && pattern[next] != wildcardParam {
+	if next != -1 && pattern[next] != wildcardParam {
		// checking the found parameterStartChar is a cluster
		for i := next + 1; i < len(pattern); i++ {
			if !parameterStartChars[pattern[i]] {
				return i - 1
			}
		}
		return len(pattern) - 1
	}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2f40775 and a1f4cf7.

📒 Files selected for processing (1)
  • path.go (5 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.go

📄 CodeRabbit inference engine (AGENTS.md)

**/*.go: Format Go code using gofumpt (enforced via make format)
Ensure code passes golangci-lint checks (enforced via make lint)
Optimize struct field alignment using betteralign (enforced via make betteralign)
Modernize Go code using gopls modernize (enforced via make modernize)

Files:

  • path.go
🔇 Additional comments (5)
path.go (5)

338-364: LGTM! Efficient inlined parameter end detection.

The refactored logic successfully inlines the parameter end detection, replacing the previous helper functions with a single efficient scan. The boolean array lookup for parameterEndChars provides O(1) character checking, and the constraint boundary detection is correctly integrated.


342-342: Fix incorrect variable reference in constraint detection.

Line 342 incorrectly references paramConstraintStart (the byte constant) instead of paramConstraintStartPosition (the local variable). This causes the condition to always evaluate incorrectly.

This issue was already identified in previous reviews and should be fixed as indicated.


367-368: LGTM! Consistent variable naming and usage.

The parameter end position calculation and usage is now consistent throughout the function, properly using paramEndPosition for both the processed part extraction and length calculation.


374-420: LGTM! Proper constraint boundary handling.

The constraint extraction logic correctly uses the new paramConstraintStartPosition and paramConstraintEndPosition variables, and the parameter name extraction properly accounts for the constraint boundaries when present.


434-434: LGTM! Correct optional parameter detection.

The optional parameter detection correctly uses paramEndPosition to check the character at the parameter's end position, maintaining the same logic as before but with the new variable naming.

@ReneWerner87 ReneWerner87 merged commit 56929f2 into gofiber:main Sep 22, 2025
15 checks passed
@github-project-automation github-project-automation bot moved this from In Progress to Done in v3 Sep 22, 2025
Abhirup-99 pushed a commit to Abhirup-99/fiber that referenced this pull request Nov 3, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants