Skip to content

Commit baea65a

Browse files
[mypyc] Faster len(bytes) (#10936)
Similar to list and tuple, we can directly get length of bytes from PyVarObject->ob_size. Implements part of mypyc/mypyc#880.
1 parent 97a1b3f commit baea65a

File tree

3 files changed

+24
-5
lines changed

3 files changed

+24
-5
lines changed

mypyc/irbuild/ll_builder.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@
3333
is_list_rprimitive, is_tuple_rprimitive, is_dict_rprimitive, is_set_rprimitive, PySetObject,
3434
none_rprimitive, RTuple, is_bool_rprimitive, is_str_rprimitive, c_int_rprimitive,
3535
pointer_rprimitive, PyObject, PyListObject, bit_rprimitive, is_bit_rprimitive,
36-
object_pointer_rprimitive, c_size_t_rprimitive, dict_rprimitive, bytes_rprimitive
36+
object_pointer_rprimitive, c_size_t_rprimitive, dict_rprimitive, bytes_rprimitive,
37+
is_bytes_rprimitive
3738
)
3839
from mypyc.ir.func_ir import FuncDecl, FuncSignature
3940
from mypyc.ir.class_ir import ClassIR, all_concrete_classes
@@ -1348,7 +1349,8 @@ def builtin_len(self, val: Value, line: int, use_pyssize_t: bool = False) -> Val
13481349
"""
13491350
typ = val.type
13501351
size_value = None
1351-
if is_list_rprimitive(typ) or is_tuple_rprimitive(typ):
1352+
if (is_list_rprimitive(typ) or is_tuple_rprimitive(typ)
1353+
or is_bytes_rprimitive(typ)):
13521354
elem_address = self.add(GetElementPtr(val, PyVarObject, 'ob_size'))
13531355
size_value = self.add(LoadMem(c_pyssize_t_rprimitive, elem_address))
13541356
self.add(KeepAlive([val]))

mypyc/test-data/irbuild-bytes.test

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,8 @@ L0:
6262
c = r6
6363
return 1
6464

65-
6665
[case testBytesJoin]
6766
from typing import List
68-
6967
def f(b: List[bytes]) -> bytes:
7068
return b" ".join(b)
7169
[out]
@@ -76,3 +74,20 @@ L0:
7674
r0 = b' '
7775
r1 = CPyBytes_Join(r0, b)
7876
return r1
77+
78+
[case testBytesLen]
79+
def f(b: bytes) -> int:
80+
return len(b)
81+
[out]
82+
def f(b):
83+
b :: bytes
84+
r0 :: ptr
85+
r1 :: native_int
86+
r2 :: short_int
87+
L0:
88+
r0 = get_element_ptr b ob_size :: PyVarObject
89+
r1 = load_mem r0 :: native_int*
90+
keep_alive b
91+
r2 = r1 << 1
92+
return r2
93+

mypyc/test-data/run-bytes.test

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ def test_len() -> None:
7575
[case testBytearrayBasics]
7676
from typing import Any
7777

78-
def test_init() -> None:
78+
def test_basics() -> None:
7979
brr1: bytes = bytearray(3)
8080
assert brr1 == bytearray(b'\x00\x00\x00')
8181
assert brr1 == b'\x00\x00\x00'
@@ -89,6 +89,8 @@ def test_init() -> None:
8989
brr4: bytes = bytearray('string', 'utf-8')
9090
assert brr4 == bytearray(b'string')
9191
assert brr4 == b'string'
92+
assert len(brr1) == 3
93+
assert len(brr2) == 4
9294

9395
def f(b: bytes) -> bool:
9496
return True

0 commit comments

Comments
 (0)