1__doc__ = u"""
2    >>> index_object(100, 100)       # doctest: +ELLIPSIS
3    Traceback (most recent call last):
4    ...
5    TypeError: 'int' object ...
6"""
7
8cdef Py_ssize_t maxsize
9
10import sys
11if sys.version_info < (2,5):
12    __doc__ = __doc__.replace(u"'int' object ...", u'unsubscriptable object')
13    maxsize = min(sys.maxint, 2**31-1)
14else:
15    maxsize = getattr(sys, 'maxsize', getattr(sys, 'maxint', None))
16
17py_maxsize = maxsize
18
19import cython
20
21def index_tuple(tuple t, int i):
22    """
23    >>> index_tuple((1,1,2,3,5), 0)
24    1
25    >>> index_tuple((1,1,2,3,5), 3)
26    3
27    >>> index_tuple((1,1,2,3,5), -1)
28    5
29    >>> index_tuple((1,1,2,3,5), 100)
30    Traceback (most recent call last):
31    IndexError: tuple index out of range
32    >>> index_tuple((1,1,2,3,5), -7)
33    Traceback (most recent call last):
34    IndexError: tuple index out of range
35    >>> index_tuple(None, 0)
36    Traceback (most recent call last):
37    TypeError: 'NoneType' object is not subscriptable
38    """
39    return t[i]
40
41def index_list(list L, int i):
42    """
43    >>> index_list([2,3,5,7,11,13,17,19], 0)
44    2
45    >>> index_list([2,3,5,7,11,13,17,19], 5)
46    13
47    >>> index_list([2,3,5,7,11,13,17,19], -1)
48    19
49    >>> index_list([2,3,5,7,11,13,17,19], 100)
50    Traceback (most recent call last):
51    IndexError: list index out of range
52    >>> index_list([2,3,5,7,11,13,17,19], -10)
53    Traceback (most recent call last):
54    IndexError: list index out of range
55    >>> index_list(None, 0)
56    Traceback (most recent call last):
57    TypeError: 'NoneType' object is not subscriptable
58    """
59    return L[i]
60
61def index_object(object o, int i):
62    """
63    >>> index_object([2,3,5,7,11,13,17,19], 1)
64    3
65    >>> index_object([2,3,5,7,11,13,17,19], -1)
66    19
67    >>> index_object((1,1,2,3,5), 2)
68    2
69    >>> index_object((1,1,2,3,5), -2)
70    3
71    >>> index_object("abcdef...z", 0)
72    'a'
73    >>> index_object("abcdef...z", -1)
74    'z'
75    >>> index_object("abcdef...z", 100)
76    Traceback (most recent call last):
77    IndexError: string index out of range
78    >>> try: index_object(None, 0)
79    ... except TypeError: pass
80    """
81    return o[i]
82
83
84def del_index_list(list L, Py_ssize_t index):
85    """
86    >>> del_index_list(list(range(4)), 0)
87    [1, 2, 3]
88    >>> del_index_list(list(range(4)), 1)
89    [0, 2, 3]
90    >>> del_index_list(list(range(4)), -1)
91    [0, 1, 2]
92    >>> del_index_list(list(range(4)), py_maxsize)  # doctest: +ELLIPSIS
93    Traceback (most recent call last):
94    IndexError: list... index out of range
95    >>> del_index_list(list(range(4)), -py_maxsize)  # doctest: +ELLIPSIS
96    Traceback (most recent call last):
97    IndexError: list... index out of range
98    """
99    del L[index]
100    return L
101
102
103def set_index_list(list L, Py_ssize_t index):
104    """
105    >>> set_index_list(list(range(4)), 0)
106    [5, 1, 2, 3]
107    >>> set_index_list(list(range(4)), 1)
108    [0, 5, 2, 3]
109    >>> set_index_list(list(range(4)), -1)
110    [0, 1, 2, 5]
111    >>> set_index_list(list(range(4)), py_maxsize)  # doctest: +ELLIPSIS
112    Traceback (most recent call last):
113    IndexError: list... index out of range
114    >>> set_index_list(list(range(4)), -py_maxsize)  # doctest: +ELLIPSIS
115    Traceback (most recent call last):
116    IndexError: list... index out of range
117    """
118    L[index] = 5
119    return L
120
121
122# These make sure that our fast indexing works with large and unsigned types.
123
124def test_unsigned_long():
125    """
126    >>> test_unsigned_long()
127    """
128    cdef int i
129    cdef unsigned long ix
130    cdef D = {}
131    for i from 0 <= i < <int>sizeof(unsigned long) * 8:
132        ix = (<unsigned long>1) << i
133        D[ix] = True
134    for i from 0 <= i < <int>sizeof(unsigned long) * 8:
135        ix = (<unsigned long>1) << i
136        assert D[ix] is True
137        del D[ix]
138    assert len(D) == 0
139
140def test_unsigned_short():
141    """
142    >>> test_unsigned_short()
143    """
144    cdef int i
145    cdef unsigned short ix
146    cdef D = {}
147    for i from 0 <= i < <int>sizeof(unsigned short) * 8:
148        ix = (<unsigned short>1) << i
149        D[ix] = True
150    for i from 0 <= i < <int>sizeof(unsigned short) * 8:
151        ix = (<unsigned short>1) << i
152        assert D[ix] is True
153        del D[ix]
154    assert len(D) == 0
155
156def test_long_long():
157    """
158    >>> test_long_long()
159    """
160    cdef int i
161    cdef long long ix
162    cdef D = {}
163    for i from 0 <= i < <int>sizeof(long long) * 8:
164        ix = (<long long>1) << i
165        D[ix] = True
166    for i from 0 <= i < <int>sizeof(long long) * 8:
167        ix = (<long long>1) << i
168        assert D[ix] is True
169        del D[ix]
170
171    L = [1, 2, 3]
172    try:
173        ix = py_maxsize + 1
174    except OverflowError:
175        pass  # can't test this here
176    else:
177        try: L[ix] = 5
178        except IndexError: pass
179        else: assert False, "setting large index failed to raise IndexError"
180
181        try: del L[ix]
182        except IndexError: pass
183        else: assert False, "deleting large index failed to raise IndexError"
184
185    try:
186        ix = -py_maxsize - 2
187    except OverflowError:
188        pass  # can't test this here
189    else:
190        try: L[ix] = 5
191        except IndexError: pass
192        else: assert False, "setting large index failed to raise IndexError"
193
194        try: del L[ix]
195        except IndexError: pass
196        else: assert False, "deleting large index failed to raise IndexError"
197
198    assert len(D) == 0
199
200
201def test_ulong_long():
202    """
203    >>> test_ulong_long()
204    """
205    cdef unsigned long long ix
206
207    L = [1, 2, 3]
208    try:
209        ix = py_maxsize + 1
210    except OverflowError:
211        pass  # can't test this here
212    else:
213        try: L[ix] = 5
214        except IndexError: pass
215        else: assert False, "setting large index failed to raise IndexError"
216
217        try: del L[ix]
218        except IndexError: pass
219        else: assert False, "deleting large index failed to raise IndexError"
220
221
222@cython.boundscheck(False)
223def test_boundscheck_unsigned(list L, tuple t, object o, unsigned long ix):
224    """
225    >>> test_boundscheck_unsigned([1, 2, 4], (1, 2, 4), [1, 2, 4], 2)
226    (4, 4, 4)
227    >>> test_boundscheck_unsigned([1, 2, 4], (1, 2, 4), "", 2)
228    Traceback (most recent call last):
229    ...
230    IndexError: string index out of range
231    """
232    return L[ix], t[ix], o[ix]
233
234@cython.boundscheck(False)
235def test_boundscheck_signed(list L, tuple t, object o, long ix):
236    """
237    >>> test_boundscheck_signed([1, 2, 4], (1, 2, 4), [1, 2, 4], 2)
238    (4, 4, 4)
239    >>> test_boundscheck_signed([1, 2, 4], (1, 2, 4), "", 2)
240    Traceback (most recent call last):
241    ...
242    IndexError: string index out of range
243    """
244    return L[ix], t[ix], o[ix]
245
246@cython.wraparound(False)
247def test_wraparound_signed(list L, tuple t, object o, long ix):
248    """
249    >>> test_wraparound_signed([1, 2, 4], (1, 2, 4), [1, 2, 4], 2)
250    (4, 4, 4)
251    >>> test_wraparound_signed([1, 2, 4], (1, 2, 4), "", 2)
252    Traceback (most recent call last):
253    ...
254    IndexError: string index out of range
255    """
256    return L[ix], t[ix], o[ix]
257
258def large_literal_index(object o):
259    """
260    >>> large_literal_index({1000000000000000000000000000000: True})
261    True
262    """
263    return o[1000000000000000000000000000000]
264
265
266class LargeIndexable(object):
267    expected = None
268
269    def __len__(self):
270        raise OverflowError
271
272    def __getitem__(self, index):
273        return index
274
275    def __setitem__(self, index, value):
276        assert index == value == self.expected
277        self.expected = None
278
279    def __delitem__(self, index):
280        assert self.expected == index
281        self.expected = None
282
283
284def test_large_indexing(obj):
285    """
286    >>> obj = LargeIndexable()
287    >>> zero, pone, none, pmaxsize, nmaxsize = test_large_indexing(obj)
288    >>> # , p2maxsize, n2maxsize
289    >>> zero
290    0
291    >>> pone
292    1
293    >>> none
294    -1
295    >>> pmaxsize == py_maxsize
296    True
297    >>> nmaxsize == -py_maxsize
298    True
299
300    #>>> p2maxsize == py_maxsize*2
301    #True
302    #>>> n2maxsize == -py_maxsize*2
303    #True
304    """
305    return (
306        obj[0], obj[1], obj[-1],
307        obj[maxsize], obj[-maxsize],
308        #obj[maxsize*2], obj[-maxsize*2]     # FIXME!
309    )
310
311
312def del_large_index(obj, Py_ssize_t index):
313    """
314    >>> obj = LargeIndexable()
315    >>> del_large_index(obj, 0)
316    >>> del_large_index(obj, 1)
317    >>> del_large_index(obj, -1)
318    >>> del_large_index(obj, py_maxsize)
319    >>> del_large_index(obj, -py_maxsize)
320    """
321    obj.expected = index
322    del obj[index]
323    assert obj.expected is None
324
325
326def set_large_index(obj, Py_ssize_t index):
327    """
328    >>> obj = LargeIndexable()
329    >>> set_large_index(obj, 0)
330    >>> set_large_index(obj, 1)
331    >>> set_large_index(obj, -1)
332    >>> set_large_index(obj, py_maxsize)
333    >>> set_large_index(obj, -py_maxsize)
334    """
335    obj.expected = index
336    obj[index] = index
337    assert obj.expected is None
338