Skip to main content

rustc_transmute/layout/
dfa.rs

1use std::fmt;
2use std::iter::Peekable;
3use std::sync::atomic::{AtomicU32, Ordering};
4
5use super::{Byte, Reference, Region, Tree, Type, Uninhabited};
6use crate::{Map, Set};
7
8#[cfg(test)]
9mod tests;
10
11#[derive(#[automatically_derived]
impl<R: ::core::cmp::PartialEq, T: ::core::cmp::PartialEq>
    ::core::marker::StructuralPartialEq for Dfa<R, T> where R: Region, T: Type
    {
}
#[automatically_derived]
impl<R: ::core::cmp::PartialEq, T: ::core::cmp::PartialEq>
    ::core::cmp::PartialEq for Dfa<R, T> where R: Region, T: Type {
    #[inline]
    fn eq(&self, other: &Dfa<R, T>) -> bool {
        self.transitions == other.transitions && self.start == other.start &&
            self.accept == other.accept
    }
}PartialEq)]
12#[cfg_attr(test, derive(Clone))]
13pub(crate) struct Dfa<R, T>
14where
15    R: Region,
16    T: Type,
17{
18    pub(crate) transitions: Map<State, Transitions<R, T>>,
19    pub(crate) start: State,
20    pub(crate) accept: State,
21}
22
23#[derive(#[automatically_derived]
impl<R: ::core::cmp::PartialEq, T: ::core::cmp::PartialEq>
    ::core::marker::StructuralPartialEq for Transitions<R, T> where R: Region,
    T: Type {
}
#[automatically_derived]
impl<R: ::core::cmp::PartialEq, T: ::core::cmp::PartialEq>
    ::core::cmp::PartialEq for Transitions<R, T> where R: Region, T: Type {
    #[inline]
    fn eq(&self, other: &Transitions<R, T>) -> bool {
        self.byte_transitions == other.byte_transitions &&
            self.ref_transitions == other.ref_transitions
    }
}PartialEq, #[automatically_derived]
impl<R: ::core::clone::Clone, T: ::core::clone::Clone> ::core::clone::Clone
    for Transitions<R, T> where R: Region, T: Type {
    #[inline]
    fn clone(&self) -> Transitions<R, T> {
        Transitions {
            byte_transitions: ::core::clone::Clone::clone(&self.byte_transitions),
            ref_transitions: ::core::clone::Clone::clone(&self.ref_transitions),
        }
    }
}Clone, #[automatically_derived]
impl<R: ::core::fmt::Debug, T: ::core::fmt::Debug> ::core::fmt::Debug for
    Transitions<R, T> where R: Region, T: Type {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f, "Transitions",
            "byte_transitions", &self.byte_transitions, "ref_transitions",
            &&self.ref_transitions)
    }
}Debug)]
24pub(crate) struct Transitions<R, T>
25where
26    R: Region,
27    T: Type,
28{
29    byte_transitions: EdgeSet<State>,
30    ref_transitions: Map<Reference<R, T>, State>,
31}
32
33impl<R, T> Default for Transitions<R, T>
34where
35    R: Region,
36    T: Type,
37{
38    fn default() -> Self {
39        Self { byte_transitions: EdgeSet::empty(), ref_transitions: Map::default() }
40    }
41}
42
43/// An identifier for a node in a [`Dfa`].
44///
45/// The numeric identifier does not encode a byte offset.
46#[derive(#[automatically_derived]
impl ::core::hash::Hash for State {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        ::core::hash::Hash::hash(&self.0, state)
    }
}Hash, #[automatically_derived]
impl ::core::cmp::Eq for State {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<u32>;
    }
}Eq, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for State { }
#[automatically_derived]
impl ::core::cmp::PartialEq for State {
    #[inline]
    fn eq(&self, other: &State) -> bool { self.0 == other.0 }
}PartialEq, #[automatically_derived]
impl ::core::cmp::PartialOrd for State {
    #[inline]
    fn partial_cmp(&self, other: &State)
        -> ::core::option::Option<::core::cmp::Ordering> {
        ::core::option::Option::Some(::core::cmp::Ord::cmp(self, other))
    }
}PartialOrd, #[automatically_derived]
impl ::core::cmp::Ord for State {
    #[inline]
    fn cmp(&self, other: &State) -> ::core::cmp::Ordering {
        ::core::cmp::Ord::cmp(&self.0, &other.0)
    }
}Ord, #[automatically_derived]
impl ::core::marker::Copy for State { }Copy, #[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for State { }
#[automatically_derived]
impl ::core::clone::Clone for State {
    #[inline]
    fn clone(&self) -> State {
        let _: ::core::clone::AssertParamIsClone<u32>;
        *self
    }
}Clone)]
47pub(crate) struct State(pub(crate) u32);
48
49impl State {
50    pub(crate) fn new() -> Self {
51        static COUNTER: AtomicU32 = AtomicU32::new(0);
52        Self(COUNTER.fetch_add(1, Ordering::SeqCst))
53    }
54}
55
56impl fmt::Debug for State {
57    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58        f.write_fmt(format_args!("S_{0}", self.0))write!(f, "S_{}", self.0)
59    }
60}
61
62impl<R, T> Dfa<R, T>
63where
64    R: Region,
65    T: Type,
66{
67    #[cfg(test)]
68    pub(crate) fn bool() -> Self {
69        Self::from_transitions(|accept| Transitions {
70            byte_transitions: EdgeSet::new(Byte::new(0x00..=0x01), accept),
71            ref_transitions: Map::default(),
72        })
73    }
74
75    pub(crate) fn unit() -> Self {
76        let transitions: Map<State, Transitions<R, T>> = Map::default();
77        let start = State::new();
78        let accept = start;
79
80        Self { transitions, start, accept }
81    }
82
83    pub(crate) fn from_byte(byte: Byte) -> Self {
84        Self::from_transitions(|accept| Transitions {
85            byte_transitions: EdgeSet::new(byte, accept),
86            ref_transitions: Map::default(),
87        })
88    }
89
90    pub(crate) fn from_ref(r: Reference<R, T>) -> Self {
91        Self::from_transitions(|accept| Transitions {
92            byte_transitions: EdgeSet::empty(),
93            ref_transitions: [(r, accept)].into_iter().collect(),
94        })
95    }
96
97    fn from_transitions(f: impl FnOnce(State) -> Transitions<R, T>) -> Self {
98        let start = State::new();
99        let accept = State::new();
100
101        Self { transitions: [(start, f(accept))].into_iter().collect(), start, accept }
102    }
103
104    pub(crate) fn from_tree(tree: Tree<!, R, T>) -> Result<Self, Uninhabited> {
105        Ok(match tree {
106            Tree::Byte(b) => Self::from_byte(b),
107            Tree::Ref(r) => Self::from_ref(r),
108            Tree::Alt(alts) => {
109                // Convert and filter the inhabited alternatives.
110                let mut alts = alts.into_iter().map(Self::from_tree).filter_map(Result::ok);
111                // If there are no alternatives, return `Uninhabited`.
112                let dfa = alts.next().ok_or(Uninhabited)?;
113                // Combine the remaining alternatives with `dfa`.
114                alts.fold(dfa, |dfa, alt| dfa.union(alt, State::new))
115            }
116            Tree::Seq(elts) => {
117                let mut dfa = Self::unit();
118                for elt in elts.into_iter().map(Self::from_tree) {
119                    dfa = dfa.concat(elt?);
120                }
121                dfa
122            }
123        })
124    }
125
126    /// Concatenate two `Dfa`s.
127    pub(crate) fn concat(self, other: Self) -> Self {
128        if self.start == self.accept {
129            return other;
130        } else if other.start == other.accept {
131            return self;
132        }
133
134        let start = self.start;
135        let accept = other.accept;
136
137        let mut transitions: Map<State, Transitions<R, T>> = self.transitions;
138
139        for (source, transition) in other.transitions {
140            let fix_state = |state| if state == other.start { self.accept } else { state };
141            let byte_transitions = transition.byte_transitions.map_states(&fix_state);
142            let ref_transitions = transition
143                .ref_transitions
144                .into_iter()
145                .map(|(r, state)| (r, fix_state(state)))
146                .collect();
147
148            let old = transitions
149                .insert(fix_state(source), Transitions { byte_transitions, ref_transitions });
150            if !old.is_none() {
    ::core::panicking::panic("assertion failed: old.is_none()")
};assert!(old.is_none());
151        }
152
153        Self { transitions, start, accept }
154    }
155
156    /// Compute the union of two `Dfa`s.
157    pub(crate) fn union(self, other: Self, mut new_state: impl FnMut() -> State) -> Self {
158        // We implement `union` by lazily initializing a set of states
159        // corresponding to the product of states in `self` and `other`, and
160        // then add transitions between these states that correspond to where
161        // they exist between `self` and `other`.
162
163        let a = self;
164        let b = other;
165
166        let accept = new_state();
167
168        let mut mapping: Map<(Option<State>, Option<State>), State> = Map::default();
169
170        let mut mapped = |(a_state, b_state)| {
171            if Some(a.accept) == a_state || Some(b.accept) == b_state {
172                // If either `a_state` or `b_state` are accepting, map to a
173                // common `accept` state.
174                accept
175            } else {
176                *mapping.entry((a_state, b_state)).or_insert_with(&mut new_state)
177            }
178        };
179
180        let start = mapped((Some(a.start), Some(b.start)));
181        let mut transitions: Map<State, Transitions<R, T>> = Map::default();
182        let empty_transitions = Transitions::default();
183
184        struct WorkQueue {
185            queue: Vec<(Option<State>, Option<State>)>,
186            // Track all entries ever enqueued to avoid duplicating work. This
187            // gives us a guarantee that a given (a_state, b_state) pair will
188            // only ever be visited once.
189            enqueued: Set<(Option<State>, Option<State>)>,
190        }
191        impl WorkQueue {
192            fn enqueue(&mut self, a_state: Option<State>, b_state: Option<State>) {
193                if self.enqueued.insert((a_state, b_state)) {
194                    self.queue.push((a_state, b_state));
195                }
196            }
197        }
198        let mut queue = WorkQueue { queue: Vec::new(), enqueued: Set::default() };
199        queue.enqueue(Some(a.start), Some(b.start));
200
201        while let Some((a_src, b_src)) = queue.queue.pop() {
202            let src = mapped((a_src, b_src));
203            if src == accept {
204                // While it's possible to have a DFA whose accept state has
205                // out-edges, these do not affect the semantics of the DFA, and
206                // so there's no point in processing them. Continuing here also
207                // has the advantage of guaranteeing that we only ever process a
208                // given node in the output DFA once. In particular, with the
209                // exception of the accept state, we ensure that we only push a
210                // given node to the `queue` once. This allows the following
211                // code to assume that we're processing a node we've never
212                // processed before, which means we never need to merge two edge
213                // sets - we only ever need to construct a new edge set from
214                // whole cloth.
215                continue;
216            }
217
218            let a_transitions =
219                a_src.and_then(|a_src| a.transitions.get(&a_src)).unwrap_or(&empty_transitions);
220            let b_transitions =
221                b_src.and_then(|b_src| b.transitions.get(&b_src)).unwrap_or(&empty_transitions);
222
223            let byte_transitions = a_transitions.byte_transitions.union(
224                &b_transitions.byte_transitions,
225                |a_dst, b_dst| {
226                    if !(a_dst.is_some() || b_dst.is_some()) {
    ::core::panicking::panic("assertion failed: a_dst.is_some() || b_dst.is_some()")
};assert!(a_dst.is_some() || b_dst.is_some());
227
228                    queue.enqueue(a_dst, b_dst);
229                    mapped((a_dst, b_dst))
230                },
231            );
232
233            let ref_transitions =
234                a_transitions.ref_transitions.keys().chain(b_transitions.ref_transitions.keys());
235
236            let ref_transitions = ref_transitions
237                .map(|ref_transition| {
238                    let a_dst = a_transitions.ref_transitions.get(ref_transition).copied();
239                    let b_dst = b_transitions.ref_transitions.get(ref_transition).copied();
240
241                    if !(a_dst.is_some() || b_dst.is_some()) {
    ::core::panicking::panic("assertion failed: a_dst.is_some() || b_dst.is_some()")
};assert!(a_dst.is_some() || b_dst.is_some());
242
243                    queue.enqueue(a_dst, b_dst);
244                    (*ref_transition, mapped((a_dst, b_dst)))
245                })
246                .collect();
247
248            let old = transitions.insert(src, Transitions { byte_transitions, ref_transitions });
249            // See `if src == accept { ... }` above. The comment there explains
250            // why this assert is valid.
251            {
    match (&old, &None) {
        (left_val, right_val) => {
            if !(*left_val == *right_val) {
                let kind = ::core::panicking::AssertKind::Eq;
                ::core::panicking::assert_failed(kind, &*left_val,
                    &*right_val, ::core::option::Option::None);
            }
        }
    }
};assert_eq!(old, None);
252        }
253
254        Self { transitions, start, accept }
255    }
256
257    pub(crate) fn get_uninit_edge_dst(&self, state: State) -> Option<State> {
258        let transitions = self.transitions.get(&state)?;
259        transitions.byte_transitions.get_uninit_edge_dst()
260    }
261
262    pub(crate) fn bytes_from(&self, start: State) -> impl Iterator<Item = (Byte, State)> {
263        self.transitions
264            .get(&start)
265            .map(|transitions| transitions.byte_transitions.iter())
266            .into_flat_iter()
267    }
268
269    pub(crate) fn refs_from(&self, start: State) -> impl Iterator<Item = (Reference<R, T>, State)> {
270        self.transitions
271            .get(&start)
272            .map(|transitions| transitions.ref_transitions.iter())
273            .into_flat_iter()
274            .map(|(r, s)| (*r, *s))
275    }
276
277    #[cfg(test)]
278    pub(crate) fn from_edges<B: Clone + Into<Byte>>(
279        start: u32,
280        accept: u32,
281        edges: &[(u32, B, u32)],
282    ) -> Self {
283        let start = State(start);
284        let accept = State(accept);
285        let mut transitions: Map<State, Vec<(Byte, State)>> = Map::default();
286
287        for &(src, ref edge, dst) in edges.iter() {
288            transitions.entry(State(src)).or_default().push((edge.clone().into(), State(dst)));
289        }
290
291        let transitions = transitions
292            .into_iter()
293            .map(|(src, edges)| {
294                (
295                    src,
296                    Transitions {
297                        byte_transitions: EdgeSet::from_edges(edges),
298                        ref_transitions: Map::default(),
299                    },
300                )
301            })
302            .collect();
303
304        Self { start, accept, transitions }
305    }
306}
307
308/// Serialize the DFA using the Graphviz DOT format.
309impl<R, T> fmt::Debug for Dfa<R, T>
310where
311    R: Region,
312    T: Type,
313{
314    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
315        f.write_fmt(format_args!("digraph {{\n"))writeln!(f, "digraph {{")?;
316        f.write_fmt(format_args!("    start [shape = point, style = invis]\n"))writeln!(f, "    start [shape = point, style = invis]")?;
317        f.write_fmt(format_args!("    start -> {0:?}\n", self.start))writeln!(f, "    start -> {:?}", self.start)?;
318        f.write_fmt(format_args!("    {0:?} [shape = doublecircle]\n", self.accept))writeln!(f, "    {:?} [shape = doublecircle]", self.accept)?;
319
320        for (src, transitions) in self.transitions.iter() {
321            for (t, dst) in transitions.byte_transitions.iter() {
322                f.write_fmt(format_args!("    {0:?} -> {1:?} [label=\"{2:?}\"]\n", src, dst,
        t))writeln!(f, "    {src:?} -> {dst:?} [label=\"{t:?}\"]")?;
323            }
324
325            for (t, dst) in transitions.ref_transitions.iter() {
326                f.write_fmt(format_args!("    {0:?} -> {1:?} [label=\"{2:?}\"]\n", src, dst,
        t))writeln!(f, "    {src:?} -> {dst:?} [label=\"{t:?}\"]")?;
327            }
328        }
329
330        f.write_fmt(format_args!("}}\n"))writeln!(f, "}}")
331    }
332}
333
334use edge_set::EdgeSet;
335mod edge_set {
336    use smallvec::SmallVec;
337
338    use super::*;
339
340    /// The set of outbound byte edges associated with a DFA node.
341    #[derive(#[automatically_derived]
impl<S: ::core::cmp::Eq> ::core::cmp::Eq for EdgeSet<S> {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<SmallVec<[(Byte, S); 1]>>;
    }
}Eq, #[automatically_derived]
impl<S: ::core::cmp::PartialEq> ::core::marker::StructuralPartialEq for
    EdgeSet<S> {
}
#[automatically_derived]
impl<S: ::core::cmp::PartialEq> ::core::cmp::PartialEq for EdgeSet<S> {
    #[inline]
    fn eq(&self, other: &EdgeSet<S>) -> bool { self.runs == other.runs }
}PartialEq, #[automatically_derived]
impl<S: ::core::clone::Clone> ::core::clone::Clone for EdgeSet<S> {
    #[inline]
    fn clone(&self) -> EdgeSet<S> {
        EdgeSet { runs: ::core::clone::Clone::clone(&self.runs) }
    }
}Clone, #[automatically_derived]
impl<S: ::core::fmt::Debug> ::core::fmt::Debug for EdgeSet<S> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field1_finish(f, "EdgeSet",
            "runs", &&self.runs)
    }
}Debug)]
342    pub(super) struct EdgeSet<S = State> {
343        // A sequence of byte edges with contiguous byte values and a common
344        // destination is stored as a single run.
345        //
346        // Runs are non-empty, non-overlapping, and stored in ascending order.
347        runs: SmallVec<[(Byte, S); 1]>,
348    }
349
350    impl<S> EdgeSet<S> {
351        pub(crate) fn new(range: Byte, dst: S) -> Self {
352            let mut this = Self { runs: SmallVec::new() };
353            if !range.is_empty() {
354                this.runs.push((range, dst));
355            }
356            this
357        }
358
359        pub(crate) fn empty() -> Self {
360            Self { runs: SmallVec::new() }
361        }
362
363        #[cfg(test)]
364        pub(crate) fn from_edges(mut edges: Vec<(Byte, S)>) -> Self
365        where
366            S: Ord,
367        {
368            edges.sort();
369            Self { runs: edges.into() }
370        }
371
372        pub(crate) fn iter(&self) -> impl Iterator<Item = (Byte, S)>
373        where
374            S: Copy,
375        {
376            self.runs.iter().copied()
377        }
378
379        pub(crate) fn get_uninit_edge_dst(&self) -> Option<S>
380        where
381            S: Copy,
382        {
383            // Uninit is ordered last.
384            let &(range, dst) = self.runs.last()?;
385            if range.contains_uninit() { Some(dst) } else { None }
386        }
387
388        pub(crate) fn map_states<SS>(self, mut f: impl FnMut(S) -> SS) -> EdgeSet<SS> {
389            EdgeSet { runs: self.runs.into_iter().map(|(b, s)| (b, f(s))).collect() }
390        }
391
392        /// Unions two edge sets together.
393        ///
394        /// If `u = a.union(b)`, then for each byte value, `u` will have an edge
395        /// with that byte value and with the destination `join(Some(_), None)`,
396        /// `join(None, Some(_))`, or `join(Some(_), Some(_))` depending on whether `a`,
397        /// `b`, or both have an edge with that byte value.
398        ///
399        /// If neither `a` nor `b` have an edge with a particular byte value,
400        /// then no edge with that value will be present in `u`.
401        pub(crate) fn union(
402            &self,
403            other: &Self,
404            mut join: impl FnMut(Option<S>, Option<S>) -> S,
405        ) -> EdgeSet<S>
406        where
407            S: Copy + Eq,
408        {
409            let mut runs: SmallVec<[(Byte, S); 1]> = SmallVec::new();
410            let xs = self.runs.iter().copied();
411            let ys = other.runs.iter().copied();
412            for (range, (x, y)) in union(xs, ys) {
413                let state = join(x, y);
414                match runs.last_mut() {
415                    // Merge contiguous runs with a common destination.
416                    Some(&mut (ref mut last_range, ref mut last_state))
417                        if last_range.end == range.start && *last_state == state =>
418                    {
419                        last_range.end = range.end
420                    }
421                    _ => runs.push((range, state)),
422                }
423            }
424            EdgeSet { runs }
425        }
426    }
427}
428
429/// Partitions two sequences of byte edges into sorted, non-overlapping ranges.
430///
431/// Within each input, ranges must be non-empty, non-overlapping, and sorted by
432/// ascending start. Each output item contains a range and the destination of the
433/// edge from each input that covers it. An input with no edge covering the range
434/// contributes `None`. Ranges covered by neither input are omitted. Adjacent
435/// output ranges are not coalesced.
436pub(crate) fn union<S: Copy, X: Iterator<Item = (Byte, S)>, Y: Iterator<Item = (Byte, S)>>(
437    xs: X,
438    ys: Y,
439) -> UnionIter<X, Y> {
440    UnionIter { xs: xs.peekable(), ys: ys.peekable() }
441}
442
443pub(crate) struct UnionIter<X: Iterator, Y: Iterator> {
444    xs: Peekable<X>,
445    ys: Peekable<Y>,
446}
447
448// FIXME(jswrenn) we'd likely benefit from specializing try_fold here.
449impl<S: Copy, X: Iterator<Item = (Byte, S)>, Y: Iterator<Item = (Byte, S)>> Iterator
450    for UnionIter<X, Y>
451{
452    type Item = (Byte, (Option<S>, Option<S>));
453
454    fn next(&mut self) -> Option<Self::Item> {
455        use std::cmp::{self, Ordering};
456
457        let ret;
458        match (self.xs.peek_mut(), self.ys.peek_mut()) {
459            (None, None) => {
460                ret = None;
461            }
462            (Some(x), None) => {
463                ret = Some((x.0, (Some(x.1), None)));
464                self.xs.next();
465            }
466            (None, Some(y)) => {
467                ret = Some((y.0, (None, Some(y.1))));
468                self.ys.next();
469            }
470            (Some(x), Some(y)) => {
471                let start;
472                let end;
473                let dst;
474                match x.0.start.cmp(&y.0.start) {
475                    Ordering::Less => {
476                        start = x.0.start;
477                        end = cmp::min(x.0.end, y.0.start);
478                        dst = (Some(x.1), None);
479                    }
480                    Ordering::Greater => {
481                        start = y.0.start;
482                        end = cmp::min(x.0.start, y.0.end);
483                        dst = (None, Some(y.1));
484                    }
485                    Ordering::Equal => {
486                        start = x.0.start;
487                        end = cmp::min(x.0.end, y.0.end);
488                        dst = (Some(x.1), Some(y.1));
489                    }
490                }
491                ret = Some((Byte { start, end }, dst));
492                if start == x.0.start {
493                    x.0.start = end;
494                }
495                if start == y.0.start {
496                    y.0.start = end;
497                }
498                if x.0.is_empty() {
499                    self.xs.next();
500                }
501                if y.0.is_empty() {
502                    self.ys.next();
503                }
504            }
505        }
506        ret
507    }
508}