Skip to content

Add str(int) and repr(int) fast path using i64 conversion#7302

Merged
youknowone merged 2 commits intoRustPython:mainfrom
youknowone:str-int-fast
Mar 2, 2026
Merged

Add str(int) and repr(int) fast path using i64 conversion#7302
youknowone merged 2 commits intoRustPython:mainfrom
youknowone:str-int-fast

Conversation

@youknowone
Copy link
Copy Markdown
Member

@youknowone youknowone commented Mar 1, 2026

  • Skip str method resolution for exact PyInt in PyObject::str()
  • Use i64::to_string() for small integers, BigInt::to_string() for large ones
  • ~36% improvement in str(int) benchmarks

Summary by CodeRabbit

  • Performance
    • Faster decimal conversion and string representation for integers, improving speed for both small and large values.
  • Refactor
    • Optimized the integer-to-string path so direct integer stringification is used when applicable, while preserving existing behavior for other objects.

- Skip __str__ method resolution for exact PyInt in PyObject::str()
- Use i64::to_string() for small integers, BigInt::to_string() for large ones
- ~36% improvement in str(int) benchmarks
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 1, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 872a6e0 and 22f6763.

📒 Files selected for processing (2)
  • crates/vm/src/builtins/int.rs
  • crates/vm/src/protocol/object.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/vm/src/builtins/int.rs

📝 Walkthrough

Walkthrough

Introduces a fast-path for converting Python integers to decimal strings: exact small integers use an i64-based conversion, while large integers fall back to BigInt string conversion; also routes PyObject.str to use this fast-path for exact PyInt objects.

Changes

Cohort / File(s) Summary
Integer implementation
crates/vm/src/builtins/int.rs
Adds pub fn to_str_radix_10(&self) -> String and updates Representable for PyInt::repr_str to return zelf.to_str_radix_10() instead of value.to_string().
Protocol / str fast-path
crates/vm/src/protocol/object.rs
Adds a fast-path in PyObject::str to directly return int.to_str_radix_10() when the object is an exact PyInt, bypassing normal __str__ lookup; existing fallback logic remains unchanged.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Caller
participant PyObject_str as PyObject.str
participant PyInt_fast as PyInt::to_str_radix_10
participant BigInt_to_string as BigInt::to_string
Caller->>PyObject_str: request str(obj)
PyObject_str->>PyObject_str: is_exact_pyint?
alt exact PyInt
PyObject_str->>PyInt_fast: to_str_radix_10()
PyInt_fast-->>PyObject_str: decimal string (i64 path or BigInt fallback)
PyObject_str-->>Caller: return string
else not exact PyInt
PyObject_str->>PyObject_str: fallback to str resolution
PyObject_str-->>Caller: result of usual str flow
end

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Suggested reviewers

  • coolreader18

Poem

🐰 I nibble bits both large and small,
I hop the fast i64 hall,
If numbers stretch and grow too wide,
BigInt keeps truth by my side. 🥕✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main optimization: adding fast paths for str(int) and repr(int) using i64 conversion, which directly matches the core changes across the two modified files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@youknowone youknowone marked this pull request as ready for review March 2, 2026 01:06
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
crates/vm/src/protocol/object.rs (1)

379-389: Fast path implementation looks correct, but duplicates logic from int.rs.

The use of downcast_exact::<PyInt> correctly ensures this optimization only applies to exact int instances, preserving correct behavior for subclasses that may override __str__.

However, the conversion logic at lines 382-385 duplicates the implementation in int.rs repr_str. If the helper method suggested in int.rs is added, this can be simplified:

♻️ Proposed refactor using shared helper
         // Fast path for exact int: skip __str__ method resolution
         let obj = match obj.downcast_exact::<PyInt>(vm) {
             Ok(int) => {
-                let s = match int.as_bigint().to_i64() {
-                    Some(i) => i.to_string(),
-                    None => int.as_bigint().to_string(),
-                };
+                let s = int.to_str_radix_10();
                 return Ok(vm.ctx.new_str(s));
             }
             Err(obj) => obj,
         };

This also removes the need for the ToPrimitive import in this file if no other code uses it.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/vm/src/protocol/object.rs` around lines 379 - 389, Fast path
duplicates int -> string conversion logic; replace the manual bigint-to-string
code inside the downcast_exact::<PyInt> match with the shared helper introduced
in int.rs (call the helper function exposed for int stringification, e.g.,
repr_str or the new PyInt helper) so the branch becomes: downcast_exact::<PyInt>
=> { let s = <use the int.rs helper>(int); return Ok(vm.ctx.new_str(s)); }, and
remove the now-unnecessary ToPrimitive import if no other code uses it; ensure
you reference downcast_exact::<PyInt>, as_bigint()/to_i64() usage sites when
locating the code to change.
crates/vm/src/builtins/int.rs (1)

605-610: Code duplication with object.rs.

This conversion logic (try to_i64() then fall back to BigInt::to_string()) is duplicated in crates/vm/src/protocol/object.rs lines 382-385. Per coding guidelines, when branches share common logic, consider extracting the differing value first, then calling the common logic once.

Consider adding a helper method to PyInt that both call sites can use:

♻️ Proposed refactor to eliminate duplication

Add a helper method in this file:

 impl PyInt {
+    /// Returns the string representation, using i64 fast path when possible.
+    #[inline]
+    pub fn to_str_radix_10(&self) -> String {
+        match self.value.to_i64() {
+            Some(i) => i.to_string(),
+            None => self.value.to_string(),
+        }
+    }
+
     pub const fn as_bigint(&self) -> &BigInt {
         &self.value
     }

Then simplify repr_str:

 impl Representable for PyInt {
     #[inline]
     fn repr_str(zelf: &Py<Self>, _vm: &VirtualMachine) -> PyResult<String> {
-        Ok(match zelf.value.to_i64() {
-            Some(i) => i.to_string(),
-            None => zelf.value.to_string(),
-        })
+        Ok(zelf.to_str_radix_10())
     }
 }

And update object.rs to use the same helper (see related comment there).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/vm/src/builtins/int.rs` around lines 605 - 610, The repr construction
logic is duplicated; add a helper on PyInt (e.g., a method like to_repr_string
or repr_fallback) that returns the String by trying self.to_i64() then falling
back to BigInt::to_string(), then change repr_str (fn repr_str(zelf: &Py<Self>,
_vm: &VirtualMachine) -> PyResult<String>) to call that helper on zelf.value (or
on PyInt) and update the duplicate site in object.rs to use the same helper so
the common logic lives in one place.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@crates/vm/src/builtins/int.rs`:
- Around line 605-610: The repr construction logic is duplicated; add a helper
on PyInt (e.g., a method like to_repr_string or repr_fallback) that returns the
String by trying self.to_i64() then falling back to BigInt::to_string(), then
change repr_str (fn repr_str(zelf: &Py<Self>, _vm: &VirtualMachine) ->
PyResult<String>) to call that helper on zelf.value (or on PyInt) and update the
duplicate site in object.rs to use the same helper so the common logic lives in
one place.

In `@crates/vm/src/protocol/object.rs`:
- Around line 379-389: Fast path duplicates int -> string conversion logic;
replace the manual bigint-to-string code inside the downcast_exact::<PyInt>
match with the shared helper introduced in int.rs (call the helper function
exposed for int stringification, e.g., repr_str or the new PyInt helper) so the
branch becomes: downcast_exact::<PyInt> => { let s = <use the int.rs
helper>(int); return Ok(vm.ctx.new_str(s)); }, and remove the now-unnecessary
ToPrimitive import if no other code uses it; ensure you reference
downcast_exact::<PyInt>, as_bigint()/to_i64() usage sites when locating the code
to change.

ℹ️ Review info

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a6b3a5b and 872a6e0.

📒 Files selected for processing (2)
  • crates/vm/src/builtins/int.rs
  • crates/vm/src/protocol/object.rs

@youknowone youknowone merged commit 888e0ee into RustPython:main Mar 2, 2026
11 of 13 checks passed
@youknowone youknowone deleted the str-int-fast branch March 2, 2026 02:02
youknowone added a commit to youknowone/RustPython that referenced this pull request Mar 22, 2026
…#7302)

* Add str(int) and repr(int) fast path using i64 conversion

- Skip __str__ method resolution for exact PyInt in PyObject::str()
- Use i64::to_string() for small integers, BigInt::to_string() for large ones
- ~36% improvement in str(int) benchmarks

* Extract PyInt::to_str_radix_10() to deduplicate i64 fast path logic
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant