From 9fbacbfd196f159cbcf339aab6d8aa0830a455a5 Mon Sep 17 00:00:00 2001
From: Andreas Reis <887320+twwn@users.noreply.github.com>
Date: Mon, 30 Sep 2024 01:28:38 +0200
Subject: [PATCH] typeanswer: micro-optimize vectors
Should get rid of most relocations, at the expense of over-allocating.
On Vec's (String's) behavior: https://stackoverflow.com/a/72787776
---
rslib/src/typeanswer.rs | 47 +++++++++++++++++++++++------------------
1 file changed, 27 insertions(+), 20 deletions(-)
diff --git a/rslib/src/typeanswer.rs b/rslib/src/typeanswer.rs
index 54f037ae0..2a6f58df6 100644
--- a/rslib/src/typeanswer.rs
+++ b/rslib/src/typeanswer.rs
@@ -71,8 +71,8 @@ trait DiffTrait {
fn to_tokens(&self) -> DiffTokens {
let mut matcher = SequenceMatcher::new(self.get_typed(), self.get_expected());
- let mut typed_tokens = Vec::new();
- let mut expected_tokens = Vec::new();
+ let mut typed_tokens = Vec::with_capacity(self.get_typed().len());
+ let mut expected_tokens = Vec::with_capacity(self.get_expected().len());
for opcode in matcher.get_opcodes() {
let typed_slice = slice(self.get_typed(), opcode.first_start, opcode.first_end);
@@ -132,13 +132,16 @@ fn prepare_expected(expected: &str) -> String {
// Render Functions
fn render_tokens(tokens: &[DiffToken]) -> String {
- tokens.iter().fold(String::new(), |mut acc, token| {
- let isolated_text = isolate_leading_mark(&token.text);
- let encoded_text = htmlescape::encode_minimal(&isolated_text);
- let class = token.to_class();
- acc.push_str(&format!("{encoded_text}"));
- acc
- })
+ tokens.iter().fold(
+ String::with_capacity(tokens.len() * 20),
+ |mut acc, token| {
+ let isolated_text = isolate_leading_mark(&token.text);
+ let encoded_text = htmlescape::encode_minimal(&isolated_text);
+ let class = token.to_class();
+ acc.push_str(&format!("{encoded_text}"));
+ acc
+ },
+ )
}
/// Prefixes a leading mark character with a non-breaking space to prevent
@@ -204,9 +207,10 @@ impl DiffTrait for DiffNonCombining {
fn new(expected: &str, typed: &str) -> Self {
// filter out combining elements
- let mut expected_stripped = String::new();
+ let mut expected_stripped = String::with_capacity(expected.len());
// tokenized into "char+combining" for final rendering
- let mut expected_split: Vec = Vec::new();
+ let mut expected_split: Vec = Vec::with_capacity(expected.len());
+
for c in normalize(&prepare_expected(expected), true) {
if unicode_normalization::char::is_combining_mark(c) {
if let Some(last) = expected_split.last_mut() {
@@ -233,15 +237,18 @@ impl DiffTrait for DiffNonCombining {
// having to otherwise e.g. include their field twice in the note template.
fn render_expected_tokens(&self, tokens: &[DiffToken]) -> String {
let mut idx = 0;
- tokens.iter().fold(String::new(), |mut acc, token| {
- let end = idx + token.text.chars().count();
- let txt = self.expected_split[idx..end].concat();
- idx = end;
- let encoded_text = htmlescape::encode_minimal(&txt);
- let class = token.to_class();
- acc.push_str(&format!("{encoded_text}"));
- acc
- })
+ tokens.iter().fold(
+ String::with_capacity(tokens.len() * 20),
+ |mut acc, token| {
+ let end = idx + token.text.chars().count();
+ let txt = self.expected_split[idx..end].concat();
+ idx = end;
+ let encoded_text = htmlescape::encode_minimal(&txt);
+ let class = token.to_class();
+ acc.push_str(&format!("{encoded_text}"));
+ acc
+ },
+ )
}
}