Refactor CandidateMap
This commit is contained in:
parent
876be9c55a
commit
3902c37768
@ -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
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user