Refactor CandidateMap

This commit is contained in:
RunasSudo 2022-08-21 06:02:06 +10:00
parent 876be9c55a
commit 3902c37768
Signed by: RunasSudo
GPG Key ID: 7234E476BF21C61A
2 changed files with 37 additions and 47 deletions

View File

@ -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

View File

@ -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