1# mode: run
2# tag: list, tuple, slice, slicing
3
4cimport cython
5
6
7@cython.test_fail_if_path_exists("//CondExprNode")
8def slice_list(list l, int start, int stop):
9    """
10    >>> slice_list([1,2,3,4], 1, 3)
11    [2, 3]
12    >>> slice_list([1,2,3,4], 1, 7)
13    [2, 3, 4]
14    >>> slice_list([], 1, 3)
15    []
16    >>> slice_list([1], 1, 3)
17    []
18    >>> slice_list([1,2,3,4], -3, -1)
19    [2, 3]
20    >>> slice_list([1,2,3,4], -10, -1)
21    [1, 2, 3]
22    >>> slice_list([], -3, -1)
23    []
24    >>> slice_list([1], -3, -1)
25    []
26    """
27    return l[start:stop]
28
29@cython.test_fail_if_path_exists("//CondExprNode")
30def slice_list_start(list l, int start):
31    """
32    >>> slice_list_start([1,2,3,4], 1)
33    [2, 3, 4]
34    >>> slice_list_start([], 1)
35    []
36    >>> slice_list_start([1], 1)
37    []
38    >>> slice_list_start([1], 2)
39    []
40    >>> slice_list_start([1,2,3,4], -3)
41    [2, 3, 4]
42    >>> slice_list_start([1,2,3,4], -10)
43    [1, 2, 3, 4]
44    >>> slice_list_start([], -3)
45    []
46    >>> slice_list_start([1], -3)
47    [1]
48    """
49    return l[start:]
50
51
52@cython.test_fail_if_path_exists("//CondExprNode")
53def slice_list_stop(list l, int stop):
54    """
55    >>> slice_list_stop([1,2,3,4], 3)
56    [1, 2, 3]
57    >>> slice_list_stop([1,2,3,4], 7)
58    [1, 2, 3, 4]
59    >>> slice_list_stop([], 3)
60    []
61    >>> slice_list_stop([1], 3)
62    [1]
63    >>> slice_list_stop([1,2,3,4], -3)
64    [1]
65    >>> slice_list_stop([1,2,3,4], -10)
66    []
67    >>> slice_list_stop([], -1)
68    []
69    >>> slice_list_stop([1], -1)
70    []
71    >>> slice_list_stop([1, 2], -3)
72    []
73    """
74    return l[:stop]
75
76
77@cython.test_fail_if_path_exists("//CondExprNode")
78def slice_list_copy(list l):
79    """
80    >>> slice_list_copy([])
81    []
82    >>> slice_list_copy([1,2,3])
83    [1, 2, 3]
84    """
85    return l[:]
86
87
88@cython.test_fail_if_path_exists("//CondExprNode")
89def slice_tuple_copy(tuple l):
90    """
91    >>> slice_tuple_copy(())
92    ()
93    >>> slice_tuple_copy((1,2,3))
94    (1, 2, 3)
95    """
96    return l[:]
97
98
99@cython.test_fail_if_path_exists("//CondExprNode")
100def slice_tuple(tuple t, int start, int stop):
101    """
102    >>> slice_tuple((1,2,3,4), 1, 3)
103    (2, 3)
104    >>> slice_tuple((1,2,3,4), 1, 7)
105    (2, 3, 4)
106    >>> slice_tuple((), 1, 3)
107    ()
108    >>> slice_tuple((1,), 1, 3)
109    ()
110    >>> slice_tuple((1,2,3,4), -3, -1)
111    (2, 3)
112    >>> slice_tuple((1,2,3,4), -10, -1)
113    (1, 2, 3)
114    >>> slice_tuple((), -3, -1)
115    ()
116    >>> slice_tuple((1,), -3, -1)
117    ()
118    """
119    return t[start:stop]
120
121
122@cython.test_fail_if_path_exists("//CondExprNode")
123def slice_tuple_start(tuple t, int start):
124    """
125    >>> slice_tuple_start((1,2,3,4), 1)
126    (2, 3, 4)
127    >>> slice_tuple_start((), 1)
128    ()
129    >>> slice_tuple_start((1,), 1)
130    ()
131    >>> slice_tuple_start((1,2,3,4), -3)
132    (2, 3, 4)
133    >>> slice_tuple_start((1,2,3,4), -10)
134    (1, 2, 3, 4)
135    >>> slice_tuple_start((), -3)
136    ()
137    >>> slice_tuple_start((1,), -3)
138    (1,)
139    """
140    return t[start:]
141
142
143@cython.test_fail_if_path_exists("//CondExprNode")
144def slice_tuple_stop(tuple t, int stop):
145    """
146    >>> slice_tuple_stop((1,2,3,4), 3)
147    (1, 2, 3)
148    >>> slice_tuple_stop((1,2,3,4), 7)
149    (1, 2, 3, 4)
150    >>> slice_tuple_stop((), 3)
151    ()
152    >>> slice_tuple_stop((1,), 3)
153    (1,)
154    >>> slice_tuple_stop((1,2,3,4), -1)
155    (1, 2, 3)
156    >>> slice_tuple_stop((), -1)
157    ()
158    """
159    return t[:stop]
160
161
162@cython.test_fail_if_path_exists("//CondExprNode")
163def slice_list_assign_list(list l):
164    """
165    >>> l = [1,2,3,4]
166    >>> l2 = l[:]
167    >>> slice_list_assign_list(l2)
168    [1, 1, 2, 3, 4, 4]
169    """
170    l[1:3] = [1,2,3,4]
171    return l
172
173
174@cython.test_fail_if_path_exists("//CondExprNode")
175def slice_list_assign_tuple(list l):
176    """
177    >>> l = [1,2,3,4]
178    >>> l2 = l[:]
179    >>> slice_list_assign_tuple(l2)
180    [1, 1, 2, 3, 4, 4]
181    """
182    l[1:3] = (1,2,3,4)
183    return l
184
185
186@cython.test_fail_if_path_exists("//CondExprNode")
187def slice_list_assign(list l, value):
188    """
189    >>> l = [1,2,3,4]
190    >>> l2 = l[:]
191    >>> slice_list_assign(l2, (1,2,3,4))
192    [1, 1, 2, 3, 4, 4]
193    >>> l2 = l[:]
194    >>> slice_list_assign(l2, dict(zip(l,l)))
195    [1, 1, 2, 3, 4, 4]
196    """
197    l[1:3] = value
198    return l
199
200
201def slice_charp(py_string_arg):
202    """
203    >>> print("%s" % slice_charp('abcdefg'))
204    bc
205    """
206    cdef bytes py_string = py_string_arg.encode(u'ASCII')
207    cdef char* s = py_string
208    return s[1:3].decode(u'ASCII')
209
210
211def slice_charp_repeat(py_string_arg):
212    """
213    >>> print("%s" % slice_charp_repeat('abcdefg'))
214    cd
215    """
216    cdef bytes py_string = py_string_arg.encode(u'ASCII')
217    cdef char* s = py_string
218    cdef bytes slice_val = s[1:6]
219    s = slice_val
220    return s[1:3].decode(u'ASCII')
221
222
223# Readers will find the common boilerplate in the tests below:
224#     >>> l = [1,2,3,4,5]
225#     >>> t = tuple(l)
226#     >>> b = ''.join(map(str, l)).encode('ASCII')
227#     >>> u = b.decode('ASCII')
228#     >>> o = (l, t, b, u)
229#     >>> n = ('list', 'tuple', 'bytes', 'unicode')
230#     >>> p = lambda o: o.decode() if isinstance(o, type(b)) else str(o)
231#     >>> r = lambda i, *a: '%s[%s] -> %s' % (n[i], ':'.join(map(repr, a)), FUNCTION_NAME(o[i], *a))
232# Originally, this was planned to be a basic iteration over
233#   the various object types contained within the slicable fused
234#   type, but Python2 -> Python3 semantics changed the class names
235#   and string representations used for raw bytes and unicode.
236# As a result, we dynamically adjust the printed string output
237#   for each test in order to ensure consistent results when running
238#   both Python2 and Python3.
239
240ctypedef fused slicable:
241    list
242    tuple
243    bytes
244    unicode
245
246
247@cython.test_assert_path_exists("//SliceIndexNode//CondExprNode")
248def slice_fused_type_start(slicable seq, start):
249    """
250    >>> l = [1,2,3,4,5]
251    >>> t = tuple(l)
252    >>> b = ''.join(map(str, l)).encode('ASCII')
253    >>> u = b.decode('ASCII')
254    >>> o = (l, t, b, u)
255    >>> n = ('list', 'tuple', 'bytes', 'unicode')
256    >>> p = lambda o: o.decode() if isinstance(o, type(b)) else str(o)
257    >>> r = lambda i, s: '%s[%r:] -> %s' % (n[i], s, p(slice_fused_type_start(o[i], s)))
258    >>> for i in range(len(o)):
259    ...     for s in (0, len(l) - 1, len(l), -1, -len(l), None):
260    ...         print(r(i, s))
261    ...
262    list[0:] -> [1, 2, 3, 4, 5]
263    list[4:] -> [5]
264    list[5:] -> []
265    list[-1:] -> [5]
266    list[-5:] -> [1, 2, 3, 4, 5]
267    list[None:] -> [1, 2, 3, 4, 5]
268    tuple[0:] -> (1, 2, 3, 4, 5)
269    tuple[4:] -> (5,)
270    tuple[5:] -> ()
271    tuple[-1:] -> (5,)
272    tuple[-5:] -> (1, 2, 3, 4, 5)
273    tuple[None:] -> (1, 2, 3, 4, 5)
274    bytes[0:] -> 12345
275    bytes[4:] -> 5
276    bytes[5:] ->
277    bytes[-1:] -> 5
278    bytes[-5:] -> 12345
279    bytes[None:] -> 12345
280    unicode[0:] -> 12345
281    unicode[4:] -> 5
282    unicode[5:] ->
283    unicode[-1:] -> 5
284    unicode[-5:] -> 12345
285    unicode[None:] -> 12345
286    """
287    obj = seq[start:]
288    return obj
289
290
291@cython.test_assert_path_exists("//SliceIndexNode//CondExprNode")
292def slice_fused_type_stop(slicable seq, stop):
293    """
294    >>> l = [1,2,3,4,5]
295    >>> t = tuple(l)
296    >>> b = ''.join(map(str, l)).encode('ASCII')
297    >>> u = b.decode('ASCII')
298    >>> o = (l, t, b, u)
299    >>> n = ('list', 'tuple', 'bytes', 'unicode')
300    >>> p = lambda o: o.decode() if isinstance(o, type(b)) else str(o)
301    >>> r = lambda i, s: '%s[:%r] -> %s' % (n[i], s, p(slice_fused_type_stop(o[i], s)))
302    >>> for i in range(len(o)):
303    ...     for s in (0, len(l) - 1, len(l), -1, -len(l), None):
304    ...         print(r(i, s))
305    ...
306    list[:0] -> []
307    list[:4] -> [1, 2, 3, 4]
308    list[:5] -> [1, 2, 3, 4, 5]
309    list[:-1] -> [1, 2, 3, 4]
310    list[:-5] -> []
311    list[:None] -> [1, 2, 3, 4, 5]
312    tuple[:0] -> ()
313    tuple[:4] -> (1, 2, 3, 4)
314    tuple[:5] -> (1, 2, 3, 4, 5)
315    tuple[:-1] -> (1, 2, 3, 4)
316    tuple[:-5] -> ()
317    tuple[:None] -> (1, 2, 3, 4, 5)
318    bytes[:0] ->
319    bytes[:4] -> 1234
320    bytes[:5] -> 12345
321    bytes[:-1] -> 1234
322    bytes[:-5] ->
323    bytes[:None] -> 12345
324    unicode[:0] ->
325    unicode[:4] -> 1234
326    unicode[:5] -> 12345
327    unicode[:-1] -> 1234
328    unicode[:-5] ->
329    unicode[:None] -> 12345
330    """
331    obj = seq[:stop]
332    return obj
333
334
335@cython.test_assert_path_exists("//SliceIndexNode//CondExprNode")
336def slice_fused_type_start_and_stop(slicable seq, start, stop):
337    """
338    >>> l = [1,2,3,4,5]
339    >>> t = tuple(l)
340    >>> b = ''.join(map(str, l)).encode('ASCII')
341    >>> u = b.decode('ASCII')
342    >>> o = (l, t, b, u)
343    >>> n = ('list', 'tuple', 'bytes', 'unicode')
344    >>> p = lambda o: o.decode() if isinstance(o, type(b)) else str(o)
345    >>> r = lambda i, t, s: '%s[%r:%r] -> %s' % (n[i], t, s, p(slice_fused_type_start_and_stop(o[i], t, s)))
346    >>> for i in range(len(o)):
347    ...     for start, stop in ((0, len(l)), (0, None), (None, len(l)),
348    ...                         (-len(l), 0), (1, 0), (0, 1)):
349    ...         print(r(i, start, stop))
350    ...
351    list[0:5] -> [1, 2, 3, 4, 5]
352    list[0:None] -> [1, 2, 3, 4, 5]
353    list[None:5] -> [1, 2, 3, 4, 5]
354    list[-5:0] -> []
355    list[1:0] -> []
356    list[0:1] -> [1]
357    tuple[0:5] -> (1, 2, 3, 4, 5)
358    tuple[0:None] -> (1, 2, 3, 4, 5)
359    tuple[None:5] -> (1, 2, 3, 4, 5)
360    tuple[-5:0] -> ()
361    tuple[1:0] -> ()
362    tuple[0:1] -> (1,)
363    bytes[0:5] -> 12345
364    bytes[0:None] -> 12345
365    bytes[None:5] -> 12345
366    bytes[-5:0] ->
367    bytes[1:0] ->
368    bytes[0:1] -> 1
369    unicode[0:5] -> 12345
370    unicode[0:None] -> 12345
371    unicode[None:5] -> 12345
372    unicode[-5:0] ->
373    unicode[1:0] ->
374    unicode[0:1] -> 1
375    """
376    obj = seq[start:stop]
377    return obj
378
379
380def slice_fused_type_step(slicable seq, step):
381    """
382    >>> l = [1,2,3,4,5]
383    >>> t = tuple(l)
384    >>> b = ''.join(map(str, l)).encode('ASCII')
385    >>> u = b.decode('ASCII')
386    >>> o = (l, t, b, u)
387    >>> n = ('list', 'tuple', 'bytes', 'unicode')
388    >>> p = lambda o: o.decode() if isinstance(o, type(b)) else str(o)
389    >>> r = lambda i, s: '%s[::%r] -> %s' % (n[i], s, p(slice_fused_type_step(o[i], s)))
390    >>> for i in range(len(o)):
391    ...     for s in (1, -1, 2, -3, 5, -5, None):
392    ...         print(r(i, s))
393    ...
394    list[::1] -> [1, 2, 3, 4, 5]
395    list[::-1] -> [5, 4, 3, 2, 1]
396    list[::2] -> [1, 3, 5]
397    list[::-3] -> [5, 2]
398    list[::5] -> [1]
399    list[::-5] -> [5]
400    list[::None] -> [1, 2, 3, 4, 5]
401    tuple[::1] -> (1, 2, 3, 4, 5)
402    tuple[::-1] -> (5, 4, 3, 2, 1)
403    tuple[::2] -> (1, 3, 5)
404    tuple[::-3] -> (5, 2)
405    tuple[::5] -> (1,)
406    tuple[::-5] -> (5,)
407    tuple[::None] -> (1, 2, 3, 4, 5)
408    bytes[::1] -> 12345
409    bytes[::-1] -> 54321
410    bytes[::2] -> 135
411    bytes[::-3] -> 52
412    bytes[::5] -> 1
413    bytes[::-5] -> 5
414    bytes[::None] -> 12345
415    unicode[::1] -> 12345
416    unicode[::-1] -> 54321
417    unicode[::2] -> 135
418    unicode[::-3] -> 52
419    unicode[::5] -> 1
420    unicode[::-5] -> 5
421    unicode[::None] -> 12345
422    >>> for v in o:
423    ...     try: slice_fused_type_step(v, 0)
424    ...     except ValueError: pass
425    ...     try: slice_fused_type_step(v, v)
426    ...     except TypeError: pass
427    """
428    obj = seq[::step]
429    return obj
430
431
432def slice_fused_type_start_and_step(slicable seq, start, step):
433    """
434    >>> l = [1,2,3,4,5]
435    >>> t = tuple(l)
436    >>> b = ''.join(map(str, l)).encode('ASCII')
437    >>> u = b.decode('ASCII')
438    >>> o = (l, t, b, u)
439    >>> n = ('list', 'tuple', 'bytes', 'unicode')
440    >>> p = lambda o: o.decode() if isinstance(o, type(b)) else str(o)
441    >>> r = lambda i, s, t: '%s[%r::%r] -> %s' % (n[i], s, t, p(slice_fused_type_start_and_step(o[i], s, t)))
442    >>> for i in range(len(o)):
443    ...     for start, step in ((0, 1), (0, -1), (1, 1), (1, -1),
444    ...                         (None, 1), (None, -1), (None, None),
445    ...                         (1, 2), (len(l), -2), (len(l), len(l))):
446    ...         print(r(i, start, step))
447    ...
448    list[0::1] -> [1, 2, 3, 4, 5]
449    list[0::-1] -> [1]
450    list[1::1] -> [2, 3, 4, 5]
451    list[1::-1] -> [2, 1]
452    list[None::1] -> [1, 2, 3, 4, 5]
453    list[None::-1] -> [5, 4, 3, 2, 1]
454    list[None::None] -> [1, 2, 3, 4, 5]
455    list[1::2] -> [2, 4]
456    list[5::-2] -> [5, 3, 1]
457    list[5::5] -> []
458    tuple[0::1] -> (1, 2, 3, 4, 5)
459    tuple[0::-1] -> (1,)
460    tuple[1::1] -> (2, 3, 4, 5)
461    tuple[1::-1] -> (2, 1)
462    tuple[None::1] -> (1, 2, 3, 4, 5)
463    tuple[None::-1] -> (5, 4, 3, 2, 1)
464    tuple[None::None] -> (1, 2, 3, 4, 5)
465    tuple[1::2] -> (2, 4)
466    tuple[5::-2] -> (5, 3, 1)
467    tuple[5::5] -> ()
468    bytes[0::1] -> 12345
469    bytes[0::-1] -> 1
470    bytes[1::1] -> 2345
471    bytes[1::-1] -> 21
472    bytes[None::1] -> 12345
473    bytes[None::-1] -> 54321
474    bytes[None::None] -> 12345
475    bytes[1::2] -> 24
476    bytes[5::-2] -> 531
477    bytes[5::5] ->
478    unicode[0::1] -> 12345
479    unicode[0::-1] -> 1
480    unicode[1::1] -> 2345
481    unicode[1::-1] -> 21
482    unicode[None::1] -> 12345
483    unicode[None::-1] -> 54321
484    unicode[None::None] -> 12345
485    unicode[1::2] -> 24
486    unicode[5::-2] -> 531
487    unicode[5::5] ->
488    >>> for o in (l, t, b):
489    ...     try: slice_fused_type_start_and_step(o, 0, 0)
490    ...     except ValueError: pass
491    """
492    obj = seq[start::step]
493    return obj
494
495
496def slice_fused_type_stop_and_step(slicable seq, stop, step):
497    """
498    >>> l = [1,2,3,4,5]
499    >>> t = tuple(l)
500    >>> b = ''.join(map(str, l)).encode('ASCII')
501    >>> u = b.decode('ASCII')
502    >>> o = (l, t, b, u)
503    >>> n = ('list', 'tuple', 'bytes', 'unicode')
504    >>> p = lambda o: o.decode() if isinstance(o, type(b)) else str(o)
505    >>> r = lambda i, s, t: '%s[:%r:%r] -> %s' % (n[i], s, t, p(slice_fused_type_stop_and_step(o[i], s, t)))
506    >>> for i in range(len(o)):
507    ...     for stop, step in ((len(l), 1), (len(l), None), (None, 1),
508    ...                        (len(l), -1), (len(l) - 1, 2), (len(l), -2),
509    ...                        (len(l), len(l))):
510    ...         print(r(i, stop, step))
511    ...
512    list[:5:1] -> [1, 2, 3, 4, 5]
513    list[:5:None] -> [1, 2, 3, 4, 5]
514    list[:None:1] -> [1, 2, 3, 4, 5]
515    list[:5:-1] -> []
516    list[:4:2] -> [1, 3]
517    list[:5:-2] -> []
518    list[:5:5] -> [1]
519    tuple[:5:1] -> (1, 2, 3, 4, 5)
520    tuple[:5:None] -> (1, 2, 3, 4, 5)
521    tuple[:None:1] -> (1, 2, 3, 4, 5)
522    tuple[:5:-1] -> ()
523    tuple[:4:2] -> (1, 3)
524    tuple[:5:-2] -> ()
525    tuple[:5:5] -> (1,)
526    bytes[:5:1] -> 12345
527    bytes[:5:None] -> 12345
528    bytes[:None:1] -> 12345
529    bytes[:5:-1] ->
530    bytes[:4:2] -> 13
531    bytes[:5:-2] ->
532    bytes[:5:5] -> 1
533    unicode[:5:1] -> 12345
534    unicode[:5:None] -> 12345
535    unicode[:None:1] -> 12345
536    unicode[:5:-1] ->
537    unicode[:4:2] -> 13
538    unicode[:5:-2] ->
539    unicode[:5:5] -> 1
540    >>> for v in o:
541    ...     try: slice_fused_type_stop_and_step(v, len(l), 0)
542    ...     except ValueError: pass
543    ...     try: slice_fused_type_stop_and_step(v, len(l), v)
544    ...     except TypeError: pass
545    """
546    obj = seq[:stop:step]
547    return obj
548
549
550def slice_fused_type_all(slicable seq, start, stop, step):
551    """
552    >>> l = [1,2,3,4,5]
553    >>> t = tuple(l)
554    >>> b = ''.join(map(str, l)).encode('ASCII')
555    >>> u = b.decode('ASCII')
556    >>> o = (l, t, b, u)
557    >>> n = ('list', 'tuple', 'bytes', 'unicode')
558    >>> p = lambda o: o.decode() if isinstance(o, type(b)) else str(o)
559    >>> r = lambda i, s, t, e: '%s[%r:%r:%r] -> %s' % (n[i], s, t, e, p(slice_fused_type_all(o[i], s, t, e)))
560    >>> for i in range(len(o)):
561    ...     for args in ((0, len(l), 1), (len(l), 0, -1), (None, len(l), 1),
562    ...                  (len(l), None, -1), (-len(l), len(l), None), (None, None, None),
563    ...                  (1, 3, 2), (len(l), 1, -3), (len(l), 0, 1)):
564    ...         print(r(i, *args))
565    ...
566    list[0:5:1] -> [1, 2, 3, 4, 5]
567    list[5:0:-1] -> [5, 4, 3, 2]
568    list[None:5:1] -> [1, 2, 3, 4, 5]
569    list[5:None:-1] -> [5, 4, 3, 2, 1]
570    list[-5:5:None] -> [1, 2, 3, 4, 5]
571    list[None:None:None] -> [1, 2, 3, 4, 5]
572    list[1:3:2] -> [2]
573    list[5:1:-3] -> [5]
574    list[5:0:1] -> []
575    tuple[0:5:1] -> (1, 2, 3, 4, 5)
576    tuple[5:0:-1] -> (5, 4, 3, 2)
577    tuple[None:5:1] -> (1, 2, 3, 4, 5)
578    tuple[5:None:-1] -> (5, 4, 3, 2, 1)
579    tuple[-5:5:None] -> (1, 2, 3, 4, 5)
580    tuple[None:None:None] -> (1, 2, 3, 4, 5)
581    tuple[1:3:2] -> (2,)
582    tuple[5:1:-3] -> (5,)
583    tuple[5:0:1] -> ()
584    bytes[0:5:1] -> 12345
585    bytes[5:0:-1] -> 5432
586    bytes[None:5:1] -> 12345
587    bytes[5:None:-1] -> 54321
588    bytes[-5:5:None] -> 12345
589    bytes[None:None:None] -> 12345
590    bytes[1:3:2] -> 2
591    bytes[5:1:-3] -> 5
592    bytes[5:0:1] ->
593    unicode[0:5:1] -> 12345
594    unicode[5:0:-1] -> 5432
595    unicode[None:5:1] -> 12345
596    unicode[5:None:-1] -> 54321
597    unicode[-5:5:None] -> 12345
598    unicode[None:None:None] -> 12345
599    unicode[1:3:2] -> 2
600    unicode[5:1:-3] -> 5
601    unicode[5:0:1] ->
602    >>> for v in o:
603    ...     try: slice_fused_type_stop_and_step(v, len(l), 0)
604    ...     except ValueError: pass
605    ...     try: slice_fused_type_stop_and_step(v, len(l), v)
606    ...     except TypeError: pass
607    """
608    obj = seq[start:stop:step]
609    return obj
610