pw_span: Updates for C++20 std::span compatibility

Apply the latest updates from Chromium's span implementation (Chromium
commit d93ae920e4309682deb9352a4637cfc2941c1d1f).

Change-Id: Ifc805b53ff70158fbc99e2a452502f525c050a62
diff --git a/pw_span/public/pw_span/span.h b/pw_span/public/pw_span/span.h
index 2ea01ff..8aa270d 100644
--- a/pw_span/public/pw_span/span.h
+++ b/pw_span/public/pw_span/span.h
@@ -19,7 +19,7 @@
 // a template parameter, so this class can be used to without stating its size.
 //
 // This file a modified version of base::span from Chromium:
-//   https://chromium.googlesource.com/chromium/src/+/ef71f9c29f0dc6eddae474879c4ca5232ca93a6c/base/containers/span.h
+//   https://chromium.googlesource.com/chromium/src/+/d93ae920e4309682deb9352a4637cfc2941c1d1f/base/containers/span.h
 //
 // In order to minimize changes from the original, this file does NOT fully
 // adhere to Pigweed's style guide.
@@ -246,9 +246,7 @@
   using pointer = T*;
   using reference = T&;
   using iterator = T*;
-  using const_iterator = const T*;
   using reverse_iterator = std::reverse_iterator<iterator>;
-  using const_reverse_iterator = std::reverse_iterator<const_iterator>;
   static constexpr size_t extent = Extent;
 
   // [span.cons], span constructors, copy, assignment, and destructor
@@ -273,19 +271,18 @@
                 span_internal::EnableIfSpanCompatibleArray<T (&)[N], T, Extent>>
   constexpr span(T (&array)[N]) noexcept : span(std::data(array), N) {}
 
-  template <
-      size_t N,
-      typename = span_internal::
-          EnableIfSpanCompatibleArray<std::array<value_type, N>&, T, Extent>>
-  constexpr span(std::array<value_type, N>& array) noexcept
+  template <typename U,
+            size_t N,
+            typename = span_internal::
+                EnableIfSpanCompatibleArray<std::array<U, N>&, T, Extent>>
+  constexpr span(std::array<U, N>& array) noexcept
       : span(std::data(array), N) {}
 
-  template <size_t N,
-            typename = span_internal::EnableIfSpanCompatibleArray<
-                const std::array<value_type, N>&,
-                T,
-                Extent>>
-  constexpr span(const std::array<value_type, N>& array) noexcept
+  template <typename U,
+            size_t N,
+            typename = span_internal::
+                EnableIfSpanCompatibleArray<const std::array<U, N>&, T, Extent>>
+  constexpr span(const std::array<U, N>& array) noexcept
       : span(std::data(array), N) {}
 
   // Conversion from a container that has compatible std::data() and integral
@@ -326,16 +323,14 @@
   // [span.sub], span subviews
   template <size_t Count>
   constexpr span<T, Count> first() const noexcept {
-    static_assert(Extent == dynamic_extent || Count <= Extent,
-                  "Count must not exceed Extent");
+    static_assert(Count <= Extent, "Count must not exceed Extent");
     _PW_SPAN_ASSERT(Extent != dynamic_extent || Count <= size());
     return {data(), Count};
   }
 
   template <size_t Count>
   constexpr span<T, Count> last() const noexcept {
-    static_assert(Extent == dynamic_extent || Count <= Extent,
-                  "Count must not exceed Extent");
+    static_assert(Count <= Extent, "Count must not exceed Extent");
     _PW_SPAN_ASSERT(Extent != dynamic_extent || Count <= size());
     return {data() + (size() - Count), Count};
   }
@@ -347,10 +342,8 @@
                       : (Extent != dynamic_extent ? Extent - Offset
                                                   : dynamic_extent))>
   subspan() const noexcept {
-    static_assert(Extent == dynamic_extent || Offset <= Extent,
-                  "Offset must not exceed Extent");
-    static_assert(Extent == dynamic_extent || Count == dynamic_extent ||
-                      Count <= Extent - Offset,
+    static_assert(Offset <= Extent, "Offset must not exceed Extent");
+    static_assert(Count == dynamic_extent || Count <= Extent - Offset,
                   "Count must not exceed Extent - Offset");
     _PW_SPAN_ASSERT(Extent != dynamic_extent || Offset <= size());
     _PW_SPAN_ASSERT(Extent != dynamic_extent || Count == dynamic_extent ||
@@ -410,9 +403,6 @@
   constexpr iterator begin() const noexcept { return data_; }
   constexpr iterator end() const noexcept { return data_ + size(); }
 
-  constexpr const_iterator cbegin() const noexcept { return begin(); }
-  constexpr const_iterator cend() const noexcept { return end(); }
-
   constexpr reverse_iterator rbegin() const noexcept {
     return reverse_iterator(end());
   }
@@ -420,13 +410,6 @@
     return reverse_iterator(begin());
   }
 
-  constexpr const_reverse_iterator crbegin() const noexcept {
-    return const_reverse_iterator(cend());
-  }
-  constexpr const_reverse_iterator crend() const noexcept {
-    return const_reverse_iterator(cbegin());
-  }
-
  private:
   T* data_;
 };
@@ -486,49 +469,4 @@
 
 }  // namespace pw
 
-// Note: std::tuple_size, std::tuple_element and std::get are specialized for
-// static spans, so that they can be used in C++17's structured bindings.
-namespace std {
-
-// [span.tuple], tuple interface
-#if defined(__clang__)
-// Due to https://llvm.org/PR39871 and https://llvm.org/PR41331 and their
-// respective fixes different versions of libc++ declare std::tuple_size and
-// std::tuple_element either as classes or structs. In order to be able to
-// specialize std::tuple_size and std::tuple_element for custom pw types we
-// thus need to disable -Wmismatched-tags in order to support all build
-// configurations. Note that this is blessed by the standard in
-// https://timsong-cpp.github.io/cppwp/n4140/dcl.type.elab#3.
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wmismatched-tags"
-#endif
-template <typename T, size_t X>
-struct tuple_size<pw::span<T, X>> : public integral_constant<size_t, X> {};
-
-template <typename T>
-struct tuple_size<pw::span<T, pw::dynamic_extent>>;  // not defined
-
-template <size_t I, typename T, size_t X>
-struct tuple_element<I, pw::span<T, X>> {
-  static_assert(
-      pw::dynamic_extent != X,
-      "std::tuple_element<> not supported for pw::span<T, dynamic_extent>");
-  static_assert(I < X,
-                "Index out of bounds in std::tuple_element<> (pw::span)");
-  using type = T;
-};
-#if defined(__clang__)
-#pragma clang diagnostic pop  // -Wmismatched-tags
-#endif
-
-template <size_t I, typename T, size_t X>
-constexpr T& get(pw::span<T, X> s) noexcept {
-  static_assert(pw::dynamic_extent != X,
-                "std::get<> not supported for pw::span<T, dynamic_extent>");
-  static_assert(I < X, "Index out of bounds in std::get<> (pw::span)");
-  return s[I];
-}
-
-}  // namespace std
-
 #undef _PW_SPAN_ASSERT
diff --git a/pw_span/span_test.cc b/pw_span/span_test.cc
index 37875f6..37d5ee4 100644
--- a/pw_span/span_test.cc
+++ b/pw_span/span_test.cc
@@ -260,6 +260,99 @@
     EXPECT_EQ(vector[i], static_span[i]);
 }
 
+TEST(SpanTest, AllowedConversionsFromStdArray) {
+  // In the following assertions we use std::is_convertible_v<From, To>, which
+  // for non-void types is equivalent to checking whether the following
+  // expression is well-formed:
+  //
+  // T obj = std::declval<From>();
+  //
+  // In particular we are checking whether From is implicitly convertible to To,
+  // which also implies that To is explicitly constructible from From.
+  static_assert(
+      std::is_convertible<std::array<int, 3>&, span<int>>::value,
+      "Error: l-value reference to std::array<int> should be convertible to "
+      "span<int> with dynamic extent.");
+  static_assert(
+      std::is_convertible<std::array<int, 3>&, span<int, 3>>::value,
+      "Error: l-value reference to std::array<int> should be convertible to "
+      "span<int> with the same static extent.");
+  static_assert(
+      std::is_convertible<std::array<int, 3>&, span<const int>>::value,
+      "Error: l-value reference to std::array<int> should be convertible to "
+      "span<const int> with dynamic extent.");
+  static_assert(
+      std::is_convertible<std::array<int, 3>&, span<const int, 3>>::value,
+      "Error: l-value reference to std::array<int> should be convertible to "
+      "span<const int> with the same static extent.");
+  static_assert(
+      std::is_convertible<const std::array<int, 3>&, span<const int>>::value,
+      "Error: const l-value reference to std::array<int> should be "
+      "convertible to span<const int> with dynamic extent.");
+  static_assert(
+      std::is_convertible<const std::array<int, 3>&, span<const int, 3>>::value,
+      "Error: const l-value reference to std::array<int> should be convertible "
+      "to span<const int> with the same static extent.");
+  static_assert(
+      std::is_convertible<std::array<const int, 3>&, span<const int>>::value,
+      "Error: l-value reference to std::array<const int> should be "
+      "convertible to span<const int> with dynamic extent.");
+  static_assert(
+      std::is_convertible<std::array<const int, 3>&, span<const int, 3>>::value,
+      "Error: l-value reference to std::array<const int> should be convertible "
+      "to span<const int> with the same static extent.");
+  static_assert(
+      std::is_convertible<const std::array<const int, 3>&,
+                          span<const int>>::value,
+      "Error: const l-value reference to std::array<const int> should be "
+      "convertible to span<const int> with dynamic extent.");
+  static_assert(
+      std::is_convertible<const std::array<const int, 3>&,
+                          span<const int, 3>>::value,
+      "Error: const l-value reference to std::array<const int> should be "
+      "convertible to span<const int> with the same static extent.");
+}
+
+TEST(SpanTest, DisallowedConstructionsFromStdArray) {
+  // In the following assertions we use !std::is_constructible_v<T, Args>, which
+  // is equivalent to checking whether the following expression is malformed:
+  //
+  // T obj(std::declval<Args>()...);
+  //
+  // In particular we are checking that T is not explicitly constructible from
+  // Args, which also implies that T is not implicitly constructible from Args
+  // as well.
+  static_assert(
+      !std::is_constructible<span<int>, const std::array<int, 3>&>::value,
+      "Error: span<int> with dynamic extent should not be constructible "
+      "from const l-value reference to std::array<int>");
+
+  static_assert(
+      !std::is_constructible<span<int>, std::array<const int, 3>&>::value,
+      "Error: span<int> with dynamic extent should not be constructible "
+      "from l-value reference to std::array<const int>");
+
+  static_assert(
+      !std::is_constructible<span<int>, const std::array<const int, 3>&>::value,
+      "Error: span<int> with dynamic extent should not be constructible "
+      "const from l-value reference to std::array<const int>");
+
+  static_assert(
+      !std::is_constructible<span<int, 2>, std::array<int, 3>&>::value,
+      "Error: span<int> with static extent should not be constructible "
+      "from l-value reference to std::array<int> with different extent");
+
+  static_assert(
+      !std::is_constructible<span<int, 4>, std::array<int, 3>&>::value,
+      "Error: span<int> with dynamic extent should not be constructible "
+      "from l-value reference to std::array<int> with different extent");
+
+  static_assert(
+      !std::is_constructible<span<int>, std::array<bool, 3>&>::value,
+      "Error: span<int> with dynamic extent should not be constructible "
+      "from l-value reference to std::array<bool>");
+}
+
 TEST(SpanTest, ConstructFromConstexprArray) {
   static constexpr int kArray[] = {5, 4, 3, 2, 1};
 
@@ -1143,8 +1236,10 @@
 
   EXPECT_TRUE(std::equal(
       std::rbegin(kArray), std::rend(kArray), span.rbegin(), span.rend()));
-  EXPECT_TRUE(std::equal(
-      std::crbegin(kArray), std::crend(kArray), span.crbegin(), span.crend()));
+  EXPECT_TRUE(std::equal(std::crbegin(kArray),
+                         std::crend(kArray),
+                         std::crbegin(span),
+                         std::crend(span)));
 }
 
 // Pigweed: These are tests for make_span, which is not included in Pigweed's
@@ -1379,46 +1474,6 @@
 }
 #endif  // 0
 
-TEST(SpanTest, StdTupleSize) {
-  static_assert(std::tuple_size<span<int, 0>>::value == 0, "");
-  static_assert(std::tuple_size<span<int, 1>>::value == 1, "");
-  static_assert(std::tuple_size<span<int, 2>>::value == 2, "");
-}
-
-TEST(SpanTest, StdTupleElement) {
-  static_assert(std::is_same<int, std::tuple_element_t<0, span<int, 1>>>::value,
-                "");
-  static_assert(
-      std::is_same<const int,
-                   std::tuple_element_t<0, span<const int, 2>>>::value,
-      "");
-  static_assert(
-      std::is_same<const int*,
-                   std::tuple_element_t<1, span<const int*, 2>>>::value,
-      "");
-}
-
-TEST(SpanTest, StdGet) {
-  static constexpr int kArray[] = {1, 6, 1, 8, 0};
-  constexpr span<const int, 5> span(kArray);
-
-  static_assert(
-      &kArray[0] == &std::get<0>(span),
-      "std::get<0>(span) does not refer to the same element as kArray[0]");
-  static_assert(
-      &kArray[1] == &std::get<1>(span),
-      "std::get<1>(span) does not refer to the same element as kArray[1]");
-  static_assert(
-      &kArray[2] == &std::get<2>(span),
-      "std::get<2>(span) does not refer to the same element as kArray[2]");
-  static_assert(
-      &kArray[3] == &std::get<3>(span),
-      "std::get<3>(span) does not refer to the same element as kArray[3]");
-  static_assert(
-      &kArray[4] == &std::get<4>(span),
-      "std::get<4>(span) does not refer to the same element as kArray[4]");
-}
-
 TEST(SpanTest, EnsureConstexprGoodness) {
   static constexpr int kArray[] = {5, 4, 3, 2, 1};
   constexpr span<const int> constexpr_span(kArray);
@@ -1488,7 +1543,7 @@
             span.data() + dest_start_index,
             span.data() + dest_start_index + kNumElements)));
     EXPECT_FALSE(CheckedContiguousConstIterator<const int>::IsRangeMoveSafe(
-        span.cbegin(), span.cend(),
+        std::cbegin(span), std::cend(span),
         CheckedContiguousConstIterator<const int>(
             span.data() + dest_start_index,
             span.data() + dest_start_index + kNumElements)));
@@ -1502,7 +1557,7 @@
             span.data() + dest_start_index,
             span.data() + dest_start_index + kNumElements)));
     EXPECT_TRUE(CheckedContiguousConstIterator<const int>::IsRangeMoveSafe(
-        span.cbegin(), span.cend(),
+        std::cbegin(span), std::cend(span),
         CheckedContiguousConstIterator<const int>(
             span.data() + dest_start_index,
             span.data() + dest_start_index + kNumElements)));
@@ -1513,7 +1568,7 @@
       span.begin(), span.begin(),
       CheckedContiguousIterator<const int>(span.data(), span.data())));
   EXPECT_TRUE(CheckedContiguousConstIterator<const int>::IsRangeMoveSafe(
-      span.cbegin(), span.cbegin(),
+      std::cbegin(span), std::cbegin(span),
       CheckedContiguousConstIterator<const int>(span.data(), span.data())));
 
   // IsRangeMoveSafe is false if end < begin.
@@ -1521,7 +1576,7 @@
       span.end(), span.begin(),
       CheckedContiguousIterator<const int>(span.data(), span.data())));
   EXPECT_FALSE(CheckedContiguousConstIterator<const int>::IsRangeMoveSafe(
-      span.cend(), span.cbegin(),
+      std::cend(span), std::cbegin(span),
       CheckedContiguousConstIterator<const int>(span.data(), span.data())));
 }
 
@@ -1566,12 +1621,12 @@
 
 TEST(SpanTest, IteratorConversions) {
   static_assert(std::is_convertible<span<int>::iterator,
-                                    span<int>::const_iterator>::value,
-                "Error: iterator should be convertible to const_iterator");
+                                    span<const int>::iterator>::value,
+                "Error: iterator should be convertible to const iterator");
 
-  static_assert(!std::is_convertible<span<int>::const_iterator,
+  static_assert(!std::is_convertible<span<const int>::iterator,
                                      span<int>::iterator>::value,
-                "Error: const_iterator should not be convertible to iterator");
+                "Error: const iterator should not be convertible to iterator");
 }
 
 }  // namespace pw