Skip to content

Commit 6f31cf7

Browse files
Merge pull request RustPython#913 from Jongy/str-preallocate-and-rmul
Preallocate strings in a smarter way + add str.rmul
2 parents 382e566 + 857a701 commit 6f31cf7

File tree

3 files changed

+30
-10
lines changed

3 files changed

+30
-10
lines changed

tests/snippets/membership.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,8 @@
1212
assert "whatever" not in "foobar"
1313

1414
# test bytes
15-
# TODO: uncomment this when bytes are implemented
16-
# assert b"foo" in b"foobar"
17-
# assert b"whatever" not in b"foobar"
15+
assert b"foo" in b"foobar"
16+
assert b"whatever" not in b"foobar"
1817
assert b"1" < b"2"
1918
assert b"1" <= b"2"
2019
assert b"5" <= b"5"
@@ -32,18 +31,20 @@
3231
assert 3 not in set([1, 2])
3332

3433
# test dicts
35-
# TODO: test dicts when keys other than strings will be allowed
3634
assert "a" in {"a": 0, "b": 0}
3735
assert "c" not in {"a": 0, "b": 0}
36+
assert 1 in {1: 5, 7: 12}
37+
assert 5 not in {9: 10, 50: 100}
38+
assert True in {True: 5}
39+
assert False not in {True: 5}
3840

3941
# test iter
4042
assert 3 in iter([1, 2, 3])
4143
assert 3 not in iter([1, 2])
4244

4345
# test sequence
44-
# TODO: uncomment this when ranges are usable
45-
# assert 1 in range(0, 2)
46-
# assert 3 not in range(0, 2)
46+
assert 1 in range(0, 2)
47+
assert 3 not in range(0, 2)
4748

4849
# test __contains__ in user objects
4950
class MyNotContainingClass():

tests/snippets/strings.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,14 @@
2929

3030
assert str(["a", "b", "can't"]) == "['a', 'b', \"can't\"]"
3131

32+
assert "xy" * 3 == "xyxyxy"
33+
assert "x" * 0 == ""
34+
assert "x" * -1 == ""
35+
36+
assert 3 * "xy" == "xyxyxy"
37+
assert 0 * "x" == ""
38+
assert -1 * "x" == ""
39+
3240
a = 'Hallo'
3341
assert a.lower() == 'hallo'
3442
assert a.upper() == 'HALLO'
@@ -94,6 +102,7 @@
94102
]
95103

96104

105+
# requires CPython 3.7, and the CI currently runs with 3.6
97106
# assert c.isascii()
98107
assert c.index('a') == 1
99108
assert c.rindex('l') == 3

vm/src/obj/objstr.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,12 @@ impl PyString {
183183
if objtype::isinstance(&val, &vm.ctx.int_type()) {
184184
let value = &self.value;
185185
let multiplier = objint::get_value(&val).to_i32().unwrap();
186-
let mut result = String::new();
186+
let capacity = if multiplier > 0 {
187+
multiplier.to_usize().unwrap() * value.len()
188+
} else {
189+
0
190+
};
191+
let mut result = String::with_capacity(capacity);
187192
for _x in 0..multiplier {
188193
result.push_str(value.as_str());
189194
}
@@ -193,6 +198,11 @@ impl PyString {
193198
}
194199
}
195200

201+
#[pymethod(name = "__rmul__")]
202+
fn rmul(&self, val: PyObjectRef, vm: &VirtualMachine) -> PyResult<String> {
203+
self.mul(val, vm)
204+
}
205+
196206
#[pymethod(name = "__str__")]
197207
fn str(zelf: PyRef<Self>, _vm: &VirtualMachine) -> PyStringRef {
198208
zelf
@@ -206,7 +216,7 @@ impl PyString {
206216
} else {
207217
'\''
208218
};
209-
let mut formatted = String::new();
219+
let mut formatted = String::with_capacity(value.len());
210220
formatted.push(quote_char);
211221
for c in value.chars() {
212222
if c == quote_char || c == '\\' {
@@ -799,7 +809,7 @@ impl PyString {
799809
#[pymethod]
800810
fn expandtabs(&self, tab_stop: OptionalArg<usize>, _vm: &VirtualMachine) -> String {
801811
let tab_stop = tab_stop.into_option().unwrap_or(8 as usize);
802-
let mut expanded_str = String::new();
812+
let mut expanded_str = String::with_capacity(self.value.len());
803813
let mut tab_size = tab_stop;
804814
let mut col_count = 0 as usize;
805815
for ch in self.value.chars() {

0 commit comments

Comments
 (0)