]> Repositorios git - scryer-prolog.git/commitdiff
improve count_to_letter_code
authorSkgland <[email protected]>
Tue, 18 Nov 2025 20:42:10 +0000 (21:42 +0100)
committerBennet Bleßmann <[email protected]>
Wed, 19 Nov 2025 18:23:41 +0000 (19:23 +0100)
- 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

index 653fc2a4dc6927afb9dd3dab6f03f5c6594e907d..7527c05c2857baaa61464645d4428ceb44c81a57 100644 (file)
@@ -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);
+    }
+}