handle Py2 compatibility case bytearray.append(pychar)
authorStefan Behnel <stefan_ml@behnel.de>
Fri, 27 Dec 2013 16:12:09 +0000 (17:12 +0100)
committerStefan Behnel <stefan_ml@behnel.de>
Fri, 27 Dec 2013 16:12:09 +0000 (17:12 +0100)
--HG--
extra : amend_source : f3b7f004f905c791e6ced2a5b27fffa21f9ceb08

Cython/Compiler/Builtin.py
Cython/Compiler/Optimize.py
Cython/Utility/StringTools.c
tests/run/bytearraymethods.pyx

index 68a8f10..ecac9da 100644 (file)
@@ -281,8 +281,6 @@ builtin_types_table = [
                                                   utility_code=UtilityCode.load("StringJoin", "StringTools.c")),
                                     ]),
     ("bytearray", "PyByteArray_Type", [
-                                    BuiltinMethod("append",  "Tz",   "r", "__Pyx_PyByteArray_Append",
-                                                  utility_code=UtilityCode.load("ByteArrayAppend", "StringTools.c")),
                                     ]),
     ("bytes",   "PyBytes_Type",    [BuiltinMethod("__contains__",  "TO",   "b", "PySequence_Contains"),
                                     BuiltinMethod("join",  "TO",   "O", "__Pyx_PyBytes_Join",
index c66ba20..ea2002c 100644 (file)
@@ -2379,6 +2379,53 @@ class OptimizeBuiltinCalls(Visitor.MethodDispatcherTransform):
             utility_code=load_c_utility('append')
         )
 
+    PyByteArray_Append_func_type = PyrexTypes.CFuncType(
+        PyrexTypes.c_returncode_type, [
+            PyrexTypes.CFuncTypeArg("bytearray", PyrexTypes.py_object_type, None),
+            PyrexTypes.CFuncTypeArg("value", PyrexTypes.c_int_type, None),
+            ],
+        exception_value="-1")
+
+    PyByteArray_AppendObject_func_type = PyrexTypes.CFuncType(
+        PyrexTypes.c_returncode_type, [
+            PyrexTypes.CFuncTypeArg("bytearray", PyrexTypes.py_object_type, None),
+            PyrexTypes.CFuncTypeArg("value", PyrexTypes.py_object_type, None),
+            ],
+        exception_value="-1")
+
+    def _handle_simple_method_bytearray_append(self, node, function, args, is_unbound_method):
+        if len(args) != 2:
+            return node
+        func_name = "__Pyx_PyByteArray_Append"
+        func_type = self.PyByteArray_Append_func_type
+
+        value = unwrap_coerced_node(args[1])
+        if value.type.is_int:
+            value = value.coerce_to(PyrexTypes.c_int_type, self.current_env())
+            utility_code = UtilityCode.load_cached("ByteArrayAppend", "StringTools.c")
+        elif value.is_string_literal:
+            if not value.can_coerce_to_char_literal():
+                return node
+            value = value.coerce_to(PyrexTypes.c_char_type, self.current_env())
+            utility_code = UtilityCode.load_cached("ByteArrayAppend", "StringTools.c")
+        elif value.type.is_pyobject:
+            func_name = "__Pyx_PyByteArray_AppendObject"
+            func_type = self.PyByteArray_AppendObject_func_type
+            utility_code = UtilityCode.load_cached("ByteArrayAppendObject", "StringTools.c")
+        else:
+            return node
+
+        new_node = ExprNodes.PythonCapiCallNode(
+            node.pos, func_name, func_type,
+            args=[args[0], value],
+            may_return_none=False,
+            is_temp=node.is_temp,
+            utility_code=utility_code,
+        )
+        if node.result_is_used:
+            new_node = new_node.coerce_to(node.type, self.current_env())
+        return new_node
+
     PyObject_Pop_func_type = PyrexTypes.CFuncType(
         PyrexTypes.py_object_type, [
             PyrexTypes.CFuncTypeArg("list", PyrexTypes.py_object_type, None),
index da71ef6..c8ea40c 100644 (file)
@@ -680,25 +680,54 @@ static CYTHON_INLINE PyObject* __Pyx_PyBytes_Join(PyObject* sep, PyObject* value
 #endif
 
 
+//////////////////// ByteArrayAppendObject.proto ////////////////////
+
+static CYTHON_INLINE int __Pyx_PyByteArray_AppendObject(PyObject* bytearray, PyObject* value);
+
+//////////////////// ByteArrayAppendObject ////////////////////
+//@requires: ByteArrayAppend
+
+static CYTHON_INLINE int __Pyx_PyByteArray_AppendObject(PyObject* bytearray, PyObject* value) {
+    Py_ssize_t ival;
+#if PY_MAJOR_VERSION < 3
+    if (unlikely(PyString_Check(value))) {
+        if (unlikely(PyString_GET_SIZE(value) != 1)) {
+            PyErr_SetString(PyExc_ValueError, "string must be of size 1");
+            return -1;
+        }
+        ival = PyString_AS_STRING(value)[0];
+    } else
+#endif
+    {
+        ival = __Pyx_PyIndex_AsSsize_t(value);
+        if (unlikely(ival == -1 && PyErr_Occurred()))
+            return -1;
+    }
+    return __Pyx_PyByteArray_Append(bytearray, ival);
+}
+
 //////////////////// ByteArrayAppend.proto ////////////////////
 
-static CYTHON_INLINE int __Pyx_PyByteArray_Append(PyObject* bytearray, Py_ssize_t value);
+static CYTHON_INLINE int __Pyx_PyByteArray_Append(PyObject* bytearray, int value);
 
 //////////////////// ByteArrayAppend ////////////////////
 //@requires: ObjectHandling.c::PyObjectCallMethod
 
 // signature uses Py_ssize_t to make coercions use PyNumber_Index(), as CPython does
-static CYTHON_INLINE int __Pyx_PyByteArray_Append(PyObject* bytearray, Py_ssize_t value) {
+static CYTHON_INLINE int __Pyx_PyByteArray_Append(PyObject* bytearray, int value) {
     PyObject *pyval, *retval;
 #if CYTHON_COMPILING_IN_CPYTHON
-    Py_ssize_t n = Py_SIZE(bytearray);
     if (likely((value >= 0) & (value <= 255))) {
-        if (likely(n < PY_SSIZE_T_MAX)) {
+        Py_ssize_t n = Py_SIZE(bytearray);
+        if (likely(n != PY_SSIZE_T_MAX)) {
             if (unlikely(PyByteArray_Resize(bytearray, n + 1) < 0))
                 return -1;
             PyByteArray_AS_STRING(bytearray)[n] = value;
             return 0;
         }
+    } else {
+        PyErr_SetString(PyExc_ValueError, "byte must be in range(0, 256)");
+        return -1;
     }
 #endif
     pyval = PyInt_FromLong(value);
index 6816972..16c9d5f 100644 (file)
@@ -1,3 +1,7 @@
+
+import sys
+IS_PY3 = sys.version_info[0] >= 3
+
 cimport cython
 
 b_a = bytearray(b'a')
@@ -197,47 +201,52 @@ def bytearray_decode_unbound_method(bytearray s, start=None, stop=None):
 
 def bytearray_append(bytearray b, char c, int i, object o):
     """
-    >>> b = bytearray('abc'.encode('ascii'))
+    >>> b = bytearray(b'abc')
     >>> b = bytearray_append(b, ord('x'), ord('y'), ord('z'))
     >>> print(b.decode('ascii'))
     abcXxyz
 
-    >>> b = bytearray('abc'.encode('ascii'))
+    >>> b = bytearray(b'abc')
+    >>> b = bytearray_append(b, ord('x'), ord('y'), ord('z') if IS_PY3 else b'z')
+    >>> print(b.decode('ascii'))
+    abcXxyz
+
+    >>> b = bytearray(b'abc')
     >>> b = bytearray_append(b, -1, ord('y'), ord('z'))  # doctest: +ELLIPSIS
     Traceback (most recent call last):
     ValueError: ...
     >>> print(b.decode('ascii'))
     abcX
 
-    >>> b = bytearray('abc'.encode('ascii'))
+    >>> b = bytearray(b'abc')
     >>> b = bytearray_append(b, ord('x'), -1, ord('z'))  # doctest: +ELLIPSIS
     Traceback (most recent call last):
     ValueError: ...
     >>> print(b.decode('ascii'))
     abcXx
 
-    >>> b = bytearray('abc'.encode('ascii'))
+    >>> b = bytearray(b'abc')
     >>> b = bytearray_append(b, ord('x'), 256, ord('z'))  # doctest: +ELLIPSIS
     Traceback (most recent call last):
     ValueError: ...
     >>> print(b.decode('ascii'))
     abcXx
 
-    >>> b = bytearray('abc'.encode('ascii'))
+    >>> b = bytearray(b'abc')
     >>> b = bytearray_append(b, ord('x'), ord('y'), -1)  # doctest: +ELLIPSIS
     Traceback (most recent call last):
     ValueError: ...
     >>> print(b.decode('ascii'))
     abcXxy
 
-    >>> b = bytearray('abc'.encode('ascii'))
+    >>> b = bytearray(b'abc')
     >>> b = bytearray_append(b, ord('x'), ord('y'), 256)  # doctest: +ELLIPSIS
     Traceback (most recent call last):
     ValueError: ...
     >>> print(b.decode('ascii'))
     abcXxy
     """
-    b.append('X')
+    assert b.append('X') is None
     b.append(c)
     b.append(i)
     b.append(o)