Branch data Line data Source code
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 : 276 : _Py_bytes_isspace(const char *cptr, Py_ssize_t len)
14 : : {
15 : 276 : const unsigned char *p
16 : : = (const unsigned char *) cptr;
17 : : const unsigned char *e;
18 : :
19 : : /* Shortcut for single character strings */
20 [ + + + + ]: 276 : if (len == 1 && Py_ISSPACE(*p))
21 : 14 : Py_RETURN_TRUE;
22 : :
23 : : /* Special case for empty strings */
24 [ + + ]: 262 : if (len == 0)
25 : 2 : Py_RETURN_FALSE;
26 : :
27 : 260 : e = p + len;
28 [ + + ]: 20892 : for (; p < e; p++) {
29 [ + + ]: 20888 : if (!Py_ISSPACE(*p))
30 : 256 : Py_RETURN_FALSE;
31 : : }
32 : 4 : Py_RETURN_TRUE;
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 : 274 : _Py_bytes_isalpha(const char *cptr, Py_ssize_t len)
44 : : {
45 : 274 : const unsigned char *p
46 : : = (const unsigned char *) cptr;
47 : : const unsigned char *e;
48 : :
49 : : /* Shortcut for single character strings */
50 [ + + + + ]: 274 : if (len == 1 && Py_ISALPHA(*p))
51 : 56 : Py_RETURN_TRUE;
52 : :
53 : : /* Special case for empty strings */
54 [ + + ]: 218 : if (len == 0)
55 : 2 : Py_RETURN_FALSE;
56 : :
57 : 216 : e = p + len;
58 [ + + ]: 20850 : for (; p < e; p++) {
59 [ + + ]: 20846 : if (!Py_ISALPHA(*p))
60 : 212 : Py_RETURN_FALSE;
61 : : }
62 : 4 : Py_RETURN_TRUE;
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 : 276 : _Py_bytes_isalnum(const char *cptr, Py_ssize_t len)
74 : : {
75 : 276 : const unsigned char *p
76 : : = (const unsigned char *) cptr;
77 : : const unsigned char *e;
78 : :
79 : : /* Shortcut for single character strings */
80 [ + + + + ]: 276 : if (len == 1 && Py_ISALNUM(*p))
81 : 66 : Py_RETURN_TRUE;
82 : :
83 : : /* Special case for empty strings */
84 [ + + ]: 210 : if (len == 0)
85 : 2 : Py_RETURN_FALSE;
86 : :
87 : 208 : e = p + len;
88 [ + + ]: 20866 : for (; p < e; p++) {
89 [ + + ]: 20860 : if (!Py_ISALNUM(*p))
90 : 202 : Py_RETURN_FALSE;
91 : : }
92 : 6 : Py_RETURN_TRUE;
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 : 76 : _Py_bytes_isascii(const char *cptr, Py_ssize_t len)
115 : : {
116 : 76 : const char *p = cptr;
117 : 76 : const char *end = p + len;
118 : :
119 [ + + ]: 226 : while (p < end) {
120 : : /* Fast path, see in STRINGLIB(utf8_decode) in stringlib/codecs.h
121 : : for an explanation. */
122 [ + + ]: 190 : if (_Py_IS_ALIGNED(p, ALIGNOF_SIZE_T)) {
123 : : /* Help allocation */
124 : 74 : const char *_p = p;
125 [ + + ]: 94 : while (_p + SIZEOF_SIZE_T <= end) {
126 : 40 : size_t value = *(const size_t *) _p;
127 [ + + ]: 40 : if (value & ASCII_CHAR_MASK) {
128 : 20 : Py_RETURN_FALSE;
129 : : }
130 : 20 : _p += SIZEOF_SIZE_T;
131 : : }
132 : 54 : p = _p;
133 [ + + ]: 54 : if (_p == end)
134 : 4 : break;
135 : : }
136 [ + + ]: 166 : if ((unsigned char)*p & 0x80) {
137 : 16 : Py_RETURN_FALSE;
138 : : }
139 : 150 : p++;
140 : : }
141 : 40 : Py_RETURN_TRUE;
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 : 270 : _Py_bytes_isdigit(const char *cptr, Py_ssize_t len)
155 : : {
156 : 270 : const unsigned char *p
157 : : = (const unsigned char *) cptr;
158 : : const unsigned char *e;
159 : :
160 : : /* Shortcut for single character strings */
161 [ + + + + ]: 270 : if (len == 1 && Py_ISDIGIT(*p))
162 : 12 : Py_RETURN_TRUE;
163 : :
164 : : /* Special case for empty strings */
165 [ + + ]: 258 : if (len == 0)
166 : 2 : Py_RETURN_FALSE;
167 : :
168 : 256 : e = p + len;
169 [ + + ]: 20908 : for (; p < e; p++) {
170 [ + + ]: 20904 : if (!Py_ISDIGIT(*p))
171 : 252 : Py_RETURN_FALSE;
172 : : }
173 : 4 : Py_RETURN_TRUE;
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 : 274 : _Py_bytes_islower(const char *cptr, Py_ssize_t len)
185 : : {
186 : 274 : 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 [ + + ]: 274 : if (len == 1)
193 : 262 : return PyBool_FromLong(Py_ISLOWER(*p));
194 : :
195 : : /* Special case for empty strings */
196 [ + + ]: 12 : if (len == 0)
197 : 2 : Py_RETURN_FALSE;
198 : :
199 : 10 : e = p + len;
200 : 10 : cased = 0;
201 [ + + ]: 21518 : for (; p < e; p++) {
202 [ + + ]: 21512 : if (Py_ISUPPER(*p))
203 : 4 : Py_RETURN_FALSE;
204 [ + + + + ]: 21508 : else if (!cased && Py_ISLOWER(*p))
205 : 10 : cased = 1;
206 : : }
207 : 6 : 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 : 274 : _Py_bytes_isupper(const char *cptr, Py_ssize_t len)
219 : : {
220 : 274 : 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 [ + + ]: 274 : if (len == 1)
227 : 262 : return PyBool_FromLong(Py_ISUPPER(*p));
228 : :
229 : : /* Special case for empty strings */
230 [ + + ]: 12 : if (len == 0)
231 : 2 : Py_RETURN_FALSE;
232 : :
233 : 10 : e = p + len;
234 : 10 : cased = 0;
235 [ + + ]: 21866 : for (; p < e; p++) {
236 [ + + ]: 21860 : if (Py_ISLOWER(*p))
237 : 4 : Py_RETURN_FALSE;
238 [ + + + + ]: 21856 : else if (!cased && Py_ISUPPER(*p))
239 : 10 : cased = 1;
240 : : }
241 : 6 : 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 : 28 : _Py_bytes_istitle(const char *cptr, Py_ssize_t len)
255 : : {
256 : 28 : 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 [ + + ]: 28 : if (len == 1)
263 : 6 : return PyBool_FromLong(Py_ISUPPER(*p));
264 : :
265 : : /* Special case for empty strings */
266 [ + + ]: 22 : if (len == 0)
267 : 2 : Py_RETURN_FALSE;
268 : :
269 : 20 : e = p + len;
270 : 20 : cased = 0;
271 : 20 : previous_is_cased = 0;
272 [ + + ]: 31082 : for (; p < e; p++) {
273 : 31072 : const unsigned char ch = *p;
274 : :
275 [ + + ]: 31072 : if (Py_ISUPPER(ch)) {
276 [ + + ]: 40 : if (previous_is_cased)
277 : 4 : Py_RETURN_FALSE;
278 : 36 : previous_is_cased = 1;
279 : 36 : cased = 1;
280 : : }
281 [ + + ]: 31032 : else if (Py_ISLOWER(ch)) {
282 [ + + ]: 30974 : if (!previous_is_cased)
283 : 6 : Py_RETURN_FALSE;
284 : 30968 : previous_is_cased = 1;
285 : 30968 : cased = 1;
286 : : }
287 : : else
288 : 58 : previous_is_cased = 0;
289 : : }
290 : 10 : 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 : 741605 : _Py_bytes_lower(char *result, const char *cptr, Py_ssize_t len)
301 : : {
302 : : Py_ssize_t i;
303 : :
304 [ + + ]: 8468346 : for (i = 0; i < len; i++) {
305 : 7726741 : result[i] = Py_TOLOWER((unsigned char) cptr[i]);
306 : : }
307 : 741605 : }
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 : 63198 : _Py_bytes_upper(char *result, const char *cptr, Py_ssize_t len)
317 : : {
318 : : Py_ssize_t i;
319 : :
320 [ + + ]: 239542 : for (i = 0; i < len; i++) {
321 : 176344 : result[i] = Py_TOUPPER((unsigned char) cptr[i]);
322 : : }
323 : 63198 : }
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 : 16 : _Py_bytes_title(char *result, const char *s, Py_ssize_t len)
334 : : {
335 : : Py_ssize_t i;
336 : 16 : int previous_is_cased = 0;
337 : :
338 [ + + ]: 10574 : for (i = 0; i < len; i++) {
339 : 10558 : int c = Py_CHARMASK(*s++);
340 [ + + ]: 10558 : if (Py_ISLOWER(c)) {
341 [ + + ]: 7302 : if (!previous_is_cased)
342 : 22 : c = Py_TOUPPER(c);
343 : 7302 : previous_is_cased = 1;
344 [ + + ]: 3256 : } else if (Py_ISUPPER(c)) {
345 [ + + ]: 3232 : if (previous_is_cased)
346 : 3222 : c = Py_TOLOWER(c);
347 : 3232 : previous_is_cased = 1;
348 : : } else
349 : 24 : previous_is_cased = 0;
350 : 10558 : *result++ = c;
351 : : }
352 : 16 : }
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 : 14 : _Py_bytes_capitalize(char *result, const char *s, Py_ssize_t len)
363 : : {
364 [ + - ]: 14 : if (len > 0) {
365 : 14 : *result = Py_TOUPPER(*s);
366 : 14 : _Py_bytes_lower(result + 1, s + 1, len - 1);
367 : : }
368 : 14 : }
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 : 8 : _Py_bytes_swapcase(char *result, const char *s, Py_ssize_t len)
379 : : {
380 : : Py_ssize_t i;
381 : :
382 [ + + ]: 10412 : for (i = 0; i < len; i++) {
383 : 10404 : int c = Py_CHARMASK(*s++);
384 [ + + ]: 10404 : if (Py_ISLOWER(c)) {
385 : 2410 : *result = Py_TOUPPER(c);
386 : : }
387 [ + + ]: 7994 : else if (Py_ISUPPER(c)) {
388 : 3204 : *result = Py_TOLOWER(c);
389 : : }
390 : : else
391 : 4790 : *result = c;
392 : 10404 : result++;
393 : : }
394 : 8 : }
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 : 1061 : _Py_bytes_maketrans(Py_buffer *frm, Py_buffer *to)
407 : : {
408 : 1061 : PyObject *res = NULL;
409 : : Py_ssize_t i;
410 : : char *p;
411 : :
412 [ + + ]: 1061 : if (frm->len != to->len) {
413 : 2 : PyErr_Format(PyExc_ValueError,
414 : : "maketrans arguments must have same length");
415 : 2 : return NULL;
416 : : }
417 : 1059 : res = PyBytes_FromStringAndSize(NULL, 256);
418 [ - + ]: 1059 : if (!res)
419 : 0 : return NULL;
420 : 1059 : p = PyBytes_AS_STRING(res);
421 [ + + ]: 272163 : for (i = 0; i < 256; i++)
422 : 271104 : p[i] = (char) i;
423 [ + + ]: 3255 : for (i = 0; i < frm->len; i++) {
424 : 2196 : p[((unsigned char *)frm->buf)[i]] = ((char *)to->buf)[i];
425 : : }
426 : :
427 : 1059 : 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 : 1376805 : 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 [ + + ]: 1376805 : if(!stringlib_parse_args_finds(function_name, args, &tmp_subobj,
462 : : start, end))
463 : 20 : return 0;
464 : :
465 [ + + ]: 1376785 : if (PyObject_CheckBuffer(tmp_subobj)) {
466 : 910580 : *subobj = tmp_subobj;
467 : 910580 : return 1;
468 : : }
469 : :
470 [ - + ]: 466205 : if (!_PyIndex_Check(tmp_subobj)) {
471 : 0 : PyErr_Format(PyExc_TypeError,
472 : : "argument should be integer or bytes-like object, "
473 : : "not '%.200s'",
474 : 0 : Py_TYPE(tmp_subobj)->tp_name);
475 : 0 : return 0;
476 : : }
477 : :
478 : 466205 : ival = PyNumber_AsSsize_t(tmp_subobj, NULL);
479 [ + + - + ]: 466205 : if (ival == -1 && PyErr_Occurred()) {
480 : 0 : return 0;
481 : : }
482 [ + + + + ]: 466205 : if (ival < 0 || ival > 255) {
483 : 36 : PyErr_SetString(PyExc_ValueError, "byte must be in range(0, 256)");
484 : 36 : return 0;
485 : : }
486 : :
487 : 466169 : *subobj = NULL;
488 : 466169 : *byte = (char)ival;
489 : 466169 : 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 = len; \
496 : : else if (end < 0) { \
497 : : end += len; \
498 : : if (end < 0) \
499 : : end = 0; \
500 : : } \
501 : : if (start < 0) { \
502 : : start += len; \
503 : : if (start < 0) \
504 : : start = 0; \
505 : : }
506 : :
507 : : Py_LOCAL_INLINE(Py_ssize_t)
508 : 1231884 : 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 : 1231884 : Py_ssize_t start = 0, end = PY_SSIZE_T_MAX;
517 : : Py_ssize_t res;
518 : :
519 [ + + ]: 1231884 : if (!parse_args_finds_byte(function_name, args,
520 : : &subobj, &byte, &start, &end))
521 : 46 : return -2;
522 : :
523 [ + + ]: 1231838 : if (subobj) {
524 [ - + ]: 765683 : if (PyObject_GetBuffer(subobj, &subbuf, PyBUF_SIMPLE) != 0)
525 : 0 : return -2;
526 : :
527 : 765683 : sub = subbuf.buf;
528 : 765683 : sub_len = subbuf.len;
529 : : }
530 : : else {
531 : 466155 : sub = &byte;
532 : 466155 : sub_len = 1;
533 : : }
534 : :
535 [ + + + + : 1231838 : ADJUST_INDICES(start, end, len);
- + + + -
+ ]
536 [ + + ]: 1231838 : if (end - start < sub_len)
537 : 132416 : res = -1;
538 [ + + ]: 1099422 : else if (sub_len == 1) {
539 [ + + ]: 701648 : if (dir > 0)
540 : 693556 : res = stringlib_find_char(
541 : : str + start, end - start,
542 : 693556 : *sub);
543 : : else
544 : 8092 : res = stringlib_rfind_char(
545 : : str + start, end - start,
546 : 8092 : *sub);
547 [ + + ]: 701648 : if (res >= 0)
548 : 566588 : res += start;
549 : : }
550 : : else {
551 [ + + ]: 397774 : if (dir > 0)
552 : 200471 : res = stringlib_find_slice(
553 : : str, len,
554 : : sub, sub_len, start, end);
555 : : else
556 : 197303 : res = stringlib_rfind_slice(
557 : : str, len,
558 : : sub, sub_len, start, end);
559 : : }
560 : :
561 [ + + ]: 1231838 : if (subobj)
562 : 765683 : PyBuffer_Release(&subbuf);
563 : :
564 : 1231838 : 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 : 960240 : _Py_bytes_find(const char *str, Py_ssize_t len, PyObject *args)
578 : : {
579 : 960240 : Py_ssize_t result = find_internal(str, len, "find", args, +1);
580 [ + + ]: 960240 : if (result == -2)
581 : 16 : return NULL;
582 : 960224 : 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 : 137 : _Py_bytes_index(const char *str, Py_ssize_t len, PyObject *args)
596 : : {
597 : 137 : Py_ssize_t result = find_internal(str, len, "index", args, +1);
598 [ + + ]: 137 : if (result == -2)
599 : 10 : return NULL;
600 [ + + ]: 127 : if (result == -1) {
601 : 33 : PyErr_SetString(PyExc_ValueError,
602 : : "subsection not found");
603 : 33 : return NULL;
604 : : }
605 : 94 : 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 : 271413 : _Py_bytes_rfind(const char *str, Py_ssize_t len, PyObject *args)
619 : : {
620 : 271413 : Py_ssize_t result = find_internal(str, len, "rfind", args, -1);
621 [ + + ]: 271413 : if (result == -2)
622 : 10 : return NULL;
623 : 271403 : 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 : 94 : _Py_bytes_rindex(const char *str, Py_ssize_t len, PyObject *args)
637 : : {
638 : 94 : Py_ssize_t result = find_internal(str, len, "rindex", args, -1);
639 [ + + ]: 94 : if (result == -2)
640 : 10 : return NULL;
641 [ + + ]: 84 : if (result == -1) {
642 : 24 : PyErr_SetString(PyExc_ValueError,
643 : : "subsection not found");
644 : 24 : return NULL;
645 : : }
646 : 60 : 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 : 144921 : _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 : 144921 : Py_ssize_t start = 0, end = PY_SSIZE_T_MAX;
664 : :
665 : : Py_buffer vsub;
666 : : PyObject *count_obj;
667 : :
668 [ + + ]: 144921 : if (!parse_args_finds_byte("count", args,
669 : : &sub_obj, &byte, &start, &end))
670 : 10 : return NULL;
671 : :
672 [ + + ]: 144911 : if (sub_obj) {
673 [ - + ]: 144897 : if (PyObject_GetBuffer(sub_obj, &vsub, PyBUF_SIMPLE) != 0)
674 : 0 : return NULL;
675 : :
676 : 144897 : sub = vsub.buf;
677 : 144897 : sub_len = vsub.len;
678 : : }
679 : : else {
680 : 14 : sub = &byte;
681 : 14 : sub_len = 1;
682 : : }
683 : :
684 [ + + + + : 144911 : ADJUST_INDICES(start, end, len);
+ + + + +
+ ]
685 : :
686 : 144911 : count_obj = PyLong_FromSsize_t(
687 : : stringlib_count(str + start, end - start, sub, sub_len, PY_SSIZE_T_MAX)
688 : : );
689 : :
690 [ + + ]: 144911 : if (sub_obj)
691 : 144897 : PyBuffer_Release(&vsub);
692 : :
693 : 144911 : return count_obj;
694 : : }
695 : :
696 : : int
697 : 744118 : _Py_bytes_contains(const char *str, Py_ssize_t len, PyObject *arg)
698 : : {
699 : 744118 : Py_ssize_t ival = PyNumber_AsSsize_t(arg, NULL);
700 [ + + + + ]: 744118 : if (ival == -1 && PyErr_Occurred()) {
701 : : Py_buffer varg;
702 : : Py_ssize_t pos;
703 : 737010 : PyErr_Clear();
704 [ + + ]: 737010 : if (PyObject_GetBuffer(arg, &varg, PyBUF_SIMPLE) != 0)
705 : 9 : return -1;
706 : 737001 : pos = stringlib_find(str, len,
707 : 737001 : varg.buf, varg.len, 0);
708 : 737001 : PyBuffer_Release(&varg);
709 : 737001 : return pos >= 0;
710 : : }
711 [ + + + + ]: 7108 : if (ival < 0 || ival >= 256) {
712 : 6 : PyErr_SetString(PyExc_ValueError, "byte must be in range(0, 256)");
713 : 6 : return -1;
714 : : }
715 : :
716 : 7102 : 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 : 154592 : tailmatch(const char *str, Py_ssize_t len, PyObject *substr,
726 : : Py_ssize_t start, Py_ssize_t end, int direction)
727 : : {
728 : 154592 : Py_buffer sub_view = {NULL, NULL};
729 : : const char *sub;
730 : : Py_ssize_t slen;
731 : :
732 [ + + ]: 154592 : if (PyBytes_Check(substr)) {
733 : 154563 : sub = PyBytes_AS_STRING(substr);
734 : 154563 : slen = PyBytes_GET_SIZE(substr);
735 : : }
736 : : else {
737 [ + + ]: 29 : if (PyObject_GetBuffer(substr, &sub_view, PyBUF_SIMPLE) != 0)
738 : 5 : return -1;
739 : 24 : sub = sub_view.buf;
740 : 24 : slen = sub_view.len;
741 : : }
742 : :
743 [ + + + - : 154587 : ADJUST_INDICES(start, end, len);
- + + + -
+ ]
744 : :
745 [ + + ]: 154587 : if (direction < 0) {
746 : : /* startswith */
747 [ + + ]: 36315 : if (start > len - slen)
748 : 899 : goto notfound;
749 : : } else {
750 : : /* endswith */
751 [ + + - + ]: 118272 : if (end - start < slen || start > len)
752 : 651 : goto notfound;
753 : :
754 [ + + ]: 117621 : if (end - slen > start)
755 : 116314 : start = end - slen;
756 : : }
757 [ - + ]: 153037 : if (end - start < slen)
758 : 0 : goto notfound;
759 [ + + ]: 153037 : if (memcmp(str + start, sub, slen) != 0)
760 : 67676 : goto notfound;
761 : :
762 : 85361 : PyBuffer_Release(&sub_view);
763 : 85361 : return 1;
764 : :
765 : 69226 : notfound:
766 : 69226 : PyBuffer_Release(&sub_view);
767 : 69226 : return 0;
768 : : }
769 : :
770 : : static PyObject *
771 : 154379 : _Py_bytes_tailmatch(const char *str, Py_ssize_t len,
772 : : const char *function_name, PyObject *args,
773 : : int direction)
774 : : {
775 : 154379 : Py_ssize_t start = 0;
776 : 154379 : Py_ssize_t end = PY_SSIZE_T_MAX;
777 : : PyObject *subobj;
778 : : int result;
779 : :
780 [ + + ]: 154379 : if (!stringlib_parse_args_finds(function_name, args, &subobj, &start, &end))
781 : 4 : return NULL;
782 [ + + ]: 154375 : if (PyTuple_Check(subobj)) {
783 : : Py_ssize_t i;
784 [ + + ]: 651 : for (i = 0; i < PyTuple_GET_SIZE(subobj); i++) {
785 : 441 : result = tailmatch(str, len, PyTuple_GET_ITEM(subobj, i),
786 : : start, end, direction);
787 [ - + ]: 441 : if (result == -1)
788 : 0 : return NULL;
789 [ + + ]: 441 : else if (result) {
790 : 14 : Py_RETURN_TRUE;
791 : : }
792 : : }
793 : 210 : Py_RETURN_FALSE;
794 : : }
795 : 154151 : result = tailmatch(str, len, subobj, start, end, direction);
796 [ + + ]: 154151 : if (result == -1) {
797 [ + - ]: 5 : if (PyErr_ExceptionMatches(PyExc_TypeError))
798 : 5 : PyErr_Format(PyExc_TypeError,
799 : : "%s first arg must be bytes or a tuple of bytes, "
800 : : "not %s",
801 : 5 : function_name, Py_TYPE(subobj)->tp_name);
802 : 5 : return NULL;
803 : : }
804 : : else
805 : 154146 : 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 : 36103 : _Py_bytes_startswith(const char *str, Py_ssize_t len, PyObject *args)
818 : : {
819 : 36103 : 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 : 118276 : _Py_bytes_endswith(const char *str, Py_ssize_t len, PyObject *args)
832 : : {
833 : 118276 : return _Py_bytes_tailmatch(str, len, "endswith", args, +1);
834 : : }
|