|
19 | 19 | * @brief Zero-copy buffer implementation for reactor protocol layer |
20 | 20 | */ |
21 | 21 |
|
| 22 | +/* Enable memmem on Linux (it's a GNU extension) */ |
| 23 | +#ifndef _GNU_SOURCE |
| 24 | +#define _GNU_SOURCE |
| 25 | +#endif |
| 26 | + |
22 | 27 | #include "py_reactor_buffer.h" |
23 | 28 | #include <unistd.h> |
24 | 29 | #include <errno.h> |
@@ -393,20 +398,33 @@ static PyObject *ReactorBuffer_find(ReactorBufferObject *self, PyObject *args) { |
393 | 398 |
|
394 | 399 | Py_ssize_t result = -1; |
395 | 400 | if (start <= end && sub_buf.len <= (end - start)) { |
396 | | - /* Simple search - for small patterns memmem isn't always available */ |
397 | 401 | const unsigned char *haystack = self->resource->data + start; |
398 | 402 | Py_ssize_t haystack_len = end - start; |
399 | 403 | const unsigned char *needle = sub_buf.buf; |
400 | 404 | Py_ssize_t needle_len = sub_buf.len; |
401 | 405 |
|
402 | 406 | if (needle_len == 0) { |
403 | 407 | result = start; |
| 408 | + } else if (needle_len == 1) { |
| 409 | + /* Single byte: use memchr (very fast) */ |
| 410 | + void *found = memchr(haystack, needle[0], haystack_len); |
| 411 | + if (found != NULL) { |
| 412 | + result = start + ((const unsigned char *)found - haystack); |
| 413 | + } |
404 | 414 | } else { |
405 | | - for (Py_ssize_t i = 0; i <= haystack_len - needle_len; i++) { |
406 | | - if (memcmp(haystack + i, needle, needle_len) == 0) { |
407 | | - result = start + i; |
| 415 | + /* Multi-byte: use memchr to find first byte, then memcmp to verify. |
| 416 | + * This is faster than memmem for short patterns (HTTP parsing). */ |
| 417 | + const unsigned char *p = haystack; |
| 418 | + Py_ssize_t remaining = haystack_len; |
| 419 | + while (remaining >= needle_len) { |
| 420 | + p = memchr(p, needle[0], remaining); |
| 421 | + if (p == NULL) break; |
| 422 | + if (memcmp(p, needle, needle_len) == 0) { |
| 423 | + result = start + (p - haystack); |
408 | 424 | break; |
409 | 425 | } |
| 426 | + p++; |
| 427 | + remaining = haystack_len - (p - haystack); |
410 | 428 | } |
411 | 429 | } |
412 | 430 | } |
@@ -450,11 +468,16 @@ static PyObject *ReactorBuffer_rfind(ReactorBufferObject *self, PyObject *args) |
450 | 468 | if (needle_len == 0) { |
451 | 469 | result = end; |
452 | 470 | } else { |
453 | | - for (Py_ssize_t i = haystack_len - needle_len; i >= 0; i--) { |
454 | | - if (memcmp(haystack + i, needle, needle_len) == 0) { |
455 | | - result = start + i; |
456 | | - break; |
457 | | - } |
| 471 | + /* Use memmem iteratively to find last occurrence */ |
| 472 | + const unsigned char *search_start = haystack; |
| 473 | + Py_ssize_t search_len = haystack_len; |
| 474 | + void *found; |
| 475 | + while ((found = memmem(search_start, search_len, needle, needle_len)) != NULL) { |
| 476 | + result = start + ((const unsigned char *)found - haystack); |
| 477 | + /* Continue searching after this match */ |
| 478 | + search_start = (const unsigned char *)found + 1; |
| 479 | + search_len = haystack_len - (search_start - haystack); |
| 480 | + if (search_len < needle_len) break; |
458 | 481 | } |
459 | 482 | } |
460 | 483 | } |
@@ -512,10 +535,29 @@ static PyObject *ReactorBuffer_count(ReactorBufferObject *self, PyObject *args) |
512 | 535 | const unsigned char *needle = sub_buf.buf; |
513 | 536 | Py_ssize_t needle_len = sub_buf.len; |
514 | 537 |
|
515 | | - for (Py_ssize_t i = 0; i <= haystack_len - needle_len; i++) { |
516 | | - if (memcmp(haystack + i, needle, needle_len) == 0) { |
| 538 | + if (needle_len == 1) { |
| 539 | + /* Single byte: use memchr repeatedly */ |
| 540 | + const unsigned char *p = haystack; |
| 541 | + Py_ssize_t remaining = haystack_len; |
| 542 | + while ((p = memchr(p, needle[0], remaining)) != NULL) { |
517 | 543 | count++; |
518 | | - i += needle_len - 1; /* Non-overlapping */ |
| 544 | + p++; |
| 545 | + remaining = haystack_len - (p - haystack); |
| 546 | + } |
| 547 | + } else { |
| 548 | + /* Multi-byte: use memchr + memcmp pattern */ |
| 549 | + const unsigned char *p = haystack; |
| 550 | + Py_ssize_t remaining = haystack_len; |
| 551 | + while (remaining >= needle_len) { |
| 552 | + p = memchr(p, needle[0], remaining); |
| 553 | + if (p == NULL) break; |
| 554 | + if (memcmp(p, needle, needle_len) == 0) { |
| 555 | + count++; |
| 556 | + p += needle_len; /* Non-overlapping */ |
| 557 | + } else { |
| 558 | + p++; |
| 559 | + } |
| 560 | + remaining = haystack_len - (p - haystack); |
519 | 561 | } |
520 | 562 | } |
521 | 563 | } else if (sub_buf.len == 0 && start <= end) { |
|
0 commit comments