diff options
author | William Ayd <william.ayd@icloud.com> | 2020-04-01 22:53:00 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-04-02 07:53:00 +0200 |
commit | 2c8e7b2204622380c20ee4b1f2a9aa59938fe33a (patch) | |
tree | c4fba6b5e4f3d3d8f3f5e313400432688fa454b4 | |
parent | e9d7fd45a2e829ee93980b1c0612f8476a46431d (diff) | |
download | cython-2c8e7b2204622380c20ee4b1f2a9aa59938fe33a.tar.gz |
Optimize builtin str() calls (GH-3478)
-rw-r--r-- | Cython/Compiler/Optimize.py | 32 | ||||
-rw-r--r-- | Cython/Utility/StringTools.c | 19 | ||||
-rw-r--r-- | tests/run/strfunction.pyx | 32 |
3 files changed, 83 insertions, 0 deletions
diff --git a/Cython/Compiler/Optimize.py b/Cython/Compiler/Optimize.py index 65f5bf2d0..e12abb22a 100644 --- a/Cython/Compiler/Optimize.py +++ b/Cython/Compiler/Optimize.py @@ -2312,6 +2312,38 @@ class OptimizeBuiltinCalls(Visitor.NodeRefCleanupMixin, return ExprNodes.CachedBuiltinMethodCallNode( node, function.obj, attr_name, arg_list) + PyObject_String_func_type = PyrexTypes.CFuncType( + Builtin.str_type, [ + PyrexTypes.CFuncTypeArg("obj", PyrexTypes.py_object_type, None) + ]) + + def _handle_simple_function_str(self, node, function, pos_args): + """Optimize single argument calls to str(). + """ + if len(pos_args) != 1: + if len(pos_args) == 0: + return ExprNodes.StringNode(node.pos, value=EncodedString(), constant_result='') + return node + arg = pos_args[0] + + if arg.type is Builtin.str_type: + if not arg.may_be_none(): + return arg + + cname = "__Pyx_PyStr_Str" + utility_code = UtilityCode.load_cached('PyStr_Str', 'StringTools.c') + else: + cname = '__Pyx_PyObject_Str' + utility_code = UtilityCode.load_cached('PyObject_Str', 'StringTools.c') + + return ExprNodes.PythonCapiCallNode( + node.pos, cname, self.PyObject_String_func_type, + args=pos_args, + is_temp=node.is_temp, + utility_code=utility_code, + py_name="str" + ) + PyObject_Unicode_func_type = PyrexTypes.CFuncType( Builtin.unicode_type, [ PyrexTypes.CFuncTypeArg("obj", PyrexTypes.py_object_type, None) diff --git a/Cython/Utility/StringTools.c b/Cython/Utility/StringTools.c index 9b20c4a2b..29a151d80 100644 --- a/Cython/Utility/StringTools.c +++ b/Cython/Utility/StringTools.c @@ -1219,3 +1219,22 @@ static CYTHON_INLINE PyObject* __Pyx_PyUnicode_Unicode(PyObject *obj) { #define __Pyx_PyObject_Unicode(obj) \ (likely(PyUnicode_CheckExact(obj)) ? __Pyx_NewRef(obj) : PyObject_Unicode(obj)) #endif + + +//////////////////// PyStr_Str.proto //////////////////// + +static CYTHON_INLINE PyObject* __Pyx_PyStr_Str(PyObject *obj);/*proto*/ + +//////////////////// PyStr_Str //////////////////// + +static CYTHON_INLINE PyObject* __Pyx_PyStr_Str(PyObject *obj) { + if (unlikely(obj == Py_None)) + obj = PYIDENT("None"); + return __Pyx_NewRef(obj); +} + + +//////////////////// PyObject_Str.proto //////////////////// + +#define __Pyx_PyObject_Str(obj) \ + (likely(PyString_CheckExact(obj)) ? __Pyx_NewRef(obj) : PyObject_Str(obj)) diff --git a/tests/run/strfunction.pyx b/tests/run/strfunction.pyx index dc6adaf79..d4a1c95d4 100644 --- a/tests/run/strfunction.pyx +++ b/tests/run/strfunction.pyx @@ -5,6 +5,8 @@ __doc__ = u""" 'test' """ +cimport cython + s = str z = str('test') @@ -39,3 +41,33 @@ def sub(string): #def csub(string): # return csubs(string) + + +@cython.test_fail_if_path_exists("//SimpleCallNode") +@cython.test_assert_path_exists("//PythonCapiCallNode") +def typed(str s): + """ + >>> print(typed(None)) + None + >>> type(typed(None)) is type(typed(None)) + True + >>> print(typed('abc')) + abc + >>> type(typed('abc')) is type(typed('abc')) + True + """ + return str(s) + + +@cython.test_fail_if_path_exists( + "//SimpleCallNode", + "//PythonCapiCallNode", +) +def typed_not_none(str s not None): + """ + >>> print(typed('abc')) + abc + >>> type(typed('abc')) is type(typed('abc')) + True + """ + return str(s) |