1# mode: run
2
3# NOTE: Py2.6+ only
4
5
6cimport cython
7
8cpdef bytearray coerce_to_charptr(char* b):
9    """
10    >>> b = bytearray(b'abc')
11    >>> coerced = coerce_to_charptr(b)
12    >>> coerced == b or coerced
13    True
14    >>> isinstance(coerced, bytearray) or type(coerced)
15    True
16    """
17    return b
18
19def coerce_to_charptrs(bytearray b):
20    """
21    >>> b = bytearray(b'abc')
22    >>> coerce_to_charptrs(b)
23    True
24    """
25    cdef char* cs = b
26    cdef unsigned char* ucs = b
27    cdef signed char* scs = b
28    return b == <bytearray>cs == <bytearray> ucs == <bytearray>scs
29
30cpdef bytearray coerce_charptr_slice(char* b):
31    """
32    >>> b = bytearray(b'abc')
33    >>> coerced = coerce_charptr_slice(b)
34    >>> coerced == b[:2] or coerced
35    True
36    >>> isinstance(coerced, bytearray) or type(coerced)
37    True
38    """
39    return b[:2]
40
41
42def infer_concatenation_types(bytearray b):
43    """
44    >>> b = bytearray(b'a\\xFEc')
45    >>> b2, c, d, e, tb, tc, td, te = infer_concatenation_types(b)
46    >>> tb, tc, td, te
47    ('bytearray object', 'bytearray object', 'bytearray object', 'bytearray object')
48    >>> b2, c, d, e
49    (bytearray(b'a\\xfec'), bytearray(b'a\\xfeca\\xfec'), bytearray(b'a\\xfeca\\xfec'), bytearray(b'a\\xfeca\\xfec'))
50    """
51    c = b[:]
52    c += b[:]
53
54    d = b[:]
55    d *= 2
56
57    e = b + b
58
59    return b, c, d, e, cython.typeof(b), cython.typeof(c), cython.typeof(d), cython.typeof(e)
60
61
62def infer_index_types(bytearray b):
63    """
64    >>> b = bytearray(b'a\\xFEc')
65    >>> print(infer_index_types(b))
66    (254, 254, 254, 'unsigned char', 'unsigned char', 'unsigned char', 'int')
67    """
68    c = b[1]
69    with cython.wraparound(False):
70        d = b[1]
71    with cython.boundscheck(False):
72        e = b[1]
73    return c, d, e, cython.typeof(c), cython.typeof(d), cython.typeof(e), cython.typeof(b[1])
74
75
76def infer_slice_types(bytearray b):
77    """
78    >>> b = bytearray(b'abc')
79    >>> print(infer_slice_types(b))
80    (bytearray(b'bc'), bytearray(b'bc'), bytearray(b'bc'), 'bytearray object', 'bytearray object', 'bytearray object', 'bytearray object')
81    """
82    c = b[1:]
83    with cython.boundscheck(False):
84        d = b[1:]
85    with cython.boundscheck(False), cython.wraparound(False):
86        e = b[1:]
87    return c, d, e, cython.typeof(c), cython.typeof(d), cython.typeof(e), cython.typeof(b[1:])
88
89
90def assign_to_index(bytearray b, value):
91    """
92    >>> b = bytearray(b'0abcdefg')
93    >>> assign_to_index(b, 1)
94    bytearray(b'xyzee\\x01h')
95    >>> b
96    bytearray(b'xyzee\\x01h')
97
98    >>> assign_to_index(bytearray(b'0ABCDEFG'), 40)
99    bytearray(b'xyzEE(o')
100
101    >>> assign_to_index(bytearray(b'0abcdefg'), -1)
102    Traceback (most recent call last):
103    OverflowError: can't convert negative value to unsigned char
104
105    >>> assign_to_index(bytearray(b'0abcdef\\x00'), 255)
106    bytearray(b'xyzee\\xff\\xff')
107    >>> assign_to_index(bytearray(b'0abcdef\\x01'), 255)
108    Traceback (most recent call last):
109    OverflowError: value too large to convert to unsigned char
110    >>> assign_to_index(bytearray(b'0abcdef\\x00'), 256)
111    Traceback (most recent call last):
112    OverflowError: value too large to convert to unsigned char
113    """
114    b[1] = 'x'
115    b[2] = b'y'
116    b[3] = c'z'
117    b[4] += 1
118    b[5] |= 1
119    b[6] = value
120    b[7] += value
121    del b[0]
122
123    try:
124        b[7] = 1
125    except IndexError:
126        pass
127    else:
128        assert False, "IndexError not raised"
129
130    try:
131        b[int(str(len(b)))] = 1   # test non-int-index assignment
132    except IndexError:
133        pass
134    else:
135        assert False, "IndexError not raised"
136
137    return b
138
139
140def check_bounds(int cvalue):
141    """
142    >>> check_bounds(0)
143    0
144    >>> check_bounds(255)
145    255
146    >>> check_bounds(256)
147    Traceback (most recent call last):
148    ValueError: byte must be in range(0, 256)
149    >>> check_bounds(-1)
150    Traceback (most recent call last):
151    ValueError: byte must be in range(0, 256)
152    """
153    b = bytearray(b'x')
154
155    try:
156        b[0] = 256
157    except ValueError:
158        pass
159    else:
160        assert False, "ValueError not raised"
161
162    try:
163        b[0] = -1
164    except ValueError:
165        pass
166    else:
167        assert False, "ValueError not raised"
168
169    b[0] = cvalue
170    return b[0]
171
172
173def nogil_assignment(bytearray x, int value):
174    """
175    >>> b = bytearray(b'abc')
176    >>> nogil_assignment(b, ord('y'))
177    >>> b
178    bytearray(b'xyc')
179    """
180    with nogil:
181        x[0] = 'x'
182        x[1] = value
183