Skip to content

Commit eba6833

Browse files
committed
PyStr::mul optimization for i=0 or str=''
1 parent b5b0738 commit eba6833

File tree

3 files changed

+13
-2
lines changed

3 files changed

+13
-2
lines changed

Lib/test/string_tests.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1188,6 +1188,8 @@ def test_extended_getslice(self):
11881188
slice(start, stop, step))
11891189

11901190
def test_mul(self):
1191+
self.assertTrue("('' * 3) is ''");
1192+
self.assertTrue("('a' * 0) is ''");
11911193
self.checkequal('', 'abc', '__mul__', -1)
11921194
self.checkequal('', 'abc', '__mul__', 0)
11931195
self.checkequal('abc', 'abc', '__mul__', 1)

vm/src/builtins/str.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -509,8 +509,13 @@ impl PyStr {
509509
#[pymethod(name = "__rmul__")]
510510
#[pymethod(magic)]
511511
fn mul(zelf: PyRef<Self>, value: isize, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
512-
if value == 1 && zelf.class().is(&vm.ctx.types.str_type) {
513-
// Special case: when some `str` is multiplied by `1`,
512+
if value == 0 && zelf.class().is(&vm.ctx.types.str_type) {
513+
// Special case: when some `str` is multiplied by `0`,
514+
// returns the empty `str`.
515+
return Ok(vm.ctx.empty_str.clone());
516+
}
517+
if (value == 1 || zelf.is_empty()) && zelf.class().is(&vm.ctx.types.str_type) {
518+
// Special case: when some `str` is multiplied by `1` or is the empty `str`,
514519
// nothing really happens, we need to return an object itself
515520
// with the same `id()` to be compatible with CPython.
516521
// This only works for `str` itself, not its subclasses.

vm/src/vm/context.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ pub struct Context {
2525
pub none: PyRef<PyNone>,
2626
pub empty_tuple: PyTupleRef,
2727
pub empty_frozenset: PyRef<PyFrozenSet>,
28+
pub empty_str: PyRef<PyStr>,
2829
pub ellipsis: PyRef<PyEllipsis>,
2930
pub not_implemented: PyRef<PyNotImplemented>,
3031

@@ -83,13 +84,16 @@ impl Context {
8384

8485
let true_str = unsafe { string_pool.intern("True", types.str_type.clone()) }.into_pyref();
8586
let false_str = unsafe { string_pool.intern("False", types.str_type.clone()) }.into_pyref();
87+
let empty_str = unsafe { string_pool.intern("", types.str_type.clone()) }.into_pyref();
8688

8789
let context = Context {
8890
true_value,
8991
false_value,
9092
none,
9193
empty_tuple,
9294
empty_frozenset,
95+
empty_str,
96+
9397
ellipsis,
9498
not_implemented,
9599

0 commit comments

Comments
 (0)