Skip to content

refactor(pulse): decompose monolithic core, optimize render allocations, and modularize test suite - #2

Merged
ingvarch merged 6 commits into
mainfrom
refactor/split-pulse-modules
Oct 1, 2026
Merged

ingvarch merged 6 commits into
mainfrom
refactor/split-pulse-modules

Conversation

@ingvarch

@ingvarch ingvarch commented Oct 1, 2026

Copy link
Copy Markdown
Owner

Description

This PR refactors the core charting package following Go best practices, Single Responsibility Principle (SRP), and memory optimization guidelines:

  1. Monolithic File Decomposition:

    • Decomposed pulse.go (1,305 lines) into 8 focused, single-responsibility modules:
      • pulse.go (318 lines): Core Model state, streaming window (Push, PushSeries), and Chart getters/setters.
      • view.go (115 lines): View() orchestrator, fmt.Stringer, and tick label calculation.
      • options.go (98 lines): Functional constructor options (With...).
      • event.go (150 lines): Timeline events, aging, pruning, EventsBox(), and shared pin/guideline rendering.
      • legend.go (37 lines): Multi-series legend presentation (Legend(), LegendBox()).
      • renderer.go (161 lines): Rendering contracts, coordinate math (spanOf, normOf, tickRowOf), and grid assembler.
      • renderer_lines.go (254 lines): Box-drawing curve engine, glyph masks, shaded and tinted fills.
      • renderer_braille.go (252 lines): Braille dot matrix and Catmull-Rom spline interpolation.
    • Every source file in the package is now strictly under 320 lines.
  2. DRY Event Rendering:

    • Unified event marker badges (▼, 🚀, ⚡) and vertical guidelines (┆) into shared helpers (eventsByColumn, renderEventPin, renderEventGuideline).
    • Eliminated duplicated event styling logic across LinesRenderer and BrailleRenderer.
  3. Performance & Memory Allocations:

    • Zero-copy Series Data in Render Loop: RenderContext now passes slice references directly (SeriesData [][]float64), eliminating redundant make([]float64) and copy() calls per series on every frame.
    • Contiguous Grid Backing Buffer: Refactored makeCells[T] to use a single continuous 1D buffer (make([]T, h*w)) with slice headers. Drops heap allocations by 76+ on every call to View().
  4. Defensive Range Normalization & Styling Constants:

    • Automatically swaps inverted ranges (min > max) in New and SetRange.
    • Extracted DefaultEventColor (#7dcfff) to replace scattered color string literals.
  5. Benchmark Suite:

    • Added pulse_bench_test.go covering View() across ModeLines, TintedFill, and ModeBraille, plus Push, LegendBox, and EventsBox with allocation tracking (b.ReportAllocs()).
  6. Test Suite Modularization:

    • Split pulse_test.go (673 lines) into domain test suites:
      • event_test.go (132 lines): sliding window aging, off-screen pruning, EventsBox.
      • legend_test.go (39 lines): Legend() and LegendBox().
      • renderer_test.go (274 lines): grid lines, fill modes, tinted and solid area fills, line styles, label widths.
      • pulse_test.go (237 lines): core model buffer, multi-series, range normalization, and tick sorting.

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Performance improvement / Refactoring

Checklist

  • I have read the CONTRIBUTING.md guide.
  • My code adheres to the project's code style and conventions (gofmt, go vet).
  • I have added tests that prove my fix is effective or that my feature works.
  • All existing and new tests pass (go test -race ./...).
  • I have updated any relevant documentation.

@ingvarch
ingvarch merged commit d596d73 into main Oct 1, 2026
2 checks passed
@ingvarch
ingvarch deleted the refactor/split-pulse-modules branch October 1, 2026 11:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant