Tested x86_64-linux. Pushed to trunk. -- >8 --
libstdc++-v3/ChangeLog: * include/experimental/internet (network_v4::netmask()): Avoid undefined shift. (network_v4::broadcast()): Optimize and fix for targets with uint_least32_t wider than 32 bits. (network_v4::to_string(const Allocator&)): Fix for custom allocators and optimize using to_chars. (operator==(const network_v4&, const network_v4&)): Add missing constexpr. (operator==(const network_v6&, const network_v6&)): Likewise. * testsuite/experimental/net/internet/network/v4/cons.cc: New test. * testsuite/experimental/net/internet/network/v4/members.cc: New test. --- libstdc++-v3/include/experimental/internet | 41 ++-- .../net/internet/network/v4/cons.cc | 129 ++++++++++++ .../net/internet/network/v4/members.cc | 186 ++++++++++++++++++ 3 files changed, 343 insertions(+), 13 deletions(-) create mode 100644 libstdc++-v3/testsuite/experimental/net/internet/network/v4/cons.cc create mode 100644 libstdc++-v3/testsuite/experimental/net/internet/network/v4/members.cc diff --git a/libstdc++-v3/include/experimental/internet b/libstdc++-v3/include/experimental/internet index 3fd200251fa..5336b8a8ce3 100644 --- a/libstdc++-v3/include/experimental/internet +++ b/libstdc++-v3/include/experimental/internet @@ -1219,10 +1219,10 @@ namespace ip /// @} - bool + constexpr bool operator==(const network_v4& __a, const network_v4& __b) noexcept; - bool + constexpr bool operator==(const network_v6& __a, const network_v6& __b) noexcept; @@ -1263,10 +1263,10 @@ namespace ip constexpr address_v4 netmask() const noexcept { - address_v4::uint_type __val = address_v4::broadcast().to_uint(); - __val >>= (32 - _M_prefix_len); - __val <<= (32 - _M_prefix_len); - return address_v4{__val}; + address_v4 __m; + if (_M_prefix_len) + __m = address_v4(0xFFFFFFFFu << (32 - _M_prefix_len)); + return __m; } constexpr address_v4 @@ -1275,7 +1275,7 @@ namespace ip constexpr address_v4 broadcast() const noexcept - { return address_v4{_M_addr.to_uint() | ~netmask().to_uint()}; } + { return address_v4{_M_addr.to_uint() | (0xFFFFFFFFu >> _M_prefix_len)}; } address_v4_range hosts() const noexcept @@ -1306,8 +1306,23 @@ namespace ip __string_with<_Allocator> to_string(const _Allocator& __a = _Allocator()) const { - return address().to_string(__a) + '/' - + std::to_string(prefix_length()); + auto __str = address().to_string(__a); + const unsigned __addrlen = __str.length(); + const unsigned __preflen = prefix_length() >= 10 ? 2 : 1; + auto __write = [=](char* __p, size_t __n) { + __p[__addrlen] = '/'; + std::__detail::__to_chars_10_impl(__p + __addrlen + 1, __preflen, + (unsigned char)prefix_length()); + return __n; + }; + const unsigned __len = __addrlen + 1 + __preflen; +#if __cpp_lib_string_resize_and_overwrite + __str.resize_and_overwrite(__len, __write); +#else + __str.resize(__len); + __write(&__str.front(), __len); +#endif + return __str; } private: @@ -1379,14 +1394,14 @@ namespace ip * @{ */ - inline bool + constexpr bool operator==(const network_v4& __a, const network_v4& __b) noexcept { return __a.address() == __b.address() && __a.prefix_length() == __b.prefix_length(); } - inline bool + constexpr bool operator!=(const network_v4& __a, const network_v4& __b) noexcept { return !(__a == __b); } @@ -1396,14 +1411,14 @@ namespace ip * @{ */ - inline bool + constexpr bool operator==(const network_v6& __a, const network_v6& __b) noexcept { return __a.address() == __b.address() && __a.prefix_length() == __b.prefix_length(); } - inline bool + constexpr bool operator!=(const network_v6& __a, const network_v6& __b) noexcept { return !(__a == __b); } diff --git a/libstdc++-v3/testsuite/experimental/net/internet/network/v4/cons.cc b/libstdc++-v3/testsuite/experimental/net/internet/network/v4/cons.cc new file mode 100644 index 00000000000..7784b6f6f58 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/net/internet/network/v4/cons.cc @@ -0,0 +1,129 @@ +// { dg-do run { target c++14 } } +// { dg-require-effective-target net_ts_ip } +// { dg-add-options net_ts } + +#include <experimental/internet> +#include <stdexcept> +#include <testsuite_hooks.h> + +using std::experimental::net::ip::network_v4; +using std::experimental::net::ip::address_v4; + +constexpr void +test01() +{ + network_v4 n0; + VERIFY( n0.address().is_unspecified() ); + VERIFY( n0.prefix_length() == 0 ); +} + +constexpr void +test02() +{ + address_v4 a0; + network_v4 n0{ a0, 0 }; + VERIFY( n0.address() == a0 ); + VERIFY( n0.prefix_length() == 0 ); + + address_v4 a1{ address_v4::bytes_type{ 1, 2, 3, 4 } }; + network_v4 n1{ a1, 12}; + VERIFY( n1.address() == a1 ); + VERIFY( n1.prefix_length() == 12 ); +} + +void +test02_errors() +{ + address_v4 a0; + try + { + network_v4{a0, -1}; + VERIFY(false); + } + catch(const std::out_of_range&) + { + } + + try + { + network_v4{a0, 33}; + VERIFY(false); + } + catch(const std::out_of_range&) + { + } +} + +constexpr void +test03() +{ + address_v4 a0; + network_v4 n0{ a0, a0 }; + VERIFY( n0.address() == a0 ); + VERIFY( n0.prefix_length() == 0 ); + + address_v4 a1{ address_v4::bytes_type{ 1, 2, 3, 4 } }; + network_v4 n1{ a1, address_v4::broadcast() }; + VERIFY( n1.address() == a1 ); + VERIFY( n1.prefix_length() == 32 ); + + network_v4 n2{ a1, address_v4::bytes_type(128, 0, 0, 0) }; + VERIFY( n2.address() == a1 ); + VERIFY( n2.prefix_length() == 1 ); + + network_v4 n3{ a1, address_v4::bytes_type(255, 255, 255, 192) }; + VERIFY( n3.address() == a1 ); + VERIFY( n3.prefix_length() == 26 ); +} + +void +test03_errors() +{ + address_v4 a0; + try + { + // Contains non-contiguous non-zero bits. + network_v4{a0, address_v4::bytes_type(255, 1, 0, 0)}; + VERIFY(false); + } + catch(const std::invalid_argument&) + { + } + + try + { + // Most significant bit is zero and any other bits are non-zero. + network_v4{a0, address_v4::bytes_type(1, 0, 0, 0)}; + VERIFY(false); + } + catch(const std::invalid_argument&) + { + } + + try + { + // Most significant bit is zero and any other bits are non-zero. + network_v4{a0, address_v4::bytes_type(0, 1, 0, 0)}; + VERIFY(false); + } + catch(const std::invalid_argument&) + { + } +} + +int +main() +{ + test01(); + test02(); + test02_errors(); + test03(); + test03_errors(); + + constexpr bool c = []{ + test01(); + test02(); + test03(); + return true; + }; +} diff --git a/libstdc++-v3/testsuite/experimental/net/internet/network/v4/members.cc b/libstdc++-v3/testsuite/experimental/net/internet/network/v4/members.cc new file mode 100644 index 00000000000..3ea65862649 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/net/internet/network/v4/members.cc @@ -0,0 +1,186 @@ +// { dg-do run { target c++14 } } +// { dg-require-effective-target net_ts_ip } +// { dg-add-options net_ts } + +#include <experimental/internet> +#include <testsuite_hooks.h> +#include <testsuite_allocator.h> + +using std::experimental::net::ip::network_v4; +using std::experimental::net::ip::address_v4; + +constexpr void +test_netmask() +{ + network_v4 n0; + VERIFY( n0.netmask() == address_v4() ); + + network_v4 n1({}, 1); + VERIFY( n1.netmask() == address_v4(address_v4::bytes_type(128)) ); + + network_v4 n2({}, 2); + VERIFY( n2.netmask() == address_v4(address_v4::bytes_type(192)) ); + + network_v4 n3({}, 3); + VERIFY( n3.netmask() == address_v4(address_v4::bytes_type(224)) ); + + network_v4 n4({}, 17); + VERIFY( n4.netmask() == address_v4(address_v4::bytes_type(255, 255, 128)) ); +} + +constexpr void +test_network() +{ + network_v4 n0; + VERIFY( n0.network() == address_v4() ); + + network_v4 n1(address_v4::bytes_type{1, 2, 3, 4}, 1); + VERIFY( n1.network() == address_v4(address_v4::bytes_type(0, 0, 0, 0)) ); + + network_v4 n2(address_v4::bytes_type{1, 2, 3, 4}, 8); + VERIFY( n2.network() == address_v4(address_v4::bytes_type(1, 0, 0, 0)) ); + + network_v4 n3(address_v4::bytes_type{1, 2, 3, 4}, 15); + VERIFY( n3.network() == address_v4(address_v4::bytes_type(1, 2, 0, 0)) ); + + network_v4 n4(address_v4::bytes_type{1, 2, 3, 4}, 16); + VERIFY( n4.network() == address_v4(address_v4::bytes_type(1, 2, 0, 0)) ); + + network_v4 n5(address_v4::bytes_type{1, 2, 3, 4}, 23); + VERIFY( n5.network() == address_v4(address_v4::bytes_type(1, 2, 2, 0)) ); + + network_v4 n6(address_v4::bytes_type{1, 2, 3, 4}, 24); + VERIFY( n6.network() == address_v4(address_v4::bytes_type(1, 2, 3, 0)) ); + + network_v4 n7(address_v4::bytes_type{1, 2, 3, 4}, 29); + VERIFY( n7.network() == address_v4(address_v4::bytes_type(1, 2, 3, 0)) ); + + network_v4 n8(address_v4::bytes_type{1, 2, 3, 4}, 30); + VERIFY( n8.network() == address_v4(address_v4::bytes_type(1, 2, 3, 4)) ); + + network_v4 n9(address_v4::bytes_type{1, 2, 3, 4}, 32); + VERIFY( n9.network() == address_v4(address_v4::bytes_type(1, 2, 3, 4)) ); +} + +constexpr void +test_broadcast() +{ + using b = address_v4::bytes_type; + + network_v4 n0; + VERIFY( n0.broadcast() == address_v4::broadcast() ); + + network_v4 n1(b{1, 2, 3, 4}, 1); + VERIFY( n1.broadcast() == address_v4(b(127, 255, 255, 255)) ); + + network_v4 n2(b{1, 2, 3, 4}, 8); + VERIFY( n2.broadcast() == address_v4(b(1, 255, 255, 255)) ); + + network_v4 n3(b{1, 2, 3, 4}, 15); + VERIFY( n3.broadcast() == address_v4(b(1, 3, 255, 255)) ); + + network_v4 n4(b{1, 2, 3, 4}, 16); + VERIFY( n4.broadcast() == address_v4(b(1, 2, 255, 255)) ); + + network_v4 n5(b{1, 2, 3, 4}, 23); + VERIFY( n5.broadcast() == address_v4(b(1, 2, 3, 255)) ); + + network_v4 n6(b{1, 2, 3, 4}, 24); + VERIFY( n6.broadcast() == address_v4(b(1, 2, 3, 255)) ); + + network_v4 n7(b{1, 2, 3, 4}, 29); + VERIFY( n7.broadcast() == address_v4(b(1, 2, 3, 7)) ); + + network_v4 n8(b{1, 2, 3, 4}, 30); + VERIFY( n8.broadcast() == address_v4(b(1, 2, 3, 7)) ); + + network_v4 n9(b{1, 2, 3, 4}, 31); + VERIFY( n9.broadcast() == address_v4(b(1, 2, 3, 5)) ); + + network_v4 n10(b{1, 2, 3, 4}, 32); + VERIFY( n10.broadcast() == address_v4(b(1, 2, 3, 4)) ); +} + +constexpr void +test_canonical() +{ + network_v4 n0; + VERIFY( n0.canonical() == network_v4(n0.network(), n0.prefix_length()) ); + + network_v4 n1(address_v4::bytes_type{1, 2, 3, 4}, 1); + VERIFY( n1.canonical() == network_v4(n1.network(), n1.prefix_length()) ); + + network_v4 n2(address_v4::bytes_type{1, 2, 3, 4}, 8); + VERIFY( n2.canonical() == network_v4(n2.network(), n2.prefix_length()) ); + + network_v4 n3(address_v4::bytes_type{1, 2, 3, 4}, 15); + VERIFY( n3.canonical() == network_v4(n3.network(), n3.prefix_length()) ); + + network_v4 n4(address_v4::bytes_type{1, 2, 3, 4}, 16); + VERIFY( n4.canonical() == network_v4(n4.network(), n4.prefix_length()) ); + + network_v4 n5(address_v4::bytes_type{1, 2, 3, 4}, 23); + VERIFY( n5.canonical() == network_v4(n5.network(), n5.prefix_length()) ); + + network_v4 n6(address_v4::bytes_type{1, 2, 3, 4}, 24); + VERIFY( n6.canonical() == network_v4(n6.network(), n6.prefix_length()) ); + + network_v4 n7(address_v4::bytes_type{1, 2, 3, 4}, 29); + VERIFY( n7.canonical() == network_v4(n7.network(), n7.prefix_length()) ); + + network_v4 n8(address_v4::bytes_type{1, 2, 3, 4}, 30); + VERIFY( n8.canonical() == network_v4(n8.network(), n8.prefix_length()) ); + + network_v4 n9(address_v4::bytes_type{1, 2, 3, 4}, 32); + VERIFY( n9.canonical() == network_v4(n9.network(), n9.prefix_length()) ); +} + +constexpr void +test_is_host() +{ + network_v4 n0; + VERIFY( ! n0.is_host() ); + + network_v4 n1(address_v4::bytes_type{1, 2, 3, 4}, 1); + VERIFY( ! n1.is_host() ); + + network_v4 n2(address_v4::bytes_type{1, 2, 3, 4}, 8); + VERIFY( ! n2.is_host() ); + + network_v4 n3(address_v4::bytes_type{1, 2, 3, 4}, 32); + VERIFY( n3.is_host() ); +} + +void +test_to_string() +{ + using b = address_v4::bytes_type; + __gnu_test::uneq_allocator<char> alloc(123); + auto str = network_v4(address_v4(b(12, 34, 56, 78)), 24).to_string(alloc); + VERIFY(str.get_allocator().get_personality() == alloc.get_personality()); + VERIFY( str == "12.34.56.78/24" ); + + __gnu_test::uneq_allocator<char> alloc2(99); + auto str2 = network_v4(address_v4(b(87, 65, 43, 21)), 4).to_string(alloc2); + VERIFY(str2.get_allocator().get_personality() == alloc2.get_personality()); + VERIFY( str2 == "87.65.43.21/4" ); +} + +int main() +{ + test_netmask(); + test_network(); + test_broadcast(); + test_canonical(); + test_is_host(); + test_to_string(); + + constexpr bool c = []{ + test_netmask(); + test_network(); + test_broadcast(); + test_canonical(); + test_is_host(); + return true; + }; +} -- 2.39.2