(root)/
gcc-13.2.0/
libstdc++-v3/
testsuite/
experimental/
net/
internet/
socket/
opt.cc
// { dg-do run { target c++14 } }
// { dg-require-effective-target net_ts_ip }

#include <experimental/internet>
#include <testsuite_common_types.h>
#include <testsuite_hooks.h>

using namespace std;

template<typename C, typename T, typename P>
void check_gettable_sockopt(P p, C c = C())
{
  static_assert( is_same<decltype(declval<const C&>().level(p)), int>(), "" );
  static_assert( noexcept(declval<const C&>().level(p)), "" );

  static_assert( is_same<decltype(declval<const C&>().name(p)), int>(), "" );
  static_assert( noexcept(declval<const C&>().name(p)), "" );

  static_assert( is_same<decltype(declval<C&>().data(p)), void*>(), "" );
  static_assert( noexcept(declval<C&>().data(p)), "" );

  static_assert( is_same<decltype(declval<const C&>().size(p)), size_t>(), "" );
  static_assert( noexcept(declval<const C&>().size(p)), "" );

  static_assert( is_same<decltype(declval<C&>().resize(p, 0)), void>(), "" );
  static_assert( ! noexcept(declval<C&>().resize(p, 0)), "" );

  VERIFY(c.size(p) == sizeof(T));
}

template<typename C, typename T, typename P>
void check_settable_sockopt(P p, C c = C())
{
  static_assert( is_same<decltype(declval<const C&>().level(p)), int>(), "" );
  static_assert( noexcept(declval<const C&>().level(p)), "" );

  static_assert( is_same<decltype(declval<const C&>().name(p)), int>(), "" );
  static_assert( noexcept(declval<const C&>().name(p)), "" );

  static_assert( is_same<decltype(declval<const C&>().data(p)), const void*>(), "" );
  static_assert( noexcept(declval<const C&>().data(p)), "" );

  static_assert( is_same<decltype(declval<C&>().size(p)), size_t>(), "" );
  static_assert( noexcept(declval<C&>().size(p)), "" );

  VERIFY(c.size(p) == sizeof(T));
}

template<typename C, typename T = int>
void check_boolean_sockopt()
{
  namespace ip = std::experimental::net::ip;
#if __has_include(<netinet/in.h>)
  check_gettable_sockopt<C, T>(ip::tcp::v4());
  check_settable_sockopt<C, T>(ip::tcp::v4());
#endif

  static_assert( is_destructible<C>(), "" );
  static_assert( is_nothrow_default_constructible<C>(), "" );
  static_assert( is_nothrow_copy_constructible<C>(), "" );
  static_assert( is_nothrow_copy_assignable<C>(), "" );

  static_assert( is_nothrow_constructible<C, bool>(), "" );
  static_assert( is_nothrow_assignable<C&, bool>(), "" );

  static_assert( is_same<decltype(declval<const C&>().value()), bool>(), "" );
  static_assert( noexcept(declval<const C&>().value()), "" );

  static_assert( is_same<decltype(static_cast<bool>(declval<const C&>())), bool>(), "" );
  static_assert( noexcept(static_cast<bool>(declval<const C&>())), "" );

  static_assert( is_same<decltype(!declval<const C&>()), bool>(), "" );
  static_assert( noexcept(!declval<const C&>()), "" );
}

template<typename C, typename T = int>
void check_integer_sockopt()
{
  namespace ip = std::experimental::net::ip;
#if __has_include(<netinet/in.h>)
  check_gettable_sockopt<C, T>(ip::tcp::v4());
  check_settable_sockopt<C, T>(ip::tcp::v4());
#endif

  static_assert( is_destructible<C>(), "" );
  static_assert( is_nothrow_default_constructible<C>(), "" );
  static_assert( is_nothrow_copy_constructible<C>(), "" );
  static_assert( is_nothrow_copy_assignable<C>(), "" );

  static_assert( is_nothrow_constructible<C, int>(), "" );
  static_assert( is_nothrow_assignable<C&, int>(), "" );

  static_assert( is_same<decltype(declval<const C&>().value()), int>(), "" );
  static_assert( noexcept(declval<const C&>().value()), "" );
}

template<typename C>
void check_mcast_sockopt(C& c)
{
  namespace ip = std::experimental::net::ip;
  static_assert( is_destructible<C>(), "" );
  static_assert( is_copy_constructible<C>(), "" );
  static_assert( is_copy_assignable<C>(), "" );

#if __has_include(<netinet/in.h>)
  check_settable_sockopt<C, ipv6_mreq>(ip::tcp::v6(), c);
  check_settable_sockopt<C, ip_mreq>(ip::tcp::v4(), c);
#endif

  static_assert( is_nothrow_constructible<C, const ip::address&>(), "" );
  static_assert( ! is_convertible<const ip::address&, C>(), "explicit" );
  static_assert( is_nothrow_constructible<C, const ip::address_v4&>(), "" );
  static_assert( ! is_convertible<const ip::address_v4&, C>(), "explicit" );
  static_assert( is_nothrow_constructible<C, const ip::address_v4&, const ip::address_v4&>(), "" );
  static_assert( is_nothrow_constructible<C, const ip::address_v6&>(), "" );
  static_assert( ! is_convertible<const ip::address_v6&, C>(), "explicit" );
  static_assert( is_nothrow_constructible<C, const ip::address_v6&, unsigned>(), "" );
}

void test_option_types()
{
  namespace ip = std::experimental::net::ip;

#if __has_include(<netinet/in.h>)
#if __has_include(<netinet/tcp.h>)
  check_boolean_sockopt<ip::tcp::no_delay>();
#endif

  check_boolean_sockopt<ip::v6_only>();

  check_integer_sockopt<ip::unicast::hops>();

  ip::multicast::join_group join(ip::address_v4::any());
  check_mcast_sockopt(join);

  ip::multicast::leave_group leave(ip::address_v4::any());
  check_mcast_sockopt(leave);

  using outbound_if = ip::multicast::outbound_interface;
  outbound_if oif(ip::address_v4::any());
  check_settable_sockopt<outbound_if, unsigned>(ip::tcp::v6(), oif);
  check_settable_sockopt<outbound_if, ::in_addr>(ip::tcp::v4(), oif);
  static_assert( is_destructible<outbound_if>(), "" );
  static_assert( ! is_default_constructible<outbound_if>(), "" );
  static_assert( is_nothrow_copy_constructible<outbound_if>(), "" );
  static_assert( is_nothrow_copy_assignable<outbound_if>(), "" );
  static_assert( is_nothrow_constructible<outbound_if, const ip::address_v4&>(), "" );
  static_assert( ! is_convertible<const ip::address_v4&, outbound_if>(), "explicit" );
  static_assert( is_nothrow_constructible<outbound_if, unsigned>(), "" );
  static_assert( ! is_convertible<unsigned, outbound_if>(), "explicit" );

  check_integer_sockopt<ip::multicast::hops>();

  check_boolean_sockopt<ip::multicast::enable_loopback>();
#endif
}

int main()
{
  test_option_types();
}