Skip to content

Commit

Permalink
Merge pull request #5 from VladimirShaleev/unicode-support
Browse files Browse the repository at this point in the history
Unicode support

Added support for wide chars, UTF-8, UTF-16 and UTF-32. If a Unicode character is found in the input string, the error will now display a more clear message:

try {
    ipv4_address::parse(u"127.𝄋0.0\ud55c8.1");
} catch (const std::exception &exc) {
    std::cerr << exc.what() << std::endl;
    // unexpected next unicode symbol {U+1d10b} in string 127.{U+1d10b}0.0{U+d55c}8.1
}
  • Loading branch information
VladimirShaleev committed May 6, 2024
2 parents 2378009 + d1fb274 commit 824e5d2
Show file tree
Hide file tree
Showing 35 changed files with 2,755 additions and 538 deletions.
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ set(IPADDRESS_IPV6_SCOPE_MAX_LENGTH "16" CACHE STRING "Maximum scope-id length f
project(ipaddress
HOMEPAGE_URL "https://github.com/VladimirShaleev/ipaddress"
DESCRIPTION "A library for working and manipulating IPv4/IPv6 addresses and networks"
VERSION 1.0.1
VERSION 1.1.0
LANGUAGES CXX)

include(CMakePackageConfigHelpers)
Expand Down Expand Up @@ -66,7 +66,7 @@ install(
install(
FILES
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc"
DESTINATION "${CMAKE_INSTALL_DATADIR}/pkgconfig"
DESTINATION "${CMAKE_INSTALL_DATADIR}/pkgconfig"
)
install(DIRECTORY include/ DESTINATION include)

Expand Down
100 changes: 50 additions & 50 deletions doc/benchmark.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,26 +37,26 @@ CPU Caches: <br>
&nbsp;&nbsp;&nbsp;&nbsp;L1 Instruction 32 KiB (x8) <br>
&nbsp;&nbsp;&nbsp;&nbsp;L2 Unified 1280 KiB (x8) <br>
&nbsp;&nbsp;&nbsp;&nbsp;L3 Unified 18432 KiB (x1) <br>
Load Average: 3.12, 5.12, 6.21
Load Average: 2.22, 2.16, 1.02

| input string | ipaddress | socket API | boost asio |
|:----------------------------------------------- | ---------:| ----------:| ----------:|
| `127.0.0.1` | 12.6 ns | 16.5 ns | 17.8 ns |
| `192.168.0.1` | 14.5 ns | 19.6 ns | 20.8 ns |
| `0.0.0.0` | 9.29 ns | 12.9 ns | 15.4 ns |
| `100.64.0.0` | 11.6 ns | 16.9 ns | 20.7 ns |
| `192.168.1.1` | 12.5 ns | 17.5 ns | 22.6 ns |
| `127.239.0.1` | 12.3 ns | 17.9 ns | 21.6 ns |
| `127.128.128.255` | 17.9 ns | 23.1 ns | 25.6 ns |
| `224.1.1.1` | 11.0 ns | 16.1 ns | 17.8 ns |
| `2001:db8::1` | 57.7 ns | 24.6 ns | 36.4 ns |
| `0001:0002:0003:0004:0005:0006:0007:0008%12345` | 165 ns | - | 73.3 ns |
| `::ffff:172.32.0.0` | 97.7 ns | 40.7 ns | 50.5 ns |
| `2002:ac1d:2d64::1` | 74.4 ns | 38.4 ns | 43.9 ns |
| `2001:0000:4136:e378:8000:63bf:3fff:fdd2` | 130 ns | 53.0 ns | 69.2 ns |
| `2000::4136:e378:8000:63bf:3fff:fdd2` | 119 ns | 58.3 ns | 68.1 ns |
| `2001:db8:0:0:1:0:0:1` | 89.7 ns | 27.7 ns | 38.2 ns |
| `fe80::1ff:fe23:4567:890a%31` | 98.4 ns | - | 1423 ns |
| `127.0.0.1` | 8.76 ns | 11.8 ns | 14.2 ns |
| `192.168.0.1` | 9.81 ns | 13.4 ns | 16.5 ns |
| `0.0.0.0` | 7.80 ns | 9.84 ns | 12.8 ns |
| `100.64.0.0` | 9.32 ns | 13.1 ns | 15.2 ns |
| `192.168.1.1` | 9.82 ns | 13.8 ns | 16.2 ns |
| `127.239.0.1` | 9.81 ns | 13.5 ns | 16.0 ns |
| `127.128.128.255` | 13.1 ns | 18.2 ns | 26.4 ns |
| `224.1.1.1` | 8.84 ns | 11.6 ns | 14.2 ns |
| `2001:db8::1` | 39.3 ns | 20.6 ns | 27.0 ns |
| `0001:0002:0003:0004:0005:0006:0007:0008%12345` | 103 ns | - | 60.4 ns |
| `::ffff:172.32.0.0` | 62.5 ns | 29.8 ns | 38.5 ns |
| `2002:ac1d:2d64::1` | 50.8 ns | 28.3 ns | 36.4 ns |
| `2001:0000:4136:e378:8000:63bf:3fff:fdd2` | 102 ns | 43.5 ns | 53.9 ns |
| `2000::4136:e378:8000:63bf:3fff:fdd2` | 93.0 ns | 45.7 ns | 55.0 ns |
| `2001:db8:0:0:1:0:0:1` | 68.3 ns | 22.0 ns | 29.4 ns |
| `fe80::1ff:fe23:4567:890a%31` | 69.5 ns | - | 1115 ns |

</details>

Expand All @@ -72,26 +72,26 @@ CPU Caches: <br>
&nbsp;&nbsp;&nbsp;&nbsp;L1 Instruction 32 KiB <br>
&nbsp;&nbsp;&nbsp;&nbsp;L2 Unified 512 KiB (x4) <br>
&nbsp;&nbsp;&nbsp;&nbsp;L3 Unified 6144 KiB <br>
Load Average: 17.22, 9.41, 6.84
Load Average: 2.70, 4.59, 7.36

| input string | ipaddress | socket API | boost asio |
|:----------------------------------------------- | ---------:| ----------:| ----------:|
| `127.0.0.1` | 14.4 ns | 49.2 ns | 57.8 ns |
| `192.168.0.1` | 16.8 ns | 56.3 ns | 64.9 ns |
| `0.0.0.0` | 12.0 ns | 38.7 ns | 48.4 ns |
| `100.64.0.0` | 15.6 ns | 51.8 ns | 60.2 ns |
| `192.168.1.1` | 16.7 ns | 55.9 ns | 63.3 ns |
| `127.239.0.1` | 16.9 ns | 55.8 ns | 63.9 ns |
| `127.128.128.255` | 22.3 ns | 70.7 ns | 80.9 ns |
| `224.1.1.1` | 14.4 ns | 47.8 ns | 57.2 ns |
| `2001:db8::1` | 71.6 ns | 80.2 ns | 95.0 ns |
| `0001:0002:0003:0004:0005:0006:0007:0008%12345` | 194 ns | 311 ns | 292 ns |
| `::ffff:172.32.0.0` | 115 ns | 132 ns | 146 ns |
| `2002:ac1d:2d64::1` | 92.3 ns | 116 ns | 129 ns |
| `2001:0000:4136:e378:8000:63bf:3fff:fdd2` | 187 ns | 265 ns | 267 ns |
| `2000::4136:e378:8000:63bf:3fff:fdd2` | 171 ns | 218 ns | 244 ns |
| `2001:db8:0:0:1:0:0:1` | 115 ns | 142 ns | 159 ns |
| `fe80::1ff:fe23:4567:890a%31` | 131 ns | 44973 ns | 47695 ns |
| `127.0.0.1` | 11.7 ns | 38.4 ns | 44.4 ns |
| `192.168.0.1` | 13.9 ns | 45.3 ns | 50.6 ns |
| `0.0.0.0` | 10.0 ns | 30.8 ns | 35.9 ns |
| `100.64.0.0` | 12.6 ns | 40.9 ns | 45.7 ns |
| `192.168.1.1` | 13.7 ns | 47.1 ns | 48.9 ns |
| `127.239.0.1` | 13.4 ns | 43.7 ns | 50.0 ns |
| `127.128.128.255` | 18.0 ns | 56.4 ns | 61.5 ns |
| `224.1.1.1` | 11.5 ns | 38.8 ns | 43.6 ns |
| `2001:db8::1` | 55.4 ns | 69.0 ns | 77.4 ns |
| `0001:0002:0003:0004:0005:0006:0007:0008%12345` | 200 ns | 250 ns | 241 ns |
| `::ffff:172.32.0.0` | 91.2 ns | 107 ns | 125 ns |
| `2002:ac1d:2d64::1` | 77.6 ns | 101 ns | 111 ns |
| `2001:0000:4136:e378:8000:63bf:3fff:fdd2` | 174 ns | 229 ns | 227 ns |
| `2000::4136:e378:8000:63bf:3fff:fdd2` | 158 ns | 184 ns | 192 ns |
| `2001:db8:0:0:1:0:0:1` | 115 ns | 121 ns | 131 ns |
| `fe80::1ff:fe23:4567:890a%31` | 118 ns | 40403 ns | 41033 ns |

</details>

Expand All @@ -110,22 +110,22 @@ CPU Caches: <br>

| input string | ipaddress | socket API | boost asio |
|:----------------------------------------------- | ---------:| ----------:| ----------:|
| `127.0.0.1` | 9.44 ns | 31.8 ns | 219 ns |
| `192.168.0.1` | 11.7 ns | 34.4 ns | 227 ns |
| `0.0.0.0` | 8.07 ns | 26.0 ns | 214 ns |
| `100.64.0.0` | 10.9 ns | 32.0 ns | 226 ns |
| `192.168.1.1` | 12.1 ns | 33.8 ns | 225 ns |
| `127.239.0.1` | 12.5 ns | 34.9 ns | 227 ns |
| `127.128.128.255` | 16.8 ns | 40.5 ns | 235 ns |
| `224.1.1.1` | 10.2 ns | 27.9 ns | 225 ns |
| `2001:db8::1` | 41.8 ns | 91.1 ns | 262 ns |
| `0001:0002:0003:0004:0005:0006:0007:0008%12345` | 125 ns | - | 424 ns |
| `::ffff:172.32.0.0` | 69.4 ns | 135 ns | 300 ns |
| `2002:ac1d:2d64::1` | 57.4 ns | 131 ns | 307 ns |
| `2001:0000:4136:e378:8000:63bf:3fff:fdd2` | 116 ns | 273 ns | 435 ns |
| `2000::4136:e378:8000:63bf:3fff:fdd2` | 101 ns | 214 ns | 338 ns |
| `2001:db8:0:0:1:0:0:1` | 67.7 ns | 169 ns | 321 ns |
| `fe80::1ff:fe23:4567:890a%31` | 71.6 ns | - | 349 ns |
| `127.0.0.1` | 8.57 ns | 29.7 ns | 214 ns |
| `192.168.0.1` | 9.89 ns | 33.9 ns | 217 ns |
| `0.0.0.0` | 8.00 ns | 28.9 ns | 207 ns |
| `100.64.0.0` | 9.57 ns | 32.2 ns | 217 ns |
| `192.168.1.1` | 10.2 ns | 32.3 ns | 221 ns |
| `127.239.0.1` | 10.2 ns | 33.6 ns | 221 ns |
| `127.128.128.255` | 14.6 ns | 38.9 ns | 229 ns |
| `224.1.1.1` | 9.02 ns | 26.9 ns | 215 ns |
| `2001:db8::1` | 38.3 ns | 94.1 ns | 271 ns |
| `0001:0002:0003:0004:0005:0006:0007:0008%12345` | 105 ns | - | 436 ns |
| `::ffff:172.32.0.0` | 61.6 ns | 144 ns | 313 ns |
| `2002:ac1d:2d64::1` | 51.0 ns | 137 ns | 314 ns |
| `2001:0000:4136:e378:8000:63bf:3fff:fdd2` | 104 ns | 275 ns | 448 ns |
| `2000::4136:e378:8000:63bf:3fff:fdd2` | 93.6 ns | 249 ns | 421 ns |
| `2001:db8:0:0:1:0:0:1` | 66.6 ns | 192 ns | 350 ns |
| `fe80::1ff:fe23:4567:890a%31` | 69.6 ns | - | 367 ns |

</details>

Expand Down
2 changes: 1 addition & 1 deletion doc/tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ For working with IP addresses, the library provides three classes:

- **ipv4_address** — A class for working with IPv4 addresses, where the instance size is always 4 bytes.
- **ipv6_address** — A class for working with IPv6 addresses, where the instance size includes both the space allocated for the IPv6 address itself and the scope id (zone index). As a result, the instance size will be 16 bytes plus the maximum length of the scope id (plus aligned bytes if any). Read about scope ids below.
- **ip_address** — Combines the `ipv4_address` and `ipv6_address` classes via a union. This ensures version-independent IP address manipulation. It has implicit constructors for converting from `ipv4_address` and `ipv6_address`. The instance size is the same as that of `ipv6_address`.
- **ip_address** — Combines the `ipv4_address` and `ipv6_address` classes via a union. This ensures version-independent IP address manipulation. It has implicit constructors for converting from `ipv4_address` and `ipv6_address`. The instance size is the same as that of `ipv6_address` plus IP address version (and data alignment).

@parblock
@note Regardless of which class you use, the internal address is stored as an array of bytes, not as an unsigned integer. This design choice ensures that the address is stored in network byte order (big-endian) regardless of the platform. This is convenient because ultimately, this address can be used in sockets or similar libraries that require passing addresses in network byte order.
Expand Down
28 changes: 21 additions & 7 deletions include/ipaddress/base-v4.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class base_v4 {

protected:
template <typename Iter>
IPADDRESS_NODISCARD static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_address_base<Ext> ip_from_string(Iter begin, Iter end, error_code& code, int& index) IPADDRESS_NOEXCEPT {
IPADDRESS_NODISCARD static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_address_base<Ext> ip_from_string(Iter begin, Iter end, error_code& code, uint32_t& index) IPADDRESS_NOEXCEPT {
if (begin == end) {
code = error_code::empty_address;
return {};
Expand All @@ -71,9 +71,15 @@ class base_v4 {

index = 0;
code = error_code::no_error;
Iter it = begin;
uint32_t error_symbol = 0;

for (auto it = begin; it != end; ++it) {
auto c = char(*it);
while (it < end) {
auto c = internal::next_char_or_error(it, end, code, error_symbol);
if (code != error_code::no_error) {
index = error_symbol;
return {};
}
if (index >= 4) {
code = error_code::expected_4_octets;
return {};
Expand Down Expand Up @@ -169,13 +175,21 @@ class base_v4 {
}

template <typename Iter>
IPADDRESS_NODISCARD static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE std::tuple<ip_address_base<Ext>, size_t> parse_netmask(Iter begin, Iter end, error_code& code, int& index) IPADDRESS_NOEXCEPT {
IPADDRESS_NODISCARD static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE std::tuple<ip_address_base<Ext>, size_t> parse_netmask(Iter begin, Iter end, error_code& code, uint32_t& code_value) IPADDRESS_NOEXCEPT {
code = error_code::no_error;
code_value = 0;
Iter it = begin;

size_t prefixlen = 0;
auto is_value = true;
auto has_prefixlen = false;
for (auto it = begin; it != end; ++it) {

while (it < end) {
has_prefixlen = true;
const auto c = char(*it);
const auto c = internal::next_char_or_error(it, end, code, code_value);
if (code != error_code::no_error) {
return std::make_tuple(ip_address_base<Ext>(), 0);
}
if (c >= '0' && c <= '9') {
prefixlen = prefixlen * 10 + (c - '0');
} else {
Expand All @@ -189,7 +203,7 @@ class base_v4 {
return std::make_tuple(ip_address_base<Ext>(), 0);
}
} else {
auto ip = ip_to_uint32(ip_from_string(begin, end, code, index).bytes());
auto ip = ip_to_uint32(ip_from_string(begin, end, code, code_value).bytes());
if (code != error_code::no_error) {
code = error_code::invalid_netmask;
return std::make_tuple(ip_address_base<Ext>(), 0);
Expand Down
Loading

0 comments on commit 824e5d2

Please sign in to comment.