From patchwork Fri Feb 24 14:28:06 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 65597 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 9F3FE383FB95 for ; Fri, 24 Feb 2023 14:29:22 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 9F3FE383FB95 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1677248962; bh=uPy/3MSvzJ/f4N/o59cLS7Tm7nvFcjpWbSDAHXFuvs8=; h=To:Subject:Date:In-Reply-To:References:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:List-Subscribe:From:Reply-To: From; b=TyJkdCHzvYkIce3Mlve9BBy8QlO7YWlHZ9QRmnBzXQjG6XS52JDMZqMjOyicGwJQa yB2+JXw7xYpvurgb/0u/BpkxlShCTrSrNEJQEimY4X9UpX5h5s5miUjtCLSBF77i2N ife7I3RaiZBxnb8GF6CkdBCQdhrZM4iAhkNkv14k= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id CE066385B501 for ; Fri, 24 Feb 2023 14:28:12 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org CE066385B501 Received: from mimecast-mx02.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-551-cEVEbGJNPoCB386JbrkjQA-1; Fri, 24 Feb 2023 09:28:11 -0500 X-MC-Unique: cEVEbGJNPoCB386JbrkjQA-1 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id EFB7C2806049; Fri, 24 Feb 2023 14:28:10 +0000 (UTC) Received: from localhost (unknown [10.33.36.228]) by smtp.corp.redhat.com (Postfix) with ESMTP id 9A1032166B29; Fri, 24 Feb 2023 14:28:10 +0000 (UTC) To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [committed 3/5] libstdc++: Fix members of net::ip::network_v4 Date: Fri, 24 Feb 2023 14:28:06 +0000 Message-Id: <20230224142808.714075-3-jwakely@redhat.com> In-Reply-To: <20230224142808.714075-1-jwakely@redhat.com> References: <20230224142808.714075-1-jwakely@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.6 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-11.9 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_NUMSUBJECT, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, SPF_HELO_NONE, SPF_NONE, TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Jonathan Wakely via Gcc-patches From: Jonathan Wakely Reply-To: Jonathan Wakely Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" 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 +#include +#include + +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 +#include +#include + +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 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 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; + }; +}