# intersect — benchmark

Workload: 10_000 rows; `filter(active) ∩ filter(val > 50)`. Tick mutates
either `active` or `val` on one row. Batch streams 1000 such ticks.
Generated by [comparisons/bench/operators/intersect.bench.ts](../../comparisons/bench/operators/intersect.bench.ts).

| Library | Setup (ms) | Single (ms) | vs data | Batch 1000 (ms) | vs data |
|---|---:|---:|---:|---:|---:|
| **data** | 4.51 | **0.126** | — | **2.35** | — |
| svelte-store | 1.16 | 0.434 | 3.4× | 554.15 | 236× |
| rxjs | 1.42 | 0.528 | 4.2× | 541.40 | 230× |
| react | 1.59 | 0.595 | 4.7× | 749.09 | 319× |
| preact-signals | 2.62 | 0.769 | 6.1× | 16.53 | 7.0× |
| solid | 6.05 | 2.72 | 21.6× | 58.60 | 24.9× |
| crossfilter | 12.44 | 3.08 | 24.4× | 1036.09 | 441× |
| mobx | 163.96 | 11.75 | 93.3× | 174.87 | 74.4× |
| vue-reactivity | 25.53 | 17.08 | 136× | 589.97 | 251× |



data is fastest on both single (3.7x over rxjs) and batch (4.7x over
preact-signals).

## How

`intersect` uses a bitmask: each source gets a bit, a row enters the
output only when `bits === all` (every bit set). Each per-source delta
threads through in O(1) ([operators/intersect/index.ts](index.ts)).
The crossfilter-shape (multi-dimension brushing) is exactly what this
operator was designed for.

Run `BENCH_OPS=intersect npm run bench:ops` to refresh.
