Charts: Remove repeated `ChartData.Values` snapshots

Merged
CO
2mo ago
+78-54

Internal chart calculations repeatedly materialized ChartData.Values, causing unnecessary allocations for large series while preserving the public snapshot API.

  • Live enumeration: Enumerate Points directly so current ChartPoint.Y values are returned.
  • Consumer cleanup: Replace snapshot-based Count, indexing, aggregation, and enumeration with Count, GetValue, and direct ChartData iteration across chart types, excluding HeatMap.
  • Equality and hashing: Preserve ChartSeries equality and first-ten-values hash semantics without snapshots.
  • Coverage: Add tests proving generic and non-generic enumeration observes mutated point values.
data[1].Y = 20.0;

data.ToList();                    // [1.0, 20.0]
((IEnumerable)data).Cast<double>(); // [1.0, 20.0]

Measured after merge

chartbeforeafter
line, 2 series × 500 points22,824,168 B / 29.3 ms5,680,216 B / 12.9 ms (−75.1% / −56%)
bar, 2 series × 200 points5,815,000 B / 6.3 ms2,255,384 B / 3.5 ms (−61.2% / −45%)

The largest single allocation saving of any change in this release. Rendered output is unchanged.

Instrument: a bare Renderer whose UpdateDisplayAsync does nothing, so the figures are render-tree work only. Release build, median of 5, this commit measured against its own parent so the numbers belong to this change alone.