55#include "structmember.h"
66#include <string.h>
77
8+ #define WARN (msg ) if (PyErr_Warn(PyExc_DeprecationWarning, msg) < 0) \
9+ return NULL;
10+
811typedef struct {
912 PyObject_HEAD
1013 long start ;
1114 long step ;
1215 long len ;
16+ int reps ;
17+ long totlen ;
1318} rangeobject ;
1419
20+ static int
21+ long_mul (long i , long j , long * kk )
22+ {
23+ PyObject * a ;
24+ PyObject * b ;
25+ PyObject * c ;
26+
27+ if ((a = PyInt_FromLong (i )) == NULL )
28+ return 0 ;
29+
30+ if ((b = PyInt_FromLong (j )) == NULL )
31+ return 0 ;
32+
33+ c = PyNumber_Multiply (a , b );
34+
35+ Py_DECREF (a );
36+ Py_DECREF (b );
37+
38+ if (c == NULL )
39+ return 0 ;
40+
41+ * kk = PyInt_AS_LONG (c );
42+ Py_DECREF (c );
43+
44+ if (* kk > INT_MAX ) {
45+ PyErr_SetString (PyExc_OverflowError ,
46+ "integer multiplication" );
47+ return 0 ;
48+ }
49+ else
50+ return 1 ;
51+ }
52+
1553PyObject *
16- PyRange_New (long start , long len , long step )
54+ PyRange_New (long start , long len , long step , int reps )
1755{
56+ long totlen = -1 ;
1857 rangeobject * obj = PyObject_NEW (rangeobject , & PyRange_Type );
1958
2059 if (obj == NULL )
2160 return NULL ;
61+
62+ if (reps != 1 )
63+ WARN ("PyRange_New's 'repetitions' argument is deprecated" );
2264
23- if (len == 0 ) {
65+ if (len == 0 || reps <= 0 ) {
2466 start = 0 ;
2567 len = 0 ;
2668 step = 1 ;
69+ reps = 1 ;
70+ totlen = 0 ;
2771 }
2872 else {
2973 long last = start + (len - 1 ) * step ;
3074 if ((step > 0 ) ?
31- (last > (PyInt_GetMax () - step ))
32- : (last < (-1 - PyInt_GetMax () - step ))) {
75+ (last > (PyInt_GetMax () - step )) :
76+ (last < (-1 - PyInt_GetMax () - step ))) {
3377 PyErr_SetString (PyExc_OverflowError ,
3478 "integer addition" );
3579 return NULL ;
80+ }
81+ if (! long_mul (len , (long ) reps , & totlen )) {
82+ if (!PyErr_ExceptionMatches (PyExc_OverflowError ))
83+ return NULL ;
84+ PyErr_Clear ();
85+ totlen = -1 ;
3686 }
3787 }
3888
3989 obj -> start = start ;
4090 obj -> len = len ;
4191 obj -> step = step ;
92+ obj -> reps = reps ;
93+ obj -> totlen = totlen ;
4294
4395 return (PyObject * ) obj ;
4496}
@@ -52,19 +104,23 @@ range_dealloc(rangeobject *r)
52104static PyObject *
53105range_item (rangeobject * r , int i )
54106{
55- if (i < 0 || i >= r -> len ) {
56- PyErr_SetString (PyExc_IndexError ,
107+ if (i < 0 || i >= r -> totlen )
108+ if (r -> totlen != -1 ) {
109+ PyErr_SetString (PyExc_IndexError ,
57110 "xrange object index out of range" );
58- return NULL ;
59- }
111+ return NULL ;
112+ }
60113
61114 return PyInt_FromLong (r -> start + (i % r -> len ) * r -> step );
62115}
63116
64117static int
65118range_length (rangeobject * r )
66119{
67- return r -> len ;
120+ if (r -> totlen == -1 )
121+ PyErr_SetString (PyExc_OverflowError ,
122+ "xrange object has too many items" );
123+ return r -> totlen ;
68124}
69125
70126static PyObject *
@@ -74,6 +130,7 @@ range_repr(rangeobject *r)
74130 * a bit of "(xrange(...) * ...)" text.
75131 */
76132 char buf1 [250 ];
133+ char buf2 [250 ];
77134
78135 if (r -> start == 0 && r -> step == 1 )
79136 sprintf (buf1 , "xrange(%ld)" , r -> start + r -> len * r -> step );
@@ -89,18 +146,162 @@ range_repr(rangeobject *r)
89146 r -> start + r -> len * r -> step ,
90147 r -> step );
91148
92- return PyString_FromString (buf1 );
149+ if (r -> reps != 1 )
150+ sprintf (buf2 , "(%s * %d)" , buf1 , r -> reps );
151+
152+ return PyString_FromString (r -> reps == 1 ? buf1 : buf2 );
153+ }
154+
155+ static PyObject *
156+ range_repeat (rangeobject * r , int n )
157+ {
158+ long lreps = 0 ;
159+
160+ WARN ("xrange object multiplication is deprecated; "
161+ "convert to list instead" );
162+
163+ if (n <= 0 )
164+ return (PyObject * ) PyRange_New (0 , 0 , 1 , 1 );
165+
166+ else if (n == 1 ) {
167+ Py_INCREF (r );
168+ return (PyObject * ) r ;
169+ }
170+
171+ else if (! long_mul ((long ) r -> reps , (long ) n , & lreps ))
172+ return NULL ;
173+
174+ else
175+ return (PyObject * ) PyRange_New (
176+ r -> start ,
177+ r -> len ,
178+ r -> step ,
179+ (int ) lreps );
180+ }
181+
182+ static int
183+ range_compare (rangeobject * r1 , rangeobject * r2 )
184+ {
185+
186+ if (PyErr_Warn (PyExc_DeprecationWarning ,
187+ "xrange object comparision is deprecated; "
188+ "convert to list instead" ) < 0 )
189+ return -1 ;
190+
191+ if (r1 -> start != r2 -> start )
192+ return r1 -> start - r2 -> start ;
193+
194+ else if (r1 -> step != r2 -> step )
195+ return r1 -> step - r2 -> step ;
196+
197+ else if (r1 -> len != r2 -> len )
198+ return r1 -> len - r2 -> len ;
199+
200+ else
201+ return r1 -> reps - r2 -> reps ;
202+ }
203+
204+ static PyObject *
205+ range_slice (rangeobject * r , int low , int high )
206+ {
207+ WARN ("xrange object slicing is deprecated; "
208+ "convert to list instead" );
209+
210+ if (r -> reps != 1 ) {
211+ PyErr_SetString (PyExc_TypeError ,
212+ "cannot slice a replicated xrange" );
213+ return NULL ;
214+ }
215+ if (low < 0 )
216+ low = 0 ;
217+ else if (low > r -> len )
218+ low = r -> len ;
219+ if (high < 0 )
220+ high = 0 ;
221+ if (high < low )
222+ high = low ;
223+ else if (high > r -> len )
224+ high = r -> len ;
225+
226+ if (low == 0 && high == r -> len ) {
227+ Py_INCREF (r );
228+ return (PyObject * ) r ;
229+ }
230+
231+ return (PyObject * ) PyRange_New (
232+ low * r -> step + r -> start ,
233+ high - low ,
234+ r -> step ,
235+ 1 );
236+ }
237+
238+ static PyObject *
239+ range_tolist (rangeobject * self , PyObject * args )
240+ {
241+ PyObject * thelist ;
242+ int j ;
243+
244+ WARN ("xrange.tolist() is deprecated; use list(xrange) instead" );
245+
246+ if (! PyArg_ParseTuple (args , ":tolist" ))
247+ return NULL ;
248+
249+ if (self -> totlen == -1 )
250+ return PyErr_NoMemory ();
251+
252+ if ((thelist = PyList_New (self -> totlen )) == NULL )
253+ return NULL ;
254+
255+ for (j = 0 ; j < self -> totlen ; ++ j )
256+ if ((PyList_SetItem (thelist , j , (PyObject * ) PyInt_FromLong (
257+ self -> start + (j % self -> len ) * self -> step ))) < 0 )
258+ return NULL ;
259+
260+ return thelist ;
261+ }
262+
263+ static PyObject *
264+ range_getattr (rangeobject * r , char * name )
265+ {
266+ PyObject * result ;
267+
268+ static PyMethodDef range_methods [] = {
269+ {"tolist" , (PyCFunction )range_tolist , METH_VARARGS ,
270+ "tolist() -> list\n"
271+ "Return a list object with the same values.\n"
272+ "(This method is deprecated; use list() instead.)" },
273+ {NULL , NULL }
274+ };
275+ static struct memberlist range_members [] = {
276+ {"step" , T_LONG , offsetof(rangeobject , step ), RO },
277+ {"start" , T_LONG , offsetof(rangeobject , start ), RO },
278+ {"stop" , T_LONG , 0 , RO },
279+ {NULL , 0 , 0 , 0 }
280+ };
281+
282+ result = Py_FindMethod (range_methods , (PyObject * ) r , name );
283+ if (result == NULL ) {
284+ PyErr_Clear ();
285+ if (strcmp ("stop" , name ) == 0 )
286+ result = PyInt_FromLong (r -> start + (r -> len * r -> step ));
287+ else
288+ result = PyMember_Get ((char * )r , range_members , name );
289+ if (result )
290+ WARN ("xrange object's 'start', 'stop' and 'step' "
291+ "attributes are deprecated" );
292+ }
293+ return result ;
93294}
94295
95296static PySequenceMethods range_as_sequence = {
96297 (inquiry )range_length , /*sq_length*/
97298 0 , /*sq_concat*/
98- 0 , /*sq_repeat*/
99- (intargfunc )range_item , /*sq_item*/
100- 0 , /*sq_slice*/
299+ ( intargfunc ) range_repeat , /*sq_repeat*/
300+ (intargfunc )range_item , /*sq_item*/
301+ ( intintargfunc ) range_slice , /*sq_slice*/
101302 0 , /*sq_ass_item*/
102303 0 , /*sq_ass_slice*/
103- 0 , /*sq_contains*/
304+ 0 , /*sq_contains*/
104305};
105306
106307PyTypeObject PyRange_Type = {
@@ -111,9 +312,9 @@ PyTypeObject PyRange_Type = {
111312 0 , /* Item size for varobject */
112313 (destructor )range_dealloc , /*tp_dealloc*/
113314 0 , /*tp_print*/
114- 0 , /*tp_getattr*/
315+ ( getattrfunc ) range_getattr , /*tp_getattr*/
115316 0 , /*tp_setattr*/
116- 0 , /*tp_compare*/
317+ ( cmpfunc ) range_compare , /*tp_compare*/
117318 (reprfunc )range_repr , /*tp_repr*/
118319 0 , /*tp_as_number*/
119320 & range_as_sequence , /*tp_as_sequence*/
@@ -126,3 +327,5 @@ PyTypeObject PyRange_Type = {
126327 0 , /*tp_as_buffer*/
127328 Py_TPFLAGS_DEFAULT , /*tp_flags*/
128329};
330+
331+ #undef WARN
0 commit comments