Look up a field's byte range using the pre-computed sidecar entries. Uses binary search and verifies hash matches against the raw msgpack to correctly resolve hash collisions.
(&self, field: &str)
| 268 | /// Uses binary search and verifies hash matches against the raw msgpack |
| 269 | /// to correctly resolve hash collisions. |
| 270 | pub fn get(&self, field: &str) -> Option<(usize, usize)> { |
| 271 | let hash = fnv1a_hash(field.as_bytes()); |
| 272 | let count = self.entries.len(); |
| 273 | if count == 0 { |
| 274 | return None; |
| 275 | } |
| 276 | |
| 277 | // Binary search for any entry with matching hash. |
| 278 | let mid = self.entries.partition_point(|e| e.field_hash < hash); |
| 279 | if mid >= count || self.entries[mid].field_hash != hash { |
| 280 | return None; |
| 281 | } |
| 282 | |
| 283 | // Scan left to find the first entry with this hash. |
| 284 | let first = { |
| 285 | let mut i = mid; |
| 286 | while i > 0 && self.entries[i - 1].field_hash == hash { |
| 287 | i -= 1; |
| 288 | } |
| 289 | i |
| 290 | }; |
| 291 | |
| 292 | // Scan right to find the last entry with this hash. |
| 293 | let last = { |
| 294 | let mut i = mid + 1; |
| 295 | while i < count && self.entries[i].field_hash == hash { |
| 296 | i += 1; |
| 297 | } |
| 298 | i |
| 299 | }; |
| 300 | |
| 301 | // Among all entries with matching hash, verify against the msgpack. |
| 302 | for i in first..last { |
| 303 | let e = &self.entries[i]; |
| 304 | let value_offset = e.value_offset as usize; |
| 305 | let value_len = e.value_len as usize; |
| 306 | if verify_entry(self.msgpack, value_offset, value_len, field) { |
| 307 | let value_end = value_offset + value_len; |
| 308 | return Some((value_offset, value_end)); |
| 309 | } |
| 310 | } |
| 311 | None |
| 312 | } |
| 313 | |
| 314 | /// Number of indexed fields. |
| 315 | pub fn len(&self) -> usize { |