From a0b4162d7a6682f839d625695575e9ed069079b7 Mon Sep 17 00:00:00 2001 From: Skgland Date: Tue, 18 Nov 2025 21:42:10 +0100 Subject: [PATCH] improve count_to_letter_code - reserve the complete required length at the beginning to reduce reallocations - use u8 instead of char so that we can re-use the allocation for the string --- src/machine/lib_machine/mod.rs | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/machine/lib_machine/mod.rs b/src/machine/lib_machine/mod.rs index 653fc2a4..7527c05c 100644 --- a/src/machine/lib_machine/mod.rs +++ b/src/machine/lib_machine/mod.rs @@ -159,9 +159,14 @@ impl Term { fn count_to_letter_code(mut count: usize) -> String { let mut letters = Vec::new(); + // +2 rather than +1 to account for the _ at the end + let length = count.checked_ilog(26).unwrap_or(0) as usize + 2; + + letters.reserve(length); + loop { - let letter_idx = (count % 26) as u32; - letters.push(char::from_u32('A' as u32 + letter_idx).unwrap()); + let letter_idx = (count % 26) as u8; + letters.push(b'A' + letter_idx); count /= 26; if count == 0 { @@ -169,7 +174,15 @@ fn count_to_letter_code(mut count: usize) -> String { } } - letters.into_iter().chain("_".chars()).rev().collect() + letters.push(b'_'); + + debug_assert_eq!(length, letters.len()); + + letters.reverse(); + + // Safety: we only push ascii chars A-Z and _ + // an ascii only byte sequence is always valid utf-8 + unsafe { String::from_utf8_unchecked(letters) } } impl Term { @@ -623,3 +636,11 @@ impl Machine { } } } + +#[test] +fn test_count_to_letter_code() { + for idx in 0..1000 { + // ensure the debug assert doesn't trigger + count_to_letter_code(idx); + } +} -- 2.54.0