##// END OF EJS Templates
rust-nodemap: core implementation for shortest...
Georges Racinet -
r44872:5ac1eecc default
parent child Browse files
Show More
@@ -226,6 +226,36 b" impl<'a> NodePrefixRef<'a> {"
226 assert!(i < self.len());
226 assert!(i < self.len());
227 get_nybble(self.buf, i)
227 get_nybble(self.buf, i)
228 }
228 }
229
230 /// Return the index first nybble that's different from `node`
231 ///
232 /// If the return value is `None` that means that `self` is
233 /// a prefix of `node`, but the current method is a bit slower
234 /// than `is_prefix_of`.
235 ///
236 /// Returned index is as in `get_nybble`, i.e., starting at 0.
237 pub fn first_different_nybble(&self, node: &Node) -> Option<usize> {
238 let buf = self.buf;
239 let until = if self.is_odd {
240 buf.len() - 1
241 } else {
242 buf.len()
243 };
244 for i in 0..until {
245 if buf[i] != node.data[i] {
246 if buf[i] & 0xf0 == node.data[i] & 0xf0 {
247 return Some(2 * i + 1);
248 } else {
249 return Some(2 * i);
250 }
251 }
252 }
253 if self.is_odd && buf[until] & 0xf0 != node.data[until] & 0xf0 {
254 Some(until * 2)
255 } else {
256 None
257 }
258 }
229 }
259 }
230
260
231 /// A shortcut for full `Node` references
261 /// A shortcut for full `Node` references
@@ -362,6 +392,36 b' mod tests {'
362 assert_eq!(prefix.borrow().get_nybble(7), 9);
392 assert_eq!(prefix.borrow().get_nybble(7), 9);
363 Ok(())
393 Ok(())
364 }
394 }
395
396 #[test]
397 fn test_first_different_nybble_even_prefix() {
398 let prefix = NodePrefix::from_hex("12ca").unwrap();
399 let prefref = prefix.borrow();
400 let mut node = Node::from([0; NODE_BYTES_LENGTH]);
401 assert_eq!(prefref.first_different_nybble(&node), Some(0));
402 node.data[0] = 0x13;
403 assert_eq!(prefref.first_different_nybble(&node), Some(1));
404 node.data[0] = 0x12;
405 assert_eq!(prefref.first_different_nybble(&node), Some(2));
406 node.data[1] = 0xca;
407 // now it is a prefix
408 assert_eq!(prefref.first_different_nybble(&node), None);
409 }
410
411 #[test]
412 fn test_first_different_nybble_odd_prefix() {
413 let prefix = NodePrefix::from_hex("12c").unwrap();
414 let prefref = prefix.borrow();
415 let mut node = Node::from([0; NODE_BYTES_LENGTH]);
416 assert_eq!(prefref.first_different_nybble(&node), Some(0));
417 node.data[0] = 0x13;
418 assert_eq!(prefref.first_different_nybble(&node), Some(1));
419 node.data[0] = 0x12;
420 assert_eq!(prefref.first_different_nybble(&node), Some(2));
421 node.data[1] = 0xca;
422 // now it is a prefix
423 assert_eq!(prefref.first_different_nybble(&node), None);
424 }
365 }
425 }
366
426
367 #[cfg(test)]
427 #[cfg(test)]
@@ -17,6 +17,7 b' use super::{'
17 RevlogIndex, NULL_REVISION,
17 RevlogIndex, NULL_REVISION,
18 };
18 };
19
19
20 use std::cmp::max;
20 use std::fmt;
21 use std::fmt;
21 use std::mem;
22 use std::mem;
22 use std::ops::Deref;
23 use std::ops::Deref;
@@ -98,6 +99,42 b' pub trait NodeMap {'
98 ) -> Result<Option<Revision>, NodeMapError> {
99 ) -> Result<Option<Revision>, NodeMapError> {
99 self.find_bin(idx, NodePrefix::from_hex(prefix)?.borrow())
100 self.find_bin(idx, NodePrefix::from_hex(prefix)?.borrow())
100 }
101 }
102
103 /// Give the size of the shortest node prefix that determines
104 /// the revision uniquely.
105 ///
106 /// From a binary node prefix, if it is matched in the node map, this
107 /// returns the number of hexadecimal digits that would had sufficed
108 /// to find the revision uniquely.
109 ///
110 /// Returns `None` if no `Revision` could be found for the prefix.
111 ///
112 /// If several Revisions match the given prefix, a [`MultipleResults`]
113 /// error is returned.
114 fn unique_prefix_len_bin<'a>(
115 &self,
116 idx: &impl RevlogIndex,
117 node_prefix: NodePrefixRef<'a>,
118 ) -> Result<Option<usize>, NodeMapError>;
119
120 /// Same as `unique_prefix_len_bin`, with the hexadecimal representation
121 /// of the prefix as input.
122 fn unique_prefix_len_hex(
123 &self,
124 idx: &impl RevlogIndex,
125 prefix: &str,
126 ) -> Result<Option<usize>, NodeMapError> {
127 self.unique_prefix_len_bin(idx, NodePrefix::from_hex(prefix)?.borrow())
128 }
129
130 /// Same as `unique_prefix_len_bin`, with a full `Node` as input
131 fn unique_prefix_len_node(
132 &self,
133 idx: &impl RevlogIndex,
134 node: &Node,
135 ) -> Result<Option<usize>, NodeMapError> {
136 self.unique_prefix_len_bin(idx, node.into())
137 }
101 }
138 }
102
139
103 pub trait MutableNodeMap: NodeMap {
140 pub trait MutableNodeMap: NodeMap {
@@ -279,20 +316,24 b' fn has_prefix_or_none('
279 fn validate_candidate(
316 fn validate_candidate(
280 idx: &impl RevlogIndex,
317 idx: &impl RevlogIndex,
281 prefix: NodePrefixRef,
318 prefix: NodePrefixRef,
282 rev: Option<Revision>,
319 candidate: (Option<Revision>, usize),
283 ) -> Result<Option<Revision>, NodeMapError> {
320 ) -> Result<(Option<Revision>, usize), NodeMapError> {
284 if prefix.is_prefix_of(&NULL_NODE) {
321 let (rev, steps) = candidate;
285 // NULL_REVISION always matches a prefix made only of zeros
322 if let Some(nz_nybble) = prefix.first_different_nybble(&NULL_NODE) {
323 rev.map_or(Ok((None, steps)), |r| {
324 has_prefix_or_none(idx, prefix, r)
325 .map(|opt| (opt, max(steps, nz_nybble + 1)))
326 })
327 } else {
328 // the prefix is only made of zeros; NULL_REVISION always matches it
286 // and any other *valid* result is an ambiguity
329 // and any other *valid* result is an ambiguity
287 match rev {
330 match rev {
288 None => Ok(Some(NULL_REVISION)),
331 None => Ok((Some(NULL_REVISION), steps + 1)),
289 Some(r) => match has_prefix_or_none(idx, prefix, r)? {
332 Some(r) => match has_prefix_or_none(idx, prefix, r)? {
290 None => Ok(Some(NULL_REVISION)),
333 None => Ok((Some(NULL_REVISION), steps + 1)),
291 _ => Err(NodeMapError::MultipleResults),
334 _ => Err(NodeMapError::MultipleResults),
292 },
335 },
293 }
336 }
294 } else {
295 rev.map_or(Ok(None), |r| has_prefix_or_none(idx, prefix, r))
296 }
337 }
297 }
338 }
298
339
@@ -387,13 +428,26 b' impl NodeTree {'
387 }
428 }
388
429
389 /// Main working method for `NodeTree` searches
430 /// Main working method for `NodeTree` searches
390 fn lookup<'p>(
431 ///
432 /// The first returned value is the result of analysing `NodeTree` data
433 /// *alone*: whereas `None` guarantees that the given prefix is absent
434 /// from the `NodeTree` data (but still could match `NULL_NODE`), with
435 /// `Some(rev)`, it is to be understood that `rev` is the unique `Revision`
436 /// that could match the prefix. Actually, all that can be inferred from
437 /// the `NodeTree` data is that `rev` is the revision with the longest
438 /// common node prefix with the given prefix.
439 ///
440 /// The second returned value is the size of the smallest subprefix
441 /// of `prefix` that would give the same result, i.e. not the
442 /// `MultipleResults` error variant (again, using only the data of the
443 /// `NodeTree`).
444 fn lookup(
391 &self,
445 &self,
392 prefix: NodePrefixRef<'p>,
446 prefix: NodePrefixRef,
393 ) -> Result<Option<Revision>, NodeMapError> {
447 ) -> Result<(Option<Revision>, usize), NodeMapError> {
394 for visit_item in self.visit(prefix) {
448 for (i, visit_item) in self.visit(prefix).enumerate() {
395 if let Some(opt) = visit_item.final_revision() {
449 if let Some(opt) = visit_item.final_revision() {
396 return Ok(opt);
450 return Ok((opt, i + 1));
397 }
451 }
398 }
452 }
399 Err(NodeMapError::MultipleResults)
453 Err(NodeMapError::MultipleResults)
@@ -638,6 +692,16 b' impl NodeMap for NodeTree {'
638 prefix: NodePrefixRef<'a>,
692 prefix: NodePrefixRef<'a>,
639 ) -> Result<Option<Revision>, NodeMapError> {
693 ) -> Result<Option<Revision>, NodeMapError> {
640 validate_candidate(idx, prefix.clone(), self.lookup(prefix)?)
694 validate_candidate(idx, prefix.clone(), self.lookup(prefix)?)
695 .map(|(opt, _shortest)| opt)
696 }
697
698 fn unique_prefix_len_bin<'a>(
699 &self,
700 idx: &impl RevlogIndex,
701 prefix: NodePrefixRef<'a>,
702 ) -> Result<Option<usize>, NodeMapError> {
703 validate_candidate(idx, prefix.clone(), self.lookup(prefix)?)
704 .map(|(opt, shortest)| opt.map(|_rev| shortest))
641 }
705 }
642 }
706 }
643
707
@@ -772,6 +836,7 b' mod tests {'
772 assert_eq!(nt.find_hex(&idx, "01"), Ok(Some(9)));
836 assert_eq!(nt.find_hex(&idx, "01"), Ok(Some(9)));
773 assert_eq!(nt.find_hex(&idx, "00"), Err(MultipleResults));
837 assert_eq!(nt.find_hex(&idx, "00"), Err(MultipleResults));
774 assert_eq!(nt.find_hex(&idx, "00a"), Ok(Some(0)));
838 assert_eq!(nt.find_hex(&idx, "00a"), Ok(Some(0)));
839 assert_eq!(nt.unique_prefix_len_hex(&idx, "00a"), Ok(Some(3)));
775 assert_eq!(nt.find_hex(&idx, "000"), Ok(Some(NULL_REVISION)));
840 assert_eq!(nt.find_hex(&idx, "000"), Ok(Some(NULL_REVISION)));
776 }
841 }
777
842
@@ -791,8 +856,10 b' mod tests {'
791 };
856 };
792 assert_eq!(nt.find_hex(&idx, "10")?, Some(1));
857 assert_eq!(nt.find_hex(&idx, "10")?, Some(1));
793 assert_eq!(nt.find_hex(&idx, "c")?, Some(2));
858 assert_eq!(nt.find_hex(&idx, "c")?, Some(2));
859 assert_eq!(nt.unique_prefix_len_hex(&idx, "c")?, Some(1));
794 assert_eq!(nt.find_hex(&idx, "00"), Err(MultipleResults));
860 assert_eq!(nt.find_hex(&idx, "00"), Err(MultipleResults));
795 assert_eq!(nt.find_hex(&idx, "000")?, Some(NULL_REVISION));
861 assert_eq!(nt.find_hex(&idx, "000")?, Some(NULL_REVISION));
862 assert_eq!(nt.unique_prefix_len_hex(&idx, "000")?, Some(3));
796 assert_eq!(nt.find_hex(&idx, "01")?, Some(9));
863 assert_eq!(nt.find_hex(&idx, "01")?, Some(9));
797 Ok(())
864 Ok(())
798 }
865 }
@@ -828,6 +895,13 b' mod tests {'
828 self.nt.find_hex(&self.index, prefix)
895 self.nt.find_hex(&self.index, prefix)
829 }
896 }
830
897
898 fn unique_prefix_len_hex(
899 &self,
900 prefix: &str,
901 ) -> Result<Option<usize>, NodeMapError> {
902 self.nt.unique_prefix_len_hex(&self.index, prefix)
903 }
904
831 /// Drain `added` and restart a new one
905 /// Drain `added` and restart a new one
832 fn commit(self) -> Self {
906 fn commit(self) -> Self {
833 let mut as_vec: Vec<Block> =
907 let mut as_vec: Vec<Block> =
@@ -880,6 +954,28 b' mod tests {'
880 }
954 }
881
955
882 #[test]
956 #[test]
957 fn test_unique_prefix_len_zero_prefix() {
958 let mut idx = TestNtIndex::new();
959 idx.insert(0, "00000abcd").unwrap();
960
961 assert_eq!(idx.find_hex("000"), Err(NodeMapError::MultipleResults));
962 // in the nodetree proper, this will be found at the first nybble
963 // yet the correct answer for unique_prefix_len is not 1, nor 1+1,
964 // but the first difference with `NULL_NODE`
965 assert_eq!(idx.unique_prefix_len_hex("00000a"), Ok(Some(6)));
966 assert_eq!(idx.unique_prefix_len_hex("00000ab"), Ok(Some(6)));
967
968 // same with odd result
969 idx.insert(1, "00123").unwrap();
970 assert_eq!(idx.unique_prefix_len_hex("001"), Ok(Some(3)));
971 assert_eq!(idx.unique_prefix_len_hex("0012"), Ok(Some(3)));
972
973 // these are unchanged of course
974 assert_eq!(idx.unique_prefix_len_hex("00000a"), Ok(Some(6)));
975 assert_eq!(idx.unique_prefix_len_hex("00000ab"), Ok(Some(6)));
976 }
977
978 #[test]
883 fn test_insert_extreme_splitting() -> Result<(), NodeMapError> {
979 fn test_insert_extreme_splitting() -> Result<(), NodeMapError> {
884 // check that the splitting loop is long enough
980 // check that the splitting loop is long enough
885 let mut nt_idx = TestNtIndex::new();
981 let mut nt_idx = TestNtIndex::new();
General Comments 0
You need to be logged in to leave comments. Login now