Commit 350f55b4 authored by Stefan Behnel's avatar Stefan Behnel

optimise len() for known builtin types

parent 647df5b2
...@@ -413,13 +413,15 @@ def init_builtins(): ...@@ -413,13 +413,15 @@ def init_builtins():
init_builtin_funcs() init_builtin_funcs()
init_builtin_types() init_builtin_types()
init_builtin_structs() init_builtin_structs()
global list_type, tuple_type, dict_type, set_type, type_type global list_type, tuple_type, dict_type, set_type, frozenset_type
global bytes_type, str_type, unicode_type, float_type, bool_type global bytes_type, str_type, unicode_type
global float_type, bool_type, type_type
type_type = builtin_scope.lookup('type').type type_type = builtin_scope.lookup('type').type
list_type = builtin_scope.lookup('list').type list_type = builtin_scope.lookup('list').type
tuple_type = builtin_scope.lookup('tuple').type tuple_type = builtin_scope.lookup('tuple').type
dict_type = builtin_scope.lookup('dict').type dict_type = builtin_scope.lookup('dict').type
set_type = builtin_scope.lookup('set').type set_type = builtin_scope.lookup('set').type
frozenset_type = builtin_scope.lookup('frozenset').type
bytes_type = builtin_scope.lookup('bytes').type bytes_type = builtin_scope.lookup('bytes').type
str_type = builtin_scope.lookup('str').type str_type = builtin_scope.lookup('str').type
unicode_type = builtin_scope.lookup('unicode').type unicode_type = builtin_scope.lookup('unicode').type
......
...@@ -1230,6 +1230,22 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -1230,6 +1230,22 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
PyrexTypes.CFuncTypeArg("bytes", PyrexTypes.c_char_ptr_type, None) PyrexTypes.CFuncTypeArg("bytes", PyrexTypes.c_char_ptr_type, None)
]) ])
PyObject_Size_func_type = PyrexTypes.CFuncType(
PyrexTypes.c_py_ssize_t_type, [
PyrexTypes.CFuncTypeArg("obj", PyrexTypes.py_object_type, None)
])
_map_to_capi_len_function = {
Builtin.unicode_type : "PyUnicode_GET_SIZE",
Builtin.str_type : "Py_SIZE",
Builtin.bytes_type : "__Pyx_PyBytes_GET_SIZE",
Builtin.list_type : "PyList_GET_SIZE",
Builtin.tuple_type : "PyTuple_GET_SIZE",
Builtin.dict_type : "PyDict_Size",
Builtin.set_type : "PySet_Size",
Builtin.frozenset_type : "PySet_Size",
}.get
def _handle_simple_function_len(self, node, pos_args): def _handle_simple_function_len(self, node, pos_args):
"""Replace len(char*) by the equivalent call to strlen(). """Replace len(char*) by the equivalent call to strlen().
""" """
...@@ -1239,14 +1255,29 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform): ...@@ -1239,14 +1255,29 @@ class OptimizeBuiltinCalls(Visitor.EnvTransform):
arg = pos_args[0] arg = pos_args[0]
if isinstance(arg, ExprNodes.CoerceToPyTypeNode): if isinstance(arg, ExprNodes.CoerceToPyTypeNode):
arg = arg.arg arg = arg.arg
if not arg.type.is_string: if arg.type.is_string:
return node
new_node = ExprNodes.PythonCapiCallNode( new_node = ExprNodes.PythonCapiCallNode(
node.pos, "strlen", self.Pyx_strlen_func_type, node.pos, "strlen", self.Pyx_strlen_func_type,
args = [arg], args = [arg],
is_temp = node.is_temp, is_temp = node.is_temp,
utility_code = include_string_h_utility_code utility_code = include_string_h_utility_code)
) elif arg.type.is_pyobject:
if isinstance(arg, ExprNodes.NoneNode):
error(node.pos, "object of type 'NoneType' has no len()")
return node
cfunc_name = self._map_to_capi_len_function(arg.type)
if cfunc_name is None:
return node
if not arg.is_literal:
arg = ExprNodes.NoneCheckNode(
arg, "PyExc_TypeError",
"object of type 'NoneType' has no len()")
new_node = ExprNodes.PythonCapiCallNode(
node.pos, cfunc_name, self.PyObject_Size_func_type,
args = [arg],
is_temp = node.is_temp)
else:
return node
if node.type not in (PyrexTypes.c_size_t_type, PyrexTypes.c_py_ssize_t_type): if node.type not in (PyrexTypes.c_size_t_type, PyrexTypes.c_py_ssize_t_type):
new_node = new_node.coerce_to(node.type, self.env_stack[-1]) new_node = new_node.coerce_to(node.type, self.env_stack[-1])
return new_node return new_node
......
...@@ -2464,10 +2464,12 @@ type_conversion_predeclarations = """ ...@@ -2464,10 +2464,12 @@ type_conversion_predeclarations = """
#define __Pyx_PyBytes_FromString PyString_FromString #define __Pyx_PyBytes_FromString PyString_FromString
#define __Pyx_PyBytes_FromStringAndSize PyString_FromStringAndSize #define __Pyx_PyBytes_FromStringAndSize PyString_FromStringAndSize
#define __Pyx_PyBytes_AsString PyString_AsString #define __Pyx_PyBytes_AsString PyString_AsString
#define __Pyx_PyBytes_GET_SIZE PyString_GET_SIZE
#else #else
#define __Pyx_PyBytes_FromString PyBytes_FromString #define __Pyx_PyBytes_FromString PyBytes_FromString
#define __Pyx_PyBytes_FromStringAndSize PyBytes_FromStringAndSize #define __Pyx_PyBytes_FromStringAndSize PyBytes_FromStringAndSize
#define __Pyx_PyBytes_AsString PyBytes_AsString #define __Pyx_PyBytes_AsString PyBytes_AsString
#define __Pyx_PyBytes_GET_SIZE PyBytes_GET_SIZE
#endif #endif
#define __Pyx_PyBytes_FromUString(s) __Pyx_PyBytes_FromString((char*)s) #define __Pyx_PyBytes_FromUString(s) __Pyx_PyBytes_FromString((char*)s)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment