1
//! Module for storing positions of terms
2
use core::fmt;
3
use mcrl2::aterm::ATermRef;
4
use smallvec::smallvec;
5
use smallvec::SmallVec;
6
use std::collections::VecDeque;
7

            
8
/// An ExplicitPosition stores a list of position indices. The index starts at 1.
9
/// The subterm of term s(s(0)) at position 1.1 is 0.
10
/// The empty position, aka the root term, is represented by the symbol ε.
11
/// Indices are stored in a SmallVec, which is configured to store 4 elements.
12
/// If the position contains a maximum of 4 elements it is stored on the stack.
13
/// If the position is longer a heap allocation is made.
14
#[derive(Hash, Clone, Default, Eq, PartialEq, Ord, PartialOrd)]
15
pub struct ExplicitPosition {
16
    pub indices: SmallVec<[usize; 4]>,
17
}
18

            
19
impl ExplicitPosition {
20
11
    pub fn new(indices: &[usize]) -> ExplicitPosition {
21
11
        ExplicitPosition {
22
11
            indices: SmallVec::from(indices),
23
11
        }
24
11
    }
25

            
26
1260884
    pub fn empty_pos() -> ExplicitPosition {
27
1260884
        ExplicitPosition { indices: smallvec![] }
28
1260884
    }
29

            
30
28419340
    pub fn len(&self) -> usize {
31
28419340
        self.indices.len()
32
28419340
    }
33

            
34
12812780
    pub fn is_empty(&self) -> bool {
35
12812780
        self.indices.len() == 0
36
12812780
    }
37
}
38

            
39
impl PositionIndexed for ATermRef<'_> {
40
    type Target<'a>
41
        = ATermRef<'a>
42
    where
43
        Self: 'a;
44

            
45
267914370
    fn get_position<'a>(&'a self, position: &ExplicitPosition) -> Self::Target<'a> {
46
267914370
        let mut result = self.copy();
47

            
48
431006426
        for index in &position.indices {
49
163092056
            result = result.arg(index - 1).upgrade(self); // Note that positions are 1 indexed.
50
163092056
        }
51

            
52
267914370
        result
53
267914370
    }
54
}
55

            
56
pub trait PositionIndexed {
57
    type Target<'a>
58
    where
59
        Self: 'a;
60

            
61
    /// Returns the Target at the given position.
62
    fn get_position<'a>(&'a self, position: &ExplicitPosition) -> Self::Target<'a>;
63
}
64

            
65
impl fmt::Display for ExplicitPosition {
66
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67
        if self.indices.is_empty() {
68
            write!(f, "ε")?;
69
        } else {
70
            let mut first = true;
71
            for p in &self.indices {
72
                if first {
73
                    write!(f, "{}", p)?;
74
                    first = false;
75
                } else {
76
                    write!(f, ".{}", p)?;
77
                }
78
            }
79
        }
80

            
81
        Ok(())
82
    }
83
}
84

            
85
impl fmt::Debug for ExplicitPosition {
86
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
87
        write!(f, "{}", self)
88
    }
89
}
90

            
91
/// An iterator over all (term, position) pairs of the given ATerm.
92
pub struct PositionIterator<'a> {
93
    queue: VecDeque<(ATermRef<'a>, ExplicitPosition)>,
94
}
95

            
96
impl<'a> PositionIterator<'a> {
97
358588
    pub fn new(t: ATermRef<'a>) -> PositionIterator<'a> {
98
358588
        PositionIterator {
99
358588
            queue: VecDeque::from([(t, ExplicitPosition::empty_pos())]),
100
358588
        }
101
358588
    }
102
}
103

            
104
impl<'a> Iterator for PositionIterator<'a> {
105
    type Item = (ATermRef<'a>, ExplicitPosition);
106

            
107
6826048
    fn next(&mut self) -> Option<Self::Item> {
108
6826048
        if self.queue.is_empty() {
109
358588
            None
110
        } else {
111
            // Get a subterm to inspect
112
6467460
            let (term, pos) = self.queue.pop_front().unwrap();
113

            
114
            // Put subterms in the queue
115
6467460
            for (i, argument) in term.arguments().enumerate() {
116
6108872
                let mut new_position = pos.clone();
117
6108872
                new_position.indices.push(i + 1);
118
6108872
                self.queue.push_back((argument.upgrade(&term), new_position));
119
6108872
            }
120

            
121
6467460
            Some((term, pos))
122
        }
123
6826048
    }
124
}
125

            
126
#[cfg(test)]
127
mod tests {
128
    use mcrl2::aterm::TermPool;
129

            
130
    use super::*;
131

            
132
    #[test]
133
1
    fn test_get_position() {
134
1
        let mut tp = TermPool::new();
135
1
        let t = tp.from_string("f(g(a),b)").unwrap();
136
1
        let expected = tp.from_string("a").unwrap();
137
1

            
138
1
        assert_eq!(t.get_position(&ExplicitPosition::new(&[1, 1])), expected.copy());
139
1
    }
140

            
141
    #[test]
142
1
    fn test_position_iterator() {
143
1
        let mut tp = TermPool::new();
144
1
        let t = tp.from_string("f(g(a),b)").unwrap();
145

            
146
4
        for (term, pos) in PositionIterator::new(t.copy()) {
147
4
            assert_eq!(
148
4
                t.get_position(&pos),
149
                term,
150
                "The resulting (subterm, position) pair doesn't match the get_position implementation"
151
            );
152
        }
153

            
154
1
        assert_eq!(
155
1
            PositionIterator::new(t.copy()).count(),
156
            4,
157
            "The number of subterms doesn't match the expected value"
158
        );
159
1
    }
160
}