@@ -273,58 +273,133 @@ range_reduce(rangeobject *r, PyObject *args)
273273 r -> start , r -> stop , r -> step );
274274}
275275
276+ /* Assumes (PyLong_CheckExact(ob) || PyBool_Check(ob)) */
277+ static int
278+ range_contains_long (rangeobject * r , PyObject * ob )
279+ {
280+ int cmp1 , cmp2 , cmp3 ;
281+ PyObject * tmp1 = NULL ;
282+ PyObject * tmp2 = NULL ;
283+ PyObject * zero = NULL ;
284+ int result = -1 ;
285+
286+ zero = PyLong_FromLong (0 );
287+ if (zero == NULL ) /* MemoryError in int(0) */
288+ goto end ;
289+
290+ /* Check if the value can possibly be in the range. */
291+
292+ cmp1 = PyObject_RichCompareBool (r -> step , zero , Py_GT );
293+ if (cmp1 == -1 )
294+ goto end ;
295+ if (cmp1 == 1 ) { /* positive steps: start <= ob < stop */
296+ cmp2 = PyObject_RichCompareBool (r -> start , ob , Py_LE );
297+ cmp3 = PyObject_RichCompareBool (ob , r -> stop , Py_LT );
298+ }
299+ else { /* negative steps: stop < ob <= start */
300+ cmp2 = PyObject_RichCompareBool (ob , r -> start , Py_LE );
301+ cmp3 = PyObject_RichCompareBool (r -> stop , ob , Py_LT );
302+ }
303+
304+ if (cmp2 == -1 || cmp3 == -1 ) /* TypeError */
305+ goto end ;
306+ if (cmp2 == 0 || cmp3 == 0 ) { /* ob outside of range */
307+ result = 0 ;
308+ goto end ;
309+ }
310+
311+ /* Check that the stride does not invalidate ob's membership. */
312+ tmp1 = PyNumber_Subtract (ob , r -> start );
313+ if (tmp1 == NULL )
314+ goto end ;
315+ tmp2 = PyNumber_Remainder (tmp1 , r -> step );
316+ if (tmp2 == NULL )
317+ goto end ;
318+ /* result = (int(ob) - start % step) == 0 */
319+ result = PyObject_RichCompareBool (tmp2 , zero , Py_EQ );
320+ end :
321+ Py_XDECREF (tmp1 );
322+ Py_XDECREF (tmp2 );
323+ Py_XDECREF (zero );
324+ return result ;
325+ }
326+
276327static int
277328range_contains (rangeobject * r , PyObject * ob ) {
329+ if (PyLong_CheckExact (ob ) || PyBool_Check (ob ))
330+ return range_contains_long (r , ob );
331+
332+ return (int )_PySequence_IterSearch ((PyObject * )r , ob ,
333+ PY_ITERSEARCH_CONTAINS );
334+ }
335+
336+ static PyObject *
337+ range_count (rangeobject * r , PyObject * ob )
338+ {
278339 if (PyLong_CheckExact (ob ) || PyBool_Check (ob )) {
279- int cmp1 , cmp2 , cmp3 ;
280- PyObject * tmp1 = NULL ;
281- PyObject * tmp2 = NULL ;
282- PyObject * zero = NULL ;
283- int result = -1 ;
284-
285- zero = PyLong_FromLong (0 );
286- if (zero == NULL ) /* MemoryError in int(0) */
287- goto end ;
288-
289- /* Check if the value can possibly be in the range. */
290-
291- cmp1 = PyObject_RichCompareBool (r -> step , zero , Py_GT );
292- if (cmp1 == -1 )
293- goto end ;
294- if (cmp1 == 1 ) { /* positive steps: start <= ob < stop */
295- cmp2 = PyObject_RichCompareBool (r -> start , ob , Py_LE );
296- cmp3 = PyObject_RichCompareBool (ob , r -> stop , Py_LT );
297- }
298- else { /* negative steps: stop < ob <= start */
299- cmp2 = PyObject_RichCompareBool (ob , r -> start , Py_LE );
300- cmp3 = PyObject_RichCompareBool (r -> stop , ob , Py_LT );
301- }
340+ if (range_contains_long (r , ob ))
341+ Py_RETURN_TRUE ;
342+ else
343+ Py_RETURN_FALSE ;
344+ } else {
345+ Py_ssize_t count ;
346+ count = _PySequence_IterSearch ((PyObject * )r , ob , PY_ITERSEARCH_COUNT );
347+ if (count == -1 )
348+ return NULL ;
349+ return PyLong_FromSsize_t (count );
350+ }
351+ }
302352
303- if (cmp2 == -1 || cmp3 == -1 ) /* TypeError */
304- goto end ;
305- if (cmp2 == 0 || cmp3 == 0 ) { /* ob outside of range */
306- result = 0 ;
307- goto end ;
308- }
353+ static PyObject *
354+ range_index (rangeobject * r , PyObject * ob )
355+ {
356+ PyObject * idx , * tmp ;
357+ int contains ;
358+ PyObject * format_tuple , * err_string ;
359+ static PyObject * err_format = NULL ;
360+
361+ if (!PyLong_CheckExact (ob ) && !PyBool_Check (ob )) {
362+ Py_ssize_t index ;
363+ index = _PySequence_IterSearch ((PyObject * )r , ob , PY_ITERSEARCH_INDEX );
364+ if (index == -1 )
365+ return NULL ;
366+ return PyLong_FromSsize_t (index );
367+ }
368+
369+ contains = range_contains_long (r , ob );
370+ if (contains == -1 )
371+ return NULL ;
372+
373+ if (!contains )
374+ goto value_error ;
375+
376+ tmp = PyNumber_Subtract (ob , r -> start );
377+ if (tmp == NULL )
378+ return NULL ;
379+
380+ /* idx = (ob - r.start) // r.step */
381+ idx = PyNumber_FloorDivide (tmp , r -> step );
382+ Py_DECREF (tmp );
383+ return idx ;
384+
385+ value_error :
309386
310- /* Check that the stride does not invalidate ob's membership. */
311- tmp1 = PyNumber_Subtract (ob , r -> start );
312- if (tmp1 == NULL )
313- goto end ;
314- tmp2 = PyNumber_Remainder (tmp1 , r -> step );
315- if (tmp2 == NULL )
316- goto end ;
317- /* result = (int(ob) - start % step) == 0 */
318- result = PyObject_RichCompareBool (tmp2 , zero , Py_EQ );
319- end :
320- Py_XDECREF (tmp1 );
321- Py_XDECREF (tmp2 );
322- Py_XDECREF (zero );
323- return result ;
387+ /* object is not in the range */
388+ if (err_format == NULL ) {
389+ err_format = PyUnicode_FromString ("%r is not in range" );
390+ if (err_format == NULL )
391+ return NULL ;
324392 }
325- /* Fall back to iterative search. */
326- return (int )_PySequence_IterSearch ((PyObject * )r , ob ,
327- PY_ITERSEARCH_CONTAINS );
393+ format_tuple = PyTuple_Pack (1 , ob );
394+ if (format_tuple == NULL )
395+ return NULL ;
396+ err_string = PyUnicode_Format (err_format , format_tuple );
397+ Py_DECREF (format_tuple );
398+ if (err_string == NULL )
399+ return NULL ;
400+ PyErr_SetObject (PyExc_ValueError , err_string );
401+ Py_DECREF (err_string );
402+ return NULL ;
328403}
329404
330405static PySequenceMethods range_as_sequence = {
@@ -344,10 +419,18 @@ static PyObject * range_reverse(PyObject *seq);
344419PyDoc_STRVAR (reverse_doc ,
345420"Returns a reverse iterator." );
346421
422+ PyDoc_STRVAR (count_doc ,
423+ "rangeobject.count(value) -> integer -- return number of occurrences of value" );
424+
425+ PyDoc_STRVAR (index_doc ,
426+ "rangeobject.index(value, [start, [stop]]) -> integer -- return index of value.\n"
427+ "Raises ValueError if the value is not present." );
428+
347429static PyMethodDef range_methods [] = {
348- {"__reversed__" , (PyCFunction )range_reverse , METH_NOARGS ,
349- reverse_doc },
350- {"__reduce__" , (PyCFunction )range_reduce , METH_VARARGS },
430+ {"__reversed__" , (PyCFunction )range_reverse , METH_NOARGS , reverse_doc },
431+ {"__reduce__" , (PyCFunction )range_reduce , METH_VARARGS },
432+ {"count" , (PyCFunction )range_count , METH_O , count_doc },
433+ {"index" , (PyCFunction )range_index , METH_O , index_doc },
351434 {NULL , NULL } /* sentinel */
352435};
353436
0 commit comments