1
1
#include < algorithm>
2
2
#include < chrono>
3
- #include < cmath>
4
3
#include < cstring>
5
4
#include < functional>
6
- #include < iomanip>
7
5
#include < iostream>
6
+ #include < limits>
8
7
#include < map>
9
8
#include < random>
10
9
#include < string>
10
+ #include < tuple>
11
11
#include < vector>
12
12
13
13
char *ndpi_strnstr (const char *s, const char *find, size_t slen) {
@@ -30,40 +30,42 @@ char *ndpi_strnstr(const char *s, const char *find, size_t slen) {
30
30
return ((char *)s);
31
31
}
32
32
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
+ if (!haystack || !needle || len == 0 ) {
35
35
return NULL ;
36
36
}
37
37
38
- char c = *find;
38
+ size_t needle_len = strlen (needle);
39
+ size_t hs_real_len = strnlen (haystack, len);
39
40
40
- if (c == ' \0 ' ) {
41
- return (char *)s ;
41
+ if (needle_len == 0 ) {
42
+ return (char *)haystack ;
42
43
}
43
44
44
- if (*(find + 1 ) == ' \0 ' ) {
45
- return (char *)memchr (s, c, slen);
46
- }
47
-
48
- size_t find_len = strnlen (find, slen);
49
-
50
- if (find_len > slen) {
45
+ if (needle_len > hs_real_len) {
51
46
return NULL ;
52
47
}
53
48
54
- const char *end = s + slen - find_len;
49
+ if (needle_len == 1 ) {
50
+ return (char *)memchr (haystack, *needle, hs_real_len);
51
+ }
55
52
56
- while (s <= end) {
57
- if (memcmp (s, find, find_len) == 0 ) {
58
- return (char *)s;
59
- }
53
+ const char *current = haystack;
54
+ const char *haystack_end = haystack + hs_real_len;
60
55
61
- size_t remaining_length = end - s;
62
- s = (char *)memchr (s + 1 , c, remaining_length );
56
+ while (current <= haystack_end - needle_len) {
57
+ current = (const char *)memchr (current, *needle, haystack_end - current );
63
58
64
- if (s == NULL || s > end ) {
59
+ if (!current ) {
65
60
return NULL ;
66
61
}
62
+
63
+ if ((current + needle_len <= haystack_end) &&
64
+ memcmp (current, needle, needle_len) == 0 ) {
65
+ return (char *)current;
66
+ }
67
+
68
+ current++;
67
69
}
68
70
69
71
return NULL ;
@@ -80,10 +82,9 @@ std::string random_string(size_t length, std::mt19937 &gen) {
80
82
81
83
double measure_time (const std::function<char *(const char *, const char *,
82
84
size_t )> &strnstr_impl,
83
- const std::string &haystack, const std::string &needle,
84
- std::mt19937 &gen) {
85
+ const std::string &haystack, const std::string &needle) {
85
86
auto start = std::chrono::high_resolution_clock::now ();
86
- // Call the function to prevent optimization
87
+
87
88
volatile auto result =
88
89
strnstr_impl (haystack.c_str (), needle.c_str (), haystack.size ());
89
90
auto end = std::chrono::high_resolution_clock::now ();
@@ -92,6 +93,31 @@ double measure_time(const std::function<char *(const char *, const char *,
92
93
.count ();
93
94
}
94
95
96
+ void warm_up (const std::function<char *(const char *, const char *, size_t )>
97
+ &strnstr_impl,
98
+ const std::string &haystack, const std::string &needle,
99
+ int iterations) {
100
+ for (int i = 0 ; i < iterations; i++) {
101
+ volatile auto result =
102
+ strnstr_impl (haystack.c_str (), needle.c_str (), haystack.size ());
103
+ }
104
+ }
105
+
106
+ double average_without_extremes (const std::vector<double > ×) {
107
+ if (times.size () < 5 ) {
108
+ return std::accumulate (times.begin (), times.end (), 0.0 ) /
109
+ static_cast <double >(times.size ());
110
+ }
111
+
112
+ auto sorted_times = times;
113
+ std::sort (sorted_times.begin (), sorted_times.end ());
114
+ sorted_times.erase (sorted_times.begin ());
115
+ sorted_times.pop_back ();
116
+
117
+ return std::accumulate (sorted_times.begin (), sorted_times.end (), 0.0 ) /
118
+ sorted_times.size ();
119
+ }
120
+
95
121
int main () {
96
122
std::ios_base::sync_with_stdio (false );
97
123
std::mt19937 gen (std::random_device{}());
@@ -105,10 +131,13 @@ int main() {
105
131
const std::vector<std::pair<
106
132
std::string, std::function<char *(const char *, const char *, size_t )>>>
107
133
strnstr_impls = {
108
- {" ndpi_strnstr" , ndpi_strnstr}, { " ndpi_strnstr_opt " , ndpi_strnstr_opt}
109
- // Add other implementations for comparison here
134
+ {" ndpi_strnstr" , ndpi_strnstr},
135
+ { " ndpi_strnstr_opt " , ndpi_strnstr_opt},
110
136
};
111
137
138
+ const int iterations = 100000 ;
139
+ const int warm_up_iterations = 1000 ;
140
+
112
141
for (size_t haystack_len : haystack_lengths) {
113
142
for (size_t needle_len : needle_lengths) {
114
143
std::cout << " \n Test case - Haystack length: " << haystack_len
@@ -120,19 +149,20 @@ int main() {
120
149
std::map<std::string, double > times;
121
150
122
151
for (const auto &impl : strnstr_impls) {
123
- double time_sum = 0.0 ;
124
- for (int i = 0 ; i < 100000 ; i++) {
125
- time_sum += measure_time (impl.second , haystack, needle, gen);
152
+ warm_up (impl.second , haystack, needle, warm_up_iterations);
153
+
154
+ std::vector<double > times_vector;
155
+ for (int i = 0 ; i < iterations; i++) {
156
+ times_vector.push_back (measure_time (impl.second , haystack, needle));
126
157
}
127
- double average_time =
128
- time_sum / 100000.0 ; // Average time in nanoseconds
158
+
159
+ double average_time = average_without_extremes (times_vector);
129
160
130
161
times[impl.first ] = average_time;
131
162
std::cout << " Average time for " << impl.first << " : " << average_time
132
163
<< " ns\n " ;
133
164
}
134
165
135
- // Compare execution times between implementations
136
166
std::string fastest_impl;
137
167
double fastest_time = std::numeric_limits<double >::max ();
138
168
for (const auto &impl_time : times) {
0 commit comments