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 #!/bin/bash
cargo build --release || exit 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 cat benchmark.log
git describe --always --dirty=-dev | tee -a 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; 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)] #[derive(Clone)]
pub struct CandidateMap<'e, V> { pub struct CandidateMap<'e, V> {
keys: Vec<Option<&'e Candidate>>, entries: Vec<Option<(&'e Candidate, V)>>
values: Vec<Option<V>>
} }
impl<'e, V> CandidateMap<'e, V> { impl<'e, V> CandidateMap<'e, V> {
/// See [HashMap::new] /// See [HashMap::new]
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
keys: Vec::new(), entries: Vec::new()
values: Vec::new()
} }
} }
/// See [HashMap::with_capacity] /// See [HashMap::with_capacity]
pub fn with_capacity(capacity: usize) -> Self { pub fn with_capacity(capacity: usize) -> Self {
let mut ret = Self { let mut ret = Self {
keys: Vec::with_capacity(capacity), entries: Vec::with_capacity(capacity)
values: Vec::with_capacity(capacity)
}; };
ret.maybe_resize(capacity); ret.maybe_resize(capacity);
return ret; return ret;
} }
fn maybe_resize(&mut self, len: usize) { fn maybe_resize(&mut self, len: usize) {
if len < self.keys.len() { if len < self.entries.len() {
return; return;
} }
self.keys.resize_with(len, || None); self.entries.resize_with(len, || None);
self.values.resize_with(len, || None);
} }
/// See [HashMap::len] /// See [HashMap::len]
#[inline] #[inline]
pub fn len(&self) -> usize { 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] /// See [HashMap::insert]
#[inline] #[inline]
pub fn insert(&mut self, candidate: &'e Candidate, value: V) { pub fn insert(&mut self, candidate: &'e Candidate, value: V) {
self.maybe_resize(candidate.index + 1); self.maybe_resize(candidate.index + 1);
self.keys[candidate.index] = Some(candidate); self.entries[candidate.index] = Some((candidate, value));
self.values[candidate.index] = Some(value);
} }
/// See [HashMap::get] /// See [HashMap::get]
#[inline] #[inline]
pub fn get(&self, candidate: &'e Candidate) -> Option<&V> { 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] /// See [HashMap::get_mut]
#[inline] #[inline]
pub fn get_mut(&mut self, candidate: &'e Candidate) -> Option<&mut V> { 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) => { Some(v) => {
return v.as_mut(); return v.as_mut().map(|(_, v)| v);
} }
None => { None => {
return None; return None;
@ -110,10 +105,11 @@ impl<'e, V> Index<&Candidate> for CandidateMap<'e, V> {
type Output = V; type Output = V;
fn index(&self, candidate: &Candidate) -> &Self::Output { 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> { pub struct Iter<'m, 'e, V> {
map: &'m CandidateMap<'e, V>, map: &'m CandidateMap<'e, V>,
index: usize index: usize
@ -124,17 +120,14 @@ impl<'m, 'e, V> Iterator for Iter<'m, 'e, V> {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
loop { loop {
match self.map.keys.get(self.index) { match self.map.entries.get(self.index) {
Some(k) => { Some(e) => {
// Key within range // Key within range
match k { match e {
Some(kk) => { Some((k, v)) => {
// Key is set // 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; self.index += 1;
return Some((kk, v)); return Some((k, v));
} }
None => { None => {
// Key is unset // 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> { pub struct IterMut<'m, 'e, V> {
map: &'m mut CandidateMap<'e, V>, map: &'m mut CandidateMap<'e, V>,
index: usize index: usize
@ -162,22 +156,19 @@ impl<'m, 'e, V> Iterator for IterMut<'m, 'e, V> {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
loop { loop {
match self.map.keys.get(self.index) { match self.map.entries.get_mut(self.index) {
Some(k) => { Some(e) => {
// Key within range // Key within range
match k { match e {
Some(kk) => { Some((k, v)) => {
// Key is set // 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; let v_ptr = v as *mut V;
// SAFETY: Need unsafe pointer magic for IterMut // SAFETY: Need unsafe pointer magic for IterMut
let vv = unsafe { &mut *v_ptr }; let vv = unsafe { &mut *v_ptr };
self.index += 1; self.index += 1;
return Some((kk, vv)); return Some((k, vv));
} }
None => { None => {
// Key is unset // 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> { pub struct Values<'m, 'e, V> {
map: &'m CandidateMap<'e, V>, map: &'m CandidateMap<'e, V>,
index: usize index: usize
@ -205,14 +197,14 @@ impl<'m, 'e, V> Iterator for Values<'m, 'e, V> {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
loop { loop {
match self.map.values.get(self.index) { match self.map.entries.get(self.index) {
Some(v) => { Some(e) => {
// Key within range // Key within range
match v { match e {
Some(vv) => { Some((_, v)) => {
// Key is set // Key is set
self.index += 1; self.index += 1;
return Some(vv); return Some(v);
} }
None => { None => {
// Key is unset // 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> { pub struct IntoIter<'e, V> {
map: CandidateMap<'e, V>, map: CandidateMap<'e, V>,
index: usize index: usize
@ -240,17 +233,14 @@ impl<'e, V> Iterator for IntoIter<'e, V> {
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
loop { loop {
match self.map.keys.get(self.index) { match self.map.entries.get_mut(self.index) {
Some(k) => { Some(e) => {
// Key within range // Key within range
match k { match e.take() {
Some(kk) => { Some((k, v)) => {
// Key is set // 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; self.index += 1;
return Some((kk, v)); return Some((k, v));
} }
None => { None => {
// Key is unset // Key is unset