| #include <charconv> | |
| #include <cstdint> | |
| #include <iostream> | |
| #include <algorithm> | |
| #include "fast_float/fast_float.h" | |
| char *uint8_to_chars_manual(char *ptr, uint8_t value) { | |
| if (value == 0) { | |
| *ptr++ = '0'; | |
| return ptr; | |
| } | |
| char *start = ptr; | |
| while (value > 0) { | |
| *ptr++ = '0' + (value % 10); | |
| value /= 10; | |
| } | |
| // Reverse the digits written so far | |
| std::reverse(start, ptr); | |
| return ptr; | |
| } | |
| void uint32_to_ipv4_string(uint32_t ip, char *buffer) { | |
| uint8_t octets[4] = {static_cast<uint8_t>(ip >> 24), | |
| static_cast<uint8_t>(ip >> 16), | |
| static_cast<uint8_t>(ip >> 8), static_cast<uint8_t>(ip)}; | |
| char *ptr = buffer; | |
| for (int i = 0; i < 4; ++i) { | |
| ptr = uint8_to_chars_manual(ptr, octets[i]); | |
| if (i < 3) { | |
| *ptr++ = '.'; | |
| } | |
| } | |
| *ptr = '\0'; | |
| } | |
| fastfloat_really_inline uint32_t ipv4_string_to_uint32(const char *str, | |
| const char *end) { | |
| uint32_t ip = 0; | |
| const char *current = str; | |
| for (int i = 0; i < 4; ++i) { | |
| uint8_t value; | |
| auto r = fast_float::from_chars(current, end, value); | |
| if (r.ec != std::errc()) { | |
| throw std::invalid_argument("Invalid IP address format"); | |
| } | |
| current = r.ptr; | |
| ip = (ip << 8) | value; | |
| if (i < 3) { | |
| if (current == end || *current++ != '.') { | |
| throw std::invalid_argument("Invalid IP address format"); | |
| } | |
| } | |
| } | |
| return ip; | |
| } | |
| bool test_all_ipv4_conversions() { | |
| std::cout << "Testing all IPv4 conversions... 0, 1000, 2000, 3000, 4000, " | |
| "5000, 6000, 7000, 8000, 9000, ..." | |
| << std::endl; | |
| char buffer[16]; | |
| for (uint64_t ip = 0; ip <= 0xFFFFFFFF; ip += 1000) { | |
| if (ip % 10000000 == 0) { | |
| std::cout << "." << std::flush; | |
| } | |
| uint32_to_ipv4_string(static_cast<uint32_t>(ip), buffer); | |
| const char *end = buffer + strlen(buffer); | |
| uint32_t parsed_ip = ipv4_string_to_uint32(buffer, end); | |
| if (parsed_ip != ip) { | |
| std::cerr << "Mismatch: original " << ip << ", parsed " << parsed_ip | |
| << std::endl; | |
| return false; | |
| } | |
| } | |
| std::cout << std::endl; | |
| return true; | |
| } | |
| int main() { | |
| if (test_all_ipv4_conversions()) { | |
| std::cout << "All IPv4 conversions passed!" << std::endl; | |
| return EXIT_SUCCESS; | |
| } else { | |
| std::cerr << "IPv4 conversion test failed!" << std::endl; | |
| return EXIT_FAILURE; | |
| } | |
| } |