LCOV - code coverage report
Current view: top level - Objects - bytes_methods.c (source / functions) Hit Total Coverage
Test: CPython 3.12 LCOV report [commit acb105a7c1f] Lines: 309 318 97.2 %
Date: 2022-07-20 13:12:14 Functions: 26 26 100.0 %
Branches: 229 244 93.9 %

           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                 :            : }

Generated by: LCOV version 1.14