diff --git a/benchmark.sh b/benchmark.sh index 5451556..ad7e8d6 100755 --- a/benchmark.sh +++ b/benchmark.sh @@ -1,7 +1,7 @@ #!/bin/bash cargo build --release || exit -perf stat -r 5 -o benchmark.log ./target/release/opentally stv '/home/runassudo/git/stvdb/Australian Senate/2022/VIC.blt' --round-votes 0 --round-quota 0 --quota droop --quota-criterion geq --ties backwards random --random-seed 20210727 --surplus uig --surplus-order by_order --exclusion by_value --pp-decimals 0 $@ +perf stat -r 5 --table -o benchmark.log ./target/release/opentally stv '/home/runassudo/git/stvdb/Australian Senate/2022/VIC.blt' --round-votes 0 --round-quota 0 --quota droop --quota-criterion geq --ties backwards random --random-seed 20210727 --surplus uig --surplus-order by_order --exclusion by_value --pp-decimals 0 $@ cat benchmark.log git describe --always --dirty=-dev | tee -a benchmark.log diff --git a/src/candmap.rs b/src/candmap.rs index a6bcfe9..5f2a877 100644 --- a/src/candmap.rs +++ b/src/candmap.rs @@ -19,67 +19,62 @@ use crate::election::Candidate; use std::ops::Index; -/// Newtype for [HashMap] on [Candidate]s +/// Mimics a [HashMap] on [Candidate]s, but internally is a [Vec] based on [Candidate::index] #[derive(Clone)] pub struct CandidateMap<'e, V> { - keys: Vec>, - values: Vec> + entries: Vec> } impl<'e, V> CandidateMap<'e, V> { /// See [HashMap::new] pub fn new() -> Self { Self { - keys: Vec::new(), - values: Vec::new() + entries: Vec::new() } } /// See [HashMap::with_capacity] pub fn with_capacity(capacity: usize) -> Self { let mut ret = Self { - keys: Vec::with_capacity(capacity), - values: Vec::with_capacity(capacity) + entries: Vec::with_capacity(capacity) }; ret.maybe_resize(capacity); return ret; } fn maybe_resize(&mut self, len: usize) { - if len < self.keys.len() { + if len < self.entries.len() { return; } - self.keys.resize_with(len, || None); - self.values.resize_with(len, || None); + self.entries.resize_with(len, || None); } /// See [HashMap::len] #[inline] pub fn len(&self) -> usize { - return self.keys.iter().filter(|k| k.is_some()).count(); + return self.entries.iter().filter(|e| e.is_some()).count(); } /// See [HashMap::insert] #[inline] pub fn insert(&mut self, candidate: &'e Candidate, value: V) { self.maybe_resize(candidate.index + 1); - self.keys[candidate.index] = Some(candidate); - self.values[candidate.index] = Some(value); + self.entries[candidate.index] = Some((candidate, value)); } /// See [HashMap::get] #[inline] pub fn get(&self, candidate: &'e Candidate) -> Option<&V> { - return self.values.get(candidate.index).unwrap_or(&None).as_ref(); + return self.entries.get(candidate.index).unwrap_or(&None).as_ref().map(|(_, v)| v); } /// See [HashMap::get_mut] #[inline] pub fn get_mut(&mut self, candidate: &'e Candidate) -> Option<&mut V> { - match self.values.get_mut(candidate.index) { + match self.entries.get_mut(candidate.index) { Some(v) => { - return v.as_mut(); + return v.as_mut().map(|(_, v)| v); } None => { return None; @@ -110,10 +105,11 @@ impl<'e, V> Index<&Candidate> for CandidateMap<'e, V> { type Output = V; fn index(&self, candidate: &Candidate) -> &Self::Output { - return self.values.get(candidate.index).unwrap_or(&None).as_ref().unwrap(); + return self.entries.get(candidate.index).unwrap_or(&None).as_ref().map(|(_, v)| v).unwrap(); } } +/// See [CandidateMap::iter] pub struct Iter<'m, 'e, V> { map: &'m CandidateMap<'e, V>, index: usize @@ -124,17 +120,14 @@ impl<'m, 'e, V> Iterator for Iter<'m, 'e, V> { fn next(&mut self) -> Option { loop { - match self.map.keys.get(self.index) { - Some(k) => { + match self.map.entries.get(self.index) { + Some(e) => { // Key within range - match k { - Some(kk) => { + match e { + Some((k, v)) => { // Key is set - - // SAFETY: Guaranteed to be set, as we update key and value at the same time - let v = unsafe { self.map.values.get_unchecked(self.index).as_ref().unwrap_unchecked() }; self.index += 1; - return Some((kk, v)); + return Some((k, v)); } None => { // Key is unset @@ -152,6 +145,7 @@ impl<'m, 'e, V> Iterator for Iter<'m, 'e, V> { } } +/// See [CandidateMap::iter_mut] pub struct IterMut<'m, 'e, V> { map: &'m mut CandidateMap<'e, V>, index: usize @@ -162,22 +156,19 @@ impl<'m, 'e, V> Iterator for IterMut<'m, 'e, V> { fn next(&mut self) -> Option { loop { - match self.map.keys.get(self.index) { - Some(k) => { + match self.map.entries.get_mut(self.index) { + Some(e) => { // Key within range - match k { - Some(kk) => { + match e { + Some((k, v)) => { // Key is set - - // SAFETY: Guaranteed to be set, as we update key and value at the same time - let v = unsafe { self.map.values.get_unchecked_mut(self.index).as_mut().unwrap_unchecked() }; let v_ptr = v as *mut V; // SAFETY: Need unsafe pointer magic for IterMut let vv = unsafe { &mut *v_ptr }; self.index += 1; - return Some((kk, vv)); + return Some((k, vv)); } None => { // Key is unset @@ -195,6 +186,7 @@ impl<'m, 'e, V> Iterator for IterMut<'m, 'e, V> { } } +/// See [CandidateMap::values] pub struct Values<'m, 'e, V> { map: &'m CandidateMap<'e, V>, index: usize @@ -205,14 +197,14 @@ impl<'m, 'e, V> Iterator for Values<'m, 'e, V> { fn next(&mut self) -> Option { loop { - match self.map.values.get(self.index) { - Some(v) => { + match self.map.entries.get(self.index) { + Some(e) => { // Key within range - match v { - Some(vv) => { + match e { + Some((_, v)) => { // Key is set self.index += 1; - return Some(vv); + return Some(v); } None => { // Key is unset @@ -230,6 +222,7 @@ impl<'m, 'e, V> Iterator for Values<'m, 'e, V> { } } +/// See [CandidateMap::into_iter] pub struct IntoIter<'e, V> { map: CandidateMap<'e, V>, index: usize @@ -240,17 +233,14 @@ impl<'e, V> Iterator for IntoIter<'e, V> { fn next(&mut self) -> Option { loop { - match self.map.keys.get(self.index) { - Some(k) => { + match self.map.entries.get_mut(self.index) { + Some(e) => { // Key within range - match k { - Some(kk) => { + match e.take() { + Some((k, v)) => { // Key is set - - // SAFETY: Guaranteed to be set, as we update key and value at the same time - let v = unsafe { self.map.values.get_unchecked_mut(self.index).take().unwrap_unchecked() }; self.index += 1; - return Some((kk, v)); + return Some((k, v)); } None => { // Key is unset