`K` is the one type parameter people change, and it was last. Naming a
history in a struct field meant writing all four to say one thing:
struct Ladder { history: History<i64, ConstantDrift, NullObserver, String> }
struct Analysis<'h> { joint: Joint<'h, i64, ConstantDrift, NullObserver, &'static str> }
Now:
struct Ladder { history: History<String> }
struct Analysis<'h> { joint: Joint<'h> }
`History<K, T, D, O>`, all four defaulted. Bounds may reference later
parameters, so `D: Drift<T> = ConstantDrift` is legal in third position.
`Joint` gains the same defaults, so `Joint<'h, String>` spells it.
72 call sites swapped, and the reorder makes most of them shorter: 18
now read `History<String>` and the `&'static str` ones read `History`.
The two turbofished builders shrink from
`HistoryBuilder::<Untimed, _, _, String>::new()` to
`HistoryBuilder::<String, Untimed>::new()`.
`Joint` keeps `O` structurally, defaulted rather than removed. #72 notes
it never touches the observer, which is true — but it borrows the whole
`&'h History<K, T, D, O>` and calls `History::resolve_terms`, so dropping
the parameter means either a view type or moving that method off
`History`. The default already buys the entire user-visible benefit,
which was the spelling.
Refs #72.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011hcFjNDmHXZF8URGLku5zZ
63 lines
2.1 KiB
Rust
63 lines
2.1 KiB
Rust
//! Ingestion cost: one event per call versus one batched call.
|
|
//!
|
|
//! The rest of the suite only measures batched construction, which is why a
|
|
//! quadratic in the incremental path went unnoticed — `record_winner` and
|
|
//! `event(..).commit()` each ingest a single event, so a caller looping over a
|
|
//! match feed takes that path.
|
|
|
|
use std::hint::black_box;
|
|
|
|
use criterion::{BenchmarkId, Criterion, criterion_group, criterion_main};
|
|
use smallvec::smallvec;
|
|
use trueskill_tt::{Event, History, Member, Outcome, Team};
|
|
|
|
fn events(n: usize, time: i64) -> Vec<Event<i64, String>> {
|
|
(0..n)
|
|
.map(|i| Event {
|
|
time,
|
|
teams: smallvec![
|
|
Team::with_members([Member::new(format!("p{}", 2 * i))]),
|
|
Team::with_members([Member::new(format!("p{}", 2 * i + 1))]),
|
|
],
|
|
outcome: Outcome::winner(0, 2),
|
|
})
|
|
.collect()
|
|
}
|
|
|
|
fn bench_ingest(c: &mut Criterion) {
|
|
let mut group = c.benchmark_group("ingest");
|
|
|
|
for n in [250usize, 500, 1000] {
|
|
group.bench_with_input(BenchmarkId::new("one-at-a-time", n), &n, |b, &n| {
|
|
b.iter_batched(
|
|
|| events(n, 0),
|
|
|evs| {
|
|
let mut h: History<String> = History::builder().key_type::<String>().build();
|
|
for ev in evs {
|
|
h.add_events(std::iter::once(ev)).unwrap();
|
|
}
|
|
black_box(h.time_slices_len())
|
|
},
|
|
criterion::BatchSize::SmallInput,
|
|
);
|
|
});
|
|
|
|
group.bench_with_input(BenchmarkId::new("single-batch", n), &n, |b, &n| {
|
|
b.iter_batched(
|
|
|| events(n, 0),
|
|
|evs| {
|
|
let mut h: History<String> = History::builder().key_type::<String>().build();
|
|
h.add_events(evs).unwrap();
|
|
black_box(h.time_slices_len())
|
|
},
|
|
criterion::BatchSize::SmallInput,
|
|
);
|
|
});
|
|
}
|
|
|
|
group.finish();
|
|
}
|
|
|
|
criterion_group!(benches, bench_ingest);
|
|
criterion_main!(benches);
|