source_map_mappings/
comparators.rs

1//! Comparator functions for sorting mappings in different ways.
2
3use super::{Mapping, OriginalLocation};
4use std::cmp::Ordering;
5use std::fmt;
6
7/// A function that can compare two `T`s.
8pub trait ComparatorFunction<T>: fmt::Debug {
9    /// Compare the given values.
10    fn compare(&T, &T) -> Ordering;
11}
12
13impl<T, F> ComparatorFunction<Option<T>> for F
14where
15    F: ComparatorFunction<T>,
16{
17    #[inline]
18    fn compare(a: &Option<T>, b: &Option<T>) -> Ordering {
19        match (a, b) {
20            (&None, &None) => Ordering::Equal,
21            (&Some(_), &None) => Ordering::Less,
22            (&None, &Some(_)) => Ordering::Greater,
23            (&Some(ref a), &Some(ref b)) => F::compare(a, b),
24        }
25    }
26}
27
28// Yes, using this style of comparison instead of `cmp.then(cmp2).then(cmp3)` is
29// actually a big performance win in practice:
30//
31// ```
32// $ cargo benchcmp control variable
33// name                                     control ns/iter  variable ns/iter  diff ns/iter   diff %  speedup
34// bench_parse_part_of_scala_js_source_map  2,029,981        1,290,716         -739,265       -36.42% x 1.57
35// ```
36//
37// This doesn't seem right, but you can't argue with those numbers...
38macro_rules! compare {
39    ($a:expr, $b:expr) => {
40        let cmp = ($a as i64) - ($b as i64);
41        if cmp < 0 {
42            return Ordering::Less;
43        } else if cmp > 0 {
44            return Ordering::Greater;
45        }
46    }
47}
48
49/// Sort mappings by their generated location, but don't compare generated
50/// lines. This is useful for when we know that all mappings being sorted have
51/// the same generated line number.
52#[derive(Debug)]
53pub struct ByGeneratedTail;
54
55impl ComparatorFunction<Mapping> for ByGeneratedTail {
56    #[inline]
57    fn compare(a: &Mapping, b: &Mapping) -> Ordering {
58        compare!(a.generated_column, b.generated_column);
59        ByOriginalLocation::compare(&a.original, &b.original)
60    }
61}
62
63/// Sort mappings by their original locations, breaking ties by their generated
64/// locations.
65#[derive(Debug)]
66pub struct ByOriginalLocation;
67
68impl ComparatorFunction<Mapping> for ByOriginalLocation {
69    #[inline]
70    fn compare(a: &Mapping, b: &Mapping) -> Ordering {
71        let c = ByOriginalLocation::compare(&a.original, &b.original);
72        match c {
73            Ordering::Less | Ordering::Greater => c,
74            Ordering::Equal => {
75                compare!(a.generated_line, b.generated_line);
76                compare!(a.generated_column, b.generated_column);
77                Ordering::Equal
78            }
79        }
80    }
81}
82
83impl ComparatorFunction<OriginalLocation> for ByOriginalLocation {
84    #[inline]
85    fn compare(a: &OriginalLocation, b: &OriginalLocation) -> Ordering {
86        compare!(a.source, b.source);
87        compare!(a.original_line, b.original_line);
88        compare!(a.original_column, b.original_column);
89        a.name.cmp(&b.name)
90    }
91}
92
93/// Assuming mappings are in the same original source, sort mappings by their
94/// original locations, breaking ties by their generated locations.
95#[derive(Debug)]
96pub struct ByOriginalLocationSameSource;
97
98impl ComparatorFunction<Mapping> for ByOriginalLocationSameSource {
99    #[inline]
100    fn compare(a: &Mapping, b: &Mapping) -> Ordering {
101        let c = ByOriginalLocationSameSource::compare(&a.original, &b.original);
102        match c {
103            Ordering::Less | Ordering::Greater => c,
104            Ordering::Equal => {
105                compare!(a.generated_line, b.generated_line);
106                compare!(a.generated_column, b.generated_column);
107                Ordering::Equal
108            }
109        }
110    }
111}
112
113impl ComparatorFunction<OriginalLocation> for ByOriginalLocationSameSource {
114    #[inline]
115    fn compare(a: &OriginalLocation, b: &OriginalLocation) -> Ordering {
116        debug_assert_eq!(a.source, b.source);
117        compare!(a.original_line, b.original_line);
118        compare!(a.original_column, b.original_column);
119        a.name.cmp(&b.name)
120    }
121}