Coverage Report

Created: 2025-08-26 06:26

/src/cpython/Objects/stringlib/transmogrify.h
Line
Count
Source (jump to first uncovered line)
1
#if STRINGLIB_IS_UNICODE
2
# error "transmogrify.h only compatible with byte-wise strings"
3
#endif
4
5
/* the more complicated methods.  parts of these should be pulled out into the
6
   shared code in bytes_methods.c to cut down on duplicate code bloat.  */
7
8
/*[clinic input]
9
class B "PyObject *" "&PyType_Type"
10
[clinic start generated code]*/
11
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=2935558188d97c76]*/
12
13
#include "clinic/transmogrify.h.h"
14
15
static inline PyObject *
16
return_self(PyObject *self)
17
33.4k
{
18
#if !STRINGLIB_MUTABLE
19
33.4k
    if (STRINGLIB_CHECK_EXACT(self)) {
20
33.4k
        return Py_NewRef(self);
21
33.4k
    }
22
0
#endif
23
0
    return STRINGLIB_NEW(STRINGLIB_STR(self), STRINGLIB_LEN(self));
24
33.4k
}
bytesobject.c:return_self
Line
Count
Source
17
33.4k
{
18
33.4k
#if !STRINGLIB_MUTABLE
19
33.4k
    if (STRINGLIB_CHECK_EXACT(self)) {
20
33.4k
        return Py_NewRef(self);
21
33.4k
    }
22
0
#endif
23
0
    return STRINGLIB_NEW(STRINGLIB_STR(self), STRINGLIB_LEN(self));
24
33.4k
}
Unexecuted instantiation: bytearrayobject.c:return_self
25
26
/*[clinic input]
27
B.expandtabs as stringlib_expandtabs
28
29
    tabsize: int = 8
30
31
Return a copy where all tab characters are expanded using spaces.
32
33
If tabsize is not given, a tab size of 8 characters is assumed.
34
[clinic start generated code]*/
35
36
static PyObject *
37
stringlib_expandtabs_impl(PyObject *self, int tabsize)
38
/*[clinic end generated code: output=069cb7fae72e4c2b input=3c6d3b12aa3ccbea]*/
39
0
{
40
0
    const char *e, *p;
41
0
    char *q;
42
0
    Py_ssize_t i, j;
43
0
    PyObject *u;
44
45
    /* First pass: determine size of output string */
46
0
    i = j = 0;
47
0
    e = STRINGLIB_STR(self) + STRINGLIB_LEN(self);
48
0
    for (p = STRINGLIB_STR(self); p < e; p++) {
49
0
        if (*p == '\t') {
50
0
            if (tabsize > 0) {
51
0
                Py_ssize_t incr = tabsize - (j % tabsize);
52
0
                if (j > PY_SSIZE_T_MAX - incr)
53
0
                    goto overflow;
54
0
                j += incr;
55
0
            }
56
0
        }
57
0
        else {
58
0
            if (j > PY_SSIZE_T_MAX - 1)
59
0
                goto overflow;
60
0
            j++;
61
0
            if (*p == '\n' || *p == '\r') {
62
0
                if (i > PY_SSIZE_T_MAX - j)
63
0
                    goto overflow;
64
0
                i += j;
65
0
                j = 0;
66
0
            }
67
0
        }
68
0
    }
69
70
0
    if (i > PY_SSIZE_T_MAX - j)
71
0
        goto overflow;
72
73
    /* Second pass: create output string and fill it */
74
0
    u = STRINGLIB_NEW(NULL, i + j);
75
0
    if (!u)
76
0
        return NULL;
77
78
0
    j = 0;
79
0
    q = STRINGLIB_STR(u);
80
81
0
    for (p = STRINGLIB_STR(self); p < e; p++) {
82
0
        if (*p == '\t') {
83
0
            if (tabsize > 0) {
84
0
                i = tabsize - (j % tabsize);
85
0
                j += i;
86
0
                while (i--)
87
0
                    *q++ = ' ';
88
0
            }
89
0
        }
90
0
        else {
91
0
            j++;
92
0
            *q++ = *p;
93
0
            if (*p == '\n' || *p == '\r')
94
0
                j = 0;
95
0
        }
96
0
    }
97
98
0
    return u;
99
0
  overflow:
100
0
    PyErr_SetString(PyExc_OverflowError, "result too long");
101
0
    return NULL;
102
0
}
Unexecuted instantiation: bytesobject.c:stringlib_expandtabs_impl
Unexecuted instantiation: bytearrayobject.c:stringlib_expandtabs_impl
103
104
static inline PyObject *
105
pad(PyObject *self, Py_ssize_t left, Py_ssize_t right, char fill)
106
0
{
107
0
    PyObject *u;
108
109
0
    if (left < 0)
110
0
        left = 0;
111
0
    if (right < 0)
112
0
        right = 0;
113
114
0
    if (left == 0 && right == 0) {
115
0
        return return_self(self);
116
0
    }
117
118
0
    u = STRINGLIB_NEW(NULL, left + STRINGLIB_LEN(self) + right);
119
0
    if (u) {
120
0
        if (left)
121
0
            memset(STRINGLIB_STR(u), fill, left);
122
0
        memcpy(STRINGLIB_STR(u) + left,
123
0
               STRINGLIB_STR(self),
124
0
               STRINGLIB_LEN(self));
125
0
        if (right)
126
0
            memset(STRINGLIB_STR(u) + left + STRINGLIB_LEN(self),
127
0
                   fill, right);
128
0
    }
129
130
0
    return u;
131
0
}
Unexecuted instantiation: bytesobject.c:pad
Unexecuted instantiation: bytearrayobject.c:pad
132
133
/*[clinic input]
134
B.ljust as stringlib_ljust
135
136
    width: Py_ssize_t
137
    fillchar: char = b' '
138
    /
139
140
Return a left-justified string of length width.
141
142
Padding is done using the specified fill character.
143
[clinic start generated code]*/
144
145
static PyObject *
146
stringlib_ljust_impl(PyObject *self, Py_ssize_t width, char fillchar)
147
/*[clinic end generated code: output=c79ca173c5ff8337 input=eff2d014bc7d80df]*/
148
0
{
149
0
    if (STRINGLIB_LEN(self) >= width) {
150
0
        return return_self(self);
151
0
    }
152
153
0
    return pad(self, 0, width - STRINGLIB_LEN(self), fillchar);
154
0
}
Unexecuted instantiation: bytesobject.c:stringlib_ljust_impl
Unexecuted instantiation: bytearrayobject.c:stringlib_ljust_impl
155
156
157
/*[clinic input]
158
B.rjust as stringlib_rjust
159
160
    width: Py_ssize_t
161
    fillchar: char = b' '
162
    /
163
164
Return a right-justified string of length width.
165
166
Padding is done using the specified fill character.
167
[clinic start generated code]*/
168
169
static PyObject *
170
stringlib_rjust_impl(PyObject *self, Py_ssize_t width, char fillchar)
171
/*[clinic end generated code: output=7df5d728a5439570 input=218b0bd31308955d]*/
172
0
{
173
0
    if (STRINGLIB_LEN(self) >= width) {
174
0
        return return_self(self);
175
0
    }
176
177
0
    return pad(self, width - STRINGLIB_LEN(self), 0, fillchar);
178
0
}
Unexecuted instantiation: bytesobject.c:stringlib_rjust_impl
Unexecuted instantiation: bytearrayobject.c:stringlib_rjust_impl
179
180
181
/*[clinic input]
182
B.center as stringlib_center
183
184
    width: Py_ssize_t
185
    fillchar: char = b' '
186
    /
187
188
Return a centered string of length width.
189
190
Padding is done using the specified fill character.
191
[clinic start generated code]*/
192
193
static PyObject *
194
stringlib_center_impl(PyObject *self, Py_ssize_t width, char fillchar)
195
/*[clinic end generated code: output=d8da2e055288b4c2 input=3776fd278765d89b]*/
196
0
{
197
0
    Py_ssize_t marg, left;
198
199
0
    if (STRINGLIB_LEN(self) >= width) {
200
0
        return return_self(self);
201
0
    }
202
203
0
    marg = width - STRINGLIB_LEN(self);
204
0
    left = marg / 2 + (marg & width & 1);
205
206
0
    return pad(self, left, marg - left, fillchar);
207
0
}
Unexecuted instantiation: bytesobject.c:stringlib_center_impl
Unexecuted instantiation: bytearrayobject.c:stringlib_center_impl
208
209
/*[clinic input]
210
@permit_long_summary
211
B.zfill as stringlib_zfill
212
213
    width: Py_ssize_t
214
    /
215
216
Pad a numeric string with zeros on the left, to fill a field of the given width.
217
218
The original string is never truncated.
219
[clinic start generated code]*/
220
221
static PyObject *
222
stringlib_zfill_impl(PyObject *self, Py_ssize_t width)
223
/*[clinic end generated code: output=0b3c684a7f1b2319 input=dfb9cbb16f521756]*/
224
0
{
225
0
    Py_ssize_t fill;
226
0
    PyObject *s;
227
0
    char *p;
228
229
0
    if (STRINGLIB_LEN(self) >= width) {
230
0
        return return_self(self);
231
0
    }
232
233
0
    fill = width - STRINGLIB_LEN(self);
234
235
0
    s = pad(self, fill, 0, '0');
236
237
0
    if (s == NULL)
238
0
        return NULL;
239
240
0
    p = STRINGLIB_STR(s);
241
0
    if (p[fill] == '+' || p[fill] == '-') {
242
        /* move sign to beginning of string */
243
0
        p[0] = p[fill];
244
0
        p[fill] = '0';
245
0
    }
246
247
0
    return s;
248
0
}
Unexecuted instantiation: bytesobject.c:stringlib_zfill_impl
Unexecuted instantiation: bytearrayobject.c:stringlib_zfill_impl
249
250
251
/* find and count characters and substrings */
252
253
#define findchar(target, target_len, c)                         \
254
36.0k
  ((char *)memchr((const void *)(target), c, target_len))
255
256
257
static Py_ssize_t
258
countchar(const char *target, Py_ssize_t target_len, char c,
259
          Py_ssize_t maxcount)
260
0
{
261
0
    Py_ssize_t count = 0;
262
0
    const char *start = target;
263
0
    const char *end = target + target_len;
264
265
0
    while ((start = findchar(start, end - start, c)) != NULL) {
266
0
        count++;
267
0
        if (count >= maxcount)
268
0
            break;
269
0
        start += 1;
270
0
    }
271
0
    return count;
272
0
}
Unexecuted instantiation: bytesobject.c:countchar
Unexecuted instantiation: bytearrayobject.c:countchar
273
274
275
/* Algorithms for different cases of string replacement */
276
277
/* len(self)>=1, from="", len(to)>=1, maxcount>=1 */
278
static PyObject *
279
stringlib_replace_interleave(PyObject *self,
280
                             const char *to_s, Py_ssize_t to_len,
281
                             Py_ssize_t maxcount)
282
0
{
283
0
    const char *self_s;
284
0
    char *result_s;
285
0
    Py_ssize_t self_len, result_len;
286
0
    Py_ssize_t count, i;
287
0
    PyObject *result;
288
289
0
    self_len = STRINGLIB_LEN(self);
290
291
    /* 1 at the end plus 1 after every character;
292
       count = min(maxcount, self_len + 1) */
293
0
    if (maxcount <= self_len) {
294
0
        count = maxcount;
295
0
    }
296
0
    else {
297
        /* Can't overflow: self_len + 1 <= maxcount <= PY_SSIZE_T_MAX. */
298
0
        count = self_len + 1;
299
0
    }
300
301
    /* Check for overflow */
302
    /*   result_len = count * to_len + self_len; */
303
0
    assert(count > 0);
304
0
    if (to_len > (PY_SSIZE_T_MAX - self_len) / count) {
305
0
        PyErr_SetString(PyExc_OverflowError,
306
0
                        "replace bytes is too long");
307
0
        return NULL;
308
0
    }
309
0
    result_len = count * to_len + self_len;
310
0
    result = STRINGLIB_NEW(NULL, result_len);
311
0
    if (result == NULL) {
312
0
        return NULL;
313
0
    }
314
315
0
    self_s = STRINGLIB_STR(self);
316
0
    result_s = STRINGLIB_STR(result);
317
318
0
    if (to_len > 1) {
319
        /* Lay the first one down (guaranteed this will occur) */
320
0
        memcpy(result_s, to_s, to_len);
321
0
        result_s += to_len;
322
0
        count -= 1;
323
324
0
        for (i = 0; i < count; i++) {
325
0
            *result_s++ = *self_s++;
326
0
            memcpy(result_s, to_s, to_len);
327
0
            result_s += to_len;
328
0
        }
329
0
    }
330
0
    else {
331
0
        result_s[0] = to_s[0];
332
0
        result_s += to_len;
333
0
        count -= 1;
334
0
        for (i = 0; i < count; i++) {
335
0
            *result_s++ = *self_s++;
336
0
            result_s[0] = to_s[0];
337
0
            result_s += to_len;
338
0
        }
339
0
    }
340
341
    /* Copy the rest of the original string */
342
0
    memcpy(result_s, self_s, self_len - i);
343
344
0
    return result;
345
0
}
Unexecuted instantiation: bytesobject.c:stringlib_replace_interleave
Unexecuted instantiation: bytearrayobject.c:stringlib_replace_interleave
346
347
/* Special case for deleting a single character */
348
/* len(self)>=1, len(from)==1, to="", maxcount>=1 */
349
static PyObject *
350
stringlib_replace_delete_single_character(PyObject *self,
351
                                          char from_c, Py_ssize_t maxcount)
352
0
{
353
0
    const char *self_s, *start, *next, *end;
354
0
    char *result_s;
355
0
    Py_ssize_t self_len, result_len;
356
0
    Py_ssize_t count;
357
0
    PyObject *result;
358
359
0
    self_len = STRINGLIB_LEN(self);
360
0
    self_s = STRINGLIB_STR(self);
361
362
0
    count = countchar(self_s, self_len, from_c, maxcount);
363
0
    if (count == 0) {
364
0
        return return_self(self);
365
0
    }
366
367
0
    result_len = self_len - count;  /* from_len == 1 */
368
0
    assert(result_len>=0);
369
370
0
    result = STRINGLIB_NEW(NULL, result_len);
371
0
    if (result == NULL) {
372
0
        return NULL;
373
0
    }
374
0
    result_s = STRINGLIB_STR(result);
375
376
0
    start = self_s;
377
0
    end = self_s + self_len;
378
0
    while (count-- > 0) {
379
0
        next = findchar(start, end - start, from_c);
380
0
        if (next == NULL)
381
0
            break;
382
0
        memcpy(result_s, start, next - start);
383
0
        result_s += (next - start);
384
0
        start = next + 1;
385
0
    }
386
0
    memcpy(result_s, start, end - start);
387
388
0
    return result;
389
0
}
Unexecuted instantiation: bytesobject.c:stringlib_replace_delete_single_character
Unexecuted instantiation: bytearrayobject.c:stringlib_replace_delete_single_character
390
391
/* len(self)>=1, len(from)>=2, to="", maxcount>=1 */
392
393
static PyObject *
394
stringlib_replace_delete_substring(PyObject *self,
395
                                   const char *from_s, Py_ssize_t from_len,
396
                                   Py_ssize_t maxcount)
397
0
{
398
0
    const char *self_s, *start, *next, *end;
399
0
    char *result_s;
400
0
    Py_ssize_t self_len, result_len;
401
0
    Py_ssize_t count, offset;
402
0
    PyObject *result;
403
404
0
    self_len = STRINGLIB_LEN(self);
405
0
    self_s = STRINGLIB_STR(self);
406
407
0
    count = stringlib_count(self_s, self_len,
408
0
                            from_s, from_len,
409
0
                            maxcount);
410
411
0
    if (count == 0) {
412
        /* no matches */
413
0
        return return_self(self);
414
0
    }
415
416
0
    result_len = self_len - (count * from_len);
417
0
    assert (result_len>=0);
418
419
0
    result = STRINGLIB_NEW(NULL, result_len);
420
0
    if (result == NULL) {
421
0
        return NULL;
422
0
    }
423
0
    result_s = STRINGLIB_STR(result);
424
425
0
    start = self_s;
426
0
    end = self_s + self_len;
427
0
    while (count-- > 0) {
428
0
        offset = stringlib_find(start, end - start,
429
0
                                from_s, from_len,
430
0
                                0);
431
0
        if (offset == -1)
432
0
            break;
433
0
        next = start + offset;
434
435
0
        memcpy(result_s, start, next - start);
436
437
0
        result_s += (next - start);
438
0
        start = next + from_len;
439
0
    }
440
0
    memcpy(result_s, start, end - start);
441
0
    return result;
442
0
}
Unexecuted instantiation: bytesobject.c:stringlib_replace_delete_substring
Unexecuted instantiation: bytearrayobject.c:stringlib_replace_delete_substring
443
444
/* len(self)>=1, len(from)==len(to)==1, maxcount>=1 */
445
static PyObject *
446
stringlib_replace_single_character_in_place(PyObject *self,
447
                                            char from_c, char to_c,
448
                                            Py_ssize_t maxcount)
449
34.3k
{
450
34.3k
    const char *self_s, *end;
451
34.3k
    char *result_s, *start, *next;
452
34.3k
    Py_ssize_t self_len;
453
34.3k
    PyObject *result;
454
455
    /* The result string will be the same size */
456
34.3k
    self_s = STRINGLIB_STR(self);
457
34.3k
    self_len = STRINGLIB_LEN(self);
458
459
34.3k
    next = findchar(self_s, self_len, from_c);
460
461
34.3k
    if (next == NULL) {
462
        /* No matches; return the original bytes */
463
33.2k
        return return_self(self);
464
33.2k
    }
465
466
    /* Need to make a new bytes */
467
1.06k
    result = STRINGLIB_NEW(NULL, self_len);
468
1.06k
    if (result == NULL) {
469
0
        return NULL;
470
0
    }
471
1.06k
    result_s = STRINGLIB_STR(result);
472
1.06k
    memcpy(result_s, self_s, self_len);
473
474
    /* change everything in-place, starting with this one */
475
1.06k
    start =  result_s + (next - self_s);
476
1.06k
    *start = to_c;
477
1.06k
    start++;
478
1.06k
    end = result_s + self_len;
479
480
1.77k
    while (--maxcount > 0) {
481
1.77k
        next = findchar(start, end - start, from_c);
482
1.77k
        if (next == NULL)
483
1.06k
            break;
484
706
        *next = to_c;
485
706
        start = next + 1;
486
706
    }
487
488
1.06k
    return result;
489
1.06k
}
bytesobject.c:stringlib_replace_single_character_in_place
Line
Count
Source
449
34.3k
{
450
34.3k
    const char *self_s, *end;
451
34.3k
    char *result_s, *start, *next;
452
34.3k
    Py_ssize_t self_len;
453
34.3k
    PyObject *result;
454
455
    /* The result string will be the same size */
456
34.3k
    self_s = STRINGLIB_STR(self);
457
34.3k
    self_len = STRINGLIB_LEN(self);
458
459
34.3k
    next = findchar(self_s, self_len, from_c);
460
461
34.3k
    if (next == NULL) {
462
        /* No matches; return the original bytes */
463
33.2k
        return return_self(self);
464
33.2k
    }
465
466
    /* Need to make a new bytes */
467
1.06k
    result = STRINGLIB_NEW(NULL, self_len);
468
1.06k
    if (result == NULL) {
469
0
        return NULL;
470
0
    }
471
1.06k
    result_s = STRINGLIB_STR(result);
472
1.06k
    memcpy(result_s, self_s, self_len);
473
474
    /* change everything in-place, starting with this one */
475
1.06k
    start =  result_s + (next - self_s);
476
1.06k
    *start = to_c;
477
1.06k
    start++;
478
1.06k
    end = result_s + self_len;
479
480
1.77k
    while (--maxcount > 0) {
481
1.77k
        next = findchar(start, end - start, from_c);
482
1.77k
        if (next == NULL)
483
1.06k
            break;
484
706
        *next = to_c;
485
706
        start = next + 1;
486
706
    }
487
488
1.06k
    return result;
489
1.06k
}
Unexecuted instantiation: bytearrayobject.c:stringlib_replace_single_character_in_place
490
491
/* len(self)>=1, len(from)==len(to)>=2, maxcount>=1 */
492
static PyObject *
493
stringlib_replace_substring_in_place(PyObject *self,
494
                                     const char *from_s, Py_ssize_t from_len,
495
                                     const char *to_s, Py_ssize_t to_len,
496
                                     Py_ssize_t maxcount)
497
0
{
498
0
    const char *self_s, *end;
499
0
    char *result_s, *start;
500
0
    Py_ssize_t self_len, offset;
501
0
    PyObject *result;
502
503
    /* The result bytes will be the same size */
504
505
0
    self_s = STRINGLIB_STR(self);
506
0
    self_len = STRINGLIB_LEN(self);
507
508
0
    offset = stringlib_find(self_s, self_len,
509
0
                            from_s, from_len,
510
0
                            0);
511
0
    if (offset == -1) {
512
        /* No matches; return the original bytes */
513
0
        return return_self(self);
514
0
    }
515
516
    /* Need to make a new bytes */
517
0
    result = STRINGLIB_NEW(NULL, self_len);
518
0
    if (result == NULL) {
519
0
        return NULL;
520
0
    }
521
0
    result_s = STRINGLIB_STR(result);
522
0
    memcpy(result_s, self_s, self_len);
523
524
    /* change everything in-place, starting with this one */
525
0
    start =  result_s + offset;
526
0
    memcpy(start, to_s, from_len);
527
0
    start += from_len;
528
0
    end = result_s + self_len;
529
530
0
    while ( --maxcount > 0) {
531
0
        offset = stringlib_find(start, end - start,
532
0
                                from_s, from_len,
533
0
                                0);
534
0
        if (offset == -1)
535
0
            break;
536
0
        memcpy(start + offset, to_s, from_len);
537
0
        start += offset + from_len;
538
0
    }
539
540
0
    return result;
541
0
}
Unexecuted instantiation: bytesobject.c:stringlib_replace_substring_in_place
Unexecuted instantiation: bytearrayobject.c:stringlib_replace_substring_in_place
542
543
/* len(self)>=1, len(from)==1, len(to)>=2, maxcount>=1 */
544
static PyObject *
545
stringlib_replace_single_character(PyObject *self,
546
                                   char from_c,
547
                                   const char *to_s, Py_ssize_t to_len,
548
                                   Py_ssize_t maxcount)
549
0
{
550
0
    const char *self_s, *start, *next, *end;
551
0
    char *result_s;
552
0
    Py_ssize_t self_len, result_len;
553
0
    Py_ssize_t count;
554
0
    PyObject *result;
555
556
0
    self_s = STRINGLIB_STR(self);
557
0
    self_len = STRINGLIB_LEN(self);
558
559
0
    count = countchar(self_s, self_len, from_c, maxcount);
560
0
    if (count == 0) {
561
        /* no matches, return unchanged */
562
0
        return return_self(self);
563
0
    }
564
565
    /* use the difference between current and new, hence the "-1" */
566
    /*   result_len = self_len + count * (to_len-1)  */
567
0
    assert(count > 0);
568
0
    if (to_len - 1 > (PY_SSIZE_T_MAX - self_len) / count) {
569
0
        PyErr_SetString(PyExc_OverflowError, "replace bytes is too long");
570
0
        return NULL;
571
0
    }
572
0
    result_len = self_len + count * (to_len - 1);
573
574
0
    result = STRINGLIB_NEW(NULL, result_len);
575
0
    if (result == NULL) {
576
0
        return NULL;
577
0
    }
578
0
    result_s = STRINGLIB_STR(result);
579
580
0
    start = self_s;
581
0
    end = self_s + self_len;
582
0
    while (count-- > 0) {
583
0
        next = findchar(start, end - start, from_c);
584
0
        if (next == NULL)
585
0
            break;
586
587
0
        if (next == start) {
588
            /* replace with the 'to' */
589
0
            memcpy(result_s, to_s, to_len);
590
0
            result_s += to_len;
591
0
            start += 1;
592
0
        } else {
593
            /* copy the unchanged old then the 'to' */
594
0
            memcpy(result_s, start, next - start);
595
0
            result_s += (next - start);
596
0
            memcpy(result_s, to_s, to_len);
597
0
            result_s += to_len;
598
0
            start = next + 1;
599
0
        }
600
0
    }
601
    /* Copy the remainder of the remaining bytes */
602
0
    memcpy(result_s, start, end - start);
603
604
0
    return result;
605
0
}
Unexecuted instantiation: bytesobject.c:stringlib_replace_single_character
Unexecuted instantiation: bytearrayobject.c:stringlib_replace_single_character
606
607
/* len(self)>=1, len(from)>=2, len(to)>=2, maxcount>=1 */
608
static PyObject *
609
stringlib_replace_substring(PyObject *self,
610
                            const char *from_s, Py_ssize_t from_len,
611
                            const char *to_s, Py_ssize_t to_len,
612
                            Py_ssize_t maxcount)
613
0
{
614
0
    const char *self_s, *start, *next, *end;
615
0
    char *result_s;
616
0
    Py_ssize_t self_len, result_len;
617
0
    Py_ssize_t count, offset;
618
0
    PyObject *result;
619
620
0
    self_s = STRINGLIB_STR(self);
621
0
    self_len = STRINGLIB_LEN(self);
622
623
0
    count = stringlib_count(self_s, self_len,
624
0
                            from_s, from_len,
625
0
                            maxcount);
626
627
0
    if (count == 0) {
628
        /* no matches, return unchanged */
629
0
        return return_self(self);
630
0
    }
631
632
    /* Check for overflow */
633
    /*    result_len = self_len + count * (to_len-from_len) */
634
0
    assert(count > 0);
635
0
    if (to_len - from_len > (PY_SSIZE_T_MAX - self_len) / count) {
636
0
        PyErr_SetString(PyExc_OverflowError, "replace bytes is too long");
637
0
        return NULL;
638
0
    }
639
0
    result_len = self_len + count * (to_len - from_len);
640
641
0
    result = STRINGLIB_NEW(NULL, result_len);
642
0
    if (result == NULL) {
643
0
        return NULL;
644
0
    }
645
0
    result_s = STRINGLIB_STR(result);
646
647
0
    start = self_s;
648
0
    end = self_s + self_len;
649
0
    while (count-- > 0) {
650
0
        offset = stringlib_find(start, end - start,
651
0
                                from_s, from_len,
652
0
                                0);
653
0
        if (offset == -1)
654
0
            break;
655
0
        next = start + offset;
656
0
        if (next == start) {
657
            /* replace with the 'to' */
658
0
            memcpy(result_s, to_s, to_len);
659
0
            result_s += to_len;
660
0
            start += from_len;
661
0
        } else {
662
            /* copy the unchanged old then the 'to' */
663
0
            memcpy(result_s, start, next - start);
664
0
            result_s += (next - start);
665
0
            memcpy(result_s, to_s, to_len);
666
0
            result_s += to_len;
667
0
            start = next + from_len;
668
0
        }
669
0
    }
670
    /* Copy the remainder of the remaining bytes */
671
0
    memcpy(result_s, start, end - start);
672
673
0
    return result;
674
0
}
Unexecuted instantiation: bytesobject.c:stringlib_replace_substring
Unexecuted instantiation: bytearrayobject.c:stringlib_replace_substring
675
676
677
static PyObject *
678
stringlib_replace(PyObject *self,
679
                  const char *from_s, Py_ssize_t from_len,
680
                  const char *to_s, Py_ssize_t to_len,
681
                  Py_ssize_t maxcount)
682
34.5k
{
683
34.5k
    if (STRINGLIB_LEN(self) < from_len) {
684
        /* nothing to do; return the original bytes */
685
197
        return return_self(self);
686
197
    }
687
34.3k
    if (maxcount < 0) {
688
34.3k
        maxcount = PY_SSIZE_T_MAX;
689
34.3k
    } else if (maxcount == 0) {
690
        /* nothing to do; return the original bytes */
691
0
        return return_self(self);
692
0
    }
693
694
    /* Handle zero-length special cases */
695
34.3k
    if (from_len == 0) {
696
0
        if (to_len == 0) {
697
            /* nothing to do; return the original bytes */
698
0
            return return_self(self);
699
0
        }
700
        /* insert the 'to' bytes everywhere.    */
701
        /*    >>> b"Python".replace(b"", b".")  */
702
        /*    b'.P.y.t.h.o.n.'                  */
703
0
        return stringlib_replace_interleave(self, to_s, to_len, maxcount);
704
0
    }
705
706
34.3k
    if (to_len == 0) {
707
        /* delete all occurrences of 'from' bytes */
708
0
        if (from_len == 1) {
709
0
            return stringlib_replace_delete_single_character(
710
0
                self, from_s[0], maxcount);
711
0
        } else {
712
0
            return stringlib_replace_delete_substring(
713
0
                self, from_s, from_len, maxcount);
714
0
        }
715
0
    }
716
717
    /* Handle special case where both bytes have the same length */
718
719
34.3k
    if (from_len == to_len) {
720
34.3k
        if (from_len == 1) {
721
34.3k
            return stringlib_replace_single_character_in_place(
722
34.3k
                self, from_s[0], to_s[0], maxcount);
723
34.3k
        } else {
724
0
            return stringlib_replace_substring_in_place(
725
0
                self, from_s, from_len, to_s, to_len, maxcount);
726
0
        }
727
34.3k
    }
728
729
    /* Otherwise use the more generic algorithms */
730
0
    if (from_len == 1) {
731
0
        return stringlib_replace_single_character(
732
0
            self, from_s[0], to_s, to_len, maxcount);
733
0
    } else {
734
        /* len('from')>=2, len('to')>=1 */
735
0
        return stringlib_replace_substring(
736
0
            self, from_s, from_len, to_s, to_len, maxcount);
737
0
    }
738
0
}
bytesobject.c:stringlib_replace
Line
Count
Source
682
34.5k
{
683
34.5k
    if (STRINGLIB_LEN(self) < from_len) {
684
        /* nothing to do; return the original bytes */
685
197
        return return_self(self);
686
197
    }
687
34.3k
    if (maxcount < 0) {
688
34.3k
        maxcount = PY_SSIZE_T_MAX;
689
34.3k
    } else if (maxcount == 0) {
690
        /* nothing to do; return the original bytes */
691
0
        return return_self(self);
692
0
    }
693
694
    /* Handle zero-length special cases */
695
34.3k
    if (from_len == 0) {
696
0
        if (to_len == 0) {
697
            /* nothing to do; return the original bytes */
698
0
            return return_self(self);
699
0
        }
700
        /* insert the 'to' bytes everywhere.    */
701
        /*    >>> b"Python".replace(b"", b".")  */
702
        /*    b'.P.y.t.h.o.n.'                  */
703
0
        return stringlib_replace_interleave(self, to_s, to_len, maxcount);
704
0
    }
705
706
34.3k
    if (to_len == 0) {
707
        /* delete all occurrences of 'from' bytes */
708
0
        if (from_len == 1) {
709
0
            return stringlib_replace_delete_single_character(
710
0
                self, from_s[0], maxcount);
711
0
        } else {
712
0
            return stringlib_replace_delete_substring(
713
0
                self, from_s, from_len, maxcount);
714
0
        }
715
0
    }
716
717
    /* Handle special case where both bytes have the same length */
718
719
34.3k
    if (from_len == to_len) {
720
34.3k
        if (from_len == 1) {
721
34.3k
            return stringlib_replace_single_character_in_place(
722
34.3k
                self, from_s[0], to_s[0], maxcount);
723
34.3k
        } else {
724
0
            return stringlib_replace_substring_in_place(
725
0
                self, from_s, from_len, to_s, to_len, maxcount);
726
0
        }
727
34.3k
    }
728
729
    /* Otherwise use the more generic algorithms */
730
0
    if (from_len == 1) {
731
0
        return stringlib_replace_single_character(
732
0
            self, from_s[0], to_s, to_len, maxcount);
733
0
    } else {
734
        /* len('from')>=2, len('to')>=1 */
735
0
        return stringlib_replace_substring(
736
0
            self, from_s, from_len, to_s, to_len, maxcount);
737
0
    }
738
0
}
Unexecuted instantiation: bytearrayobject.c:stringlib_replace
739
740
#undef findchar