Skip to content

Commit

Permalink
[mypyc] Add bytes and bytearray initialization ops (#10900)
Browse files Browse the repository at this point in the history
Use `PyBytes_FromObject` for `bytes(o)`.
Use `PyByteArray_FromObject` for `bytearray(o)`.

Current approach doesn't support empty initialization.

Related to mypyc/mypyc#880.
  • Loading branch information
97littleleaf11 authored Aug 4, 2021
1 parent d7fabc9 commit d991d19
Show file tree
Hide file tree
Showing 8 changed files with 123 additions and 9 deletions.
3 changes: 2 additions & 1 deletion mypyc/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,10 @@
'getargs.c',
'getargsfast.c',
'int_ops.c',
'str_ops.c',
'bytes_ops.c',
'list_ops.c',
'dict_ops.c',
'str_ops.c',
'set_ops.c',
'tuple_ops.c',
'exc_ops.c',
Expand Down
4 changes: 4 additions & 0 deletions mypyc/lib-rt/CPy.h
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,10 @@ bool CPyStr_IsTrue(PyObject *obj);
Py_ssize_t CPyStr_Size_size_t(PyObject *str);


// Bytes operations



// Set operations


Expand Down
6 changes: 6 additions & 0 deletions mypyc/lib-rt/bytes_ops.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// Bytes primitive operations
//
// These are registered in mypyc.primitives.bytes_ops.

#include <Python.h>
#include "CPy.h"
24 changes: 22 additions & 2 deletions mypyc/primitives/bytes_ops.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,31 @@
"""Primitive bytes ops."""

from mypyc.ir.rtypes import object_rprimitive
from mypyc.primitives.registry import load_address_op
from mypyc.ir.ops import ERR_MAGIC
from mypyc.ir.rtypes import (
object_rprimitive, bytes_rprimitive, list_rprimitive, dict_rprimitive,
str_rprimitive, RUnion
)
from mypyc.primitives.registry import load_address_op, function_op


# Get the 'bytes' type object.
load_address_op(
name='builtins.bytes',
type=object_rprimitive,
src='PyBytes_Type')

# bytes(obj)
function_op(
name='builtins.bytes',
arg_types=[RUnion([list_rprimitive, dict_rprimitive, str_rprimitive])],
return_type=bytes_rprimitive,
c_function_name='PyBytes_FromObject',
error_kind=ERR_MAGIC)

# bytearray(obj)
function_op(
name='builtins.bytearray',
arg_types=[object_rprimitive],
return_type=bytes_rprimitive,
c_function_name='PyByteArray_FromObject',
error_kind=ERR_MAGIC)
4 changes: 2 additions & 2 deletions mypyc/primitives/int_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
type=object_rprimitive,
src='PyLong_Type')

# Convert from a float to int. We could do a bit better directly.
# int(float). We could do a bit better directly.
function_op(
name='builtins.int',
arg_types=[float_rprimitive],
Expand All @@ -52,7 +52,7 @@
c_function_name='CPyLong_FromStrWithBase',
error_kind=ERR_MAGIC)

# str(n) on ints
# str(int)
int_to_str_op = function_op(
name='builtins.str',
arg_types=[int_rprimitive],
Expand Down
64 changes: 64 additions & 0 deletions mypyc/test-data/irbuild-bytes.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
[case testBytesBasics]
def f(num: int, l: list, d: dict, s: str) -> None:
b1 = bytes()
b2 = bytes(num)
b3 = bytes(l)
b4 = bytes(d)
b5 = bytes(s)
[out]
def f(num, l, d, s):
num :: int
l :: list
d :: dict
s :: str
r0, r1 :: object
r2, b1 :: bytes
r3, r4, r5 :: object
r6, b2, r7, b3, r8, b4, r9, b5 :: bytes
L0:
r0 = load_address PyBytes_Type
r1 = PyObject_CallFunctionObjArgs(r0, 0)
r2 = cast(bytes, r1)
b1 = r2
r3 = load_address PyBytes_Type
r4 = box(int, num)
r5 = PyObject_CallFunctionObjArgs(r3, r4, 0)
r6 = cast(bytes, r5)
b2 = r6
r7 = PyBytes_FromObject(l)
b3 = r7
r8 = PyBytes_FromObject(d)
b4 = r8
r9 = PyBytes_FromObject(s)
b5 = r9
return 1

[case testBytearrayBasics]
def f(s: str, num: int) -> None:
a = bytearray()
b = bytearray(s)
c = bytearray(num)
[out]
def f(s, num):
s :: str
num :: int
r0 :: object
r1 :: str
r2, r3, a :: object
r4 :: bytes
b, r5 :: object
r6 :: bytes
c :: object
L0:
r0 = builtins :: module
r1 = 'bytearray'
r2 = CPyObject_GetAttr(r0, r1)
r3 = PyObject_CallFunctionObjArgs(r2, 0)
a = r3
r4 = PyByteArray_FromObject(s)
b = r4
r5 = box(int, num)
r6 = PyByteArray_FromObject(r5)
c = r6
return 1

18 changes: 18 additions & 0 deletions mypyc/test-data/run-bytes.test
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,24 @@ try:
except TypeError:
pass

[case testBytesInit]
def test_bytes_init() -> None:
b1 = bytes([5])
assert b1 == b'\x05'
b2 = bytes([5, 10, 12])
assert b2 == b'\x05\n\x0c'
b3 = bytes(bytearray(b'foo'))
assert b3 == b'foo'
b4 = bytes(b'aaa')
assert b4 == b'aaa'
b5 = bytes(5)
assert b5 == b'\x00\x00\x00\x00\x00'
try:
bytes('x')
assert False
except TypeError:
pass

[case testBytesOps]
def test_indexing() -> None:
# Use bytes() to avoid constant folding
Expand Down
9 changes: 5 additions & 4 deletions mypyc/test/test_irbuild.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,21 @@

files = [
'irbuild-basic.test',
'irbuild-int.test',
'irbuild-lists.test',
'irbuild-tuple.test',
'irbuild-dict.test',
'irbuild-set.test',
'irbuild-str.test',
'irbuild-bytes.test',
'irbuild-statements.test',
'irbuild-nested.test',
'irbuild-classes.test',
'irbuild-optional.test',
'irbuild-tuple.test',
'irbuild-any.test',
'irbuild-generics.test',
'irbuild-try.test',
'irbuild-set.test',
'irbuild-str.test',
'irbuild-strip-asserts.test',
'irbuild-int.test',
'irbuild-vectorcall.test',
'irbuild-unreachable.test',
'irbuild-isinstance.test',
Expand Down

0 comments on commit d991d19

Please sign in to comment.