comparison rust/hg-core/tests/test_missing_ancestors.rs @ 50979:4c5f6e95df84

rust: make `Revision` a newtype This change is the one we've been building towards during this series. The aim is to make `Revision` mean more than a simple integer, holding the information that it is valid for a given revlog index. While this still allows for programmer error, since creating a revision directly and querying a different index with a "checked" revision are still possible, the friction created by the newtype will hopefully make us think twice about which type to use. Enough of the Rust ecosystem relies on the newtype pattern to be efficiently optimized away (even compiler in codegen testsĀ¹), so I'm not worried about this being a fundamental problem. [1] https://github.com/rust-lang/rust/blob/7a70647f195f6b0a0f1ebd72b1542ba91a32f43a/tests/codegen/vec-in-place.rs#L47
author Raphaël Gomès <rgomes@octobus.net>
date Fri, 18 Aug 2023 14:34:29 +0200
parents e98fd81bb151
children ec7171748350
comparison
equal deleted inserted replaced
50978:27e773aa607d 50979:4c5f6e95df84
24 let mut vg: VecGraph = Vec::with_capacity(nodes); 24 let mut vg: VecGraph = Vec::with_capacity(nodes);
25 for i in 0..nodes { 25 for i in 0..nodes {
26 if i == 0 || rng.gen_bool(rootprob) { 26 if i == 0 || rng.gen_bool(rootprob) {
27 vg.push([NULL_REVISION, NULL_REVISION]) 27 vg.push([NULL_REVISION, NULL_REVISION])
28 } else if i == 1 { 28 } else if i == 1 {
29 vg.push([0, NULL_REVISION]) 29 vg.push([Revision(0), NULL_REVISION])
30 } else if rng.gen_bool(mergeprob) { 30 } else if rng.gen_bool(mergeprob) {
31 let p1 = { 31 let p1 = {
32 if i == 2 || rng.gen_bool(prevprob) { 32 if i == 2 || rng.gen_bool(prevprob) {
33 (i - 1) as Revision 33 Revision((i - 1) as BaseRevision)
34 } else { 34 } else {
35 rng.gen_range(0..i - 1) as Revision 35 Revision(rng.gen_range(0..i - 1) as BaseRevision)
36 } 36 }
37 }; 37 };
38 // p2 is a random revision lower than i and different from p1 38 // p2 is a random revision lower than i and different from p1
39 let mut p2 = rng.gen_range(0..i - 1) as Revision; 39 let mut p2 = Revision(rng.gen_range(0..i - 1) as BaseRevision);
40 if p2 >= p1 { 40 if p2 >= p1 {
41 p2 += 1; 41 p2.0 += 1;
42 } 42 }
43 vg.push([p1, p2]); 43 vg.push([p1, p2]);
44 } else if rng.gen_bool(prevprob) { 44 } else if rng.gen_bool(prevprob) {
45 vg.push([(i - 1) as Revision, NULL_REVISION]) 45 vg.push([Revision((i - 1) as BaseRevision), NULL_REVISION])
46 } else { 46 } else {
47 vg.push([rng.gen_range(0..i - 1) as Revision, NULL_REVISION]) 47 vg.push([
48 Revision(rng.gen_range(0..i - 1) as BaseRevision),
49 NULL_REVISION,
50 ])
48 } 51 }
49 } 52 }
50 vg 53 vg
51 } 54 }
52 55
53 /// Compute the ancestors set of all revisions of a VecGraph 56 /// Compute the ancestors set of all revisions of a VecGraph
54 fn ancestors_sets(vg: &VecGraph) -> Vec<HashSet<Revision>> { 57 fn ancestors_sets(vg: &VecGraph) -> Vec<HashSet<Revision>> {
55 let mut ancs: Vec<HashSet<Revision>> = Vec::new(); 58 let mut ancs: Vec<HashSet<Revision>> = Vec::new();
56 (0..vg.len()).for_each(|i| { 59 (0..vg.len()).for_each(|i| {
57 let mut ancs_i = HashSet::new(); 60 let mut ancs_i = HashSet::new();
58 ancs_i.insert(i as Revision); 61 ancs_i.insert(Revision(i as BaseRevision));
59 for p in vg[i].iter().cloned() { 62 for p in vg[i].iter().cloned() {
60 if p != NULL_REVISION { 63 if p != NULL_REVISION {
61 ancs_i.extend(&ancs[p as usize]); 64 ancs_i.extend(&ancs[p.0 as usize]);
62 } 65 }
63 } 66 }
64 ancs.push(ancs_i); 67 ancs.push(ancs_i);
65 }); 68 });
66 ancs 69 ancs
113 revs.remove(&NULL_REVISION); 116 revs.remove(&NULL_REVISION);
114 self.history 117 self.history
115 .push(MissingAncestorsAction::RemoveAncestorsFrom(revs.clone())); 118 .push(MissingAncestorsAction::RemoveAncestorsFrom(revs.clone()));
116 for base in self.bases.iter().cloned() { 119 for base in self.bases.iter().cloned() {
117 if base != NULL_REVISION { 120 if base != NULL_REVISION {
118 for rev in &self.ancestors_sets[base as usize] { 121 for rev in &self.ancestors_sets[base.0 as usize] {
119 revs.remove(rev); 122 revs.remove(rev);
120 } 123 }
121 } 124 }
122 } 125 }
123 } 126 }
129 let revs_as_set: HashSet<Revision> = revs.into_iter().collect(); 132 let revs_as_set: HashSet<Revision> = revs.into_iter().collect();
130 133
131 let mut missing: HashSet<Revision> = HashSet::new(); 134 let mut missing: HashSet<Revision> = HashSet::new();
132 for rev in revs_as_set.iter().cloned() { 135 for rev in revs_as_set.iter().cloned() {
133 if rev != NULL_REVISION { 136 if rev != NULL_REVISION {
134 missing.extend(&self.ancestors_sets[rev as usize]) 137 missing.extend(&self.ancestors_sets[rev.0 as usize])
135 } 138 }
136 } 139 }
137 self.history 140 self.history
138 .push(MissingAncestorsAction::MissingAncestors(revs_as_set)); 141 .push(MissingAncestorsAction::MissingAncestors(revs_as_set));
139 142
140 for base in self.bases.iter().cloned() { 143 for base in self.bases.iter().cloned() {
141 if base != NULL_REVISION { 144 if base != NULL_REVISION {
142 for rev in &self.ancestors_sets[base as usize] { 145 for rev in &self.ancestors_sets[base.0 as usize] {
143 missing.remove(rev); 146 missing.remove(rev);
144 } 147 }
145 } 148 }
146 } 149 }
147 let mut res: Vec<Revision> = missing.iter().cloned().collect(); 150 let mut res: Vec<Revision> = missing.iter().cloned().collect();
191 ) -> HashSet<Revision> { 194 ) -> HashSet<Revision> {
192 let mu = mu_opt.unwrap_or(1.1); 195 let mu = mu_opt.unwrap_or(1.1);
193 let sigma = sigma_opt.unwrap_or(0.8); 196 let sigma = sigma_opt.unwrap_or(0.8);
194 197
195 let log_normal = LogNormal::new(mu, sigma).unwrap(); 198 let log_normal = LogNormal::new(mu, sigma).unwrap();
196 let nb = min(maxrev as usize, log_normal.sample(rng).floor() as usize); 199 let nb = min(maxrev.0 as usize, log_normal.sample(rng).floor() as usize);
197 200
198 let dist = Uniform::from(NULL_REVISION..maxrev); 201 let dist = Uniform::from(NULL_REVISION.0..maxrev.0);
199 rng.sample_iter(&dist).take(nb).collect() 202 rng.sample_iter(&dist).take(nb).map(Revision).collect()
200 } 203 }
201 204
202 /// Produces the hexadecimal representation of a slice of bytes 205 /// Produces the hexadecimal representation of a slice of bytes
203 fn hex_bytes(bytes: &[u8]) -> String { 206 fn hex_bytes(bytes: &[u8]) -> String {
204 let mut s = String::with_capacity(bytes.len() * 2); 207 let mut s = String::with_capacity(bytes.len() * 2);
292 for g in 0..graphcount { 295 for g in 0..graphcount {
293 if g != 0 && g % 100 == 0 { 296 if g != 0 && g % 100 == 0 {
294 eprintln!("Tested with {} graphs", g); 297 eprintln!("Tested with {} graphs", g);
295 } 298 }
296 let graph = build_random_graph(None, None, None, None); 299 let graph = build_random_graph(None, None, None, None);
297 let graph_len = graph.len() as Revision; 300 let graph_len = Revision(graph.len() as BaseRevision);
298 let ancestors_sets = ancestors_sets(&graph); 301 let ancestors_sets = ancestors_sets(&graph);
299 for _testno in 0..testcount { 302 for _testno in 0..testcount {
300 let bases: HashSet<Revision> = 303 let bases: HashSet<Revision> =
301 sample_revs(&mut rng, graph_len, None, None); 304 sample_revs(&mut rng, graph_len, None, None);
302 let mut inc = MissingAncestors::<VecGraph>::new( 305 let mut inc = MissingAncestors::<VecGraph>::new(