Skip to content

Conversation

@Shane32
Copy link
Owner

@Shane32 Shane32 commented Oct 7, 2025

Summary by CodeRabbit

  • Refactor
    • Optimized ASCII QR code generation for faster performance and lower memory usage.
    • Improved throughput for smaller QR sizes with reduced per-line allocations.
    • Preserves identical output and behavior; no public API changes.

@Shane32 Shane32 added this to the 1.7.0 milestone Oct 7, 2025
@Shane32 Shane32 self-assigned this Oct 7, 2025
@Shane32 Shane32 added the performance Performance related enhancements or benchmarks label Oct 7, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 7, 2025

📝 Walkthrough

Walkthrough

Replaces dynamic list with a pre-sized string[] for QR lines, adds a HAS_SPAN-guarded fast path using stack-allocated Span<char> when conditions allow, and updates the fallback to reuse a StringBuilder per line while computing capacities upfront and early-returning from the span path. (50 words)

Changes

Cohort / File(s) Summary
ASCII QR line construction optimization
QRCoder/ASCIIQRCode.cs
Replaced List<string> with pre-sized string[]; added HAS_SPAN fast path using stack-allocated Span<char> when dark/white token lengths match and capacity is small; precomputed sideLength and lineCapacity; fallback uses a reusable StringBuilder per line and writes directly into the array; early return from span path.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Caller
  participant ASCIIQRCode as ASCIIQRCode.Generate
  participant SpanPath as HAS_SPAN Fast Path
  participant Builder as StringBuilder Fallback

  Caller->>ASCIIQRCode: Generate ASCII QR lines
  ASCIIQRCode->>ASCIIQRCode: compute sideLength & lineCapacity
  alt HAS_SPAN enabled && token lengths equal && small capacity
    ASCIIQRCode->>SpanPath: stackalloc Span<char>, fill each line directly
    SpanPath-->>ASCIIQRCode: populated string[] lines
    ASCIIQRCode-->>Caller: return string[] lines
  else Fallback
    ASCIIQRCode->>Builder: reuse/reset builder per line, append blocks
    Builder-->>ASCIIQRCode: write resulting string into pre-sized array
    ASCIIQRCode-->>Caller: return string[] lines
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • gfoidl

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title accurately summarizes the main change in the pull request by indicating optimizations to the ASCII renderer component. It is concise, specific, and directly reflects the performance enhancements made in ASCIIQRCode.cs. It omits extraneous detail and avoids vague terms, making it easily understood by teammates.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch ascii_opt

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.

@Shane32 Shane32 requested a review from gfoidl October 7, 2025 21:28
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 (1)
QRCoder/ASCIIQRCode.cs (1)

71-74: Cache spans outside the hot loop

AsSpan() gets re-evaluated for every module even though the underlying strings never change. Caching var darkSpan = darkColorString.AsSpan(); / var whiteSpan = whiteSpaceString.AsSpan(); once before the loops lets you reuse them in the inner loop and avoids repeated method calls in this perf-sensitive path.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 317c587 and 9590d2e.

📒 Files selected for processing (1)
  • QRCoder/ASCIIQRCode.cs (2 hunks)
⏰ 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: Test .NET Core 2.1
  • GitHub Check: Test .NET Core 3.1
  • GitHub Check: Test .NET 5.0 Windows
  • GitHub Check: Test .NET 6.0 Windows
  • GitHub Check: additional-tests

Co-authored-by: Günther Foidl <[email protected]>
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 (1)
QRCoder/ASCIIQRCode.cs (1)

59-81: Verify the lineCapacity < 510 threshold.

The 510 limit leaves a 2-char safety buffer in the 512-char stackalloc, but this might unnecessarily exclude cases where lineCapacity is 510-512. Unless there's a specific reason for this buffer, consider using <= 512 to maximize the fast path coverage.

If the 2-char buffer is intentional, adding a brief comment explaining why would improve maintainability:

+        // Limit to 510 to leave buffer space for safety/alignment
         if (darkColorString.Length == whiteSpaceString.Length && lineCapacity < 510)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9590d2e and cef1680.

📒 Files selected for processing (1)
  • QRCoder/ASCIIQRCode.cs (2 hunks)
⏰ 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: Test .NET Framework 4.6.2
  • GitHub Check: Test .NET 6.0 Windows
  • GitHub Check: Test .NET Core 2.1
  • GitHub Check: Test .NET 5.0 Windows
  • GitHub Check: Test .NET Core 3.1
  • GitHub Check: additional-tests
🔇 Additional comments (3)
QRCoder/ASCIIQRCode.cs (3)

57-58: LGTM! Pre-allocation eliminates List overhead.

Pre-computing lineCapacity and switching to a fixed-size array removes dynamic growth costs and enables the span optimization below.


82-82: LGTM! StringBuilder capacity optimization.

Initializing the StringBuilder with lineCapacity and reusing it across iterations (with reset on line 94) eliminates repeated buffer allocations in the fallback path.


93-96: LGTM! Efficient array population and return.

Direct array indexing (line 93) and StringBuilder reset via Length = 0 (line 94) are efficient choices. The direct return of the pre-allocated array (line 96) completes the optimization, with GetGraphic (line 35) handling the join operation as needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

performance Performance related enhancements or benchmarks

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants