Skip to content

Commit 7eeee70

Browse files
mpizenbergEh2406
authored andcommitted
perf: use smallvec for unit propagation buffer (#90)
1 parent 3f2c1b9 commit 7eeee70

File tree

2 files changed

+57
-2
lines changed

2 files changed

+57
-2
lines changed

src/internal/core.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use crate::internal::assignment::Assignment::{Decision, Derivation};
1111
use crate::internal::incompatibility::IncompId;
1212
use crate::internal::incompatibility::{Incompatibility, Relation};
1313
use crate::internal::partial_solution::{DecisionLevel, PartialSolution};
14+
use crate::internal::small_vec::SmallVec;
1415
use crate::package::Package;
1516
use crate::report::DerivationTree;
1617
use crate::solver::DependencyConstraints;
@@ -39,7 +40,7 @@ pub struct State<P: Package, V: Version> {
3940
/// This is a stack of work to be done in `unit_propagation`.
4041
/// It can definitely be a local variable to that method, but
4142
/// this way we can reuse the same allocation for better performance.
42-
unit_propagation_buffer: Vec<P>,
43+
unit_propagation_buffer: SmallVec<P>,
4344
}
4445

4546
impl<P: Package, V: Version> State<P, V> {
@@ -59,7 +60,7 @@ impl<P: Package, V: Version> State<P, V> {
5960
contradicted_incompatibilities: rustc_hash::FxHashSet::default(),
6061
partial_solution: PartialSolution::empty(),
6162
incompatibility_store,
62-
unit_propagation_buffer: vec![],
63+
unit_propagation_buffer: SmallVec::Empty,
6364
}
6465
}
6566

src/internal/small_vec.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,32 @@ impl<T> SmallVec<T> {
3939
}
4040
}
4141

42+
pub fn pop(&mut self) -> Option<T> {
43+
match std::mem::take(self) {
44+
Self::Empty => None,
45+
Self::One([v1]) => {
46+
*self = Self::Empty;
47+
Some(v1)
48+
}
49+
Self::Two([v1, v2]) => {
50+
*self = Self::One([v1]);
51+
Some(v2)
52+
}
53+
Self::Flexible(mut v) => {
54+
let out = v.pop();
55+
*self = Self::Flexible(v);
56+
out
57+
}
58+
}
59+
}
60+
61+
pub fn clear(&mut self) {
62+
if let Self::Flexible(mut v) = std::mem::take(self) {
63+
v.clear();
64+
*self = Self::Flexible(v);
65+
} // else: self already eq Empty from the take
66+
}
67+
4268
pub fn iter(&self) -> std::slice::Iter<'_, T> {
4369
self.as_slice().iter()
4470
}
@@ -101,3 +127,31 @@ impl<'de, T: serde::Deserialize<'de>> serde::Deserialize<'de> for SmallVec<T> {
101127
Ok(v)
102128
}
103129
}
130+
131+
// TESTS #######################################################################
132+
133+
#[cfg(test)]
134+
pub mod tests {
135+
use super::*;
136+
use proptest::prelude::*;
137+
138+
proptest! {
139+
#[test]
140+
fn push_and_pop(comands: Vec<Option<u8>>) {
141+
let mut v = vec![];
142+
let mut sv = SmallVec::Empty;
143+
for comand in comands {
144+
match comand {
145+
Some(i) => {
146+
v.push(i);
147+
sv.push(i);
148+
}
149+
None => {
150+
assert_eq!(v.pop(), sv.pop());
151+
}
152+
}
153+
assert_eq!(v.as_slice(), sv.as_slice());
154+
}
155+
}
156+
}
157+
}

0 commit comments

Comments
 (0)