pond-ts 0.34.0 → 0.34.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -8,7 +8,8 @@ The `@pond-ts` packages — `pond-ts`, `@pond-ts/react`, `@pond-ts/charts`, and
8
8
  them all. Pre-1.0: minor bumps may include new features and type-level changes;
9
9
  patch bumps are strictly additive.
10
10
 
11
- [Unreleased]: https://github.com/pjm17971/pond-ts/compare/v0.34.0...HEAD
11
+ [Unreleased]: https://github.com/pjm17971/pond-ts/compare/v0.34.1...HEAD
12
+ [0.34.1]: https://github.com/pjm17971/pond-ts/compare/v0.34.0...v0.34.1
12
13
  [0.34.0]: https://github.com/pjm17971/pond-ts/compare/v0.33.0...v0.34.0
13
14
  [0.33.0]: https://github.com/pjm17971/pond-ts/compare/v0.32.0...v0.33.0
14
15
  [0.32.0]: https://github.com/pjm17971/pond-ts/compare/v0.31.2...v0.32.0
@@ -29,6 +30,29 @@ patch bumps are strictly additive.
29
30
  [0.19.0]: https://github.com/pjm17971/pond-ts/compare/v0.18.0...v0.19.0
30
31
  [0.18.0]: https://github.com/pjm17971/pond-ts/compare/v0.17.1...v0.18.0
31
32
 
33
+ ## [0.34.1] — 2026-07-01
34
+
35
+ A `pond-ts` core patch: fixes a performance regression introduced in 0.34.0.
36
+ `@pond-ts/react`, `@pond-ts/charts`, and `@pond-ts/fit` carry no code
37
+ changes — republished in lock-step; their `^0.34.0` peer ranges already
38
+ admit this patch.
39
+
40
+ ### Fixed
41
+
42
+ - **`TimeSeries.fromColumns` — `number[]` column conversion was ~7-18x
43
+ slower than intended.** The `null`/`NaN`-gap parity fix in 0.34.0
44
+ converted `number[]` columns via `Float64Array.from(raw, mapFn)`.
45
+ Supplying a map function forces V8's generic iterable-protocol path even
46
+ for a plain array, dramatically slower than a manual loop into a
47
+ preallocated buffer at 100k-element scale. Found while pointing the
48
+ `pond-columnar-ingest` wire-format spike at the real published package
49
+ instead of a local build. Fixed with a manual `for` loop in both the
50
+ key-column and value-column conversion paths — no behavior change, same
51
+ gap semantics, all 12 `fromColumns` tests unchanged and green. Added
52
+ `scripts/perf-from-columns.mjs` as the durable regression benchmark.
53
+ Measured: 100k × 7 cols, `number[]` columns, dense — 21.5ms → 2.9ms.
54
+ (#311)
55
+
32
56
  ## [0.34.0] — 2026-07-01
33
57
 
34
58
  A `pond-ts` core release: the columnar/typed-array ingress driven by the
@@ -535,10 +535,22 @@ export class TimeSeries {
535
535
  if (keyRaw === undefined) {
536
536
  throw new ValidationError(`fromColumns: missing key column '${keyDef.name}'`);
537
537
  }
538
- // epoch-ms buffer; TimeKeyColumn asserts all finite.
539
- const begin = keyRaw instanceof Float64Array
540
- ? keyRaw
541
- : Float64Array.from(keyRaw, (v) => (v == null ? NaN : Number(v)));
538
+ // epoch-ms buffer; TimeKeyColumn asserts all finite. A manual loop, not
539
+ // `Float64Array.from(arr, mapFn)`: supplying a map function forces V8's
540
+ // generic iterable-protocol path even for a plain array, ~15-20x slower
541
+ // than a preallocated-buffer copy at 100k-element scale measured, not
542
+ // theoretical (see the pond-columnar-ingest spike's ingest regression).
543
+ let begin;
544
+ if (keyRaw instanceof Float64Array) {
545
+ begin = keyRaw;
546
+ }
547
+ else {
548
+ begin = new Float64Array(keyRaw.length);
549
+ for (let j = 0; j < keyRaw.length; j += 1) {
550
+ const v = keyRaw[j];
551
+ begin[j] = v == null ? NaN : Number(v);
552
+ }
553
+ }
542
554
  const count = begin.length;
543
555
  // Throws on any non-finite timestamp.
544
556
  const keys = new TimeKeyColumn(begin, count);
@@ -579,9 +591,19 @@ export class TimeSeries {
579
591
  // the `Float64Array` branch's `Number.isFinite` gap signal — the same
580
592
  // wire value would silently mean different things depending on which
581
593
  // array type decoded it.
582
- const values = raw instanceof Float64Array
583
- ? raw
584
- : Float64Array.from(raw, (v) => (v == null ? NaN : v));
594
+ // Manual loop, not `Float64Array.from(arr, mapFn)` — see the key-column
595
+ // comment above; the cost applies identically here.
596
+ let values;
597
+ if (raw instanceof Float64Array) {
598
+ values = raw;
599
+ }
600
+ else {
601
+ values = new Float64Array(count);
602
+ for (let j = 0; j < count; j += 1) {
603
+ const v = raw[j];
604
+ values[j] = v == null ? NaN : v;
605
+ }
606
+ }
585
607
  const validity = validityFromPredicate(count, (j) => Number.isFinite(values[j]));
586
608
  columnMap.set(def.name, new Float64Column(values, count, validity, validity === undefined));
587
609
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pond-ts",
3
- "version": "0.34.0",
3
+ "version": "0.34.1",
4
4
  "description": "TypeScript-first time series primitives",
5
5
  "license": "MIT",
6
6
  "repository": {