Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/codegen/meta/src/unique_table.rs
1692 views
1
//! An index-accessed table implementation that avoids duplicate entries.
2
use std::collections::HashMap;
3
use std::hash::Hash;
4
use std::slice;
5
6
/// Collect items into the `table` list, removing duplicates.
7
pub(crate) struct UniqueTable<'entries, T: Eq + Hash> {
8
table: Vec<&'entries T>,
9
map: HashMap<&'entries T, usize>,
10
}
11
12
impl<'entries, T: Eq + Hash> UniqueTable<'entries, T> {
13
pub fn new() -> Self {
14
Self {
15
table: Vec::new(),
16
map: HashMap::new(),
17
}
18
}
19
20
pub fn add(&mut self, entry: &'entries T) -> usize {
21
match self.map.get(&entry) {
22
None => {
23
let i = self.table.len();
24
self.table.push(entry);
25
self.map.insert(entry, i);
26
i
27
}
28
Some(&i) => i,
29
}
30
}
31
32
pub fn len(&self) -> usize {
33
self.table.len()
34
}
35
pub fn iter(&self) -> slice::Iter<'_, &'entries T> {
36
self.table.iter()
37
}
38
}
39
40
/// A table of sequences which tries to avoid common subsequences.
41
pub(crate) struct UniqueSeqTable<T: PartialEq + Clone> {
42
table: Vec<T>,
43
}
44
45
impl<T: PartialEq + Clone> UniqueSeqTable<T> {
46
pub fn new() -> Self {
47
Self { table: Vec::new() }
48
}
49
pub fn add(&mut self, values: &[T]) -> usize {
50
if values.is_empty() {
51
return 0;
52
}
53
if let Some(offset) = find_subsequence(values, &self.table) {
54
offset
55
} else {
56
let table_len = self.table.len();
57
58
// Try to put in common the last elements of the table if they're a prefix of the new
59
// sequence.
60
//
61
// We know there wasn't a full match, so the best prefix we can hope to find contains
62
// all the values but the last one.
63
let mut start_from = usize::min(table_len, values.len() - 1);
64
while start_from != 0 {
65
// Loop invariant: start_from <= table_len, so table_len - start_from >= 0.
66
if values[0..start_from] == self.table[table_len - start_from..table_len] {
67
break;
68
}
69
start_from -= 1;
70
}
71
72
self.table
73
.extend(values[start_from..values.len()].iter().cloned());
74
table_len - start_from
75
}
76
}
77
pub fn len(&self) -> usize {
78
self.table.len()
79
}
80
pub fn iter(&self) -> slice::Iter<'_, T> {
81
self.table.iter()
82
}
83
}
84
85
/// Try to find the subsequence `sub` in the `whole` sequence. Returns None if
86
/// it's not been found, or Some(index) if it has been. Naive implementation
87
/// until proven we need something better.
88
fn find_subsequence<T: PartialEq>(sub: &[T], whole: &[T]) -> Option<usize> {
89
assert!(!sub.is_empty());
90
// We want i + sub.len() <= whole.len(), i.e. i < whole.len() + 1 - sub.len().
91
if whole.len() < sub.len() {
92
return None;
93
}
94
let max = whole.len() - sub.len();
95
for i in 0..=max {
96
if whole[i..i + sub.len()] == sub[..] {
97
return Some(i);
98
}
99
}
100
None
101
}
102
103
#[test]
104
fn test_find_subsequence() {
105
assert_eq!(find_subsequence(&vec![1], &vec![4]), None);
106
assert_eq!(find_subsequence(&vec![1], &vec![1]), Some(0));
107
assert_eq!(find_subsequence(&vec![1, 2], &vec![1]), None);
108
assert_eq!(find_subsequence(&vec![1, 2], &vec![1, 2]), Some(0));
109
assert_eq!(find_subsequence(&vec![1, 2], &vec![1, 3]), None);
110
assert_eq!(find_subsequence(&vec![1, 2], &vec![0, 1, 2]), Some(1));
111
assert_eq!(find_subsequence(&vec![1, 2], &vec![0, 1, 3, 1]), None);
112
assert_eq!(find_subsequence(&vec![1, 2], &vec![0, 1, 3, 1, 2]), Some(3));
113
assert_eq!(
114
find_subsequence(&vec![1, 1, 3], &vec![1, 1, 1, 3, 3]),
115
Some(1)
116
);
117
}
118
119
#[test]
120
fn test_optimal_add() {
121
let mut seq_table = UniqueSeqTable::new();
122
// [0, 1, 2, 3]
123
assert_eq!(seq_table.add(&vec![0, 1, 2, 3]), 0);
124
assert_eq!(seq_table.add(&vec![0, 1, 2, 3]), 0);
125
assert_eq!(seq_table.add(&vec![1, 2, 3]), 1);
126
assert_eq!(seq_table.add(&vec![2, 3]), 2);
127
assert_eq!(seq_table.len(), 4);
128
// [0, 1, 2, 3, 4]
129
assert_eq!(seq_table.add(&vec![2, 3, 4]), 2);
130
assert_eq!(seq_table.len(), 5);
131
// [0, 1, 2, 3, 4, 6, 5, 7]
132
assert_eq!(seq_table.add(&vec![4, 6, 5, 7]), 4);
133
assert_eq!(seq_table.len(), 8);
134
// [0, 1, 2, 3, 4, 6, 5, 7, 8, 2, 3, 4]
135
assert_eq!(seq_table.add(&vec![8, 2, 3, 4]), 8);
136
assert_eq!(seq_table.add(&vec![8]), 8);
137
assert_eq!(seq_table.len(), 12);
138
}
139
140