diff --git a/CMakeLists.txt b/CMakeLists.txt
index da8e02f..af8524b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -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)
@@ -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)
diff --git a/doc/benchmark.md b/doc/benchmark.md
index d2a0a24..642acfa 100644
--- a/doc/benchmark.md
+++ b/doc/benchmark.md
@@ -37,26 +37,26 @@ CPU Caches:
L1 Instruction 32 KiB (x8)
L2 Unified 1280 KiB (x8)
L3 Unified 18432 KiB (x1)
-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 |
@@ -72,26 +72,26 @@ CPU Caches:
L1 Instruction 32 KiB
L2 Unified 512 KiB (x4)
L3 Unified 6144 KiB
-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 |
@@ -110,22 +110,22 @@ CPU Caches:
| 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 |
diff --git a/doc/tutorial.md b/doc/tutorial.md
index b0738fb..d794413 100644
--- a/doc/tutorial.md
+++ b/doc/tutorial.md
@@ -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.
diff --git a/include/ipaddress/base-v4.hpp b/include/ipaddress/base-v4.hpp
index 8ddf373..1ba7e46 100644
--- a/include/ipaddress/base-v4.hpp
+++ b/include/ipaddress/base-v4.hpp
@@ -58,7 +58,7 @@ class base_v4 {
protected:
template
- IPADDRESS_NODISCARD static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_address_base 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 ip_from_string(Iter begin, Iter end, error_code& code, uint32_t& index) IPADDRESS_NOEXCEPT {
if (begin == end) {
code = error_code::empty_address;
return {};
@@ -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 {};
@@ -169,13 +175,21 @@ class base_v4 {
}
template
- IPADDRESS_NODISCARD static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE std::tuple, 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, 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(), 0);
+ }
if (c >= '0' && c <= '9') {
prefixlen = prefixlen * 10 + (c - '0');
} else {
@@ -189,7 +203,7 @@ class base_v4 {
return std::make_tuple(ip_address_base(), 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(), 0);
diff --git a/include/ipaddress/base-v6.hpp b/include/ipaddress/base-v6.hpp
index 45f2835..0c06fe4 100644
--- a/include/ipaddress/base-v6.hpp
+++ b/include/ipaddress/base-v6.hpp
@@ -60,38 +60,32 @@ class base_v6 {
static constexpr size_t _max_parts = 8;
template
- IPADDRESS_NODISCARD static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_address_base ip_from_string(Iter begin, Iter end, error_code& code, int& parts_count) IPADDRESS_NOEXCEPT {
+ IPADDRESS_NODISCARD static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_address_base ip_from_string(Iter begin, Iter end, error_code& code, uint32_t& value) IPADDRESS_NOEXCEPT {
if (begin == end) {
code = error_code::empty_address;
return {};
}
- auto ip_and_scope = split_scope_id(begin, end, code);
- end = ip_and_scope.first;
+ auto ip_and_scope = split_scope_id(begin, end, code, value);
if (code != error_code::no_error) {
return {};
}
- const auto parts = split_parts(begin, end, parts_count, code);
+ const auto parts = split_parts(begin, ip_and_scope.end_ip, value, code);
if (code != error_code::no_error) {
return {};
}
- const auto result = get_parts_bound(parts, parts_count, code);
+ const auto result = get_parts_bound(parts, value, code);
if (code != error_code::no_error) {
return {};
}
- auto ip = ip_address_base(parse_parts(parts, parts_count, std::get<0>(result), std::get<1>(result), std::get<2>(result), code));
-
- char scope_id[IPADDRESS_IPV6_SCOPE_MAX_LENGTH + 1] = {};
- for (size_t i = 0; i < ip_and_scope.second.size(); ++i) {
- scope_id[i] = ip_and_scope.second[i];
- }
- ip.set_scope_id(scope_id);
+ auto ip = ip_address_base(parse_parts(parts, value, std::get<0>(result), std::get<1>(result), std::get<2>(result), code));
+ ip.set_scope_id(ip_and_scope.scope_id);
return ip;
}
@@ -224,13 +218,16 @@ class base_v6 {
}
template
- IPADDRESS_NODISCARD static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE std::tuple, size_t> parse_netmask(Iter begin, Iter end, error_code& code, int& index) IPADDRESS_NOEXCEPT {
- index = 0;
+ IPADDRESS_NODISCARD static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE std::tuple, size_t> parse_netmask(Iter begin, Iter end, error_code& code, uint32_t& code_value) IPADDRESS_NOEXCEPT {
size_t prefixlen = 0;
+ auto it = begin;
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(), 0);
+ }
if (c >= '0' && c <= '9') {
prefixlen = prefixlen * 10 + (c - '0');
} else {
@@ -272,38 +269,47 @@ class base_v6 {
private:
template
- IPADDRESS_NODISCARD static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE std::pair> split_scope_id(Iter begin, Iter end, error_code& error) IPADDRESS_NOEXCEPT {
- char scope_id[IPADDRESS_IPV6_SCOPE_MAX_LENGTH + 1] = {};
+ struct ip_and_scope {
+ Iter end_ip;
+ char scope_id[IPADDRESS_IPV6_SCOPE_MAX_LENGTH + 1];
+ };
+
+ template
+ IPADDRESS_NODISCARD static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_and_scope split_scope_id(Iter begin, Iter end, error_code& error, uint32_t& error_value) IPADDRESS_NOEXCEPT {
auto index = 0;
- Iter end_ip = begin;
+ auto it = begin;
auto scope = false;
- for (auto it = begin; it != end; ++it) {
- const auto c = char(*it);
+ ip_and_scope result{};
+ while (it < end) {
+ const auto c = internal::next_char_or_error(it, end, error, error_value);
+ if (error != error_code::no_error) {
+ return result;
+ }
if (!scope && c != '%') {
- end_ip = it + 1;
+ result.end_ip = it;
} else if (scope) {
if (index > IPADDRESS_IPV6_SCOPE_MAX_LENGTH - 1) {
error = error_code::scope_id_is_too_long;
- return std::make_pair(end_ip, make_fixed_string(scope_id));
+ return result;
}
- if (c == '%' || c == '/') {
+ if (c == '%' || c == '/' || uint32_t(c) > 127) {
error = error_code::invalid_scope_id;
- return std::make_pair(end_ip, make_fixed_string(scope_id));
+ return result;
}
- scope_id[index++] = c;
+ result.scope_id[index++] = c;
} else {
scope = true;
}
}
- if (scope && scope_id[0] == '\0') {
+ if (scope && result.scope_id[0] == '\0') {
error = error_code::invalid_scope_id;
- return std::make_pair(end_ip, make_fixed_string(scope_id));
+ return result;
}
- return std::make_pair(end_ip, make_fixed_string(scope_id));
+ return result;
}
template
- IPADDRESS_NODISCARD static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE std::array, _max_parts + 1> split_parts(Iter begin, Iter end, int& parts_count, error_code& error) IPADDRESS_NOEXCEPT {
+ IPADDRESS_NODISCARD static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE std::array, _max_parts + 1> split_parts(Iter begin, Iter end, uint32_t& parts_count, error_code& error) IPADDRESS_NOEXCEPT {
IPADDRESS_CONSTEXPR std::array, _max_parts + 1> empty_parts = {
make_fixed_string("\0\0\0\0"),
make_fixed_string("\0\0\0\0"),
@@ -323,8 +329,15 @@ class base_v6 {
char prev_c = '\0';
bool has_double_colon = false;
- for (auto it = begin; it != end; ++it) {
- auto c = char(*it);
+ Iter it = begin;
+ uint32_t error_symbol = 0;
+
+ while (it < end) {
+ auto c = internal::next_char_or_error(it, end, error, error_symbol);
+ if (error != error_code::no_error) {
+ parts_count = error_symbol;
+ return empty_parts;
+ }
if (!has_double_colon && c == ':' && prev_c == ':') {
has_double_colon = true;
}
diff --git a/include/ipaddress/byte-array.hpp b/include/ipaddress/byte-array.hpp
index a3e65a0..4bae440 100644
--- a/include/ipaddress/byte-array.hpp
+++ b/include/ipaddress/byte-array.hpp
@@ -29,10 +29,10 @@ namespace IPADDRESS_NAMESPACE {
* @remark The purpose of the byte_array class is to provide functionality similar to std::array in .
* environments where std::array cannot be used to its full extent during compile-time operations.
*/
-template
+template
struct byte_array {
using value_type = uint8_t; /**< The type of elements contained in the byte_array. */
- using size_type = std::size_t; /**< The type representing sizes and counts. */
+ using size_type = size_t; /**< The type representing sizes and counts. */
using difference_type = std::ptrdiff_t; /**< The type representing the difference between two pointers. */
using pointer = value_type*; /**< A pointer to an element in the byte_array. */
using const_pointer = const value_type*; /**< A pointer to a constant element in the byte_array. */
@@ -277,7 +277,7 @@ template <>
class byte_array<0> {
public:
using value_type = uint8_t;
- using size_type = std::size_t;
+ using size_type = size_t;
using difference_type = std::ptrdiff_t;
using pointer = value_type*;
using const_pointer = const value_type*;
@@ -390,9 +390,9 @@ class byte_array<0> {
* @retval true the two byte_array objects are equal
* @retval false the two byte_array objects are not equal
*/
-template
+template
IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator==(const byte_array& lhs, const byte_array& rhs) IPADDRESS_NOEXCEPT {
- for (std::size_t i = 0; i < N; ++i) {
+ for (size_t i = 0; i < N; ++i) {
if (lhs[i] != rhs[i]) {
return false;
}
@@ -412,7 +412,7 @@ IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator==(c
* @retval true the two byte_array objects are not equal
* @retval false the two byte_array objects are equal
*/
-template
+template
IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator!=(const byte_array& lhs, const byte_array& rhs) IPADDRESS_NOEXCEPT {
return !(lhs == rhs);
}
@@ -434,9 +434,9 @@ IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator!=(c
* @retval std::strong_ordering::greater if lhs is lexicographically greater than rhs
* @retval std::strong_ordering::equivalent if lhs is lexicographically equal to rhs
*/
- template
+ template
IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE std::strong_ordering operator<=>(const byte_array& lhs, const byte_array& rhs) IPADDRESS_NOEXCEPT {
- for (std::size_t i = 0; i < N; ++i) {
+ for (size_t i = 0; i < N; ++i) {
if (const auto result = lhs[i] <=> rhs[i]; result != std::strong_ordering::equivalent) {
return result;
}
@@ -458,9 +458,9 @@ IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator!=(c
* @param[in] rhs A reference to the right-hand side byte_array object.
* @return `true` if lhs is lexicographically less than rhs, `false` otherwise.
*/
- template
+ template
IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator<(const byte_array& lhs, const byte_array& rhs) IPADDRESS_NOEXCEPT {
- for (std::size_t i = 0; i < N; ++i) {
+ for (size_t i = 0; i < N; ++i) {
if (lhs._data[i] < rhs._data[i]) {
return true;
} else if (lhs._data[i] != rhs._data[i]) {
@@ -478,7 +478,7 @@ IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator!=(c
* @param[in] rhs A reference to the right-hand side byte_array object.
* @return `true` if lhs is lexicographically greater than rhs, `false` otherwise.
*/
- template
+ template
IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator>(const byte_array& lhs, const byte_array& rhs) IPADDRESS_NOEXCEPT {
return rhs < lhs;
}
@@ -491,7 +491,7 @@ IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator!=(c
* @param[in] rhs A reference to the right-hand side byte_array object.
* @return `true` if lhs is lexicographically less than or equal to rhs, `false` otherwise.
*/
- template
+ template
IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator<=(const byte_array& lhs, const byte_array& rhs) IPADDRESS_NOEXCEPT {
return !(rhs < lhs);
}
@@ -504,7 +504,7 @@ IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator!=(c
* @param[in] rhs A reference to the right-hand side byte_array object.
* @return `true` if lhs is lexicographically greater than or equal to rhs, `false` otherwise.
*/
- template
+ template
IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator>=(const byte_array& lhs, const byte_array& rhs) IPADDRESS_NOEXCEPT {
return !(lhs < rhs);
}
diff --git a/include/ipaddress/config.hpp b/include/ipaddress/config.hpp
index a9187a4..5cf5f61 100644
--- a/include/ipaddress/config.hpp
+++ b/include/ipaddress/config.hpp
@@ -25,6 +25,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/include/ipaddress/endian.hpp b/include/ipaddress/endian.hpp
index 10cda95..f1121d4 100644
--- a/include/ipaddress/endian.hpp
+++ b/include/ipaddress/endian.hpp
@@ -17,8 +17,8 @@
* and handling data with different endianness.
*
* The determination of endianness is done with a priority order:
- * 1. User-defined `IPADDRESS_ENDIAN`.
- * 2. C++20's `std::endian`.
+ * 1. C++20's `std::endian`.
+ * 2. User-defined `IPADDRESS_ENDIAN`.
* 3. Platform/compiler-provided macros.
*
* If the endianness cannot be determined, a compilation error is raised
@@ -93,7 +93,7 @@
# define IPADDRESS_ENDIAN IPADDRESS_LITTLE_ENDIAN
# elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64))
# define IPADDRESS_ENDIAN IPADDRESS_LITTLE_ENDIAN
-# else
+# elif !defined(IPADDRESS_HAS_STD_ENDIAN)
# error Unknown endianness detected. Needs to define IPADDRESS_ENDIAN
# endif
#endif
diff --git a/include/ipaddress/errors.hpp b/include/ipaddress/errors.hpp
index af1c6fa..e8e8b25 100644
--- a/include/ipaddress/errors.hpp
+++ b/include/ipaddress/errors.hpp
@@ -86,7 +86,11 @@ enum class error_code {
new_prefix_must_be_shorter, /**< The new prefix length must be shorter for the operation being performed. */
new_prefix_must_be_longer, /**< The new prefix length must be longer for the operation being performed. */
cannot_set_prefixlen_diff_and_new_prefix, /**< Both prefix length difference and new prefix cannot be set simultaneously. */
- not_contained_network /**< The network is not a subnet of the other network as expected. */
+ not_contained_network, /**< The network is not a subnet of the other network as expected. */
+
+ // input string errors
+ unexpected_symbol, /**< The input string contains an unexpected character. */
+ wrong_encoding_sequence /**< Incorrect byte sequence in Unicode encoding. */
};
/**
@@ -149,25 +153,40 @@ class error : public std::runtime_error {
return _code;
}
+ struct symbol {
+ uint32_t value;
+ };
+
private:
template
static std::string concatenate(const Args&... args) {
std::ostringstream ss;
- print(ss, args...);
+ concat(ss, args...);
return ss.str();
}
template
- static void print(std::ostringstream& out, const FirstArg& arg, const Args&... args) {
- out << arg << ' ';
- print(out, args...);
+ static void concat(std::ostringstream& out, const FirstArg& arg, const Args&... args) {
+ print(out, arg) << ' ';
+ concat(out, args...);
}
template
- static void print(std::ostringstream& out, const FirstArg& arg) {
+ static void concat(std::ostringstream& out, const FirstArg& arg) {
+ print(out, arg);
+ }
+
+ template
+ static std::ostringstream& print(std::ostringstream& out, const T& arg) {
out << arg;
+ return out;
}
+ static std::ostringstream& print(std::ostringstream& out, const symbol& arg);
+
+ template
+ static std::ostringstream& print(std::ostringstream& out, const T (&str)[N]);
+
error_code _code;
};
@@ -263,11 +282,11 @@ class logic_error : public error {
* Raises an error with a specific error code and additional context.
*
* This function constructs an error message based on the provided error code,
- * index, and address, then throws a parse_error or a logic_error exception with the constructed message.
+ * value, and address, then throws a parse_error or a logic_error exception with the constructed message.
*
* @tparam T The character type of the address string.
* @param[in] code The error code indicating the type of error encountered.
- * @param[in] index The index at which the error occurred, if applicable.
+ * @param[in] value The value at which the error occurred, if applicable.
* @param[in] address A pointer to the beginning of the address string.
* @param[in] length The length of the address string.
* @throw parse_error Thrown with a message corresponding to the error code.
@@ -278,15 +297,20 @@ template
#ifndef IPADDRESS_NO_EXCEPTIONS
[[noreturn]]
#endif
-IPADDRESS_CONSTEXPR inline void raise_error(error_code code, int index, const T* address, size_t length) {
+IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE void raise_error(error_code code, uint32_t value, const T* address, size_t length) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
#ifndef IPADDRESS_NO_EXCEPTIONS
- char str[101] = {};
+ T str[104] = {};
size_t max_len = length;
if (length > 100) {
max_len = 100;
}
for (size_t i = 0; i < max_len; ++i) {
- str[i] = char(address[i]);
+ str[i] = address[i];
+ }
+ if (length > 100) {
+ str[100] = '.';
+ str[101] = '.';
+ str[102] = '.';
}
switch (code) {
case error_code::empty_address:
@@ -304,25 +328,25 @@ IPADDRESS_CONSTEXPR inline void raise_error(error_code code, int index, const T*
case error_code::string_is_too_long:
throw parse_error(code, "input string is too long", str);
case error_code::empty_octet:
- throw parse_error(code, "empty octet", index, "in address", str);
+ throw parse_error(code, "empty octet", value, "in address", str);
case error_code::expected_4_octets:
throw parse_error(code, "expected 4 octets in", str);
case error_code::leading_0_are_not_permitted:
- throw parse_error(code, "leading zeros are not permitted in octet", index, "of address", str);
+ throw parse_error(code, "leading zeros are not permitted in octet", value, "of address", str);
case error_code::octet_more_3_characters:
- throw parse_error(code, "in octet", index, "of address", str, "more 3 characters");
+ throw parse_error(code, "in octet", value, "of address", str, "more 3 characters");
case error_code::octet_has_invalid_symbol:
- throw parse_error(code, "in octet", index, "of address", str, "has invalid symbol");
+ throw parse_error(code, "in octet", value, "of address", str, "has invalid symbol");
case error_code::octet_exceeded_255:
- throw parse_error(code, "octet", index, "of address", str, "exceeded 255");
+ throw parse_error(code, "octet", value, "of address", str, "exceeded 255");
case error_code::least_3_parts:
throw parse_error(code, "least 3 parts in address", str);
case error_code::most_8_colons_permitted:
throw parse_error(code, "most 8 colons permitted in address", str);
case error_code::part_is_more_4_chars:
- throw parse_error(code, "in part", index, "of address", str, "more 4 characters");
+ throw parse_error(code, "in part", value, "of address", str, "more 4 characters");
case error_code::part_has_invalid_symbol:
- throw parse_error(code, "in part", index, "of address", str, "has invalid symbols");
+ throw parse_error(code, "in part", value, "of address", str, "has invalid symbols");
case error_code::most_one_double_colon_permitted:
throw parse_error(code, "at most one '::' permitted in address", str);
case error_code::leading_colon_only_permitted_as_part_of_double_colon:
@@ -349,6 +373,10 @@ IPADDRESS_CONSTEXPR inline void raise_error(error_code code, int index, const T*
throw logic_error(code, "cannot set prefixlen_diff and new_prefix");
case error_code::not_contained_network:
throw logic_error(code, "network is not a subnet of other");
+ case error_code::unexpected_symbol:
+ throw parse_error(code, "unexpected next unicode symbol", error::symbol { value }, "in string", str);
+ case error_code::wrong_encoding_sequence:
+ throw parse_error(code, "incorrect sequence of bytes in unicode encoding for string", str);
default:
throw error(code, "unknown error");
}
diff --git a/include/ipaddress/fixed-string.hpp b/include/ipaddress/fixed-string.hpp
index e7f8640..a5c09bf 100644
--- a/include/ipaddress/fixed-string.hpp
+++ b/include/ipaddress/fixed-string.hpp
@@ -13,27 +13,10 @@
#define IPADDRESS_FIXED_STRING_HPP
#include "config.hpp"
+#include "unicode.hpp"
namespace IPADDRESS_NAMESPACE {
-namespace internal {
-
-template
-IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE void is_char_type() IPADDRESS_NOEXCEPT {
- static_assert(std::is_same::value
- || std::is_same::value
- || std::is_same::value
- || std::is_same::value
- || std::is_same::value
- || std::is_same::value
- #if __cpp_char8_t >= 201811L
- || std::is_same::value
- #endif // __cpp_char8_t
- , "Only character type supported");
-}
-
-} // namespace IPADDRESS_NAMESPACE::internal
-
/**
* Fixed size string class.
*
@@ -44,6 +27,7 @@ IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE void is_char_type() IPADDRESS_NOEXCEP
*/
template
struct fixed_string {
+ using value_type = char; /**< Type of character in a string. */
using const_pointer = const char*; /**< Type of constant pointer to the string data. */
using const_reference = const char&; /**< Type of constant reference to a character in the string. */
using const_iterator = const_pointer; /**< Type of constant iterator for traversing the string. */
@@ -66,26 +50,46 @@ struct fixed_string {
* Constructs a fixed_string from a character array.
*
* This constructor template initializes a fixed_string with the contents of a given character array.
- * Characters from encodings other than ASCII may be truncated.
*
* @tparam T The character type of the input array.
* @param[in] data The character array to initialize the fixed_string with.
+ * @throw parse_error Thrown if contains unexpected characters for addresses
*/
template
- IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE fixed_string(const T (&data)[N + 1]) IPADDRESS_NOEXCEPT {
- internal::is_char_type();
- auto ended = false;
+ IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE fixed_string(const T (&data)[N + 1]) IPADDRESS_NOEXCEPT(noexcept(internal::char_reader::has_throw())) {
+ const auto begin = &data[0];
+ const auto end = &data[N];
+ auto it = begin;
for (size_t i = 0; i < N; ++i) {
- if (IPADDRESS_IS_CONST_EVALUATED(data) && data[i] > 127) {
- const size_t err = data[i] / (data[i] - data[i]); // NOLINT(misc-redundant-expression): invalid symbol for ip address
+ _data[i] = internal::next_char(it, begin, end);
+ if (_data[i] == '\0') {
+ break;
}
- _data[i] = char(data[i]);
- if (data[i] == '\0') {
- ended = true;
- }
- if (!ended) {
- ++length;
+ ++length;
+ }
+ }
+
+ /**
+ * Constructs a fixed_string from a character array.
+ *
+ * This constructor template initializes a fixed_string with the contents of a given character array.
+ *
+ * @tparam T The character type of the input array.
+ * @param[in] data The character array to initialize the fixed_string with.
+ * @param[out] code A reference to an `error_code` object that will be set if an error occurs during parsing.
+ */
+ template
+ IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE fixed_string(const T (&data)[N + 1], error_code& code) IPADDRESS_NOEXCEPT {
+ const auto begin = &data[0];
+ const auto end = &data[N];
+ auto it = begin;
+ uint32_t error_symbol = 0;
+ for (size_t i = 0; i < N; ++i) {
+ _data[i] = internal::next_char_or_error(it, end, code, error_symbol);
+ if (_data[i] == '\0' || code != error_code::no_error) {
+ break;
}
+ ++length;
}
}
@@ -382,6 +386,7 @@ struct fixed_string {
template <>
struct fixed_string<0> {
+ using value_type = char;
using const_pointer = const char*;
using const_reference = const char&;
using const_iterator = const_pointer;
@@ -405,9 +410,29 @@ struct fixed_string<0> {
IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE fixed_string(const char32_t*) IPADDRESS_NOEXCEPT {
}
+ IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE fixed_string(const char*, error_code& code) IPADDRESS_NOEXCEPT {
+ code = error_code::no_error;
+ }
+
+ IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE fixed_string(const wchar_t*, error_code& code) IPADDRESS_NOEXCEPT {
+ code = error_code::no_error;
+ }
+
+ IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE fixed_string(const char16_t*, error_code& code) IPADDRESS_NOEXCEPT {
+ code = error_code::no_error;
+ }
+
+ IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE fixed_string(const char32_t*, error_code& code) IPADDRESS_NOEXCEPT {
+ code = error_code::no_error;
+ }
+
#if __cpp_char8_t >= 201811L
IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE fixed_string(const char8_t*) IPADDRESS_NOEXCEPT {
}
+
+ IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE fixed_string(const char8_t*, error_code& code) IPADDRESS_NOEXCEPT {
+ code = error_code::no_error;
+ }
#endif // __cpp_char8_t
IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE const_iterator begin() const IPADDRESS_NOEXCEPT {
@@ -618,75 +643,32 @@ IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator!=(c
*
* Constructs a fixed_string object from a character array, deducing the size automatically.
*
+ * @tparam T The character type of the input array.
* @tparam N The size of the character array plus one for the null terminator.
* @param[in] data The character array to initialize the fixed_string with.
* @return A fixed_string object of size N-1.
*/
-template
-IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE fixed_string make_fixed_string(const char(&data)[N]) IPADDRESS_NOEXCEPT {
+template
+IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE fixed_string make_fixed_string(const T(&data)[N]) IPADDRESS_NOEXCEPT(noexcept(fixed_string(data))) {
return fixed_string(data);
}
/**
- * Creates a fixed-length string from a wide character array.
- *
- * Constructs a fixed_string object from a wide character array, deducing the size automatically.
- *
- * @tparam N The size of the wide character array plus one for the null terminator.
- * @param[in] data The wide character array to initialize the fixed_string with.
- * @return A fixed_string object of size N-1.
- */
-template
-IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE fixed_string make_fixed_string(const wchar_t(&data)[N]) IPADDRESS_NOEXCEPT {
- return fixed_string(data);
-}
-
-/**
- * Creates a fixed-length string from a UTF-16 character array.
- *
- * Constructs a fixed_string object from a UTF-16 character array, deducing the size automatically.
- *
- * @tparam N The size of the UTF-16 character array plus one for the null terminator.
- * @param[in] data The UTF-16 character array to initialize the fixed_string with.
- * @return A fixed_string object of size N-1.
- */
-template
-IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE fixed_string make_fixed_string(const char16_t(&data)[N]) IPADDRESS_NOEXCEPT {
- return fixed_string(data);
-}
-
-/**
- * Creates a fixed-length string from a UTF-32 character array.
- *
- * Constructs a fixed_string object from a UTF-32 character array, deducing the size automatically.
- *
- * @tparam N The size of the UTF-32 character array plus one for the null terminator.
- * @param[in] data The UTF-32 character array to initialize the fixed_string with.
- * @return A fixed_string object of size N-1.
- */
-template
-IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE fixed_string make_fixed_string(const char32_t(&data)[N]) IPADDRESS_NOEXCEPT {
- return fixed_string(data);
-}
-
-#if __cpp_char8_t >= 201811L
-
-/**
- * Creates a fixed-length string from a UTF-8 character array.
+ * Creates a fixed-length string from a character array.
*
- * Constructs a fixed_string object from a UTF-8 character array, deducing the size automatically.
+ * Constructs a fixed_string object from a character array, deducing the size automatically.
*
- * @tparam N The size of the UTF-8 character array plus one for the null terminator.
- * @param[in] data The UTF-8 character array to initialize the fixed_string with.
+ * @tparam T The character type of the input array.
+ * @tparam N The size of the character array plus one for the null terminator.
+ * @param[in] data The character array to initialize the fixed_string with.
+ * @param[out] code A reference to an `error_code` object that will be set if an error occurs during parsing.
* @return A fixed_string object of size N-1.
*/
-template
-IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE fixed_string make_fixed_string(const char8_t(&data)[N]) IPADDRESS_NOEXCEPT {
- return fixed_string(data);
+template
+IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE fixed_string make_fixed_string(const T(&data)[N], error_code& code) IPADDRESS_NOEXCEPT {
+ return fixed_string(data, code);
}
-#endif // __cpp_char8_t
-
#if IPADDRESS_CPP_VERSION >= 17
#if __cpp_char8_t >= 201811L
diff --git a/include/ipaddress/hash.hpp b/include/ipaddress/hash.hpp
index c2dfd5b..f92dc3e 100644
--- a/include/ipaddress/hash.hpp
+++ b/include/ipaddress/hash.hpp
@@ -23,46 +23,46 @@ namespace IPADDRESS_NAMESPACE {
namespace internal {
-template
+template
struct hash_combine;
template <>
struct hash_combine<4> {
- IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE std::size_t operator()(std::uint32_t value) const IPADDRESS_NOEXCEPT {
+ IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE size_t operator()(uint32_t value) const IPADDRESS_NOEXCEPT {
value ^= value >> 16;
value *= 0x21f0aaad;
value ^= value >> 15;
value *= 0x735a2d97;
value ^= value >> 15;
- return std::size_t(value);
+ return size_t(value);
}
};
template <>
struct hash_combine<8> {
- IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE std::size_t operator()(std::uint64_t value) const IPADDRESS_NOEXCEPT {
+ IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE size_t operator()(uint64_t value) const IPADDRESS_NOEXCEPT {
value ^= value >> 32;
value *= 0xe9846af9b1a615d;
value ^= value >> 32;
value *= 0xe9846af9b1a615d;
value ^= value >> 28;
- return std::size_t(value);
+ return size_t(value);
}
};
-IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE std::size_t hash_sum(std::size_t seed, std::size_t value) IPADDRESS_NOEXCEPT {
- const hash_combine hash{};
+IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE size_t hash_sum(size_t seed, size_t value) IPADDRESS_NOEXCEPT {
+ const hash_combine hash{};
return hash(seed + 0x9e3779b9 + value);
}
template
-IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE std::size_t calc_hash(std::size_t seed, Arg arg) IPADDRESS_NOEXCEPT {
+IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE size_t calc_hash(size_t seed, Arg arg) IPADDRESS_NOEXCEPT {
return hash_sum(seed, arg);
}
template
-IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE std::size_t calc_hash(std::size_t seed, Arg arg, Args... args) IPADDRESS_NOEXCEPT {
- seed = hash_sum(seed, std::size_t(arg));
+IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE size_t calc_hash(size_t seed, Arg arg, Args... args) IPADDRESS_NOEXCEPT {
+ seed = hash_sum(seed, size_t(arg));
return calc_hash(seed, args...);
}
diff --git a/include/ipaddress/ip-address-base.hpp b/include/ipaddress/ip-address-base.hpp
index 3f99d33..74ecce5 100644
--- a/include/ipaddress/ip-address-base.hpp
+++ b/include/ipaddress/ip-address-base.hpp
@@ -123,10 +123,10 @@ class ip_address_base : public Base {
IPADDRESS_NODISCARD static IPADDRESS_CONSTEVAL IPADDRESS_FORCE_INLINE ip_address_base parse() IPADDRESS_NOEXCEPT {
constexpr auto str = FixedString;
auto code = error_code::no_error;
- auto index = 0;
- auto result = Base::ip_from_string(str.begin(), str.end(), code, index);
+ uint32_t value = 0;
+ auto result = Base::ip_from_string(str.begin(), str.end(), code, value);
if (code != error_code::no_error) {
- raise_error(code, index, str.data(), str.size());
+ raise_error(code, value, str.data(), str.size());
}
return ip_address_base(result);
}
@@ -401,7 +401,6 @@ class ip_address_base : public Base {
*/
template
IPADDRESS_NODISCARD_WHEN_NO_EXCEPTIONS static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_address_base parse(const T(&address)[N]) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
- internal::is_char_type();
auto str = make_fixed_string(address);
return parse_string(str);
}
@@ -420,9 +419,8 @@ class ip_address_base : public Base {
*/
template
static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_address_base parse(const T(&address)[N], error_code& code) IPADDRESS_NOEXCEPT {
- internal::is_char_type();
- auto str = make_fixed_string(address);
- return parse_string(str, code);
+ auto str = make_fixed_string(address, code);
+ return code == error_code::no_error ? parse_string(str, code) : ip_address_base{};
}
/**
@@ -524,6 +522,66 @@ class ip_address_base : public Base {
return std::string(res, len);
}
+ /**
+ * Converts the IP address to a string representation.
+ *
+ * The function converts the binary representation of the IP address to a string.
+ * The format of the output string can be adjusted by passing the desired format as an argument.
+ * The default format is 'compressed'.
+ *
+ * @param[in] fmt The format to use for the string representation. Defaults to `format::compressed`.
+ * @return A `std::wstring` representing the IP address in the specified format.
+ */
+ IPADDRESS_NODISCARD IPADDRESS_FORCE_INLINE std::wstring to_wstring(format fmt = format::compressed) const {
+ return internal::string_converter::convert(to_string(fmt));
+ }
+
+ /**
+ * Converts the IP address to a string representation.
+ *
+ * The function converts the binary representation of the IP address to a string.
+ * The format of the output string can be adjusted by passing the desired format as an argument.
+ * The default format is 'compressed'.
+ *
+ * @param[in] fmt The format to use for the string representation. Defaults to `format::compressed`.
+ * @return A `std::u16string` representing the IP address in the specified format.
+ */
+ IPADDRESS_NODISCARD IPADDRESS_FORCE_INLINE std::u16string to_u16string(format fmt = format::compressed) const {
+ return internal::string_converter::convert(to_string(fmt));
+ }
+
+ /**
+ * Converts the IP address to a string representation.
+ *
+ * The function converts the binary representation of the IP address to a string.
+ * The format of the output string can be adjusted by passing the desired format as an argument.
+ * The default format is 'compressed'.
+ *
+ * @param[in] fmt The format to use for the string representation. Defaults to `format::compressed`.
+ * @return A `std::u32string` representing the IP address in the specified format.
+ */
+ IPADDRESS_NODISCARD IPADDRESS_FORCE_INLINE std::u32string to_u32string(format fmt = format::compressed) const {
+ return internal::string_converter::convert(to_string(fmt));
+ }
+
+#if __cpp_char8_t >= 201811L
+
+ /**
+ * Converts the IP address to a string representation.
+ *
+ * The function converts the binary representation of the IP address to a string.
+ * The format of the output string can be adjusted by passing the desired format as an argument.
+ * The default format is 'compressed'.
+ *
+ * @param[in] fmt The format to use for the string representation. Defaults to `format::compressed`.
+ * @return A `std::u8string` representing the IP address in the specified format.
+ */
+ IPADDRESS_NODISCARD IPADDRESS_FORCE_INLINE std::u8string to_u8string(format fmt = format::compressed) const {
+ return internal::string_converter::convert(to_string(fmt));
+ }
+
+#endif // __cpp_char8_t
+
/**
* Swaps the contents of this IP address with another IP address.
*
@@ -587,10 +645,12 @@ class ip_address_base : public Base {
*
* This operator allows the IP address to be converted to a string.
*
- * @return A `std::string` representation of the IP address.
+ * @tparam T The character type of the string.
+ * @return A string representation of the IP address.
*/
- IPADDRESS_NODISCARD IPADDRESS_FORCE_INLINE explicit operator std::string() const {
- return to_string();
+ template
+ IPADDRESS_NODISCARD IPADDRESS_FORCE_INLINE explicit operator std::basic_string, std::allocator>() const {
+ return internal::string_converter::convert(to_string());
}
/**
@@ -694,10 +754,10 @@ class ip_address_base : public Base {
template
IPADDRESS_NODISCARD static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_address_base parse_string(const Str& address) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
auto code = error_code::no_error;
- auto index = 0;
- auto result = Base::ip_from_string(address.begin(), address.end(), code, index);
+ uint32_t value = 0;
+ auto result = Base::ip_from_string(address.data(), address.data() + address.size(), code, value);
if (code != error_code::no_error) {
- raise_error(code, index, address.data(), address.size());
+ raise_error(code, value, address.data(), address.size());
}
return result;
}
@@ -705,8 +765,8 @@ class ip_address_base : public Base {
template
static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_address_base parse_string(const Str& address, error_code& code) IPADDRESS_NOEXCEPT {
code = error_code::no_error;
- auto index = 0;
- return Base::ip_from_string(address.begin(), address.end(), code, index);
+ uint32_t value = 0;
+ return Base::ip_from_string(address.data(), address.data() + address.size(), code, value);
}
};
@@ -715,7 +775,7 @@ class ip_address_base : public Base {
namespace internal {
template
-IPADDRESS_NODISCARD_WHEN_NO_EXCEPTIONS IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_address_base parse_ip_from_literal(const TChar* address, std::size_t size) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
+IPADDRESS_NODISCARD_WHEN_NO_EXCEPTIONS IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_address_base parse_ip_from_literal(const TChar* address, size_t size) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
if (size > MaxLen) {
raise_error(error_code::string_is_too_long, 0, address, size);
}
@@ -737,17 +797,20 @@ IPADDRESS_NODISCARD IPADDRESS_FORCE_INLINE int stream_index() {
return i;
}
-IPADDRESS_FORCE_INLINE std::ostream& full(std::ostream& stream) {
+template
+IPADDRESS_FORCE_INLINE std::basic_ostream>& full(std::basic_ostream>& stream) {
stream.iword(stream_index()) = long(format::full) + 1;
return stream;
}
-IPADDRESS_FORCE_INLINE std::ostream& compact(std::ostream& stream) {
+template
+IPADDRESS_FORCE_INLINE std::basic_ostream>& compact(std::basic_ostream>& stream) {
stream.iword(stream_index()) = long(format::compact) + 1;
return stream;
}
-IPADDRESS_FORCE_INLINE std::ostream& compressed(std::ostream& stream) {
+template
+IPADDRESS_FORCE_INLINE std::basic_ostream>& compressed(std::basic_ostream>& stream) {
stream.iword(stream_index()) = long(format::compressed) + 1;
return stream;
}
@@ -762,7 +825,7 @@ namespace std {
template
struct hash> {
- IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE std::size_t operator()(const IPADDRESS_NAMESPACE::ip_address_base& ip) const IPADDRESS_NOEXCEPT {
+ IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE size_t operator()(const IPADDRESS_NAMESPACE::ip_address_base& ip) const IPADDRESS_NOEXCEPT {
return ip.hash();
}
};
@@ -778,7 +841,12 @@ IPADDRESS_NODISCARD IPADDRESS_FORCE_INLINE std::string to_string(const IPADDRESS
}
template
-IPADDRESS_FORCE_INLINE std::ostream& operator<<(std::ostream& stream, const IPADDRESS_NAMESPACE::ip_address_base& ip) {
+IPADDRESS_NODISCARD IPADDRESS_FORCE_INLINE std::wstring to_wstring(const IPADDRESS_NAMESPACE::ip_address_base& ip) {
+ return ip.to_wstring();
+}
+
+template
+IPADDRESS_FORCE_INLINE std::basic_ostream>& operator<<(std::basic_ostream>& stream, const IPADDRESS_NAMESPACE::ip_address_base& ip) {
auto& iword = stream.iword(IPADDRESS_NAMESPACE::stream_index());
auto fmt = iword
? (IPADDRESS_NAMESPACE::format) (iword - 1)
@@ -791,12 +859,12 @@ IPADDRESS_FORCE_INLINE std::ostream& operator<<(std::ostream& stream, const IPAD
return std::toupper(c);
});
}
- return stream << str;
+ return stream << IPADDRESS_NAMESPACE::internal::string_converter::convert(str);
}
-template
-IPADDRESS_FORCE_INLINE std::istream& operator>>(std::istream& stream, IPADDRESS_NAMESPACE::ip_address_base& ip) {
- std::string str;
+template
+IPADDRESS_FORCE_INLINE std::basic_istream>& operator>>(std::basic_istream>& stream, IPADDRESS_NAMESPACE::ip_address_base& ip) {
+ std::basic_string, std::allocator> str;
stream >> str;
IPADDRESS_NAMESPACE::error_code err = IPADDRESS_NAMESPACE::error_code::no_error;
ip = IPADDRESS_NAMESPACE::ip_address_base::parse(str, err);
diff --git a/include/ipaddress/ip-address-iterator.hpp b/include/ipaddress/ip-address-iterator.hpp
index f895a49..a1a5e81 100644
--- a/include/ipaddress/ip-address-iterator.hpp
+++ b/include/ipaddress/ip-address-iterator.hpp
@@ -38,7 +38,7 @@ class ip_reverse_iterator {
using iterator_concept = std::random_access_iterator_tag; /**< The iterator concept, defined if concepts are available. */
#endif
using iterator_category = typename std::iterator_traits::iterator_category; /**< The category of the iterator. */
- using iterator_type = Iterator; /**< The underlying iterator type. */
+ using iterator_type = Iterator; /**< The underlying iterator type. */
using value_type = typename std::iterator_traits::value_type; /**< The type of the values iterated over. */
using difference_type = typename std::iterator_traits::difference_type; /**< The type representing the difference between two iterators. */
using pointer = typename std::iterator_traits::pointer; /**< The pointer type of the iterated values. */
@@ -426,7 +426,7 @@ class ip_address_iterator> {
#endif
using iterator_category = std::random_access_iterator_tag; /**< The category of the iterator. */
using value_type = ip_address_base; /**< The type of the values iterated over. */
- using difference_type = std::int64_t; /**< The type representing the difference between two iterators. */
+ using difference_type = int64_t; /**< The type representing the difference between two iterators. */
using pointer = const value_type*; /**< The pointer type of the iterated values. */
using reference = const value_type&; /**< The reference type of the iterated values. */
@@ -868,7 +868,7 @@ template
class hosts_sequence> {
public:
using value_type = ip_address_base; /**< The type of the IP addresses in the sequence. */
- using size_type = std::size_t; /**< The type used for representing the size of the sequence. */
+ using size_type = size_t; /**< The type used for representing the size of the sequence. */
using difference_type = typename value_type::uint_type; /**< The type used for representing differences between iterators. */
using pointer = value_type*; /**< The pointer type for the value_type. */
using const_pointer = const value_type*; /**< The const pointer type for the value_type. */
diff --git a/include/ipaddress/ip-any-address.hpp b/include/ipaddress/ip-any-address.hpp
index b0867db..5c15637 100644
--- a/include/ipaddress/ip-any-address.hpp
+++ b/include/ipaddress/ip-any-address.hpp
@@ -27,9 +27,6 @@ namespace IPADDRESS_NAMESPACE {
namespace internal {
-// Parsing has been removed from the ip_address class due to a bug
-// in the Clang compiler in version 14 and below
-// https://bugs.llvm.org/show_bug.cgi?id=18781
template
struct ip_any_parser {
template
@@ -452,6 +449,58 @@ class ip_address {
return _version == ip_version::V4 ? _ipv.ipv4.to_string(fmt) : _ipv.ipv6.to_string(fmt);
}
+ /**
+ * Converts the IP address to a string.
+ *
+ * This function returns a string representation of the IP address. The format can be specified by the \a fmt parameter.
+ *
+ * @param[in] fmt The format to use for the string representation, defaults to compressed format.
+ * @return A `std::wstring` representing the IP address in the specified format.
+ */
+ IPADDRESS_NODISCARD IPADDRESS_FORCE_INLINE std::wstring to_wstring(format fmt = format::compressed) const {
+ return _version == ip_version::V4 ? _ipv.ipv4.to_wstring(fmt) : _ipv.ipv6.to_wstring(fmt);
+ }
+
+ /**
+ * Converts the IP address to a string.
+ *
+ * This function returns a string representation of the IP address. The format can be specified by the \a fmt parameter.
+ *
+ * @param[in] fmt The format to use for the string representation, defaults to compressed format.
+ * @return A `std::u16string` representing the IP address in the specified format.
+ */
+ IPADDRESS_NODISCARD IPADDRESS_FORCE_INLINE std::u16string to_u16string(format fmt = format::compressed) const {
+ return _version == ip_version::V4 ? _ipv.ipv4.to_u16string(fmt) : _ipv.ipv6.to_u16string(fmt);
+ }
+
+ /**
+ * Converts the IP address to a string.
+ *
+ * This function returns a string representation of the IP address. The format can be specified by the \a fmt parameter.
+ *
+ * @param[in] fmt The format to use for the string representation, defaults to compressed format.
+ * @return A `std::u32string` representing the IP address in the specified format.
+ */
+ IPADDRESS_NODISCARD IPADDRESS_FORCE_INLINE std::u32string to_u32string(format fmt = format::compressed) const {
+ return _version == ip_version::V4 ? _ipv.ipv4.to_u32string(fmt) : _ipv.ipv6.to_u32string(fmt);
+ }
+
+#if __cpp_char8_t >= 201811L
+
+ /**
+ * Converts the IP address to a string.
+ *
+ * This function returns a string representation of the IP address. The format can be specified by the \a fmt parameter.
+ *
+ * @param[in] fmt The format to use for the string representation, defaults to compressed format.
+ * @return A `std::u8string` representing the IP address in the specified format.
+ */
+ IPADDRESS_NODISCARD IPADDRESS_FORCE_INLINE std::u8string to_u8string(format fmt = format::compressed) const {
+ return _version == ip_version::V4 ? _ipv.ipv4.to_u8string(fmt) : _ipv.ipv6.to_u8string(fmt);
+ }
+
+#endif // __cpp_char8_t
+
/**
* Generates a reverse DNS lookup pointer for the IP address.
*
@@ -1094,7 +1143,6 @@ class ip_address {
*/
template
IPADDRESS_NODISCARD_WHEN_NO_EXCEPTIONS static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_address parse(const T(&address)[N]) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
- internal::is_char_type();
auto code = error_code::no_error;
auto result = internal::ip_any_parser::parse(address, code);
if (code != error_code::no_error) {
@@ -1117,7 +1165,6 @@ class ip_address {
*/
template
static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_address parse(const T(&address)[N], error_code& code) IPADDRESS_NOEXCEPT {
- internal::is_char_type();
return internal::ip_any_parser::parse(address, code);
}
@@ -1133,8 +1180,7 @@ class ip_address {
* @remark If scope is disabled in settings (`IPADDRESS_IPV6_SCOPE_MAX_LENGTH == 0`) then this call will have no effect.
*/
template
- IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE void set_scope_id(const T(&scope_id)[N]) IPADDRESS_NOEXCEPT {
- internal::is_char_type();
+ IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE void set_scope_id(const T(&scope_id)[N]) IPADDRESS_NOEXCEPT(noexcept(ipv6_address().set_scope_id(scope_id))) {
if (_version == ip_version::V6) {
_ipv.ipv6.set_scope_id(scope_id);
}
@@ -1187,10 +1233,12 @@ class ip_address {
*
* This operator allows the IP address to be converted to a string.
*
+ * @tparam T The character type of the string.
* @return A `std::string` representation of the IP address.
*/
- IPADDRESS_NODISCARD IPADDRESS_FORCE_INLINE explicit operator std::string() const {
- return _version == ip_version::V4 ? _ipv.ipv4.to_string() : _ipv.ipv6.to_string();
+ template
+ IPADDRESS_NODISCARD IPADDRESS_FORCE_INLINE explicit operator std::basic_string, std::allocator>() const {
+ return internal::string_converter::convert(to_string());
}
/**
@@ -1297,35 +1345,6 @@ class ip_address {
#endif // !IPADDRESS_HAS_SPACESHIP_OPERATOR
private:
- // not used due to clang bug in version 14 and below
- // https://bugs.llvm.org/show_bug.cgi?id=18781
- //
- // template
- // IPADDRESS_NODISCARD_WHEN_NO_EXCEPTIONS static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_address parse_string(const Str& address) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
- // auto code = error_code::no_error;
- // const auto ipv4 = ipv4_address::parse(address, code);
- // if (code == error_code::no_error) {
- // return ip_address(ipv4);
- // }
- // return ip_address(ipv6_address::parse(address));
- // }
- //
- // template
- // static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_address parse_string(const Str& address, error_code& code) IPADDRESS_NOEXCEPT {
- // code = error_code::no_error;
- // const auto ipv4 = ipv4_address::parse(address, code);
- // if (code == error_code::no_error) {
- // return ip_address(ipv4);
- // }
- //
- // const auto ipv6 = ipv6_address::parse(address, code);
- // if (code == error_code::no_error) {
- // return ip_address(ipv6);
- // }
- //
- // return ip_address();
- // }
-
union ip_any_address {
IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_any_address() IPADDRESS_NOEXCEPT : ipv4() {
}
@@ -1370,7 +1389,7 @@ class ip_address {
* @param[in] size The size of the character array.
* @return An ip_address object parsed from the string literal.
*/
- IPADDRESS_NODISCARD_WHEN_NO_EXCEPTIONS IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_address operator""_ip(const char* address, std::size_t size) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
+ IPADDRESS_NODISCARD_WHEN_NO_EXCEPTIONS IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_address operator""_ip(const char* address, size_t size) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
if (size > ipv6_address::base_max_string_len) {
raise_error(error_code::string_is_too_long, 0, address, size);
}
@@ -1388,7 +1407,7 @@ class ip_address {
* @param[in] size The size of the character array.
* @return An ip_address object parsed from the string literal.
*/
- IPADDRESS_NODISCARD_WHEN_NO_EXCEPTIONS IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_address operator""_ip(const wchar_t* address, std::size_t size) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
+ IPADDRESS_NODISCARD_WHEN_NO_EXCEPTIONS IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_address operator""_ip(const wchar_t* address, size_t size) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
if (size > ipv6_address::base_max_string_len) {
raise_error(error_code::string_is_too_long, 0, address, size);
}
@@ -1406,7 +1425,7 @@ class ip_address {
* @param[in] size The size of the character array.
* @return An ip_address object parsed from the string literal.
*/
- IPADDRESS_NODISCARD_WHEN_NO_EXCEPTIONS IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_address operator""_ip(const char16_t* address, std::size_t size) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
+ IPADDRESS_NODISCARD_WHEN_NO_EXCEPTIONS IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_address operator""_ip(const char16_t* address, size_t size) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
if (size > ipv6_address::base_max_string_len) {
raise_error(error_code::string_is_too_long, 0, address, size);
}
@@ -1424,7 +1443,7 @@ class ip_address {
* @param[in] size The size of the character array.
* @return An ip_address object parsed from the string literal.
*/
- IPADDRESS_NODISCARD_WHEN_NO_EXCEPTIONS IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_address operator""_ip(const char32_t* address, std::size_t size) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
+ IPADDRESS_NODISCARD_WHEN_NO_EXCEPTIONS IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_address operator""_ip(const char32_t* address, size_t size) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
if (size > ipv6_address::base_max_string_len) {
raise_error(error_code::string_is_too_long, 0, address, size);
}
@@ -1445,7 +1464,7 @@ namespace std {
template <>
struct hash {
- IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE std::size_t operator()(const IPADDRESS_NAMESPACE::ip_address& ip) const IPADDRESS_NOEXCEPT {
+ IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE size_t operator()(const IPADDRESS_NAMESPACE::ip_address& ip) const IPADDRESS_NOEXCEPT {
return ip.hash();
}
};
@@ -1458,7 +1477,12 @@ IPADDRESS_NODISCARD IPADDRESS_FORCE_INLINE std::string to_string(const IPADDRESS
return ip.to_string();
}
-IPADDRESS_FORCE_INLINE std::ostream& operator<<(std::ostream& stream, const IPADDRESS_NAMESPACE::ip_address& ip) {
+IPADDRESS_NODISCARD IPADDRESS_FORCE_INLINE std::wstring to_wstring(const IPADDRESS_NAMESPACE::ip_address& ip) {
+ return ip.to_wstring();
+}
+
+template
+IPADDRESS_FORCE_INLINE std::basic_ostream>& operator<<(std::basic_ostream>& stream, const IPADDRESS_NAMESPACE::ip_address& ip) {
auto& iword = stream.iword(IPADDRESS_NAMESPACE::stream_index());
auto fmt = iword
? (IPADDRESS_NAMESPACE::format) (iword - 1)
@@ -1471,11 +1495,12 @@ IPADDRESS_FORCE_INLINE std::ostream& operator<<(std::ostream& stream, const IPAD
return std::toupper(c);
});
}
- return stream << str;
+ return stream << IPADDRESS_NAMESPACE::internal::string_converter::convert(str);
}
-IPADDRESS_FORCE_INLINE std::istream& operator>>(std::istream& stream, IPADDRESS_NAMESPACE::ip_address& ip) {
- std::string str;
+template
+IPADDRESS_FORCE_INLINE std::basic_istream>& operator>>(std::basic_istream>& stream, IPADDRESS_NAMESPACE::ip_address& ip) {
+ std::basic_string, std::allocator> str;
stream >> str;
IPADDRESS_NAMESPACE::error_code err = IPADDRESS_NAMESPACE::error_code::no_error;
ip = IPADDRESS_NAMESPACE::ip_address::parse(str, err);
diff --git a/include/ipaddress/ip-any-iterator.hpp b/include/ipaddress/ip-any-iterator.hpp
index 13a17fb..7ceb482 100644
--- a/include/ipaddress/ip-any-iterator.hpp
+++ b/include/ipaddress/ip-any-iterator.hpp
@@ -48,7 +48,7 @@ class ip_any_iterator {
#endif
using iterator_category = std::random_access_iterator_tag; /**< Iterator category. */
using value_type = T; /**< Value type iterated over. */
- using difference_type = std::int64_t; /**< Difference type between iterators. */
+ using difference_type = int64_t; /**< Difference type between iterators. */
using pointer = const value_type*; /**< Pointer to value type. */
using reference = const value_type&; /**< Reference to value type. */
@@ -482,7 +482,7 @@ class ip_any_iterator {
class hosts_any_sequence {
public:
using value_type = ip_address; /**< The type of the IP addresses in the sequence. */
- using size_type = std::size_t; /**< The type used for representing the size of the sequence. */
+ using size_type = size_t; /**< The type used for representing the size of the sequence. */
using difference_type = uint128_t; /**< The type used for representing differences between iterators. */
using pointer = value_type*; /**< The pointer type for the value_type. */
using const_pointer = const value_type*; /**< The const pointer type for the value_type. */
@@ -661,7 +661,7 @@ template
class subnets_any_sequence {
public:
using value_type = T; /**< The type of subnet value. */
- using size_type = std::size_t; /**< An unsigned integral type. */
+ using size_type = size_t; /**< An unsigned integral type. */
using difference_type = uint128_t; /**< Unsigned integer type for differences. */
using pointer = value_type*; /**< Pointer to the subnet type. */
using const_pointer = const value_type*; /**< Const pointer to the subnet type. */
diff --git a/include/ipaddress/ip-any-network.hpp b/include/ipaddress/ip-any-network.hpp
index 38af7de..90e18d6 100644
--- a/include/ipaddress/ip-any-network.hpp
+++ b/include/ipaddress/ip-any-network.hpp
@@ -29,9 +29,6 @@ namespace IPADDRESS_NAMESPACE {
namespace internal {
-// Parsing has been removed from the ip_network class due to a bug
-// in the Clang compiler in version 14 and below
-// https://bugs.llvm.org/show_bug.cgi?id=18781
template
struct net_any_parser {
template
@@ -786,6 +783,62 @@ class ip_network {
return is_v4() ? _ipv_net.ipv4.to_string(fmt) : _ipv_net.ipv6.to_string(fmt);
}
+ /**
+ * Converts the network to a string representation.
+ *
+ * This method returns a string representation of the network, combining the network address
+ * and the prefix length, formatted according to the specified format.
+ *
+ * @param[in] fmt The format to use for the string representation. *Defaults to format::compressed*.
+ * @return A string representation of the network.
+ */
+ IPADDRESS_NODISCARD IPADDRESS_FORCE_INLINE std::wstring to_wstring(format fmt = format::compressed) const {
+ return is_v4() ? _ipv_net.ipv4.to_wstring(fmt) : _ipv_net.ipv6.to_wstring(fmt);
+ }
+
+ /**
+ * Converts the network to a string representation.
+ *
+ * This method returns a string representation of the network, combining the network address
+ * and the prefix length, formatted according to the specified format.
+ *
+ * @param[in] fmt The format to use for the string representation. *Defaults to format::compressed*.
+ * @return A string representation of the network.
+ */
+ IPADDRESS_NODISCARD IPADDRESS_FORCE_INLINE std::u16string to_u16string(format fmt = format::compressed) const {
+ return is_v4() ? _ipv_net.ipv4.to_u16string(fmt) : _ipv_net.ipv6.to_u16string(fmt);
+ }
+
+ /**
+ * Converts the network to a string representation.
+ *
+ * This method returns a string representation of the network, combining the network address
+ * and the prefix length, formatted according to the specified format.
+ *
+ * @param[in] fmt The format to use for the string representation. *Defaults to format::compressed*.
+ * @return A string representation of the network.
+ */
+ IPADDRESS_NODISCARD IPADDRESS_FORCE_INLINE std::u32string to_u32string(format fmt = format::compressed) const {
+ return is_v4() ? _ipv_net.ipv4.to_u32string(fmt) : _ipv_net.ipv6.to_u32string(fmt);
+ }
+
+#if __cpp_char8_t >= 201811L
+
+ /**
+ * Converts the network to a string representation.
+ *
+ * This method returns a string representation of the network, combining the network address
+ * and the prefix length, formatted according to the specified format.
+ *
+ * @param[in] fmt The format to use for the string representation. *Defaults to format::compressed*.
+ * @return A string representation of the network.
+ */
+ IPADDRESS_NODISCARD IPADDRESS_FORCE_INLINE std::u8string to_u8string(format fmt = format::compressed) const {
+ return is_v4() ? _ipv_net.ipv4.to_u8string(fmt) : _ipv_net.ipv6.to_u8string(fmt);
+ }
+
+#endif // __cpp_char8_t
+
/**
* Swaps the contents of this network with another network.
*
@@ -1125,7 +1178,6 @@ class ip_network {
*/
template
IPADDRESS_NODISCARD_WHEN_NO_EXCEPTIONS static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_network parse(const T(&address)[N], bool strict = true) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
- internal::is_char_type();
auto code = error_code::no_error;
auto result = internal::net_any_parser::parse(address, code, strict);
if (code != error_code::no_error) {
@@ -1149,7 +1201,6 @@ class ip_network {
*/
template
static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_network parse(const T(&address)[N], error_code& code, bool strict = true) IPADDRESS_NOEXCEPT {
- internal::is_char_type();
code = error_code::no_error;
const auto net4 = ipv4_network::parse(address, code, strict);
@@ -1168,10 +1219,12 @@ class ip_network {
/**
* Converts the ip network object to a std::string.
*
+ * @tparam T The character type of the string.
* @return A `std::string` representation of the ip network object.
*/
- IPADDRESS_NODISCARD IPADDRESS_FORCE_INLINE explicit operator std::string() const {
- return is_v4() ? _ipv_net.ipv4.to_string() : _ipv_net.ipv6.to_string();
+ template
+ IPADDRESS_NODISCARD IPADDRESS_FORCE_INLINE explicit operator std::basic_string, std::allocator>() const {
+ return internal::string_converter::convert(to_string());
}
/**
@@ -1278,35 +1331,6 @@ class ip_network {
#endif // !IPADDRESS_HAS_SPACESHIP_OPERATOR
private:
- // not used due to clang bug in version 14 and below
- // https://bugs.llvm.org/show_bug.cgi?id=18781
- //
- // template
- // IPADDRESS_NODISCARD_WHEN_NO_EXCEPTIONS static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_network parse_string(const Str& address, bool strict) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
- // auto code = error_code::no_error;
- // const auto net4 = ipv4_network::parse(address, code, strict);
- // if (code == error_code::no_error) {
- // return ip_network(net4);
- // }
- // return ip_network(ipv6_network::parse(address, strict));
- // }
- //
- // template
- // static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_network parse_string(const Str& address, error_code& code, bool strict) IPADDRESS_NOEXCEPT {
- // code = error_code::no_error;
- // const auto net4 = ipv4_network::parse(address, code, strict);
- // if (code == error_code::no_error) {
- // return ip_network(net4);
- // }
- //
- // const auto net6 = ipv6_network::parse(address, code, strict);
- // if (code == error_code::no_error) {
- // return ip_network(net6);
- // }
- //
- // return ip_network();
- // }
-
union ip_any_network {
IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_any_network() IPADDRESS_NOEXCEPT : ipv4() {
}
@@ -1351,7 +1375,7 @@ class ip_network {
* @param[in] size The size of the string literal.
* @return An ip_network object representing the network specified by the string literal.
*/
- IPADDRESS_NODISCARD_WHEN_NO_EXCEPTIONS IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_network operator""_net(const char* address, std::size_t size) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
+ IPADDRESS_NODISCARD_WHEN_NO_EXCEPTIONS IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_network operator""_net(const char* address, size_t size) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
const auto max_len = ipv6_address::base_max_string_len * 2 + 1;
if (size > max_len) {
raise_error(error_code::string_is_too_long, 0, address, size);
@@ -1373,7 +1397,7 @@ class ip_network {
* @param[in] size The size of the string literal.
* @return An ip_network object representing the network specified by the string literal.
*/
- IPADDRESS_NODISCARD_WHEN_NO_EXCEPTIONS IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_network operator""_net(const wchar_t* address, std::size_t size) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
+ IPADDRESS_NODISCARD_WHEN_NO_EXCEPTIONS IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_network operator""_net(const wchar_t* address, size_t size) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
const auto max_len = ipv6_address::base_max_string_len * 2 + 1;
if (size > max_len) {
raise_error(error_code::string_is_too_long, 0, address, size);
@@ -1395,7 +1419,7 @@ class ip_network {
* @param[in] size The size of the string literal.
* @return An ip_network object representing the network specified by the string literal.
*/
- IPADDRESS_NODISCARD_WHEN_NO_EXCEPTIONS IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_network operator""_net(const char16_t* address, std::size_t size) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
+ IPADDRESS_NODISCARD_WHEN_NO_EXCEPTIONS IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_network operator""_net(const char16_t* address, size_t size) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
const auto max_len = ipv6_address::base_max_string_len * 2 + 1;
if (size > max_len) {
raise_error(error_code::string_is_too_long, 0, address, size);
@@ -1417,7 +1441,7 @@ class ip_network {
* @param[in] size The size of the string literal.
* @return An ip_network object representing the network specified by the string literal.
*/
- IPADDRESS_NODISCARD_WHEN_NO_EXCEPTIONS IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_network operator""_net(const char32_t* address, std::size_t size) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
+ IPADDRESS_NODISCARD_WHEN_NO_EXCEPTIONS IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_network operator""_net(const char32_t* address, size_t size) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
const auto max_len = ipv6_address::base_max_string_len * 2 + 1;
if (size > max_len) {
raise_error(error_code::string_is_too_long, 0, address, size);
@@ -1439,7 +1463,7 @@ namespace std {
template <>
struct hash {
- IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE std::size_t operator()(const IPADDRESS_NAMESPACE::ip_network& network) const IPADDRESS_NOEXCEPT {
+ IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE size_t operator()(const IPADDRESS_NAMESPACE::ip_network& network) const IPADDRESS_NOEXCEPT {
return network.hash();
}
};
@@ -1452,7 +1476,12 @@ IPADDRESS_FORCE_INLINE std::string to_string(const IPADDRESS_NAMESPACE::ip_netwo
return network.to_string();
}
-IPADDRESS_FORCE_INLINE std::ostream& operator<<(std::ostream& stream, const IPADDRESS_NAMESPACE::ip_network& network) {
+IPADDRESS_FORCE_INLINE std::wstring to_wstring(const IPADDRESS_NAMESPACE::ip_network& network) {
+ return network.to_wstring();
+}
+
+template
+IPADDRESS_FORCE_INLINE std::basic_ostream>& operator<<(std::basic_ostream>& stream, const IPADDRESS_NAMESPACE::ip_network& network) {
auto& iword = stream.iword(IPADDRESS_NAMESPACE::stream_index());
auto fmt = iword
? (IPADDRESS_NAMESPACE::format) (iword - 1)
@@ -1465,15 +1494,16 @@ IPADDRESS_FORCE_INLINE std::ostream& operator<<(std::ostream& stream, const IPAD
return std::toupper(c);
});
}
- return stream << str;
+ return stream << IPADDRESS_NAMESPACE::internal::string_converter::convert(str);
}
-IPADDRESS_FORCE_INLINE std::istream& operator>>(std::istream& stream, IPADDRESS_NAMESPACE::ip_network& network) {
+template
+IPADDRESS_FORCE_INLINE std::basic_istream>& operator>>(std::basic_istream>& stream, IPADDRESS_NAMESPACE::ip_network& network) {
auto& iword = stream.iword(IPADDRESS_NAMESPACE::network_strict_index());
auto strict = iword == 0;
iword = 0;
- std::string str;
+ std::basic_string, std::allocator> str;
stream >> str;
IPADDRESS_NAMESPACE::error_code err = IPADDRESS_NAMESPACE::error_code::no_error;
network = IPADDRESS_NAMESPACE::ip_network::parse(str, err, strict);
diff --git a/include/ipaddress/ip-network-base.hpp b/include/ipaddress/ip-network-base.hpp
index 76972fc..37124aa 100644
--- a/include/ipaddress/ip-network-base.hpp
+++ b/include/ipaddress/ip-network-base.hpp
@@ -65,10 +65,10 @@ class ip_network_base : public Base {
IPADDRESS_NODISCARD static IPADDRESS_CONSTEVAL ip_network_base parse() IPADDRESS_NOEXCEPT {
constexpr auto str = FixedString;
auto code = error_code::no_error;
- auto index = 0;
- auto result = parse_address_with_prefix(str, Strict, code, index);
+ uint32_t value = 0;
+ auto result = parse_address_with_prefix(str, Strict, code, value);
if (code != error_code::no_error) {
- raise_error(code, index, str.data(), str.size());
+ raise_error(code, value, str.data(), str.size());
}
return result;
}
@@ -179,8 +179,8 @@ class ip_network_base : public Base {
* @remark For C++ versions prior to C++17, member functions with `std::string` and C-strings will be used instead.
*/
static IPADDRESS_CONSTEXPR ip_network_base parse(std::string_view address, error_code& code, bool strict = true) IPADDRESS_NOEXCEPT {
- auto index = 0;
- return parse_address_with_prefix(address, strict, code, index);
+ uint32_t value = 0;
+ return parse_address_with_prefix(address, strict, code, value);
}
/**
@@ -197,8 +197,8 @@ class ip_network_base : public Base {
* @remark For C++ versions prior to C++17, member functions with `std::wstring` and C-strings will be used instead.
*/
static IPADDRESS_CONSTEXPR ip_network_base parse(std::wstring_view address, error_code& code, bool strict = true) IPADDRESS_NOEXCEPT {
- auto index = 0;
- return parse_address_with_prefix(address, strict, code, index);
+ uint32_t value = 0;
+ return parse_address_with_prefix(address, strict, code, value);
}
#if __cpp_char8_t >= 201811L
@@ -216,8 +216,8 @@ class ip_network_base : public Base {
* @note This method is available for C++20 and later versions where `char8_t` is supported.
*/
static IPADDRESS_CONSTEXPR ip_network_base parse(std::u8string_view address, error_code& code, bool strict = true) IPADDRESS_NOEXCEPT {
- auto index = 0;
- return parse_address_with_prefix(address, strict, code, index);
+ uint32_t value = 0;
+ return parse_address_with_prefix(address, strict, code, value);
}
#endif // __cpp_char8_t
@@ -236,8 +236,8 @@ class ip_network_base : public Base {
* @remark For C++ versions prior to C++17, member functions with `std::u16string` and C-strings will be used instead.
*/
static IPADDRESS_CONSTEXPR ip_network_base parse(std::u16string_view address, error_code& code, bool strict = true) IPADDRESS_NOEXCEPT {
- auto index = 0;
- return parse_address_with_prefix(address, strict, code, index);
+ uint32_t value = 0;
+ return parse_address_with_prefix(address, strict, code, value);
}
/**
@@ -254,8 +254,8 @@ class ip_network_base : public Base {
* @remark For C++ versions prior to C++17, member functions with `std::u32string` and C-strings will be used instead.
*/
static IPADDRESS_CONSTEXPR ip_network_base parse(std::u32string_view address, error_code& code, bool strict = true) IPADDRESS_NOEXCEPT {
- auto index = 0;
- return parse_address_with_prefix(address, strict, code, index);
+ uint32_t value = 0;
+ return parse_address_with_prefix(address, strict, code, value);
}
#else // IPADDRESS_CPP_VERSION < 17
@@ -317,8 +317,8 @@ class ip_network_base : public Base {
* @return An ip network object representing the parsed network.
*/
static ip_network_base parse(const std::string& address, error_code& code, bool strict = true) IPADDRESS_NOEXCEPT {
- auto index = 0;
- return parse_address_with_prefix(address, strict, code, index);
+ uint32_t value = 0;
+ return parse_address_with_prefix(address, strict, code, value);
}
/**
@@ -330,8 +330,8 @@ class ip_network_base : public Base {
* @return An ip network object representing the parsed network.
*/
static ip_network_base parse(const std::wstring& address, error_code& code, bool strict = true) IPADDRESS_NOEXCEPT {
- auto index = 0;
- return parse_address_with_prefix(address, strict, code, index);
+ uint32_t value = 0;
+ return parse_address_with_prefix(address, strict, code, value);
}
/**
@@ -343,8 +343,8 @@ class ip_network_base : public Base {
* @return An ip network object representing the parsed network.
*/
static ip_network_base parse(const std::u16string& address, error_code& code, bool strict = true) IPADDRESS_NOEXCEPT {
- auto index = 0;
- return parse_address_with_prefix(address, strict, code, index);
+ uint32_t value = 0;
+ return parse_address_with_prefix(address, strict, code, value);
}
/**
@@ -356,8 +356,8 @@ class ip_network_base : public Base {
* @return An ip network object representing the parsed network.
*/
static ip_network_base parse(const std::u32string& address, error_code& code, bool strict = true) IPADDRESS_NOEXCEPT {
- auto index = 0;
- return parse_address_with_prefix(address, strict, code, index);
+ uint32_t value = 0;
+ return parse_address_with_prefix(address, strict, code, value);
}
#endif // IPADDRESS_CPP_VERSION < 17
@@ -376,7 +376,6 @@ class ip_network_base : public Base {
*/
template
IPADDRESS_NODISCARD_WHEN_NO_EXCEPTIONS static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_network_base parse(const T(&address)[N], bool strict = true) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
- internal::is_char_type();
auto str = make_fixed_string(address);
return parse_address_with_prefix(str, strict);
}
@@ -396,10 +395,9 @@ class ip_network_base : public Base {
*/
template
static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_network_base parse(const T(&address)[N], error_code& code, bool strict = true) IPADDRESS_NOEXCEPT {
- internal::is_char_type();
- auto str = make_fixed_string(address);
- auto index = 0;
- return parse_address_with_prefix(str, strict, code, index);
+ auto str = make_fixed_string(address, code);
+ uint32_t value = 0;
+ return code == error_code::no_error ? parse_address_with_prefix(str, strict, code, value) : ip_network_base{};
}
/**
@@ -580,6 +578,62 @@ class ip_network_base : public Base {
return _network_address.to_string(fmt) + '/' + std::to_string(_prefixlen);
}
+ /**
+ * Converts the network to a string representation.
+ *
+ * This method returns a string representation of the network, combining the network address
+ * and the prefix length, formatted according to the specified format.
+ *
+ * @param[in] fmt The format to use for the string representation. *Defaults to format::compressed*.
+ * @return A string representation of the network.
+ */
+ IPADDRESS_NODISCARD IPADDRESS_FORCE_INLINE std::wstring to_wstring(format fmt = format::compressed) const {
+ return internal::string_converter::convert(to_string(fmt));
+ }
+
+ /**
+ * Converts the network to a string representation.
+ *
+ * This method returns a string representation of the network, combining the network address
+ * and the prefix length, formatted according to the specified format.
+ *
+ * @param[in] fmt The format to use for the string representation. *Defaults to format::compressed*.
+ * @return A string representation of the network.
+ */
+ IPADDRESS_NODISCARD IPADDRESS_FORCE_INLINE std::u16string to_u16string(format fmt = format::compressed) const {
+ return internal::string_converter::convert(to_string(fmt));
+ }
+
+ /**
+ * Converts the network to a string representation.
+ *
+ * This method returns a string representation of the network, combining the network address
+ * and the prefix length, formatted according to the specified format.
+ *
+ * @param[in] fmt The format to use for the string representation. *Defaults to format::compressed*.
+ * @return A string representation of the network.
+ */
+ IPADDRESS_NODISCARD IPADDRESS_FORCE_INLINE std::u32string to_u32string(format fmt = format::compressed) const {
+ return internal::string_converter::convert(to_string(fmt));
+ }
+
+#if __cpp_char8_t >= 201811L
+
+ /**
+ * Converts the network to a string representation.
+ *
+ * This method returns a string representation of the network, combining the network address
+ * and the prefix length, formatted according to the specified format.
+ *
+ * @param[in] fmt The format to use for the string representation. *Defaults to format::compressed*.
+ * @return A string representation of the network.
+ */
+ IPADDRESS_NODISCARD IPADDRESS_FORCE_INLINE std::u8string to_u8string(format fmt = format::compressed) const {
+ return internal::string_converter::convert(to_string(fmt));
+ }
+
+#endif // __cpp_char8_t
+
/**
* Swaps the contents of this network with another network.
*
@@ -1072,10 +1126,12 @@ class ip_network_base : public Base {
/**
* Converts the ip network object to a std::string.
*
- * @return A `std::string` representation of the ip network object.
+ * @tparam T The character type of the string.
+ * @return A string representation of the ip network object.
*/
- IPADDRESS_NODISCARD explicit operator std::string() const {
- return to_string();
+ template
+ IPADDRESS_NODISCARD IPADDRESS_FORCE_INLINE explicit operator std::basic_string, std::allocator>() const {
+ return internal::string_converter::convert(to_string());
}
/**
@@ -1086,7 +1142,7 @@ class ip_network_base : public Base {
* @param[in] rhs The other ip network object to compare with.
* @return `true` if both objects are equal, `false` otherwise.
*/
- IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR bool operator==(const ip_network_base& rhs) const IPADDRESS_NOEXCEPT {
+ IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator==(const ip_network_base& rhs) const IPADDRESS_NOEXCEPT {
return _network_address == rhs._network_address && _netmask == rhs._netmask;
}
@@ -1098,7 +1154,7 @@ class ip_network_base : public Base {
* @param[in] rhs The other ip network object to compare with.
* @return `true` if both objects are not equal, `false` otherwise.
*/
- IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR bool operator!=(const ip_network_base& rhs) const IPADDRESS_NOEXCEPT {
+ IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator!=(const ip_network_base& rhs) const IPADDRESS_NOEXCEPT {
return !(*this == rhs);
}
@@ -1112,7 +1168,7 @@ class ip_network_base : public Base {
* @param[in] rhs The other ip network object to compare with.
* @return `std::strong_ordering` result of the comparison.
*/
- IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR std::strong_ordering operator<=>(const ip_network_base& rhs) const IPADDRESS_NOEXCEPT {
+ IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE std::strong_ordering operator<=>(const ip_network_base& rhs) const IPADDRESS_NOEXCEPT {
if (auto result = _network_address <=> rhs._network_address; result != std::strong_ordering::equivalent) {
return result;
}
@@ -1129,7 +1185,7 @@ class ip_network_base : public Base {
* @param[in] rhs The other ip network object to compare with.
* @return `true` if this object is less than the other, `false` otherwise.
*/
- IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR bool operator<(const ip_network_base& rhs) const IPADDRESS_NOEXCEPT {
+ IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator<(const ip_network_base& rhs) const IPADDRESS_NOEXCEPT {
if (_network_address != rhs._network_address) {
return _network_address < rhs._network_address;
}
@@ -1147,7 +1203,7 @@ class ip_network_base : public Base {
* @param[in] rhs The other ip network object to compare with.
* @return `true` if this object is greater than the other, `false` otherwise.
*/
- IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR bool operator>(const ip_network_base& rhs) const IPADDRESS_NOEXCEPT {
+ IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator>(const ip_network_base& rhs) const IPADDRESS_NOEXCEPT {
return rhs < *this;
}
@@ -1159,7 +1215,7 @@ class ip_network_base : public Base {
* @param[in] rhs The other ip network object to compare with.
* @return `true` if this object is less than or equal to the other, `false` otherwise.
*/
- IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR bool operator<=(const ip_network_base& rhs) const IPADDRESS_NOEXCEPT {
+ IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator<=(const ip_network_base& rhs) const IPADDRESS_NOEXCEPT {
return !(rhs < *this);
}
@@ -1171,7 +1227,7 @@ class ip_network_base : public Base {
* @param[in] rhs The other ip network object to compare with.
* @return `true` if this object is greater than or equal to the other, `false` otherwise.
*/
- IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR bool operator>=(const ip_network_base& rhs) const IPADDRESS_NOEXCEPT {
+ IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool operator>=(const ip_network_base& rhs) const IPADDRESS_NOEXCEPT {
return !(*this < rhs);
}
@@ -1181,34 +1237,38 @@ class ip_network_base : public Base {
template
static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_network_base parse_address_with_prefix(const Str& str, bool strict) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
auto code = error_code::no_error;
- auto index = 0;
- auto result = parse_address_with_prefix(str, strict, code, index);
+ uint32_t value = 0;
+ auto result = parse_address_with_prefix(str, strict, code, value);
if (code != error_code::no_error) {
- raise_error(code, index, str.data(), str.size());
+ raise_error(code, value, str.data(), str.size());
}
return result;
}
template
- static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_network_base parse_address_with_prefix(const Str& str, bool strict, error_code& code, int& index) IPADDRESS_NOEXCEPT {
+ static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_network_base parse_address_with_prefix(const Str& str, bool strict, error_code& code, uint32_t& code_value) IPADDRESS_NOEXCEPT {
code = error_code::no_error;
-
+ auto it = str.data();
+ auto end = str.data() + str.size();
auto has_slash = false;
- auto netmask = str.end();
+ auto netmask = end;
auto symbol = 0;
char address[ip_address_type::base_max_string_len + 1] = {};
- for (auto it = str.begin(); it != str.end(); ++it) {
- const auto c = char(*it);
+ while (it < end) {
+ const auto c = internal::next_char_or_error(it, end, code, code_value);
+ if (code != error_code::no_error) {
+ return ip_network_base();
+ }
if (c == '/') {
if (has_slash) {
code = error_code::only_one_slash_permitted;
return ip_network_base();
}
- if (it + 1 == str.end()) {
+ if (it == end) {
code = error_code::empty_netmask;
return ip_network_base();
}
- netmask = it + 1;
+ netmask = it;
has_slash = true;
}
if (!has_slash) {
@@ -1219,7 +1279,7 @@ class ip_network_base : public Base {
}
}
- auto netmask_result = ip_address_type::parse_netmask(netmask, str.end(), code, index);
+ auto netmask_result = ip_address_type::parse_netmask(netmask, end, code, code_value);
if (code != error_code::no_error) {
return ip_network_base();
@@ -1257,7 +1317,7 @@ class ip_network_base : public Base {
namespace internal {
template
-IPADDRESS_NODISCARD_WHEN_NO_EXCEPTIONS IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_network_base parse_net_from_literal(const TChar* address, std::size_t size) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
+IPADDRESS_NODISCARD_WHEN_NO_EXCEPTIONS IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ip_network_base parse_net_from_literal(const TChar* address, size_t size) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
if (size > MaxLen) {
raise_error(error_code::string_is_too_long, 0, address, size);
}
@@ -1274,17 +1334,19 @@ IPADDRESS_NODISCARD_WHEN_NO_EXCEPTIONS IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLIN
#ifndef IPADDRESS_NO_OVERLOAD_STD
-inline int network_strict_index() {
+IPADDRESS_FORCE_INLINE int network_strict_index() {
static int i = std::ios_base::xalloc();
return i;
}
-inline std::istream& strict(std::istream& stream) {
+template
+IPADDRESS_FORCE_INLINE std::basic_istream>& strict(std::basic_istream>& stream) {
stream.iword(network_strict_index()) = 0;
return stream;
}
-inline std::istream& non_strict(std::istream& stream) {
+template
+IPADDRESS_FORCE_INLINE std::basic_istream>& non_strict(std::basic_istream>& stream) {
stream.iword(network_strict_index()) = 1;
return stream;
}
@@ -1299,38 +1361,50 @@ namespace std {
template
struct hash> {
- IPADDRESS_CONSTEXPR std::size_t operator()(const IPADDRESS_NAMESPACE::ip_network_base& network) const IPADDRESS_NOEXCEPT {
+ IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE size_t operator()(const IPADDRESS_NAMESPACE::ip_network_base& network) const IPADDRESS_NOEXCEPT {
return network.hash();
}
};
template
-inline IPADDRESS_CONSTEXPR void swap(IPADDRESS_NAMESPACE::ip_network_base& net1, IPADDRESS_NAMESPACE::ip_network_base& net2) IPADDRESS_NOEXCEPT {
+IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE void swap(IPADDRESS_NAMESPACE::ip_network_base& net1, IPADDRESS_NAMESPACE::ip_network_base& net2) IPADDRESS_NOEXCEPT {
return net1.swap(net2);
}
template
-inline std::string to_string(const IPADDRESS_NAMESPACE::ip_network_base& network) {
+IPADDRESS_NODISCARD IPADDRESS_FORCE_INLINE std::string to_string(const IPADDRESS_NAMESPACE::ip_network_base& network) {
return network.to_string();
}
template
-inline std::ostream& operator<<(std::ostream& stream, const IPADDRESS_NAMESPACE::ip_network_base& network) {
+IPADDRESS_NODISCARD IPADDRESS_FORCE_INLINE std::wstring to_wstring(const IPADDRESS_NAMESPACE::ip_network_base& network) {
+ return network.to_wstring();
+}
+
+template
+IPADDRESS_FORCE_INLINE std::basic_ostream>& operator<<(std::basic_ostream>& stream, const IPADDRESS_NAMESPACE::ip_network_base& network) {
auto& iword = stream.iword(IPADDRESS_NAMESPACE::stream_index());
auto fmt = iword
? (IPADDRESS_NAMESPACE::format) (iword - 1)
: IPADDRESS_NAMESPACE::format::compressed;
iword = 0;
- return stream << network.to_string(fmt);
+ auto str = network.to_string(fmt);
+ if (stream.flags() & ios_base::uppercase) {
+ auto end = std::find(str.cbegin(), str.cend(), '%');
+ std::transform(str.cbegin(), end, str.begin(), [](char c){
+ return std::toupper(c);
+ });
+ }
+ return stream << IPADDRESS_NAMESPACE::internal::string_converter::convert(str);
}
-template
-inline std::istream& operator>>(std::istream& stream, IPADDRESS_NAMESPACE::ip_network_base& network) {
+template
+IPADDRESS_FORCE_INLINE std::basic_istream>& operator>>(std::basic_istream>& stream, IPADDRESS_NAMESPACE::ip_network_base& network) {
auto& iword = stream.iword(IPADDRESS_NAMESPACE::network_strict_index());
auto strict = iword == 0;
iword = 0;
- std::string str;
+ std::basic_string, std::allocator> str;
stream >> str;
IPADDRESS_NAMESPACE::error_code err = IPADDRESS_NAMESPACE::error_code::no_error;
network = IPADDRESS_NAMESPACE::ip_network_base::parse(str, err, strict);
diff --git a/include/ipaddress/ip-network-iterator.hpp b/include/ipaddress/ip-network-iterator.hpp
index c97561d..331c682 100644
--- a/include/ipaddress/ip-network-iterator.hpp
+++ b/include/ipaddress/ip-network-iterator.hpp
@@ -34,7 +34,7 @@ class ip_network_iterator {
public:
using iterator_category = std::random_access_iterator_tag; /**< The category of the iterator. */
using value_type = T; /**< The type of value iterated over. */
- using difference_type = std::int64_t; /**< Type to represent the difference between two iterators. */
+ using difference_type = int64_t; /**< Type to represent the difference between two iterators. */
using pointer = const value_type*; /**< Pointer to the value type. */
using reference = const value_type&; /**< Reference to the value type. */
@@ -463,7 +463,7 @@ class ip_exclude_network_iterator {
public:
using iterator_category = std::forward_iterator_tag; /**< The category of the iterator. */
using value_type = T; /**< The type of value iterated over. */
- using difference_type = std::int64_t; /**< Type to represent the difference between two iterators. */
+ using difference_type = int64_t; /**< Type to represent the difference between two iterators. */
using pointer = const value_type*; /**< Pointer to the value type. */
using reference = const value_type&; /**< Reference to the value type. */
@@ -678,7 +678,7 @@ template
class subnets_sequence {
public:
using value_type = T; /**< The type of subnet value. */
- using size_type = std::size_t; /**< An unsigned integral type. */
+ using size_type = size_t; /**< An unsigned integral type. */
using difference_type = typename value_type::uint_type; /**< Unsigned integer type for differences. */
using pointer = value_type*; /**< Pointer to the subnet type. */
using const_pointer = const value_type*; /**< Const pointer to the subnet type. */
@@ -890,7 +890,7 @@ template
class exclude_network_sequence {
public:
using value_type = T; /**< The type of network value. */
- using size_type = std::size_t; /**< An unsigned integral type. */
+ using size_type = size_t; /**< An unsigned integral type. */
using difference_type = typename value_type::uint_type; /**< Unsigned integer type for differences. */
using pointer = value_type*; /**< Pointer to the network type. */
using const_pointer = const value_type*; /**< Const pointer to the network type. */
diff --git a/include/ipaddress/ip-networks.hpp b/include/ipaddress/ip-networks.hpp
index f68b5ee..6820267 100644
--- a/include/ipaddress/ip-networks.hpp
+++ b/include/ipaddress/ip-networks.hpp
@@ -26,7 +26,7 @@ struct networks {
static const ipv4_network ipv4_private_networks[];
static const ipv6_network ipv6_private_networks[];
- static const ipv4_network ipv4_is_global;
+ static const ipv4_network ipv4_is_public_network;
static const ipv4_network ipv4_reserved_network;
static const ipv6_network ipv6_reserved_networks[];
@@ -93,7 +93,7 @@ static constexpr ipv4_network
template const ipv4_network networks::
#endif
// NOLINTNEXTLINE(cert-err58-cpp): for C++11
- ipv4_is_global = ipv4_network::parse("100.64.0.0/10");
+ ipv4_is_public_network = ipv4_network::parse("100.64.0.0/10");
// Reserved networks
#if __cpp_constexpr >= 201304L
@@ -190,7 +190,7 @@ template
constexpr ipv6_network networks::ipv6_private_networks[];
template
-constexpr ipv4_network networks::ipv4_is_global;
+constexpr ipv4_network networks::ipv4_is_public_network;
template
constexpr ipv4_network networks::ipv4_reserved_network;
@@ -248,7 +248,7 @@ IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool ipv6_network
template<>
IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool ipv4_network::is_global() const IPADDRESS_NOEXCEPT {
- const auto& network = internal::nets::ipv4_is_global;
+ const auto& network = internal::nets::ipv4_is_public_network;
const auto& address = network_address();
const auto broadcast = broadcast_address();
return !(network.contains(address) && network.contains(broadcast)) && !is_private();
@@ -298,7 +298,7 @@ IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool ipv6_address
template<>
IPADDRESS_NODISCARD IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE bool ipv4_address::is_global() const IPADDRESS_NOEXCEPT {
- return !internal::nets::ipv4_is_global.contains(*this) && !is_private();
+ return !internal::nets::ipv4_is_public_network.contains(*this) && !is_private();
}
template<>
diff --git a/include/ipaddress/ipv4-address.hpp b/include/ipaddress/ipv4-address.hpp
index 710146a..5d2d80f 100644
--- a/include/ipaddress/ipv4-address.hpp
+++ b/include/ipaddress/ipv4-address.hpp
@@ -81,7 +81,7 @@ class ipv4_address_base : public base_v4 {
lhs._bytes.swap(rhs._bytes);
}
- IPADDRESS_NODISCARD static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE std::size_t hash(const base_type& bytes) IPADDRESS_NOEXCEPT {
+ IPADDRESS_NODISCARD static IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE size_t hash(const base_type& bytes) IPADDRESS_NOEXCEPT {
return internal::calc_hash(0, size_t(bytes[0]), size_t(bytes[1]), size_t(bytes[2]), size_t(bytes[3]));
}
@@ -151,7 +151,7 @@ using ipv4_address = ip_address_base;
* @param[in] size The size of the character array.
* @return An ipv4_address object parsed from the string literal.
*/
- IPADDRESS_NODISCARD_WHEN_NO_EXCEPTIONS IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ipv4_address operator""_ipv4(const char* address, std::size_t size) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
+ IPADDRESS_NODISCARD_WHEN_NO_EXCEPTIONS IPADDRESS_CONSTEXPR IPADDRESS_FORCE_INLINE ipv4_address operator""_ipv4(const char* address, size_t size) IPADDRESS_NOEXCEPT_WHEN_NO_EXCEPTIONS {
return internal::parse_ip_from_literal(address, size);
}
@@ -162,7 +162,7 @@ using ipv4_address = ip_address_base