support len(char*) efficiently by calling strlen() instead
authorStefan Behnel <scoder@users.berlios.de>
Thu, 26 Nov 2009 19:49:09 +0000 (20:49 +0100)
committerStefan Behnel <scoder@users.berlios.de>
Thu, 26 Nov 2009 19:49:09 +0000 (20:49 +0100)
Cython/Compiler/Optimize.py
tests/run/charptr_len.pyx [new file with mode: 0644]

index 3e5482af9789a2bb934ecc734df952f8a854bf30..51dbd767f3ff04abd165aed2990233f9aea2ee69 100644 (file)
@@ -1045,6 +1045,28 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
                 )
         return node
 
+    Pyx_strlen_func_type = PyrexTypes.CFuncType(
+        PyrexTypes.c_size_t_type, [
+            PyrexTypes.CFuncTypeArg("bytes", PyrexTypes.c_char_ptr_type, None)
+            ])
+
+    def _handle_simple_function_len(self, node, pos_args):
+        if len(pos_args) != 1:
+            self._error_wrong_arg_count('len', node, pos_args, 1)
+            return node
+        arg = pos_args[0]
+        if isinstance(arg, ExprNodes.CoerceToPyTypeNode):
+            arg = arg.arg
+        if not arg.type.is_string:
+            return node
+        node = ExprNodes.PythonCapiCallNode(
+            node.pos, "strlen", self.Pyx_strlen_func_type,
+                args = [arg],
+                is_temp = node.is_temp,
+                utility_code = include_string_h_utility_code,
+                )
+        return node
+
     ### special methods
 
     Pyx_tp_new_func_type = PyrexTypes.CFuncType(
@@ -1483,6 +1505,13 @@ static INLINE PyObject* __Pyx_Type(PyObject* o) {
 )
 
 
+include_string_h_utility_code = UtilityCode(
+proto = """
+#include <string.h>
+"""
+)
+
+
 tpnew_utility_code = UtilityCode(
 proto = """
 static INLINE PyObject* __Pyx_tp_new(PyObject* type_obj) {
diff --git a/tests/run/charptr_len.pyx b/tests/run/charptr_len.pyx
new file mode 100644 (file)
index 0000000..84c9400
--- /dev/null
@@ -0,0 +1,65 @@
+__doc__ = """
+>>> lentest_char()
+7
+>>> lentest_char_c()
+7
+
+>>> lentest_uchar()
+7
+>>> lentest_uchar_c()
+7
+
+>>> lentest_py()
+7
+>>> lentest_py_c()
+7
+"""
+
+
+cimport cython
+
+cdef char* s = b"abcdefg"
+cdef unsigned char* us = b"abcdefg"
+cdef bytes pystr =  b"abcdefg"
+
+
+@cython.test_assert_path_exists(
+    "//PythonCapiCallNode",
+    )
+def lentest_char():
+    return len(s)
+
+@cython.test_assert_path_exists(
+    "//PythonCapiCallNode",
+    )
+def lentest_char_c():
+    cdef Py_ssize_t l = len(s)
+    return l
+
+
+@cython.test_assert_path_exists(
+    "//PythonCapiCallNode",
+    )
+def lentest_uchar():
+    return len(us)
+
+@cython.test_assert_path_exists(
+    "//PythonCapiCallNode",
+    )
+def lentest_uchar_c():
+    cdef Py_ssize_t l = len(us)
+    return l
+
+
+@cython.test_assert_path_exists(
+    "//SimpleCallNode",
+    )
+def lentest_py():
+    return len(pystr)
+
+@cython.test_assert_path_exists(
+    "//SimpleCallNode",
+    )
+def lentest_py_c():
+    cdef Py_ssize_t l = len(pystr)
+    return l