Avoid more allocations in fold

This commit is contained in:
RunasSudo 2022-08-20 22:33:48 +10:00
parent 2bce8cfc3f
commit 9a4af322ca
No known key found for this signature in database
GPG Key ID: 7234E476BF21C61A
4 changed files with 53 additions and 21 deletions

View File

@ -343,7 +343,7 @@ where
for<'r> &'r N: ops::Neg<Output=N> for<'r> &'r N: ops::Neg<Output=N>
{ {
// Describe count // Describe count
let total_ballots = election.ballots.iter().fold(N::zero(), |acc, b| { acc + &b.orig_value }); let total_ballots = election.ballots.iter().fold(N::new(), |mut acc, b| { acc += &b.orig_value; acc });
print!("Count computed by OpenTally (revision {}). Read {:.0} ballots from \"{}\" for election \"{}\". There are {} candidates for {} vacancies. ", crate::VERSION, total_ballots, filename, election.name, election.candidates.iter().filter(|c| !c.is_dummy).count(), election.seats); print!("Count computed by OpenTally (revision {}). Read {:.0} ballots from \"{}\" for election \"{}\". There are {} candidates for {} vacancies. ", crate::VERSION, total_ballots, filename, election.name, election.candidates.iter().filter(|c| !c.is_dummy).count(), election.seats);
let opts_str = opts.describe::<N>(); let opts_str = opts.describe::<N>();
if !opts_str.is_empty() { if !opts_str.is_empty() {
@ -441,7 +441,7 @@ where
for<'r> &'r N: ops::Neg<Output=N> for<'r> &'r N: ops::Neg<Output=N>
{ {
// Header rows // Header rows
let total_ballots = election.ballots.iter().fold(N::zero(), |acc, b| { acc + &b.orig_value }); let total_ballots = election.ballots.iter().fold(N::new(), |mut acc, b| { acc += &b.orig_value; acc });
// eSTV does not consistently quote records, so we won't use a CSV library here // eSTV does not consistently quote records, so we won't use a CSV library here
println!(r#""Election for","{}""#, election.name); println!(r#""Election for","{}""#, election.name);

View File

@ -301,7 +301,7 @@ impl<'a, N: Number> CountState<'a, N> {
result.push_str(&format!("Exhausted: {:.dps$} ({:.dps$})\n", self.exhausted.votes, self.exhausted.transfers, dps=opts.pp_decimals)); result.push_str(&format!("Exhausted: {:.dps$} ({:.dps$})\n", self.exhausted.votes, self.exhausted.transfers, dps=opts.pp_decimals));
result.push_str(&format!("Loss by fraction: {:.dps$} ({:.dps$})\n", self.loss_fraction.votes, self.loss_fraction.transfers, dps=opts.pp_decimals)); result.push_str(&format!("Loss by fraction: {:.dps$} ({:.dps$})\n", self.loss_fraction.votes, self.loss_fraction.transfers, dps=opts.pp_decimals));
let mut total_vote = self.candidates.iter().filter_map(|(c, cc)| if c.is_dummy { None } else { Some(cc) }).fold(N::zero(), |acc, cc| { acc + &cc.votes }); let mut total_vote = self.candidates.iter().filter_map(|(c, cc)| if c.is_dummy { None } else { Some(cc) }).fold(N::new(), |mut acc, cc| { acc += &cc.votes; acc });
total_vote += &self.exhausted.votes; total_vote += &self.exhausted.votes;
total_vote += &self.loss_fraction.votes; total_vote += &self.loss_fraction.votes;
result.push_str(&format!("Total votes: {:.dps$}\n", total_vote, dps=opts.pp_decimals)); result.push_str(&format!("Total votes: {:.dps$}\n", total_vote, dps=opts.pp_decimals));

View File

@ -902,11 +902,19 @@ fn update_vre_ers<N: Number>(state: &mut CountState<N>, opts: &STVOptions) {
let mut log = String::new(); let mut log = String::new();
// Calculate active vote // Calculate active vote
let active_vote = state.candidates.values().fold(N::zero(), |acc, cc| { let active_vote = state.candidates.values().fold(N::new(), |mut acc, cc| {
match cc.state { match cc.state {
CandidateState::Elected => { if !cc.finalised && &cc.votes > state.quota.as_ref().unwrap() { acc + &cc.votes - state.quota.as_ref().unwrap() } else { acc } } CandidateState::Elected => {
_ => { acc + &cc.votes } if !cc.finalised && &cc.votes > state.quota.as_ref().unwrap() {
acc += &cc.votes;
acc -= state.quota.as_ref().unwrap();
}
}
_ => {
acc += &cc.votes;
}
} }
acc
}); });
log.push_str(format!("Active vote is {:.dps$}, so the vote required for election is ", active_vote, dps=opts.pp_decimals).as_str()); log.push_str(format!("Active vote is {:.dps$}, so the vote required for election is ", active_vote, dps=opts.pp_decimals).as_str());
@ -942,11 +950,19 @@ fn update_vre_bulk<N: Number>(state: &mut CountState<N>, _opts: &STVOptions) {
//let mut log = String::new(); //let mut log = String::new();
// Calculate active vote // Calculate active vote
let active_vote = state.candidates.values().fold(N::zero(), |acc, cc| { let active_vote = state.candidates.values().fold(N::new(), |mut acc, cc| {
match cc.state { match cc.state {
CandidateState::Elected => { if !cc.finalised && &cc.votes > state.quota.as_ref().unwrap() { acc + &cc.votes - state.quota.as_ref().unwrap() } else { acc } } CandidateState::Elected => {
_ => { acc + &cc.votes } if !cc.finalised && &cc.votes > state.quota.as_ref().unwrap() {
acc += &cc.votes;
acc -= state.quota.as_ref().unwrap();
}
}
_ => {
acc += &cc.votes;
}
} }
acc
}); });
//log.push_str(format!("Active vote is {:.dps$}, so the vote required for election is ", active_vote, dps=opts.pp_decimals).as_str()); //log.push_str(format!("Active vote is {:.dps$}, so the vote required for election is ", active_vote, dps=opts.pp_decimals).as_str());
@ -977,7 +993,7 @@ fn calculate_quota<N: Number>(state: &mut CountState<N>, opts: &STVOptions) {
let mut log = String::new(); let mut log = String::new();
// Calculate the total vote // Calculate the total vote
let total_vote = state.candidates.values().fold(N::zero(), |acc, cc| { acc + &cc.votes }); let total_vote = state.candidates.values().fold(N::new(), |mut acc, cc| { acc += &cc.votes; acc });
log.push_str(format!("{:.dps$} usable votes, so the quota is ", total_vote, dps=opts.pp_decimals).as_str()); log.push_str(format!("{:.dps$} usable votes, so the quota is ", total_vote, dps=opts.pp_decimals).as_str());
let quota = total_to_quota(total_vote, state.election.seats, opts); let quota = total_to_quota(total_vote, state.election.seats, opts);
@ -992,11 +1008,19 @@ fn calculate_quota<N: Number>(state: &mut CountState<N>, opts: &STVOptions) {
let mut log = String::new(); let mut log = String::new();
// Calculate the active vote // Calculate the active vote
let active_vote = state.candidates.values().fold(N::zero(), |acc, cc| { let active_vote = state.candidates.values().fold(N::new(), |mut acc, cc| {
match cc.state { match cc.state {
CandidateState::Elected => { if !cc.finalised && &cc.votes > state.quota.as_ref().unwrap() { acc + &cc.votes - state.quota.as_ref().unwrap() } else { acc } } CandidateState::Elected => {
_ => { acc + &cc.votes } if !cc.finalised && &cc.votes > state.quota.as_ref().unwrap() {
acc += &cc.votes;
acc -= state.quota.as_ref().unwrap();
}
}
_ => {
acc += &cc.votes;
}
} }
acc
}); });
log.push_str(format!("Active vote is {:.dps$}, so the quota is is ", active_vote, dps=opts.pp_decimals).as_str()); log.push_str(format!("Active vote is {:.dps$}, so the quota is is ", active_vote, dps=opts.pp_decimals).as_str());
@ -1018,7 +1042,7 @@ fn calculate_quota<N: Number>(state: &mut CountState<N>, opts: &STVOptions) {
let mut log = String::new(); let mut log = String::new();
// Calculate the total vote // Calculate the total vote
let total_vote = state.candidates.values().fold(N::zero(), |acc, cc| { acc + &cc.votes }); let total_vote = state.candidates.values().fold(N::new(), |mut acc, cc| { acc += &cc.votes; acc });
log.push_str(format!("{:.dps$} usable votes, so the quota is reduced to ", total_vote, dps=opts.pp_decimals).as_str()); log.push_str(format!("{:.dps$} usable votes, so the quota is reduced to ", total_vote, dps=opts.pp_decimals).as_str());
let quota = total_to_quota(total_vote, state.election.seats, opts); let quota = total_to_quota(total_vote, state.election.seats, opts);
@ -1102,12 +1126,20 @@ fn elect_sure_winners<'a, N: Number>(state: &mut CountState<'a, N>, opts: &STVOp
// For trailing candidates, count all votes // For trailing candidates, count all votes
total_trailing += hopefuls.iter().skip(num_vacancies).fold(N::new(), |mut acc, (_, cc)| { acc += &cc.votes; acc }); total_trailing += hopefuls.iter().skip(num_vacancies).fold(N::new(), |mut acc, (_, cc)| { acc += &cc.votes; acc });
// Add finally any votes awaiting transfer // Add finally any votes awaiting transfer
total_trailing += state.candidates.values().fold(N::zero(), |acc, cc| { total_trailing += state.candidates.values().fold(N::new(), |mut acc, cc| {
match cc.state { match cc.state {
CandidateState::Elected => { if !cc.finalised && &cc.votes > state.quota.as_ref().unwrap() { acc + &cc.votes - state.quota.as_ref().unwrap() } else { acc } } CandidateState::Elected => {
CandidateState::Hopeful | CandidateState::Guarded | CandidateState::Withdrawn => { acc } if !cc.finalised && &cc.votes > state.quota.as_ref().unwrap() {
CandidateState::Excluded | CandidateState::Doomed => { acc + &cc.votes } acc += &cc.votes;
acc -= state.quota.as_ref().unwrap();
}
}
CandidateState::Hopeful | CandidateState::Guarded | CandidateState::Withdrawn => {}
CandidateState::Excluded | CandidateState::Doomed => {
acc += &cc.votes;
}
} }
acc
}); });
if num_vacancies - 1 < hopefuls.len() { if num_vacancies - 1 < hopefuls.len() {

View File

@ -329,7 +329,7 @@ impl STVOptions {
pub fn describe_count<N: Number>(filename: String, election: &Election<N>, opts: &stv::STVOptions) -> String { pub fn describe_count<N: Number>(filename: String, election: &Election<N>, opts: &stv::STVOptions) -> String {
let mut result = String::from("<p>Count computed by OpenTally (revision "); let mut result = String::from("<p>Count computed by OpenTally (revision ");
result.push_str(crate::VERSION); result.push_str(crate::VERSION);
let total_ballots = election.ballots.iter().fold(N::zero(), |acc, b| { acc + &b.orig_value }); let total_ballots = election.ballots.iter().fold(N::new(), |mut acc, b| { acc += &b.orig_value; acc });
result.push_str(&format!(r#"). Read {:.0} ballots from &lsquo;{}&rsquo; for election &lsquo;{}&rsquo;. There are {} candidates for {} vacancies. "#, total_ballots, filename, election.name, election.candidates.iter().filter(|c| !c.is_dummy).count(), election.seats)); result.push_str(&format!(r#"). Read {:.0} ballots from &lsquo;{}&rsquo; for election &lsquo;{}&rsquo;. There are {} candidates for {} vacancies. "#, total_ballots, filename, election.name, election.candidates.iter().filter(|c| !c.is_dummy).count(), election.seats));
let opts_str = opts.describe::<N>(); let opts_str = opts.describe::<N>();
@ -605,7 +605,7 @@ pub fn update_results_table<N: Number>(stage_num: usize, state: &CountState<N>,
} }
// Calculate total votes // Calculate total votes
let mut total_vote = state.candidates.iter().filter_map(|(c, cc)| if c.is_dummy { None } else { Some(cc) }).fold(N::zero(), |acc, cc| { acc + &cc.votes }); let mut total_vote = state.candidates.iter().filter_map(|(c, cc)| if c.is_dummy { None } else { Some(cc) }).fold(N::new(), |mut acc, cc| { acc += &cc.votes; acc });
total_vote += &state.exhausted.votes; total_vote += &state.exhausted.votes;
total_vote += &state.loss_fraction.votes; total_vote += &state.loss_fraction.votes;
@ -622,7 +622,7 @@ pub fn update_results_table<N: Number>(stage_num: usize, state: &CountState<N>,
} }
"ballots_votes" => { "ballots_votes" => {
// Calculate total ballots // Calculate total ballots
let mut total_ballots = state.candidates.values().fold(N::zero(), |acc, cc| { acc + cc.num_ballots() }); let mut total_ballots = state.candidates.values().fold(N::new(), |mut acc, cc| { acc += cc.num_ballots(); acc });
total_ballots += state.exhausted.num_ballots(); total_ballots += state.exhausted.num_ballots();
result.push(&format!(r#"<td class="{}count">{}</td><td class="count">{}</td>"#, classes_i, pp(&total_ballots, 0), pp(&total_vote, opts.pp_decimals)).into()); result.push(&format!(r#"<td class="{}count">{}</td><td class="count">{}</td>"#, classes_i, pp(&total_ballots, 0), pp(&total_vote, opts.pp_decimals)).into());
} }