Skip to content

Commit 0d2c6c2

Browse files
authored
transpile: Rewrite fn compare_src_locs implementation to have a total order (#1128)
This implementation is simplified compared to the previous one. It is also almost twice as slow in [the exhaustive test](#1126 (comment)) (15 vs 25 seconds). However, in real sort usage the impact should be significantly less. * Fixes #1126
2 parents beb017f + ea15739 commit 0d2c6c2

File tree

1 file changed

+266
-20
lines changed
  • c2rust-transpile/src/c_ast

1 file changed

+266
-20
lines changed

c2rust-transpile/src/c_ast/mod.rs

Lines changed: 266 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -206,32 +206,37 @@ impl TypedAstContext {
206206
self.files[id].path.as_deref()
207207
}
208208

209+
/// Compare two [`SrcLoc`]s based on their import path
209210
pub fn compare_src_locs(&self, a: &SrcLoc, b: &SrcLoc) -> Ordering {
210-
/// Compare `self` with `other`, without regard to file id
211-
fn cmp_pos(a: &SrcLoc, b: &SrcLoc) -> Ordering {
212-
(a.line, a.column).cmp(&(b.line, b.column))
213-
}
214-
let path_a = self.include_map[self.file_map[a.fileid as usize]].clone();
215-
let path_b = self.include_map[self.file_map[b.fileid as usize]].clone();
216-
for (include_a, include_b) in path_a.iter().zip(path_b.iter()) {
217-
if include_a.fileid != include_b.fileid {
218-
return cmp_pos(include_a, include_b);
219-
}
220-
}
221211
use Ordering::*;
222-
match path_a.len().cmp(&path_b.len()) {
212+
let path_a = &self.include_map[self.file_map[a.fileid as usize]];
213+
let path_b = &self.include_map[self.file_map[b.fileid as usize]];
214+
215+
// Find the first include that does not match between the two
216+
let common_len = path_a.len().min(path_b.len());
217+
let order = path_a[..common_len].cmp(&path_b[..common_len]);
218+
if order != Equal {
219+
return order;
220+
}
221+
222+
// Either all parent includes are the same, or the include paths are of different lengths
223+
// because .zip() stops when one of the iterators is empty.
224+
let (a, b) = match path_a.len().cmp(&path_b.len()) {
223225
Less => {
224-
// compare the place b was included in a'a file with a
225-
let b = path_b.get(path_a.len()).unwrap();
226-
cmp_pos(a, b)
226+
// a has the shorter path, which means b was included in a's file
227+
// so extract that include and compare the position to a
228+
let b = &path_b[path_a.len()];
229+
(a, b)
227230
}
228-
Equal => cmp_pos(a, b),
231+
Equal => (a, b), // a and b have the same include path and are thus in the same file
229232
Greater => {
230-
// compare the place a was included in b's file with b
231-
let a = path_a.get(path_b.len()).unwrap();
232-
cmp_pos(a, b)
233+
// b has the shorter path, which means a was included in b's file
234+
// so extract that include and compare the position to b
235+
let a = &path_a[path_b.len()];
236+
(a, b)
233237
}
234-
}
238+
};
239+
a.cmp(b)
235240
}
236241

237242
pub fn get_file_include_line_number(&self, file: FileId) -> Option<u64> {
@@ -1865,3 +1870,244 @@ impl CTypeKind {
18651870
Some(ty)
18661871
}
18671872
}
1873+
1874+
#[cfg(test)]
1875+
mod tests {
1876+
use super::*;
1877+
1878+
#[test]
1879+
fn test_compare_src_locs_ord() {
1880+
let ctx = TypedAstContext {
1881+
c_types: Default::default(),
1882+
c_exprs: Default::default(),
1883+
c_stmts: Default::default(),
1884+
c_decls: Default::default(),
1885+
c_decls_top: vec![],
1886+
c_main: None,
1887+
parents: Default::default(),
1888+
files: vec![],
1889+
file_map: vec![0, 1, 2, 3, 4, 5, 4, 5],
1890+
include_map: vec![
1891+
vec![],
1892+
vec![],
1893+
vec![SrcLoc {
1894+
fileid: 2,
1895+
line: 6,
1896+
column: 10,
1897+
}],
1898+
vec![],
1899+
vec![],
1900+
vec![SrcLoc {
1901+
fileid: 5,
1902+
line: 6,
1903+
column: 10,
1904+
}],
1905+
],
1906+
label_names: Default::default(),
1907+
macro_invocations: Default::default(),
1908+
macro_expansions: Default::default(),
1909+
macro_expansion_text: Default::default(),
1910+
comments: vec![],
1911+
prenamed_decls: Default::default(),
1912+
va_list_kind: BuiltinVaListKind::CharPtrBuiltinVaList,
1913+
target: "".to_string(),
1914+
};
1915+
let locs = &mut [
1916+
SrcLoc {
1917+
fileid: 5,
1918+
line: 5,
1919+
column: 1,
1920+
},
1921+
SrcLoc {
1922+
fileid: 5,
1923+
line: 5,
1924+
column: 1,
1925+
},
1926+
SrcLoc {
1927+
fileid: 1,
1928+
line: 5,
1929+
column: 1,
1930+
},
1931+
SrcLoc {
1932+
fileid: 1,
1933+
line: 5,
1934+
column: 1,
1935+
},
1936+
SrcLoc {
1937+
fileid: 1,
1938+
line: 10,
1939+
column: 1,
1940+
},
1941+
SrcLoc {
1942+
fileid: 1,
1943+
line: 5,
1944+
column: 1,
1945+
},
1946+
SrcLoc {
1947+
fileid: 2,
1948+
line: 4,
1949+
column: 1,
1950+
},
1951+
SrcLoc {
1952+
fileid: 5,
1953+
line: 3,
1954+
column: 7,
1955+
},
1956+
SrcLoc {
1957+
fileid: 5,
1958+
line: 3,
1959+
column: 1,
1960+
},
1961+
SrcLoc {
1962+
fileid: 5,
1963+
line: 3,
1964+
column: 1,
1965+
},
1966+
SrcLoc {
1967+
fileid: 5,
1968+
line: 5,
1969+
column: 7,
1970+
},
1971+
SrcLoc {
1972+
fileid: 5,
1973+
line: 5,
1974+
column: 1,
1975+
},
1976+
SrcLoc {
1977+
fileid: 5,
1978+
line: 5,
1979+
column: 1,
1980+
},
1981+
SrcLoc {
1982+
fileid: 5,
1983+
line: 5,
1984+
column: 7,
1985+
},
1986+
SrcLoc {
1987+
fileid: 5,
1988+
line: 7,
1989+
column: 7,
1990+
},
1991+
SrcLoc {
1992+
fileid: 5,
1993+
line: 7,
1994+
column: 1,
1995+
},
1996+
SrcLoc {
1997+
fileid: 5,
1998+
line: 7,
1999+
column: 1,
2000+
},
2001+
SrcLoc {
2002+
fileid: 5,
2003+
line: 9,
2004+
column: 7,
2005+
},
2006+
SrcLoc {
2007+
fileid: 5,
2008+
line: 9,
2009+
column: 1,
2010+
},
2011+
SrcLoc {
2012+
fileid: 5,
2013+
line: 9,
2014+
column: 1,
2015+
},
2016+
SrcLoc {
2017+
fileid: 5,
2018+
line: 5,
2019+
column: 7,
2020+
},
2021+
SrcLoc {
2022+
fileid: 5,
2023+
line: 5,
2024+
column: 1,
2025+
},
2026+
SrcLoc {
2027+
fileid: 5,
2028+
line: 5,
2029+
column: 1,
2030+
},
2031+
SrcLoc {
2032+
fileid: 5,
2033+
line: 8,
2034+
column: 3,
2035+
},
2036+
SrcLoc {
2037+
fileid: 5,
2038+
line: 8,
2039+
column: 1,
2040+
},
2041+
SrcLoc {
2042+
fileid: 5,
2043+
line: 7,
2044+
column: 1,
2045+
},
2046+
SrcLoc {
2047+
fileid: 5,
2048+
line: 0,
2049+
column: 4,
2050+
},
2051+
SrcLoc {
2052+
fileid: 5,
2053+
line: 0,
2054+
column: 1,
2055+
},
2056+
SrcLoc {
2057+
fileid: 5,
2058+
line: 2,
2059+
column: 1,
2060+
},
2061+
SrcLoc {
2062+
fileid: 5,
2063+
line: 98,
2064+
column: 3,
2065+
},
2066+
SrcLoc {
2067+
fileid: 5,
2068+
line: 98,
2069+
column: 1,
2070+
},
2071+
SrcLoc {
2072+
fileid: 5,
2073+
line: 202,
2074+
column: 1,
2075+
},
2076+
SrcLoc {
2077+
fileid: 5,
2078+
line: 202,
2079+
column: 1,
2080+
},
2081+
SrcLoc {
2082+
fileid: 7,
2083+
line: 1,
2084+
column: 1,
2085+
},
2086+
SrcLoc {
2087+
fileid: 7,
2088+
line: 3,
2089+
column: 1,
2090+
},
2091+
];
2092+
2093+
let n = locs.len();
2094+
for i in 0..n {
2095+
let a = locs[i];
2096+
for j in 0..n {
2097+
let b = locs[j];
2098+
for k in 0..n {
2099+
let c = locs[k];
2100+
let ab = ctx.compare_src_locs(&a, &b);
2101+
let bc = ctx.compare_src_locs(&b, &c);
2102+
let ac = ctx.compare_src_locs(&a, &c);
2103+
if ab == bc {
2104+
assert_eq!(ab, ac, "Total order (transitivity) has been violated");
2105+
}
2106+
}
2107+
}
2108+
}
2109+
2110+
// This should not panic
2111+
locs.sort_unstable_by(|a, b| ctx.compare_src_locs(a, b));
2112+
}
2113+
}

0 commit comments

Comments
 (0)