Open-source election counting https://yingtongli.me/opentally/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
OpenTally/src/candmap.rs

269 lines
5.7 KiB

/* OpenTally: Open-source election vote counting
* Copyright © 2021–2022 Lee Yingtong Li (RunasSudo)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
use crate::election::Candidate;
use std::ops::Index;
/// Mimics a [HashMap] on [Candidate]s, but internally is a [Vec] based on [Candidate::index]
#[derive(Clone)]
pub struct CandidateMap<'e, V> {
entries: Vec<Option<(&'e Candidate, V)>>
}
impl<'e, V> CandidateMap<'e, V> {
/// See [HashMap::new]
pub fn new() -> Self {
Self {
entries: Vec::new()
}
}
/// See [HashMap::with_capacity]
pub fn with_capacity(capacity: usize) -> Self {
let mut ret = Self {
entries: Vec::with_capacity(capacity)
};
ret.maybe_resize(capacity);
return ret;
}
fn maybe_resize(&mut self, len: usize) {
if len < self.entries.len() {
return;
}
self.entries.resize_with(len, || None);
}
/// See [HashMap::len]
#[inline]
pub fn len(&self) -> usize {
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.entries[candidate.index] = Some((candidate, value));
}
/// See [HashMap::get]
#[inline]
pub fn get(&self, candidate: &'e Candidate) -> Option<&V> {
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.entries.get_mut(candidate.index) {
Some(v) => {
return v.as_mut().map(|(_, v)| v);
}
None => {
return None;
}
}
}
/// See [HashMap::iter]
#[inline]
pub fn iter(&self) -> Iter<'_, 'e, V> {
return Iter { map: &self, index: 0 };
}
/// See [HashMap::iter_mut]
#[inline]
pub fn iter_mut(&mut self) -> IterMut<'_, 'e, V> {
return IterMut { map: self, index: 0 };
}
/// See [HashMap::values]
#[inline]
pub fn values(&self) -> Values<'_, 'e, V> {
return Values { map: &self, index: 0 };
}
}
impl<'e, V> Index<&Candidate> for CandidateMap<'e, V> {
type Output = V;
fn index(&self, candidate: &Candidate) -> &Self::Output {
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
}
impl<'m, 'e, V> Iterator for Iter<'m, 'e, V> {
type Item = (&'e Candidate, &'m V);
fn next(&mut self) -> Option<Self::Item> {
loop {
match self.map.entries.get(self.index) {
Some(e) => {
// Key within range
match e {
Some((k, v)) => {
// Key is set
self.index += 1;
return Some((k, v));
}
None => {
// Key is unset
self.index += 1;
continue;
}
}
}
None => {
// Key outside range
return None;
}
}
}
}
}
/// See [CandidateMap::iter_mut]
pub struct IterMut<'m, 'e, V> {
map: &'m mut CandidateMap<'e, V>,
index: usize
}
impl<'m, 'e, V> Iterator for IterMut<'m, 'e, V> {
type Item = (&'e Candidate, &'m mut V);
fn next(&mut self) -> Option<Self::Item> {
loop {
match self.map.entries.get_mut(self.index) {
Some(e) => {
// Key within range
match e {
Some((k, v)) => {
// Key is set
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((k, vv));
}
None => {
// Key is unset
self.index += 1;
continue;
}
}
}
None => {
// Key outside range
return None;
}
}
}
}
}
/// See [CandidateMap::values]
pub struct Values<'m, 'e, V> {
map: &'m CandidateMap<'e, V>,
index: usize
}
impl<'m, 'e, V> Iterator for Values<'m, 'e, V> {
type Item = &'m V;
fn next(&mut self) -> Option<Self::Item> {
loop {
match self.map.entries.get(self.index) {
Some(e) => {
// Key within range
match e {
Some((_, v)) => {
// Key is set
self.index += 1;
return Some(v);
}
None => {
// Key is unset
self.index += 1;
continue;
}
}
}
None => {
// Key outside range
return None;
}
}
}
}
}
/// See [CandidateMap::into_iter]
pub struct IntoIter<'e, V> {
map: CandidateMap<'e, V>,
index: usize
}
impl<'e, V> Iterator for IntoIter<'e, V> {
type Item = (&'e Candidate, V);
fn next(&mut self) -> Option<Self::Item> {
loop {
match self.map.entries.get_mut(self.index) {
Some(e) => {
// Key within range
match e.take() {
Some((k, v)) => {
// Key is set
self.index += 1;
return Some((k, v));
}
None => {
// Key is unset
self.index += 1;
continue;
}
}
}
None => {
// Key outside range
return None;
}
}
}
}
}
impl<'e, V> IntoIterator for CandidateMap<'e, V> {
type Item = (&'e Candidate, V);
type IntoIter = IntoIter<'e, V>;
fn into_iter(self) -> Self::IntoIter {
return IntoIter { map: self, index: 0 };
}
}