Show More
@@ -226,6 +226,36 b" impl<'a> NodePrefixRef<'a> {" | |||
|
226 | 226 | assert!(i < self.len()); |
|
227 | 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 | 261 | /// A shortcut for full `Node` references |
@@ -362,6 +392,36 b' mod tests {' | |||
|
362 | 392 | assert_eq!(prefix.borrow().get_nybble(7), 9); |
|
363 | 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 | 427 | #[cfg(test)] |
@@ -17,6 +17,7 b' use super::{' | |||
|
17 | 17 | RevlogIndex, NULL_REVISION, |
|
18 | 18 | }; |
|
19 | 19 | |
|
20 | use std::cmp::max; | |
|
20 | 21 | use std::fmt; |
|
21 | 22 | use std::mem; |
|
22 | 23 | use std::ops::Deref; |
@@ -98,6 +99,42 b' pub trait NodeMap {' | |||
|
98 | 99 | ) -> Result<Option<Revision>, NodeMapError> { |
|
99 | 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 | 140 | pub trait MutableNodeMap: NodeMap { |
@@ -279,20 +316,24 b' fn has_prefix_or_none(' | |||
|
279 | 316 | fn validate_candidate( |
|
280 | 317 | idx: &impl RevlogIndex, |
|
281 | 318 | prefix: NodePrefixRef, |
|
282 |
|
|
|
283 | ) -> Result<Option<Revision>, NodeMapError> { | |
|
284 | if prefix.is_prefix_of(&NULL_NODE) { | |
|
285 | // NULL_REVISION always matches a prefix made only of zeros | |
|
319 | candidate: (Option<Revision>, usize), | |
|
320 | ) -> Result<(Option<Revision>, usize), NodeMapError> { | |
|
321 | let (rev, steps) = candidate; | |
|
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 | 329 | // and any other *valid* result is an ambiguity |
|
287 | 330 | match rev { |
|
288 | None => Ok(Some(NULL_REVISION)), | |
|
331 | None => Ok((Some(NULL_REVISION), steps + 1)), | |
|
289 | 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 | 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 | 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 | 445 | &self, |
|
392 |
prefix: NodePrefixRef |
|
|
393 | ) -> Result<Option<Revision>, NodeMapError> { | |
|
394 | for visit_item in self.visit(prefix) { | |
|
446 | prefix: NodePrefixRef, | |
|
447 | ) -> Result<(Option<Revision>, usize), NodeMapError> { | |
|
448 | for (i, visit_item) in self.visit(prefix).enumerate() { | |
|
395 | 449 | if let Some(opt) = visit_item.final_revision() { |
|
396 | return Ok(opt); | |
|
450 | return Ok((opt, i + 1)); | |
|
397 | 451 | } |
|
398 | 452 | } |
|
399 | 453 | Err(NodeMapError::MultipleResults) |
@@ -638,6 +692,16 b' impl NodeMap for NodeTree {' | |||
|
638 | 692 | prefix: NodePrefixRef<'a>, |
|
639 | 693 | ) -> Result<Option<Revision>, NodeMapError> { |
|
640 | 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 | 836 | assert_eq!(nt.find_hex(&idx, "01"), Ok(Some(9))); |
|
773 | 837 | assert_eq!(nt.find_hex(&idx, "00"), Err(MultipleResults)); |
|
774 | 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 | 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 | 857 | assert_eq!(nt.find_hex(&idx, "10")?, Some(1)); |
|
793 | 858 | assert_eq!(nt.find_hex(&idx, "c")?, Some(2)); |
|
859 | assert_eq!(nt.unique_prefix_len_hex(&idx, "c")?, Some(1)); | |
|
794 | 860 | assert_eq!(nt.find_hex(&idx, "00"), Err(MultipleResults)); |
|
795 | 861 | assert_eq!(nt.find_hex(&idx, "000")?, Some(NULL_REVISION)); |
|
862 | assert_eq!(nt.unique_prefix_len_hex(&idx, "000")?, Some(3)); | |
|
796 | 863 | assert_eq!(nt.find_hex(&idx, "01")?, Some(9)); |
|
797 | 864 | Ok(()) |
|
798 | 865 | } |
@@ -828,6 +895,13 b' mod tests {' | |||
|
828 | 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 | 905 | /// Drain `added` and restart a new one |
|
832 | 906 | fn commit(self) -> Self { |
|
833 | 907 | let mut as_vec: Vec<Block> = |
@@ -880,6 +954,28 b' mod tests {' | |||
|
880 | 954 | } |
|
881 | 955 | |
|
882 | 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 | 979 | fn test_insert_extreme_splitting() -> Result<(), NodeMapError> { |
|
884 | 980 | // check that the splitting loop is long enough |
|
885 | 981 | let mut nt_idx = TestNtIndex::new(); |
General Comments 0
You need to be logged in to leave comments.
Login now