public inbox for libstdc++@gcc.gnu.org
 help / color / mirror / Atom feed
* [committed 1/5] libstdc++: Optimize net::ip::address_v4::to_string()
@ 2023-02-24 14:28 Jonathan Wakely
  2023-02-24 14:28 ` [committed 2/5] libstdc++: Fix conversion to/from net::ip::address_v4::bytes_type Jonathan Wakely
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Jonathan Wakely @ 2023-02-24 14:28 UTC (permalink / raw)
  To: libstdc++, gcc-patches

Tested x86_64-linux. Pushed to trunk.

-- >8 --

This is an order of magnitude faster than calling inet_ntop (and not
only because we now avoid allocating a string that is one byte larger
than the SSO buffer).

libstdc++-v3/ChangeLog:

	* include/experimental/internet (address_v4::to_string):
	Optimize.
	* testsuite/experimental/net/internet/address/v4/members.cc:
	Check more addresses.
---
 libstdc++-v3/include/experimental/internet    | 28 +++++++++++++------
 .../net/internet/address/v4/members.cc        | 11 ++++++++
 2 files changed, 31 insertions(+), 8 deletions(-)

diff --git a/libstdc++-v3/include/experimental/internet b/libstdc++-v3/include/experimental/internet
index 707370d5611..08bd0db4bb2 100644
--- a/libstdc++-v3/include/experimental/internet
+++ b/libstdc++-v3/include/experimental/internet
@@ -44,6 +44,7 @@
 #include <sstream>
 #include <cstdint>
 #include <experimental/string_view>
+#include <bits/charconv.h>
 #ifdef _GLIBCXX_HAVE_UNISTD_H
 # include <unistd.h>
 #endif
@@ -241,17 +242,28 @@ namespace ip
       __string_with<_Allocator>
       to_string(const _Allocator& __a = _Allocator()) const
       {
-#ifdef _GLIBCXX_HAVE_ARPA_INET_H
+	auto __write = [__addr = to_uint()](char* __p, size_t __n) {
+	  auto __to_chars = [](char* __p, uint8_t __v) {
+	    unsigned __n = __v >= 100u ? 3 : __v >= 10u ? 2 : 1;
+	    std::__detail::__to_chars_10_impl(__p, __n, __v);
+	    return __p + __n;
+	  };
+	  const auto __begin = __p;
+	  __p = __to_chars(__p, uint8_t(__addr >> 24));
+	  for (int __i = 2; __i >= 0; __i--) {
+	    *__p++ = '.';
+	    __p = __to_chars(__p, uint8_t(__addr >> (__i * 8)));
+	  }
+	  return __p - __begin;
+	};
 	__string_with<_Allocator> __str(__a);
-	__str.resize(INET_ADDRSTRLEN);
-	if (inet_ntop(AF_INET, &_M_addr, &__str.front(), __str.size()))
-	  __str.erase(__str.find('\0'));
-	else
-	  __str.resize(0);
-	return __str;
+#if __cpp_lib_string_resize_and_overwrite
+	__str.resize_and_overwrite(15, __write);
 #else
-	std::__throw_system_error((int)__unsupported_err());
+	__str.resize(15);
+	__str.resize(__write(&__str.front(), 15));
 #endif
+	return __str;
       }
 
     // static members:
diff --git a/libstdc++-v3/testsuite/experimental/net/internet/address/v4/members.cc b/libstdc++-v3/testsuite/experimental/net/internet/address/v4/members.cc
index df19b11804d..c40a8103664 100644
--- a/libstdc++-v3/testsuite/experimental/net/internet/address/v4/members.cc
+++ b/libstdc++-v3/testsuite/experimental/net/internet/address/v4/members.cc
@@ -22,6 +22,7 @@
 #include <experimental/internet>
 #include <sstream>
 #include <testsuite_hooks.h>
+#include <testsuite_allocator.h>
 
 using std::experimental::net::ip::address_v4;
 
@@ -100,6 +101,16 @@ test04()
   VERIFY( address_v4::any().to_string() == "0.0.0.0" );
   VERIFY( address_v4::loopback().to_string() == "127.0.0.1" );
   VERIFY( address_v4::broadcast().to_string() == "255.255.255.255" );
+  using b = address_v4::bytes_type;
+  VERIFY( address_v4(b(1, 23, 45, 67)).to_string() == "1.23.45.67" );
+  VERIFY( address_v4(b(12, 34, 56, 78)).to_string() == "12.34.56.78" );
+  VERIFY( address_v4(b(123, 4, 5, 6)).to_string() == "123.4.5.6" );
+  VERIFY( address_v4(b(123, 234, 124, 235)).to_string() == "123.234.124.235" );
+
+  __gnu_test::uneq_allocator<char> alloc(123);
+  auto str = address_v4(b(12, 34, 56, 78)).to_string(alloc);
+  VERIFY(str.get_allocator().get_personality() == alloc.get_personality());
+  VERIFY( str == "12.34.56.78" );
 }
 
 void
-- 
2.39.2


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [committed 2/5] libstdc++: Fix conversion to/from net::ip::address_v4::bytes_type
  2023-02-24 14:28 [committed 1/5] libstdc++: Optimize net::ip::address_v4::to_string() Jonathan Wakely
@ 2023-02-24 14:28 ` Jonathan Wakely
  2023-02-24 14:28 ` [committed 3/5] libstdc++: Fix members of net::ip::network_v4 Jonathan Wakely
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Jonathan Wakely @ 2023-02-24 14:28 UTC (permalink / raw)
  To: libstdc++, gcc-patches

Tested x86_64-linux. Pushed to trunk.

-- >8 --

I messed up the endianness of the address_v4::bytes_type array, which
should always be in network byte order. We can just use bit_cast to
convert the _M_addr member to/from bytes_type.

libstdc++-v3/ChangeLog:

	* include/experimental/internet (address_4(const bytes_type&)):
	Use __builtin_bit_cast if available, otherwise convert to
	network byte order.
	(address_v4::to_bytes()): Likewise, but convert from network
	byte order.
	* testsuite/experimental/net/internet/address/v4/cons.cc: Fix
	incorrect tests. Check for constexpr too.
	* testsuite/experimental/net/internet/address/v4/creation.cc:
	Likewise.
	* testsuite/experimental/net/internet/address/v4/members.cc:
	Check that bytes_type is a standard-layout type.
---
 libstdc++-v3/include/experimental/internet    | 20 ++++++++---
 .../net/internet/address/v4/cons.cc           | 33 ++++++++++++-------
 .../net/internet/address/v4/creation.cc       | 24 +++++++++++---
 .../net/internet/address/v4/members.cc        |  3 ++
 4 files changed, 60 insertions(+), 20 deletions(-)

diff --git a/libstdc++-v3/include/experimental/internet b/libstdc++-v3/include/experimental/internet
index 08bd0db4bb2..3fd200251fa 100644
--- a/libstdc++-v3/include/experimental/internet
+++ b/libstdc++-v3/include/experimental/internet
@@ -198,7 +198,12 @@ namespace ip
 
     constexpr
     address_v4(const bytes_type& __b)
-    : _M_addr((__b[0] << 24) | (__b[1] << 16) | (__b[2] << 8) | __b[3])
+#if __has_builtin(__builtin_bit_cast)
+    : _M_addr(__builtin_bit_cast(uint_type, __b))
+#else
+    : _M_addr(_S_hton_32((__b[0] << 24) | (__b[1] << 16)
+			   | (__b[2] << 8) | __b[3]))
+#endif
     { }
 
     explicit constexpr
@@ -227,12 +232,17 @@ namespace ip
     constexpr bytes_type
     to_bytes() const noexcept
     {
+#if __has_builtin(__builtin_bit_cast)
+      return __builtin_bit_cast(bytes_type, _M_addr);
+#else
+      auto __host = to_uint();
       return bytes_type{
-	  (_M_addr >> 24) & 0xFF,
-	  (_M_addr >> 16) & 0xFF,
-	  (_M_addr >> 8) & 0xFF,
-	  _M_addr & 0xFF
+	(__host >> 24) & 0xFF,
+	(__host >> 16) & 0xFF,
+	(__host >> 8) & 0xFF,
+	__host & 0xFF
       };
+#endif
     }
 
     constexpr uint_type
diff --git a/libstdc++-v3/testsuite/experimental/net/internet/address/v4/cons.cc b/libstdc++-v3/testsuite/experimental/net/internet/address/v4/cons.cc
index 65f23642de4..af9fef2215e 100644
--- a/libstdc++-v3/testsuite/experimental/net/internet/address/v4/cons.cc
+++ b/libstdc++-v3/testsuite/experimental/net/internet/address/v4/cons.cc
@@ -24,41 +24,45 @@
 
 using std::experimental::net::ip::address_v4;
 
-void
+#if __cplusplus < 202002L
+// Naughty, but operator== for std::array is not constexpr until C++20.
+constexpr bool
+operator==(const address_v4::bytes_type& lhs, const address_v4::bytes_type& rhs)
+{
+  return lhs[0] == rhs[0] && lhs[1] == rhs[1]
+      && lhs[2] == rhs[2] && lhs[3] == rhs[3];
+}
+#endif
+
+constexpr void
 test01()
 {
-  bool test __attribute__((unused)) = false;
-
   address_v4 a0;
   VERIFY( a0.to_uint() == 0 );
   VERIFY( a0.to_bytes() == address_v4::bytes_type{} );
 }
 
-void
+constexpr void
 test02()
 {
-  bool test __attribute__((unused)) = false;
-
   address_v4 a0{ address_v4::bytes_type{} };
   VERIFY( a0.to_uint() == 0 );
   VERIFY( a0.to_bytes() == address_v4::bytes_type{} );
 
   address_v4::bytes_type b1{ 1, 2, 3, 4 };
   address_v4 a1{ b1 };
-  VERIFY( a1.to_uint() == ntohl((1 << 24) | (2 << 16) | (3 << 8) | 4) );
+  VERIFY( a1.to_uint() == ((1 << 24) | (2 << 16) | (3 << 8) | 4) );
   VERIFY( a1.to_bytes() == b1 );
 }
 
-void
+constexpr void
 test03()
 {
-  bool test __attribute__((unused)) = false;
-
   address_v4 a0{ 0u };
   VERIFY( a0.to_uint() == 0 );
   VERIFY( a0.to_bytes() == address_v4::bytes_type{} );
 
-  address_v4::uint_type u1 = ntohl((5 << 24) | (6 << 16) | (7 << 8) | 8);
+  address_v4::uint_type u1 = (5 << 24) | (6 << 16) | (7 << 8) | 8;
   address_v4 a1{ u1 };
   VERIFY( a1.to_uint() == u1 );
   VERIFY( a1.to_bytes() == address_v4::bytes_type( 5, 6, 7, 8 ) );
@@ -70,4 +74,11 @@ main()
   test01();
   test02();
   test03();
+
+  constexpr bool c = []{
+    test01();
+    test02();
+    test03();
+    return true;
+  };
 }
diff --git a/libstdc++-v3/testsuite/experimental/net/internet/address/v4/creation.cc b/libstdc++-v3/testsuite/experimental/net/internet/address/v4/creation.cc
index 441c832bf54..84aebbb7adc 100644
--- a/libstdc++-v3/testsuite/experimental/net/internet/address/v4/creation.cc
+++ b/libstdc++-v3/testsuite/experimental/net/internet/address/v4/creation.cc
@@ -25,7 +25,17 @@
 namespace net = std::experimental::net;
 using net::ip::address_v4;
 
-void
+#if __cplusplus < 202002L
+// Naughty, but operator== for std::array is not constexpr until C++20.
+constexpr bool
+operator==(const address_v4::bytes_type& lhs, const address_v4::bytes_type& rhs)
+{
+  return lhs[0] == rhs[0] && lhs[1] == rhs[1]
+      && lhs[2] == rhs[2] && lhs[3] == rhs[3];
+}
+#endif
+
+constexpr void
 test01()
 {
   auto a0 = make_address_v4( address_v4::bytes_type{} );
@@ -34,18 +44,18 @@ test01()
 
   address_v4::bytes_type b1{ 1, 2, 3, 4 };
   auto a1 = make_address_v4( b1 );
-  VERIFY( a1.to_uint() == ntohl((1 << 24) | (2 << 16) | (3 << 8) | 4) );
+  VERIFY( a1.to_uint() == ((1 << 24) | (2 << 16) | (3 << 8) | 4) );
   VERIFY( a1.to_bytes() == b1 );
 }
 
-void
+constexpr void
 test02()
 {
   auto a0 = net::ip::make_address_v4(0u);
   VERIFY( a0.to_uint() == 0 );
   VERIFY( a0.to_bytes() == address_v4::bytes_type{} );
 
-  address_v4::uint_type u1 = ntohl((5 << 24) | (6 << 16) | (7 << 8) | 8);
+  address_v4::uint_type u1 = ((5 << 24) | (6 << 16) | (7 << 8) | 8);
   auto a1 = net::ip::make_address_v4( u1 );
   VERIFY( a1.to_uint() == u1 );
   VERIFY( a1.to_bytes() == address_v4::bytes_type( 5, 6, 7, 8 ) );
@@ -84,4 +94,10 @@ main()
   test01();
   test02();
   test03();
+
+  constexpr bool c = []{
+    test01();
+    test02();
+    return true;
+  };
 }
diff --git a/libstdc++-v3/testsuite/experimental/net/internet/address/v4/members.cc b/libstdc++-v3/testsuite/experimental/net/internet/address/v4/members.cc
index c40a8103664..ac59405c599 100644
--- a/libstdc++-v3/testsuite/experimental/net/internet/address/v4/members.cc
+++ b/libstdc++-v3/testsuite/experimental/net/internet/address/v4/members.cc
@@ -26,6 +26,9 @@
 
 using std::experimental::net::ip::address_v4;
 
+static_assert(std::is_standard_layout<address_v4::bytes_type>::value,
+    "net::ip::address_v4::bytes_type is a standard layout type");
+
 constexpr bool
 test01()
 {
-- 
2.39.2


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [committed 3/5] libstdc++: Fix members of net::ip::network_v4
  2023-02-24 14:28 [committed 1/5] libstdc++: Optimize net::ip::address_v4::to_string() Jonathan Wakely
  2023-02-24 14:28 ` [committed 2/5] libstdc++: Fix conversion to/from net::ip::address_v4::bytes_type Jonathan Wakely
@ 2023-02-24 14:28 ` Jonathan Wakely
  2023-02-24 14:28 ` [committed 4/5] libstdc++: Make net::ip::basic_endpoint comparisons constexpr Jonathan Wakely
  2023-02-24 14:28 ` [committed 5/5] libstdc++: Constrain net::executor constructors Jonathan Wakely
  3 siblings, 0 replies; 5+ messages in thread
From: Jonathan Wakely @ 2023-02-24 14:28 UTC (permalink / raw)
  To: libstdc++, 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 <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


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [committed 4/5] libstdc++: Make net::ip::basic_endpoint comparisons constexpr
  2023-02-24 14:28 [committed 1/5] libstdc++: Optimize net::ip::address_v4::to_string() Jonathan Wakely
  2023-02-24 14:28 ` [committed 2/5] libstdc++: Fix conversion to/from net::ip::address_v4::bytes_type Jonathan Wakely
  2023-02-24 14:28 ` [committed 3/5] libstdc++: Fix members of net::ip::network_v4 Jonathan Wakely
@ 2023-02-24 14:28 ` Jonathan Wakely
  2023-02-24 14:28 ` [committed 5/5] libstdc++: Constrain net::executor constructors Jonathan Wakely
  3 siblings, 0 replies; 5+ messages in thread
From: Jonathan Wakely @ 2023-02-24 14:28 UTC (permalink / raw)
  To: libstdc++, gcc-patches

Tested x86_64-linux. Pushed to trunk.

-- >8 --

libstdc++-v3/ChangeLog:

	* include/experimental/internet (basic_endpoint): Add missing
	constexpr to comparison operators.
	* testsuite/experimental/net/internet/endpoint/cons.cc: New test.
---
 libstdc++-v3/include/experimental/internet    | 12 ++--
 .../net/internet/endpoint/cons.cc             | 66 +++++++++++++++++++
 2 files changed, 72 insertions(+), 6 deletions(-)
 create mode 100644 libstdc++-v3/testsuite/experimental/net/internet/endpoint/cons.cc

diff --git a/libstdc++-v3/include/experimental/internet b/libstdc++-v3/include/experimental/internet
index 5336b8a8ce3..cae07f466da 100644
--- a/libstdc++-v3/include/experimental/internet
+++ b/libstdc++-v3/include/experimental/internet
@@ -1626,19 +1626,19 @@ namespace ip
    */
 
   template<typename _InternetProtocol>
-    inline bool
+    constexpr bool
     operator==(const basic_endpoint<_InternetProtocol>& __a,
 	       const basic_endpoint<_InternetProtocol>& __b)
     { return __a.address() == __b.address() && __a.port() == __b.port(); }
 
   template<typename _InternetProtocol>
-    inline bool
+    constexpr bool
     operator!=(const basic_endpoint<_InternetProtocol>& __a,
 	       const basic_endpoint<_InternetProtocol>& __b)
     { return !(__a == __b); }
 
   template<typename _InternetProtocol>
-    inline bool
+    constexpr bool
     operator< (const basic_endpoint<_InternetProtocol>& __a,
 	       const basic_endpoint<_InternetProtocol>& __b)
     {
@@ -1647,19 +1647,19 @@ namespace ip
     }
 
   template<typename _InternetProtocol>
-    inline bool
+    constexpr bool
     operator> (const basic_endpoint<_InternetProtocol>& __a,
 	       const basic_endpoint<_InternetProtocol>& __b)
     { return __b < __a; }
 
   template<typename _InternetProtocol>
-    inline bool
+    constexpr bool
     operator<=(const basic_endpoint<_InternetProtocol>& __a,
 	       const basic_endpoint<_InternetProtocol>& __b)
     { return !(__b < __a); }
 
   template<typename _InternetProtocol>
-    inline bool
+    constexpr bool
     operator>=(const basic_endpoint<_InternetProtocol>& __a,
 	       const basic_endpoint<_InternetProtocol>& __b)
     { return !(__a < __b); }
diff --git a/libstdc++-v3/testsuite/experimental/net/internet/endpoint/cons.cc b/libstdc++-v3/testsuite/experimental/net/internet/endpoint/cons.cc
new file mode 100644
index 00000000000..1b5c92c0b58
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/net/internet/endpoint/cons.cc
@@ -0,0 +1,66 @@
+// { 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>
+
+using namespace std::experimental::net;
+
+constexpr void
+test_default()
+{
+  ip::tcp::endpoint t1;
+  VERIFY( t1.protocol() == ip::tcp::v4() );
+  VERIFY( t1.address() == ip::address() );
+  VERIFY( t1.port() == 0 );
+
+  ip::udp::endpoint t2;
+  VERIFY( t2.protocol() == ip::udp::v4() );
+  VERIFY( t2.address() == ip::address() );
+  VERIFY( t2.port() == 0 );
+}
+
+constexpr void
+test_proto()
+{
+  ip::tcp::endpoint t1(ip::tcp::v4(), 22);
+  VERIFY( t1.protocol() == ip::tcp::v4() );
+  VERIFY( t1.address() == ip::address_v4() );
+  VERIFY( t1.port() == 22 );
+
+  ip::tcp::endpoint t2(ip::tcp::v6(), 80);
+  VERIFY( t2.protocol() == ip::tcp::v6() );
+  VERIFY( t2.address() == ip::address_v6() );
+  VERIFY( t2.port() == 80 );
+}
+
+constexpr void
+test_addr()
+{
+  ip::address_v4 a1(ip::address_v4::bytes_type(1, 2, 3, 4));
+  ip::tcp::endpoint t1(a1, 22);
+  VERIFY( t1.protocol() == ip::tcp::v4() );
+  VERIFY( t1.address() == a1 );
+  VERIFY( t1.port() == 22 );
+
+  ip::address_v6 a2(ip::address_v6::bytes_type(21,22,23,24,25,26,27,28,29));
+  ip::tcp::endpoint t2(a2, 80);
+  VERIFY( t2.protocol() == ip::tcp::v6() );
+  VERIFY( t2.address() == a2 );
+  VERIFY( t2.port() == 80 );
+}
+
+int main()
+{
+  test_default();
+  test_proto();
+  test_addr();
+
+  constexpr bool c = [] {
+    test_default();
+    test_proto();
+    test_addr();
+    return true;
+  };
+}
-- 
2.39.2


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [committed 5/5] libstdc++: Constrain net::executor constructors
  2023-02-24 14:28 [committed 1/5] libstdc++: Optimize net::ip::address_v4::to_string() Jonathan Wakely
                   ` (2 preceding siblings ...)
  2023-02-24 14:28 ` [committed 4/5] libstdc++: Make net::ip::basic_endpoint comparisons constexpr Jonathan Wakely
@ 2023-02-24 14:28 ` Jonathan Wakely
  3 siblings, 0 replies; 5+ messages in thread
From: Jonathan Wakely @ 2023-02-24 14:28 UTC (permalink / raw)
  To: libstdc++, gcc-patches

Tested x86_64-linux. Pushed to trunk.

-- >8 --

The TS says the arguments to these constructors shall meet the Executor
requirements, so it's undefined if they don't. Constraining on a subset
of those requirements won't affect valid cases, but prevents the
majority of invalid cases from trying to instantiate the constructor.

This prevents the non-explicit executor(Executor) constructor being a
candidate anywhere that a net::executor could be constructed e.g.
comparing ip::tcp::v4() == ip::udp::v4() would try to convert both
operands to executor using that constructor, then compare then using
operator==(const executor&, const executor&).

libstdc++-v3/ChangeLog:

	* include/experimental/executor (executor): Constrain template
	constructors.
---
 libstdc++-v3/include/experimental/executor | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/libstdc++-v3/include/experimental/executor b/libstdc++-v3/include/experimental/executor
index cd75d99ddb3..1dae8925916 100644
--- a/libstdc++-v3/include/experimental/executor
+++ b/libstdc++-v3/include/experimental/executor
@@ -1012,6 +1012,9 @@ inline namespace v1
 
   class executor
   {
+    template<typename _Executor>
+      using _Context_t = decltype(std::declval<_Executor&>().context());
+
   public:
     // construct / copy / destroy:
 
@@ -1021,12 +1024,14 @@ inline namespace v1
     executor(const executor&) noexcept = default;
     executor(executor&&) noexcept = default;
 
-    template<typename _Executor>
+    template<typename _Executor,
+	     typename = _Require<is_lvalue_reference<_Context_t<_Executor>>>>
       executor(_Executor __e)
       : _M_target(make_shared<_Tgt1<_Executor>>(std::move(__e)))
       { }
 
-    template<typename _Executor, typename _ProtoAlloc>
+    template<typename _Executor, typename _ProtoAlloc,
+	     typename = _Require<is_lvalue_reference<_Context_t<_Executor>>>>
       executor(allocator_arg_t, const _ProtoAlloc& __a, _Executor __e)
       : _M_target(allocate_shared<_Tgt2<_Executor, _ProtoAlloc>>(__a,
 	    std::move(__e), __a))
-- 
2.39.2


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2023-02-24 14:28 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-02-24 14:28 [committed 1/5] libstdc++: Optimize net::ip::address_v4::to_string() Jonathan Wakely
2023-02-24 14:28 ` [committed 2/5] libstdc++: Fix conversion to/from net::ip::address_v4::bytes_type Jonathan Wakely
2023-02-24 14:28 ` [committed 3/5] libstdc++: Fix members of net::ip::network_v4 Jonathan Wakely
2023-02-24 14:28 ` [committed 4/5] libstdc++: Make net::ip::basic_endpoint comparisons constexpr Jonathan Wakely
2023-02-24 14:28 ` [committed 5/5] libstdc++: Constrain net::executor constructors Jonathan Wakely

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).