Mercurial > cpython-lru_cache-weakref
view Objects/rangeobject.c @ 66978:aed2bbafa550 3.1
Blocked revisions 87324 via svnmerge
........
r87324 | r.david.murray | 2010-12-16 14:08:51 -0500 (Thu, 16 Dec 2010) | 9 lines
#10719: restore messages generated on invalid compileall args
Before the introduction of filename arguments to compileall it gave semi useful
messages about not being able to 'list' names that weren't valid directories.
This fix restores that behavior. In addition to the test for this case, the
patch also adds a test for the default behavior of compileall when no arguments
are provided, and fixes a bug in one of the previously added tests.
........
| author | R. David Murray <rdmurray@bitdance.com> |
|---|---|
| date | Thu, 16 Dec 2010 19:10:16 +0000 |
| parents | f197407bdba2 |
| children | 3c9232a684ae |
line wrap: on
line source
/* Range object implementation */ #include "Python.h" /* Support objects whose length is > PY_SSIZE_T_MAX. This could be sped up for small PyLongs if they fit in an Py_ssize_t. This only matters on Win64. Though we could use PY_LONG_LONG which would presumably help perf. */ typedef struct { PyObject_HEAD PyObject *start; PyObject *stop; PyObject *step; } rangeobject; /* Helper function for validating step. Always returns a new reference or NULL on error. */ static PyObject * validate_step(PyObject *step) { /* No step specified, use a step of 1. */ if (!step) return PyLong_FromLong(1); step = PyNumber_Index(step); if (step) { Py_ssize_t istep = PyNumber_AsSsize_t(step, NULL); if (istep == -1 && PyErr_Occurred()) { /* Ignore OverflowError, we know the value isn't 0. */ PyErr_Clear(); } else if (istep == 0) { PyErr_SetString(PyExc_ValueError, "range() arg 3 must not be zero"); Py_CLEAR(step); } } return step; } /* XXX(nnorwitz): should we error check if the user passes any empty ranges? range(-10) range(0, -5) range(0, 5, -1) */ static PyObject * range_new(PyTypeObject *type, PyObject *args, PyObject *kw) { rangeobject *obj = NULL; PyObject *start = NULL, *stop = NULL, *step = NULL; if (!_PyArg_NoKeywords("range()", kw)) return NULL; if (PyTuple_Size(args) <= 1) { if (!PyArg_UnpackTuple(args, "range", 1, 1, &stop)) return NULL; stop = PyNumber_Index(stop); if (!stop) return NULL; start = PyLong_FromLong(0); if (!start) { Py_DECREF(stop); return NULL; } step = PyLong_FromLong(1); if (!step) { Py_DECREF(stop); Py_DECREF(start); return NULL; } } else { if (!PyArg_UnpackTuple(args, "range", 2, 3, &start, &stop, &step)) return NULL; /* Convert borrowed refs to owned refs */ start = PyNumber_Index(start); if (!start) return NULL; stop = PyNumber_Index(stop); if (!stop) { Py_DECREF(start); return NULL; } step = validate_step(step); /* Caution, this can clear exceptions */ if (!step) { Py_DECREF(start); Py_DECREF(stop); return NULL; } } obj = PyObject_New(rangeobject, &PyRange_Type); if (obj == NULL) goto Fail; obj->start = start; obj->stop = stop; obj->step = step; return (PyObject *) obj; Fail: Py_XDECREF(start); Py_XDECREF(stop); Py_XDECREF(step); return NULL; } PyDoc_STRVAR(range_doc, "range([start,] stop[, step]) -> range object\n\ \n\ Returns an iterator that generates the numbers in the range on demand."); static void range_dealloc(rangeobject *r) { Py_DECREF(r->start); Py_DECREF(r->stop); Py_DECREF(r->step); PyObject_Del(r); } /* Return number of items in range (lo, hi, step) as a PyLong object, * when arguments are PyLong objects. Arguments MUST return 1 with * PyLong_Check(). Return NULL when there is an error. */ static PyObject* range_length_obj(rangeobject *r) { /* ------------------------------------------------------------- Algorithm is equal to that of get_len_of_range(), but it operates on PyObjects (which are assumed to be PyLong objects). ---------------------------------------------------------------*/ int cmp_result; PyObject *lo, *hi; PyObject *step = NULL; PyObject *diff = NULL; PyObject *one = NULL; PyObject *tmp1 = NULL, *tmp2 = NULL, *result; /* holds sub-expression evaluations */ PyObject *zero = PyLong_FromLong(0); if (zero == NULL) return NULL; cmp_result = PyObject_RichCompareBool(r->step, zero, Py_GT); Py_DECREF(zero); if (cmp_result == -1) return NULL; if (cmp_result == 1) { lo = r->start; hi = r->stop; step = r->step; Py_INCREF(step); } else { lo = r->stop; hi = r->start; step = PyNumber_Negative(r->step); if (!step) return NULL; } /* if (lo >= hi), return length of 0. */ if (PyObject_RichCompareBool(lo, hi, Py_GE) == 1) { Py_XDECREF(step); return PyLong_FromLong(0); } if ((one = PyLong_FromLong(1L)) == NULL) goto Fail; if ((tmp1 = PyNumber_Subtract(hi, lo)) == NULL) goto Fail; if ((diff = PyNumber_Subtract(tmp1, one)) == NULL) goto Fail; if ((tmp2 = PyNumber_FloorDivide(diff, step)) == NULL) goto Fail; if ((result = PyNumber_Add(tmp2, one)) == NULL) goto Fail; Py_DECREF(tmp2); Py_DECREF(diff); Py_DECREF(step); Py_DECREF(tmp1); Py_DECREF(one); return result; Fail: Py_XDECREF(tmp2); Py_XDECREF(diff); Py_XDECREF(step); Py_XDECREF(tmp1); Py_XDECREF(one); return NULL; } static Py_ssize_t range_length(rangeobject *r) { PyObject *len = range_length_obj(r); Py_ssize_t result = -1; if (len) { result = PyLong_AsSsize_t(len); Py_DECREF(len); } return result; } /* range(...)[x] is necessary for: seq[:] = range(...) */ static PyObject * range_item(rangeobject *r, Py_ssize_t i) { Py_ssize_t len = range_length(r); PyObject *rem, *incr, *result; /* XXX(nnorwitz): should negative indices be supported? */ /* XXX(nnorwitz): should support range[x] where x > PY_SSIZE_T_MAX? */ if (i < 0 || i >= len) { if (!PyErr_Occurred()) PyErr_SetString(PyExc_IndexError, "range object index out of range"); return NULL; } /* XXX(nnorwitz): optimize for short ints. */ rem = PyLong_FromSsize_t(i); if (!rem) return NULL; incr = PyNumber_Multiply(rem, r->step); Py_DECREF(rem); if (!incr) return NULL; result = PyNumber_Add(r->start, incr); Py_DECREF(incr); return result; } static PyObject * range_repr(rangeobject *r) { Py_ssize_t istep; /* Check for special case values for printing. We don't always need the step value. We don't care about errors (it means overflow), so clear the errors. */ istep = PyNumber_AsSsize_t(r->step, NULL); if (istep != 1 || (istep == -1 && PyErr_Occurred())) { PyErr_Clear(); } if (istep == 1) return PyUnicode_FromFormat("range(%R, %R)", r->start, r->stop); else return PyUnicode_FromFormat("range(%R, %R, %R)", r->start, r->stop, r->step); } /* Pickling support */ static PyObject * range_reduce(rangeobject *r, PyObject *args) { return Py_BuildValue("(O(OOO))", Py_TYPE(r), r->start, r->stop, r->step); } static PySequenceMethods range_as_sequence = { (lenfunc)range_length, /* sq_length */ 0, /* sq_concat */ 0, /* sq_repeat */ (ssizeargfunc)range_item, /* sq_item */ 0, /* sq_slice */ }; static PyObject * range_iter(PyObject *seq); static PyObject * range_reverse(PyObject *seq); PyDoc_STRVAR(reverse_doc, "Returns a reverse iterator."); static PyMethodDef range_methods[] = { {"__reversed__", (PyCFunction)range_reverse, METH_NOARGS, reverse_doc}, {"__reduce__", (PyCFunction)range_reduce, METH_VARARGS}, {NULL, NULL} /* sentinel */ }; PyTypeObject PyRange_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "range", /* Name of this type */ sizeof(rangeobject), /* Basic object size */ 0, /* Item size for varobject */ (destructor)range_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_reserved */ (reprfunc)range_repr, /* tp_repr */ 0, /* tp_as_number */ &range_as_sequence, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ range_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ range_iter, /* tp_iter */ 0, /* tp_iternext */ range_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ range_new, /* tp_new */ }; /*********************** range Iterator **************************/ /* There are 2 types of iterators, one for C longs, the other for Python longs (ie, PyObjects). This should make iteration fast in the normal case, but possible for any numeric value. */ typedef struct { PyObject_HEAD long index; long start; long step; long len; } rangeiterobject; static PyObject * rangeiter_next(rangeiterobject *r) { if (r->index < r->len) /* cast to unsigned to avoid possible signed overflow in intermediate calculations. */ return PyLong_FromLong((long)(r->start + (unsigned long)(r->index++) * r->step)); return NULL; } static PyObject * rangeiter_len(rangeiterobject *r) { return PyLong_FromLong(r->len - r->index); } typedef struct { PyObject_HEAD PyObject *index; PyObject *start; PyObject *step; PyObject *len; } longrangeiterobject; static PyObject * longrangeiter_len(longrangeiterobject *r, PyObject *no_args) { return PyNumber_Subtract(r->len, r->index); } static PyObject *rangeiter_new(PyTypeObject *, PyObject *args, PyObject *kw); PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it))."); static PyMethodDef rangeiter_methods[] = { {"__length_hint__", (PyCFunction)rangeiter_len, METH_NOARGS, length_hint_doc}, {NULL, NULL} /* sentinel */ }; PyTypeObject PyRangeIter_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "range_iterator", /* tp_name */ sizeof(rangeiterobject), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)PyObject_Del, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_reserved */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ 0, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ PyObject_SelfIter, /* tp_iter */ (iternextfunc)rangeiter_next, /* tp_iternext */ rangeiter_methods, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ rangeiter_new, /* tp_new */ }; /* Return number of items in range (lo, hi, step). step != 0 * required. The result always fits in an unsigned long. */ static unsigned long get_len_of_range(long lo, long hi, long step) { /* ------------------------------------------------------------- If step > 0 and lo >= hi, or step < 0 and lo <= hi, the range is empty. Else for step > 0, if n values are in the range, the last one is lo + (n-1)*step, which must be <= hi-1. Rearranging, n <= (hi - lo - 1)/step + 1, so taking the floor of the RHS gives the proper value. Since lo < hi in this case, hi-lo-1 >= 0, so the RHS is non-negative and so truncation is the same as the floor. Letting M be the largest positive long, the worst case for the RHS numerator is hi=M, lo=-M-1, and then hi-lo-1 = M-(-M-1)-1 = 2*M. Therefore unsigned long has enough precision to compute the RHS exactly. The analysis for step < 0 is similar. ---------------------------------------------------------------*/ assert(step != 0); if (step > 0 && lo < hi) return 1UL + (hi - 1UL - lo) / step; else if (step < 0 && lo > hi) return 1UL + (lo - 1UL - hi) / (0UL - step); else return 0UL; } /* Initialize a rangeiter object. If the length of the rangeiter object is not representable as a C long, OverflowError is raised. */ static PyObject * int_range_iter(long start, long stop, long step) { rangeiterobject *it = PyObject_New(rangeiterobject, &PyRangeIter_Type); unsigned long ulen; if (it == NULL) return NULL; it->start = start; it->step = step; ulen = get_len_of_range(start, stop, step); if (ulen > (unsigned long)LONG_MAX) { Py_DECREF(it); PyErr_SetString(PyExc_OverflowError, "range too large to represent as a range_iterator"); return NULL; } it->len = (long)ulen; it->index = 0; return (PyObject *)it; } static PyObject * rangeiter_new(PyTypeObject *type, PyObject *args, PyObject *kw) { long start, stop, step; if (!_PyArg_NoKeywords("rangeiter()", kw)) return NULL; if (!PyArg_ParseTuple(args, "lll;rangeiter() requires 3 int arguments", &start, &stop, &step)) return NULL; return int_range_iter(start, stop, step); } static PyMethodDef longrangeiter_methods[] = { {"__length_hint__", (PyCFunction)longrangeiter_len, METH_NOARGS, length_hint_doc}, {NULL, NULL} /* sentinel */ }; static void longrangeiter_dealloc(longrangeiterobject *r) { Py_XDECREF(r->index); Py_XDECREF(r->start); Py_XDECREF(r->step); Py_XDECREF(r->len); PyObject_Del(r); } static PyObject * longrangeiter_next(longrangeiterobject *r) { PyObject *one, *product, *new_index, *result; if (PyObject_RichCompareBool(r->index, r->len, Py_LT) != 1) return NULL; one = PyLong_FromLong(1); if (!one) return NULL; new_index = PyNumber_Add(r->index, one); Py_DECREF(one); if (!new_index) return NULL; product = PyNumber_Multiply(r->index, r->step); if (!product) { Py_DECREF(new_index); return NULL; } result = PyNumber_Add(r->start, product); Py_DECREF(product); if (result) { Py_DECREF(r->index); r->index = new_index; } else { Py_DECREF(new_index); } return result; } PyTypeObject PyLongRangeIter_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "longrange_iterator", /* tp_name */ sizeof(longrangeiterobject), /* tp_basicsize */ 0, /* tp_itemsize */ /* methods */ (destructor)longrangeiter_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_reserved */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ PyObject_GenericGetAttr, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ 0, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ PyObject_SelfIter, /* tp_iter */ (iternextfunc)longrangeiter_next, /* tp_iternext */ longrangeiter_methods, /* tp_methods */ 0, }; static PyObject * range_iter(PyObject *seq) { rangeobject *r = (rangeobject *)seq; longrangeiterobject *it; long lstart, lstop, lstep; PyObject *int_it; assert(PyRange_Check(seq)); /* If all three fields and the length convert to long, use the int * version */ lstart = PyLong_AsLong(r->start); if (lstart == -1 && PyErr_Occurred()) { PyErr_Clear(); goto long_range; } lstop = PyLong_AsLong(r->stop); if (lstop == -1 && PyErr_Occurred()) { PyErr_Clear(); goto long_range; } lstep = PyLong_AsLong(r->step); if (lstep == -1 && PyErr_Occurred()) { PyErr_Clear(); goto long_range; } int_it = int_range_iter(lstart, lstop, lstep); if (int_it == NULL && PyErr_ExceptionMatches(PyExc_OverflowError)) { PyErr_Clear(); goto long_range; } return (PyObject *)int_it; long_range: it = PyObject_New(longrangeiterobject, &PyLongRangeIter_Type); if (it == NULL) return NULL; /* Do all initialization here, so we can DECREF on failure. */ it->start = r->start; it->step = r->step; Py_INCREF(it->start); Py_INCREF(it->step); it->len = it->index = NULL; it->len = range_length_obj(r); if (!it->len) goto create_failure; it->index = PyLong_FromLong(0); if (!it->index) goto create_failure; return (PyObject *)it; create_failure: Py_DECREF(it); return NULL; } static PyObject * range_reverse(PyObject *seq) { rangeobject *range = (rangeobject*) seq; longrangeiterobject *it; PyObject *one, *sum, *diff, *len = NULL, *product; long lstart, lstop, lstep, new_start, new_stop; unsigned long ulen; assert(PyRange_Check(seq)); /* reversed(range(start, stop, step)) can be expressed as range(start+(n-1)*step, start-step, -step), where n is the number of integers in the range. If each of start, stop, step, -step, start-step, and the length of the iterator is representable as a C long, use the int version. This excludes some cases where the reversed range is representable as a range_iterator, but it's good enough for common cases and it makes the checks simple. */ lstart = PyLong_AsLong(range->start); if (lstart == -1 && PyErr_Occurred()) { PyErr_Clear(); goto long_range; } lstop = PyLong_AsLong(range->stop); if (lstop == -1 && PyErr_Occurred()) { PyErr_Clear(); goto long_range; } lstep = PyLong_AsLong(range->step); if (lstep == -1 && PyErr_Occurred()) { PyErr_Clear(); goto long_range; } /* check for possible overflow of -lstep */ if (lstep == LONG_MIN) goto long_range; /* check for overflow of lstart - lstep: for lstep > 0, need only check whether lstart - lstep < LONG_MIN. for lstep < 0, need only check whether lstart - lstep > LONG_MAX Rearrange these inequalities as: lstart - LONG_MIN < lstep (lstep > 0) LONG_MAX - lstart < -lstep (lstep < 0) and compute both sides as unsigned longs, to avoid the possibility of undefined behaviour due to signed overflow. */ if (lstep > 0) { if ((unsigned long)lstart - LONG_MIN < (unsigned long)lstep) goto long_range; } else { if (LONG_MAX - (unsigned long)lstart < 0UL - lstep) goto long_range; } ulen = get_len_of_range(lstart, lstop, lstep); if (ulen > (unsigned long)LONG_MAX) goto long_range; new_stop = lstart - lstep; new_start = (long)(new_stop + ulen * lstep); return int_range_iter(new_start, new_stop, -lstep); long_range: it = PyObject_New(longrangeiterobject, &PyLongRangeIter_Type); if (it == NULL) return NULL; /* start + (len - 1) * step */ len = range_length_obj(range); if (!len) goto create_failure; /* Steal reference to len. */ it->len = len; one = PyLong_FromLong(1); if (!one) goto create_failure; diff = PyNumber_Subtract(len, one); Py_DECREF(one); if (!diff) goto create_failure; product = PyNumber_Multiply(diff, range->step); Py_DECREF(diff); if (!product) goto create_failure; sum = PyNumber_Add(range->start, product); Py_DECREF(product); it->start = sum; if (!it->start) goto create_failure; it->step = PyNumber_Negative(range->step); if (!it->step) goto create_failure; it->index = PyLong_FromLong(0); if (!it->index) goto create_failure; return (PyObject *)it; create_failure: Py_DECREF(it); return NULL; }
