@@ -26,6 +26,28 @@ void pretty_print(size_t volume, size_t bytes, std::string name,
2626 printf (" \n " );
2727}
2828
29+ const char *seek_ip_end (const char *p, const char *pend) {
30+ const char *current = p;
31+ size_t count = 0 ;
32+ for (; current != pend; ++current) {
33+ if (*current == ' .' ) {
34+ count++;
35+ if (count == 3 ) {
36+ ++current;
37+ break ;
38+ }
39+ }
40+ }
41+ while (current != pend) {
42+ if (*current <= ' 9' && *current >= ' 0' ) {
43+ ++current;
44+ } else {
45+ break ;
46+ }
47+ }
48+ return current;
49+ }
50+
2951int parse_u8_fastfloat (const char *&p, const char *pend, uint8_t *out) {
3052 if (p == pend)
3153 return 0 ;
@@ -39,8 +61,9 @@ int parse_u8_fastfloat(const char *&p, const char *pend, uint8_t *out) {
3961
4062static inline int parse_u8_fromchars (const char *&p, const char *pend,
4163 uint8_t *out) {
42- if (p == pend)
64+ if (p == pend) {
4365 return 0 ;
66+ }
4467 auto r = std::from_chars (p, pend, *out);
4568 if (r.ec == std::errc ()) {
4669 p = r.ptr ;
@@ -50,26 +73,35 @@ static inline int parse_u8_fromchars(const char *&p, const char *pend,
5073}
5174
5275template <typename Parser>
53- static inline int parse_ip_line (const char *&p, const char *pend, uint32_t &sum,
54- Parser parse_uint8) {
55- uint8_t o = 0 ;
56- for (int i = 0 ; i < 4 ; ++i) {
57- if (!parse_uint8 (p, pend, &o))
58- return 0 ;
59- sum += o;
60- if (i != 3 ) {
61- if (p == pend || *p != ' .' )
62- return 0 ;
63- ++p;
64- }
76+ std::pair<bool , uint32_t > simple_parse_ip_line (const char *p, const char *pend,
77+ Parser parse_uint8) {
78+ uint8_t v1;
79+ if (!parse_uint8 (p, pend, &v1)) {
80+ return {false , 0 };
81+ }
82+ if (p == pend || *p++ != ' .' ) {
83+ return {false , 0 };
84+ }
85+ uint8_t v2;
86+ if (!parse_uint8 (p, pend, &v2)) {
87+ return {false , 0 };
88+ }
89+ if (p == pend || *p++ != ' .' ) {
90+ return {false , 0 };
91+ }
92+ uint8_t v3;
93+ if (!parse_uint8 (p, pend, &v3)) {
94+ return {false , 0 };
6595 }
66- // consume optional '\r'
67- if (p != pend && *p == ' \r ' )
68- ++p;
69- // expect '\n' or end
70- if (p != pend && *p == ' \n ' )
71- ++p;
72- return 1 ;
96+ if (p == pend || *p++ != ' .' ) {
97+ return {false , 0 };
98+ }
99+ uint8_t v4;
100+ if (!parse_uint8 (p, pend, &v4)) {
101+ return {false , 0 };
102+ }
103+ return {true , (uint32_t (v1) << 24 ) | (uint32_t (v2) << 16 ) |
104+ (uint32_t (v3) << 8 ) | uint32_t (v4)};
73105}
74106
75107static std::string make_ip_line (uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
@@ -87,19 +119,22 @@ static std::string make_ip_line(uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
87119}
88120
89121int main () {
90- constexpr size_t N = 500000 ;
122+ constexpr size_t N = 15000 ;
91123 std::mt19937 rng (1234 );
92124 std::uniform_int_distribution<int > dist (0 , 255 );
93125
94126 std::string buf;
95- buf.reserve (N * 16 );
127+ constexpr size_t ip_size = 16 ;
128+ buf.reserve (N * ip_size);
96129
97130 for (size_t i = 0 ; i < N; ++i) {
98131 uint8_t a = (uint8_t )dist (rng);
99132 uint8_t b = (uint8_t )dist (rng);
100133 uint8_t c = (uint8_t )dist (rng);
101134 uint8_t d = (uint8_t )dist (rng);
102- buf += make_ip_line (a, b, c, d);
135+ std::string ip_line = make_ip_line (a, b, c, d);
136+ ip_line.resize (ip_size, ' ' ); // pad to fixed size
137+ buf.append (ip_line);
103138 }
104139
105140 // sentinel to allow 4-byte loads at end
@@ -108,40 +143,35 @@ int main() {
108143 const size_t bytes = buf.size () - 4 ; // exclude sentinel from throughput
109144 const size_t volume = N;
110145
111- // validate correctness
112- {
113- const char *start = buf.data ();
114- const char *end = buf.data () + bytes;
115- const char *p = start;
116- const char *pend = end;
117- uint32_t sum = 0 ;
118- for (size_t i = 0 ; i < N; ++i) {
119- int ok = parse_ip_line (p, pend, sum, parse_u8_fromchars);
120- if (!ok) {
121- std::fprintf (stderr, " fromchars parse failed at line %zu\n " , i);
122- std::abort ();
123- }
124- p = start;
125- pend = end;
126- ok = parse_ip_line (p, pend, sum, parse_u8_fastfloat);
127- if (!ok) {
128- std::fprintf (stderr, " fastswar parse failed at line %zu\n " , i);
129- std::abort ();
130- }
131- }
132- }
146+ volatile uint32_t sink = 0 ;
133147
134- uint32_t sink = 0 ;
148+ pretty_print (volume, bytes, " just_seek_ip_end (no parse)" ,
149+ counters::bench ([&]() {
150+ const char *p = buf.data ();
151+ const char *pend = buf.data () + bytes;
152+ uint32_t sum = 0 ;
153+ int ok = 0 ;
154+ for (size_t i = 0 ; i < N; ++i) {
155+ const char *q = seek_ip_end (p, pend);
156+ sum += (uint32_t )(q - p);
157+ p += ip_size;
158+ }
159+ sink += sum;
160+ }));
135161
136162 pretty_print (volume, bytes, " parse_ip_std_fromchars" , counters::bench ([&]() {
137163 const char *p = buf.data ();
138164 const char *pend = buf.data () + bytes;
139165 uint32_t sum = 0 ;
140166 int ok = 0 ;
141167 for (size_t i = 0 ; i < N; ++i) {
142- ok = parse_ip_line (p, pend, sum, parse_u8_fromchars);
143- if (!ok)
168+ auto [ok, ip] =
169+ simple_parse_ip_line (p, pend, parse_u8_fromchars);
170+ sum += ip;
171+ if (!ok) {
144172 std::abort ();
173+ }
174+ p += ip_size;
145175 }
146176 sink += sum;
147177 }));
@@ -152,13 +182,16 @@ int main() {
152182 uint32_t sum = 0 ;
153183 int ok = 0 ;
154184 for (size_t i = 0 ; i < N; ++i) {
155- ok = parse_ip_line (p, pend, sum, parse_u8_fastfloat);
156- if (!ok)
185+ auto [ok, ip] =
186+ simple_parse_ip_line (p, pend, parse_u8_fastfloat);
187+ sum += ip;
188+ if (!ok) {
157189 std::abort ();
190+ }
191+ p += ip_size;
158192 }
159193 sink += sum;
160194 }));
161195
162- std::printf (" sink=%u\n " , sink);
163196 return EXIT_SUCCESS;
164197}
0 commit comments