~ubuntu-branches/ubuntu/maverick/python3.1/maverick

« back to all changes in this revision

Viewing changes to Objects/sliceobject.c

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2009-03-23 00:01:27 UTC
  • Revision ID: james.westby@ubuntu.com-20090323000127-5fstfxju4ufrhthq
Tags: upstream-3.1~a1+20090322
ImportĀ upstreamĀ versionĀ 3.1~a1+20090322

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
Written by Jim Hugunin and Chris Chase.
 
3
 
 
4
This includes both the singular ellipsis object and slice objects.
 
5
 
 
6
Guido, feel free to do whatever you want in the way of copyrights
 
7
for this file.
 
8
*/
 
9
 
 
10
/* 
 
11
Py_Ellipsis encodes the '...' rubber index token. It is similar to
 
12
the Py_NoneStruct in that there is no way to create other objects of
 
13
this type and there is exactly one in existence.
 
14
*/
 
15
 
 
16
#include "Python.h"
 
17
#include "structmember.h"
 
18
 
 
19
static PyObject *
 
20
ellipsis_repr(PyObject *op)
 
21
{
 
22
        return PyUnicode_FromString("Ellipsis");
 
23
}
 
24
 
 
25
static PyTypeObject PyEllipsis_Type = {
 
26
        PyVarObject_HEAD_INIT(&PyType_Type, 0)
 
27
        "ellipsis",                     /* tp_name */
 
28
        0,                              /* tp_basicsize */
 
29
        0,                              /* tp_itemsize */
 
30
        0, /*never called*/             /* tp_dealloc */
 
31
        0,                              /* tp_print */
 
32
        0,                              /* tp_getattr */
 
33
        0,                              /* tp_setattr */
 
34
        0,                              /* tp_reserved */
 
35
        ellipsis_repr,                  /* tp_repr */
 
36
        0,                              /* tp_as_number */
 
37
        0,                              /* tp_as_sequence */
 
38
        0,                              /* tp_as_mapping */
 
39
        0,                              /* tp_hash */
 
40
        0,                              /* tp_call */
 
41
        0,                              /* tp_str */
 
42
        PyObject_GenericGetAttr,        /* tp_getattro */
 
43
        0,                              /* tp_setattro */
 
44
        0,                              /* tp_as_buffer */
 
45
        Py_TPFLAGS_DEFAULT,             /* tp_flags */
 
46
};
 
47
 
 
48
PyObject _Py_EllipsisObject = {
 
49
        _PyObject_EXTRA_INIT
 
50
        1, &PyEllipsis_Type
 
51
};
 
52
 
 
53
 
 
54
/* Slice object implementation
 
55
 
 
56
   start, stop, and step are python objects with None indicating no
 
57
   index is present.
 
58
*/
 
59
 
 
60
PyObject *
 
61
PySlice_New(PyObject *start, PyObject *stop, PyObject *step)
 
62
{
 
63
        PySliceObject *obj = PyObject_New(PySliceObject, &PySlice_Type);
 
64
 
 
65
        if (obj == NULL)
 
66
                return NULL;
 
67
 
 
68
        if (step == NULL) step = Py_None;
 
69
        Py_INCREF(step);
 
70
        if (start == NULL) start = Py_None;
 
71
        Py_INCREF(start);
 
72
        if (stop == NULL) stop = Py_None;
 
73
        Py_INCREF(stop);
 
74
 
 
75
        obj->step = step;
 
76
        obj->start = start;
 
77
        obj->stop = stop;
 
78
 
 
79
        return (PyObject *) obj;
 
80
}
 
81
 
 
82
PyObject *
 
83
_PySlice_FromIndices(Py_ssize_t istart, Py_ssize_t istop)
 
84
{
 
85
        PyObject *start, *end, *slice;
 
86
        start = PyLong_FromSsize_t(istart);
 
87
        if (!start)
 
88
                return NULL;
 
89
        end = PyLong_FromSsize_t(istop);
 
90
        if (!end) {
 
91
                Py_DECREF(start);
 
92
                return NULL;
 
93
        }
 
94
 
 
95
        slice = PySlice_New(start, end, NULL);
 
96
        Py_DECREF(start);
 
97
        Py_DECREF(end);
 
98
        return slice;
 
99
}
 
100
 
 
101
int
 
102
PySlice_GetIndices(PySliceObject *r, Py_ssize_t length,
 
103
                   Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step)
 
104
{
 
105
        /* XXX support long ints */
 
106
        if (r->step == Py_None) {
 
107
                *step = 1;
 
108
        } else {
 
109
                if (!PyLong_Check(r->step)) return -1;
 
110
                *step = PyLong_AsSsize_t(r->step);
 
111
        }
 
112
        if (r->start == Py_None) {
 
113
                *start = *step < 0 ? length-1 : 0;
 
114
        } else {
 
115
                if (!PyLong_Check(r->start)) return -1;
 
116
                *start = PyLong_AsSsize_t(r->start);
 
117
                if (*start < 0) *start += length;
 
118
        }
 
119
        if (r->stop == Py_None) {
 
120
                *stop = *step < 0 ? -1 : length;
 
121
        } else {
 
122
                if (!PyLong_Check(r->stop)) return -1;
 
123
                *stop = PyLong_AsSsize_t(r->stop);
 
124
                if (*stop < 0) *stop += length;
 
125
        }
 
126
        if (*stop > length) return -1;
 
127
        if (*start >= length) return -1;
 
128
        if (*step == 0) return -1;
 
129
        return 0;
 
130
}
 
131
 
 
132
int
 
133
PySlice_GetIndicesEx(PySliceObject *r, Py_ssize_t length,
 
134
                     Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step, Py_ssize_t *slicelength)
 
135
{
 
136
        /* this is harder to get right than you might think */
 
137
 
 
138
        Py_ssize_t defstart, defstop;
 
139
 
 
140
        if (r->step == Py_None) {
 
141
                *step = 1;
 
142
        } 
 
143
        else {
 
144
                if (!_PyEval_SliceIndex(r->step, step)) return -1;
 
145
                if (*step == 0) {
 
146
                        PyErr_SetString(PyExc_ValueError,
 
147
                                        "slice step cannot be zero");
 
148
                        return -1;
 
149
                }
 
150
        }
 
151
 
 
152
        defstart = *step < 0 ? length-1 : 0;
 
153
        defstop = *step < 0 ? -1 : length;
 
154
 
 
155
        if (r->start == Py_None) {
 
156
                *start = defstart;
 
157
        }
 
158
        else {
 
159
                if (!_PyEval_SliceIndex(r->start, start)) return -1;
 
160
                if (*start < 0) *start += length;
 
161
                if (*start < 0) *start = (*step < 0) ? -1 : 0;
 
162
                if (*start >= length) 
 
163
                        *start = (*step < 0) ? length - 1 : length;
 
164
        }
 
165
 
 
166
        if (r->stop == Py_None) {
 
167
                *stop = defstop;
 
168
        }
 
169
        else {
 
170
                if (!_PyEval_SliceIndex(r->stop, stop)) return -1;
 
171
                if (*stop < 0) *stop += length;
 
172
                if (*stop < 0) *stop = (*step < 0) ? -1 : 0;
 
173
                if (*stop >= length)
 
174
                        *stop = (*step < 0) ? length - 1 : length;
 
175
        }
 
176
 
 
177
        if ((*step < 0 && *stop >= *start) 
 
178
            || (*step > 0 && *start >= *stop)) {
 
179
                *slicelength = 0;
 
180
        }
 
181
        else if (*step < 0) {
 
182
                *slicelength = (*stop-*start+1)/(*step)+1;
 
183
        }
 
184
        else {
 
185
                *slicelength = (*stop-*start-1)/(*step)+1;
 
186
        }
 
187
 
 
188
        return 0;
 
189
}
 
190
 
 
191
static PyObject *
 
192
slice_new(PyTypeObject *type, PyObject *args, PyObject *kw)
 
193
{
 
194
        PyObject *start, *stop, *step;
 
195
 
 
196
        start = stop = step = NULL;
 
197
 
 
198
        if (!_PyArg_NoKeywords("slice()", kw))
 
199
                return NULL;
 
200
 
 
201
        if (!PyArg_UnpackTuple(args, "slice", 1, 3, &start, &stop, &step))
 
202
                return NULL;
 
203
 
 
204
        /* This swapping of stop and start is to maintain similarity with
 
205
           range(). */
 
206
        if (stop == NULL) {
 
207
                stop = start;
 
208
                start = NULL;
 
209
        }
 
210
        return PySlice_New(start, stop, step);
 
211
}
 
212
 
 
213
PyDoc_STRVAR(slice_doc,
 
214
"slice([start,] stop[, step])\n\
 
215
\n\
 
216
Create a slice object.  This is used for extended slicing (e.g. a[0:10:2]).");
 
217
 
 
218
static void
 
219
slice_dealloc(PySliceObject *r)
 
220
{
 
221
        Py_DECREF(r->step);
 
222
        Py_DECREF(r->start);
 
223
        Py_DECREF(r->stop);
 
224
        PyObject_Del(r);
 
225
}
 
226
 
 
227
static PyObject *
 
228
slice_repr(PySliceObject *r)
 
229
{
 
230
        return PyUnicode_FromFormat("slice(%R, %R, %R)", r->start, r->stop, r->step);
 
231
}
 
232
 
 
233
static PyMemberDef slice_members[] = {
 
234
        {"start", T_OBJECT, offsetof(PySliceObject, start), READONLY},
 
235
        {"stop", T_OBJECT, offsetof(PySliceObject, stop), READONLY},
 
236
        {"step", T_OBJECT, offsetof(PySliceObject, step), READONLY},
 
237
        {0}
 
238
};
 
239
 
 
240
static PyObject*
 
241
slice_indices(PySliceObject* self, PyObject* len)
 
242
{
 
243
        Py_ssize_t ilen, start, stop, step, slicelength;
 
244
 
 
245
        ilen = PyNumber_AsSsize_t(len, PyExc_OverflowError);
 
246
 
 
247
        if (ilen == -1 && PyErr_Occurred()) {
 
248
                return NULL;
 
249
        }
 
250
 
 
251
        if (PySlice_GetIndicesEx(self, ilen, &start, &stop, 
 
252
                                 &step, &slicelength) < 0) {
 
253
                return NULL;
 
254
        }
 
255
 
 
256
        return Py_BuildValue("(nnn)", start, stop, step);
 
257
}
 
258
 
 
259
PyDoc_STRVAR(slice_indices_doc,
 
260
"S.indices(len) -> (start, stop, stride)\n\
 
261
\n\
 
262
Assuming a sequence of length len, calculate the start and stop\n\
 
263
indices, and the stride length of the extended slice described by\n\
 
264
S. Out of bounds indices are clipped in a manner consistent with the\n\
 
265
handling of normal slices.");
 
266
 
 
267
static PyObject *
 
268
slice_reduce(PySliceObject* self)
 
269
{
 
270
        return Py_BuildValue("O(OOO)", Py_TYPE(self), self->start, self->stop, self->step);
 
271
}
 
272
 
 
273
PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
 
274
 
 
275
static PyMethodDef slice_methods[] = {
 
276
        {"indices",     (PyCFunction)slice_indices,
 
277
         METH_O,        slice_indices_doc},
 
278
        {"__reduce__",  (PyCFunction)slice_reduce,
 
279
         METH_NOARGS,   reduce_doc},
 
280
        {NULL, NULL}
 
281
};
 
282
 
 
283
static PyObject *
 
284
slice_richcompare(PyObject *v, PyObject *w, int op)
 
285
{
 
286
        PyObject *t1;
 
287
        PyObject *t2;
 
288
        PyObject *res;
 
289
 
 
290
        if (!PySlice_Check(v) || !PySlice_Check(w)) {
 
291
                Py_INCREF(Py_NotImplemented);
 
292
                return Py_NotImplemented;
 
293
        }
 
294
 
 
295
        if (v == w) {
 
296
                /* XXX Do we really need this shortcut?
 
297
                   There's a unit test for it, but is that fair? */
 
298
                switch (op) {
 
299
                case Py_EQ: 
 
300
                case Py_LE:
 
301
                case Py_GE:
 
302
                        res = Py_True; 
 
303
                        break;
 
304
                default:
 
305
                        res = Py_False; 
 
306
                        break;
 
307
                }
 
308
                Py_INCREF(res);
 
309
                return res;
 
310
        }
 
311
 
 
312
        t1 = PyTuple_New(3);
 
313
        t2 = PyTuple_New(3);
 
314
        if (t1 == NULL || t2 == NULL)
 
315
                return NULL;
 
316
 
 
317
        PyTuple_SET_ITEM(t1, 0, ((PySliceObject *)v)->start);
 
318
        PyTuple_SET_ITEM(t1, 1, ((PySliceObject *)v)->stop);
 
319
        PyTuple_SET_ITEM(t1, 2, ((PySliceObject *)v)->step);
 
320
        PyTuple_SET_ITEM(t2, 0, ((PySliceObject *)w)->start);
 
321
        PyTuple_SET_ITEM(t2, 1, ((PySliceObject *)w)->stop);
 
322
        PyTuple_SET_ITEM(t2, 2, ((PySliceObject *)w)->step);
 
323
 
 
324
        res = PyObject_RichCompare(t1, t2, op);
 
325
 
 
326
        PyTuple_SET_ITEM(t1, 0, NULL);
 
327
        PyTuple_SET_ITEM(t1, 1, NULL);
 
328
        PyTuple_SET_ITEM(t1, 2, NULL);
 
329
        PyTuple_SET_ITEM(t2, 0, NULL);
 
330
        PyTuple_SET_ITEM(t2, 1, NULL);
 
331
        PyTuple_SET_ITEM(t2, 2, NULL);
 
332
 
 
333
        Py_DECREF(t1);
 
334
        Py_DECREF(t2);
 
335
 
 
336
        return res;
 
337
}
 
338
 
 
339
static long
 
340
slice_hash(PySliceObject *v)
 
341
{
 
342
        PyErr_SetString(PyExc_TypeError, "unhashable type");
 
343
        return -1L;
 
344
}
 
345
 
 
346
PyTypeObject PySlice_Type = {
 
347
        PyVarObject_HEAD_INIT(&PyType_Type, 0)
 
348
        "slice",                /* Name of this type */
 
349
        sizeof(PySliceObject),  /* Basic object size */
 
350
        0,                      /* Item size for varobject */
 
351
        (destructor)slice_dealloc,              /* tp_dealloc */
 
352
        0,                                      /* tp_print */
 
353
        0,                                      /* tp_getattr */
 
354
        0,                                      /* tp_setattr */
 
355
        0,                                      /* tp_reserved */
 
356
        (reprfunc)slice_repr,                   /* tp_repr */
 
357
        0,                                      /* tp_as_number */
 
358
        0,                                      /* tp_as_sequence */
 
359
        0,                                      /* tp_as_mapping */
 
360
        (hashfunc)slice_hash,                   /* tp_hash */
 
361
        0,                                      /* tp_call */
 
362
        0,                                      /* tp_str */
 
363
        PyObject_GenericGetAttr,                /* tp_getattro */
 
364
        0,                                      /* tp_setattro */
 
365
        0,                                      /* tp_as_buffer */
 
366
        Py_TPFLAGS_DEFAULT,                     /* tp_flags */
 
367
        slice_doc,                              /* tp_doc */
 
368
        0,                                      /* tp_traverse */
 
369
        0,                                      /* tp_clear */
 
370
        slice_richcompare,                      /* tp_richcompare */
 
371
        0,                                      /* tp_weaklistoffset */
 
372
        0,                                      /* tp_iter */
 
373
        0,                                      /* tp_iternext */
 
374
        slice_methods,                          /* tp_methods */
 
375
        slice_members,                          /* tp_members */
 
376
        0,                                      /* tp_getset */
 
377
        0,                                      /* tp_base */
 
378
        0,                                      /* tp_dict */
 
379
        0,                                      /* tp_descr_get */
 
380
        0,                                      /* tp_descr_set */
 
381
        0,                                      /* tp_dictoffset */
 
382
        0,                                      /* tp_init */
 
383
        0,                                      /* tp_alloc */
 
384
        slice_new,                              /* tp_new */
 
385
};