Commit eed01890 authored by Robert Bradshaw's avatar Robert Bradshaw

Append optimization.

parent c37a4543
...@@ -52,6 +52,9 @@ builtin_function_table = [ ...@@ -52,6 +52,9 @@ builtin_function_table = [
# Can't do these easily until we have builtin type entries. # Can't do these easily until we have builtin type entries.
#('typecheck', "OO", "i", "PyObject_TypeCheck", False), #('typecheck', "OO", "i", "PyObject_TypeCheck", False),
#('issubtype', "OO", "i", "PyType_IsSubtype", False), #('issubtype', "OO", "i", "PyType_IsSubtype", False),
# Put in namespace append optimization.
('__Pyx_PyObject_Append', "OO", "O", "__Pyx_PyObject_Append"),
] ]
# Builtin types # Builtin types
......
...@@ -1519,12 +1519,15 @@ class SimpleCallNode(ExprNode): ...@@ -1519,12 +1519,15 @@ class SimpleCallNode(ExprNode):
# coerced_self ExprNode or None used internally # coerced_self ExprNode or None used internally
# wrapper_call bool used internally # wrapper_call bool used internally
# optimized_call str or None
subexprs = ['self', 'coerced_self', 'function', 'args', 'arg_tuple'] subexprs = ['self', 'coerced_self', 'function', 'args', 'arg_tuple']
self = None self = None
coerced_self = None coerced_self = None
arg_tuple = None arg_tuple = None
wrapper_call = False wrapper_call = False
optimized_call = None
def compile_time_value(self, denv): def compile_time_value(self, denv):
function = self.function.compile_time_value(denv) function = self.function.compile_time_value(denv)
...@@ -1538,6 +1541,15 @@ class SimpleCallNode(ExprNode): ...@@ -1538,6 +1541,15 @@ class SimpleCallNode(ExprNode):
function = self.function function = self.function
function.is_called = 1 function.is_called = 1
self.function.analyse_types(env) self.function.analyse_types(env)
if function.is_attribute and function.is_py_attr and \
function.attribute == "append" and len(self.args) == 1:
# L.append(x) is almost always applied to a list
self.py_func = self.function
self.function = NameNode(pos=self.function.pos, name="__Pyx_PyObject_Append")
self.function.analyse_types(env)
self.self = self.py_func.obj
function.obj = CloneNode(self.self)
env.use_utility_code(append_utility_code)
if function.is_attribute and function.entry and function.entry.is_cmethod: if function.is_attribute and function.entry and function.entry.is_cmethod:
# Take ownership of the object from which the attribute # Take ownership of the object from which the attribute
# was obtained, because we need to pass it as 'self'. # was obtained, because we need to pass it as 'self'.
...@@ -4105,3 +4117,18 @@ static void __Pyx_CppExn2PyErr() { ...@@ -4105,3 +4117,18 @@ static void __Pyx_CppExn2PyErr() {
""",""] """,""]
#------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------
append_utility_code = [
"""
static inline PyObject* __Pyx_PyObject_Append(PyObject* L, PyObject* x) {
if (likely(PyList_CheckExact(L))) {
if (PyList_Append(L, x) < 0) return NULL;
Py_INCREF(Py_None);
return Py_None; // this is just to have an accurate signature
}
else {
return PyObject_CallMethod(L, "append", "O", x);
}
}
""",""
]
\ No newline at end of file
__doc__ = """
>>> test_append([])
None
None
got error
[1, 2]
>>> test_append(A())
appending
1
appending
2
got error
<append.A instance at ...>
>>> test_append(B())
None
None
None
[1, 2, 3, 4]
"""
class A:
def append(self, x):
print "appending"
return x
class B(list):
def append(self, *args):
for arg in args:
list.append(self, arg)
def test_append(L):
print L.append(1)
print L.append(2)
try:
print L.append(3,4)
except TypeError:
print "got error"
print L
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