use core::cmp::Ordering;
use super::DataValue;
const ORDERED_PROBE_MIN_PAIRS: usize = 32;
#[inline(always)]
fn key_cmp(a: &[u8], b: &[u8]) -> Ordering {
let n = a.len().min(b.len());
for i in 0..n {
if a[i] != b[i] {
return a[i].cmp(&b[i]);
}
}
a.len().cmp(&b.len())
}
#[inline]
fn ordered_probe<'a>(
pairs: &'a [(&'a str, DataValue<'a>)],
target: &str,
) -> Option<&'a DataValue<'a>> {
let tb = target.as_bytes();
let mut lo = 0usize;
let mut hi = pairs.len();
while lo < hi {
let mid = lo + (hi - lo) / 2;
match key_cmp(pairs[mid].0.as_bytes(), tb) {
Ordering::Less => lo = mid + 1,
Ordering::Greater => hi = mid,
Ordering::Equal => {
let mut i = mid;
while i > 0 && key_eq(pairs[i - 1].0, target) {
i -= 1;
}
return Some(&pairs[i].1);
}
}
}
None
}
#[inline(always)]
pub(crate) fn key_eq(a: &str, b: &str) -> bool {
let ab = a.as_bytes();
let bb = b.as_bytes();
if ab.len() != bb.len() {
return false;
}
let n = ab.len();
match n {
0 => true,
1 => ab[0] == bb[0],
2 => {
let x = u16::from_ne_bytes(ab[..2].try_into().unwrap());
let y = u16::from_ne_bytes(bb[..2].try_into().unwrap());
x == y
}
3 => {
let x = u16::from_ne_bytes(ab[..2].try_into().unwrap());
let y = u16::from_ne_bytes(bb[..2].try_into().unwrap());
x == y && ab[2] == bb[2]
}
4 => {
let x = u32::from_ne_bytes(ab[..4].try_into().unwrap());
let y = u32::from_ne_bytes(bb[..4].try_into().unwrap());
x == y
}
5..=7 => {
let x = u32::from_ne_bytes(ab[..4].try_into().unwrap());
let y = u32::from_ne_bytes(bb[..4].try_into().unwrap());
if x != y {
return false;
}
let xt = u32::from_ne_bytes(ab[n - 4..].try_into().unwrap());
let yt = u32::from_ne_bytes(bb[n - 4..].try_into().unwrap());
xt == yt
}
8 => {
let x = u64::from_ne_bytes(ab[..8].try_into().unwrap());
let y = u64::from_ne_bytes(bb[..8].try_into().unwrap());
x == y
}
9..=16 => {
let x = u64::from_ne_bytes(ab[..8].try_into().unwrap());
let y = u64::from_ne_bytes(bb[..8].try_into().unwrap());
if x != y {
return false;
}
let xt = u64::from_ne_bytes(ab[n - 8..].try_into().unwrap());
let yt = u64::from_ne_bytes(bb[n - 8..].try_into().unwrap());
xt == yt
}
_ => ab == bb,
}
}
#[cold]
#[inline(never)]
fn wide_lookup<'a>(
pairs: &'a [(&'a str, DataValue<'a>)],
target: &str,
) -> Option<&'a DataValue<'a>> {
if let Some(v) = ordered_probe(pairs, target) {
return Some(v);
}
linear_lookup(pairs, target)
}
#[inline(always)]
fn linear_lookup<'a>(
pairs: &'a [(&'a str, DataValue<'a>)],
target: &str,
) -> Option<&'a DataValue<'a>> {
let tb = target.as_bytes();
let tlen = tb.len();
if tlen == 0 {
for (k, v) in pairs {
if k.is_empty() {
return Some(v);
}
}
return None;
}
let tfirst = tb[0];
for (k, v) in pairs {
let kb = k.as_bytes();
if kb.len() != tlen {
continue;
}
if kb[0] != tfirst {
continue;
}
if key_eq(k, target) {
return Some(v);
}
}
None
}
#[inline(always)]
pub(crate) fn object_lookup_field<'a>(
pairs: &'a [(&'a str, DataValue<'a>)],
target: &str,
) -> Option<&'a DataValue<'a>> {
if pairs.len() >= ORDERED_PROBE_MIN_PAIRS {
return wide_lookup(pairs, target);
}
linear_lookup(pairs, target)
}
#[inline(always)]
pub(crate) fn object_lookup_field_hinted<'a>(
pairs: &'a [(&'a str, DataValue<'a>)],
target: &str,
hint: &mut usize,
) -> Option<&'a DataValue<'a>> {
if let Some((k, v)) = pairs.get(*hint) {
if key_eq(k, target) {
return Some(v);
}
}
let idx = pairs.iter().position(|(k, _)| key_eq(k, target))?;
*hint = idx;
Some(&pairs[idx].1)
}
#[cfg(test)]
mod tests {
use bumpalo::Bump;
use super::*;
fn sorted_pairs<'a>(arena: &'a Bump, n: usize) -> Vec<(&'a str, DataValue<'a>)> {
(0..n)
.map(|i| {
let k: &str = arena.alloc_str(&format!("k{i:03}"));
let v: &str = arena.alloc_str(&format!("v{i:03}"));
(k, DataValue::String(v))
})
.collect()
}
fn lookup_str<'a>(pairs: &'a [(&'a str, DataValue<'a>)], target: &str) -> Option<&'a str> {
object_lookup_field(pairs, target).and_then(|v| v.as_str())
}
#[test]
fn wide_sorted_hits_and_misses() {
let arena = Bump::new();
let mut pairs = sorted_pairs(&arena, 128);
pairs.push(("list_a", DataValue::Bool(true)));
pairs.push(("nested", DataValue::Bool(false)));
assert_eq!(lookup_str(&pairs, "k000"), Some("v000"));
assert_eq!(lookup_str(&pairs, "k064"), Some("v064"));
assert_eq!(lookup_str(&pairs, "k127"), Some("v127"));
assert_eq!(
object_lookup_field(&pairs, "nested").and_then(DataValue::as_bool),
Some(false)
);
assert_eq!(lookup_str(&pairs, "a"), None);
assert_eq!(lookup_str(&pairs, "k0640"), None);
assert_eq!(lookup_str(&pairs, "zzz"), None);
}
#[test]
fn wide_unsorted_hits_and_misses() {
let arena = Bump::new();
let mut pairs = sorted_pairs(&arena, 128);
pairs.reverse();
for i in [0usize, 1, 63, 64, 126, 127] {
let key = format!("k{i:03}");
let want = format!("v{i:03}");
assert_eq!(lookup_str(&pairs, &key), Some(want.as_str()));
}
assert_eq!(lookup_str(&pairs, "k128"), None);
assert_eq!(lookup_str(&pairs, ""), None);
}
#[test]
fn threshold_boundary_unsorted() {
let arena = Bump::new();
let mut pairs = sorted_pairs(&arena, ORDERED_PROBE_MIN_PAIRS);
pairs.swap(0, ORDERED_PROBE_MIN_PAIRS - 1);
assert_eq!(lookup_str(&pairs, "k000"), Some("v000"));
assert_eq!(lookup_str(&pairs, "k031"), Some("v031"));
assert_eq!(lookup_str(&pairs, "missing"), None);
}
#[test]
fn wide_sorted_adjacent_duplicates_return_first() {
let arena = Bump::new();
let mut pairs = sorted_pairs(&arena, 64);
pairs.insert(33, ("k032", DataValue::String("dup")));
assert_eq!(lookup_str(&pairs, "k032"), Some("v032"));
pairs.insert(34, ("k032", DataValue::String("dup2")));
assert_eq!(lookup_str(&pairs, "k032"), Some("v032"));
}
#[test]
fn wide_unsorted_scattered_duplicates_stay_key_correct() {
let arena = Bump::new();
let mut pairs = sorted_pairs(&arena, 64);
pairs.reverse();
pairs.push(("k010", DataValue::String("dup")));
let got = lookup_str(&pairs, "k010");
assert!(got == Some("v010") || got == Some("dup"), "got {got:?}");
}
#[test]
fn key_cmp_orders_bytewise() {
use core::cmp::Ordering::{Equal, Greater, Less};
assert_eq!(key_cmp(b"", b""), Equal);
assert_eq!(key_cmp(b"a", b"b"), Less);
assert_eq!(key_cmp(b"ab", b"a"), Greater); assert_eq!(key_cmp(b"k010", b"k010"), Equal);
assert_eq!(key_cmp(b"k2", b"k10"), Greater); }
#[test]
fn empty_key_on_wide_object() {
let arena = Bump::new();
let mut pairs = vec![("", DataValue::Bool(true))];
pairs.extend(sorted_pairs(&arena, 63));
assert_eq!(
object_lookup_field(&pairs, "").and_then(DataValue::as_bool),
Some(true)
);
}
}