Refactor CandidateMap
This commit is contained in:
parent
876be9c55a
commit
3902c37768
|
@ -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
|
||||
|
|
|
@ -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<Option<&'e Candidate>>,
|
||||
values: Vec<Option<V>>
|
||||
entries: Vec<Option<(&'e Candidate, V)>>
|
||||
}
|
||||
|
||||
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<Self::Item> {
|
||||
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<Self::Item> {
|
||||
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<Self::Item> {
|
||||
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<Self::Item> {
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue