libstdc++: Make std::span layout-compatible with struct iovec [PR 95609]
authorJonathan Wakely <jwakely@redhat.com>
Wed, 28 Oct 2020 12:07:40 +0000 (12:07 +0000)
committerJonathan Wakely <jwakely@redhat.com>
Wed, 28 Oct 2020 12:07:40 +0000 (12:07 +0000)
This change reorders the data members of std::span so that span<byte> is
layout-compatible with common implementations of struct iovec. This will
allow span<byte> to be used directly in places that use a struct iovec
to do scatter-gather I/O.

It's important to note that POSIX doesn't specify the order of members
in iovec. Also the equivalent type on Windows has members in the other
order, and uses type ULONG (which is always 32-bit whereas size_t is
64-bit for Win64). So this change will only help for certain targets and
an indirection between std::span and I/O system calls will still be
needed for the general case.

libstdc++-v3/ChangeLog:

PR libstdc++/95609
* include/std/span (span): Reorder data members to match common
implementations of struct iovec.
* testsuite/23_containers/span/layout_compat.cc: New test.

libstdc++-v3/include/std/span
libstdc++-v3/testsuite/23_containers/span/layout_compat.cc [new file with mode: 0644]

index fb349403c9ee0297afd1e35a6d0eefc340c3c1c8..24c61ba41728adf365ddbea49b86c29ed7a3727c 100644 (file)
@@ -38,8 +38,8 @@
 
 #if __cplusplus > 201703L
 
-#include <type_traits>
 #include <array>
+#include <cstddef>
 #include <bits/stl_iterator.h>
 #include <bits/ranges_base.h>
 
@@ -151,7 +151,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       constexpr
       span() noexcept
       requires ((_Extent + 1u) <= 1u)
-      : _M_extent(0), _M_ptr(nullptr)
+      : _M_ptr(nullptr), _M_extent(0)
       { }
 
       template<contiguous_iterator _It>
@@ -159,7 +159,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        constexpr explicit(extent != dynamic_extent)
        span(_It __first, size_type __count)
        noexcept
-       : _M_extent(__count), _M_ptr(std::to_address(__first))
+       : _M_ptr(std::to_address(__first)), _M_extent(__count)
        {
          if constexpr (_Extent != dynamic_extent)
            {
@@ -173,8 +173,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        constexpr explicit(extent != dynamic_extent)
        span(_It __first, _End __last)
        noexcept(noexcept(__last - __first))
-       : _M_extent(static_cast<size_type>(__last - __first)),
-         _M_ptr(std::to_address(__first))
+       : _M_ptr(std::to_address(__first)),
+         _M_extent(static_cast<size_type>(__last - __first))
        {
          if constexpr (_Extent != dynamic_extent)
            {
@@ -392,8 +392,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       }
 
     private:
-      [[no_unique_address]] __detail::__extent_storage<extent> _M_extent;
       pointer _M_ptr;
+      [[no_unique_address]] __detail::__extent_storage<extent> _M_extent;
     };
 
   // deduction guides
diff --git a/libstdc++-v3/testsuite/23_containers/span/layout_compat.cc b/libstdc++-v3/testsuite/23_containers/span/layout_compat.cc
new file mode 100644 (file)
index 0000000..efc5b8e
--- /dev/null
@@ -0,0 +1,48 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library.  This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3.  If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++2a" }
+// { dg-do compile { target c++2a } }
+
+#include <span>
+#include <cstddef>
+
+#if __has_include(<sys/uio.h>)
+#include <sys/uio.h>
+#else
+struct iovec { void* iov_base; std::size_t iov_len; };
+#endif
+
+#if __cpp_lib_is_pointer_interconvertible
+using std::is_layout_compatible_v;
+#else
+// A poor substitute for is_layout_compatible_v
+template<typename T, typename U>
+  constexpr bool is_layout_compatible_v
+    = std::is_standard_layout_v<T> && std::is_standard_layout_v<U>
+      && sizeof(T) == sizeof(U) && alignof(T) == alignof(U);
+#endif
+
+void
+test_pr95609()
+{
+  using rbuf = std::span<const std::byte>;
+  using wbuf = std::span<std::byte>;
+
+  static_assert(is_layout_compatible_v<rbuf, struct iovec>);
+  static_assert(is_layout_compatible_v<wbuf, struct iovec>);
+}