Commit b56859e3 authored by zaur's avatar zaur

Merge branch 'master' of https://github.com/intellimath/cython

parents 334a195b 23350e5a
...@@ -19,6 +19,9 @@ Features added ...@@ -19,6 +19,9 @@ Features added
Bugs fixed Bugs fixed
---------- ----------
* ``dir()`` without arguments previously returned an unsorted list, which now
gets sorted as expected.
* ``dict.items()``, ``dict.keys()`` and ``dict.values()`` no longer return lists * ``dict.items()``, ``dict.keys()`` and ``dict.values()`` no longer return lists
in Python 3. in Python 3.
......
...@@ -4993,8 +4993,10 @@ class AttributeNode(ExprNode): ...@@ -4993,8 +4993,10 @@ class AttributeNode(ExprNode):
def generate_result_code(self, code): def generate_result_code(self, code):
if self.is_py_attr: if self.is_py_attr:
code.globalstate.use_utility_code(
UtilityCode.load_cached("PyObjectGetAttrStr", "ObjectHandling.c"))
code.putln( code.putln(
'%s = PyObject_GetAttr(%s, %s); %s' % ( '%s = __Pyx_PyObject_GetAttrStr(%s, %s); %s' % (
self.result(), self.result(),
self.obj.py_result(), self.obj.py_result(),
code.intern_identifier(self.attribute), code.intern_identifier(self.attribute),
...@@ -10262,33 +10264,13 @@ class DocstringRefNode(ExprNode): ...@@ -10262,33 +10264,13 @@ class DocstringRefNode(ExprNode):
code.put_gotref(self.result()) code.put_gotref(self.result())
#------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------
# #
# Runtime support code # Runtime support code
# #
#------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------
get_name_interned_utility_code = UtilityCode( get_name_interned_utility_code = UtilityCode.load("GetGlobalName", "ObjectHandling.c")
proto = """
static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name); /*proto*/
""",
impl = """
static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name) {
PyObject *result;
result = PyObject_GetAttr(dict, name);
if (!result) {
if (dict != %(BUILTINS)s) {
PyErr_Clear();
result = PyObject_GetAttr(%(BUILTINS)s, name);
}
if (!result) {
PyErr_SetObject(PyExc_NameError, name);
}
}
return result;
}
""" % {'BUILTINS' : Naming.builtins_cname})
#------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------
......
...@@ -1073,7 +1073,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1073,7 +1073,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
for entry in cpp_class_attrs: for entry in cpp_class_attrs:
code.putln("new((void*)&(p->%s)) %s();" % code.putln("new((void*)&(p->%s)) %s();" %
(entry.cname, entry.type.declaration_code(""))); (entry.cname, entry.type.declaration_code("")))
for entry in py_attrs: for entry in py_attrs:
if scope.is_internal or entry.name == "__weakref__": if scope.is_internal or entry.name == "__weakref__":
...@@ -1100,7 +1100,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1100,7 +1100,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln( code.putln(
"if (%s(%s) < 0) {" % "if (%s(%s) < 0) {" %
(new_func_entry.func_cname, cinit_args)) (new_func_entry.func_cname, cinit_args))
code.put_decref_clear("o", py_object_type, nanny=False); code.put_decref_clear("o", py_object_type, nanny=False)
code.putln( code.putln(
"}") "}")
code.putln( code.putln(
...@@ -1133,7 +1133,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1133,7 +1133,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
# We must mark ths object as (gc) untracked while tearing it down, lest # We must mark ths object as (gc) untracked while tearing it down, lest
# the garbage collection is invoked while running this destructor. # the garbage collection is invoked while running this destructor.
if scope.needs_gc(): if scope.needs_gc():
code.putln("PyObject_GC_UnTrack(o);"); code.putln("PyObject_GC_UnTrack(o);")
# call the user's __dealloc__ # call the user's __dealloc__
self.generate_usr_dealloc_call(scope, code) self.generate_usr_dealloc_call(scope, code)
...@@ -1158,12 +1158,12 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1158,12 +1158,12 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.put_xdecref_memoryviewslice("p->%s" % entry.cname, code.put_xdecref_memoryviewslice("p->%s" % entry.cname,
have_gil=True) have_gil=True)
# The base class deallocator probably expects this to be tracked, so
# undo the untracking above.
if scope.needs_gc():
code.putln("PyObject_GC_Track(o);");
if base_type: if base_type:
# The base class deallocator probably expects this to be tracked, so
# undo the untracking above.
if scope.needs_gc():
code.putln("PyObject_GC_Track(o);")
tp_dealloc = TypeSlots.get_base_slot_function(scope, tp_slot) tp_dealloc = TypeSlots.get_base_slot_function(scope, tp_slot)
if tp_dealloc is not None: if tp_dealloc is not None:
code.putln("%s(o);" % tp_dealloc) code.putln("%s(o);" % tp_dealloc)
...@@ -1857,8 +1857,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1857,8 +1857,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
env.use_utility_code(UtilityCode.load("CheckBinaryVersion", "ModuleSetupCode.c")) env.use_utility_code(UtilityCode.load("CheckBinaryVersion", "ModuleSetupCode.c"))
code.putln("if ( __Pyx_check_binary_version() < 0) %s" % code.error_goto(self.pos)) code.putln("if ( __Pyx_check_binary_version() < 0) %s" % code.error_goto(self.pos))
code.putln("%s = PyTuple_New(0); %s" % (Naming.empty_tuple, code.error_goto_if_null(Naming.empty_tuple, self.pos))); code.putln("%s = PyTuple_New(0); %s" % (Naming.empty_tuple, code.error_goto_if_null(Naming.empty_tuple, self.pos)))
code.putln("%s = PyBytes_FromStringAndSize(\"\", 0); %s" % (Naming.empty_bytes, code.error_goto_if_null(Naming.empty_bytes, self.pos))); code.putln("%s = PyBytes_FromStringAndSize(\"\", 0); %s" % (Naming.empty_bytes, code.error_goto_if_null(Naming.empty_bytes, self.pos)))
code.putln("#ifdef __Pyx_CyFunction_USED") code.putln("#ifdef __Pyx_CyFunction_USED")
code.putln("if (__Pyx_CyFunction_init() < 0) %s" % code.error_goto(self.pos)) code.putln("if (__Pyx_CyFunction_init() < 0) %s" % code.error_goto(self.pos))
......
...@@ -3856,8 +3856,10 @@ class OverrideCheckNode(StatNode): ...@@ -3856,8 +3856,10 @@ class OverrideCheckNode(StatNode):
func_node_temp = code.funcstate.allocate_temp(py_object_type, manage_ref=True) func_node_temp = code.funcstate.allocate_temp(py_object_type, manage_ref=True)
self.func_node.set_cname(func_node_temp) self.func_node.set_cname(func_node_temp)
# need to get attribute manually--scope would return cdef method # need to get attribute manually--scope would return cdef method
code.globalstate.use_utility_code(
UtilityCode.load_cached("PyObjectGetAttrStr", "ObjectHandling.c"))
err = code.error_goto_if_null(func_node_temp, self.pos) err = code.error_goto_if_null(func_node_temp, self.pos)
code.putln("%s = PyObject_GetAttr(%s, %s); %s" % ( code.putln("%s = __Pyx_PyObject_GetAttrStr(%s, %s); %s" % (
func_node_temp, self_arg, interned_attr_cname, err)) func_node_temp, self_arg, interned_attr_cname, err))
code.put_gotref(func_node_temp) code.put_gotref(func_node_temp)
is_builtin_function_or_method = "PyCFunction_Check(%s)" % func_node_temp is_builtin_function_or_method = "PyCFunction_Check(%s)" % func_node_temp
...@@ -5849,10 +5851,12 @@ class WithStatNode(StatNode): ...@@ -5849,10 +5851,12 @@ class WithStatNode(StatNode):
code.putln("/*with:*/ {") code.putln("/*with:*/ {")
self.manager.generate_evaluation_code(code) self.manager.generate_evaluation_code(code)
self.exit_var = code.funcstate.allocate_temp(py_object_type, manage_ref=False) self.exit_var = code.funcstate.allocate_temp(py_object_type, manage_ref=False)
code.putln("%s = PyObject_GetAttr(%s, %s); %s" % ( code.globalstate.use_utility_code(
UtilityCode.load_cached("PyObjectGetAttrStr", "ObjectHandling.c"))
code.putln("%s = __Pyx_PyObject_GetAttrStr(%s, %s); %s" % (
self.exit_var, self.exit_var,
self.manager.py_result(), self.manager.py_result(),
code.get_py_string_const(EncodedString('__exit__'), identifier=True), code.intern_identifier(EncodedString('__exit__')),
code.error_goto_if_null(self.exit_var, self.pos), code.error_goto_if_null(self.exit_var, self.pos),
)) ))
code.put_gotref(self.exit_var) code.put_gotref(self.exit_var)
...@@ -6710,10 +6714,12 @@ class FromImportStatNode(StatNode): ...@@ -6710,10 +6714,12 @@ class FromImportStatNode(StatNode):
code.error_goto(self.pos))) code.error_goto(self.pos)))
item_temp = code.funcstate.allocate_temp(py_object_type, manage_ref=True) item_temp = code.funcstate.allocate_temp(py_object_type, manage_ref=True)
self.item.set_cname(item_temp) self.item.set_cname(item_temp)
code.globalstate.use_utility_code(
UtilityCode.load_cached("PyObjectGetAttrStr", "ObjectHandling.c"))
for name, target, coerced_item in self.interned_items: for name, target, coerced_item in self.interned_items:
cname = code.intern_identifier(name) cname = code.intern_identifier(name)
code.putln( code.putln(
'%s = PyObject_GetAttr(%s, %s);' % ( '%s = __Pyx_PyObject_GetAttrStr(%s, %s);' % (
item_temp, item_temp,
self.module.py_result(), self.module.py_result(),
cname)) cname))
......
...@@ -2294,6 +2294,7 @@ class OptimizeBuiltinCalls(Visitor.MethodDispatcherTransform): ...@@ -2294,6 +2294,7 @@ class OptimizeBuiltinCalls(Visitor.MethodDispatcherTransform):
PyrexTypes.CFuncTypeArg("dict", PyrexTypes.py_object_type, None), PyrexTypes.CFuncTypeArg("dict", PyrexTypes.py_object_type, None),
PyrexTypes.CFuncTypeArg("key", PyrexTypes.py_object_type, None), PyrexTypes.CFuncTypeArg("key", PyrexTypes.py_object_type, None),
PyrexTypes.CFuncTypeArg("default", PyrexTypes.py_object_type, None), PyrexTypes.CFuncTypeArg("default", PyrexTypes.py_object_type, None),
PyrexTypes.CFuncTypeArg("is_safe_type", PyrexTypes.c_int_type, None),
]) ])
def _handle_simple_method_dict_setdefault(self, node, args, is_unbound_method): def _handle_simple_method_dict_setdefault(self, node, args, is_unbound_method):
...@@ -2304,12 +2305,22 @@ class OptimizeBuiltinCalls(Visitor.MethodDispatcherTransform): ...@@ -2304,12 +2305,22 @@ class OptimizeBuiltinCalls(Visitor.MethodDispatcherTransform):
elif len(args) != 3: elif len(args) != 3:
self._error_wrong_arg_count('dict.setdefault', node, args, "2 or 3") self._error_wrong_arg_count('dict.setdefault', node, args, "2 or 3")
return node return node
key_type = args[1].type
if key_type.is_builtin_type:
is_safe_type = int(key_type.name in
'str bytes unicode float int long bool')
elif key_type is PyrexTypes.py_object_type:
is_safe_type = -1 # don't know
else:
is_safe_type = 0 # definitely not
args.append(ExprNodes.IntNode(
node.pos, value=is_safe_type, constant_result=is_safe_type))
return self._substitute_method_call( return self._substitute_method_call(
node, "__Pyx_PyDict_SetDefault", self.Pyx_PyDict_SetDefault_func_type, node, "__Pyx_PyDict_SetDefault", self.Pyx_PyDict_SetDefault_func_type,
'setdefault', is_unbound_method, args, 'setdefault', is_unbound_method, args,
may_return_none = True, may_return_none=True,
utility_code = load_c_utility('dict_setdefault')) utility_code=load_c_utility('dict_setdefault'))
### unicode type methods ### unicode type methods
......
...@@ -56,6 +56,7 @@ static int __Pyx_PyGen_FetchStopIterationValue(PyObject **pvalue); ...@@ -56,6 +56,7 @@ static int __Pyx_PyGen_FetchStopIterationValue(PyObject **pvalue);
//@requires: Exceptions.c::PyErrFetchRestore //@requires: Exceptions.c::PyErrFetchRestore
//@requires: Exceptions.c::SwapException //@requires: Exceptions.c::SwapException
//@requires: Exceptions.c::RaiseException //@requires: Exceptions.c::RaiseException
//@requires: ObjectHandling.c::PyObjectCallMethod
static PyObject *__Pyx_Generator_Next(PyObject *self); static PyObject *__Pyx_Generator_Next(PyObject *self);
static PyObject *__Pyx_Generator_Send(PyObject *self, PyObject *value); static PyObject *__Pyx_Generator_Send(PyObject *self, PyObject *value);
...@@ -285,7 +286,7 @@ static PyObject *__Pyx_Generator_Send(PyObject *self, PyObject *value) { ...@@ -285,7 +286,7 @@ static PyObject *__Pyx_Generator_Send(PyObject *self, PyObject *value) {
if (value == Py_None) if (value == Py_None)
ret = PyIter_Next(yf); ret = PyIter_Next(yf);
else else
ret = PyObject_CallMethod(yf, (char*)"send", (char*)"O", value); ret = __Pyx_PyObject_CallMethod1(yf, PYIDENT("send"), value);
} }
gen->is_running = 0; gen->is_running = 0;
//Py_DECREF(yf); //Py_DECREF(yf);
......
...@@ -23,8 +23,9 @@ typedef struct { ...@@ -23,8 +23,9 @@ typedef struct {
#define __pyx_atomic_int_type int #define __pyx_atomic_int_type int
/* todo: Portland pgcc, maybe OS X's OSAtomicIncrement32, /* todo: Portland pgcc, maybe OS X's OSAtomicIncrement32,
libatomic + autotools-like distutils support? Such a pain... */ libatomic + autotools-like distutils support? Such a pain... */
#if CYTHON_ATOMICS && __GNUC__ >= 4 && (__GNUC_MINOR__ > 1 || \ #if CYTHON_ATOMICS && __GNUC__ >= 4 && (__GNUC_MINOR__ > 1 || \
(__GNUC_MINOR__ == 1 && __GNUC_PATHLEVEL >= 2)) (__GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL >= 2)) && \
!defined(WIN32) && !defined(MS_WINDOWS)
/* gcc >= 4.1.2 */ /* gcc >= 4.1.2 */
#define __pyx_atomic_incr_aligned(value, lock) __sync_fetch_and_add(value, 1) #define __pyx_atomic_incr_aligned(value, lock) __sync_fetch_and_add(value, 1)
#define __pyx_atomic_decr_aligned(value, lock) __sync_fetch_and_sub(value, 1) #define __pyx_atomic_decr_aligned(value, lock) __sync_fetch_and_sub(value, 1)
......
...@@ -221,8 +221,12 @@ static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key) { ...@@ -221,8 +221,12 @@ static PyObject *__Pyx_PyDict_GetItem(PyObject *d, PyObject* key) {
PyObject *value; PyObject *value;
value = PyDict_GetItemWithError(d, key); value = PyDict_GetItemWithError(d, key);
if (unlikely(!value)) { if (unlikely(!value)) {
if (!PyErr_Occurred()) if (!PyErr_Occurred()) {
PyErr_SetObject(PyExc_KeyError, key); PyObject* args = PyTuple_Pack(1, key);
if (likely(args))
PyErr_SetObject(PyExc_KeyError, args);
Py_XDECREF(args);
}
return NULL; return NULL;
} }
Py_INCREF(value); Py_INCREF(value);
...@@ -581,3 +585,68 @@ static CYTHON_INLINE int __Pyx_PySequence_Contains(PyObject* item, PyObject* seq ...@@ -581,3 +585,68 @@ static CYTHON_INLINE int __Pyx_PySequence_Contains(PyObject* item, PyObject* seq
static CYTHON_INLINE PyObject* __Pyx_PyBoolOrNull_FromLong(long b) { static CYTHON_INLINE PyObject* __Pyx_PyBoolOrNull_FromLong(long b) {
return unlikely(b < 0) ? NULL : __Pyx_PyBool_FromLong(b); return unlikely(b < 0) ? NULL : __Pyx_PyBool_FromLong(b);
} }
/////////////// GetGlobalName.proto ///////////////
static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name); /*proto*/
/////////////// GetGlobalName ///////////////
//@requires: PyObjectGetAttrStr
//@substitute: naming
static PyObject *__Pyx_GetName(PyObject *dict, PyObject *name) {
PyObject *result;
result = __Pyx_PyObject_GetAttrStr(dict, name);
if (!result) {
if (dict != $builtins_cname) {
PyErr_Clear();
result = __Pyx_PyObject_GetAttrStr($builtins_cname, name);
}
if (!result) {
PyErr_SetObject(PyExc_NameError, name);
}
}
return result;
}
/////////////// PyObjectGetAttrStr.proto ///////////////
#if CYTHON_COMPILING_IN_CPYTHON
static CYTHON_INLINE PyObject* __Pyx_PyObject_GetAttrStr(PyObject* obj, PyObject* attr_name) {
PyTypeObject* tp = Py_TYPE(obj);
if (likely(tp->tp_getattro))
return tp->tp_getattro(obj, attr_name);
#if PY_MAJOR_VERSION < 3
if (likely(tp->tp_getattr))
return tp->tp_getattr(obj, PyString_AS_STRING(attr_name));
#endif
return PyObject_GetAttr(obj, attr_name);
}
#else
#define __Pyx_PyObject_GetAttrStr(o,n) PyObject_GetAttr(o,n)
#endif
/////////////// PyObjectCallMethod.proto ///////////////
//@requires: PyObjectGetAttrStr
//@substitute: naming
static PyObject* __Pyx_PyObject_CallMethodTuple(PyObject* obj, PyObject* method_name, PyObject* args) {
PyObject *method, *result = NULL;
if (unlikely(!args)) return NULL;
method = __Pyx_PyObject_GetAttrStr(obj, method_name);
if (unlikely(!method)) goto bad;
result = PyObject_Call(method, args, NULL);
Py_DECREF(method);
bad:
Py_DECREF(args);
return result;
}
#define __Pyx_PyObject_CallMethod3(obj, name, arg1, arg2, arg3) \
__Pyx_PyObject_CallMethodTuple(obj, name, PyTuple_Pack(3, arg1, arg2, arg3))
#define __Pyx_PyObject_CallMethod2(obj, name, arg1, arg2) \
__Pyx_PyObject_CallMethodTuple(obj, name, PyTuple_Pack(2, arg1, arg2))
#define __Pyx_PyObject_CallMethod1(obj, name, arg1) \
__Pyx_PyObject_CallMethodTuple(obj, name, PyTuple_Pack(1, arg1))
#define __Pyx_PyObject_CallMethod0(obj, name) \
__Pyx_PyObject_CallMethodTuple(obj, name, (Py_INCREF($empty_tuple), $empty_tuple))
...@@ -4,6 +4,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_Append(PyObject* L, PyObject* x); ...@@ -4,6 +4,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_Append(PyObject* L, PyObject* x);
/////////////// append /////////////// /////////////// append ///////////////
//@requires: ListAppend //@requires: ListAppend
//@requires: ObjectHandling.c::PyObjectCallMethod
static CYTHON_INLINE PyObject* __Pyx_PyObject_Append(PyObject* L, PyObject* x) { static CYTHON_INLINE PyObject* __Pyx_PyObject_Append(PyObject* L, PyObject* x) {
if (likely(PyList_CheckExact(L))) { if (likely(PyList_CheckExact(L))) {
...@@ -11,7 +12,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_Append(PyObject* L, PyObject* x) { ...@@ -11,7 +12,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_Append(PyObject* L, PyObject* x) {
Py_INCREF(Py_None); Py_INCREF(Py_None);
return Py_None; /* this is just to have an accurate signature */ return Py_None; /* this is just to have an accurate signature */
} else { } else {
return PyObject_CallMethodObjArgs(L, PYIDENT("append"), x, NULL); return __Pyx_PyObject_CallMethod1(L, PYIDENT("append"), x);
} }
} }
...@@ -56,6 +57,7 @@ static CYTHON_INLINE int __Pyx_ListComp_Append(PyObject* list, PyObject* x) { ...@@ -56,6 +57,7 @@ static CYTHON_INLINE int __Pyx_ListComp_Append(PyObject* list, PyObject* x) {
static CYTHON_INLINE PyObject* __Pyx_PyObject_Pop(PyObject* L); /*proto*/ static CYTHON_INLINE PyObject* __Pyx_PyObject_Pop(PyObject* L); /*proto*/
/////////////// pop /////////////// /////////////// pop ///////////////
//@requires: ObjectHandling.c::PyObjectCallMethod
static CYTHON_INLINE PyObject* __Pyx_PyObject_Pop(PyObject* L) { static CYTHON_INLINE PyObject* __Pyx_PyObject_Pop(PyObject* L) {
#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x02040000 #if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x02040000
...@@ -71,7 +73,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_Pop(PyObject* L) { ...@@ -71,7 +73,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_Pop(PyObject* L) {
} }
#endif #endif
#endif #endif
return PyObject_CallMethodObjArgs(L, PYIDENT("pop"), NULL); return __Pyx_PyObject_CallMethod0(L, PYIDENT("pop"));
} }
...@@ -80,44 +82,33 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_Pop(PyObject* L) { ...@@ -80,44 +82,33 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_Pop(PyObject* L) {
static PyObject* __Pyx_PyObject_PopIndex(PyObject* L, Py_ssize_t ix); /*proto*/ static PyObject* __Pyx_PyObject_PopIndex(PyObject* L, Py_ssize_t ix); /*proto*/
/////////////// pop_index /////////////// /////////////// pop_index ///////////////
//@requires: ObjectHandling.c::PyObjectCallMethod
static PyObject* __Pyx_PyObject_PopIndex(PyObject* L, Py_ssize_t ix) { static PyObject* __Pyx_PyObject_PopIndex(PyObject* L, Py_ssize_t ix) {
PyObject *r, *m, *t, *py_ix; PyObject *r, *py_ix;
#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x02040000 #if CYTHON_COMPILING_IN_CPYTHON
if (likely(PyList_CheckExact(L))) { if (likely(PyList_CheckExact(L))) {
Py_ssize_t size = PyList_GET_SIZE(L); Py_ssize_t size = PyList_GET_SIZE(L);
if (likely(size > (((PyListObject*)L)->allocated >> 1))) { if (likely(size > (((PyListObject*)L)->allocated >> 1))) {
if (ix < 0) { Py_ssize_t cix = ix;
ix += size; if (cix < 0) {
cix += size;
} }
if (likely(0 <= ix && ix < size)) { if (likely(0 <= cix && cix < size)) {
PyObject* v = PyList_GET_ITEM(L, ix); PyObject* v = PyList_GET_ITEM(L, cix);
Py_SIZE(L) -= 1; Py_SIZE(L) -= 1;
size -= 1; size -= 1;
memmove(&PyList_GET_ITEM(L, ix), &PyList_GET_ITEM(L, ix+1), (size-ix)*sizeof(PyObject*)); memmove(&PyList_GET_ITEM(L, cix), &PyList_GET_ITEM(L, cix+1), (size-cix)*sizeof(PyObject*));
return v; return v;
} }
} }
} }
#endif #endif
py_ix = t = NULL;
m = PyObject_GetAttr(L, PYIDENT("pop"));
if (!m) goto bad;
py_ix = PyInt_FromSsize_t(ix); py_ix = PyInt_FromSsize_t(ix);
if (!py_ix) goto bad; if (!py_ix) return NULL;
t = PyTuple_New(1); r = __Pyx_PyObject_CallMethod1(L, PYIDENT("pop"), py_ix);
if (!t) goto bad; Py_DECREF(py_ix);
PyTuple_SET_ITEM(t, 0, py_ix);
py_ix = NULL;
r = PyObject_CallObject(m, t);
Py_DECREF(m);
Py_DECREF(t);
return r; return r;
bad:
Py_XDECREF(m);
Py_XDECREF(t);
Py_XDECREF(py_ix);
return NULL;
} }
...@@ -315,25 +306,28 @@ static PyObject* __Pyx_PyDict_GetItemDefault(PyObject* d, PyObject* key, PyObjec ...@@ -315,25 +306,28 @@ static PyObject* __Pyx_PyDict_GetItemDefault(PyObject* d, PyObject* key, PyObjec
/////////////// dict_setdefault.proto /////////////// /////////////// dict_setdefault.proto ///////////////
static PyObject *__Pyx_PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *default_value); /*proto*/ static CYTHON_INLINE PyObject *__Pyx_PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *default_value, int is_safe_type); /*proto*/
/////////////// dict_setdefault /////////////// /////////////// dict_setdefault ///////////////
//@requires: ObjectHandling.c::PyObjectCallMethod
static PyObject *__Pyx_PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *default_value) { static CYTHON_INLINE PyObject *__Pyx_PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *default_value, int is_safe_type) {
PyObject* value; PyObject* value;
if (is_safe_type == 1 || (is_safe_type == -1 &&
/* the following builtins presumably have repeatably safe and fast hash functions */
#if PY_MAJOR_VERSION >= 3 #if PY_MAJOR_VERSION >= 3
value = PyDict_GetItemWithError(d, key); (PyUnicode_CheckExact(key) || PyString_CheckExact(key) || PyLong_CheckExact(key)))) {
if (unlikely(!value)) { value = PyDict_GetItemWithError(d, key);
if (unlikely(PyErr_Occurred())) if (unlikely(!value)) {
return NULL; if (unlikely(PyErr_Occurred()))
if (unlikely(PyDict_SetItem(d, key, default_value) == -1)) return NULL;
return NULL; if (unlikely(PyDict_SetItem(d, key, default_value) == -1))
value = default_value; return NULL;
} value = default_value;
Py_INCREF(value); }
Py_INCREF(value);
#else #else
if (PyString_CheckExact(key) || PyUnicode_CheckExact(key) || PyInt_CheckExact(key)) { (PyString_CheckExact(key) || PyUnicode_CheckExact(key) || PyInt_CheckExact(key) || PyLong_CheckExact(key)))) {
/* these presumably have safe hash functions */
value = PyDict_GetItem(d, key); value = PyDict_GetItem(d, key);
if (unlikely(!value)) { if (unlikely(!value)) {
if (unlikely(PyDict_SetItem(d, key, default_value) == -1)) if (unlikely(PyDict_SetItem(d, key, default_value) == -1))
...@@ -341,10 +335,10 @@ static PyObject *__Pyx_PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *d ...@@ -341,10 +335,10 @@ static PyObject *__Pyx_PyDict_SetDefault(PyObject *d, PyObject *key, PyObject *d
value = default_value; value = default_value;
} }
Py_INCREF(value); Py_INCREF(value);
#endif
} else { } else {
value = PyObject_CallMethodObjArgs(d, PYIDENT("setdefault"), key, default_value, NULL); value = __Pyx_PyObject_CallMethod2(d, PYIDENT("setdefault"), key, default_value);
} }
#endif
return value; return value;
} }
...@@ -411,6 +405,7 @@ static CYTHON_INLINE int __Pyx_dict_iter_next(PyObject* dict_or_iter, Py_ssize_t ...@@ -411,6 +405,7 @@ static CYTHON_INLINE int __Pyx_dict_iter_next(PyObject* dict_or_iter, Py_ssize_t
/////////////// dict_iter /////////////// /////////////// dict_iter ///////////////
//@requires: ObjectHandling.c::UnpackTuple2 //@requires: ObjectHandling.c::UnpackTuple2
//@requires: ObjectHandling.c::IterFinish //@requires: ObjectHandling.c::IterFinish
//@requires: ObjectHandling.c::PyObjectCallMethod
static CYTHON_INLINE PyObject* __Pyx_dict_iterator(PyObject* iterable, int is_dict, PyObject* method_name, static CYTHON_INLINE PyObject* __Pyx_dict_iterator(PyObject* iterable, int is_dict, PyObject* method_name,
Py_ssize_t* p_orig_length, int* p_source_is_dict) { Py_ssize_t* p_orig_length, int* p_source_is_dict) {
...@@ -426,7 +421,7 @@ static CYTHON_INLINE PyObject* __Pyx_dict_iterator(PyObject* iterable, int is_di ...@@ -426,7 +421,7 @@ static CYTHON_INLINE PyObject* __Pyx_dict_iterator(PyObject* iterable, int is_di
*p_orig_length = 0; *p_orig_length = 0;
if (method_name) { if (method_name) {
PyObject* iter; PyObject* iter;
iterable = PyObject_CallMethodObjArgs(iterable, method_name, NULL); iterable = __Pyx_PyObject_CallMethod0(iterable, method_name);
if (!iterable) if (!iterable)
return NULL; return NULL;
#if !CYTHON_COMPILING_IN_PYPY #if !CYTHON_COMPILING_IN_PYPY
......
...@@ -17,6 +17,22 @@ def test(dict d, index): ...@@ -17,6 +17,22 @@ def test(dict d, index):
Traceback (most recent call last): Traceback (most recent call last):
KeyError: (1, 2) KeyError: (1, 2)
>>> import sys
>>> try: d[(1,)]
... except KeyError:
... args = sys.exc_info()[1].args
... if sys.version_info >= (2,5): print(args)
... else: print((args,)) # fake it for older CPython versions
((1,),)
>>> import sys
>>> try: test(d, (1,))
... except KeyError:
... args = sys.exc_info()[1].args
... if sys.version_info >= (2,5): print(args)
... else: print((args,)) # fake it for older CPython versions
((1,),)
>>> class Unhashable: >>> class Unhashable:
... def __hash__(self): ... def __hash__(self):
... raise ValueError ... raise ValueError
......
...@@ -11,6 +11,17 @@ class Hashable(object): ...@@ -11,6 +11,17 @@ class Hashable(object):
def __eq__(self, other): def __eq__(self, other):
return isinstance(other, Hashable) return isinstance(other, Hashable)
class CountedHashable(object):
def __init__(self):
self.hash_count = 0
self.eq_count = 0
def __hash__(self):
self.hash_count += 1
return 42
def __eq__(self, other):
self.eq_count += 1
return id(self) == id(other)
@cython.test_fail_if_path_exists('//AttributeNode') @cython.test_fail_if_path_exists('//AttributeNode')
@cython.test_assert_path_exists('//PythonCapiCallNode') @cython.test_assert_path_exists('//PythonCapiCallNode')
@cython.locals(d=dict) @cython.locals(d=dict)
...@@ -36,6 +47,23 @@ def setdefault1(d, key): ...@@ -36,6 +47,23 @@ def setdefault1(d, key):
>>> len(d) >>> len(d)
2 2
>>> d[Hashable()] >>> d[Hashable()]
# CPython's behaviour depends on version and py_debug setting, so just compare to it
>>> py_hashed1 = CountedHashable()
>>> y = {py_hashed1: 5}
>>> py_hashed2 = CountedHashable()
>>> y.setdefault(py_hashed2)
>>> cy_hashed1 = CountedHashable()
>>> y = {cy_hashed1: 5}
>>> cy_hashed2 = CountedHashable()
>>> setdefault1(y, cy_hashed2)
>>> py_hashed1.hash_count - cy_hashed1.hash_count
0
>>> py_hashed2.hash_count - cy_hashed2.hash_count
0
>>> (py_hashed1.eq_count + py_hashed2.eq_count) - (cy_hashed1.eq_count + cy_hashed2.eq_count)
0
""" """
return d.setdefault(key) return d.setdefault(key)
...@@ -72,5 +100,24 @@ def setdefault2(d, key, value): ...@@ -72,5 +100,24 @@ def setdefault2(d, key, value):
3 3
>>> d[Hashable()] >>> d[Hashable()]
55 55
# CPython's behaviour depends on version and py_debug setting, so just compare to it
>>> py_hashed1 = CountedHashable()
>>> y = {py_hashed1: 5}
>>> py_hashed2 = CountedHashable()
>>> y.setdefault(py_hashed2, [])
[]
>>> cy_hashed1 = CountedHashable()
>>> y = {cy_hashed1: 5}
>>> cy_hashed2 = CountedHashable()
>>> setdefault2(y, cy_hashed2, [])
[]
>>> py_hashed1.hash_count - cy_hashed1.hash_count
0
>>> py_hashed2.hash_count - cy_hashed2.hash_count
0
>>> (py_hashed1.eq_count + py_hashed2.eq_count) - (cy_hashed1.eq_count + cy_hashed2.eq_count)
0
""" """
return d.setdefault(key, value) return d.setdefault(key, value)
...@@ -24,7 +24,6 @@ def simple_pop(L): ...@@ -24,7 +24,6 @@ def simple_pop(L):
[] []
>>> simple_pop(L) >>> simple_pop(L)
Traceback (most recent call last): Traceback (most recent call last):
...
IndexError: pop from empty list IndexError: pop from empty list
>>> simple_pop(A()) >>> simple_pop(A())
...@@ -50,7 +49,6 @@ def simple_pop_typed(list L): ...@@ -50,7 +49,6 @@ def simple_pop_typed(list L):
[] []
>>> simple_pop_typed(L) >>> simple_pop_typed(L)
Traceback (most recent call last): Traceback (most recent call last):
...
IndexError: pop from empty list IndexError: pop from empty list
""" """
return L.pop() return L.pop()
...@@ -63,17 +61,18 @@ def index_pop(L, int i): ...@@ -63,17 +61,18 @@ def index_pop(L, int i):
>>> L = list(range(10)) >>> L = list(range(10))
>>> index_pop(L, 2) >>> index_pop(L, 2)
2 2
>>> index_pop(L, -10)
Traceback (most recent call last):
IndexError: pop index out of range
>>> index_pop(L, -2) >>> index_pop(L, -2)
8 8
>>> L >>> L
[0, 1, 3, 4, 5, 6, 7, 9] [0, 1, 3, 4, 5, 6, 7, 9]
>>> index_pop(L, 100) >>> index_pop(L, 100)
Traceback (most recent call last): Traceback (most recent call last):
...
IndexError: pop index out of range IndexError: pop index out of range
>>> index_pop(L, -100) >>> index_pop(L, -100)
Traceback (most recent call last): Traceback (most recent call last):
...
IndexError: pop index out of range IndexError: pop index out of range
>>> while L: >>> while L:
...@@ -84,7 +83,6 @@ def index_pop(L, int i): ...@@ -84,7 +83,6 @@ def index_pop(L, int i):
>>> index_pop(L, 0) >>> index_pop(L, 0)
Traceback (most recent call last): Traceback (most recent call last):
...
IndexError: pop from empty list IndexError: pop from empty list
>>> index_pop(A(), 3) >>> index_pop(A(), 3)
...@@ -105,11 +103,9 @@ def index_pop_typed(list L, int i): ...@@ -105,11 +103,9 @@ def index_pop_typed(list L, int i):
[0, 1, 3, 4, 5, 6, 7, 9] [0, 1, 3, 4, 5, 6, 7, 9]
>>> index_pop_typed(L, 100) >>> index_pop_typed(L, 100)
Traceback (most recent call last): Traceback (most recent call last):
...
IndexError: pop index out of range IndexError: pop index out of range
>>> index_pop_typed(L, -100) >>> index_pop_typed(L, -100)
Traceback (most recent call last): Traceback (most recent call last):
...
IndexError: pop index out of range IndexError: pop index out of range
>>> while L: >>> while L:
...@@ -120,7 +116,6 @@ def index_pop_typed(list L, int i): ...@@ -120,7 +116,6 @@ def index_pop_typed(list L, int i):
>>> index_pop_typed(L, 0) >>> index_pop_typed(L, 0)
Traceback (most recent call last): Traceback (most recent call last):
...
IndexError: pop from empty list IndexError: pop from empty list
""" """
return L.pop(i) return L.pop(i)
...@@ -143,7 +138,6 @@ def index_pop_literal(list L): ...@@ -143,7 +138,6 @@ def index_pop_literal(list L):
>>> index_pop_literal(L) >>> index_pop_literal(L)
Traceback (most recent call last): Traceback (most recent call last):
...
IndexError: pop from empty list IndexError: pop from empty list
""" """
return L.pop(0) return L.pop(0)
......
...@@ -526,11 +526,6 @@ def test_broken_getattr_handling(): ...@@ -526,11 +526,6 @@ def test_broken_getattr_handling():
def __getattr__(self, attr): def __getattr__(self, attr):
1/0 1/0
if sys.version_info >= (3,3):
expected_exception = ZeroDivisionError
else:
expected_exception = AttributeError
def g(): def g():
yield from Broken() yield from Broken()
...@@ -539,7 +534,7 @@ def test_broken_getattr_handling(): ...@@ -539,7 +534,7 @@ def test_broken_getattr_handling():
gi = g() gi = g()
assert next(gi) == 1 assert next(gi) == 1
gi.send(1) gi.send(1)
except expected_exception: except ZeroDivisionError:
pass pass
else: else:
not_raised.append(1) not_raised.append(1)
......
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