Skip to content

Commit eeb4569

Browse files
committed
Optimize performance of ndpi_strnstr()
1 parent 33d3d25 commit eeb4569

File tree

3 files changed

+89
-49
lines changed

3 files changed

+89
-49
lines changed

src/include/ndpi_api.h

+8-8
Original file line numberDiff line numberDiff line change
@@ -115,17 +115,17 @@ extern "C" {
115115
u_int32_t ndpi_get_tot_allocated_memory(void);
116116

117117
/**
118-
* Search the first occurrence of substring -find- in -s-
119-
* The search is limited to the first -slen- characters of the string
118+
* Finds the first occurrence of the substring 'needle' in the string 'haystack'.
120119
*
121-
* @par s = string to parse
122-
* @par find = string to match with -s-
123-
* @par slen = max length to match between -s- and -find-
124-
* @return a pointer to the beginning of the located substring;
125-
* NULL if the substring is not found
120+
* This function is similar to the standard `strstr()` function, but it has an additional parameter `len` that
121+
* specifies the maximum length of the search.
126122
*
123+
* @param haystack The string to search in.
124+
* @param needle The substring to search for.
125+
* @param len The maximum length of the search.
126+
* @return Pointer to the first occurrence of 'needle' in 'haystack', or NULL if no match is found.
127127
*/
128-
char* ndpi_strnstr(const char *s, const char *find, size_t slen);
128+
char *ndpi_strnstr(const char *haystack, const char *needle, size_t len);
129129

130130
/**
131131
* Same as ndpi_strnstr but case insensitive

src/lib/ndpi_main.c

+46-23
Original file line numberDiff line numberDiff line change
@@ -9685,32 +9685,55 @@ void ndpi_dump_risks_score(FILE *risk_out) {
96859685

96869686
/* ****************************************************** */
96879687

9688-
/*
9689-
* Find the first occurrence of find in s, where the search is limited to the
9690-
* first slen characters of s.
9691-
*/
9692-
char *ndpi_strnstr(const char *s, const char *find, size_t slen) {
9693-
char c;
9694-
size_t len;
9688+
char *ndpi_strnstr(const char *haystack, const char *needle, size_t len)
9689+
{
9690+
if (!haystack || !needle || len == 0)
9691+
{
9692+
return NULL;
9693+
}
9694+
9695+
size_t needle_len = strlen(needle);
9696+
size_t hs_real_len = strnlen(haystack, len);
96959697

9696-
if(s == NULL || find == NULL || slen == 0)
9698+
if (needle_len == 0)
9699+
{
9700+
return (char *)haystack;
9701+
}
9702+
9703+
if (needle_len > hs_real_len)
9704+
{
96979705
return NULL;
9706+
}
9707+
9708+
if (needle_len == 1)
9709+
{
9710+
return (char *)memchr(haystack, (int)*needle, hs_real_len);
9711+
}
96989712

9699-
if((c = *find++) != '\0') {
9700-
len = strnlen(find, slen);
9701-
do {
9702-
char sc;
9703-
9704-
do {
9705-
if(slen-- < 1 || (sc = *s++) == '\0')
9706-
return(NULL);
9707-
} while(sc != c);
9708-
if(len > slen)
9709-
return(NULL);
9710-
} while(strncmp(s, find, len) != 0);
9711-
s--;
9712-
}
9713-
return((char *) s);
9713+
const char *current = haystack;
9714+
const char *haystack_end = haystack + hs_real_len;
9715+
9716+
while (current <= haystack_end - needle_len)
9717+
{
9718+
/* Find the first occurrence of the first character from the needle */
9719+
current = (const char *)memchr(current, *needle, haystack_end - current);
9720+
9721+
if (!current)
9722+
{
9723+
return NULL;
9724+
}
9725+
9726+
/* Check the rest of the needle for a match */
9727+
if ((current + needle_len <= haystack_end) && (memcmp(current, needle, needle_len) == 0))
9728+
{
9729+
return (char *)current;
9730+
}
9731+
9732+
/* Shift one character to the right for the next search */
9733+
current++;
9734+
}
9735+
9736+
return NULL;
97149737
}
97159738

97169739
/* ****************************************************** */

tests/performance/strnstr.cpp

+35-18
Original file line numberDiff line numberDiff line change
@@ -30,40 +30,57 @@ char *ndpi_strnstr(const char *s, const char *find, size_t slen) {
3030
return ((char *)s);
3131
}
3232

33-
char *ndpi_strnstr_opt(const char *s, const char *find, size_t slen) {
34-
if (s == NULL || find == NULL || slen == 0) {
33+
char *ndpi_strnstr_opt(const char *haystack, const char *needle, size_t len)
34+
{
35+
if (!haystack || !needle)
36+
{
3537
return NULL;
3638
}
3739

38-
char c = *find;
40+
size_t needle_len = strlen(needle);
41+
size_t hs_real_len = strnlen(haystack, len);
3942

40-
if (c == '\0') {
41-
return (char *)s;
43+
if (!haystack || !needle)
44+
{
45+
return NULL;
4246
}
4347

44-
if (*(find + 1) == '\0') {
45-
return (char *)memchr(s, c, slen);
48+
if (needle_len == 0)
49+
{
50+
return (char *)haystack;
4651
}
4752

48-
size_t find_len = strnlen(find, slen);
49-
50-
if (find_len > slen) {
53+
if (needle_len > hs_real_len)
54+
{
5155
return NULL;
5256
}
5357

54-
const char *end = s + slen - find_len;
58+
if (needle_len == 1)
59+
{
60+
return (char *)memchr(haystack, (int)*needle, hs_real_len);
61+
}
5562

56-
while (s <= end) {
57-
if (memcmp(s, find, find_len) == 0) {
58-
return (char *)s;
59-
}
63+
const char *current = haystack;
64+
const char *haystack_end = haystack + hs_real_len;
6065

61-
size_t remaining_length = end - s;
62-
s = (char *)memchr(s + 1, c, remaining_length);
66+
while (current <= haystack_end - needle_len)
67+
{
68+
/* Find the first occurrence of the first character from the needle */
69+
current = (const char *)memchr(current, *needle, haystack_end - current);
6370

64-
if (s == NULL || s > end) {
71+
if (!current)
72+
{
6573
return NULL;
6674
}
75+
76+
/* Check the rest of the needle for a match */
77+
if ((current + needle_len <= haystack_end) && (memcmp(current, needle, needle_len) == 0))
78+
{
79+
return (char *)current;
80+
}
81+
82+
/* Shift one character to the right for the next search */
83+
current++;
6784
}
6885

6986
return NULL;

0 commit comments

Comments
 (0)