Skip to content

Commit d991d19

Browse files
[mypyc] Add bytes and bytearray initialization ops (#10900)
Use `PyBytes_FromObject` for `bytes(o)`. Use `PyByteArray_FromObject` for `bytearray(o)`. Current approach doesn't support empty initialization. Related to mypyc/mypyc#880.
1 parent d7fabc9 commit d991d19

File tree

8 files changed

+123
-9
lines changed

8 files changed

+123
-9
lines changed

mypyc/common.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,10 @@
5555
'getargs.c',
5656
'getargsfast.c',
5757
'int_ops.c',
58+
'str_ops.c',
59+
'bytes_ops.c',
5860
'list_ops.c',
5961
'dict_ops.c',
60-
'str_ops.c',
6162
'set_ops.c',
6263
'tuple_ops.c',
6364
'exc_ops.c',

mypyc/lib-rt/CPy.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,6 +397,10 @@ bool CPyStr_IsTrue(PyObject *obj);
397397
Py_ssize_t CPyStr_Size_size_t(PyObject *str);
398398

399399

400+
// Bytes operations
401+
402+
403+
400404
// Set operations
401405

402406

mypyc/lib-rt/bytes_ops.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
// Bytes primitive operations
2+
//
3+
// These are registered in mypyc.primitives.bytes_ops.
4+
5+
#include <Python.h>
6+
#include "CPy.h"

mypyc/primitives/bytes_ops.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,31 @@
11
"""Primitive bytes ops."""
22

3-
from mypyc.ir.rtypes import object_rprimitive
4-
from mypyc.primitives.registry import load_address_op
3+
from mypyc.ir.ops import ERR_MAGIC
4+
from mypyc.ir.rtypes import (
5+
object_rprimitive, bytes_rprimitive, list_rprimitive, dict_rprimitive,
6+
str_rprimitive, RUnion
7+
)
8+
from mypyc.primitives.registry import load_address_op, function_op
59

610

711
# Get the 'bytes' type object.
812
load_address_op(
913
name='builtins.bytes',
1014
type=object_rprimitive,
1115
src='PyBytes_Type')
16+
17+
# bytes(obj)
18+
function_op(
19+
name='builtins.bytes',
20+
arg_types=[RUnion([list_rprimitive, dict_rprimitive, str_rprimitive])],
21+
return_type=bytes_rprimitive,
22+
c_function_name='PyBytes_FromObject',
23+
error_kind=ERR_MAGIC)
24+
25+
# bytearray(obj)
26+
function_op(
27+
name='builtins.bytearray',
28+
arg_types=[object_rprimitive],
29+
return_type=bytes_rprimitive,
30+
c_function_name='PyByteArray_FromObject',
31+
error_kind=ERR_MAGIC)

mypyc/primitives/int_ops.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
type=object_rprimitive,
2929
src='PyLong_Type')
3030

31-
# Convert from a float to int. We could do a bit better directly.
31+
# int(float). We could do a bit better directly.
3232
function_op(
3333
name='builtins.int',
3434
arg_types=[float_rprimitive],
@@ -52,7 +52,7 @@
5252
c_function_name='CPyLong_FromStrWithBase',
5353
error_kind=ERR_MAGIC)
5454

55-
# str(n) on ints
55+
# str(int)
5656
int_to_str_op = function_op(
5757
name='builtins.str',
5858
arg_types=[int_rprimitive],

mypyc/test-data/irbuild-bytes.test

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
[case testBytesBasics]
2+
def f(num: int, l: list, d: dict, s: str) -> None:
3+
b1 = bytes()
4+
b2 = bytes(num)
5+
b3 = bytes(l)
6+
b4 = bytes(d)
7+
b5 = bytes(s)
8+
[out]
9+
def f(num, l, d, s):
10+
num :: int
11+
l :: list
12+
d :: dict
13+
s :: str
14+
r0, r1 :: object
15+
r2, b1 :: bytes
16+
r3, r4, r5 :: object
17+
r6, b2, r7, b3, r8, b4, r9, b5 :: bytes
18+
L0:
19+
r0 = load_address PyBytes_Type
20+
r1 = PyObject_CallFunctionObjArgs(r0, 0)
21+
r2 = cast(bytes, r1)
22+
b1 = r2
23+
r3 = load_address PyBytes_Type
24+
r4 = box(int, num)
25+
r5 = PyObject_CallFunctionObjArgs(r3, r4, 0)
26+
r6 = cast(bytes, r5)
27+
b2 = r6
28+
r7 = PyBytes_FromObject(l)
29+
b3 = r7
30+
r8 = PyBytes_FromObject(d)
31+
b4 = r8
32+
r9 = PyBytes_FromObject(s)
33+
b5 = r9
34+
return 1
35+
36+
[case testBytearrayBasics]
37+
def f(s: str, num: int) -> None:
38+
a = bytearray()
39+
b = bytearray(s)
40+
c = bytearray(num)
41+
[out]
42+
def f(s, num):
43+
s :: str
44+
num :: int
45+
r0 :: object
46+
r1 :: str
47+
r2, r3, a :: object
48+
r4 :: bytes
49+
b, r5 :: object
50+
r6 :: bytes
51+
c :: object
52+
L0:
53+
r0 = builtins :: module
54+
r1 = 'bytearray'
55+
r2 = CPyObject_GetAttr(r0, r1)
56+
r3 = PyObject_CallFunctionObjArgs(r2, 0)
57+
a = r3
58+
r4 = PyByteArray_FromObject(s)
59+
b = r4
60+
r5 = box(int, num)
61+
r6 = PyByteArray_FromObject(r5)
62+
c = r6
63+
return 1
64+

mypyc/test-data/run-bytes.test

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,24 @@ try:
2424
except TypeError:
2525
pass
2626

27+
[case testBytesInit]
28+
def test_bytes_init() -> None:
29+
b1 = bytes([5])
30+
assert b1 == b'\x05'
31+
b2 = bytes([5, 10, 12])
32+
assert b2 == b'\x05\n\x0c'
33+
b3 = bytes(bytearray(b'foo'))
34+
assert b3 == b'foo'
35+
b4 = bytes(b'aaa')
36+
assert b4 == b'aaa'
37+
b5 = bytes(5)
38+
assert b5 == b'\x00\x00\x00\x00\x00'
39+
try:
40+
bytes('x')
41+
assert False
42+
except TypeError:
43+
pass
44+
2745
[case testBytesOps]
2846
def test_indexing() -> None:
2947
# Use bytes() to avoid constant folding

mypyc/test/test_irbuild.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,21 @@
1616

1717
files = [
1818
'irbuild-basic.test',
19+
'irbuild-int.test',
1920
'irbuild-lists.test',
21+
'irbuild-tuple.test',
2022
'irbuild-dict.test',
23+
'irbuild-set.test',
24+
'irbuild-str.test',
25+
'irbuild-bytes.test',
2126
'irbuild-statements.test',
2227
'irbuild-nested.test',
2328
'irbuild-classes.test',
2429
'irbuild-optional.test',
25-
'irbuild-tuple.test',
2630
'irbuild-any.test',
2731
'irbuild-generics.test',
2832
'irbuild-try.test',
29-
'irbuild-set.test',
30-
'irbuild-str.test',
3133
'irbuild-strip-asserts.test',
32-
'irbuild-int.test',
3334
'irbuild-vectorcall.test',
3435
'irbuild-unreachable.test',
3536
'irbuild-isinstance.test',

0 commit comments

Comments
 (0)