Coverage Report

Created: 2022-07-08 09:39

/home/mdboom/Work/builds/cpython/Objects/bytes_methods.c
Line
Count
Source (jump to first uncovered line)
1
#define PY_SSIZE_T_CLEAN
2
#include "Python.h"
3
#include "pycore_abstract.h"   // _PyIndex_Check()
4
#include "pycore_bytes_methods.h"
5
6
PyDoc_STRVAR_shared(_Py_isspace__doc__,
7
"B.isspace() -> bool\n\
8
\n\
9
Return True if all characters in B are whitespace\n\
10
and there is at least one character in B, False otherwise.");
11
12
PyObject*
13
_Py_bytes_isspace(const char *cptr, Py_ssize_t len)
14
{
15
    const unsigned char *p
16
        = (const unsigned char *) cptr;
17
    const unsigned char *e;
18
19
    /* Shortcut for single character strings */
20
    if (len == 1 && 
Py_ISSPACE10
(*p))
  Branch (20:9): [True: 10, False: 10]
21
        Py_RETURN_TRUE;
22
23
    /* Special case for empty strings */
24
    if (len == 0)
  Branch (24:9): [True: 2, False: 10]
25
        Py_RETURN_FALSE;
26
27
    e = p + len;
28
    for (; p < e; 
p++20.6k
) {
  Branch (28:12): [True: 20.6k, False: 4]
29
        if (!Py_ISSPACE(*p))
  Branch (29:13): [True: 6, False: 20.6k]
30
            Py_RETURN_FALSE;
31
    }
32
    
Py_RETURN_TRUE4
;
33
}
34
35
36
PyDoc_STRVAR_shared(_Py_isalpha__doc__,
37
"B.isalpha() -> bool\n\
38
\n\
39
Return True if all characters in B are alphabetic\n\
40
and there is at least one character in B, False otherwise.");
41
42
PyObject*
43
_Py_bytes_isalpha(const char *cptr, Py_ssize_t len)
44
{
45
    const unsigned char *p
46
        = (const unsigned char *) cptr;
47
    const unsigned char *e;
48
49
    /* Shortcut for single character strings */
50
    if (len == 1 && 
Py_ISALPHA6
(*p))
  Branch (50:9): [True: 6, False: 12]
51
        Py_RETURN_TRUE;
52
53
    /* Special case for empty strings */
54
    if (len == 0)
  Branch (54:9): [True: 2, False: 12]
55
        Py_RETURN_FALSE;
56
57
    e = p + len;
58
    for (; p < e; 
p++20.6k
) {
  Branch (58:12): [True: 20.6k, False: 4]
59
        if (!Py_ISALPHA(*p))
  Branch (59:13): [True: 8, False: 20.6k]
60
            Py_RETURN_FALSE;
61
    }
62
    
Py_RETURN_TRUE4
;
63
}
64
65
66
PyDoc_STRVAR_shared(_Py_isalnum__doc__,
67
"B.isalnum() -> bool\n\
68
\n\
69
Return True if all characters in B are alphanumeric\n\
70
and there is at least one character in B, False otherwise.");
71
72
PyObject*
73
_Py_bytes_isalnum(const char *cptr, Py_ssize_t len)
74
{
75
    const unsigned char *p
76
        = (const unsigned char *) cptr;
77
    const unsigned char *e;
78
79
    /* Shortcut for single character strings */
80
    if (len == 1 && 
Py_ISALNUM6
(*p))
  Branch (80:9): [True: 6, False: 14]
81
        Py_RETURN_TRUE;
82
83
    /* Special case for empty strings */
84
    if (len == 0)
  Branch (84:9): [True: 2, False: 14]
85
        Py_RETURN_FALSE;
86
87
    e = p + len;
88
    for (; p < e; 
p++20.6k
) {
  Branch (88:12): [True: 20.6k, False: 6]
89
        if (!Py_ISALNUM(*p))
  Branch (89:13): [True: 8, False: 20.6k]
90
            Py_RETURN_FALSE;
91
    }
92
    
Py_RETURN_TRUE6
;
93
}
94
95
96
PyDoc_STRVAR_shared(_Py_isascii__doc__,
97
"B.isascii() -> bool\n\
98
\n\
99
Return True if B is empty or all characters in B are ASCII,\n\
100
False otherwise.");
101
102
// Optimization is copied from ascii_decode in unicodeobject.c
103
/* Mask to quickly check whether a C 'size_t' contains a
104
   non-ASCII, UTF8-encoded char. */
105
#if (SIZEOF_SIZE_T == 8)
106
# define ASCII_CHAR_MASK 0x8080808080808080ULL
107
#elif (SIZEOF_SIZE_T == 4)
108
# define ASCII_CHAR_MASK 0x80808080U
109
#else
110
# error C 'size_t' size should be either 4 or 8!
111
#endif
112
113
PyObject*
114
_Py_bytes_isascii(const char *cptr, Py_ssize_t len)
115
{
116
    const char *p = cptr;
117
    const char *end = p + len;
118
119
    while (p < end) {
  Branch (119:12): [True: 190, False: 36]
120
        /* Fast path, see in STRINGLIB(utf8_decode) in stringlib/codecs.h
121
           for an explanation. */
122
        if (_Py_IS_ALIGNED(p, ALIGNOF_SIZE_T)) {
123
            /* Help allocation */
124
            const char *_p = p;
125
            while (_p + SIZEOF_SIZE_T <= end) {
  Branch (125:20): [True: 40, False: 54]
126
                size_t value = *(const size_t *) _p;
127
                if (value & ASCII_CHAR_MASK) {
  Branch (127:21): [True: 20, False: 20]
128
                    Py_RETURN_FALSE;
129
                }
130
                _p += SIZEOF_SIZE_T;
131
            }
132
            p = _p;
133
            if (_p == end)
  Branch (133:17): [True: 4, False: 50]
134
                break;
135
        }
136
        if ((unsigned char)*p & 0x80) {
  Branch (136:13): [True: 16, False: 150]
137
            Py_RETURN_FALSE;
138
        }
139
        p++;
140
    }
141
    
Py_RETURN_TRUE40
;
142
}
143
144
#undef ASCII_CHAR_MASK
145
146
147
PyDoc_STRVAR_shared(_Py_isdigit__doc__,
148
"B.isdigit() -> bool\n\
149
\n\
150
Return True if all characters in B are digits\n\
151
and there is at least one character in B, False otherwise.");
152
153
PyObject*
154
_Py_bytes_isdigit(const char *cptr, Py_ssize_t len)
155
{
156
    const unsigned char *p
157
        = (const unsigned char *) cptr;
158
    const unsigned char *e;
159
160
    /* Shortcut for single character strings */
161
    if (len == 1 && 
Py_ISDIGIT4
(*p))
  Branch (161:9): [True: 4, False: 10]
162
        Py_RETURN_TRUE;
163
164
    /* Special case for empty strings */
165
    if (len == 0)
  Branch (165:9): [True: 2, False: 10]
166
        Py_RETURN_FALSE;
167
168
    e = p + len;
169
    for (; p < e; 
p++20.6k
) {
  Branch (169:12): [True: 20.6k, False: 4]
170
        if (!Py_ISDIGIT(*p))
  Branch (170:13): [True: 6, False: 20.6k]
171
            Py_RETURN_FALSE;
172
    }
173
    
Py_RETURN_TRUE4
;
174
}
175
176
177
PyDoc_STRVAR_shared(_Py_islower__doc__,
178
"B.islower() -> bool\n\
179
\n\
180
Return True if all cased characters in B are lowercase and there is\n\
181
at least one cased character in B, False otherwise.");
182
183
PyObject*
184
_Py_bytes_islower(const char *cptr, Py_ssize_t len)
185
{
186
    const unsigned char *p
187
        = (const unsigned char *) cptr;
188
    const unsigned char *e;
189
    int cased;
190
191
    /* Shortcut for single character strings */
192
    if (len == 1)
  Branch (192:9): [True: 6, False: 12]
193
        return PyBool_FromLong(Py_ISLOWER(*p));
194
195
    /* Special case for empty strings */
196
    if (len == 0)
  Branch (196:9): [True: 2, False: 10]
197
        Py_RETURN_FALSE;
198
199
    e = p + len;
200
    cased = 0;
201
    for (; p < e; 
p++21.5k
) {
  Branch (201:12): [True: 21.5k, False: 6]
202
        if (Py_ISUPPER(*p))
203
            Py_RETURN_FALSE;
204
        else if (!cased && 
Py_ISLOWER294
(*p))
  Branch (204:18): [True: 294, False: 21.2k]
205
            cased = 1;
206
    }
207
    return PyBool_FromLong(cased);
208
}
209
210
211
PyDoc_STRVAR_shared(_Py_isupper__doc__,
212
"B.isupper() -> bool\n\
213
\n\
214
Return True if all cased characters in B are uppercase and there is\n\
215
at least one cased character in B, False otherwise.");
216
217
PyObject*
218
_Py_bytes_isupper(const char *cptr, Py_ssize_t len)
219
{
220
    const unsigned char *p
221
        = (const unsigned char *) cptr;
222
    const unsigned char *e;
223
    int cased;
224
225
    /* Shortcut for single character strings */
226
    if (len == 1)
  Branch (226:9): [True: 6, False: 12]
227
        return PyBool_FromLong(Py_ISUPPER(*p));
228
229
    /* Special case for empty strings */
230
    if (len == 0)
  Branch (230:9): [True: 2, False: 10]
231
        Py_RETURN_FALSE;
232
233
    e = p + len;
234
    cased = 0;
235
    for (; p < e; 
p++21.8k
) {
  Branch (235:12): [True: 21.8k, False: 6]
236
        if (Py_ISLOWER(*p))
237
            Py_RETURN_FALSE;
238
        else if (!cased && 
Py_ISUPPER270
(*p))
  Branch (238:18): [True: 270, False: 21.5k]
239
            cased = 1;
240
    }
241
    return PyBool_FromLong(cased);
242
}
243
244
245
PyDoc_STRVAR_shared(_Py_istitle__doc__,
246
"B.istitle() -> bool\n\
247
\n\
248
Return True if B is a titlecased string and there is at least one\n\
249
character in B, i.e. uppercase characters may only follow uncased\n\
250
characters and lowercase characters only cased ones. Return False\n\
251
otherwise.");
252
253
PyObject*
254
_Py_bytes_istitle(const char *cptr, Py_ssize_t len)
255
{
256
    const unsigned char *p
257
        = (const unsigned char *) cptr;
258
    const unsigned char *e;
259
    int cased, previous_is_cased;
260
261
    /* Shortcut for single character strings */
262
    if (len == 1)
  Branch (262:9): [True: 6, False: 22]
263
        return PyBool_FromLong(Py_ISUPPER(*p));
264
265
    /* Special case for empty strings */
266
    if (len == 0)
  Branch (266:9): [True: 2, False: 20]
267
        Py_RETURN_FALSE;
268
269
    e = p + len;
270
    cased = 0;
271
    previous_is_cased = 0;
272
    for (; p < e; 
p++31.0k
) {
  Branch (272:12): [True: 31.0k, False: 10]
273
        const unsigned char ch = *p;
274
275
        if (Py_ISUPPER(ch)) {
276
            if (previous_is_cased)
  Branch (276:17): [True: 4, False: 36]
277
                Py_RETURN_FALSE;
278
            previous_is_cased = 1;
279
            cased = 1;
280
        }
281
        else if (Py_ISLOWER(ch)) {
282
            if (!previous_is_cased)
  Branch (282:17): [True: 6, False: 30.9k]
283
                Py_RETURN_FALSE;
284
            previous_is_cased = 1;
285
            cased = 1;
286
        }
287
        else
288
            previous_is_cased = 0;
289
    }
290
    return PyBool_FromLong(cased);
291
}
292
293
294
PyDoc_STRVAR_shared(_Py_lower__doc__,
295
"B.lower() -> copy of B\n\
296
\n\
297
Return a copy of B with all ASCII characters converted to lowercase.");
298
299
void
300
_Py_bytes_lower(char *result, const char *cptr, Py_ssize_t len)
301
{
302
    Py_ssize_t i;
303
304
    for (i = 0; i < len; 
i++4.69M
) {
  Branch (304:17): [True: 4.69M, False: 412k]
305
        result[i] = Py_TOLOWER((unsigned char) cptr[i]);
306
    }
307
}
308
309
310
PyDoc_STRVAR_shared(_Py_upper__doc__,
311
"B.upper() -> copy of B\n\
312
\n\
313
Return a copy of B with all ASCII characters converted to uppercase.");
314
315
void
316
_Py_bytes_upper(char *result, const char *cptr, Py_ssize_t len)
317
{
318
    Py_ssize_t i;
319
320
    for (i = 0; i < len; 
i++105k
) {
  Branch (320:17): [True: 105k, False: 8.19k]
321
        result[i] = Py_TOUPPER((unsigned char) cptr[i]);
322
    }
323
}
324
325
326
PyDoc_STRVAR_shared(_Py_title__doc__,
327
"B.title() -> copy of B\n\
328
\n\
329
Return a titlecased version of B, i.e. ASCII words start with uppercase\n\
330
characters, all remaining cased characters have lowercase.");
331
332
void
333
_Py_bytes_title(char *result, const char *s, Py_ssize_t len)
334
{
335
    Py_ssize_t i;
336
    int previous_is_cased = 0;
337
338
    for (i = 0; i < len; 
i++10.5k
) {
  Branch (338:17): [True: 10.5k, False: 16]
339
        int c = Py_CHARMASK(*s++);
340
        if (Py_ISLOWER(c)) {
341
            if (!previous_is_cased)
  Branch (341:17): [True: 22, False: 7.28k]
342
                c = Py_TOUPPER(c);
343
            previous_is_cased = 1;
344
        } else 
if (3.25k
Py_ISUPPER3.25k
(c)) {
345
            if (previous_is_cased)
  Branch (345:17): [True: 3.22k, False: 10]
346
                c = Py_TOLOWER(c);
347
            previous_is_cased = 1;
348
        } else
349
            previous_is_cased = 0;
350
        *result++ = c;
351
    }
352
}
353
354
355
PyDoc_STRVAR_shared(_Py_capitalize__doc__,
356
"B.capitalize() -> copy of B\n\
357
\n\
358
Return a copy of B with only its first character capitalized (ASCII)\n\
359
and the rest lower-cased.");
360
361
void
362
_Py_bytes_capitalize(char *result, const char *s, Py_ssize_t len)
363
{
364
    if (len > 0) {
  Branch (364:9): [True: 14, False: 0]
365
        *result = Py_TOUPPER(*s);
366
        _Py_bytes_lower(result + 1, s + 1, len - 1);
367
    }
368
}
369
370
371
PyDoc_STRVAR_shared(_Py_swapcase__doc__,
372
"B.swapcase() -> copy of B\n\
373
\n\
374
Return a copy of B with uppercase ASCII characters converted\n\
375
to lowercase ASCII and vice versa.");
376
377
void
378
_Py_bytes_swapcase(char *result, const char *s, Py_ssize_t len)
379
{
380
    Py_ssize_t i;
381
382
    for (i = 0; i < len; 
i++10.4k
) {
  Branch (382:17): [True: 10.4k, False: 8]
383
        int c = Py_CHARMASK(*s++);
384
        if (Py_ISLOWER(c)) {
385
            *result = Py_TOUPPER(c);
386
        }
387
        else if (Py_ISUPPER(c)) {
388
            *result = Py_TOLOWER(c);
389
        }
390
        else
391
            *result = c;
392
        result++;
393
    }
394
}
395
396
397
PyDoc_STRVAR_shared(_Py_maketrans__doc__,
398
"B.maketrans(frm, to) -> translation table\n\
399
\n\
400
Return a translation table (a bytes object of length 256) suitable\n\
401
for use in the bytes or bytearray translate method where each byte\n\
402
in frm is mapped to the byte at the same position in to.\n\
403
The bytes objects frm and to must be of the same length.");
404
405
PyObject *
406
_Py_bytes_maketrans(Py_buffer *frm, Py_buffer *to)
407
{
408
    PyObject *res = NULL;
409
    Py_ssize_t i;
410
    char *p;
411
412
    if (frm->len != to->len) {
  Branch (412:9): [True: 2, False: 97]
413
        PyErr_Format(PyExc_ValueError,
414
                     "maketrans arguments must have same length");
415
        return NULL;
416
    }
417
    res = PyBytes_FromStringAndSize(NULL, 256);
418
    if (!res)
  Branch (418:9): [True: 0, False: 97]
419
        return NULL;
420
    p = PyBytes_AS_STRING(res);
421
    for (i = 0; i < 256; 
i++24.8k
)
  Branch (421:17): [True: 24.8k, False: 97]
422
        p[i] = (char) i;
423
    for (i = 0; i < frm->len; 
i++272
) {
  Branch (423:17): [True: 272, False: 97]
424
        p[((unsigned char *)frm->buf)[i]] = ((char *)to->buf)[i];
425
    }
426
427
    return res;
428
}
429
430
#define FASTSEARCH fastsearch
431
#define STRINGLIB(F) stringlib_##F
432
#define STRINGLIB_CHAR char
433
#define STRINGLIB_SIZEOF_CHAR 1
434
#define STRINGLIB_FAST_MEMCHR memchr
435
436
#include "stringlib/fastsearch.h"
437
#include "stringlib/count.h"
438
#include "stringlib/find.h"
439
440
/*
441
Wraps stringlib_parse_args_finds() and additionally checks the first
442
argument type.
443
444
In case the first argument is a bytes-like object, sets it to subobj,
445
and doesn't touch the byte parameter.
446
In case it is an integer in range(0, 256), writes the integer value
447
to byte, and sets subobj to NULL.
448
449
The other parameters are similar to those of
450
stringlib_parse_args_finds().
451
*/
452
453
Py_LOCAL_INLINE(int)
454
parse_args_finds_byte(const char *function_name, PyObject *args,
455
                      PyObject **subobj, char *byte,
456
                      Py_ssize_t *start, Py_ssize_t *end)
457
{
458
    PyObject *tmp_subobj;
459
    Py_ssize_t ival;
460
461
    if(!stringlib_parse_args_finds(function_name, args, &tmp_subobj,
  Branch (461:8): [True: 20, False: 895k]
462
                                   start, end))
463
        return 0;
464
465
    if (PyObject_CheckBuffer(tmp_subobj)) {
  Branch (465:9): [True: 880k, False: 15.5k]
466
        *subobj = tmp_subobj;
467
        return 1;
468
    }
469
470
    if (!_PyIndex_Check(tmp_subobj)) {
  Branch (470:9): [True: 0, False: 15.5k]
471
        PyErr_Format(PyExc_TypeError,
472
                     "argument should be integer or bytes-like object, "
473
                     "not '%.200s'",
474
                     Py_TYPE(tmp_subobj)->tp_name);
475
        return 0;
476
    }
477
478
    ival = PyNumber_AsSsize_t(tmp_subobj, NULL);
479
    if (ival == -1 && 
PyErr_Occurred()12
) {
  Branch (479:9): [True: 12, False: 15.5k]
  Branch (479:23): [True: 0, False: 12]
480
        return 0;
481
    }
482
    if (ival < 0 || 
ival > 25515.5k
) {
  Branch (482:9): [True: 12, False: 15.5k]
  Branch (482:21): [True: 24, False: 15.5k]
483
        PyErr_SetString(PyExc_ValueError, "byte must be in range(0, 256)");
484
        return 0;
485
    }
486
487
    *subobj = NULL;
488
    *byte = (char)ival;
489
    return 1;
490
}
491
492
/* helper macro to fixup start/end slice values */
493
#define ADJUST_INDICES(start, end, len)         \
494
    if (end > len)                          \
495
        
end = len1.17M
; \
496
    else 
if (156
end < 0156
) { \
497
        end += len;                         \
498
        if (end < 0)                        \
499
        
end = 02
; \
500
    }                                       \
501
    if (start < 0) {                        \
502
        start += len;                       \
503
        if (start < 0)                      \
504
        
start = 04
; \
505
    }
506
507
Py_LOCAL_INLINE(Py_ssize_t)
508
find_internal(const char *str, Py_ssize_t len,
509
              const char *function_name, PyObject *args, int dir)
510
{
511
    PyObject *subobj;
512
    char byte;
513
    Py_buffer subbuf;
514
    const char *sub;
515
    Py_ssize_t sub_len;
516
    Py_ssize_t start = 0, end = PY_SSIZE_T_MAX;
517
    Py_ssize_t res;
518
519
    if (!parse_args_finds_byte(function_name, args,
  Branch (519:9): [True: 46, False: 754k]
520
                               &subobj, &byte, &start, &end))
521
        return -2;
522
523
    if (subobj) {
  Branch (523:9): [True: 739k, False: 15.4k]
524
        if (PyObject_GetBuffer(subobj, &subbuf, PyBUF_SIMPLE) != 0)
  Branch (524:13): [True: 0, False: 739k]
525
            return -2;
526
527
        sub = subbuf.buf;
528
        sub_len = subbuf.len;
529
    }
530
    else {
531
        sub = &byte;
532
        sub_len = 1;
533
    }
534
535
    ADJUST_INDICES(start, end, len);
536
    if (end - start < sub_len)
  Branch (536:9): [True: 132k, False: 622k]
537
        res = -1;
538
    else if (sub_len == 1) {
  Branch (538:14): [True: 224k, False: 397k]
539
        if (dir > 0)
  Branch (539:13): [True: 217k, False: 7.39k]
540
            res = stringlib_find_char(
541
                str + start, end - start,
542
                *sub);
543
        else
544
            res = stringlib_rfind_char(
545
                str + start, end - start,
546
                *sub);
547
        if (res >= 0)
  Branch (547:13): [True: 203k, False: 21.5k]
548
            res += start;
549
    }
550
    else {
551
        if (dir > 0)
  Branch (551:13): [True: 200k, False: 196k]
552
            res = stringlib_find_slice(
553
                str, len,
554
                sub, sub_len, start, end);
555
        else
556
            res = stringlib_rfind_slice(
557
                str, len,
558
                sub, sub_len, start, end);
559
    }
560
561
    if (subobj)
  Branch (561:9): [True: 739k, False: 15.4k]
562
        PyBuffer_Release(&subbuf);
563
564
    return res;
565
}
566
567
PyDoc_STRVAR_shared(_Py_find__doc__,
568
"B.find(sub[, start[, end]]) -> int\n\
569
\n\
570
Return the lowest index in B where subsection sub is found,\n\
571
such that sub is contained within B[start,end].  Optional\n\
572
arguments start and end are interpreted as in slice notation.\n\
573
\n\
574
Return -1 on failure.");
575
576
PyObject *
577
_Py_bytes_find(const char *str, Py_ssize_t len, PyObject *args)
578
{
579
    Py_ssize_t result = find_internal(str, len, "find", args, +1);
580
    if (result == -2)
  Branch (580:9): [True: 16, False: 484k]
581
        return NULL;
582
    return PyLong_FromSsize_t(result);
583
}
584
585
PyDoc_STRVAR_shared(_Py_index__doc__,
586
"B.index(sub[, start[, end]]) -> int\n\
587
\n\
588
Return the lowest index in B where subsection sub is found,\n\
589
such that sub is contained within B[start,end].  Optional\n\
590
arguments start and end are interpreted as in slice notation.\n\
591
\n\
592
Raises ValueError when the subsection is not found.");
593
594
PyObject *
595
_Py_bytes_index(const char *str, Py_ssize_t len, PyObject *args)
596
{
597
    Py_ssize_t result = find_internal(str, len, "index", args, +1);
598
    if (result == -2)
  Branch (598:9): [True: 10, False: 123]
599
        return NULL;
600
    if (result == -1) {
  Branch (600:9): [True: 33, False: 90]
601
        PyErr_SetString(PyExc_ValueError,
602
                        "subsection not found");
603
        return NULL;
604
    }
605
    return PyLong_FromSsize_t(result);
606
}
607
608
PyDoc_STRVAR_shared(_Py_rfind__doc__,
609
"B.rfind(sub[, start[, end]]) -> int\n\
610
\n\
611
Return the highest index in B where subsection sub is found,\n\
612
such that sub is contained within B[start,end].  Optional\n\
613
arguments start and end are interpreted as in slice notation.\n\
614
\n\
615
Return -1 on failure.");
616
617
PyObject *
618
_Py_bytes_rfind(const char *str, Py_ssize_t len, PyObject *args)
619
{
620
    Py_ssize_t result = find_internal(str, len, "rfind", args, -1);
621
    if (result == -2)
  Branch (621:9): [True: 10, False: 270k]
622
        return NULL;
623
    return PyLong_FromSsize_t(result);
624
}
625
626
PyDoc_STRVAR_shared(_Py_rindex__doc__,
627
"B.rindex(sub[, start[, end]]) -> int\n\
628
\n\
629
Return the highest index in B where subsection sub is found,\n\
630
such that sub is contained within B[start,end].  Optional\n\
631
arguments start and end are interpreted as in slice notation.\n\
632
\n\
633
Raise ValueError when the subsection is not found.");
634
635
PyObject *
636
_Py_bytes_rindex(const char *str, Py_ssize_t len, PyObject *args)
637
{
638
    Py_ssize_t result = find_internal(str, len, "rindex", args, -1);
639
    if (result == -2)
  Branch (639:9): [True: 10, False: 84]
640
        return NULL;
641
    if (result == -1) {
  Branch (641:9): [True: 24, False: 60]
642
        PyErr_SetString(PyExc_ValueError,
643
                        "subsection not found");
644
        return NULL;
645
    }
646
    return PyLong_FromSsize_t(result);
647
}
648
649
PyDoc_STRVAR_shared(_Py_count__doc__,
650
"B.count(sub[, start[, end]]) -> int\n\
651
\n\
652
Return the number of non-overlapping occurrences of subsection sub in\n\
653
bytes B[start:end].  Optional arguments start and end are interpreted\n\
654
as in slice notation.");
655
656
PyObject *
657
_Py_bytes_count(const char *str, Py_ssize_t len, PyObject *args)
658
{
659
    PyObject *sub_obj;
660
    const char *sub;
661
    Py_ssize_t sub_len;
662
    char byte;
663
    Py_ssize_t start = 0, end = PY_SSIZE_T_MAX;
664
665
    Py_buffer vsub;
666
    PyObject *count_obj;
667
668
    if (!parse_args_finds_byte("count", args,
  Branch (668:9): [True: 10, False: 141k]
669
                               &sub_obj, &byte, &start, &end))
670
        return NULL;
671
672
    if (sub_obj) {
  Branch (672:9): [True: 140k, False: 14]
673
        if (PyObject_GetBuffer(sub_obj, &vsub, PyBUF_SIMPLE) != 0)
  Branch (673:13): [True: 0, False: 140k]
674
            return NULL;
675
676
        sub = vsub.buf;
677
        sub_len = vsub.len;
678
    }
679
    else {
680
        sub = &byte;
681
        sub_len = 1;
682
    }
683
684
    ADJUST_INDICES(start, end, len);
685
686
    count_obj = PyLong_FromSsize_t(
687
        stringlib_count(str + start, end - start, sub, sub_len, PY_SSIZE_T_MAX)
688
        );
689
690
    if (sub_obj)
  Branch (690:9): [True: 140k, False: 14]
691
        PyBuffer_Release(&vsub);
692
693
    return count_obj;
694
}
695
696
int
697
_Py_bytes_contains(const char *str, Py_ssize_t len, PyObject *arg)
698
{
699
    Py_ssize_t ival = PyNumber_AsSsize_t(arg, NULL);
700
    if (ival == -1 && 
PyErr_Occurred()627k
) {
  Branch (700:9): [True: 627k, False: 7.09k]
  Branch (700:23): [True: 627k, False: 2]
701
        Py_buffer varg;
702
        Py_ssize_t pos;
703
        PyErr_Clear();
704
        if (PyObject_GetBuffer(arg, &varg, PyBUF_SIMPLE) != 0)
  Branch (704:13): [True: 9, False: 627k]
705
            return -1;
706
        pos = stringlib_find(str, len,
707
                             varg.buf, varg.len, 0);
708
        PyBuffer_Release(&varg);
709
        return pos >= 0;
710
    }
711
    if (ival < 0 || 
ival >= 2567.09k
) {
  Branch (711:9): [True: 2, False: 7.09k]
  Branch (711:21): [True: 4, False: 7.09k]
712
        PyErr_SetString(PyExc_ValueError, "byte must be in range(0, 256)");
713
        return -1;
714
    }
715
716
    return memchr(str, (int) ival, len) != NULL;
717
}
718
719
720
/* Matches the end (direction >= 0) or start (direction < 0) of the buffer
721
 * against substr, using the start and end arguments. Returns
722
 * -1 on error, 0 if not found and 1 if found.
723
 */
724
static int
725
tailmatch(const char *str, Py_ssize_t len, PyObject *substr,
726
          Py_ssize_t start, Py_ssize_t end, int direction)
727
{
728
    Py_buffer sub_view = {NULL, NULL};
729
    const char *sub;
730
    Py_ssize_t slen;
731
732
    if (PyBytes_Check(substr)) {
733
        sub = PyBytes_AS_STRING(substr);
734
        slen = PyBytes_GET_SIZE(substr);
735
    }
736
    else {
737
        if (PyObject_GetBuffer(substr, &sub_view, PyBUF_SIMPLE) != 0)
  Branch (737:13): [True: 5, False: 24]
738
            return -1;
739
        sub = sub_view.buf;
740
        slen = sub_view.len;
741
    }
742
743
    ADJUST_INDICES(start, end, len);
744
745
    if (direction < 0) {
  Branch (745:9): [True: 97.6k, False: 182k]
746
        /* startswith */
747
        if (start > len - slen)
  Branch (747:13): [True: 761, False: 96.8k]
748
            goto notfound;
749
    } else {
750
        /* endswith */
751
        if (end - start < slen || 
start > len182k
)
  Branch (751:13): [True: 650, False: 182k]
  Branch (751:35): [True: 0, False: 182k]
752
            goto notfound;
753
754
        if (end - slen > start)
  Branch (754:13): [True: 180k, False: 1.34k]
755
            start = end - slen;
756
    }
757
    if (end - start < slen)
  Branch (757:9): [True: 0, False: 278k]
758
        goto notfound;
759
    if (memcmp(str + start, sub, slen) != 0)
  Branch (759:9): [True: 187k, False: 91.6k]
760
        goto notfound;
761
762
    PyBuffer_Release(&sub_view);
763
    return 1;
764
765
notfound:
766
    PyBuffer_Release(&sub_view);
767
    return 0;
768
}
769
770
static PyObject *
771
_Py_bytes_tailmatch(const char *str, Py_ssize_t len,
772
                    const char *function_name, PyObject *args,
773
                    int direction)
774
{
775
    Py_ssize_t start = 0;
776
    Py_ssize_t end = PY_SSIZE_T_MAX;
777
    PyObject *subobj;
778
    int result;
779
780
    if (!stringlib_parse_args_finds(function_name, args, &subobj, &start, &end))
  Branch (780:9): [True: 4, False: 280k]
781
        return NULL;
782
    if (PyTuple_Check(subobj)) {
783
        Py_ssize_t i;
784
        for (i = 0; i < PyTuple_GET_SIZE(subobj); 
i++427
) {
  Branch (784:21): [True: 441, False: 210]
785
            result = tailmatch(str, len, PyTuple_GET_ITEM(subobj, i),
786
                               start, end, direction);
787
            if (result == -1)
  Branch (787:17): [True: 0, False: 441]
788
                return NULL;
789
            else if (result) {
  Branch (789:22): [True: 14, False: 427]
790
                Py_RETURN_TRUE;
791
            }
792
        }
793
        
Py_RETURN_FALSE210
;
794
    }
795
    result = tailmatch(str, len, subobj, start, end, direction);
796
    if (result == -1) {
  Branch (796:9): [True: 5, False: 279k]
797
        if (PyErr_ExceptionMatches(PyExc_TypeError))
  Branch (797:13): [True: 5, False: 0]
798
            PyErr_Format(PyExc_TypeError,
799
                         "%s first arg must be bytes or a tuple of bytes, "
800
                         "not %s",
801
                         function_name, Py_TYPE(subobj)->tp_name);
802
        return NULL;
803
    }
804
    else
805
        return PyBool_FromLong(result);
806
}
807
808
PyDoc_STRVAR_shared(_Py_startswith__doc__,
809
"B.startswith(prefix[, start[, end]]) -> bool\n\
810
\n\
811
Return True if B starts with the specified prefix, False otherwise.\n\
812
With optional start, test B beginning at that position.\n\
813
With optional end, stop comparing B at that position.\n\
814
prefix can also be a tuple of bytes to try.");
815
816
PyObject *
817
_Py_bytes_startswith(const char *str, Py_ssize_t len, PyObject *args)
818
{
819
    return _Py_bytes_tailmatch(str, len, "startswith", args, -1);
820
}
821
822
PyDoc_STRVAR_shared(_Py_endswith__doc__,
823
"B.endswith(suffix[, start[, end]]) -> bool\n\
824
\n\
825
Return True if B ends with the specified suffix, False otherwise.\n\
826
With optional start, test B beginning at that position.\n\
827
With optional end, stop comparing B at that position.\n\
828
suffix can also be a tuple of bytes to try.");
829
830
PyObject *
831
_Py_bytes_endswith(const char *str, Py_ssize_t len, PyObject *args)
832
{
833
    return _Py_bytes_tailmatch(str, len, "endswith", args, +1);
834
}