LCOV - code coverage report
Current view: | top level - Objects - bytes_methods.c (source / functions) |  |  | Hit | Total | Coverage
Test: | CPython 3.12 LCOV report [commit 5e6661bce9] |  | Lines: | 85 | 318 | 26.7 %
Date: | 2023-03-20 08:15:36 |  | Functions: | 10 | 26 | 38.5 %
|  |  | Branches: | 44 | 244 | 18.0 %

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

Generated by: LCOV version 1.14