https://lemire.me/blog/2025/12/27/parsing-ip-addresses-quickly-portably-without-simd-magic/ Skip to content Daniel Lemire's blog Daniel Lemire is a software performance expert. He ranks among the top 2% of scientists globally (Stanford/Elsevier 2025) and is one of GitHub's top 1000 most followed developers. Menu and widgets * My home page * GitHub profile Your business needs help? Get in touch, I offer private talks, training, consulting and I do sponsored open-source projects. Support my work! I do not accept any advertisement. However, you can you can sponsor my open-source work on GitHub. Daniel Lemire started this blog in 2004. It contains 2,339 posts and 16,104 approved comments. Daniel Lemire's blog ranks among the top 50 most popular blogs on Hacker News, a leading tech news aggregation platform. Join over 12,500 email subscribers: [ ][Go!] You can follow this blog on telegram. Follow me on GitHub: Follow me on X: Follow @lemire Search for: [ ] [Search] Recent Posts * Don't be so eager to rewrite your code * Parsing IP addresses quickly (portably, without SIMD magic) * Performance trick : optimistic vs pessimistic checks * JSON-complete data formats and programming languages * Multiplying the Shuffle Speed in Go with Batched Shuffling Recent Comments * Daniel Lemire on Performance trick : optimistic vs pessimistic checks * Robert Wishlaw on Performance trick : optimistic vs pessimistic checks * Daniel Lemire on Performance trick : optimistic vs pessimistic checks * KWillets on Performance trick : optimistic vs pessimistic checks * purplesyringa on Performance trick : optimistic vs pessimistic checks Pages * A short history of technology * About me * Book recommendations * Cognitive biases * Interviews and talks * My bets * My favorite articles * My favorite quotes * My rules * Newsletter * Predictions * Privacy Policy * Recommended video games * Terms of use * Write good papers Archives Archives [Select Month ] Boring stuff * Log in * Entries feed * Comments feed * WordPress.org [Capture-decran-le-2025-12-27-a-18] Parsing IP addresses quickly (portably, without SIMD magic) Most programmers are familiar with IP addresses. They take the form of four numbers between 0 and 255 separated by dots: 192.168.0.1. In some sense, it is a convoluted way to represent a 32-bit integer. The modern version of an IP address is IPv6 which is usually surrounded by square brackets. It is less common in my experience. Using fancy techniques, you can parse IP addresses with as little as 50 instructions. It is a bit complicated and not necessarily portable. What if you want high speed without too much work or a specialized library? You can try to roll your own. But since I am civilized programmer, I just asked my favorite AI to write it for me. // Parse an IPv4 address starting at 'p'. // p : start pointer, pend: end of the string std::expected parse_manual(const char *p, const char *pend) { uint32_t ip = 0; int octets = 0; while (p < pend && octets < 4) { uint32_t val = 0; const char *start = p; while (p < pend && *p >= '0' && *p <= '9') { val = val * 10 + (*p - '0'); if (val > 255) { return std::unexpected(invalid_format); } p++; } if (p == start || (p - start > 1 && *start == '0')) { return std::unexpected(invalid_format); } ip = (ip << 8) | val; octets++; if (octets < 4) { if (p == pend || *p != '.') { return std::unexpected(invalid_format); } p++; // Skip dot } } if (octets == 4 && p == pend) { return ip; } else { return std::unexpected(invalid_format); } } It was immediately clear to me that this function was not as fast as it could be. I then asked the AI to improve the result by using the fact that each number is made of between one and three digits. I got the following reasonable function. std::expected parse_manual_unrolled(const char *p, const char *pend) { uint32_t ip = 0; int octets = 0; while (p < pend && octets < 4) { uint32_t val = 0; if (p < pend && *p >= '0' && *p <= '9') { val = (*p++ - '0'); if (p < pend && *p >= '0' && *p <= '9') { if (val == 0) { return std::unexpected(invalid_format); } val = val * 10 + (*p++ - '0'); if (p < pend && *p >= '0' && *p <= '9') { val = val * 10 + (*p++ - '0'); if (val > 255) { return std::unexpected(invalid_format); } } } } else { return std::unexpected(parse_error::invalid_format); } ip = (ip << 8) | val; octets++; if (octets < 4) { if (p == pend || *p != '.') { return std::unexpected(invalid_format); } p++; // Skip the dot } } if (octets == 4 && p == pend) { return ip; } else { return std::unexpected(invalid_format); } } Nice work AI! In C++, we have standard functions to parse numbers (std::from_chars) which can significantly simplify the code. std::expected parse_ip(const char *p, const char *pend) { const char *current = p; uint32_t ip = 0; for (int i = 0; i < 4; ++i) { uint8_t value; auto r = std::from_chars(current, pend, value); if (r.ec != std::errc()) { return std::unexpected(invalid_format); } current = r.ptr; ip = (ip << 8) | value; if (i < 3) { if (current == pend || *current++ != '.') { return std::unexpected(invalid_format); } } } return ip; } You can also use the fast_float library as a substitute for std::from_chars. The latest version of fast_float has faster 8-bit integer parsing thanks to Shikhar Soni (with a fix by Pavel Novikov). I wrote a benchmark for this problem. Let us first consider the results using an Apple M4 processors (4.5 GHz) with LLVM 17. function instructions/ip ns/ip manual 185 6.2 manual (unrolled) 114 3.3 from_chars 381 14 fast_float 181 7.2 Let us try with GCC 12 and an Intel Ice Lake processor (3.2 GHz) using GCC 12. function instructions/ip ns/ip manual 219 30 manual (unrolled) 154 24 from_chars 220 29 fast_float 211 18 And finally, let us try with a Chinese Longsoon 3A6000 processor (2.5 GHz) using LLVM 21. function instructions/ip ns/ip manual 187 29 manual (unrolled) 109 21 from_chars 191 39 fast_float 193 27 The optimization work on the fast_float library paid off. The difference is especially striking on the x64 processor. What is also interesting in my little experiment is that I was able to get the AI to produce faster code with relatively little effort on my part. I did have to 'guide' the AI. Does that mean that I can retire? Not yet. But I am happy that I can more quickly get good reference baselines, which allows me to better focus my work where it matters. Reference: The fast_float C++ library is a fast number parsing library part of GCC and major web browsers. Daniel Lemire, "Parsing IP addresses quickly (portably, without SIMD magic)," in Daniel Lemire's blog, December 27, 2025, https:// lemire.me/blog/2025/12/27/ parsing-ip-addresses-quickly-portably-without-simd-magic/. [BibTeX] Published by [a0c6c3] Daniel Lemire A computer science professor at the University of Quebec (TELUQ). View all posts by Daniel Lemire Posted on December 27, 2025December 28, 2025Author Daniel Lemire Categories Leave a Reply Cancel reply Your email address will not be published. [ ] [ ] [ ] [ ] [ ] [ ] [ ] Comment * [ ] Name * [ ] Email * [ ] Website [ ] [ ] Save my name, email, and website in this browser for the next time I comment. [Post Comment] [ ] [ ] [ ] [ ] [ ] [ ] [ ] D[ ] You can also subscribe by email to this blog (non commercial, no ads, weekly email) If you want to post code, consider formatting it with a tool like tohtml. Post navigation Previous Previous post: Performance trick : optimistic vs pessimistic checks Next Next post: Don't be so eager to rewrite your code Terms of use Proudly powered by WordPress