/src/regalloc.rs/lib/src/sparse_set.rs
Line | Count | Source (jump to first uncovered line) |
1 | | #![allow(non_snake_case)] |
2 | | #![allow(non_camel_case_types)] |
3 | | |
4 | | //! An implementation of sets which aims to be fast for both large sets and |
5 | | //! very small sets, even if the elements are sparse relative to the universe. |
6 | | |
7 | | use rustc_hash::FxHashSet; |
8 | | use std::fmt; |
9 | | use std::hash::Hash; |
10 | | |
11 | | //============================================================================= |
12 | | // SparseSet |
13 | | |
14 | | // Handy wrappers around `SparseSetU`, if you don't want to have to guess at an "optimal" |
15 | | // in-line size. |
16 | | pub type SparseSet<T> = SparseSetU<[T; 12]>; |
17 | | //pub type SparseSetIter<'a, T> = SparseSetUIter<'a, [T; 12]>; // No use case yet |
18 | | |
19 | | // Implementation: for small, unordered but no dups |
20 | | |
21 | | use core::mem::MaybeUninit; |
22 | | use core::ptr::{read, write}; |
23 | | |
24 | | // Types that can be used as the backing store for a SparseSet. |
25 | | pub trait Array { |
26 | | // The type of the array's elements. |
27 | | type Item; |
28 | | // Returns the number of items the array can hold. |
29 | | fn size() -> usize; |
30 | | } |
31 | | macro_rules! impl_array( |
32 | | ($($size:expr),+) => { |
33 | | $( |
34 | | impl<T> Array for [T; $size] { |
35 | | type Item = T; |
36 | 610k | fn size() -> usize { $size }<[regalloc::data_structures::BlockIx; 4] as regalloc::sparse_set::Array>::size Line | Count | Source | 36 | 101k | fn size() -> usize { $size } |
<[regalloc::data_structures::VirtualRangeIx; 4] as regalloc::sparse_set::Array>::size Line | Count | Source | 36 | 43.9k | fn size() -> usize { $size } |
<[regalloc::data_structures::Reg; 12] as regalloc::sparse_set::Array>::size Line | Count | Source | 36 | 391k | fn size() -> usize { $size } |
<[regalloc::data_structures::RangeId; 12] as regalloc::sparse_set::Array>::size Line | Count | Source | 36 | 28.4k | fn size() -> usize { $size } |
<[regalloc::data_structures::RangeId; 4] as regalloc::sparse_set::Array>::size Line | Count | Source | 36 | 44.5k | fn size() -> usize { $size } |
|
37 | | } |
38 | | )+ |
39 | | } |
40 | | ); |
41 | | impl_array!(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 28, 32); |
42 | | |
43 | | // The U here stands for "unordered". It refers to the fact that the elements |
44 | | // in `Small::arr` are in no particular order, although they are |
45 | | // duplicate-free. |
46 | | pub enum SparseSetU<A: Array> { |
47 | | Large { set: FxHashSet<A::Item> }, |
48 | | Small { card: usize, arr: MaybeUninit<A> }, |
49 | | } |
50 | | |
51 | | // ================ Admin (private) methods ================ |
52 | | |
53 | | impl<A> SparseSetU<A> |
54 | | where |
55 | | A: Array, |
56 | | A::Item: Eq + Hash + Copy, |
57 | | { |
58 | | #[cfg(test)] |
59 | | fn is_small(&self) -> bool { |
60 | | match self { |
61 | | SparseSetU::Large { .. } => false, |
62 | | SparseSetU::Small { .. } => true, |
63 | | } |
64 | | } |
65 | | |
66 | | #[cfg(test)] |
67 | | fn is_large(&self) -> bool { |
68 | | !self.is_small() |
69 | | } |
70 | | |
71 | | #[inline(never)] |
72 | 1.53k | fn upgrade(&mut self) { |
73 | 1.53k | match self { |
74 | 0 | SparseSetU::Large { .. } => panic!("SparseSetU: upgrade"), |
75 | 1.53k | SparseSetU::Small { card, arr } => { |
76 | 1.53k | assert!(*card == A::size()); |
77 | 1.53k | let mut set = FxHashSet::<A::Item>::default(); |
78 | 1.53k | set.reserve(A::size()); |
79 | 1.53k | // Could this be done faster? |
80 | 1.53k | let arr_p = arr.as_mut_ptr() as *mut A::Item; |
81 | 13.2k | for i in 0..*card { |
82 | 13.2k | set.insert(unsafe { read(arr_p.add(i)) }); |
83 | 13.2k | } |
84 | 1.53k | *self = SparseSetU::Large { set } |
85 | 1.53k | } |
86 | 1.53k | } |
87 | 1.53k | } Unexecuted instantiation: <regalloc::sparse_set::SparseSetU<[regalloc::linear_scan::analysis::RangeId; 12]>>::upgrade <regalloc::sparse_set::SparseSetU<[regalloc::data_structures::Reg; 12]>>::upgrade Line | Count | Source | 72 | 450 | fn upgrade(&mut self) { | 73 | 450 | match self { | 74 | 0 | SparseSetU::Large { .. } => panic!("SparseSetU: upgrade"), | 75 | 450 | SparseSetU::Small { card, arr } => { | 76 | 450 | assert!(*card == A::size()); | 77 | 450 | let mut set = FxHashSet::<A::Item>::default(); | 78 | 450 | set.reserve(A::size()); | 79 | 450 | // Could this be done faster? | 80 | 450 | let arr_p = arr.as_mut_ptr() as *mut A::Item; | 81 | 5.40k | for i in 0..*card { | 82 | 5.40k | set.insert(unsafe { read(arr_p.add(i)) }); | 83 | 5.40k | } | 84 | 450 | *self = SparseSetU::Large { set } | 85 | 450 | } | 86 | 450 | } | 87 | 450 | } |
<regalloc::sparse_set::SparseSetU<[regalloc::data_structures::RangeId; 12]>>::upgrade Line | Count | Source | 72 | 441 | fn upgrade(&mut self) { | 73 | 441 | match self { | 74 | 0 | SparseSetU::Large { .. } => panic!("SparseSetU: upgrade"), | 75 | 441 | SparseSetU::Small { card, arr } => { | 76 | 441 | assert!(*card == A::size()); | 77 | 441 | let mut set = FxHashSet::<A::Item>::default(); | 78 | 441 | set.reserve(A::size()); | 79 | 441 | // Could this be done faster? | 80 | 441 | let arr_p = arr.as_mut_ptr() as *mut A::Item; | 81 | 5.29k | for i in 0..*card { | 82 | 5.29k | set.insert(unsafe { read(arr_p.add(i)) }); | 83 | 5.29k | } | 84 | 441 | *self = SparseSetU::Large { set } | 85 | 441 | } | 86 | 441 | } | 87 | 441 | } |
<regalloc::sparse_set::SparseSetU<[regalloc::data_structures::VirtualRangeIx; 4]>>::upgrade Line | Count | Source | 72 | 103 | fn upgrade(&mut self) { | 73 | 103 | match self { | 74 | 0 | SparseSetU::Large { .. } => panic!("SparseSetU: upgrade"), | 75 | 103 | SparseSetU::Small { card, arr } => { | 76 | 103 | assert!(*card == A::size()); | 77 | 103 | let mut set = FxHashSet::<A::Item>::default(); | 78 | 103 | set.reserve(A::size()); | 79 | 103 | // Could this be done faster? | 80 | 103 | let arr_p = arr.as_mut_ptr() as *mut A::Item; | 81 | 412 | for i in 0..*card { | 82 | 412 | set.insert(unsafe { read(arr_p.add(i)) }); | 83 | 412 | } | 84 | 103 | *self = SparseSetU::Large { set } | 85 | 103 | } | 86 | 103 | } | 87 | 103 | } |
<regalloc::sparse_set::SparseSetU<[regalloc::data_structures::RangeId; 4]>>::upgrade Line | Count | Source | 72 | 221 | fn upgrade(&mut self) { | 73 | 221 | match self { | 74 | 0 | SparseSetU::Large { .. } => panic!("SparseSetU: upgrade"), | 75 | 221 | SparseSetU::Small { card, arr } => { | 76 | 221 | assert!(*card == A::size()); | 77 | 221 | let mut set = FxHashSet::<A::Item>::default(); | 78 | 221 | set.reserve(A::size()); | 79 | 221 | // Could this be done faster? | 80 | 221 | let arr_p = arr.as_mut_ptr() as *mut A::Item; | 81 | 884 | for i in 0..*card { | 82 | 884 | set.insert(unsafe { read(arr_p.add(i)) }); | 83 | 884 | } | 84 | 221 | *self = SparseSetU::Large { set } | 85 | 221 | } | 86 | 221 | } | 87 | 221 | } |
Unexecuted instantiation: <regalloc::sparse_set::SparseSetU<[regalloc::linear_scan::analysis::RangeId; 4]>>::upgrade <regalloc::sparse_set::SparseSetU<[regalloc::data_structures::BlockIx; 4]>>::upgrade Line | Count | Source | 72 | 317 | fn upgrade(&mut self) { | 73 | 317 | match self { | 74 | 0 | SparseSetU::Large { .. } => panic!("SparseSetU: upgrade"), | 75 | 317 | SparseSetU::Small { card, arr } => { | 76 | 317 | assert!(*card == A::size()); | 77 | 317 | let mut set = FxHashSet::<A::Item>::default(); | 78 | 317 | set.reserve(A::size()); | 79 | 317 | // Could this be done faster? | 80 | 317 | let arr_p = arr.as_mut_ptr() as *mut A::Item; | 81 | 1.26k | for i in 0..*card { | 82 | 1.26k | set.insert(unsafe { read(arr_p.add(i)) }); | 83 | 1.26k | } | 84 | 317 | *self = SparseSetU::Large { set } | 85 | 317 | } | 86 | 317 | } | 87 | 317 | } |
|
88 | | |
89 | | // A large set is only downgradeable if its card does not exceed this value. |
90 | | #[inline(always)] |
91 | 2.60k | fn small_halfmax_card(&self) -> usize { |
92 | 2.60k | let limit = A::size(); |
93 | 2.60k | //if limit >= 4 { |
94 | 2.60k | // limit / 2 |
95 | 2.60k | //} else { |
96 | 2.60k | // limit - 1 |
97 | 2.60k | //} |
98 | 2.60k | if false { |
99 | | // Set the transition point as roughly half of the inline size |
100 | | match limit { |
101 | | 0 | 1 => panic!("SparseSetU: small_halfmax_card"), |
102 | | 2 => 1, |
103 | | 3 => 2, |
104 | | 4 => 2, |
105 | | 5 => 3, |
106 | | 6 => 3, |
107 | | _ => limit / 2, |
108 | | } |
109 | | } else { |
110 | | // Set the transition point as roughly two thirds of the inline size |
111 | 2.60k | match limit { |
112 | 0 | 0 | 1 => panic!("SparseSetU: small_halfmax_card"), |
113 | 0 | 2 => 1, |
114 | 0 | 3 => 2, |
115 | 0 | 4 => 3, |
116 | 0 | 5 => 4, |
117 | 0 | 6 => 4, |
118 | | // FIXME JRS 2020Apr10 avoid possible integer overflow here: |
119 | 2.60k | _ => (2 * limit) / 3, |
120 | | } |
121 | | } |
122 | 2.60k | } |
123 | | |
124 | | // If we have a large-format set, but the cardinality has fallen below half |
125 | | // the size of a small format set, convert it to the small format. This |
126 | | // isn't done at the point when the cardinality falls to the max capacity of |
127 | | // a small set in order to give some hysteresis -- we don't want to be |
128 | | // constantly converting back and forth for a set whose size repeatedly |
129 | | // crosses the border. |
130 | | #[inline(never)] |
131 | 2.60k | fn maybe_downgrade(&mut self) { |
132 | 2.60k | let small_halfmax_card = self.small_halfmax_card(); |
133 | 2.60k | match self { |
134 | 2.60k | SparseSetU::Large { set } => { |
135 | 2.60k | if set.len() <= small_halfmax_card { |
136 | 525 | let mut arr = MaybeUninit::<A>::uninit(); |
137 | 525 | let arr_p = arr.as_mut_ptr() as *mut A::Item; |
138 | 525 | let mut i = 0; |
139 | 3.67k | for e in set.iter() { |
140 | 3.67k | unsafe { write(arr_p.add(i), *e) }; |
141 | 3.67k | i += 1; |
142 | 3.67k | } |
143 | 525 | assert!(i <= small_halfmax_card); |
144 | 525 | *self = SparseSetU::Small { card: i, arr }; |
145 | 2.07k | } |
146 | | } |
147 | | SparseSetU::Small { .. } => { |
148 | 0 | panic!("SparseSetU::maybe_downgrade: is already small"); |
149 | | } |
150 | | } |
151 | 2.60k | } |
152 | | |
153 | | #[inline(always)] |
154 | 106k | fn insert_no_dup_check(&mut self, item: A::Item) { |
155 | 106k | match self { |
156 | 96 | SparseSetU::Large { set } => { |
157 | 96 | set.insert(item); |
158 | 96 | } |
159 | 106k | SparseSetU::Small { card, arr } => { |
160 | 106k | assert!(*card <= A::size()); |
161 | 106k | if *card < A::size() { |
162 | 105k | // Stay small |
163 | 105k | let arr_p = arr.as_mut_ptr() as *mut A::Item; |
164 | 105k | unsafe { |
165 | 105k | write(arr_p.add(*card), item); |
166 | 105k | } |
167 | 105k | *card += 1; |
168 | 105k | } else { |
169 | | // Transition up |
170 | 361 | self.upgrade(); |
171 | 361 | match self { |
172 | 361 | SparseSetU::Large { set } => { |
173 | 361 | let _ = set.insert(item); |
174 | 361 | } |
175 | | SparseSetU::Small { .. } => { |
176 | | // Err, what? Still Small after upgrade? |
177 | 0 | panic!("SparseSetU::insert_no_dup_check") |
178 | | } |
179 | | } |
180 | | } |
181 | | } |
182 | | } |
183 | 106k | } |
184 | | } |
185 | | |
186 | | #[inline(always)] |
187 | 303k | fn small_contains<A>(card: usize, arr: &MaybeUninit<A>, item: A::Item) -> bool |
188 | 303k | where |
189 | 303k | A: Array, |
190 | 303k | A::Item: Eq, |
191 | 303k | { |
192 | 303k | let arr_p = arr.as_ptr() as *const A::Item; |
193 | 342k | for i in 0..card { |
194 | 342k | if unsafe { read(arr_p.add(i)) } == item { |
195 | 79.4k | return true; |
196 | 262k | } |
197 | | } |
198 | 223k | false |
199 | 303k | } Unexecuted instantiation: regalloc::sparse_set::small_contains::<[regalloc::data_structures::Reg; 12]> regalloc::sparse_set::small_contains::<[regalloc::data_structures::VirtualRangeIx; 4]> Line | Count | Source | 187 | 27.6k | fn small_contains<A>(card: usize, arr: &MaybeUninit<A>, item: A::Item) -> bool | 188 | 27.6k | where | 189 | 27.6k | A: Array, | 190 | 27.6k | A::Item: Eq, | 191 | 27.6k | { | 192 | 27.6k | let arr_p = arr.as_ptr() as *const A::Item; | 193 | 27.6k | for i in 0..card { | 194 | 7.16k | if unsafe { read(arr_p.add(i)) } == item { | 195 | 5.67k | return true; | 196 | 1.49k | } | 197 | | } | 198 | 21.9k | false | 199 | 27.6k | } |
regalloc::sparse_set::small_contains::<[regalloc::data_structures::Reg; 12]> Line | Count | Source | 187 | 56.3k | fn small_contains<A>(card: usize, arr: &MaybeUninit<A>, item: A::Item) -> bool | 188 | 56.3k | where | 189 | 56.3k | A: Array, | 190 | 56.3k | A::Item: Eq, | 191 | 56.3k | { | 192 | 56.3k | let arr_p = arr.as_ptr() as *const A::Item; | 193 | 73.8k | for i in 0..card { | 194 | 73.8k | if unsafe { read(arr_p.add(i)) } == item { | 195 | 23.1k | return true; | 196 | 50.7k | } | 197 | | } | 198 | 33.1k | false | 199 | 56.3k | } |
regalloc::sparse_set::small_contains::<[regalloc::data_structures::VirtualRangeIx; 4]> Line | Count | Source | 187 | 21.8k | fn small_contains<A>(card: usize, arr: &MaybeUninit<A>, item: A::Item) -> bool | 188 | 21.8k | where | 189 | 21.8k | A: Array, | 190 | 21.8k | A::Item: Eq, | 191 | 21.8k | { | 192 | 21.8k | let arr_p = arr.as_ptr() as *const A::Item; | 193 | 21.8k | for i in 0..card { | 194 | 1.35k | if unsafe { read(arr_p.add(i)) } == item { | 195 | 0 | return true; | 196 | 1.35k | } | 197 | | } | 198 | 21.8k | false | 199 | 21.8k | } |
regalloc::sparse_set::small_contains::<[regalloc::data_structures::RangeId; 12]> Line | Count | Source | 187 | 19.4k | fn small_contains<A>(card: usize, arr: &MaybeUninit<A>, item: A::Item) -> bool | 188 | 19.4k | where | 189 | 19.4k | A: Array, | 190 | 19.4k | A::Item: Eq, | 191 | 19.4k | { | 192 | 19.4k | let arr_p = arr.as_ptr() as *const A::Item; | 193 | 79.3k | for i in 0..card { | 194 | 79.3k | if unsafe { read(arr_p.add(i)) } == item { | 195 | 8.37k | return true; | 196 | 70.9k | } | 197 | | } | 198 | 11.1k | false | 199 | 19.4k | } |
regalloc::sparse_set::small_contains::<[regalloc::data_structures::RangeId; 4]> Line | Count | Source | 187 | 22.1k | fn small_contains<A>(card: usize, arr: &MaybeUninit<A>, item: A::Item) -> bool | 188 | 22.1k | where | 189 | 22.1k | A: Array, | 190 | 22.1k | A::Item: Eq, | 191 | 22.1k | { | 192 | 22.1k | let arr_p = arr.as_ptr() as *const A::Item; | 193 | 22.1k | for i in 0..card { | 194 | 5.66k | if unsafe { read(arr_p.add(i)) } == item { | 195 | 218 | return true; | 196 | 5.44k | } | 197 | | } | 198 | 21.9k | false | 199 | 22.1k | } |
regalloc::sparse_set::small_contains::<[regalloc::data_structures::BlockIx; 4]> Line | Count | Source | 187 | 51.0k | fn small_contains<A>(card: usize, arr: &MaybeUninit<A>, item: A::Item) -> bool | 188 | 51.0k | where | 189 | 51.0k | A: Array, | 190 | 51.0k | A::Item: Eq, | 191 | 51.0k | { | 192 | 51.0k | let arr_p = arr.as_ptr() as *const A::Item; | 193 | 51.0k | for i in 0..card { | 194 | 15.4k | if unsafe { read(arr_p.add(i)) } == item { | 195 | 1.66k | return true; | 196 | 13.8k | } | 197 | | } | 198 | 49.4k | false | 199 | 51.0k | } |
Unexecuted instantiation: regalloc::sparse_set::small_contains::<[regalloc::linear_scan::analysis::RangeId; 4]> regalloc::sparse_set::small_contains::<[regalloc::data_structures::Reg; 12]> Line | Count | Source | 187 | 104k | fn small_contains<A>(card: usize, arr: &MaybeUninit<A>, item: A::Item) -> bool | 188 | 104k | where | 189 | 104k | A: Array, | 190 | 104k | A::Item: Eq, | 191 | 104k | { | 192 | 104k | let arr_p = arr.as_ptr() as *const A::Item; | 193 | 159k | for i in 0..card { | 194 | 159k | if unsafe { read(arr_p.add(i)) } == item { | 195 | 40.3k | return true; | 196 | 118k | } | 197 | | } | 198 | 64.4k | false | 199 | 104k | } |
Unexecuted instantiation: regalloc::sparse_set::small_contains::<[regalloc::linear_scan::analysis::RangeId; 12]> |
200 | | |
201 | | // ================ Public methods ================ |
202 | | |
203 | | impl<A> SparseSetU<A> |
204 | | where |
205 | | A: Array, |
206 | | A::Item: Eq + Hash + Copy, |
207 | | { |
208 | | #[inline(always)] |
209 | 290k | pub fn empty() -> Self { |
210 | 290k | SparseSetU::Small { |
211 | 290k | card: 0, |
212 | 290k | arr: MaybeUninit::uninit(), |
213 | 290k | } |
214 | 290k | } <regalloc::sparse_set::SparseSetU<[regalloc::data_structures::VirtualRangeIx; 4]>>::empty Line | Count | Source | 209 | 176k | pub fn empty() -> Self { | 210 | 176k | SparseSetU::Small { | 211 | 176k | card: 0, | 212 | 176k | arr: MaybeUninit::uninit(), | 213 | 176k | } | 214 | 176k | } |
<regalloc::sparse_set::SparseSetU<[regalloc::data_structures::Reg; 12]>>::empty Line | Count | Source | 209 | 65.2k | pub fn empty() -> Self { | 210 | 65.2k | SparseSetU::Small { | 211 | 65.2k | card: 0, | 212 | 65.2k | arr: MaybeUninit::uninit(), | 213 | 65.2k | } | 214 | 65.2k | } |
<regalloc::sparse_set::SparseSetU<[regalloc::data_structures::BlockIx; 4]>>::empty Line | Count | Source | 209 | 26.1k | pub fn empty() -> Self { | 210 | 26.1k | SparseSetU::Small { | 211 | 26.1k | card: 0, | 212 | 26.1k | arr: MaybeUninit::uninit(), | 213 | 26.1k | } | 214 | 26.1k | } |
<regalloc::sparse_set::SparseSetU<[regalloc::data_structures::RangeId; 12]>>::empty Line | Count | Source | 209 | 3.45k | pub fn empty() -> Self { | 210 | 3.45k | SparseSetU::Small { | 211 | 3.45k | card: 0, | 212 | 3.45k | arr: MaybeUninit::uninit(), | 213 | 3.45k | } | 214 | 3.45k | } |
<regalloc::sparse_set::SparseSetU<[regalloc::data_structures::RangeId; 4]>>::empty Line | Count | Source | 209 | 18.5k | pub fn empty() -> Self { | 210 | 18.5k | SparseSetU::Small { | 211 | 18.5k | card: 0, | 212 | 18.5k | arr: MaybeUninit::uninit(), | 213 | 18.5k | } | 214 | 18.5k | } |
|
215 | | |
216 | | #[inline(always)] |
217 | 269k | pub fn is_empty(&self) -> bool { |
218 | 269k | match self { |
219 | 268k | SparseSetU::Small { card, .. } => *card == 0, |
220 | 280 | SparseSetU::Large { set } => { |
221 | | // This holds because `maybe_downgrade` will always convert a |
222 | | // zero-sized large variant into a small variant. |
223 | 280 | assert!(set.len() > 0); |
224 | 280 | false |
225 | | } |
226 | | } |
227 | 269k | } <regalloc::sparse_set::SparseSetU<[regalloc::data_structures::VirtualRangeIx; 4]>>::is_empty Line | Count | Source | 217 | 218k | pub fn is_empty(&self) -> bool { | 218 | 218k | match self { | 219 | 218k | SparseSetU::Small { card, .. } => *card == 0, | 220 | 85 | SparseSetU::Large { set } => { | 221 | | // This holds because `maybe_downgrade` will always convert a | 222 | | // zero-sized large variant into a small variant. | 223 | 85 | assert!(set.len() > 0); | 224 | 85 | false | 225 | | } | 226 | | } | 227 | 218k | } |
Unexecuted instantiation: <regalloc::sparse_set::SparseSetU<[regalloc::data_structures::VirtualRangeIx; 4]>>::is_empty <regalloc::sparse_set::SparseSetU<[regalloc::data_structures::BlockIx; 4]>>::is_empty Line | Count | Source | 217 | 50.8k | pub fn is_empty(&self) -> bool { | 218 | 50.8k | match self { | 219 | 50.6k | SparseSetU::Small { card, .. } => *card == 0, | 220 | 195 | SparseSetU::Large { set } => { | 221 | | // This holds because `maybe_downgrade` will always convert a | 222 | | // zero-sized large variant into a small variant. | 223 | 195 | assert!(set.len() > 0); | 224 | 195 | false | 225 | | } | 226 | | } | 227 | 50.8k | } |
|
228 | | |
229 | | #[inline(never)] |
230 | 88.3k | pub fn card(&self) -> usize { |
231 | 88.3k | match self { |
232 | 2.27k | SparseSetU::Large { set } => set.len(), |
233 | 86.0k | SparseSetU::Small { card, .. } => *card, |
234 | | } |
235 | 88.3k | } <regalloc::sparse_set::SparseSetU<[regalloc::data_structures::BlockIx; 4]>>::card Line | Count | Source | 230 | 29.6k | pub fn card(&self) -> usize { | 231 | 29.6k | match self { | 232 | 14 | SparseSetU::Large { set } => set.len(), | 233 | 29.6k | SparseSetU::Small { card, .. } => *card, | 234 | | } | 235 | 29.6k | } |
<regalloc::sparse_set::SparseSetU<[regalloc::data_structures::Reg; 12]>>::card Line | Count | Source | 230 | 58.6k | pub fn card(&self) -> usize { | 231 | 58.6k | match self { | 232 | 2.26k | SparseSetU::Large { set } => set.len(), | 233 | 56.3k | SparseSetU::Small { card, .. } => *card, | 234 | | } | 235 | 58.6k | } |
|
236 | | |
237 | | #[inline(never)] |
238 | 236k | pub fn insert(&mut self, item: A::Item) { |
239 | 236k | match self { |
240 | 20.4k | SparseSetU::Large { set } => { |
241 | 20.4k | set.insert(item); |
242 | 20.4k | } |
243 | 216k | SparseSetU::Small { card, arr } => { |
244 | 216k | assert!(*card <= A::size()); |
245 | | // Do we already have it? |
246 | 216k | if small_contains(*card, arr, item) { |
247 | 47.6k | return; |
248 | 168k | } |
249 | 168k | // No. |
250 | 168k | let arr_p = arr.as_mut_ptr() as *mut A::Item; |
251 | 167k | if *card < A::size() { |
252 | 167k | // Stay small |
253 | 167k | unsafe { |
254 | 167k | write(arr_p.add(*card), item); |
255 | 167k | } |
256 | 167k | *card += 1; |
257 | 1.17k | } else { |
258 | 1.17k | // Transition up |
259 | 1.17k | self.upgrade(); |
260 | 1.17k | self.insert(item); |
261 | 1.17k | } |
262 | | } |
263 | | } |
264 | 236k | } <regalloc::sparse_set::SparseSetU<[regalloc::data_structures::Reg; 12]>>::insert Line | Count | Source | 238 | 105k | pub fn insert(&mut self, item: A::Item) { | 239 | 105k | match self { | 240 | 238 | SparseSetU::Large { set } => { | 241 | 238 | set.insert(item); | 242 | 238 | } | 243 | 104k | SparseSetU::Small { card, arr } => { | 244 | 104k | assert!(*card <= A::size()); | 245 | | // Do we already have it? | 246 | 104k | if small_contains(*card, arr, item) { | 247 | 40.3k | return; | 248 | 64.4k | } | 249 | 64.4k | // No. | 250 | 64.4k | let arr_p = arr.as_mut_ptr() as *mut A::Item; | 251 | 64.3k | if *card < A::size() { | 252 | 64.3k | // Stay small | 253 | 64.3k | unsafe { | 254 | 64.3k | write(arr_p.add(*card), item); | 255 | 64.3k | } | 256 | 64.3k | *card += 1; | 257 | 89 | } else { | 258 | 89 | // Transition up | 259 | 89 | self.upgrade(); | 260 | 89 | self.insert(item); | 261 | 89 | } | 262 | | } | 263 | | } | 264 | 105k | } |
Unexecuted instantiation: <regalloc::sparse_set::SparseSetU<[regalloc::linear_scan::analysis::RangeId; 12]>>::insert <regalloc::sparse_set::SparseSetU<[regalloc::data_structures::BlockIx; 4]>>::insert Line | Count | Source | 238 | 51.7k | pub fn insert(&mut self, item: A::Item) { | 239 | 51.7k | match self { | 240 | 631 | SparseSetU::Large { set } => { | 241 | 631 | set.insert(item); | 242 | 631 | } | 243 | 51.0k | SparseSetU::Small { card, arr } => { | 244 | 51.0k | assert!(*card <= A::size()); | 245 | | // Do we already have it? | 246 | 51.0k | if small_contains(*card, arr, item) { | 247 | 1.66k | return; | 248 | 49.4k | } | 249 | 49.4k | // No. | 250 | 49.4k | let arr_p = arr.as_mut_ptr() as *mut A::Item; | 251 | 49.0k | if *card < A::size() { | 252 | 49.0k | // Stay small | 253 | 49.0k | unsafe { | 254 | 49.0k | write(arr_p.add(*card), item); | 255 | 49.0k | } | 256 | 49.0k | *card += 1; | 257 | 317 | } else { | 258 | 317 | // Transition up | 259 | 317 | self.upgrade(); | 260 | 317 | self.insert(item); | 261 | 317 | } | 262 | | } | 263 | | } | 264 | 51.7k | } |
<regalloc::sparse_set::SparseSetU<[regalloc::data_structures::RangeId; 4]>>::insert Line | Count | Source | 238 | 23.9k | pub fn insert(&mut self, item: A::Item) { | 239 | 23.9k | match self { | 240 | 1.77k | SparseSetU::Large { set } => { | 241 | 1.77k | set.insert(item); | 242 | 1.77k | } | 243 | 22.1k | SparseSetU::Small { card, arr } => { | 244 | 22.1k | assert!(*card <= A::size()); | 245 | | // Do we already have it? | 246 | 22.1k | if small_contains(*card, arr, item) { | 247 | 218 | return; | 248 | 21.9k | } | 249 | 21.9k | // No. | 250 | 21.9k | let arr_p = arr.as_mut_ptr() as *mut A::Item; | 251 | 21.7k | if *card < A::size() { | 252 | 21.7k | // Stay small | 253 | 21.7k | unsafe { | 254 | 21.7k | write(arr_p.add(*card), item); | 255 | 21.7k | } | 256 | 21.7k | *card += 1; | 257 | 221 | } else { | 258 | 221 | // Transition up | 259 | 221 | self.upgrade(); | 260 | 221 | self.insert(item); | 261 | 221 | } | 262 | | } | 263 | | } | 264 | 23.9k | } |
Unexecuted instantiation: <regalloc::sparse_set::SparseSetU<[regalloc::linear_scan::analysis::RangeId; 4]>>::insert <regalloc::sparse_set::SparseSetU<[regalloc::data_structures::VirtualRangeIx; 4]>>::insert Line | Count | Source | 238 | 22.7k | pub fn insert(&mut self, item: A::Item) { | 239 | 22.7k | match self { | 240 | 919 | SparseSetU::Large { set } => { | 241 | 919 | set.insert(item); | 242 | 919 | } | 243 | 21.8k | SparseSetU::Small { card, arr } => { | 244 | 21.8k | assert!(*card <= A::size()); | 245 | | // Do we already have it? | 246 | 21.8k | if small_contains(*card, arr, item) { | 247 | 0 | return; | 248 | 21.8k | } | 249 | 21.8k | // No. | 250 | 21.8k | let arr_p = arr.as_mut_ptr() as *mut A::Item; | 251 | 21.7k | if *card < A::size() { | 252 | 21.7k | // Stay small | 253 | 21.7k | unsafe { | 254 | 21.7k | write(arr_p.add(*card), item); | 255 | 21.7k | } | 256 | 21.7k | *card += 1; | 257 | 103 | } else { | 258 | 103 | // Transition up | 259 | 103 | self.upgrade(); | 260 | 103 | self.insert(item); | 261 | 103 | } | 262 | | } | 263 | | } | 264 | 22.7k | } |
<regalloc::sparse_set::SparseSetU<[regalloc::data_structures::RangeId; 12]>>::insert Line | Count | Source | 238 | 33.3k | pub fn insert(&mut self, item: A::Item) { | 239 | 33.3k | match self { | 240 | 16.8k | SparseSetU::Large { set } => { | 241 | 16.8k | set.insert(item); | 242 | 16.8k | } | 243 | 16.4k | SparseSetU::Small { card, arr } => { | 244 | 16.4k | assert!(*card <= A::size()); | 245 | | // Do we already have it? | 246 | 16.4k | if small_contains(*card, arr, item) { | 247 | 5.38k | return; | 248 | 11.1k | } | 249 | 11.1k | // No. | 250 | 11.1k | let arr_p = arr.as_mut_ptr() as *mut A::Item; | 251 | 10.6k | if *card < A::size() { | 252 | 10.6k | // Stay small | 253 | 10.6k | unsafe { | 254 | 10.6k | write(arr_p.add(*card), item); | 255 | 10.6k | } | 256 | 10.6k | *card += 1; | 257 | 441 | } else { | 258 | 441 | // Transition up | 259 | 441 | self.upgrade(); | 260 | 441 | self.insert(item); | 261 | 441 | } | 262 | | } | 263 | | } | 264 | 33.3k | } |
|
265 | | |
266 | | #[inline(always)] |
267 | 97.9k | pub fn contains(&self, item: A::Item) -> bool { |
268 | 97.9k | match self { |
269 | 11.0k | SparseSetU::Large { set } => set.contains(&item), |
270 | 86.8k | SparseSetU::Small { card, arr } => small_contains(*card, arr, item), |
271 | | } |
272 | 97.9k | } Unexecuted instantiation: <regalloc::sparse_set::SparseSetU<[regalloc::data_structures::Reg; 12]>>::contains <regalloc::sparse_set::SparseSetU<[regalloc::data_structures::VirtualRangeIx; 4]>>::contains Line | Count | Source | 267 | 28.5k | pub fn contains(&self, item: A::Item) -> bool { | 268 | 28.5k | match self { | 269 | 992 | SparseSetU::Large { set } => set.contains(&item), | 270 | 27.6k | SparseSetU::Small { card, arr } => small_contains(*card, arr, item), | 271 | | } | 272 | 28.5k | } |
<regalloc::sparse_set::SparseSetU<[regalloc::data_structures::Reg; 12]>>::contains Line | Count | Source | 267 | 56.3k | pub fn contains(&self, item: A::Item) -> bool { | 268 | 56.3k | match self { | 269 | 0 | SparseSetU::Large { set } => set.contains(&item), | 270 | 56.3k | SparseSetU::Small { card, arr } => small_contains(*card, arr, item), | 271 | | } | 272 | 56.3k | } |
Unexecuted instantiation: <regalloc::sparse_set::SparseSetU<[regalloc::data_structures::VirtualRangeIx; 4]>>::contains Unexecuted instantiation: <regalloc::sparse_set::SparseSetU<[regalloc::data_structures::Reg; 12]>>::contains <regalloc::sparse_set::SparseSetU<[regalloc::data_structures::RangeId; 12]>>::contains Line | Count | Source | 267 | 13.0k | pub fn contains(&self, item: A::Item) -> bool { | 268 | 13.0k | match self { | 269 | 10.0k | SparseSetU::Large { set } => set.contains(&item), | 270 | 2.98k | SparseSetU::Small { card, arr } => small_contains(*card, arr, item), | 271 | | } | 272 | 13.0k | } |
Unexecuted instantiation: <regalloc::sparse_set::SparseSetU<[regalloc::linear_scan::analysis::RangeId; 12]>>::contains |
273 | | |
274 | | #[inline(never)] |
275 | 79.7k | pub fn union(&mut self, other: &Self) { |
276 | 79.7k | match self { |
277 | 2.47k | SparseSetU::Large { set: set1 } => match other { |
278 | 365 | SparseSetU::Large { set: set2 } => { |
279 | 4.76k | for item in set2.iter() { |
280 | 4.76k | set1.insert(*item); |
281 | 4.76k | } |
282 | | } |
283 | | SparseSetU::Small { |
284 | 2.11k | card: card2, |
285 | 2.11k | arr: arr2, |
286 | 2.11k | } => { |
287 | 2.11k | let arr2_p = arr2.as_ptr() as *const A::Item; |
288 | 5.88k | for i in 0..*card2 { |
289 | 5.88k | let item = unsafe { read(arr2_p.add(i)) }; |
290 | 5.88k | set1.insert(item); |
291 | 5.88k | } |
292 | | } |
293 | | }, |
294 | | SparseSetU::Small { |
295 | 77.2k | card: card1, |
296 | 77.2k | arr: arr1, |
297 | 77.2k | } => { |
298 | 77.2k | let arr1_p = arr1.as_mut_ptr() as *mut A::Item; |
299 | 77.2k | match other { |
300 | 1.73k | SparseSetU::Large { set: set2 } => { |
301 | 1.73k | let mut set2c = set2.clone(); |
302 | 1.73k | for i in 0..*card1 { |
303 | 1.27k | let item = unsafe { read(arr1_p.add(i)) }; |
304 | 1.27k | set2c.insert(item); |
305 | 1.27k | } |
306 | 1.73k | *self = SparseSetU::Large { set: set2c }; |
307 | | } |
308 | | SparseSetU::Small { |
309 | 75.5k | card: card2, |
310 | 75.5k | arr: arr2, |
311 | 75.5k | } => { |
312 | 75.5k | let mut extras: MaybeUninit<A> = MaybeUninit::uninit(); |
313 | 75.5k | let mut n_extras = 0; |
314 | 75.5k | let extras_p = extras.as_mut_ptr() as *mut A::Item; |
315 | 75.5k | let arr2_p = arr2.as_ptr() as *const A::Item; |
316 | | // Iterate through the second set. Add every item not in the |
317 | | // first set to `extras`. |
318 | 134k | for i in 0..*card2 { |
319 | 134k | let item2 = unsafe { read(arr2_p.add(i)) }; |
320 | 134k | let mut in1 = false; |
321 | 180k | for j in 0..*card1 { |
322 | 180k | let item1 = unsafe { read(arr1_p.add(j)) }; |
323 | 180k | if item1 == item2 { |
324 | 28.6k | in1 = true; |
325 | 28.6k | break; |
326 | 152k | } |
327 | | } |
328 | 134k | if !in1 { |
329 | | debug_assert!(n_extras < A::size()); |
330 | 106k | unsafe { |
331 | 106k | write(extras_p.add(n_extras), item2); |
332 | 106k | } |
333 | 106k | n_extras += 1; |
334 | 28.6k | } |
335 | | } |
336 | | // The result is the concatenation of arr1 and extras. |
337 | 106k | for i in 0..n_extras { |
338 | 106k | let item = unsafe { read(extras_p.add(i)) }; |
339 | 106k | self.insert_no_dup_check(item); |
340 | 106k | } |
341 | | } |
342 | | } |
343 | | } |
344 | | } |
345 | 79.7k | } |
346 | | |
347 | | #[inline(never)] |
348 | 48.6k | pub fn remove(&mut self, other: &Self) { |
349 | 48.6k | match self { |
350 | 2.60k | SparseSetU::Large { set: set1 } => { |
351 | 2.60k | match other { |
352 | 0 | SparseSetU::Large { set: set2 } => { |
353 | 0 | for item in set2.iter() { |
354 | 0 | set1.remove(item); |
355 | 0 | } |
356 | | } |
357 | | SparseSetU::Small { |
358 | 2.60k | card: card2, |
359 | 2.60k | arr: arr2, |
360 | 2.60k | } => { |
361 | 2.60k | let arr2_p = arr2.as_ptr() as *const A::Item; |
362 | 7.50k | for i in 0..*card2 { |
363 | 7.50k | let item = unsafe { read(arr2_p.add(i)) }; |
364 | 7.50k | set1.remove(&item); |
365 | 7.50k | } |
366 | | } |
367 | | } |
368 | 2.60k | self.maybe_downgrade(); |
369 | | } |
370 | | SparseSetU::Small { |
371 | 46.0k | card: card1, |
372 | 46.0k | arr: arr1, |
373 | 46.0k | } => { |
374 | 46.0k | let arr1_p = arr1.as_mut_ptr() as *mut A::Item; |
375 | 46.0k | match other { |
376 | 0 | SparseSetU::Large { set: set2 } => { |
377 | 0 | let mut w = 0; |
378 | 0 | for r in 0..*card1 { |
379 | 0 | let item = unsafe { read(arr1_p.add(r)) }; |
380 | 0 | let is_in2 = set2.contains(&item); |
381 | 0 | if !is_in2 { |
382 | | // Keep it. |
383 | 0 | if r != w { |
384 | 0 | unsafe { |
385 | 0 | write(arr1_p.add(w), item); |
386 | 0 | } |
387 | 0 | } |
388 | 0 | w += 1; |
389 | 0 | } |
390 | | } |
391 | 0 | *card1 = w; |
392 | | } |
393 | | SparseSetU::Small { |
394 | 46.0k | card: card2, |
395 | 46.0k | arr: arr2, |
396 | | } => { |
397 | 46.0k | let arr2_p = arr2.as_ptr() as *const A::Item; |
398 | 46.0k | let mut w = 0; |
399 | 109k | for r in 0..*card1 { |
400 | 109k | let item = unsafe { read(arr1_p.add(r)) }; |
401 | 109k | let mut is_in2 = false; |
402 | 239k | for i in 0..*card2 { |
403 | 239k | if unsafe { read(arr2_p.add(i)) } == item { |
404 | 39.4k | is_in2 = true; |
405 | 39.4k | break; |
406 | 200k | } |
407 | | } |
408 | 109k | if !is_in2 { |
409 | | // Keep it. |
410 | 69.6k | if r != w { |
411 | 21.9k | unsafe { |
412 | 21.9k | write(arr1_p.add(w), item); |
413 | 21.9k | } |
414 | 47.7k | } |
415 | 69.6k | w += 1; |
416 | 39.4k | } |
417 | | } |
418 | 46.0k | *card1 = w; |
419 | | } |
420 | | } |
421 | | } |
422 | | } |
423 | 48.6k | } |
424 | | |
425 | | // return true if `self` is a subset of `other` |
426 | | #[inline(never)] |
427 | 3.64k | pub fn is_subset_of(&self, other: &Self) -> bool { |
428 | 3.64k | if self.card() > other.card() { |
429 | 183 | return false; |
430 | 3.45k | } |
431 | 3.45k | // Visit all items in `self`, and see if they are in `other`. If so |
432 | 3.45k | // return true. |
433 | 3.45k | match self { |
434 | 0 | SparseSetU::Large { set: set1 } => match other { |
435 | 0 | SparseSetU::Large { set: set2 } => set1.is_subset(set2), |
436 | | SparseSetU::Small { |
437 | 0 | card: card2, |
438 | 0 | arr: arr2, |
439 | | } => { |
440 | 0 | for item in set1.iter() { |
441 | 0 | if !small_contains(*card2, arr2, *item) { |
442 | 0 | return false; |
443 | 0 | } |
444 | | } |
445 | 0 | true |
446 | | } |
447 | | }, |
448 | | SparseSetU::Small { |
449 | 3.45k | card: card1, |
450 | 3.45k | arr: arr1, |
451 | 3.45k | } => { |
452 | 3.45k | let arr1_p = arr1.as_ptr() as *const A::Item; |
453 | 3.45k | match other { |
454 | 0 | SparseSetU::Large { set: set2 } => { |
455 | 0 | for i in 0..*card1 { |
456 | 0 | let item = unsafe { read(arr1_p.add(i)) }; |
457 | 0 | if !set2.contains(&item) { |
458 | 0 | return false; |
459 | 0 | } |
460 | | } |
461 | 0 | true |
462 | | } |
463 | | SparseSetU::Small { |
464 | 3.45k | card: card2, |
465 | 3.45k | arr: arr2, |
466 | | } => { |
467 | 3.45k | for i in 0..*card1 { |
468 | 0 | let item = unsafe { read(arr1_p.add(i)) }; |
469 | 0 | if !small_contains(*card2, arr2, item) { |
470 | 0 | return false; |
471 | 0 | } |
472 | | } |
473 | 3.45k | true |
474 | | } |
475 | | } |
476 | | } |
477 | | } |
478 | 3.64k | } |
479 | | |
480 | | #[inline(never)] |
481 | 7.10k | pub fn from_vec(vec: Vec<A::Item>) -> Self { |
482 | 7.10k | let vec_len = vec.len(); |
483 | 7.10k | if vec_len <= A::size() { |
484 | 7.10k | let mut card = 0; |
485 | 7.10k | let mut arr: MaybeUninit<A> = MaybeUninit::uninit(); |
486 | 7.10k | for i in 0..vec_len { |
487 | 0 | let item = vec[i]; |
488 | 0 | if small_contains(card, &arr, item) { |
489 | | continue; |
490 | 0 | } |
491 | 0 | let arr_p = arr.as_mut_ptr() as *mut A::Item; |
492 | 0 | unsafe { write(arr_p.add(card), item) } |
493 | 0 | card += 1; |
494 | | } |
495 | 7.10k | SparseSetU::Small { card, arr } |
496 | | } else { |
497 | 0 | let mut set = FxHashSet::<A::Item>::default(); |
498 | 0 | for i in 0..vec_len { |
499 | 0 | set.insert(vec[i]); |
500 | 0 | } |
501 | 0 | SparseSetU::Large { set } |
502 | | } |
503 | 7.10k | } |
504 | | |
505 | | #[inline(never)] |
506 | 25.6k | pub fn equals(&self, other: &Self) -> bool { |
507 | 25.6k | if self.card() != other.card() { |
508 | 14.4k | return false; |
509 | 11.2k | } |
510 | 11.2k | match (self, other) { |
511 | 439 | (SparseSetU::Large { set: set1 }, SparseSetU::Large { set: set2 }) => set1 == set2, |
512 | | ( |
513 | | SparseSetU::Small { |
514 | 10.7k | card: card1, |
515 | 10.7k | arr: arr1, |
516 | | }, |
517 | | SparseSetU::Small { |
518 | 10.7k | card: card2, |
519 | 10.7k | arr: arr2, |
520 | | }, |
521 | | ) => { |
522 | 10.7k | assert!(*card1 == *card2); |
523 | | // Check to see that all items in arr1 are present in arr2. Since the |
524 | | // arrays have the same length and are duplicate free, although |
525 | | // unordered, this is a sufficient equality test. |
526 | 10.7k | let arr1_p = arr1.as_ptr() as *const A::Item; |
527 | 10.7k | let arr2_p = arr2.as_ptr() as *const A::Item; |
528 | 10.7k | for i1 in 0..*card1 { |
529 | 8.91k | let item1 = unsafe { read(arr1_p.add(i1)) }; |
530 | 8.91k | let mut found1 = false; |
531 | 34.5k | for i2 in 0..*card2 { |
532 | 34.5k | let item2 = unsafe { read(arr2_p.add(i2)) }; |
533 | 34.5k | if item1 == item2 { |
534 | 8.91k | found1 = true; |
535 | 8.91k | break; |
536 | 25.6k | } |
537 | | } |
538 | 8.91k | if !found1 { |
539 | 0 | return false; |
540 | 8.91k | } |
541 | | } |
542 | 10.7k | true |
543 | | } |
544 | 0 | (SparseSetU::Small { card, arr }, SparseSetU::Large { set }) |
545 | 32 | | (SparseSetU::Large { set }, SparseSetU::Small { card, arr }) => { |
546 | | // Same rationale as above as to why this is a sufficient test. |
547 | 32 | let arr_p = arr.as_ptr() as *const A::Item; |
548 | 367 | for i in 0..*card { |
549 | 367 | let item = unsafe { read(arr_p.add(i)) }; |
550 | 367 | if !set.contains(&item) { |
551 | 0 | return false; |
552 | 367 | } |
553 | | } |
554 | 32 | true |
555 | | } |
556 | | } |
557 | 25.6k | } |
558 | | } |
559 | | |
560 | | impl<A> SparseSetU<A> |
561 | | where |
562 | | A: Array, |
563 | | A::Item: Eq + Ord + Hash + Copy + fmt::Debug, |
564 | | { |
565 | | #[inline(never)] |
566 | 183 | pub fn to_vec(&self) -> Vec<A::Item> { |
567 | 183 | let mut res = Vec::<A::Item>::new(); |
568 | 183 | match self { |
569 | 71 | SparseSetU::Large { set } => { |
570 | 784 | for item in set.iter() { |
571 | 784 | res.push(*item); |
572 | 784 | } |
573 | | } |
574 | 112 | SparseSetU::Small { card, arr } => { |
575 | 112 | let arr_p = arr.as_ptr() as *const A::Item; |
576 | 469 | for i in 0..*card { |
577 | 469 | res.push(unsafe { read(arr_p.add(i)) }); |
578 | 469 | } |
579 | | } |
580 | | } |
581 | | // Don't delete this. It is important. |
582 | 183 | res.sort_unstable(); |
583 | 183 | res |
584 | 183 | } <regalloc::sparse_set::SparseSetU<[regalloc::data_structures::Reg; 12]>>::to_vec Line | Count | Source | 566 | 183 | pub fn to_vec(&self) -> Vec<A::Item> { | 567 | 183 | let mut res = Vec::<A::Item>::new(); | 568 | 183 | match self { | 569 | 71 | SparseSetU::Large { set } => { | 570 | 784 | for item in set.iter() { | 571 | 784 | res.push(*item); | 572 | 784 | } | 573 | | } | 574 | 112 | SparseSetU::Small { card, arr } => { | 575 | 112 | let arr_p = arr.as_ptr() as *const A::Item; | 576 | 469 | for i in 0..*card { | 577 | 469 | res.push(unsafe { read(arr_p.add(i)) }); | 578 | 469 | } | 579 | | } | 580 | | } | 581 | | // Don't delete this. It is important. | 582 | 183 | res.sort_unstable(); | 583 | 183 | res | 584 | 183 | } |
Unexecuted instantiation: <regalloc::sparse_set::SparseSetU<[regalloc::data_structures::BlockIx; 4]>>::to_vec |
585 | | } |
586 | | |
587 | | impl<A> fmt::Debug for SparseSetU<A> |
588 | | where |
589 | | A: Array + Eq + Ord + Hash + Copy + fmt::Debug, |
590 | | A::Item: Eq + Ord + Hash + Copy + fmt::Debug, |
591 | | { |
592 | | #[inline(never)] |
593 | 0 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |
594 | 0 | // Print the elements in some way which depends only on what is |
595 | 0 | // present in the set, and not on any other factor. In particular, |
596 | 0 | // <Debug for FxHashSet> has been observed to to print the elements |
597 | 0 | // of a two element set in both orders on different occasions. |
598 | 0 | let sorted_vec = self.to_vec(); |
599 | 0 | let mut s = "{".to_string(); |
600 | 0 | for i in 0..sorted_vec.len() { |
601 | 0 | if i > 0 { |
602 | 0 | s = s + &", ".to_string(); |
603 | 0 | } |
604 | 0 | s = s + &format!("{:?}", &sorted_vec[i]); |
605 | | } |
606 | 0 | s = s + &"}".to_string(); |
607 | 0 | write!(fmt, "{}", s) |
608 | 0 | } |
609 | | } |
610 | | |
611 | | impl<A> Clone for SparseSetU<A> |
612 | | where |
613 | | A: Array + Eq + Hash + Copy + Clone, |
614 | | A::Item: Eq + Hash + Copy + Clone, |
615 | | { |
616 | | #[inline(never)] |
617 | 105k | fn clone(&self) -> Self { |
618 | 105k | match self { |
619 | 3.04k | SparseSetU::Large { set } => SparseSetU::Large { set: set.clone() }, |
620 | 102k | SparseSetU::Small { card, arr } => { |
621 | 102k | let arr2 = arr.clone(); |
622 | 102k | SparseSetU::Small { |
623 | 102k | card: *card, |
624 | 102k | arr: arr2, |
625 | 102k | } |
626 | | } |
627 | | } |
628 | 105k | } <regalloc::sparse_set::SparseSetU<[regalloc::data_structures::Reg; 12]> as core::clone::Clone>::clone Line | Count | Source | 617 | 84.6k | fn clone(&self) -> Self { | 618 | 84.6k | match self { | 619 | 2.60k | SparseSetU::Large { set } => SparseSetU::Large { set: set.clone() }, | 620 | 82.0k | SparseSetU::Small { card, arr } => { | 621 | 82.0k | let arr2 = arr.clone(); | 622 | 82.0k | SparseSetU::Small { | 623 | 82.0k | card: *card, | 624 | 82.0k | arr: arr2, | 625 | 82.0k | } | 626 | | } | 627 | | } | 628 | 84.6k | } |
Unexecuted instantiation: <regalloc::sparse_set::SparseSetU<[regalloc::linear_scan::analysis::RangeId; 12]> as core::clone::Clone>::clone <regalloc::sparse_set::SparseSetU<[regalloc::data_structures::RangeId; 12]> as core::clone::Clone>::clone Line | Count | Source | 617 | 3.45k | fn clone(&self) -> Self { | 618 | 3.45k | match self { | 619 | 441 | SparseSetU::Large { set } => SparseSetU::Large { set: set.clone() }, | 620 | 3.01k | SparseSetU::Small { card, arr } => { | 621 | 3.01k | let arr2 = arr.clone(); | 622 | 3.01k | SparseSetU::Small { | 623 | 3.01k | card: *card, | 624 | 3.01k | arr: arr2, | 625 | 3.01k | } | 626 | | } | 627 | | } | 628 | 3.45k | } |
<regalloc::sparse_set::SparseSetU<[regalloc::data_structures::BlockIx; 4]> as core::clone::Clone>::clone Line | Count | Source | 617 | 17.6k | fn clone(&self) -> Self { | 618 | 17.6k | match self { | 619 | 0 | SparseSetU::Large { set } => SparseSetU::Large { set: set.clone() }, | 620 | 17.6k | SparseSetU::Small { card, arr } => { | 621 | 17.6k | let arr2 = arr.clone(); | 622 | 17.6k | SparseSetU::Small { | 623 | 17.6k | card: *card, | 624 | 17.6k | arr: arr2, | 625 | 17.6k | } | 626 | | } | 627 | | } | 628 | 17.6k | } |
|
629 | | } |
630 | | |
631 | | pub enum SparseSetUIter<'a, A: Array> { |
632 | | Large { |
633 | | set_iter: std::collections::hash_set::Iter<'a, A::Item>, |
634 | | }, |
635 | | Small { |
636 | | card: usize, |
637 | | arr: &'a MaybeUninit<A>, |
638 | | next: usize, |
639 | | }, |
640 | | } |
641 | | impl<A: Array> SparseSetU<A> { |
642 | 344k | pub fn iter(&self) -> SparseSetUIter<A> { |
643 | 344k | match self { |
644 | 1.96k | SparseSetU::Large { set } => SparseSetUIter::Large { |
645 | 1.96k | set_iter: set.iter(), |
646 | 1.96k | }, |
647 | 342k | SparseSetU::Small { card, arr } => SparseSetUIter::Small { |
648 | 342k | card: *card, |
649 | 342k | arr, |
650 | 342k | next: 0, |
651 | 342k | }, |
652 | | } |
653 | 344k | } <regalloc::sparse_set::SparseSetU<[regalloc::data_structures::BlockIx; 4]>>::iter Line | Count | Source | 642 | 225k | pub fn iter(&self) -> SparseSetUIter<A> { | 643 | 225k | match self { | 644 | 321 | SparseSetU::Large { set } => SparseSetUIter::Large { | 645 | 321 | set_iter: set.iter(), | 646 | 321 | }, | 647 | 224k | SparseSetU::Small { card, arr } => SparseSetUIter::Small { | 648 | 224k | card: *card, | 649 | 224k | arr, | 650 | 224k | next: 0, | 651 | 224k | }, | 652 | | } | 653 | 225k | } |
<regalloc::sparse_set::SparseSetU<[regalloc::data_structures::RangeId; 4]>>::iter Line | Count | Source | 642 | 12.0k | pub fn iter(&self) -> SparseSetUIter<A> { | 643 | 12.0k | match self { | 644 | 6 | SparseSetU::Large { set } => SparseSetUIter::Large { | 645 | 6 | set_iter: set.iter(), | 646 | 6 | }, | 647 | 12.0k | SparseSetU::Small { card, arr } => SparseSetUIter::Small { | 648 | 12.0k | card: *card, | 649 | 12.0k | arr, | 650 | 12.0k | next: 0, | 651 | 12.0k | }, | 652 | | } | 653 | 12.0k | } |
Unexecuted instantiation: <regalloc::sparse_set::SparseSetU<[regalloc::linear_scan::analysis::RangeId; 4]>>::iter <regalloc::sparse_set::SparseSetU<[regalloc::data_structures::Reg; 12]>>::iter Line | Count | Source | 642 | 33.4k | pub fn iter(&self) -> SparseSetUIter<A> { | 643 | 33.4k | match self { | 644 | 723 | SparseSetU::Large { set } => SparseSetUIter::Large { | 645 | 723 | set_iter: set.iter(), | 646 | 723 | }, | 647 | 32.7k | SparseSetU::Small { card, arr } => SparseSetUIter::Small { | 648 | 32.7k | card: *card, | 649 | 32.7k | arr, | 650 | 32.7k | next: 0, | 651 | 32.7k | }, | 652 | | } | 653 | 33.4k | } |
Unexecuted instantiation: <regalloc::sparse_set::SparseSetU<[regalloc::linear_scan::analysis::RangeId; 12]>>::iter <regalloc::sparse_set::SparseSetU<[regalloc::data_structures::VirtualRangeIx; 4]>>::iter Line | Count | Source | 642 | 67.0k | pub fn iter(&self) -> SparseSetUIter<A> { | 643 | 67.0k | match self { | 644 | 28 | SparseSetU::Large { set } => SparseSetUIter::Large { | 645 | 28 | set_iter: set.iter(), | 646 | 28 | }, | 647 | 67.0k | SparseSetU::Small { card, arr } => SparseSetUIter::Small { | 648 | 67.0k | card: *card, | 649 | 67.0k | arr, | 650 | 67.0k | next: 0, | 651 | 67.0k | }, | 652 | | } | 653 | 67.0k | } |
<regalloc::sparse_set::SparseSetU<[regalloc::data_structures::RangeId; 12]>>::iter Line | Count | Source | 642 | 6.91k | pub fn iter(&self) -> SparseSetUIter<A> { | 643 | 6.91k | match self { | 644 | 882 | SparseSetU::Large { set } => SparseSetUIter::Large { | 645 | 882 | set_iter: set.iter(), | 646 | 882 | }, | 647 | 6.03k | SparseSetU::Small { card, arr } => SparseSetUIter::Small { | 648 | 6.03k | card: *card, | 649 | 6.03k | arr, | 650 | 6.03k | next: 0, | 651 | 6.03k | }, | 652 | | } | 653 | 6.91k | } |
|
654 | | } |
655 | | impl<'a, A: Array> Iterator for SparseSetUIter<'a, A> { |
656 | | type Item = &'a A::Item; |
657 | 719k | fn next(&mut self) -> Option<Self::Item> { |
658 | 719k | match self { |
659 | 35.2k | SparseSetUIter::Large { set_iter } => set_iter.next(), |
660 | 684k | SparseSetUIter::Small { card, arr, next } => { |
661 | 684k | if next < card { |
662 | 371k | let arr_p = arr.as_ptr() as *const A::Item; |
663 | 371k | let item_p = unsafe { arr_p.add(*next) }; |
664 | 371k | *next += 1; |
665 | 371k | Some(unsafe { &*item_p }) |
666 | | } else { |
667 | 313k | None |
668 | | } |
669 | | } |
670 | | } |
671 | 719k | } <regalloc::sparse_set::SparseSetUIter<[regalloc::data_structures::RangeId; 12]> as core::iter::traits::iterator::Iterator>::next Line | Count | Source | 657 | 39.8k | fn next(&mut self) -> Option<Self::Item> { | 658 | 39.8k | match self { | 659 | 23.0k | SparseSetUIter::Large { set_iter } => set_iter.next(), | 660 | 16.8k | SparseSetUIter::Small { card, arr, next } => { | 661 | 16.8k | if next < card { | 662 | 10.7k | let arr_p = arr.as_ptr() as *const A::Item; | 663 | 10.7k | let item_p = unsafe { arr_p.add(*next) }; | 664 | 10.7k | *next += 1; | 665 | 10.7k | Some(unsafe { &*item_p }) | 666 | | } else { | 667 | 6.03k | None | 668 | | } | 669 | | } | 670 | | } | 671 | 39.8k | } |
Unexecuted instantiation: <regalloc::sparse_set::SparseSetUIter<[regalloc::linear_scan::analysis::RangeId; 4]> as core::iter::traits::iterator::Iterator>::next <regalloc::sparse_set::SparseSetUIter<[regalloc::data_structures::Reg; 12]> as core::iter::traits::iterator::Iterator>::next Line | Count | Source | 657 | 119k | fn next(&mut self) -> Option<Self::Item> { | 658 | 119k | match self { | 659 | 10.3k | SparseSetUIter::Large { set_iter } => set_iter.next(), | 660 | 108k | SparseSetUIter::Small { card, arr, next } => { | 661 | 108k | if next < card { | 662 | 76.0k | let arr_p = arr.as_ptr() as *const A::Item; | 663 | 76.0k | let item_p = unsafe { arr_p.add(*next) }; | 664 | 76.0k | *next += 1; | 665 | 76.0k | Some(unsafe { &*item_p }) | 666 | | } else { | 667 | 32.7k | None | 668 | | } | 669 | | } | 670 | | } | 671 | 119k | } |
<regalloc::sparse_set::SparseSetUIter<[regalloc::data_structures::RangeId; 4]> as core::iter::traits::iterator::Iterator>::next Line | Count | Source | 657 | 25.1k | fn next(&mut self) -> Option<Self::Item> { | 658 | 25.1k | match self { | 659 | 46 | SparseSetUIter::Large { set_iter } => set_iter.next(), | 660 | 25.0k | SparseSetUIter::Small { card, arr, next } => { | 661 | 25.0k | if next < card { | 662 | 12.9k | let arr_p = arr.as_ptr() as *const A::Item; | 663 | 12.9k | let item_p = unsafe { arr_p.add(*next) }; | 664 | 12.9k | *next += 1; | 665 | 12.9k | Some(unsafe { &*item_p }) | 666 | | } else { | 667 | 12.0k | None | 668 | | } | 669 | | } | 670 | | } | 671 | 25.1k | } |
<regalloc::sparse_set::SparseSetUIter<[regalloc::data_structures::VirtualRangeIx; 4]> as core::iter::traits::iterator::Iterator>::next Line | Count | Source | 657 | 71.6k | fn next(&mut self) -> Option<Self::Item> { | 658 | 71.6k | match self { | 659 | 462 | SparseSetUIter::Large { set_iter } => set_iter.next(), | 660 | 71.2k | SparseSetUIter::Small { card, arr, next } => { | 661 | 71.2k | if next < card { | 662 | 4.20k | let arr_p = arr.as_ptr() as *const A::Item; | 663 | 4.20k | let item_p = unsafe { arr_p.add(*next) }; | 664 | 4.20k | *next += 1; | 665 | 4.20k | Some(unsafe { &*item_p }) | 666 | | } else { | 667 | 67.0k | None | 668 | | } | 669 | | } | 670 | | } | 671 | 71.6k | } |
<regalloc::sparse_set::SparseSetUIter<[regalloc::data_structures::BlockIx; 4]> as core::iter::traits::iterator::Iterator>::next Line | Count | Source | 657 | 463k | fn next(&mut self) -> Option<Self::Item> { | 658 | 463k | match self { | 659 | 1.33k | SparseSetUIter::Large { set_iter } => set_iter.next(), | 660 | 462k | SparseSetUIter::Small { card, arr, next } => { | 661 | 462k | if next < card { | 662 | 267k | let arr_p = arr.as_ptr() as *const A::Item; | 663 | 267k | let item_p = unsafe { arr_p.add(*next) }; | 664 | 267k | *next += 1; | 665 | 267k | Some(unsafe { &*item_p }) | 666 | | } else { | 667 | 195k | None | 668 | | } | 669 | | } | 670 | | } | 671 | 463k | } |
Unexecuted instantiation: <regalloc::sparse_set::SparseSetUIter<[regalloc::linear_scan::analysis::RangeId; 12]> as core::iter::traits::iterator::Iterator>::next |
672 | | } |
673 | | |
674 | | // ================ Testing machinery for SparseSetU ================ |
675 | | |
676 | | #[cfg(test)] |
677 | | mod sparse_set_test_utils { |
678 | | // As currently set up, each number (from rand, not rand_base) has a 1-in-4 |
679 | | // chance of being a dup of the last 8 numbers produced. |
680 | | pub struct RNGwithDups { |
681 | | seed: u32, |
682 | | circ: [u32; 8], |
683 | | circC: usize, // the cursor for `circ` |
684 | | } |
685 | | impl RNGwithDups { |
686 | | pub fn new() -> Self { |
687 | | Self { |
688 | | seed: 0, |
689 | | circ: [0; 8], |
690 | | circC: 0, |
691 | | } |
692 | | } |
693 | | fn rand_base(&mut self) -> u32 { |
694 | | self.seed = self.seed.wrapping_mul(1103515245).wrapping_add(12345); |
695 | | self.seed |
696 | | } |
697 | | pub fn rand(&mut self) -> u32 { |
698 | | let r = self.rand_base(); |
699 | | let rlo = r & 0xFFFF; |
700 | | let rhi = (r >> 16) & 0xFF; |
701 | | if rhi < 64 { |
702 | | self.circ[(rhi % 8) as usize] |
703 | | } else { |
704 | | self.circ[self.circC as usize] = rlo; |
705 | | self.circC += 1; |
706 | | if self.circC == 8 { |
707 | | self.circC = 0 |
708 | | }; |
709 | | rlo |
710 | | } |
711 | | } |
712 | | pub fn rand_vec(&mut self, len: usize) -> Vec<u32> { |
713 | | let mut res = vec![]; |
714 | | for _ in 0..len { |
715 | | res.push(self.rand()); |
716 | | } |
717 | | res |
718 | | } |
719 | | } |
720 | | } |
721 | | |
722 | | #[test] |
723 | | fn test_sparse_set() { |
724 | | use crate::data_structures::Set; |
725 | | let mut set = SparseSetU::<[u32; 3]>::empty(); |
726 | | assert!(set.is_small()); |
727 | | set.insert(3); |
728 | | assert!(set.is_small()); |
729 | | set.insert(1); |
730 | | assert!(set.is_small()); |
731 | | set.insert(4); |
732 | | assert!(set.is_small()); |
733 | | set.insert(7); |
734 | | assert!(set.is_large()); |
735 | | |
736 | | let iters = 20; |
737 | | let mut rng = sparse_set_test_utils::RNGwithDups::new(); |
738 | | |
739 | | // empty |
740 | | { |
741 | | let spa = SparseSetU::<[u32; 10]>::empty(); |
742 | | assert!(spa.card() == 0); |
743 | | } |
744 | | |
745 | | // card, is_empty |
746 | | for _ in 0..iters * 3 { |
747 | | for n1 in 0..100 { |
748 | | let size1 = n1 % 25; |
749 | | let vec1a = rng.rand_vec(size1); |
750 | | let vec1b = vec1a.clone(); // This is very stupid. |
751 | | let spa1 = SparseSetU::<[u32; 10]>::from_vec(vec1a); |
752 | | let std1 = Set::<u32>::from_vec(vec1b); |
753 | | assert!(spa1.card() == std1.card()); |
754 | | assert!(spa1.is_empty() == (size1 == 0)); |
755 | | } |
756 | | } |
757 | | |
758 | | // insert |
759 | | for _ in 0..iters * 3 { |
760 | | for n1 in 0..100 { |
761 | | let size1 = n1 % 25; |
762 | | let vec1a = rng.rand_vec(size1); |
763 | | let vec1b = vec1a.clone(); |
764 | | let tmp = if size1 == 0 { 0 } else { vec1a[0] }; |
765 | | let mut spa1 = SparseSetU::<[u32; 10]>::from_vec(vec1a); |
766 | | let mut std1 = Set::<u32>::from_vec(vec1b); |
767 | | // Insert an item which is almost certainly not in the set. |
768 | | let n = rng.rand(); |
769 | | spa1.insert(n); |
770 | | std1.insert(n); |
771 | | assert!(spa1.card() == std1.card()); |
772 | | assert!(spa1.to_vec() == std1.to_vec()); |
773 | | // Insert an item which is already in the set. |
774 | | if n1 > 0 { |
775 | | spa1.insert(tmp); |
776 | | std1.insert(tmp); |
777 | | assert!(spa1.card() == std1.card()); |
778 | | assert!(spa1.to_vec() == std1.to_vec()); |
779 | | } |
780 | | } |
781 | | } |
782 | | |
783 | | // contains |
784 | | for _ in 0..iters * 2 { |
785 | | for n1 in 0..100 { |
786 | | let size1 = n1 % 25; |
787 | | let vec1a = rng.rand_vec(size1); |
788 | | let vec1b = vec1a.clone(); |
789 | | let tmp = if size1 == 0 { 0 } else { vec1a[0] }; |
790 | | let spa1 = SparseSetU::<[u32; 10]>::from_vec(vec1a); |
791 | | let std1 = Set::<u32>::from_vec(vec1b); |
792 | | // Check for an item which is almost certainly not in the set. |
793 | | let n = rng.rand(); |
794 | | assert!(spa1.contains(n) == std1.contains(n)); |
795 | | // Check for an item which is already in the set. |
796 | | if n1 > 0 { |
797 | | assert!(spa1.contains(tmp) == std1.contains(tmp)); |
798 | | } |
799 | | } |
800 | | } |
801 | | |
802 | | // union |
803 | | for _ in 0..iters * 2 { |
804 | | for size1 in 0..25 { |
805 | | for size2 in 0..25 { |
806 | | let vec1a = rng.rand_vec(size1); |
807 | | let vec2a = rng.rand_vec(size2); |
808 | | let vec1b = vec1a.clone(); |
809 | | let vec2b = vec2a.clone(); |
810 | | let mut spa1 = SparseSetU::<[u32; 10]>::from_vec(vec1a); |
811 | | let spa2 = SparseSetU::<[u32; 10]>::from_vec(vec2a); |
812 | | let mut std1 = Set::<u32>::from_vec(vec1b); |
813 | | let std2 = Set::<u32>::from_vec(vec2b); |
814 | | spa1.union(&spa2); |
815 | | std1.union(&std2); |
816 | | assert!(spa1.to_vec() == std1.to_vec()); |
817 | | } |
818 | | } |
819 | | } |
820 | | |
821 | | // remove |
822 | | for _ in 0..iters * 2 { |
823 | | for size1 in 0..25 { |
824 | | for size2 in 0..25 { |
825 | | let vec1a = rng.rand_vec(size1); |
826 | | let vec2a = rng.rand_vec(size2); |
827 | | let vec1b = vec1a.clone(); |
828 | | let vec2b = vec2a.clone(); |
829 | | let mut spa1 = SparseSetU::<[u32; 10]>::from_vec(vec1a); |
830 | | let spa2 = SparseSetU::<[u32; 10]>::from_vec(vec2a); |
831 | | let mut std1 = Set::<u32>::from_vec(vec1b); |
832 | | let std2 = Set::<u32>::from_vec(vec2b); |
833 | | spa1.remove(&spa2); |
834 | | std1.remove(&std2); |
835 | | assert!(spa1.to_vec() == std1.to_vec()); |
836 | | } |
837 | | } |
838 | | } |
839 | | |
840 | | // is_subset_of |
841 | | for _ in 0..iters * 2 { |
842 | | for size1 in 0..25 { |
843 | | for size2 in 0..25 { |
844 | | let vec1a = rng.rand_vec(size1); |
845 | | let vec2a = rng.rand_vec(size2); |
846 | | let vec1b = vec1a.clone(); |
847 | | let vec2b = vec2a.clone(); |
848 | | let spa1 = SparseSetU::<[u32; 10]>::from_vec(vec1a); |
849 | | let spa2 = SparseSetU::<[u32; 10]>::from_vec(vec2a); |
850 | | let std1 = Set::<u32>::from_vec(vec1b); |
851 | | let std2 = Set::<u32>::from_vec(vec2b); |
852 | | assert!(spa1.is_subset_of(&spa2) == std1.is_subset_of(&std2)); |
853 | | } |
854 | | } |
855 | | } |
856 | | |
857 | | // to_vec and from_vec are implicitly tested by the above; there's no way |
858 | | // they could be wrong and still have the above tests succeed. |
859 | | // (Famous last words!) |
860 | | |
861 | | // equals |
862 | | for _ in 0..iters * 2 { |
863 | | for size1 in 0..25 { |
864 | | for size2 in 0..25 { |
865 | | let vec1a = rng.rand_vec(size1); |
866 | | let vec2a = rng.rand_vec(size2); |
867 | | let vec1b = vec1a.clone(); |
868 | | let vec2b = vec2a.clone(); |
869 | | let spa1 = SparseSetU::<[u32; 10]>::from_vec(vec1a); |
870 | | let spa2 = SparseSetU::<[u32; 10]>::from_vec(vec2a); |
871 | | let std1 = Set::<u32>::from_vec(vec1b); |
872 | | let std2 = Set::<u32>::from_vec(vec2b); |
873 | | assert!(std1.equals(&std1)); // obviously |
874 | | assert!(std2.equals(&std2)); // obviously |
875 | | assert!(spa1.equals(&spa1)); // obviously |
876 | | assert!(spa2.equals(&spa2)); // obviously |
877 | | // More seriously |
878 | | assert!(spa1.equals(&spa2) == std1.equals(&std2)); |
879 | | } |
880 | | } |
881 | | } |
882 | | |
883 | | // clone |
884 | | for _ in 0..iters * 3 { |
885 | | for n1 in 0..100 { |
886 | | let size1 = n1 % 25; |
887 | | let vec1a = rng.rand_vec(size1); |
888 | | let spa1 = SparseSetU::<[u32; 10]>::from_vec(vec1a); |
889 | | let spa2 = spa1.clone(); |
890 | | assert!(spa1.equals(&spa2)); |
891 | | } |
892 | | } |
893 | | } |