pub struct Fields(/* private fields */);Expand description
A record’s fields, sorted by name.
This was a BTreeMap, and a record is the wrong size for one: three to eight entries, built
once and read many times. A B-tree pays a node allocation and a pointer chase per level to buy
an asymptotic advantage that never arrives at that size, and profiling awfy/havlak.beck put
a fifth of the process inside its search, its insert and the memcmp underneath them.
Sorted by name and searched linearly: one allocation for the whole record, the names lie next
to each other in cache, and get compares lengths before bytes because it wants equality
rather than order. Iteration is in name order, so the value order, the state digest and the
wire format (crate::repr) are all bit-for-bit what the BTreeMap gave — which is what
makes this a representation change and not a semantic one.
Implementations§
Source§impl Fields
impl Fields
pub fn new() -> Fields
pub fn with_capacity(n: usize) -> Fields
pub fn get(&self, name: &str) -> Option<&Value>
Sourcepub fn insert(&mut self, name: Arc<str>, value: Value) -> Option<Value>
pub fn insert(&mut self, name: Arc<str>, value: Value) -> Option<Value>
Set name, keeping the order by name. Answers the value that was there.
The search is by equality and not by order, which is the whole difference: == on two
strs compares their lengths first and reaches memcmp only for a pair that could match,
where a binary search has to order every probe it makes. A record has three to eight
fields, so a scan makes at most as many comparisons as a binary search and nearly all of
them are an integer test. Only a field that is genuinely new pays for the ordered insert,
and with — which is what calls this in a loop — never has one.
Sourcepub fn from_pairs(pairs: Vec<(Arc<str>, Value)>) -> Fields
pub fn from_pairs(pairs: Vec<(Arc<str>, Value)>) -> Fields
Build from fields in any order, sorting once.
This is how a record literal is built, and it is a separate entry point from insert in a
loop because the two cost differently: sort_unstable_by on a handful of elements is an
insertion sort, which makes n - 1 comparisons and moves nothing when the fields already
arrive in order — as a record literal’s usually do.
Sourcepub fn from_sorted(pairs: Vec<(Arc<str>, Value)>) -> Fields
pub fn from_sorted(pairs: Vec<(Arc<str>, Value)>) -> Fields
Build from fields the caller has already put in order.
The caller is crate::fields, which decided the order once at compile time — a record
literal’s field names are written in the source, so sorting them once per record built is
work with a known answer. Nothing else should use this: the order is the Map iteration,
the state digest and the patch stream, so getting it wrong is a wire-format bug rather than
a slow lookup.