forked from Rust-related/RustPython
Merge pull request #3703 from killme2008/feat/issue-3702
PyStr::mul optimization for i=0 or str=''
This commit is contained in:
2
Lib/test/string_tests.py
vendored
2
Lib/test/string_tests.py
vendored
@@ -1188,6 +1188,8 @@ class MixinStrUnicodeUserStringTest:
|
||||
slice(start, stop, step))
|
||||
|
||||
def test_mul(self):
|
||||
self.assertTrue("('' * 3) is ''");
|
||||
self.assertTrue("('a' * 0) is ''");
|
||||
self.checkequal('', 'abc', '__mul__', -1)
|
||||
self.checkequal('', 'abc', '__mul__', 0)
|
||||
self.checkequal('abc', 'abc', '__mul__', 1)
|
||||
|
||||
@@ -509,8 +509,13 @@ impl PyStr {
|
||||
#[pymethod(name = "__rmul__")]
|
||||
#[pymethod(magic)]
|
||||
fn mul(zelf: PyRef<Self>, value: isize, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
|
||||
if value == 1 && zelf.class().is(&vm.ctx.types.str_type) {
|
||||
// Special case: when some `str` is multiplied by `1`,
|
||||
if value == 0 && zelf.class().is(&vm.ctx.types.str_type) {
|
||||
// Special case: when some `str` is multiplied by `0`,
|
||||
// returns the empty `str`.
|
||||
return Ok(vm.ctx.empty_str.clone());
|
||||
}
|
||||
if (value == 1 || zelf.is_empty()) && zelf.class().is(&vm.ctx.types.str_type) {
|
||||
// Special case: when some `str` is multiplied by `1` or is the empty `str`,
|
||||
// nothing really happens, we need to return an object itself
|
||||
// with the same `id()` to be compatible with CPython.
|
||||
// This only works for `str` itself, not its subclasses.
|
||||
|
||||
@@ -507,7 +507,7 @@ impl PyBaseException {
|
||||
pub(super) fn str(&self, vm: &VirtualMachine) -> PyStrRef {
|
||||
let str_args = vm.exception_args_as_string(self.args(), true);
|
||||
match str_args.into_iter().exactly_one() {
|
||||
Err(i) if i.len() == 0 => PyStr::from("").into_ref(vm),
|
||||
Err(i) if i.len() == 0 => vm.ctx.empty_str.clone(),
|
||||
Ok(s) => s,
|
||||
Err(i) => PyStr::from(format!("({})", i.format(", "))).into_ref(vm),
|
||||
}
|
||||
|
||||
@@ -1125,7 +1125,7 @@ impl ExecutingFrame<'_> {
|
||||
|
||||
#[cfg_attr(feature = "flame-it", flame("Frame"))]
|
||||
fn import(&mut self, vm: &VirtualMachine, module: Option<PyStrRef>) -> FrameResult {
|
||||
let module = module.unwrap_or_else(|| PyStr::from("").into_ref(vm));
|
||||
let module = module.unwrap_or_else(|| vm.ctx.empty_str.clone());
|
||||
let from_list = <Option<PyTupleTyped<PyStrRef>>>::try_from_object(vm, self.pop_value())?;
|
||||
let level = usize::try_from_object(vm, self.pop_value())?;
|
||||
|
||||
|
||||
@@ -305,7 +305,7 @@ mod builtins {
|
||||
) -> PyResult<PyStrRef> {
|
||||
let format_spec = format_spec
|
||||
.into_option()
|
||||
.unwrap_or_else(|| PyStr::from("").into_ref(vm));
|
||||
.unwrap_or_else(|| vm.ctx.empty_str.clone());
|
||||
|
||||
call_object_format(vm, value, None, format_spec.as_str())
|
||||
}
|
||||
|
||||
@@ -2588,7 +2588,7 @@ mod _io {
|
||||
}
|
||||
}
|
||||
if chunks.is_empty() {
|
||||
PyStr::from("").into_ref(vm)
|
||||
vm.ctx.empty_str.clone()
|
||||
} else if chunks.len() == 1 {
|
||||
chunks.pop().unwrap()
|
||||
} else {
|
||||
@@ -2850,7 +2850,7 @@ mod _io {
|
||||
} else if let Some(cur_line) = cur_line {
|
||||
cur_line.slice_pystr(vm)
|
||||
} else {
|
||||
PyStr::from("").into_ref(vm)
|
||||
vm.ctx.empty_str.clone()
|
||||
};
|
||||
Ok(line)
|
||||
}
|
||||
@@ -3009,7 +3009,7 @@ mod _io {
|
||||
append: Option<PyStrRef>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyStrRef {
|
||||
let empty_str = || PyStr::from("").into_ref(vm);
|
||||
let empty_str = || vm.ctx.empty_str.clone();
|
||||
let chars_pos = std::mem::take(&mut self.decoded_chars_used).bytes;
|
||||
let decoded_chars = match std::mem::take(&mut self.decoded_chars) {
|
||||
None => return append.unwrap_or_else(empty_str),
|
||||
|
||||
@@ -25,6 +25,7 @@ pub struct Context {
|
||||
pub none: PyRef<PyNone>,
|
||||
pub empty_tuple: PyTupleRef,
|
||||
pub empty_frozenset: PyRef<PyFrozenSet>,
|
||||
pub empty_str: PyRef<PyStr>,
|
||||
pub ellipsis: PyRef<PyEllipsis>,
|
||||
pub not_implemented: PyRef<PyNotImplemented>,
|
||||
|
||||
@@ -83,6 +84,7 @@ impl Context {
|
||||
|
||||
let true_str = unsafe { string_pool.intern("True", types.str_type.clone()) }.into_pyref();
|
||||
let false_str = unsafe { string_pool.intern("False", types.str_type.clone()) }.into_pyref();
|
||||
let empty_str = unsafe { string_pool.intern("", types.str_type.clone()) }.into_pyref();
|
||||
|
||||
let context = Context {
|
||||
true_value,
|
||||
@@ -90,6 +92,8 @@ impl Context {
|
||||
none,
|
||||
empty_tuple,
|
||||
empty_frozenset,
|
||||
empty_str,
|
||||
|
||||
ellipsis,
|
||||
not_implemented,
|
||||
|
||||
|
||||
Reference in New Issue
Block a user