def _PyTuple_Resize(space, p_ref, newsize): """Can be used to resize a tuple. newsize will be the new length of the tuple. Because tuples are supposed to be immutable, this should only be used if there is only one reference to the object. Do not use this if the tuple may already be known to some other part of the code. The tuple will always grow or shrink at the end. Think of this as destroying the old tuple and creating a new one, only more efficiently. Returns 0 on success. Client code should never assume that the resulting value of *p will be the same as before calling this function. If the object referenced by *p is replaced, the original *p is destroyed. On failure, returns -1 and sets *p to NULL, and raises MemoryError or SystemError.""" ref = p_ref[0] if not tuple_check_ref(space, ref): PyErr_BadInternalCall(space) oldref = rffi.cast(PyTupleObject, ref) oldsize = oldref.c_ob_size p_ref[0] = new_empty_tuple(space, newsize) newref = rffi.cast(PyTupleObject, p_ref[0]) try: if oldsize < newsize: to_cp = oldsize else: to_cp = newsize for i in range(to_cp): ob = oldref.c_ob_item[i] incref(space, ob) newref.c_ob_item[i] = ob except: decref(space, p_ref[0]) p_ref[0] = lltype.nullptr(PyObject.TO) raise finally: decref(space, ref) return 0
def _PyTuple_Resize(space, p_ref, newsize): """Can be used to resize a tuple. newsize will be the new length of the tuple. Because tuples are supposed to be immutable, this should only be used if there is only one reference to the object. Do not use this if the tuple may already be known to some other part of the code. The tuple will always grow or shrink at the end. Think of this as destroying the old tuple and creating a new one, only more efficiently. Returns 0 on success. Client code should never assume that the resulting value of *p will be the same as before calling this function. If the object referenced by *p is replaced, the original *p is destroyed. On failure, returns -1 and sets *p to NULL, and raises MemoryError or SystemError.""" ref = p_ref[0] if not tuple_check_ref(space, ref): PyErr_BadInternalCall(space) oldref = rffi.cast(PyTupleObject, ref) oldsize = oldref.c_ob_size p_ref[0] = new_empty_tuple(space, newsize) newref = rffi.cast(PyTupleObject, p_ref[0]) try: if oldsize < newsize: to_cp = oldsize else: to_cp = newsize for i in range(to_cp): ob = oldref.c_ob_item[i] incref(space, ob) newref.c_ob_item[i] = ob except: decref(space, p_ref[0]) p_ref[0] = lltype.nullptr(PyObject.TO) raise finally: decref(space, ref) return 0
def PyBuffer_FillInfo(space, view, obj, buf, length, readonly, flags): """ Fills in a buffer-info structure correctly for an exporter that can only share a contiguous chunk of memory of "unsigned bytes" of the given length. Returns 0 on success and -1 (with raising an error) on error. """ flags = widen(flags) if flags & PyBUF_WRITABLE and readonly: raise oefmt(space.w_ValueError, "Object is not writable") view.c_buf = buf view.c_len = length view.c_obj = obj if obj: incref(space, obj) view.c_itemsize = 1 rffi.setintfield(view, 'c_readonly', readonly) rffi.setintfield(view, 'c_ndim', 1) view.c_format = lltype.nullptr(rffi.CCHARP.TO) if (flags & PyBUF_FORMAT) == PyBUF_FORMAT: # NB: this needs to be a static string, because nothing frees it view.c_format = DEFAULT_FMT view.c_shape = lltype.nullptr(Py_ssize_tP.TO) if (flags & PyBUF_ND) == PyBUF_ND: view.c_shape = rffi.cast(Py_ssize_tP, view.c__shape) view.c_shape[0] = view.c_len view.c_strides = lltype.nullptr(Py_ssize_tP.TO) if (flags & PyBUF_STRIDES) == PyBUF_STRIDES: view.c_strides = rffi.cast(Py_ssize_tP, view.c__strides) view.c_strides[0] = view.c_itemsize view.c_suboffsets = lltype.nullptr(Py_ssize_tP.TO) view.c_internal = lltype.nullptr(rffi.VOIDP.TO) return 0
def PySequence_ITEM(space, w_obj, i): """Return the ith element of o or NULL on failure. Macro form of PySequence_GetItem() but without checking that PySequence_Check(o)() is true and without adjustment for negative indices. This function used an int type for i. This might require changes in your code for properly supporting 64-bit systems.""" # XXX we should call Py*_GET_ITEM() instead of Py*_GetItem() # from here, but we cannot because we are also called from # PySequence_GetItem() py_obj = as_pyobj(space, w_obj) if isinstance(w_obj, tupleobject.W_TupleObject): from pypy.module.cpyext.tupleobject import PyTuple_GetItem py_res = PyTuple_GetItem(space, py_obj, i) incref(space, py_res) keepalive_until_here(w_obj) return py_res if isinstance(w_obj, W_ListObject): from pypy.module.cpyext.listobject import PyList_GetItem py_res = PyList_GetItem(space, py_obj, i) incref(space, py_res) keepalive_until_here(w_obj) return py_res as_sequence = py_obj.c_ob_type.c_tp_as_sequence if not as_sequence or not as_sequence.c_sq_item: raise oefmt(space.w_TypeError, "'%T' object does not support indexing", w_obj) ret = generic_cpy_call(space, as_sequence.c_sq_item, w_obj, i) return make_ref(space, ret)
def _PySet_NextEntry(space, w_set, ppos, pkey, phash): if w_set is None or not PyAnySet_Check(space, w_set): PyErr_BadInternalCall(space) return -1 if not pkey: PyErr_BadInternalCall(space) return -1 pos = ppos[0] py_obj = as_pyobj(space, w_set) py_set = rffi.cast(PySetObject, py_obj) if pos == 0: # Store the current item list in the PySetObject. # w_keys must use the object strategy in order to keep the keys alive w_keys = space.newlist(space.listview(w_set)) w_keys.switch_to_object_strategy() oldlist = py_set.c__tmplist py_set.c__tmplist = create_ref(space, w_keys) incref(space, py_set.c__tmplist) decref(space, oldlist) else: if not py_set.c__tmplist: # pos should have been 0, cannot fail so return 0 return 0 w_keys = from_ref(space, py_set.c__tmplist) ppos[0] += 1 if pos >= space.len_w(w_keys): decref(space, py_set.c__tmplist) py_set.c__tmplist = lltype.nullptr(PyObject.TO) return 0 w_key = space.listview(w_keys)[pos] pkey[0] = as_pyobj(space, w_key) if phash: phash[0] = space.hash_w(w_key) return 1
def test_tupleobject_base(self, space): assert not PyTuple_Check(space, space.w_None) with raises_w(space, SystemError): n = make_ref(space, space.w_None) incref(space, n) PyTuple_SetItem(space, n, 0, n) atuple = space.newtuple( [space.wrap(0), space.wrap(1), space.wrap('yay')]) assert PyTuple_Size(space, atuple) == 3 with raises_w(space, SystemError): PyTuple_Size(space, space.newlist([]))
def PyDict_Next(space, w_dict, ppos, pkey, pvalue): """Iterate over all key-value pairs in the dictionary p. The Py_ssize_t referred to by ppos must be initialized to 0 prior to the first call to this function to start the iteration; the function returns true for each pair in the dictionary, and false once all pairs have been reported. The parameters pkey and pvalue should either point to PyObject* variables that will be filled in with each key and value, respectively, or may be NULL. Any references returned through them are borrowed. ppos should not be altered during iteration. Its value represents offsets within the internal dictionary structure, and since the structure is sparse, the offsets are not consecutive. For example: PyObject *key, *value; Py_ssize_t pos = 0; while (PyDict_Next(self->dict, &pos, &key, &value)) { /* do something interesting with the values... */ ... } The dictionary p should not be mutated during iteration. It is safe (since Python 2.1) to modify the values but not the keys as you iterate over the dictionary, the keys must not change. For example: PyObject *key, *value; Py_ssize_t pos = 0; while (PyDict_Next(self->dict, &pos, &key, &value)) { int i = PyInt_AS_LONG(value) + 1; PyObject *o = PyInt_FromLong(i); if (o == NULL) return -1; if (PyDict_SetItem(self->dict, key, o) < 0) { Py_DECREF(o); return -1; } Py_DECREF(o); }""" if w_dict is None: return 0 if not space.isinstance_w(w_dict, space.w_dict): return 0 pos = ppos[0] py_obj = as_pyobj(space, w_dict) py_dict = rffi.cast(PyDictObject, py_obj) if pos == 0: # Store the current keys in the PyDictObject. from pypy.objspace.std.listobject import W_ListObject decref(space, py_dict.c__tmpkeys) w_keys = space.call_method(space.w_dict, "keys", w_dict) # w_keys must use the object strategy in order to keep the keys alive if not isinstance(w_keys, W_ListObject): return 0 # XXX should not call keys() above w_keys.switch_to_object_strategy() py_dict.c__tmpkeys = create_ref(space, w_keys) incref(space, py_dict.c__tmpkeys) else: if not py_dict.c__tmpkeys: # pos should have been 0, cannot fail so return 0 return 0 w_keys = from_ref(space, py_dict.c__tmpkeys) ppos[0] += 1 if pos >= space.len_w(w_keys): decref(space, py_dict.c__tmpkeys) py_dict.c__tmpkeys = lltype.nullptr(PyObject.TO) return 0 w_key = space.listview(w_keys)[pos] # fast iff w_keys uses object strat w_value = space.getitem(w_dict, w_key) if pkey: pkey[0] = as_pyobj(space, w_key) if pvalue: pvalue[0] = as_pyobj(space, w_value) return 1
def PyObject_SelfIter(space, ref): """Undocumented function, this is what CPython does.""" incref(space, ref) return ref
def PyType_FromSpecWithBases(space, spec, bases): from pypy.module.cpyext.unicodeobject import PyUnicode_FromString state = space.fromcache(State) p_type = cts.cast('PyTypeObject*', make_ref(space, space.w_type)) res = state.ccall("PyType_GenericAlloc", p_type, 0) res = cts.cast('PyHeapTypeObject *', res) typ = res.c_ht_type typ.c_tp_flags = rffi.cast(lltype.Unsigned, spec.c_flags) typ.c_tp_flags |= Py_TPFLAGS_HEAPTYPE specname = rffi.charp2str(cts.cast('char*', spec.c_name)) dotpos = specname.rfind('.') if dotpos < 0: name = specname else: name = specname[dotpos + 1:] res.c_ht_name = make_ref(space, space.newtext(name)) res.c_ht_qualname = res.c_ht_name incref(space, res.c_ht_qualname) typ.c_tp_name = spec.c_name slotdefs = rffi.cast(rffi.CArrayPtr(cts.gettype('PyType_Slot')), spec.c_slots) if not bases: w_base = space.w_object bases_w = [] i = 0 while True: slotdef = slotdefs[i] slotnum = rffi.cast(lltype.Signed, slotdef.c_slot) if slotnum == 0: break elif slotnum == cts.macros['Py_tp_base']: w_base = from_ref(space, cts.cast('PyObject*', slotdef.c_pfunc)) elif slotnum == cts.macros['Py_tp_bases']: bases = cts.cast('PyObject*', slotdef.c_pfunc) bases_w = space.fixedview(from_ref(space, bases)) i += 1 if not bases_w: bases_w = [w_base] else: bases_w = space.fixedview(from_ref(space, bases)) w_base = best_base(space, bases_w) base = cts.cast('PyTypeObject*', make_ref(space, w_base)) if False: # not base.c_tp_flags & Py_TPFLAGS_BASETYPE: raise oefmt(space.w_TypeError, "type '%s' is not an acceptable base type", rffi.charp2str(base.c_tp_name)) typ.c_tp_as_async = res.c_as_async typ.c_tp_as_number = res.c_as_number typ.c_tp_as_sequence = res.c_as_sequence typ.c_tp_as_mapping = res.c_as_mapping typ.c_tp_as_buffer = res.c_as_buffer typ.c_tp_bases = bases typ.c_tp_base = base typ.c_tp_basicsize = cts.cast('Py_ssize_t', spec.c_basicsize) typ.c_tp_itemsize = cts.cast('Py_ssize_t', spec.c_itemsize) i = 0 while True: slotdef = slotdefs[i] slot = rffi.cast(lltype.Signed, slotdef.c_slot) if slot == 0: break if slot < 0: # or slot > len(slotoffsets): raise oefmt(space.w_RuntimeError, "invalid slot offset") if slot in (cts.macros['Py_tp_base'], cts.macros['Py_tp_bases']): # Processed above i += 1 continue fill_ht_slot(res, slot, slotdef.c_pfunc) # XXX: need to make a copy of the docstring slot, which usually # points to a static string literal i += 1 if not typ.c_tp_dealloc: typ.c_tp_dealloc = state.C._PyPy_subtype_dealloc py_type_ready(space, typ) return cts.cast('PyObject*', res)